diff --git a/.github/workflows/render_nanomaps.yml b/.github/workflows/render_nanomaps.yml
new file mode 100644
index 0000000000..6b58c9e8e0
--- /dev/null
+++ b/.github/workflows/render_nanomaps.yml
@@ -0,0 +1,35 @@
+# GitHub action to autorender nanomaps outside the game
+# This kills off the awful verb we have that takes a full 50 seconds and hangs the whole server
+# The file names and locations are VERY important here
+# DO NOT EDIT THIS UNLESS YOU KNOW WHAT YOU ARE DOING
+# -aa
+name: 'Render Nanomaps'
+on:
+ push:
+ branches: master
+ paths:
+ - 'maps/**'
+
+jobs:
+ generate_maps:
+ name: 'Generate NanoMaps'
+ runs-on: ubuntu-18.04
+ steps:
+ - name: 'Update Branch'
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 1
+
+ - name: 'Generate Maps'
+ run: './tools/github-actions/nanomap-renderer-invoker.sh'
+
+ - name: 'Commit Maps'
+ run: |
+ git config --local user.email "action@github.com"
+ git config --local user.name "NanoMap Generation"
+ git pull origin master
+ git commit -m "NanoMap Auto-Update (`date`)" -a || true
+ - name: 'Push Maps'
+ uses: ad-m/github-push-action@master
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/README.md b/README.md
index 2780275b94..51ceb23af6 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,8 @@ Going to make a Pull Request? Make sure you read the [CONTRIBUTING.md](.github/C
VOREStation is a fork of the Polaris code branch, itself a fork of the Baystation12 code branch, for the game Space Station 13.
+
+
---
### LICENSE
diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
index dd38dae3ca..e960d36fa7 100644
--- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
@@ -13,6 +13,7 @@
desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power."
use_power = USE_POWER_OFF
+ interact_offline = TRUE
var/unlocked = 0 //If 0, then the valve is locked closed, otherwise it is open(-able, it's a one-way valve so it closes if gas would flow backwards).
var/target_pressure = ONE_ATMOSPHERE
@@ -216,7 +217,7 @@
tgui_interact(user)
/obj/machinery/atmospherics/binary/passive_gate/tgui_interact(mob/user, datum/tgui/ui)
- if(stat & (BROKEN|NOPOWER))
+ if(stat & BROKEN)
return FALSE
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
diff --git a/code/ATMOSPHERICS/components/omni_devices/filter.dm b/code/ATMOSPHERICS/components/omni_devices/filter.dm
index 56171a0880..00e2f9d5dc 100644
--- a/code/ATMOSPHERICS/components/omni_devices/filter.dm
+++ b/code/ATMOSPHERICS/components/omni_devices/filter.dm
@@ -33,8 +33,10 @@
return ..()
/obj/machinery/atmospherics/omni/atmos_filter/sort_ports()
+ var/any_updated = FALSE
for(var/datum/omni_port/P in ports)
if(P.update)
+ any_updated = TRUE
if(output == P)
output = null
if(input == P)
@@ -50,6 +52,8 @@
output = P
if(ATM_O2 to ATM_N2O)
atmos_filters += P
+ if(any_updated)
+ rebuild_filtering_list()
/obj/machinery/atmospherics/omni/atmos_filter/error_check()
if(!input || !output || !atmos_filters)
@@ -231,7 +235,6 @@
target_port.mode = mode
if(target_port.mode != previous_mode)
handle_port_change(target_port)
- rebuild_filtering_list()
else
return
else
diff --git a/code/ATMOSPHERICS/pipes/tank.dm b/code/ATMOSPHERICS/pipes/tank.dm
index 54f90d9521..a893facff6 100644
--- a/code/ATMOSPHERICS/pipes/tank.dm
+++ b/code/ATMOSPHERICS/pipes/tank.dm
@@ -70,10 +70,6 @@
if(istype(W, /obj/item/device/pipe_painter))
return
- if(istype(W, /obj/item/device/analyzer) && in_range(user, src))
- var/obj/item/device/analyzer/A = W
- A.analyze_gases(src, user)
-
/obj/machinery/atmospherics/pipe/tank/air
name = "Pressure Tank (Air)"
icon_state = "air_map"
diff --git a/code/__defines/pda.dm b/code/__defines/pda.dm
new file mode 100644
index 0000000000..c5d32f03ba
--- /dev/null
+++ b/code/__defines/pda.dm
@@ -0,0 +1,3 @@
+#define PDA_APP_UPDATE 0
+#define PDA_APP_NOUPDATE 1
+#define PDA_APP_UPDATE_SLOW 2
diff --git a/code/_helpers/text.dm b/code/_helpers/text.dm
index 02a8806089..a9aac1ffcf 100644
--- a/code/_helpers/text.dm
+++ b/code/_helpers/text.dm
@@ -21,6 +21,27 @@
/*
* Text sanitization
*/
+// Can be used almost the same way as normal input for text
+/proc/clean_input(Message, Title, Default, mob/user=usr)
+ var/txt = input(user, Message, Title, Default) as text | null
+ if(txt)
+ return html_encode(txt)
+
+//Simply removes < and > and limits the length of the message
+/proc/strip_html_simple(var/t,var/limit=MAX_MESSAGE_LEN)
+ var/list/strip_chars = list("<",">")
+ t = copytext(t,1,limit)
+ for(var/char in strip_chars)
+ var/index = findtext(t, char)
+ while(index)
+ t = copytext(t, 1, index) + copytext(t, index+1)
+ index = findtext(t, char)
+ return t
+
+//Runs byond's sanitization proc along-side strip_html_simple
+//I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' that html_encode() would cause
+/proc/adminscrub(var/t,var/limit=MAX_MESSAGE_LEN)
+ return copytext((html_encode(strip_html_simple(t))),1,limit)
//Used for preprocessing entered text
/proc/sanitize(var/input, var/max_length = MAX_MESSAGE_LEN, var/encode = 1, var/trim = 1, var/extra = 1)
diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm
index 859884a8b7..76b18f7222 100644
--- a/code/_onclick/ai.dm
+++ b/code/_onclick/ai.dm
@@ -141,8 +141,9 @@
return 1
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
- Topic(src, list("command"="enable", "value"="[!enabled]"))
- return 1
+ enabled = !enabled
+ updateTurrets()
+ return TRUE
/atom/proc/AIAltClick(var/atom/A)
return AltClick(A)
@@ -156,8 +157,10 @@
return 1
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
- Topic(src, list("command"="lethal", "value"="[!lethal]"))
- return 1
+ if(lethal_is_configurable)
+ lethal = !lethal
+ updateTurrets()
+ return TRUE
/atom/proc/AIMiddleClick(var/mob/living/silicon/user)
return 0
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index 66cf3d1c12..5e5f044ac2 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -515,7 +515,7 @@
if("Show Crew Manifest")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
- AI.ai_roster()
+ AI.subsystem_crew_manifest()
if("Show Alerts")
if(isAI(usr))
@@ -540,12 +540,14 @@
if("PDA - Send Message")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
- AI.aiPDA.cmd_send_pdamesg(usr)
+ AI.aiPDA.start_program(AI.aiPDA.find_program(/datum/data/pda/app/messenger))
+ AI.aiPDA.cmd_pda_open_ui(usr)
if("PDA - Show Message Log")
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
- AI.aiPDA.cmd_show_message_log(usr)
+ AI.aiPDA.start_program(AI.aiPDA.find_program(/datum/data/pda/app/messenger))
+ AI.aiPDA.cmd_pda_open_ui(usr)
if("Take Image")
if(isAI(usr))
diff --git a/code/controllers/subsystems/nanoui.dm b/code/controllers/subsystems/nanoui.dm
deleted file mode 100644
index c916eb2739..0000000000
--- a/code/controllers/subsystems/nanoui.dm
+++ /dev/null
@@ -1,22 +0,0 @@
-SUBSYSTEM_DEF(nanoui)
- name = "NanoUI"
- wait = 5
- flags = SS_NO_INIT
- // a list of current open /nanoui UIs, grouped by src_object and ui_key
- var/list/open_uis = list()
- // a list of current open /nanoui UIs, not grouped, for use in processing
- var/list/processing_uis = list()
-
-/datum/controller/subsystem/nanoui/Recover()
- if(SSnanoui.open_uis)
- open_uis |= SSnanoui.open_uis
- if(SSnanoui.processing_uis)
- processing_uis |= SSnanoui.processing_uis
-
-/datum/controller/subsystem/nanoui/stat_entry()
- return ..("[processing_uis.len] UIs")
-
-/datum/controller/subsystem/nanoui/fire(resumed)
- for(var/thing in processing_uis)
- var/datum/nanoui/UI = thing
- UI.process()
diff --git a/code/controllers/subsystems/persistence.dm b/code/controllers/subsystems/persistence.dm
index c2724c2d60..00c08363de 100644
--- a/code/controllers/subsystems/persistence.dm
+++ b/code/controllers/subsystems/persistence.dm
@@ -31,7 +31,7 @@ SUBSYSTEM_DEF(persistence)
return
// if((!T.z in GLOB.using_map.station_levels) || !initialized)
- if(!T.z in using_map.station_levels)
+ if(!(T.z in using_map.station_levels))
return
if(!tracking_values[track_type])
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index 61eb4c6953..d806728f5d 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -31,5 +31,5 @@
weakref = null // Clear this reference to ensure it's kept for as brief duration as possible.
tag = null
- SSnanoui.close_uis(src)
+ SStgui.close_uis(src)
return QDEL_HINT_QUEUE
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 10a7b4b7b9..bca9df5ae1 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -85,7 +85,6 @@
current.verbs -= /datum/changeling/proc/EvolutionMenu
current.mind = null
- SSnanoui.user_transferred(current, new_character) // transfer active NanoUI instances to new user
if(new_character.mind) //remove any mind currently in our new body's mind variable
new_character.mind.current = null
diff --git a/code/datums/repositories/crew.dm b/code/datums/repositories/crew.dm
index 7a748049bc..c45202194b 100644
--- a/code/datums/repositories/crew.dm
+++ b/code/datums/repositories/crew.dm
@@ -38,9 +38,10 @@ var/global/datum/repository/crew/crew_repository = new()
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
- crewmemberData["dead"] = H.stat > UNCONSCIOUS
+ crewmemberData["dead"] = H.stat == DEAD
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
+ crewmemberData["stat"] = H.stat
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
diff --git a/code/datums/uplink/announcements.dm b/code/datums/uplink/announcements.dm
index 1c4a448cee..e85541a55d 100644
--- a/code/datums/uplink/announcements.dm
+++ b/code/datums/uplink/announcements.dm
@@ -25,16 +25,7 @@
return list("title" = title, "message" = message)
/datum/uplink_item/abstract/announcements/fake_centcom/get_goods(var/obj/item/device/uplink/U, var/loc, var/mob/user, var/list/args)
- for (var/obj/machinery/computer/communications/C in machines)
- if(! (C.stat & (BROKEN|NOPOWER) ) )
- var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc )
- P.name = "'[command_name()] Update.'"
- P.info = replacetext(args["message"], "\n", "
")
- P.update_space(P.info)
- P.update_icon()
- C.messagetitle.Add(args["title"])
- C.messagetext.Add(P.info)
-
+ post_comm_message(args["title"], replacetext(args["message"], "\n", "
"))
command_announcement.Announce(args["message"], args["title"])
return 1
diff --git a/code/datums/uplink/implants.dm b/code/datums/uplink/implants.dm
index bbbeaf9e7e..d1bb93acdc 100644
--- a/code/datums/uplink/implants.dm
+++ b/code/datums/uplink/implants.dm
@@ -73,3 +73,13 @@
name = "Integrated Surge Implant"
item_cost = 40
path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/surge
+
+/datum/uplink_item/item/implants/imp_armblade
+ name = "Integrated Armblade Implant"
+ item_cost = 40
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/armblade
+
+/datum/uplink_item/item/implants/imp_handblade
+ name = "Integrated Handblade Implant"
+ item_cost = 25
+ path = /obj/item/weapon/storage/box/syndie_kit/imp_aug/handblade
diff --git a/code/datums/uplink/uplink_items.dm b/code/datums/uplink/uplink_items.dm
index cca1933c9c..8d9de8f732 100644
--- a/code/datums/uplink/uplink_items.dm
+++ b/code/datums/uplink/uplink_items.dm
@@ -51,7 +51,7 @@ var/datum/uplink/uplink = new()
if(!can_buy(U))
return
- if(U.CanUseTopic(user, inventory_state) != STATUS_INTERACTIVE)
+ if(U.CanUseTopic(user, GLOB.tgui_inventory_state) != STATUS_INTERACTIVE)
return
var/cost = cost(U.uses, U)
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index 6c05e65438..8be56acbf3 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -10,6 +10,8 @@
w_class = ITEMSIZE_SMALL
attack_verb = list("called", "rang")
hitsound = 'sound/weapons/ring.ogg'
+ drop_sound = 'sound/items/drop/device.ogg'
+ pickup_sound = 'sound/items/pickup/device.ogg'
/obj/item/weapon/rsp
name = "\improper Rapid-Seed-Producer (RSP)"
@@ -22,6 +24,8 @@
var/stored_matter = 0
var/mode = 1
w_class = ITEMSIZE_NORMAL
+ drop_sound = 'sound/items/drop/device.ogg'
+ pickup_sound = 'sound/items/pickup/device.ogg'
/obj/item/weapon/soap
name = "soap"
@@ -35,7 +39,6 @@
throwforce = 0
throw_speed = 4
throw_range = 20
- drop_sound = 'sound/misc/slip.ogg'
/obj/item/weapon/soap/nanotrasen
desc = "A NanoTrasen-brand bar of soap. Smells of phoron."
@@ -149,6 +152,8 @@
throw_range = 20
matter = list(DEFAULT_WALL_MATERIAL = 100)
origin_tech = list(TECH_MAGNET = 1)
+ drop_sound = 'sound/items/drop/device.ogg'
+ pickup_sound = 'sound/items/pickup/device.ogg'
/obj/item/weapon/staff
name = "wizards staff"
@@ -196,6 +201,8 @@
item_state = "std_mod"
w_class = ITEMSIZE_SMALL
var/mtype = 1 // 1=electronic 2=hardware
+ drop_sound = 'sound/items/drop/component.ogg'
+ pickup_sound = 'sound/items/pickup/component.ogg'
/obj/item/weapon/module/card_reader
name = "card reader module"
@@ -227,7 +234,6 @@
item_state = "std_mod"
desc = "Charging circuits for power cells."
-
/obj/item/device/camera_bug
name = "camera bug"
icon = 'icons/obj/device.dmi'
@@ -303,6 +309,8 @@
display_contents_with_number = 1
max_w_class = ITEMSIZE_NORMAL
max_storage_space = 100
+ drop_sound = 'sound/items/drop/device.ogg'
+ pickup_sound = 'sound/items/pickup/device.ogg'
/obj/item/weapon/storage/part_replacer/adv
name = "advanced rapid part exchange device"
@@ -326,7 +334,8 @@
icon = 'icons/obj/stock_parts.dmi'
w_class = ITEMSIZE_SMALL
var/rating = 1
- drop_sound = 'sound/items/drop/glass.ogg'
+ drop_sound = 'sound/items/drop/component.ogg'
+ pickup_sound = 'sound/items/pickup/component.ogg'
/obj/item/weapon/stock_parts/New()
src.pixel_x = rand(-5.0, 5)
diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm
index 1d48349cb5..03185d31d3 100644
--- a/code/game/dna/dna2.dm
+++ b/code/game/dna/dna2.dm
@@ -276,7 +276,7 @@ var/global/list/datum/dna/gene/dna_genes[0]
// Set a DNA UI block's raw value.
/datum/dna/proc/SetUIValue(var/block,var/value,var/defer=0)
if (block<=0) return
- ASSERT(value>0)
+ ASSERT(value>=0)
ASSERT(value<=4095)
UI[block]=value
dirtyUI=1
@@ -292,7 +292,6 @@ var/global/list/datum/dna/gene/dna_genes[0]
// Used in hair and facial styles (value being the index and maxvalue being the len of the hairstyle list)
/datum/dna/proc/SetUIValueRange(var/block,var/value,var/maxvalue,var/defer=0)
if (block<=0) return
- if (value==0) value = 1 // FIXME: hair/beard/eye RGB values if they are 0 are not set, this is a work around we'll encode it in the DNA to be 1 instead.
ASSERT(maxvalue<=4095)
var/range = (4095 / maxvalue)
if(value)
@@ -302,7 +301,7 @@ var/global/list/datum/dna/gene/dna_genes[0]
/datum/dna/proc/GetUIValueRange(var/block,var/maxvalue)
if (block<=0) return 0
var/value = GetUIValue(block)
- return round(0.5 + (value / 4096) * maxvalue)
+ return round(0.5 + (value / 4095) * maxvalue)
// Is the UI gene "on" or "off"?
// For UI, this is simply a check of if the value is > 2050.
@@ -388,7 +387,7 @@ var/global/list/datum/dna/gene/dna_genes[0]
/datum/dna/proc/GetSEValueRange(var/block,var/maxvalue)
if (block<=0) return 0
var/value = GetSEValue(block)
- return round(1 +(value / 4096)*maxvalue)
+ return round(1 +(value / 4095)*maxvalue)
// Is the block "on" (1) or "off" (0)? (Un-assigned genes are always off.)
/datum/dna/proc/GetSEState(var/block)
diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm
index f4fcffbd34..cd3ec6a44d 100644
--- a/code/game/dna/dna2_helpers.dm
+++ b/code/game/dna/dna2_helpers.dm
@@ -177,7 +177,7 @@
// Ears
var/ears = dna.GetUIValueRange(DNA_UI_EAR_STYLE, ear_styles_list.len + 1) - 1
- if(ears <= 1)
+ if(ears < 1)
H.ear_style = null
else if((0 < ears) && (ears <= ear_styles_list.len))
H.ear_style = ear_styles_list[ear_styles_list[ears]]
@@ -192,14 +192,14 @@
//Tail
var/tail = dna.GetUIValueRange(DNA_UI_TAIL_STYLE, tail_styles_list.len + 1) - 1
- if(tail <= 1)
+ if(tail < 1)
H.tail_style = null
else if((0 < tail) && (tail <= tail_styles_list.len))
H.tail_style = tail_styles_list[tail_styles_list[tail]]
//Wing
var/wing = dna.GetUIValueRange(DNA_UI_WING_STYLE, wing_styles_list.len + 1) - 1
- if(wing <= 1)
+ if(wing < 1)
H.wing_style = null
else if((0 < wing) && (wing <= wing_styles_list.len))
H.wing_style = wing_styles_list[wing_styles_list[wing]]
diff --git a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm b/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
index b90b402e78..6ec87a64d4 100644
--- a/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
+++ b/code/game/gamemodes/changeling/powers/fabricate_clothing.dm
@@ -286,5 +286,5 @@ var/global/list/changeling_fabricated_clothing = list(
if(!registered_user)
registered_user = usr
usr.set_id_info(src)
- ui_interact(registered_user)
+ tgui_interact(registered_user)
..()
\ No newline at end of file
diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm
index 4ee64999fa..b49c41f30f 100644
--- a/code/game/jobs/access.dm
+++ b/code/game/jobs/access.dm
@@ -180,7 +180,7 @@
/proc/get_access_by_id(id)
var/list/AS = get_all_access_datums_by_id()
- return AS[id]
+ return AS["[id]"]
/proc/get_all_jobs()
var/list/all_jobs = list()
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 403efbf4fe..3aec6c8c37 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -540,6 +540,8 @@ var/global/datum/controller/occupations/job_master
// EMAIL GENERATION
// Email addresses will be created under this domain name. Mostly for the looks.
var/domain = "freemail.nt"
+ if(using_map && LAZYLEN(using_map.usable_email_tlds))
+ domain = using_map.usable_email_tlds[1]
var/sanitized_name = sanitize(replacetext(replacetext(lowertext(H.real_name), " ", "."), "'", ""))
var/complete_login = "[sanitized_name]@[domain]"
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 6fe30aeaab..2d5e39b1b7 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -260,7 +260,7 @@ update_flag
..()
- SSnanoui.update_uis(src) // Update all NanoUIs attached to src
+ SStgui.update_uis(src) // Update all NanoUIs attached to src
/obj/machinery/portable_atmospherics/canister/attack_ai(var/mob/user as mob)
return src.attack_hand(user)
diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm
index 915fb8fac1..dc530ecc2f 100644
--- a/code/game/machinery/atmoalter/portable_atmospherics.dm
+++ b/code/game/machinery/atmoalter/portable_atmospherics.dm
@@ -136,12 +136,6 @@
else
to_chat(user, "Nothing happens.")
return
-
- else if ((istype(W, /obj/item/device/analyzer)) && Adjacent(user))
- var/obj/item/device/analyzer/A = W
- A.analyze_gases(src, user)
- return
-
return
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index 73b78cb148..955ccf596a 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -204,7 +204,9 @@
else
P = W
itemname = P.name
- info = P.notehtml
+ var/datum/data/pda/app/notekeeper/N = P.find_program(/datum/data/pda/app/notekeeper)
+ if(N)
+ info = N.notehtml
to_chat(U, "You hold \a [itemname] up to the camera ...")
for(var/mob/living/silicon/ai/O in living_mob_list)
if(!O.client)
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 8ef01c9b64..6921cf989c 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -92,8 +92,11 @@
var/blocked = 0 //Player cannot attack/heal while set
var/turtle = 0
-/obj/machinery/computer/arcade/battle/New()
- ..()
+/obj/machinery/computer/arcade/battle/Initialize()
+ . = ..()
+ randomize_characters()
+
+/obj/machinery/computer/arcade/battle/proc/randomize_characters()
var/name_action
var/name_part1
var/name_part2
@@ -111,17 +114,17 @@
if(..())
return
user.set_machine(src)
- ui_interact(user)
+ tgui_interact(user)
-/**
- * Display the NanoUI window for the arcade machine.
- *
- * See NanoUI documentation for details.
- */
-/obj/machinery/computer/arcade/battle/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- user.set_machine(src)
+/obj/machinery/computer/arcade/battle/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "ArcadeBattle", name)
+ ui.open()
- var/list/data = list()
+/obj/machinery/computer/arcade/battle/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+ data["name"] = name
data["temp"] = temp
data["enemyAction"] = enemy_action
data["enemyName"] = enemy_name
@@ -129,59 +132,54 @@
data["playerMP"] = player_mp
data["enemyHP"] = enemy_hp
data["gameOver"] = gameover
+ return data
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "arcade_battle.tmpl", src.name, 400, 300)
- ui.set_initial_data(data)
- ui.open()
- //ui.set_auto_update(2)
-
-/obj/machinery/computer/arcade/battle/Topic(href, href_list)
+/obj/machinery/computer/arcade/battle/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
+ return TRUE
- if (!blocked && !gameover)
- if (href_list["attack"])
- blocked = 1
- var/attackamt = rand(2,6)
- temp = "You attack for [attackamt] damage!"
- playsound(src, 'sound/arcade/hit.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
- if(turtle > 0)
- turtle--
+ if(!blocked && !gameover)
+ switch(action)
+ if("attack")
+ blocked = 1
+ var/attackamt = rand(2,6)
+ temp = "You attack for [attackamt] damage!"
+ playsound(src, 'sound/arcade/hit.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
+ if(turtle > 0)
+ turtle--
- sleep(10)
- enemy_hp -= attackamt
- arcade_action()
+ sleep(10)
+ enemy_hp -= attackamt
+ arcade_action()
- else if (href_list["heal"])
- blocked = 1
- var/pointamt = rand(1,3)
- var/healamt = rand(6,8)
- temp = "You use [pointamt] magic to heal for [healamt] damage!"
- playsound(src, 'sound/arcade/heal.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
- turtle++
+ if("heal")
+ blocked = 1
+ var/pointamt = rand(1,3)
+ var/healamt = rand(6,8)
+ temp = "You use [pointamt] magic to heal for [healamt] damage!"
+ playsound(src, 'sound/arcade/heal.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
+ turtle++
- sleep(10)
- player_mp -= pointamt
- player_hp += healamt
- blocked = 1
- arcade_action()
+ sleep(10)
+ player_mp -= pointamt
+ player_hp += healamt
+ blocked = 1
+ arcade_action()
- else if (href_list["charge"])
- blocked = 1
- var/chargeamt = rand(4,7)
- temp = "You regain [chargeamt] points"
- playsound(src, 'sound/arcade/mana.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
- player_mp += chargeamt
- if(turtle > 0)
- turtle--
+ if("charge")
+ blocked = 1
+ var/chargeamt = rand(4,7)
+ temp = "You regain [chargeamt] points"
+ playsound(src, 'sound/arcade/mana.ogg', 50, 1, extrarange = -3, falloff = 0.1, ignore_walls = FALSE)
+ player_mp += chargeamt
+ if(turtle > 0)
+ turtle--
- sleep(10)
- arcade_action()
+ sleep(10)
+ arcade_action()
- else if (href_list["newgame"]) //Reset everything
+ if(action == "newgame") //Reset everything
temp = "New Round"
player_hp = 30
player_mp = 10
@@ -191,12 +189,11 @@
turtle = 0
if(emagged)
- src.New()
+ randomize_characters()
emagged = 0
- src.add_fingerprint(usr)
- SSnanoui.update_uis(src)
- return
+ add_fingerprint(usr)
+ return TRUE
/obj/machinery/computer/arcade/battle/proc/arcade_action()
if ((enemy_mp <= 0) || (enemy_hp <= 0))
@@ -211,7 +208,7 @@
new /obj/item/clothing/head/collectable/petehat(src.loc)
message_admins("[key_name_admin(usr)] has outbombed Cuban Pete and been awarded a bomb.")
log_game("[key_name_admin(usr)] has outbombed Cuban Pete and been awarded a bomb.")
- src.New()
+ randomize_characters()
emagged = 0
else if(!contents.len)
feedback_inc("arcade_win_normal")
diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm
index 97d68e190a..29783c4c9c 100644
--- a/code/game/machinery/computer/camera.dm
+++ b/code/game/machinery/computer/camera.dm
@@ -36,6 +36,13 @@
return
tgui_interact(user)
+/obj/machinery/computer/security/attack_robot(mob/user)
+ if(isrobot(user))
+ var/mob/living/silicon/robot/R = user
+ if(!R.shell)
+ return attack_hand(user)
+ ..()
+
/obj/machinery/computer/security/attack_ai(mob/user)
if(isAI(user))
to_chat(user, "You realise its kind of stupid to access a camera console when you have the entire camera network at your metaphorical fingertips")
diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm
index 7833a58d72..0f52e67b8c 100644
--- a/code/game/machinery/computer/card.dm
+++ b/code/game/machinery/computer/card.dm
@@ -26,7 +26,7 @@
var/list/formatted = list()
for(var/job in jobs)
formatted.Add(list(list(
- "display_name" = replacetext(job, " ", " "),
+ "display_name" = replacetext(job, " ", " "),
"target_rank" = get_target_rank(),
"job" = job)))
@@ -68,7 +68,7 @@
id_card.forceMove(src)
modify = id_card
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
attack_hand(user)
/obj/machinery/computer/card/attack_ai(var/mob/user as mob)
@@ -77,20 +77,27 @@
/obj/machinery/computer/card/attack_hand(mob/user as mob)
if(..()) return
if(stat & (NOPOWER|BROKEN)) return
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/computer/card/ui_interact(mob/user, ui_key="main", var/datum/nanoui/ui = null, var/force_open = 1)
- user.set_machine(src)
+/obj/machinery/computer/card/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "IdentificationComputer", name)
+ ui.open()
+/obj/machinery/computer/card/tgui_static_data(mob/user)
+ var/list/data = ..()
if(data_core)
data_core.get_manifest_list()
+ data["manifest"] = PDA_Manifest
+ return data
+
+/obj/machinery/computer/card/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- var/data[0]
- data["src"] = "\ref[src]"
data["station_name"] = station_name()
data["mode"] = mode
data["printing"] = printing
- data["manifest"] = PDA_Manifest
data["target_name"] = modify ? modify.name : "-----"
data["target_owner"] = modify && modify.registered_name ? modify.registered_name : "-----"
data["target_rank"] = get_target_rank()
@@ -110,27 +117,27 @@
continue
if(dept.centcom_only && !is_centcom())
continue
- departments[++departments.len] = list("department_name" = dept.name, "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)) )
-
+ departments.Add(list(list(
+ "department_name" = dept.name,
+ "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name))
+ )))
data["departments"] = departments
- if (modify && is_centcom())
- var/list/all_centcom_access = list()
+ var/list/all_centcom_access = list()
+ var/list/regions = list()
+ if(modify && is_centcom())
for(var/access in get_all_centcom_access())
all_centcom_access.Add(list(list(
- "desc" = replacetext(get_centcom_access_desc(access), " ", " "),
+ "desc" = replacetext(get_centcom_access_desc(access), " ", " "),
"ref" = access,
"allowed" = (access in modify.access) ? 1 : 0)))
-
- data["all_centcom_access"] = all_centcom_access
- else if (modify)
- var/list/regions = list()
- for(var/i = 1; i <= 7; i++)
+ else if(modify)
+ for(var/i in ACCESS_REGION_SECURITY to ACCESS_REGION_SUPPLY)
var/list/accesses = list()
for(var/access in get_region_accesses(i))
if (get_access_desc(access))
accesses.Add(list(list(
- "desc" = replacetext(get_access_desc(access), " ", " "),
+ "desc" = replacetext(get_access_desc(access), " ", " "),
"ref" = access,
"allowed" = (access in modify.access) ? 1 : 0)))
@@ -138,23 +145,20 @@
"name" = get_region_accesses_name(i),
"accesses" = accesses)))
- data["regions"] = regions
+ data["regions"] = regions
+ data["all_centcom_access"] = all_centcom_access
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 600, 700)
- ui.set_initial_data(data)
- ui.open()
+ return data
-/obj/machinery/computer/card/Topic(href, href_list)
+/obj/machinery/computer/card/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
+ return TRUE
- switch(href_list["choice"])
- if ("modify")
- if (modify)
+ switch(action)
+ if("modify")
+ if(modify)
data_core.manifest_modify(modify.registered_name, modify.assignment)
- modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])")
+ modify.name = "[modify.registered_name]'s ID Card ([modify.assignment])"
if(ishuman(usr))
modify.forceMove(get_turf(src))
if(!usr.get_active_hand())
@@ -165,12 +169,13 @@
modify = null
else
var/obj/item/I = usr.get_active_hand()
- if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
+ if(istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
I.forceMove(src)
modify = I
+ . = TRUE
- if ("scan")
- if (scan)
+ if("scan")
+ if(scan)
if(ishuman(usr))
scan.forceMove(get_turf(src))
if(!usr.get_active_hand())
@@ -181,25 +186,26 @@
scan = null
else
var/obj/item/I = usr.get_active_hand()
- if (istype(I, /obj/item/weapon/card/id))
+ if(istype(I, /obj/item/weapon/card/id))
usr.drop_item()
I.forceMove(src)
scan = I
+ . = TRUE
if("access")
- if(href_list["allowed"])
- if(is_authenticated())
- var/access_type = text2num(href_list["access_target"])
- var/access_allowed = text2num(href_list["allowed"])
- if(access_type in (is_centcom() ? get_all_centcom_access() : get_all_station_access()))
- modify.access -= access_type
- if(!access_allowed)
- modify.access += access_type
- modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications
+ if(is_authenticated())
+ var/access_type = text2num(params["access_target"])
+ var/access_allowed = text2num(params["allowed"])
+ if(access_type in (is_centcom() ? get_all_centcom_access() : get_all_station_access()))
+ modify.access -= access_type
+ if(!access_allowed)
+ modify.access += access_type
+ modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications
+ . = TRUE
- if ("assign")
- if (is_authenticated() && modify)
- var/t1 = href_list["assign_target"]
+ if("assign")
+ if(is_authenticated() && modify)
+ var/t1 = params["assign_target"]
if(t1 == "Custom")
var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment"), 45)
//let custom jobs function as an impromptu alt title, mainly for sechuds
@@ -222,44 +228,42 @@
modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications
callHook("reassign_employee", list(modify))
+ . = TRUE
- if ("reg")
- if (is_authenticated())
- var/t2 = modify
- if ((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
- var/temp_name = sanitizeName(href_list["reg"])
- if(temp_name)
- modify.registered_name = temp_name
- else
- src.visible_message("[src] buzzes rudely.")
- SSnanoui.update_uis(src)
+ if("reg")
+ if(is_authenticated())
+ var/temp_name = sanitizeName(params["reg"])
+ if(temp_name)
+ modify.registered_name = temp_name
+ else
+ visible_message("[src] buzzes rudely.")
+ . = TRUE
- if ("account")
- if (is_authenticated())
- var/t2 = modify
- if ((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf)))
- var/account_num = text2num(href_list["account"])
- modify.associated_account_number = account_num
- SSnanoui.update_uis(src)
+ if("account")
+ if(is_authenticated())
+ var/account_num = text2num(params["account"])
+ modify.associated_account_number = account_num
+ . = TRUE
- if ("mode")
- mode = text2num(href_list["mode_target"])
+ if("mode")
+ mode = text2num(params["mode_target"])
+ . = TRUE
- if ("print")
- if (!printing)
+ if("print")
+ if(!printing)
printing = 1
spawn(50)
printing = null
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
var/obj/item/weapon/paper/P = new(loc)
- if (mode)
+ if(mode)
P.name = text("crew manifest ([])", stationtime2text())
P.info = {"
Crew Manifest
[data_core ? data_core.get_manifest(0) : ""]
"}
- else if (modify)
+ else if(modify)
P.name = "access report"
P.info = {"Access Report
Prepared By: [scan.registered_name ? scan.registered_name : "Unknown"]
@@ -273,19 +277,20 @@
for(var/A in modify.access)
P.info += " [get_access_desc(A)]"
+ . = TRUE
- if ("terminate")
- if (is_authenticated())
+ if("terminate")
+ if(is_authenticated())
modify.assignment = "Dismissed" //VOREStation Edit: setting adjustment
modify.access = list()
modify.lost_access = list() //VOREStation addition: reset the lost access upon any modifications
callHook("terminate_employee", list(modify))
- if (modify)
- modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])")
+ . = TRUE
- return 1
+ if(modify)
+ modify.name = "[modify.registered_name]'s ID Card ([modify.assignment])"
/obj/machinery/computer/card/centcom
name = "\improper CentCom ID card modification console"
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index 9333e32556..e878aaaf8a 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -9,553 +9,24 @@
light_color = "#0099ff"
req_access = list(access_heads)
circuit = /obj/item/weapon/circuitboard/communications
- var/prints_intercept = 1
- var/authenticated = 0
- var/list/messagetitle = list()
- var/list/messagetext = list()
- var/currmsg = 0
- var/aicurrmsg = 0
- var/state = STATE_DEFAULT
- var/aistate = STATE_DEFAULT
- var/message_cooldown = 0
- var/centcomm_message_cooldown = 0
- var/tmp_alertlevel = 0
- var/const/STATE_DEFAULT = 1
- var/const/STATE_CALLSHUTTLE = 2
- var/const/STATE_CANCELSHUTTLE = 3
- var/const/STATE_MESSAGELIST = 4
- var/const/STATE_VIEWMESSAGE = 5
- var/const/STATE_DELMESSAGE = 6
- var/const/STATE_STATUSDISPLAY = 7
- var/const/STATE_ALERT_LEVEL = 8
- var/const/STATE_CONFIRM_LEVEL = 9
- var/const/STATE_CREWTRANSFER = 10
- var/status_display_freq = "1435"
- var/stat_msg1
- var/stat_msg2
+ var/datum/tgui_module/communications/communications
- var/datum/lore/atc_controller/ATC
- var/datum/announcement/priority/crew_announcement = new
-
-/obj/machinery/computer/communications/New()
- ..()
- ATC = atc
- crew_announcement.newscast = 1
-
-/obj/machinery/computer/communications/process()
- if(..())
- if(state != STATE_STATUSDISPLAY)
- src.updateDialog()
-
-
-/obj/machinery/computer/communications/Topic(href, href_list)
- if(..())
- return 1
- if (using_map && !(src.z in using_map.contact_levels))
- to_chat(usr, "Unable to establish a connection: You're too far away from the station!")
- return
- usr.set_machine(src)
-
- if(!href_list["operation"])
- return
- switch(href_list["operation"])
- // main interface
- if("main")
- src.state = STATE_DEFAULT
- if("login")
- var/mob/M = usr
- var/obj/item/weapon/card/id/I = M.GetIdCard()
- if (I && istype(I))
- if(src.check_access(I))
- authenticated = 1
- if(access_captain in I.access)
- authenticated = 2
- crew_announcement.announcer = GetNameAndAssignmentFromId(I)
- if("logout")
- authenticated = 0
- crew_announcement.announcer = ""
-
- if("swipeidseclevel")
- if(src.authenticated) //Let heads change the alert level.
- var/old_level = security_level
- if(!tmp_alertlevel) tmp_alertlevel = SEC_LEVEL_GREEN
- if(tmp_alertlevel < SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN
- if(tmp_alertlevel > SEC_LEVEL_BLUE) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this
- set_security_level(tmp_alertlevel)
- if(security_level != old_level)
- //Only notify the admins if an actual change happened
- log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
- message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
- switch(security_level)
- if(SEC_LEVEL_GREEN)
- feedback_inc("alert_comms_green",1)
- if(SEC_LEVEL_YELLOW)
- feedback_inc("alert_comms_yellow",1)
- if(SEC_LEVEL_VIOLET)
- feedback_inc("alert_comms_violet",1)
- if(SEC_LEVEL_ORANGE)
- feedback_inc("alert_comms_orange",1)
- if(SEC_LEVEL_BLUE)
- feedback_inc("alert_comms_blue",1)
- tmp_alertlevel = 0
- state = STATE_DEFAULT
-
- if("announce")
- if(src.authenticated==2)
- if(message_cooldown)
- to_chat(usr, "Please allow at least one minute to pass between announcements")
- return
- var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|message
- if(!input || !(usr in view(1,src)))
- return
- crew_announcement.Announce(input)
- message_cooldown = 1
- spawn(600)//One minute cooldown
- message_cooldown = 0
-
- if("callshuttle")
- src.state = STATE_DEFAULT
- if(src.authenticated)
- src.state = STATE_CALLSHUTTLE
- if("callshuttle2")
- if(src.authenticated)
- call_shuttle_proc(usr)
- if(emergency_shuttle.online())
- post_status("shuttle")
- src.state = STATE_DEFAULT
- if("cancelshuttle")
- src.state = STATE_DEFAULT
- if(src.authenticated)
- src.state = STATE_CANCELSHUTTLE
- if("cancelshuttle2")
- if(src.authenticated)
- cancel_call_proc(usr)
- src.state = STATE_DEFAULT
- if("messagelist")
- src.currmsg = 0
- src.state = STATE_MESSAGELIST
- if("toggleatc")
- src.ATC.squelched = !src.ATC.squelched
- if("viewmessage")
- src.state = STATE_VIEWMESSAGE
- if (!src.currmsg)
- if(href_list["message-num"])
- src.currmsg = text2num(href_list["message-num"])
- else
- src.state = STATE_MESSAGELIST
- if("delmessage")
- src.state = (src.currmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST
- if("delmessage2")
- if(src.authenticated)
- if(src.currmsg)
- var/title = src.messagetitle[src.currmsg]
- var/text = src.messagetext[src.currmsg]
- src.messagetitle.Remove(title)
- src.messagetext.Remove(text)
- if(src.currmsg == src.aicurrmsg)
- src.aicurrmsg = 0
- src.currmsg = 0
- src.state = STATE_MESSAGELIST
- else
- src.state = STATE_VIEWMESSAGE
- if("status")
- src.state = STATE_STATUSDISPLAY
-
- // Status display stuff
- if("setstat")
- switch(href_list["statdisp"])
- if("message")
- post_status("message", stat_msg1, stat_msg2)
- if("alert")
- post_status("alert", href_list["alert"])
- else
- post_status(href_list["statdisp"])
-
- if("setmsg1")
- stat_msg1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", stat_msg1) as text|null, 40), 40)
- src.updateDialog()
- if("setmsg2")
- stat_msg2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", stat_msg2) as text|null, 40), 40)
- src.updateDialog()
-
- // OMG CENTCOMM LETTERHEAD
- if("MessageCentCom")
- if(src.authenticated==2)
- if(centcomm_message_cooldown)
- to_chat(usr, "Arrays recycling. Please stand by.")
- return
- var/input = sanitize(input("Please choose a message to transmit to [using_map.boss_short] via quantum entanglement. \
- Please be aware that this process is very expensive, and abuse will lead to... termination. \
- Transmission does not guarantee a response. \
- There is a 30 second delay before you may send another message, be clear, full and concise.", "Central Command Quantum Messaging") as null|message)
- if(!input || !(usr in view(1,src)))
- return
- CentCom_announce(input, usr)
- to_chat(usr, "Message transmitted.")
- log_game("[key_name(usr)] has made an IA [using_map.boss_short] announcement: [input]")
- centcomm_message_cooldown = 1
- spawn(300)//10 minute cooldown
- centcomm_message_cooldown = 0
-
-
- // OMG SYNDICATE ...LETTERHEAD
- if("MessageSyndicate")
- if((src.authenticated==2) && (src.emagged))
- if(centcomm_message_cooldown)
- to_chat(usr, "Arrays recycling. Please stand by.")
- return
- var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", ""))
- if(!input || !(usr in view(1,src)))
- return
- Syndicate_announce(input, usr)
- to_chat(usr, "Message transmitted.")
- log_game("[key_name(usr)] has made an illegal announcement: [input]")
- centcomm_message_cooldown = 1
- spawn(300)//10 minute cooldown
- centcomm_message_cooldown = 0
-
- if("RestoreBackup")
- to_chat(usr, "Backup routing data restored!")
- src.emagged = 0
- src.updateDialog()
-
-
-
- // AI interface
- if("ai-main")
- src.aicurrmsg = 0
- src.aistate = STATE_DEFAULT
- if("ai-callshuttle")
- src.aistate = STATE_CALLSHUTTLE
- if("ai-callshuttle2")
- call_shuttle_proc(usr)
- src.aistate = STATE_DEFAULT
- if("ai-messagelist")
- src.aicurrmsg = 0
- src.aistate = STATE_MESSAGELIST
- if("ai-viewmessage")
- src.aistate = STATE_VIEWMESSAGE
- if (!src.aicurrmsg)
- if(href_list["message-num"])
- src.aicurrmsg = text2num(href_list["message-num"])
- else
- src.aistate = STATE_MESSAGELIST
- if("ai-delmessage")
- src.aistate = (src.aicurrmsg) ? STATE_DELMESSAGE : STATE_MESSAGELIST
- if("ai-delmessage2")
- if(src.aicurrmsg)
- var/title = src.messagetitle[src.aicurrmsg]
- var/text = src.messagetext[src.aicurrmsg]
- src.messagetitle.Remove(title)
- src.messagetext.Remove(text)
- if(src.currmsg == src.aicurrmsg)
- src.currmsg = 0
- src.aicurrmsg = 0
- src.aistate = STATE_MESSAGELIST
- if("ai-status")
- src.aistate = STATE_STATUSDISPLAY
-
- if("securitylevel")
- src.tmp_alertlevel = text2num( href_list["newalertlevel"] )
- if(!tmp_alertlevel) tmp_alertlevel = 0
- state = STATE_CONFIRM_LEVEL
-
- if("changeseclevel")
- state = STATE_ALERT_LEVEL
-
-
-
- src.updateUsrDialog()
+/obj/machinery/computer/communications/Initialize()
+ . = ..()
+ communications = new(src)
/obj/machinery/computer/communications/emag_act(var/remaining_charges, var/mob/user)
if(!emagged)
- src.emagged = 1
+ emagged = TRUE
+ communications.emagged = TRUE
to_chat(user, "You scramble the communication routing circuits!")
- return 1
+ return TRUE
-/obj/machinery/computer/communications/attack_ai(var/mob/user as mob)
- return src.attack_hand(user)
+/obj/machinery/computer/communications/attack_ai(mob/user)
+ return attack_hand(user)
-/obj/machinery/computer/communications/attack_hand(var/mob/user as mob)
+/obj/machinery/computer/communications/attack_hand(mob/user)
if(..())
return
- if (using_map && !(src.z in using_map.contact_levels))
- to_chat(user, "Unable to establish a connection: You're too far away from the station!")
- return
-
- user.set_machine(src)
- var/dat = "Communications Console"
- if (emergency_shuttle.has_eta())
- var/timeleft = emergency_shuttle.estimate_arrival_time()
- dat += "Emergency shuttle\n
\nETA: [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]
"
-
- if (istype(user, /mob/living/silicon))
- var/dat2 = src.interact_ai(user) // give the AI a different interact proc to limit its access
- if(dat2)
- dat += dat2
- user << browse(dat, "window=communications;size=400x500")
- onclose(user, "communications")
- return
-
- switch(src.state)
- if(STATE_DEFAULT)
- if (src.authenticated)
- dat += "
\[ Log Out \]"
- if (src.authenticated==2)
- dat += "
\[ Make An Announcement \]"
- if(src.emagged == 0)
- dat += "
\[ Send an emergency message to [using_map.boss_short] \]"
- else
- dat += "
\[ Send an emergency message to \[UNKNOWN\] \]"
- dat += "
\[ Restore Backup Routing Data \]"
-
- dat += "
\[ Change alert level \]"
- if(emergency_shuttle.location())
- if (emergency_shuttle.online())
- dat += "
\[ Cancel Shuttle Call \]"
- else
- dat += "
\[ Call Emergency Shuttle \]"
-
- dat += "
\[ Set Status Display \]"
- else
- dat += "
\[ Log In \]"
- dat += "
\[ Message List \]"
- dat += "
\[ [ATC.squelched ? "Enable" : "Disable"] ATC Relay \]"
- if(STATE_CALLSHUTTLE)
- dat += "Are you sure you want to call the shuttle? \[ OK | Cancel \]"
- if(STATE_CANCELSHUTTLE)
- dat += "Are you sure you want to cancel the shuttle? \[ OK | Cancel \]"
- if(STATE_MESSAGELIST)
- dat += "Messages:"
- for(var/i = 1; i<=src.messagetitle.len; i++)
- dat += "
[src.messagetitle[i]]"
- if(STATE_VIEWMESSAGE)
- if (src.currmsg)
- dat += "[src.messagetitle[src.currmsg]]
[src.messagetext[src.currmsg]]"
- if (src.authenticated)
- dat += "
\[ Delete \]"
- else
- src.state = STATE_MESSAGELIST
- src.attack_hand(user)
- return
- if(STATE_DELMESSAGE)
- if (src.currmsg)
- dat += "Are you sure you want to delete this message? \[ OK | Cancel \]"
- else
- src.state = STATE_MESSAGELIST
- src.attack_hand(user)
- return
- if(STATE_STATUSDISPLAY)
- dat += "Set Status Displays
"
- dat += "\[ Clear \]
"
- dat += "\[ Station Time \]
"
- dat += "\[ Shuttle ETA \]
"
- dat += "\[ Message \]"
- dat += "
"
- dat += "\[ Alert: None |"
- dat += " Red Alert |"
- dat += " Lockdown |"
- dat += " Biohazard \]
"
- if(STATE_ALERT_LEVEL)
- dat += "Current alert level: [get_security_level()]
"
- if(security_level == SEC_LEVEL_DELTA)
- dat += "The self-destruct mechanism is active. Find a way to deactivate the mechanism to lower the alert level or evacuate."
- else
- dat += "Blue
"
- dat += "Orange
"
- dat += "Violet
"
- dat += "Yellow
"
- dat += "Green"
- if(STATE_CONFIRM_LEVEL)
- dat += "Current alert level: [get_security_level()]
"
- dat += "Confirm the change to: [num2seclevel(tmp_alertlevel)]
"
- dat += "OK to confirm change.
"
-
- dat += "
\[ [(src.state != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]"
- user << browse(dat, "window=communications;size=400x500")
- onclose(user, "communications")
-
-
-
-
-/obj/machinery/computer/communications/proc/interact_ai(var/mob/living/silicon/ai/user as mob)
- var/dat = ""
- switch(src.aistate)
- if(STATE_DEFAULT)
- if(emergency_shuttle.location() && !emergency_shuttle.online())
- dat += "
\[ Call Emergency Shuttle \]"
- dat += "
\[ Message List \]"
- dat += "
\[ Set Status Display \]"
- dat += "
\[ [ATC.squelched ? "Enable" : "Disable"] ATC Relay \]"
- if(STATE_CALLSHUTTLE)
- dat += "Are you sure you want to call the shuttle? \[ OK | Cancel \]"
- if(STATE_MESSAGELIST)
- dat += "Messages:"
- for(var/i = 1; i<=src.messagetitle.len; i++)
- dat += "
[src.messagetitle[i]]"
- if(STATE_VIEWMESSAGE)
- if (src.aicurrmsg)
- dat += "[src.messagetitle[src.aicurrmsg]]
[src.messagetext[src.aicurrmsg]]"
- dat += "
\[ Delete \]"
- else
- src.aistate = STATE_MESSAGELIST
- src.attack_hand(user)
- return null
- if(STATE_DELMESSAGE)
- if(src.aicurrmsg)
- dat += "Are you sure you want to delete this message? \[ OK | Cancel \]"
- else
- src.aistate = STATE_MESSAGELIST
- src.attack_hand(user)
- return
-
- if(STATE_STATUSDISPLAY)
- dat += "Set Status Displays
"
- dat += "\[ Clear \]
"
- dat += "\[ Station Time \]
"
- dat += "\[ Shuttle ETA \]
"
- dat += "\[ Message \]"
- dat += "
"
- dat += "\[ Alert: None |"
- dat += " Red Alert |"
- dat += " Lockdown |"
- dat += " Biohazard \]
"
-
-
- dat += "
\[ [(src.aistate != STATE_DEFAULT) ? "Main Menu | " : ""]Close \]"
- return dat
-
-/proc/enable_prison_shuttle(var/mob/user)
- for(var/obj/machinery/computer/prison_shuttle/PS in machines)
- PS.allowedtocall = !(PS.allowedtocall)
-
-/proc/call_shuttle_proc(var/mob/user)
- if ((!( ticker ) || !emergency_shuttle.location()))
- return
-
- if(!universe.OnShuttleCall(usr))
- to_chat(user, "Cannot establish a bluespace connection.")
- return
-
- if(deathsquad.deployed)
- to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.")
- return
-
- if(emergency_shuttle.deny_shuttle)
- to_chat(user, "The emergency shuttle may not be sent at this time. Please try again later.")
- return
-
- if(world.time < 6000) // Ten minute grace period to let the game get going without lolmetagaming. -- TLE
- to_chat(user, "The emergency shuttle is refueling. Please wait another [round((6000-world.time)/600)] minute\s before trying again.")
- return
-
- if(emergency_shuttle.going_to_centcom())
- to_chat(user, "The emergency shuttle may not be called while returning to [using_map.boss_short].")
- return
-
- if(emergency_shuttle.online())
- to_chat(user, "The emergency shuttle is already on its way.")
- return
-
- if(ticker.mode.name == "blob")
- to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.")
- return
-
- emergency_shuttle.call_evac()
- log_game("[key_name(user)] has called the shuttle.")
- message_admins("[key_name_admin(user)] has called the shuttle.", 1)
- admin_chat_message(message = "Emergency evac beginning! Called by [key_name(user)]!", color = "#CC2222") //VOREStation Add
-
-
- return
-
-/proc/init_shift_change(var/mob/user, var/force = 0)
- if ((!( ticker ) || !emergency_shuttle.location()))
- return
-
- if(emergency_shuttle.going_to_centcom())
- to_chat(user, "The shuttle may not be called while returning to [using_map.boss_short].")
- return
-
- if(emergency_shuttle.online())
- to_chat(user, "The shuttle is already on its way.")
- return
-
- // if force is 0, some things may stop the shuttle call
- if(!force)
- if(emergency_shuttle.deny_shuttle)
- to_chat(user, "[using_map.boss_short] does not currently have a shuttle available in your sector. Please try again later.")
- return
-
- if(deathsquad.deployed == 1)
- to_chat(user, "[using_map.boss_short] will not allow the shuttle to be called. Consider all contracts terminated.")
- return
-
- if(world.time < 54000) // 30 minute grace period to let the game get going
- to_chat(user, "The shuttle is refueling. Please wait another [round((54000-world.time)/60)] minutes before trying again.")
- return
-
- if(ticker.mode.auto_recall_shuttle)
- //New version pretends to call the shuttle but cause the shuttle to return after a random duration.
- emergency_shuttle.auto_recall = 1
-
- if(ticker.mode.name == "blob" || ticker.mode.name == "epidemic")
- to_chat(user, "Under directive 7-10, [station_name()] is quarantined until further notice.")
- return
-
- emergency_shuttle.call_transfer()
-
- //delay events in case of an autotransfer
- if (isnull(user))
- SSevents.delay_events(EVENT_LEVEL_MODERATE, 9000) //15 minutes
- SSevents.delay_events(EVENT_LEVEL_MAJOR, 9000)
-
- log_game("[user? key_name(user) : "Autotransfer"] has called the shuttle.")
- message_admins("[user? key_name_admin(user) : "Autotransfer"] has called the shuttle.", 1)
- admin_chat_message(message = "Autotransfer shuttle dispatched, shift ending soon.", color = "#2277BB") //VOREStation Add
-
- return
-
-/proc/cancel_call_proc(var/mob/user)
- if (!( ticker ) || !emergency_shuttle.can_recall())
- return
- if((ticker.mode.name == "blob")||(ticker.mode.name == "Meteor"))
- return
-
- if(!emergency_shuttle.going_to_centcom()) //check that shuttle isn't already heading to CentCom
- emergency_shuttle.recall()
- log_game("[key_name(user)] has recalled the shuttle.")
- message_admins("[key_name_admin(user)] has recalled the shuttle.", 1)
- return
-
-
-/proc/is_relay_online()
- for(var/obj/machinery/telecomms/relay/M in world)
- if(M.stat == 0)
- return 1
- return 0
-
-/obj/machinery/computer/communications/proc/post_status(var/command, var/data1, var/data2)
-
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
-
- if(!frequency) return
-
- var/datum/signal/status_signal = new
- status_signal.source = src
- status_signal.transmission_method = TRANSMISSION_RADIO
- status_signal.data["command"] = command
-
- switch(command)
- if("message")
- status_signal.data["msg1"] = data1
- status_signal.data["msg2"] = data2
- log_admin("STATUS: [src.fingerprintslast] set status screen message with [src]: [data1] [data2]")
- //message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
- if("alert")
- status_signal.data["picture_state"] = data1
-
- frequency.post_signal(src, status_signal)
+ communications.tgui_interact(user)
diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm
index eb634c249f..1a4ec083df 100644
--- a/code/game/machinery/computer/guestpass.dm
+++ b/code/game/machinery/computer/guestpass.dm
@@ -13,14 +13,14 @@
var/reason = "NOT SPECIFIED"
/obj/item/weapon/card/id/guest/GetAccess()
- if (world.time > expiration_time)
+ if(world.time > expiration_time)
return access
else
return temp_access
/obj/item/weapon/card/id/guest/examine(mob/user)
. = ..()
- if (world.time < expiration_time)
+ if(world.time < expiration_time)
. += "This pass expires at [worldtime2stationtime(expiration_time)]."
else
. += "It expired at [worldtime2stationtime(expiration_time)]."
@@ -28,7 +28,7 @@
/obj/item/weapon/card/id/guest/read()
if(!Adjacent(usr))
return //Too far to read
- if (world.time > expiration_time)
+ if(world.time > expiration_time)
to_chat(usr, "This pass expired at [worldtime2stationtime(expiration_time)].")
else
to_chat(usr, "This pass expires at [worldtime2stationtime(expiration_time)].")
@@ -105,7 +105,7 @@
if(!giver && user.unEquip(I))
I.forceMove(src)
giver = I
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
else if(giver)
to_chat(user, "There is already ID card inside.")
return
@@ -119,128 +119,119 @@
return
user.set_machine(src)
+ tgui_interact(user)
- ui_interact(user)
+/obj/machinery/computer/guestpass/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "GuestPass", name)
+ ui.open()
-/**
- * Display the NanoUI window for the guest pass console.
- *
- * See NanoUI documentation for details.
- */
-/obj/machinery/computer/guestpass/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- user.set_machine(src)
+/obj/machinery/computer/guestpass/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- var/list/data = list()
+ var/list/area_list = list()
- var/area_list[0]
-
- if (giver && giver.access)
+ data["access"] = null
+ if(giver && giver.access)
data["access"] = giver.access
for (var/A in giver.access)
if(A in accesses)
- area_list[++area_list.len] = list("area" = A, "area_name" = get_access_desc(A), "on" = 1)
+ area_list.Add(list(list("area" = A, "area_name" = get_access_desc(A), "on" = 1)))
else
- area_list[++area_list.len] = list("area" = A, "area_name" = get_access_desc(A), "on" = null)
+ area_list.Add(list(list("area" = A, "area_name" = get_access_desc(A), "on" = null)))
+ data["area"] = area_list
data["giver"] = giver
data["giveName"] = giv_name
data["reason"] = reason
data["duration"] = duration
- data["area"] = area_list
data["mode"] = mode
data["log"] = internal_log
data["uid"] = uid
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "guest_pass.tmpl", src.name, 400, 520)
- ui.set_initial_data(data)
- ui.open()
- //ui.set_auto_update(5)
+ return data
-/obj/machinery/computer/guestpass/Topic(href, href_list)
+/obj/machinery/computer/guestpass/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
- usr.set_machine(src)
- if (href_list["mode"])
- mode = href_list["mode"]
+ return TRUE
- if (href_list["choice"])
- switch(href_list["choice"])
- if ("giv_name")
- var/nam = sanitizeName(input("Person pass is issued to", "Name", giv_name) as text|null)
- if (nam)
- giv_name = nam
- if ("reason")
- var/reas = sanitize(input("Reason why pass is issued", "Reason", reason) as text|null)
- if(reas)
- reason = reas
- if ("duration")
- var/dur = input("Duration (in minutes) during which pass is valid (up to 120 minutes).", "Duration") as num|null
- if (dur)
- if (dur > 0 && dur <= 120)
- duration = dur
- else
- to_chat(usr, "Invalid duration.")
- if ("access")
- var/A = text2num(href_list["access"])
- if (A in accesses)
- accesses.Remove(A)
+ switch(action)
+ if("mode")
+ mode = params["mode"]
+
+ if("giv_name")
+ var/nam = sanitizeName(input("Person pass is issued to", "Name", giv_name) as text|null)
+ if(nam)
+ giv_name = nam
+ if("reason")
+ var/reas = sanitize(input("Reason why pass is issued", "Reason", reason) as text|null)
+ if(reas)
+ reason = reas
+ if("duration")
+ var/dur = input("Duration (in minutes) during which pass is valid (up to 120 minutes).", "Duration") as num|null
+ if(dur)
+ if(dur > 0 && dur <= 120)
+ duration = dur
else
- if(A in giver.access) //Let's make sure the ID card actually has the access.
- accesses.Add(A)
- else
- to_chat(usr, "Invalid selection, please consult technical support if there are any issues.")
- log_debug("[key_name_admin(usr)] tried selecting an invalid guest pass terminal option.")
- if (href_list["action"])
- switch(href_list["action"])
- if ("id")
- if (giver)
- if(ishuman(usr))
- giver.loc = usr.loc
- if(!usr.get_active_hand())
- usr.put_in_hands(giver)
- giver = null
- else
- giver.loc = src.loc
- giver = null
- accesses.Cut()
+ to_chat(usr, "Invalid duration.")
+ if("access")
+ var/A = text2num(params["access"])
+ if(A in accesses)
+ accesses.Remove(A)
+ else
+ if(A in giver.access) //Let's make sure the ID card actually has the access.
+ accesses.Add(A)
else
- var/obj/item/I = usr.get_active_hand()
- if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
- I.loc = src
- giver = I
-
- if ("print")
- var/dat = "Activity log of guest pass terminal #[uid]
"
- for (var/entry in internal_log)
- dat += "[entry]
"
- //to_chat(usr, "Printing the log, standby...")
- //sleep(50)
- var/obj/item/weapon/paper/P = new/obj/item/weapon/paper( loc )
- P.name = "activity log"
- P.info = dat
-
- if ("issue")
- if (giver)
- var/number = add_zero("[rand(0,9999)]", 4)
- var/entry = "\[[stationtime2text()]\] Pass #[number] issued by [giver.registered_name] ([giver.assignment]) to [giv_name]. Reason: [reason]. Grants access to following areas: "
- for (var/i=1 to accesses.len)
- var/A = accesses[i]
- if (A)
- var/area = get_access_desc(A)
- entry += "[i > 1 ? ", [area]" : "[area]"]"
- entry += ". Expires at [worldtime2stationtime(world.time + duration*10*60)]."
- internal_log.Add(entry)
-
- var/obj/item/weapon/card/id/guest/pass = new(src.loc)
- pass.temp_access = accesses.Copy()
- pass.registered_name = giv_name
- pass.expiration_time = world.time + duration*10*60
- pass.reason = reason
- pass.name = "guest pass #[number]"
+ to_chat(usr, "Invalid selection, please consult technical support if there are any issues.")
+ log_debug("[key_name_admin(usr)] tried selecting an invalid guest pass terminal option.")
+ if("id")
+ if(giver)
+ if(ishuman(usr))
+ giver.loc = usr.loc
+ if(!usr.get_active_hand())
+ usr.put_in_hands(giver)
+ giver = null
else
- to_chat(usr, "Cannot issue pass without issuing ID.")
+ giver.loc = src.loc
+ giver = null
+ accesses.Cut()
+ else
+ var/obj/item/I = usr.get_active_hand()
+ if(istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
+ I.loc = src
+ giver = I
- src.add_fingerprint(usr)
- SSnanoui.update_uis(src)
\ No newline at end of file
+ if("print")
+ var/dat = "Activity log of guest pass terminal #[uid]
"
+ for (var/entry in internal_log)
+ dat += "[entry]
"
+ //to_chat(usr, "Printing the log, standby...")
+ //sleep(50)
+ var/obj/item/weapon/paper/P = new/obj/item/weapon/paper( loc )
+ P.name = "activity log"
+ P.info = dat
+
+ if("issue")
+ if(giver)
+ var/number = add_zero("[rand(0,9999)]", 4)
+ var/entry = "\[[stationtime2text()]\] Pass #[number] issued by [giver.registered_name] ([giver.assignment]) to [giv_name]. Reason: [reason]. Grants access to following areas: "
+ for (var/i=1 to accesses.len)
+ var/A = accesses[i]
+ if(A)
+ var/area = get_access_desc(A)
+ entry += "[i > 1 ? ", [area]" : "[area]"]"
+ entry += ". Expires at [worldtime2stationtime(world.time + duration*10*60)]."
+ internal_log.Add(entry)
+
+ var/obj/item/weapon/card/id/guest/pass = new(src.loc)
+ pass.temp_access = accesses.Copy()
+ pass.registered_name = giv_name
+ pass.expiration_time = world.time + duration*10*60
+ pass.reason = reason
+ pass.name = "guest pass #[number]"
+ else
+ to_chat(usr, "Cannot issue pass without issuing ID.")
+
+ add_fingerprint(usr)
+ return TRUE
\ No newline at end of file
diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm
index 1dc0709ed3..1caa7b61a4 100644
--- a/code/game/machinery/computer/message.dm
+++ b/code/game/machinery/computer/message.dm
@@ -131,7 +131,10 @@
//Get out list of viable PDAs
var/list/obj/item/device/pda/sendPDAs = list()
for(var/obj/item/device/pda/P in PDAs)
- if(!P.owner || P.toff || P.hidden)
+ if(!P.owner || P.hidden)
+ continue
+ var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger)
+ if(!M || M.toff)
continue
sendPDAs["[P.name]"] = "\ref[P]"
data["possibleRecipients"] = sendPDAs
@@ -265,7 +268,11 @@
if("set_recipient")
var/ref = params["val"]
var/obj/item/device/pda/P = locate(ref)
- if(!istype(P) || !P.owner || P.toff || P.hidden)
+ if(!istype(P) || !P.owner || P.hidden)
+ return FALSE
+
+ var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger)
+ if(!M || M.toff)
return FALSE
customrecepient = P
. = TRUE
@@ -286,22 +293,26 @@
var/obj/item/device/pda/PDARec = null
for(var/obj/item/device/pda/P in PDAs)
- if(!P.owner || P.toff || P.hidden) continue
+ if(!P.owner || P.hidden)
+ continue
+ var/datum/data/pda/app/messenger/M = P.find_program(/datum/data/pda/app/messenger)
+ if(!M || M.toff)
+ continue
if(P.owner == customsender)
PDARec = P
//Sender isn't faking as someone who exists
if(isnull(PDARec))
linkedServer.send_pda_message("[customrecepient.owner]", "[customsender]","[custommessage]")
- customrecepient.new_message(customsender, customsender, customjob, custommessage)
+ var/datum/data/pda/app/messenger/M = customrecepient.find_program(/datum/data/pda/app/messenger)
+ if(M)
+ M.receive_message(list("sent" = 0, "owner" = customsender, "job" = customjob, "message" = custommessage), null)
//Sender is faking as someone who exists
else
linkedServer.send_pda_message("[customrecepient.owner]", "[PDARec.owner]","[custommessage]")
- customrecepient.tnote.Add(list(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" ="\ref[PDARec]")))
-
- if(!customrecepient.conversations.Find("\ref[PDARec]"))
- customrecepient.conversations.Add("\ref[PDARec]")
-
- customrecepient.new_message(PDARec, custommessage)
+
+ var/datum/data/pda/app/messenger/M = customrecepient.find_program(/datum/data/pda/app/messenger)
+ if(M)
+ M.receive_message(list("sent" = 0, "owner" = "[PDARec.owner]", "job" = "[customjob]", "message" = "[custommessage]", "target" = "\ref[PDARec]"), "\ref[PDARec]")
//Finally..
ResetMessage()
. = TRUE
diff --git a/code/game/machinery/computer/timeclock_vr.dm b/code/game/machinery/computer/timeclock_vr.dm
index a94b338320..8cfc711c18 100644
--- a/code/game/machinery/computer/timeclock_vr.dm
+++ b/code/game/machinery/computer/timeclock_vr.dm
@@ -55,7 +55,7 @@
if(!card && user.unEquip(I))
I.forceMove(src)
card = I
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
update_icon()
else if(card)
to_chat(user, "There is already ID card inside.")
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 7eb9e4a342..014efcb581 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -851,11 +851,13 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/attack_ghost(mob/user)
tgui_interact(user)
-/obj/machinery/door/airlock/tgui_interact(mob/user, datum/tgui/ui)
+/obj/machinery/door/airlock/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/tgui_state/custom_state)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "AiAirlock", name)
ui.open()
+ if(custom_state)
+ ui.set_state(custom_state)
return TRUE
/obj/machinery/door/airlock/tgui_data(mob/user)
diff --git a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm
index ef6367758f..9e65c06bcd 100644
--- a/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm
+++ b/code/game/machinery/embedded_controller/airlock_controllers_dummy.dm
@@ -7,7 +7,6 @@
layer = ABOVE_OBJ_LAYER
var/id_tag
- var/datum/topic_state/remote/remote_state
var/obj/machinery/embedded_controller/radio/airlock/master_controller
/obj/machinery/dummy_airlock_controller/process()
@@ -25,15 +24,10 @@
break
if(!master_controller)
qdel(src)
- else
- remote_state = new /datum/topic_state/remote(src, master_controller)
/obj/machinery/dummy_airlock_controller/Destroy()
if(master_controller)
master_controller.dummy_terminals -= src
- if(remote_state)
- qdel(remote_state)
- remote_state = null
return ..()
/obj/machinery/dummy_airlock_controller/interface_interact(var/mob/user)
diff --git a/code/game/machinery/jukebox.dm b/code/game/machinery/jukebox.dm
index 00a8e68760..e8e741b578 100644
--- a/code/game/machinery/jukebox.dm
+++ b/code/game/machinery/jukebox.dm
@@ -192,7 +192,6 @@
if(inoperable())
to_chat(usr, "\The [src] doesn't appear to function.")
return
- ui_interact(user)
tgui_interact(user)
/obj/machinery/media/jukebox/tgui_status(mob/user)
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 05e2256d9d..de85f95e9a 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -101,22 +101,22 @@
NEWSCASTER.newsAlert(annoncement)
NEWSCASTER.update_icon()
- var/list/receiving_pdas = new
- for (var/obj/item/device/pda/P in PDAs)
- if(!P.owner)
- continue
- if(P.toff)
- continue
- receiving_pdas += P
+ // var/list/receiving_pdas = new
+ // for (var/obj/item/device/pda/P in PDAs)
+ // if(!P.owner)
+ // continue
+ // if(P.toff)
+ // continue
+ // receiving_pdas += P
- spawn(0) // get_receptions sleeps further down the line, spawn of elsewhere
- var/datum/receptions/receptions = get_receptions(null, receiving_pdas) // datums are not atoms, thus we have to assume the newscast network always has reception
+ // spawn(0) // get_receptions sleeps further down the line, spawn of elsewhere
+ // var/datum/receptions/receptions = get_receptions(null, receiving_pdas) // datums are not atoms, thus we have to assume the newscast network always has reception
- for(var/obj/item/device/pda/PDA in receiving_pdas)
- if(!(receptions.receiver_reception[PDA] & TELECOMMS_RECEPTION_RECEIVER))
- continue
+ // for(var/obj/item/device/pda/PDA in receiving_pdas)
+ // if(!(receptions.receiver_reception[PDA] & TELECOMMS_RECEPTION_RECEIVER))
+ // continue
- PDA.new_news(annoncement)
+ // PDA.new_news(annoncement)
var/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list.
diff --git a/code/game/machinery/oxygen_pump.dm b/code/game/machinery/oxygen_pump.dm
index 37c75957be..f7821a4e84 100644
--- a/code/game/machinery/oxygen_pump.dm
+++ b/code/game/machinery/oxygen_pump.dm
@@ -79,7 +79,7 @@
update_use_power(USE_POWER_IDLE)
/obj/machinery/oxygen_pump/attack_ai(mob/user as mob)
- ui_interact(user)
+ tgui_interact(user)
/obj/machinery/oxygen_pump/proc/attach_mask(var/mob/living/carbon/C)
if(C && istype(C))
@@ -176,61 +176,60 @@
set src in oview(1)
set category = "Object"
set name = "Show Tank Settings"
- ui_interact(usr)
+ tgui_interact(usr)
-//GUI Tank Setup
-/obj/machinery/oxygen_pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- var/data[0]
+/obj/machinery/oxygen_pump/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
if(!tank)
- to_chat(usr, "It is missing a tank!")
- data["tankPressure"] = 0
- data["releasePressure"] = 0
- data["defaultReleasePressure"] = 0
- data["maxReleasePressure"] = 0
- data["maskConnected"] = 0
- data["tankInstalled"] = 0
- // this is the data which will be sent to the ui
+ to_chat(user, "[src] is missing a tank.")
+ if(ui)
+ ui.close()
+ return
+
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Tank", name)
+ ui.open()
+
+/obj/machinery/oxygen_pump/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
+ data["showToggle"] = FALSE
+ data["maskConnected"] = !!breather
+
+ data["tankPressure"] = 0
+ data["releasePressure"] = 0
+ data["defaultReleasePressure"] = 0
+ data["minReleasePressure"] = 0
+ data["releasePressure"] = round(tank.distribute_pressure ? tank.distribute_pressure : 0)
+ data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE)
+
if(tank)
data["tankPressure"] = round(tank.air_contents.return_pressure() ? tank.air_contents.return_pressure() : 0)
- data["releasePressure"] = round(tank.distribute_pressure ? tank.distribute_pressure : 0)
data["defaultReleasePressure"] = round(TANK_DEFAULT_RELEASE_PRESSURE)
- data["maxReleasePressure"] = round(TANK_MAX_RELEASE_PRESSURE)
- data["maskConnected"] = 0
- data["tankInstalled"] = 1
- if(!breather)
- data["maskConnected"] = 0
- if(breather)
- data["maskConnected"] = 1
+ return data
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "Oxygen_pump.tmpl", "Tank", 500, 300)
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(1)
-
-/obj/machinery/oxygen_pump/Topic(href, href_list)
+/obj/machinery/oxygen_pump/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
+ return TRUE
- if (href_list["dist_p"])
- if (href_list["dist_p"] == "reset")
- tank.distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE
- else if (href_list["dist_p"] == "max")
- tank.distribute_pressure = TANK_MAX_RELEASE_PRESSURE
- else
- var/cp = text2num(href_list["dist_p"])
- tank.distribute_pressure += cp
- tank.distribute_pressure = min(max(round(tank.distribute_pressure), 0), TANK_MAX_RELEASE_PRESSURE)
- return 1
+ switch(action)
+ if("pressure")
+ var/pressure = params["pressure"]
+ if(pressure == "reset")
+ pressure = TANK_DEFAULT_RELEASE_PRESSURE
+ . = TRUE
+ else if(pressure == "min")
+ pressure = 0
+ . = TRUE
+ else if(pressure == "max")
+ pressure = TANK_MAX_RELEASE_PRESSURE
+ . = TRUE
+ else if(text2num(pressure) != null)
+ pressure = text2num(pressure)
+ . = TRUE
+ if(.)
+ tank.distribute_pressure = clamp(round(pressure), 0, TANK_MAX_RELEASE_PRESSURE)
/obj/machinery/oxygen_pump/anesthetic
name = "anesthetic pump"
diff --git a/code/game/machinery/partslathe_vr.dm b/code/game/machinery/partslathe_vr.dm
index aab15f40f9..c5ddcff900 100644
--- a/code/game/machinery/partslathe_vr.dm
+++ b/code/game/machinery/partslathe_vr.dm
@@ -233,7 +233,6 @@
/obj/machinery/partslathe/attack_hand(mob/user)
if(..())
return
- ui_interact(user)
tgui_interact(user)
/obj/machinery/partslathe/ui_assets(mob/user)
diff --git a/code/game/machinery/pda_multicaster.dm b/code/game/machinery/pda_multicaster.dm
index 20e870d3d0..a70f1ede37 100644
--- a/code/game/machinery/pda_multicaster.dm
+++ b/code/game/machinery/pda_multicaster.dm
@@ -63,7 +63,9 @@
/obj/machinery/pda_multicaster/proc/update_PDAs(var/turn_off)
for(var/obj/item/device/pda/pda in contents)
- pda.toff = turn_off
+ var/datum/data/pda/app/messenger/M = pda.find_program(/datum/data/pda/app/messenger/multicast)
+ if(M)
+ M.toff = turn_off
/obj/machinery/pda_multicaster/proc/update_power()
if(toggle)
diff --git a/code/game/machinery/pointdefense.dm b/code/game/machinery/pointdefense.dm
index 8eeb73fbc5..5b10e398a3 100644
--- a/code/game/machinery/pointdefense.dm
+++ b/code/game/machinery/pointdefense.dm
@@ -95,7 +95,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
/obj/machinery/pointdefense_control/attackby(var/obj/item/W, var/mob/user)
if(W?.is_multitool())
var/new_ident = input(user, "Enter a new ident tag.", "[src]", id_tag) as null|text
- if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, physical_state))
+ if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.tgui_physical_state))
// Check for duplicate controllers with this ID
for(var/thing in pointdefense_controllers)
var/obj/machinery/pointdefense_control/PC = thing
@@ -211,7 +211,7 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
/obj/machinery/power/pointdefense/attackby(var/obj/item/W, var/mob/user)
if(W?.is_multitool())
var/new_ident = input(user, "Enter a new ident tag.", "[src]", id_tag) as null|text
- if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, physical_state))
+ if(new_ident && new_ident != id_tag && user.Adjacent(src) && CanInteract(user, GLOB.tgui_physical_state))
to_chat(user, "You register [src] with the [new_ident] network.")
id_tag = new_ident
return
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index 1ed44c61bc..01a890bd79 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -66,6 +66,7 @@
var/last_fired = FALSE //TRUE: if the turret is cooling down from a shot, FALSE: turret is ready to fire
var/shot_delay = 1.5 SECONDS //1.5 seconds between each shot
+ var/targetting_is_configurable = TRUE // if false, you cannot change who this turret attacks via its UI
var/check_arrest = TRUE //checks if the perp is set to arrest
var/check_records = TRUE //checks if a security record exists at all
var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have
@@ -81,6 +82,7 @@
var/enabled = TRUE //determines if the turret is on
var/lethal = FALSE //whether in lethal or stun mode
+ var/lethal_is_configurable = TRUE // if false, its lethal setting cannot be changed
var/disabled = FALSE
var/shot_sound //what sound should play when the turret fires
@@ -214,6 +216,9 @@
req_one_access = list()
installation = /obj/item/weapon/gun/energy/lasertag/omni
+ targetting_is_configurable = FALSE
+ lethal_is_configurable = FALSE
+
locked = FALSE
enabled = FALSE
anchored = FALSE
@@ -262,43 +267,14 @@
if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag) && check_weapons) // Checks if they are a blue player
return TURRET_PRIORITY_TARGET
-/obj/machinery/porta_turret/lasertag/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- var/data[0]
- data["access"] = !isLocked(user)
- data["locked"] = locked
- data["enabled"] = enabled
- //data["is_lethal"] = 1 // VOREStation Removal of "Lethal" setting - it does nothing. Rykka did dis.
- //data["lethal"] = lethal // VOREStation Removal of "Lethal" setting - it does nothing. Rykka did dis.
-
- if(data["access"])
- var/settings[0]
- settings[++settings.len] = list("category" = "Target Red", "setting" = "check_synth", "value" = check_synth) // Could not get the UI to work with new vars specifically for lasertag turrets -Nalarac
- settings[++settings.len] = list("category" = "Target Blue", "setting" = "check_weapons", "value" = check_weapons) // So I'm using these variables since they don't do anything else in this case
- data["settings"] = settings
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
-
-/obj/machinery/porta_turret/lasertag/Topic(href, href_list)
- if(..())
- return 1
-
- if(href_list["command"] && href_list["value"])
- var/value = text2num(href_list["value"])
- if(href_list["command"] == "enable")
- enabled = value
- //else if(href_list["command"] == "lethal") // VOREStation Removal of "Lethal" setting - it does nothing. Rykka did dis.
- //lethal = value // VOREStation Removal of "Lethal" setting - it does nothing. Rykka did dis.
- else if(href_list["command"] == "check_synth")
- check_synth = value
- else if(href_list["command"] == "check_weapons")
- check_weapons = value
-
- return 1
+/obj/machinery/porta_turret/lasertag/tgui_data(mob/user)
+ var/list/data = list(
+ "locked" = isLocked(user), // does the current user have access?
+ "on" = enabled, // is turret turned on?
+ "lethal" = lethal,
+ "lethal_is_configurable" = lethal_is_configurable
+ )
+ return data
/obj/machinery/porta_turret/Initialize()
//Sets up a spark system
@@ -401,102 +377,99 @@
lethal_shot_sound = 'sound/weapons/eluger.ogg'
shot_sound = 'sound/weapons/Taser.ogg'
-/obj/machinery/porta_turret/proc/isLocked(mob/user)
- if(ailock && issilicon(user))
- to_chat(user, "There seems to be a firewall preventing you from accessing this device.")
- return 1
-
- if(locked && !issilicon(user))
- to_chat(user, "Controls locked.")
- return 1
-
- return 0
-
-/obj/machinery/porta_turret/attack_ai(mob/user)
- if(isLocked(user))
- return
-
- ui_interact(user)
-
-/obj/machinery/porta_turret/attack_hand(mob/user)
- if(isLocked(user))
- return
-
- ui_interact(user)
-
-/obj/machinery/porta_turret/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- var/data[0]
- data["access"] = !isLocked(user)
- data["locked"] = locked
- data["enabled"] = enabled
- data["is_lethal"] = 1
- data["lethal"] = lethal
-
- if(data["access"])
- var/settings[0]
- settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth)
- settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons)
- settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records)
- settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest)
- settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access)
- settings[++settings.len] = list("category" = "Check misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies)
- settings[++settings.len] = list("category" = "Neutralize All Entities", "setting" = "check_all", "value" = check_all)
- settings[++settings.len] = list("category" = "Neutralize Downed Entities", "setting" = "check_down", "value" = check_down)
- data["settings"] = settings
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
-
/obj/machinery/porta_turret/proc/HasController()
var/area/A = get_area(src)
return A && A.turret_controls.len > 0
-/obj/machinery/porta_turret/CanUseTopic(var/mob/user)
+/obj/machinery/porta_turret/proc/isLocked(mob/user)
if(HasController())
- to_chat(user, "Turrets can only be controlled using the assigned turret controller.")
- return STATUS_CLOSE
+ return TRUE
+ if(isrobot(user) || isAI(user))
+ if(ailock)
+ to_chat(user, "There seems to be a firewall preventing you from accessing this device.")
+ return TRUE
+ else
+ return FALSE
+ if(isobserver(user))
+ var/mob/observer/dead/D = user
+ if(D.can_admin_interact())
+ return FALSE
+ else
+ return TRUE
+ if(locked)
+ return TRUE
+ return FALSE
- if(isLocked(user))
- return STATUS_CLOSE
+/obj/machinery/porta_turret/attack_ai(mob/user)
+ tgui_interact(user)
+/obj/machinery/porta_turret/attack_ghost(mob/user)
+ tgui_interact(user)
+
+/obj/machinery/porta_turret/attack_hand(mob/user)
+ tgui_interact(user)
+
+/obj/machinery/porta_turret/tgui_interact(mob/user, datum/tgui/ui = null)
+ if(HasController())
+ to_chat(user, "[src] can only be controlled using the assigned turret controller.")
+ return
if(!anchored)
- to_chat(user, "\The [src] has to be secured first!")
- return STATUS_CLOSE
+ to_chat(user, "[src] has to be secured first!")
+ return
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "PortableTurret", name, 500, 400)
+ ui.open()
- return ..()
+/obj/machinery/porta_turret/tgui_data(mob/user)
+ var/list/data = list(
+ "locked" = isLocked(user), // does the current user have access?
+ "on" = enabled,
+ "targetting_is_configurable" = targetting_is_configurable, // If false, targetting settings don't show up
+ "lethal" = lethal,
+ "lethal_is_configurable" = lethal_is_configurable,
+ "check_weapons" = check_weapons,
+ "neutralize_noaccess" = check_access,
+ "neutralize_norecord" = check_records,
+ "neutralize_criminals" = check_arrest,
+ "neutralize_all" = check_all,
+ "neutralize_nonsynth" = check_synth,
+ "neutralize_unidentified" = check_anomalies,
+ "neutralize_down" = check_down,
+ )
+ return data
-/obj/machinery/porta_turret/Topic(href, href_list)
+/obj/machinery/porta_turret/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
+ return TRUE
+ if(isLocked(usr))
+ return TRUE
+ . = TRUE
- if(href_list["command"] && href_list["value"])
- var/value = text2num(href_list["value"])
- if(href_list["command"] == "enable")
- enabled = value
- else if(href_list["command"] == "lethal")
- lethal = value
- else if(href_list["command"] == "check_synth")
- check_synth = value
- else if(href_list["command"] == "check_weapons")
- check_weapons = value
- else if(href_list["command"] == "check_records")
- check_records = value
- else if(href_list["command"] == "check_arrest")
- check_arrest = value
- else if(href_list["command"] == "check_access")
- check_access = value
- else if(href_list["command"] == "check_anomalies")
- check_anomalies = value
- else if(href_list["command"] == "check_all")
- check_all = value
- else if(href_list["command"] == "check_down")
- check_down = value
-
- return 1
+ switch(action)
+ if("power")
+ enabled = !enabled
+ if("lethal")
+ if(lethal_is_configurable)
+ lethal = !lethal
+ if(targetting_is_configurable)
+ switch(action)
+ if("authweapon")
+ check_weapons = !check_weapons
+ if("authaccess")
+ check_access = !check_access
+ if("authnorecord")
+ check_records = !check_records
+ if("autharrest")
+ check_arrest = !check_arrest
+ if("authxeno")
+ check_anomalies = !check_anomalies
+ if("authsynth")
+ check_synth = !check_synth
+ if("authall")
+ check_all = !check_all
+ if("authdown")
+ check_down = !check_down
/obj/machinery/porta_turret/power_change()
if(powered())
@@ -929,6 +902,7 @@
var/check_weapons
var/check_anomalies
var/check_all
+ var/check_down
var/ailock
/obj/machinery/porta_turret/proc/setState(var/datum/turret_checks/TC)
@@ -944,6 +918,7 @@
check_weapons = TC.check_weapons
check_anomalies = TC.check_anomalies
check_all = TC.check_all
+ check_down = TC.check_down
ailock = TC.ailock
power_change()
diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm
index 75b78d4114..c205395199 100644
--- a/code/game/machinery/recharger.dm
+++ b/code/game/machinery/recharger.dm
@@ -93,6 +93,8 @@
return
/obj/machinery/recharger/attack_hand(mob/user as mob)
+ if(!Adjacent(user))
+ return FALSE
add_fingerprint(user)
if(charging)
diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm
index e87de196d9..86b339e6d5 100644
--- a/code/game/machinery/requests_console.dm
+++ b/code/game/machinery/requests_console.dm
@@ -104,7 +104,6 @@ var/list/obj/machinery/requests_console/allConsoles = list()
/obj/machinery/requests_console/attack_hand(user as mob)
if(..(user))
return
- ui_interact(user)
tgui_interact(user)
/obj/machinery/requests_console/tgui_interact(mob/user, datum/tgui/ui)
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 4e30affc1a..87d2ca9b44 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -602,37 +602,37 @@
name = "Engineering suit cycler"
model_text = "Engineering"
req_access = list(access_construction)
- departments = list("Engineering","Atmospherics","HAZMAT","Construction")
+ departments = list("Engineering","Atmospherics","HAZMAT","Construction","No Change")
/obj/machinery/suit_cycler/mining
name = "Mining suit cycler"
model_text = "Mining"
req_access = list(access_mining)
- departments = list("Mining")
+ departments = list("Mining","No Change")
/obj/machinery/suit_cycler/security
name = "Security suit cycler"
model_text = "Security"
req_access = list(access_security)
- departments = list("Security","Crowd Control","Security EVA")
+ departments = list("Security","Crowd Control","Security EVA","No Change")
/obj/machinery/suit_cycler/medical
name = "Medical suit cycler"
model_text = "Medical"
req_access = list(access_medical)
- departments = list("Medical","Biohazard","Emergency Medical Response")
+ departments = list("Medical","Biohazard","Emergency Medical Response","No Change")
/obj/machinery/suit_cycler/syndicate
name = "Nonstandard suit cycler"
model_text = "Nonstandard"
req_access = list(access_syndicate)
- departments = list("Mercenary", "Charring")
+ departments = list("Mercenary", "Charring","No Change")
can_repair = 1
/obj/machinery/suit_cycler/exploration
name = "Explorer suit cycler"
model_text = "Exploration"
- departments = list("Exploration","Old Exploration")
+ departments = list("Exploration","Old Exploration","No Change")
/obj/machinery/suit_cycler/exploration/Initialize()
species -= SPECIES_TESHARI
@@ -641,33 +641,33 @@
/obj/machinery/suit_cycler/pilot
name = "Pilot suit cycler"
model_text = "Pilot"
- departments = list("Pilot Blue","Pilot")
+ departments = list("Pilot Blue","Pilot","No Change")
/obj/machinery/suit_cycler/vintage
name = "Vintage Crew suit cycler"
model_text = "Vintage"
- departments = list("Vintage Crew")
+ departments = list("Vintage Crew","No Change")
req_access = null
/obj/machinery/suit_cycler/vintage/pilot
name = "Vintage Pilot suit cycler"
model_text = "Vintage Pilot"
- departments = list("Vintage Pilot (Bubble Helm)","Vintage Pilot (Closed Helm)")
+ departments = list("Vintage Pilot (Bubble Helm)","Vintage Pilot (Closed Helm)","No Change")
/obj/machinery/suit_cycler/vintage/medsci
name = "Vintage MedSci suit cycler"
model_text = "Vintage MedSci"
- departments = list("Vintage Medical (Bubble Helm)","Vintage Medical (Closed Helm)","Vintage Research (Bubble Helm)","Vintage Research (Closed Helm)")
+ departments = list("Vintage Medical (Bubble Helm)","Vintage Medical (Closed Helm)","Vintage Research (Bubble Helm)","Vintage Research (Closed Helm)","No Change")
/obj/machinery/suit_cycler/vintage/rugged
name = "Vintage Ruggedized suit cycler"
model_text = "Vintage Ruggedized"
- departments = list("Vintage Engineering","Vintage Marine","Vintage Officer","Vintage Mercenary")
+ departments = list("Vintage Engineering","Vintage Marine","Vintage Officer","Vintage Mercenary","No Change")
/obj/machinery/suit_cycler/vintage/omni
name = "Vintage Master suit cycler"
model_text = "Vintage Master"
- departments = list("Vintage Crew","Vintage Engineering","Vintage Pilot (Bubble Helm)","Vintage Pilot (Closed Helm)","Vintage Medical (Bubble Helm)","Vintage Medical (Closed Helm)","Vintage Research (Bubble Helm)","Vintage Research (Closed Helm)","Vintage Marine","Vintage Officer","Vintage Mercenary")
+ departments = list("Vintage Crew","Vintage Engineering","Vintage Pilot (Bubble Helm)","Vintage Pilot (Closed Helm)","Vintage Medical (Bubble Helm)","Vintage Medical (Closed Helm)","Vintage Research (Bubble Helm)","Vintage Research (Closed Helm)","Vintage Marine","Vintage Officer","Vintage Mercenary","No Change")
/obj/machinery/suit_cycler/vintage/Initialize()
species -= SPECIES_TESHARI
@@ -1049,17 +1049,9 @@
/obj/machinery/suit_cycler/proc/apply_paintjob()
var/obj/item/clothing/head/helmet/parent_helmet
var/obj/item/clothing/suit/space/parent_suit
-
+ var/turf/T = get_turf(src)
if(!target_species || !target_department)
return
-
- if(target_species)
- if(helmet) helmet.refit_for_species(target_species)
- if(suit)
- suit.refit_for_species(target_species)
- if(suit.helmet)
- suit.helmet.refit_for_species(target_species)
-
//Now "Complete" with most departmental and variant suits, and sorted by department. These aren't available in the standard or emagged cycler lists because they're incomplete for most species.
switch(target_department)
if("No Change")
@@ -1217,7 +1209,32 @@
parent_suit = /obj/item/clothing/suit/space/void/refurb/mercenary/talon
//VOREStation Addition End
//END: downstream variant space
-
+ if(target_species)
+ //Only run these checks if they have a sprite sheet defined, otherwise they use human's anyways, and there is almost definitely a sprite.
+ if((helmet!=null&&(target_species in helmet.sprite_sheets_obj))||(suit!=null&&(target_species in suit.sprite_sheets_obj)))
+ //Making sure all of our items have the sprites to be refitted.
+ var/helmet_check = ((helmet!=null && (initial(parent_helmet.icon_state) in icon_states(helmet.sprite_sheets_obj[target_species],1))) || helmet==null)
+ //If the helmet exists, only return true if there's also sprites for it. If the helmet doesn't exist, return true.
+ var/suit_check = ((suit!=null && (initial(parent_suit.icon_state) in icon_states(suit.sprite_sheets_obj[target_species],1))) || suit==null)
+ var/suit_helmet_check = ((suit!=null && suit.helmet!=null && (initial(parent_helmet.icon_state) in icon_states(suit.helmet.sprite_sheets_obj[target_species],1))) || suit==null || suit.helmet==null)
+ if(helmet_check && suit_check && suit_helmet_check)
+ if(helmet)
+ helmet.refit_for_species(target_species)
+ if(suit)
+ suit.refit_for_species(target_species)
+ if(suit.helmet)
+ suit.helmet.refit_for_species(target_species)
+ else
+ //If they don't, alert the user and stop here.
+ T.visible_message("[bicon(src)]Unable to apply specified cosmetics with specified species. Please try again with a different species or cosmetic option selected.")
+ return
+ else
+ if(helmet)
+ helmet.refit_for_species(target_species)
+ if(suit)
+ suit.refit_for_species(target_species)
+ if(suit.helmet)
+ suit.helmet.refit_for_species(target_species)
//look at this! isn't it beautiful? -KK (well ok not beautiful but it's a lot cleaner)
if(helmet && target_department != "No Change")
var/obj/item/clothing/H = new parent_helmet
diff --git a/code/game/machinery/suit_storage_unit_vr.dm b/code/game/machinery/suit_storage_unit_vr.dm
index 3702914e32..168114844d 100644
--- a/code/game/machinery/suit_storage_unit_vr.dm
+++ b/code/game/machinery/suit_storage_unit_vr.dm
@@ -1,11 +1,11 @@
/obj/machinery/suit_cycler
- departments = list("Engineering","Mining","Medical","Security","Atmos","HAZMAT","Construction","Biohazard","Emergency Medical Response","Crowd Control","Exploration","Pilot Blue","Pilot","Manager","Prototype")
+ departments = list("Engineering","Mining","Medical","Security","Atmos","HAZMAT","Construction","Biohazard","Emergency Medical Response","Crowd Control","Exploration","Pilot Blue","Pilot","Manager","Prototype","No Change")
species = list(SPECIES_HUMAN, SPECIES_SKRELL, SPECIES_UNATHI, SPECIES_TAJ, SPECIES_TESHARI, SPECIES_AKULA, SPECIES_SERGAL, SPECIES_VULPKANIN)
// Old Exploration is too WIP to use right now
/obj/machinery/suit_cycler/exploration
req_access = list(access_explorer)
- departments = list("Exploration")
+ departments = list("Exploration","No Change")
/obj/machinery/suit_cycler/pilot
req_access = list(access_pilot)
@@ -14,7 +14,7 @@
name = "Manager suit cycler"
model_text = "Manager"
req_access = list(access_captain)
- departments = list("Manager")
+ departments = list("Manager","No Change")
/obj/machinery/suit_cycler/captain/Initialize() //No Teshari Sprites
species -= SPECIES_TESHARI
@@ -24,7 +24,7 @@
name = "Prototype suit cycler"
model_text = "Prototype"
req_access = list(access_hos)
- departments = list("Prototype")
+ departments = list("Prototype","No Change")
/obj/machinery/suit_cycler/prototype/Initialize() //No Teshari Sprites
species -= SPECIES_TESHARI
@@ -34,34 +34,34 @@
name = "Talon crew suit cycler"
model_text = "Talon crew"
req_access = list(access_talon)
- departments = list("Talon Crew")
+ departments = list("Talon Crew","No Change")
/obj/machinery/suit_cycler/vintage/tpilot
name = "Talon pilot suit cycler"
model_text = "Talon pilot"
req_access = list(access_talon)
- departments = list("Talon Pilot (Bubble Helm)","Talon Pilot (Closed Helm)")
+ departments = list("Talon Pilot (Bubble Helm)","Talon Pilot (Closed Helm)","No Change")
/obj/machinery/suit_cycler/vintage/tengi
name = "Talon engineer suit cycler"
model_text = "Talon engineer"
req_access = list(access_talon)
- departments = list("Talon Engineering")
+ departments = list("Talon Engineering","No Change")
/obj/machinery/suit_cycler/vintage/tguard
name = "Talon guard suit cycler"
model_text = "Talon guard"
req_access = list(access_talon)
- departments = list("Talon Marine","Talon Mercenary")
+ departments = list("Talon Marine","Talon Mercenary","No Change")
/obj/machinery/suit_cycler/vintage/tmedic
name = "Talon doctor suit cycler"
model_text = "Talon doctor"
req_access = list(access_talon)
- departments = list("Talon Medical (Bubble Helm)","Talon Medical (Closed Helm)")
+ departments = list("Talon Medical (Bubble Helm)","Talon Medical (Closed Helm)","No Change")
/obj/machinery/suit_cycler/vintage/tcaptain
name = "Talon captain suit cycler"
model_text = "Talon captain"
req_access = list(access_talon)
- departments = list("Talon Officer")
\ No newline at end of file
+ departments = list("Talon Officer","No Change")
\ No newline at end of file
diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm
index 31dd9d2e13..cc8c262803 100644
--- a/code/game/machinery/teleporter.dm
+++ b/code/game/machinery/teleporter.dm
@@ -11,7 +11,7 @@
var/id = null
var/one_time_use = 0 //Used for one-time-use teleport cards (such as clown planet coordinates.)
//Setting this to 1 will set locked to null after a player enters the portal and will not allow hand-teles to open portals to that location.
- var/datum/nano_module/program/teleport_control/teleport_control
+ var/datum/tgui_module/teleport_control/teleport_control
/obj/machinery/computer/teleporter/New()
id = "[rand(1000, 9999)]"
@@ -44,7 +44,7 @@
teleport_control.station = station
/obj/machinery/computer/teleporter/Destroy()
- qdel_null(teleport_control)
+ QDEL_NULL(teleport_control)
return ..()
/obj/machinery/computer/teleporter/attackby(I as obj, mob/living/user as mob)
@@ -96,108 +96,13 @@
attack_hand()
/obj/machinery/computer/teleporter/attack_ai(mob/user)
- ui_interact(user)
+ teleport_control.tgui_interact(user)
/obj/machinery/computer/teleporter/attack_hand(mob/user)
add_fingerprint(user)
if(stat & (BROKEN|NOPOWER))
return
- ui_interact(user)
-
-/obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- teleport_control.ui_interact(user, ui_key, ui, force_open)
-
-/obj/machinery/computer/teleporter/interact(mob/user)
- teleport_control.ui_interact(user)
-
-//////
-////// Nano-module for teleporter
-//////
-/datum/nano_module/program/teleport_control
- name = "Teleporter Control"
- var/locked_name = "Not Locked"
- var/obj/item/locked = null
- var/obj/machinery/teleport/station/station = null
- var/obj/machinery/teleport/hub/hub = null
-
-/datum/nano_module/program/teleport_control/Topic(href, href_list)
- if(..()) return 1
-
- if(href_list["select_target"])
- var/list/L = list()
- var/list/areaindex = list()
-
- for(var/obj/item/device/radio/beacon/R in all_beacons)
- var/turf/T = get_turf(R)
- if(!T)
- continue
- if(!(T.z in using_map.player_levels))
- continue
- var/tmpname = T.loc.name
- if(areaindex[tmpname])
- tmpname = "[tmpname] ([++areaindex[tmpname]])"
- else
- areaindex[tmpname] = 1
- L[tmpname] = R
-
- for (var/obj/item/weapon/implant/tracking/I in all_tracking_implants)
- if(!I.implanted || !ismob(I.loc))
- continue
- else
- var/mob/M = I.loc
- if(M.stat == 2)
- if(M.timeofdeath + 6000 < world.time)
- continue
- var/turf/T = get_turf(M)
- if(T) continue
- if(T.z == 2) continue
- var/tmpname = M.real_name
- if(areaindex[tmpname])
- tmpname = "[tmpname] ([++areaindex[tmpname]])"
- else
- areaindex[tmpname] = 1
- L[tmpname] = I
-
- var/desc = input("Please select a location to lock in.", "Locking Menu") in L|null
- if(!desc)
- return 0
- if(get_dist(host, usr) > 1 && !issilicon(usr))
- return 0
-
- locked = L[desc]
- locked_name = desc
- return 1
-
- if(href_list["test_fire"])
- station?.testfire()
- return 1
-
- if(href_list["toggle_on"])
- if(!station)
- return 0
-
- if(station.engaged)
- station.disengage()
- else
- station.engage()
-
- return 1
-
-/datum/nano_module/program/teleport_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- var/list/data = host.initial_data()
-
- data["locked_name"] = locked_name ? locked_name : "No Target"
- data["station_connected"] = station ? 1 : 0
- data["hub_connected"] = hub ? 1 : 0
- data["calibrated"] = hub ? hub.accurate : 0
- data["teleporter_on"] = station ? station.engaged : 0
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "teleport_control.tmpl", "Teleport Control Console", 400, 500, state = state)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ teleport_control.tgui_interact(user)
/obj/machinery/computer/teleporter/verb/set_id(t as text)
set category = "Object"
@@ -211,14 +116,6 @@
id = t
return
-/proc/find_loc(obj/R as obj)
- if(!R) return null
- var/turf/T = R.loc
- while(!istype(T, /turf))
- T = T.loc
- if(!T || istype(T, /area)) return null
- return T
-
//////
////// Root of all the machinery
//////
diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm
index a3d10db557..ad55fe14a1 100644
--- a/code/game/machinery/turret_control.dm
+++ b/code/game/machinery/turret_control.dm
@@ -11,31 +11,35 @@
desc = "Used to control a room's automated defenses."
icon = 'icons/obj/machines/turret_control.dmi'
icon_state = "control_standby"
- anchored = 1
- density = 0
- var/enabled = 0
- var/lethal = 0
- var/locked = 1
+ anchored = TRUE
+ density = FALSE
+ var/enabled = FALSE
+ var/lethal = FALSE
+ var/lethal_is_configurable = TRUE
+ var/locked = TRUE
var/area/control_area //can be area name, path or nothing.
- var/check_arrest = 1 //checks if the perp is set to arrest
- var/check_records = 1 //checks if a security record exists at all
- var/check_weapons = 0 //checks if it can shoot people that have a weapon they aren't authorized to have
- var/check_access = 1 //if this is active, the turret shoots everything that does not meet the access requirements
- var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos)
- var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg
- var/check_all = 0 //If active, will shoot at anything.
- var/ailock = 0 //Silicons cannot use this
+ var/targetting_is_configurable = TRUE // if false, you cannot change who this turret attacks via its UI
+ var/check_arrest = TRUE //checks if the perp is set to arrest
+ var/check_records = TRUE //checks if a security record exists at all
+ var/check_weapons = FALSE //checks if it can shoot people that have a weapon they aren't authorized to have
+ var/check_access = TRUE //if this is active, the turret shoots everything that does not meet the access requirements
+ var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos)
+ var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg
+ var/check_all = FALSE //If active, will shoot at anything.
+ var/check_down = TRUE //If active, won't shoot laying targets.
+ var/ailock = FALSE //Silicons cannot use this
+ var/syndicate = FALSE
req_access = list(access_ai_upload)
/obj/machinery/turretid/stun
- enabled = 1
+ enabled = TRUE
icon_state = "control_stun"
/obj/machinery/turretid/lethal
- enabled = 1
- lethal = 1
+ enabled = TRUE
+ lethal = TRUE
icon_state = "control_kill"
/obj/machinery/turretid/Destroy()
@@ -67,21 +71,24 @@
. = ..()
/obj/machinery/turretid/proc/isLocked(mob/user)
- if(ailock && issilicon(user))
- to_chat(user, "There seems to be a firewall preventing you from accessing this device.")
- return 1
+ if(isrobot(user) || isAI(user))
+ if(ailock)
+ to_chat(user, "There seems to be a firewall preventing you from accessing this device.")
+ return TRUE
+ else
+ return FALSE
- if(locked && !issilicon(user))
- to_chat(user, "Access denied.")
- return 1
+ if(isobserver(user))
+ var/mob/observer/dead/D = user
+ if(D.can_admin_interact())
+ return FALSE
+ else
+ return TRUE
- return 0
+ if(locked)
+ return TRUE
-/obj/machinery/turretid/CanUseTopic(mob/user)
- if(isLocked(user))
- return STATUS_CLOSE
-
- return ..()
+ return FALSE
/obj/machinery/turretid/attackby(obj/item/weapon/W, mob/user)
if(stat & BROKEN)
@@ -100,77 +107,80 @@
/obj/machinery/turretid/emag_act(var/remaining_charges, var/mob/user)
if(!emagged)
to_chat(user, "You short out the turret controls' access analysis module.")
- emagged = 1
- locked = 0
- ailock = 0
- return 1
+ emagged = TRUE
+ locked = FALSE
+ ailock = FALSE
+ return TRUE
/obj/machinery/turretid/attack_ai(mob/user as mob)
- if(isLocked(user))
- return
+ tgui_interact(user)
- ui_interact(user)
+/obj/machinery/turretid/attack_ghost(mob/user as mob)
+ tgui_interact(user)
/obj/machinery/turretid/attack_hand(mob/user as mob)
- if(isLocked(user))
+ tgui_interact(user)
+
+/obj/machinery/turretid/tgui_interact(mob/user, datum/tgui/ui = null)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "PortableTurret", name) // 500, 400
+ ui.open()
+
+/obj/machinery/turretid/tgui_data(mob/user)
+ var/list/data = list(
+ "locked" = isLocked(user), // does the current user have access?
+ "on" = enabled,
+ "targetting_is_configurable" = targetting_is_configurable,
+ "lethal" = lethal,
+ "lethal_is_configurable" = lethal_is_configurable,
+ "check_weapons" = check_weapons,
+ "neutralize_noaccess" = check_access,
+ "one_access" = FALSE,
+ "selectedAccess" = list(),
+ "access_is_configurable" = FALSE,
+ "neutralize_norecord" = check_records,
+ "neutralize_criminals" = check_arrest,
+ "neutralize_nonsynth" = check_synth,
+ "neutralize_all" = check_all,
+ "neutralize_unidentified" = check_anomalies,
+ "neutralize_down" = check_down,
+ )
+ return data
+
+/obj/machinery/turretid/tgui_act(action, params)
+ if(..())
+ return
+ if(isLocked(usr))
return
- ui_interact(user)
+ . = TRUE
+ switch(action)
+ if("power")
+ enabled = !enabled
+ if("lethal")
+ if(lethal_is_configurable)
+ lethal = !lethal
+ if(targetting_is_configurable)
+ switch(action)
+ if("authweapon")
+ check_weapons = !check_weapons
+ if("authaccess")
+ check_access = !check_access
+ if("authnorecord")
+ check_records = !check_records
+ if("autharrest")
+ check_arrest = !check_arrest
+ if("authxeno")
+ check_anomalies = !check_anomalies
+ if("authsynth")
+ check_synth = !check_synth
+ if("authall")
+ check_all = !check_all
+ if("authdown")
+ check_down = !check_down
-/obj/machinery/turretid/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- var/data[0]
- data["access"] = !isLocked(user)
- data["locked"] = locked
- data["enabled"] = enabled
- data["is_lethal"] = 1
- data["lethal"] = lethal
-
- if(data["access"])
- var/settings[0]
- settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth)
- settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons)
- settings[++settings.len] = list("category" = "Check Security Records", "setting" = "check_records", "value" = check_records)
- settings[++settings.len] = list("category" = "Check Arrest Status", "setting" = "check_arrest", "value" = check_arrest)
- settings[++settings.len] = list("category" = "Check Access Authorization", "setting" = "check_access", "value" = check_access)
- settings[++settings.len] = list("category" = "Check misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies)
- settings[++settings.len] = list("category" = "Neutralize All Entities", "setting" = "check_all", "value" = check_all)
-
- data["settings"] = settings
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "turret_control.tmpl", "Turret Controls", 500, 300)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
-
-/obj/machinery/turretid/Topic(href, href_list)
- if(..())
- return 1
-
- if(href_list["command"] && href_list["value"])
- var/value = text2num(href_list["value"])
- if(href_list["command"] == "enable")
- enabled = value
- else if(href_list["command"] == "lethal")
- lethal = value
- else if(href_list["command"] == "check_synth")
- check_synth = value
- else if(href_list["command"] == "check_weapons")
- check_weapons = value
- else if(href_list["command"] == "check_records")
- check_records = value
- else if(href_list["command"] == "check_arrest")
- check_arrest = value
- else if(href_list["command"] == "check_access")
- check_access = value
- else if(href_list["command"] == "check_anomalies")
- check_anomalies = value
- else if(href_list["command"] == "check_all")
- check_all = value
-
- updateTurrets()
- return 1
+ updateTurrets()
/obj/machinery/turretid/proc/updateTurrets()
var/datum/turret_checks/TC = new
@@ -183,10 +193,11 @@
TC.check_weapons = check_weapons
TC.check_anomalies = check_anomalies
TC.check_all = check_all
+ TC.check_down = check_down
TC.ailock = ailock
if(istype(control_area))
- for (var/obj/machinery/porta_turret/aTurret in control_area)
+ for(var/obj/machinery/porta_turret/aTurret in control_area)
aTurret.setState(TC)
update_icon()
diff --git a/code/game/machinery/vitals_monitor.dm b/code/game/machinery/vitals_monitor.dm
index a26c3ff706..e6d1ba5811 100644
--- a/code/game/machinery/vitals_monitor.dm
+++ b/code/game/machinery/vitals_monitor.dm
@@ -144,6 +144,6 @@
if(!istype(user))
return
- if(CanInteract(user, physical_state))
+ if(CanInteract(user, GLOB.tgui_physical_state))
beep = !beep
to_chat(user, "You turn the sound on \the [src] [beep ? "on" : "off"].")
diff --git a/code/game/mecha/combat/combat.dm b/code/game/mecha/combat/combat.dm
index d618d276c3..7661bb3255 100644
--- a/code/game/mecha/combat/combat.dm
+++ b/code/game/mecha/combat/combat.dm
@@ -17,6 +17,8 @@
max_special_equip = 1
cargo_capacity = 1
+ encumbrance_gap = 1.5
+
starting_components = list(
/obj/item/mecha_parts/component/hull/durable,
/obj/item/mecha_parts/component/actuator,
diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm
index 17aea92345..3ae3e41e13 100644
--- a/code/game/mecha/combat/phazon.dm
+++ b/code/game/mecha/combat/phazon.dm
@@ -25,6 +25,8 @@
max_universal_equip = 3
max_special_equip = 4
+ encumbrance_gap = 2
+
starting_components = list(
/obj/item/mecha_parts/component/hull/durable,
/obj/item/mecha_parts/component/actuator,
diff --git a/code/game/mecha/equipment/tools/drill.dm b/code/game/mecha/equipment/tools/drill.dm
index 346481eb66..7a3587e454 100644
--- a/code/game/mecha/equipment/tools/drill.dm
+++ b/code/game/mecha/equipment/tools/drill.dm
@@ -49,11 +49,34 @@
for(var/obj/item/weapon/ore/ore in range(chassis,1))
if(get_dir(chassis,ore)&chassis.dir)
ore.forceMove(ore_box)
+ else if(isliving(target))
+ drill_mob(target, chassis.occupant)
+ return 1
else if(target.loc == C)
log_message("Drilled through [target]")
target.ex_act(2)
return 1
+/obj/item/mecha_parts/mecha_equipment/tool/drill/proc/drill_mob(mob/living/target, mob/user)
+ add_attack_logs(user, target, "attacked", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
+ var/drill_force = force //Couldn't manage it otherwise.
+ if(ishuman(target))
+ target.apply_damage(drill_force, BRUTE)
+ return
+
+ else if(istype(target, /mob/living/simple_mob))
+ var/mob/living/simple_mob/S = target
+ if(target.stat == DEAD)
+ if(S.meat_amount > 0)
+ S.harvest(user)
+ return
+ else
+ S.gib()
+ return
+ else
+ S.apply_damage(drill_force)
+ return
+
/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill
name = "diamond drill"
desc = "This is an upgraded version of the drill that'll pierce the heavens!"
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index a6aafb577e..e9e3397bba 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -31,7 +31,10 @@
var/initial_icon = null //Mech type for resetting icon. Only used for reskinning kits (see custom items)
var/can_move = 1
var/mob/living/carbon/occupant = null
+
var/step_in = 10 //Make a step in step_in/10 sec.
+ var/encumbrance_gap = 1 //How many points of slowdown are negated from equipment? Added to the mech's base step_in.
+
var/dir_in = 2 //What direction will the mech face when entered/powered on? Defaults to South.
var/step_energy_drain = 10
var/health = 300 //Health is health
@@ -193,6 +196,7 @@
var/datum/action/innate/mecha/mech_toggle_cloaking/cloak_action = new
var/weapons_only_cycle = FALSE //So combat mechs don't switch to their equipment at times.
+
/obj/mecha/Initialize()
..()
@@ -559,12 +563,12 @@
target.attack_hand(src.occupant)
return 1
if(istype(target, /obj/machinery/embedded_controller))
- target.ui_interact(src.occupant)
+ target.tgui_interact(src.occupant)
return 1
return 0
-/obj/mecha/contents_nano_distance(var/src_object, var/mob/living/user)
- . = user.shared_living_nano_distance(src_object) //allow them to interact with anything they can interact with normally.
+/obj/mecha/contents_tgui_distance(var/src_object, var/mob/living/user)
+ . = user.shared_living_tgui_distance(src_object) //allow them to interact with anything they can interact with normally.
if(. != STATUS_INTERACTIVE)
//Allow interaction with the mecha or anything that is part of the mecha
if(src_object == src || (src_object in src))
@@ -641,18 +645,21 @@
/obj/mecha/proc/get_step_delay()
var/tally = 0
- if(overload)
- tally = min(1, round(step_in/2))
+ if(LAZYLEN(equipment))
+ for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment)
+ if(ME.get_step_delay())
+ tally += ME.get_step_delay()
+
+ if(tally <= encumbrance_gap) // If the total is less than our encumbrance gap, ignore equipment weight.
+ tally = 0
+ else // Otherwise, start the tally after cutting that gap out.
+ tally -= encumbrance_gap
for(var/slot in internal_components)
var/obj/item/mecha_parts/component/C = internal_components[slot]
if(C && C.get_step_delay())
tally += C.get_step_delay()
- for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment)
- if(ME.get_step_delay())
- tally += ME.get_step_delay()
-
var/obj/item/mecha_parts/component/actuator/actuator = internal_components[MECH_ACTUATOR]
if(!actuator) // Relying purely on hydraulic pumps. You're going nowhere fast.
@@ -674,7 +681,10 @@
break
break
- return max(1, round(tally, 0.1))
+ if(overload) // At the end, because this would normally just make the mech *slower* since tally wasn't starting at 0.
+ tally = min(1, round(tally/2))
+
+ return max(1, round(tally, 0.1)) // Round the total to the nearest 10th. Can't go lower than 1 tick. Even humans have a delay longer than that.
/obj/mecha/proc/dyndomove(direction)
if(!can_move)
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index 86405b6934..aff19e301d 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -14,6 +14,8 @@
minimum_penetration = 10
+ encumbrance_gap = 2
+
starting_components = list(
/obj/item/mecha_parts/component/hull/durable,
/obj/item/mecha_parts/component/actuator,
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 9812704a75..e90cf3aaea 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -91,16 +91,16 @@
var/icon/default_worn_icon //Default on-mob icon
var/worn_layer //Default on-mob layer
-
+
// Pickup/Drop/Equip/Throw Sounds
///Used when thrown into a mob
var/mob_throw_hit_sound
// Sound used when equipping the items into a valid slot.
- var/equip_sound
+ var/equip_sound
// pickup sound - this is the default
- var/pickup_sound = 'sound/items/pickup/device.ogg'
+ var/pickup_sound = "generic_pickup"
// drop sound - this is the default
- var/drop_sound = 'sound/items/drop/device.ogg'
+ var/drop_sound = "generic_drop"
var/tip_timer // reference to timer id for a tooltip we might open soon
@@ -468,12 +468,12 @@ var/list/global/slot_flags_enumeration = list(
if(!canremove)
return 0
-
+
if(!slot)
if(issilicon(M))
return 1 // for stuff in grippers
return 0
-
+
if(!M.slot_is_accessible(slot, src, disable_warning? null : M))
return 0
return 1
@@ -785,6 +785,8 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
// My best guess as to why this is here would be that it does so little. Still, keep it under all the procs, for sanity's sake.
/obj/item/device
icon = 'icons/obj/device.dmi'
+ pickup_sound = 'sound/items/pickup/device.ogg'
+ drop_sound = 'sound/items/drop/device.ogg'
//Worn icon generation for on-mob sprites
/obj/item/proc/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer,var/icon/clip_mask = null) //VOREStation edit - add 'clip mask' argument.
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
deleted file mode 100644
index 91784b5de6..0000000000
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ /dev/null
@@ -1,1608 +0,0 @@
-
-//The advanced pea-green monochrome lcd of tomorrow.
-
-var/global/list/obj/item/device/pda/PDAs = list()
-
-/obj/item/device/pda
- name = "\improper PDA"
- desc = "A portable microcomputer by Thinktronic Systems, LTD. Functionality determined by a preprogrammed ROM cartridge."
- icon = 'icons/obj/pda.dmi'
- icon_state = "pda"
- item_state = "electronic"
- w_class = ITEMSIZE_SMALL
- slot_flags = SLOT_ID | SLOT_BELT
- sprite_sheets = list(SPECIES_TESHARI = 'icons/mob/species/seromi/id.dmi')
-
- //Main variables
- var/pdachoice = 1
- var/owner = null
- var/default_cartridge = 0 // Access level defined by cartridge
- var/obj/item/weapon/cartridge/cartridge = null //current cartridge
- var/mode = 0 //Controls what menu the PDA will display. 0 is hub; the rest are either built in or based on cartridge.
-
- var/lastmode = 0
- var/ui_tick = 0
- var/nanoUI[0]
-
- //Secondary variables
- var/scanmode = 0 //1 is medical scanner, 2 is forensics, 3 is reagent scanner.
- var/fon = 0 //Is the flashlight function on?
- var/f_lum = 2 //Luminosity for the flashlight function
- var/message_silent = 0 //To beep or not to beep, that is the question
- var/news_silent = 1 //To beep or not to beep, that is the question. The answer is No.
- var/toff = 0 //If 1, messenger disabled
- var/tnote[0] //Current Texts
- var/last_text //No text spamming
- var/last_honk //Also no honk spamming that's bad too
- var/ttone = "beep" //The PDA ringtone!
- var/newstone = "beep, beep" //The news ringtone!
- var/lock_code = "" // Lockcode to unlock uplink
- var/honkamt = 0 //How many honks left when infected with honk.exe
- var/mimeamt = 0 //How many silence left when infected with mime.exe
- var/note = "Congratulations, your station has chosen the Thinktronic 5230 Personal Data Assistant!" //Current note in the notepad function
- var/notehtml = ""
- var/cart = "" //A place to stick cartridge menu information
- var/detonate = 1 // Can the PDA be blown up?
- var/hidden = 0 // Is the PDA hidden from the PDA list?
- var/active_conversation = null // New variable that allows us to only view a single conversation.
- var/list/conversations = list() // For keeping up with who we have PDA messsages from.
- var/new_message = 0 //To remove hackish overlay check
- var/new_news = 0
- var/touch_silent = 0 //If 1, no beeps on interacting.
-
- var/active_feed // The selected feed
- var/list/warrant // The warrant as we last knew it
- var/list/feeds = list() // The list of feeds as we last knew them
- var/list/feed_info = list() // The data and contents of each feed as we last knew them
-
- var/list/cartmodes = list(40, 42, 43, 433, 44, 441, 45, 451, 46, 48, 47, 49) // If you add more cartridge modes add them to this list as well.
- var/list/no_auto_update = list(1, 40, 43, 44, 441, 45, 451) // These modes we turn off autoupdate
- var/list/update_every_five = list(3, 41, 433, 46, 47, 48, 49) // These we update every 5 ticks
-
- var/obj/item/weapon/card/id/id = null //Making it possible to slot an ID card into the PDA so it can function as both.
- var/ownjob = null //related to above - this is assignment (potentially alt title)
- var/ownrank = null // this one is rank, never alt title
-
- var/obj/item/device/paicard/pai = null // A slot for a personal AI device
-
- var/spam_proof = FALSE // If true, it can't be spammed by random events.
-
-/obj/item/device/pda/examine(mob/user)
- . = ..()
- if(Adjacent(user))
- . += "The time [stationtime2text()] is displayed in the corner of the screen."
-
-/obj/item/device/pda/CtrlClick()
- if(issilicon(usr))
- return
-
- if(can_use(usr))
- remove_pen()
- return
- ..()
-
-/obj/item/device/pda/AltClick()
- if(issilicon(usr))
- return
-
- if ( can_use(usr) )
- if(id)
- remove_id()
- else
- to_chat(usr, "This PDA does not have an ID in it.")
-
-//Bloop when using:
-/obj/item/device/pda/CouldUseTopic(var/mob/user)
- ..()
- if(iscarbon(user) && !touch_silent)
- playsound(src, 'sound/machines/pda_click.ogg', 20)
-
-/obj/item/device/pda/medical
- default_cartridge = /obj/item/weapon/cartridge/medical
- icon_state = "pda-m"
-
-/obj/item/device/pda/viro
- default_cartridge = /obj/item/weapon/cartridge/medical
- icon_state = "pda-v"
-
-/obj/item/device/pda/engineering
- default_cartridge = /obj/item/weapon/cartridge/engineering
- icon_state = "pda-e"
-
-/obj/item/device/pda/security
- default_cartridge = /obj/item/weapon/cartridge/security
- icon_state = "pda-s"
-
-/obj/item/device/pda/detective
- default_cartridge = /obj/item/weapon/cartridge/detective
- icon_state = "pda-det"
-
-/obj/item/device/pda/warden
- default_cartridge = /obj/item/weapon/cartridge/security
- icon_state = "pda-warden"
-
-/obj/item/device/pda/janitor
- default_cartridge = /obj/item/weapon/cartridge/janitor
- icon_state = "pda-j"
- ttone = "slip"
-
-/obj/item/device/pda/science
- default_cartridge = /obj/item/weapon/cartridge/signal/science
- icon_state = "pda-tox"
- ttone = "boom"
-
-/obj/item/device/pda/clown
- default_cartridge = /obj/item/weapon/cartridge/clown
- icon_state = "pda-clown"
- desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings."
- ttone = "honk"
-
-/obj/item/device/pda/mime
- default_cartridge = /obj/item/weapon/cartridge/mime
- icon_state = "pda-mime"
- message_silent = 1
- news_silent = 1
- ttone = "silence"
- newstone = "silence"
-
-/obj/item/device/pda/heads
- default_cartridge = /obj/item/weapon/cartridge/head
- icon_state = "pda-h"
- news_silent = 1
-
-/obj/item/device/pda/heads/hop
- default_cartridge = /obj/item/weapon/cartridge/hop
- icon_state = "pda-hop"
-
-/obj/item/device/pda/heads/hos
- default_cartridge = /obj/item/weapon/cartridge/hos
- icon_state = "pda-hos"
-
-/obj/item/device/pda/heads/ce
- default_cartridge = /obj/item/weapon/cartridge/ce
- icon_state = "pda-ce"
-
-/obj/item/device/pda/heads/cmo
- default_cartridge = /obj/item/weapon/cartridge/cmo
- icon_state = "pda-cmo"
-
-/obj/item/device/pda/heads/rd
- default_cartridge = /obj/item/weapon/cartridge/rd
- icon_state = "pda-rd"
-
-/obj/item/device/pda/captain
- default_cartridge = /obj/item/weapon/cartridge/captain
- icon_state = "pda-c"
- detonate = 0
- //toff = 1
-
-/obj/item/device/pda/ert
- default_cartridge = /obj/item/weapon/cartridge/captain
- icon_state = "pda-h"
- detonate = 0
-// hidden = 1
-
-/obj/item/device/pda/cargo
- default_cartridge = /obj/item/weapon/cartridge/quartermaster
- icon_state = "pda-cargo"
-
-/obj/item/device/pda/quartermaster
- default_cartridge = /obj/item/weapon/cartridge/quartermaster
- icon_state = "pda-q"
-
-/obj/item/device/pda/shaftminer
- icon_state = "pda-miner"
- default_cartridge = /obj/item/weapon/cartridge/miner
-
-/obj/item/device/pda/syndicate
- default_cartridge = /obj/item/weapon/cartridge/syndicate
- icon_state = "pda-syn"
-// name = "Military PDA" // Vorestation Edit
-// owner = "John Doe"
- hidden = 1
-
-/obj/item/device/pda/chaplain
- default_cartridge = /obj/item/weapon/cartridge/service
- icon_state = "pda-holy"
- ttone = "holy"
-
-/obj/item/device/pda/lawyer
- default_cartridge = /obj/item/weapon/cartridge/lawyer
- icon_state = "pda-lawyer"
- ttone = "..."
-
-/obj/item/device/pda/botanist
- default_cartridge = /obj/item/weapon/cartridge/service
- icon_state = "pda-hydro"
-
-/obj/item/device/pda/roboticist
- default_cartridge = /obj/item/weapon/cartridge/signal/science
- icon_state = "pda-robot"
-
-/obj/item/device/pda/librarian
- default_cartridge = /obj/item/weapon/cartridge/service
- icon_state = "pda-libb"
- desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a WGW-11 series e-reader."
- note = "Congratulations, your station has chosen the Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant!"
- message_silent = 1 //Quiet in the library!
- news_silent = 0 // Librarian is above the law! (That and alt job title is reporter)
-
-/obj/item/device/pda/clear
- icon_state = "pda-transp"
- desc = "A portable microcomputer by Thinktronic Systems, LTD. This is model is a special edition with a transparent case."
- note = "Congratulations, you have chosen the Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition!"
-
-/obj/item/device/pda/chef
- default_cartridge = /obj/item/weapon/cartridge/service
- icon_state = "pda-chef"
-
-/obj/item/device/pda/bar
- default_cartridge = /obj/item/weapon/cartridge/service
- icon_state = "pda-bar"
-
-/obj/item/device/pda/atmos
- default_cartridge = /obj/item/weapon/cartridge/atmos
- icon_state = "pda-atmo"
-
-/obj/item/device/pda/chemist
- default_cartridge = /obj/item/weapon/cartridge/chemistry
- icon_state = "pda-chem"
-
-/obj/item/device/pda/geneticist
- default_cartridge = /obj/item/weapon/cartridge/medical
- icon_state = "pda-gene"
-
-
-// Special AI/pAI PDAs that cannot explode.
-/obj/item/device/pda/ai
- icon_state = "NONE"
- ttone = "data"
- newstone = "news"
- detonate = 0
-
-
-/obj/item/device/pda/ai/proc/set_name_and_job(newname as text, newjob as text, newrank as null|text)
- owner = newname
- ownjob = newjob
- if(newrank)
- ownrank = newrank
- else
- ownrank = ownjob
- name = newname + " (" + ownjob + ")"
-
-//AI verb and proc for sending PDA messages.
-/obj/item/device/pda/ai/verb/cmd_send_pdamesg()
- set category = "AI IM"
- set name = "Send Message"
- set src in usr
- if(usr.stat == 2)
- to_chat(usr, "You can't send PDA messages because you are dead!")
- return
- var/list/plist = available_pdas()
- if (plist)
- var/c = input(usr, "Please select a PDA") as null|anything in sortList(plist)
- if (!c) // if the user hasn't selected a PDA file we can't send a message
- return
- var/selected = plist[c]
- create_message(usr, selected, 0)
-
-/obj/item/device/pda/ai/verb/cmd_toggle_pda_receiver()
- set category = "AI IM"
- set name = "Toggle Sender/Receiver"
- set src in usr
- if(usr.stat == 2)
- to_chat(usr, "You can't send PDA messages because you are dead!")
- return
- toff = !toff
- to_chat(usr, "PDA sender/receiver toggled [(toff ? "Off" : "On")]!")
-
-/obj/item/device/pda/ai/verb/cmd_toggle_pda_silent()
- set category = "AI IM"
- set name = "Toggle Ringer"
- set src in usr
- if(usr.stat == 2)
- to_chat(usr, "You can't send PDA messages because you are dead!")
- return
- message_silent=!message_silent
- to_chat(usr, "PDA ringer toggled [(message_silent ? "Off" : "On")]!")
-
-/obj/item/device/pda/ai/verb/cmd_show_message_log()
- set category = "AI IM"
- set name = "Show Message Log"
- set src in usr
- if(usr.stat == 2)
- to_chat(usr, "You can't send PDA messages because you are dead!")
- return
- var/HTML = "AI PDA Message Log"
- for(var/index in tnote)
- if(index["sent"])
- HTML += addtext("→ To ", index["owner"],":
", index["message"], "
")
- else
- HTML += addtext("← From ", index["owner"],":
", index["message"], "
")
- HTML +=""
- usr << browse(HTML, "window=log;size=400x444;border=1;can_resize=1;can_close=1;can_minimize=0")
-
-
-/obj/item/device/pda/ai/can_use()
- return 1
-
-
-/obj/item/device/pda/ai/attack_self(mob/user as mob)
- if ((honkamt > 0) && (prob(60)))//For clown virus.
- honkamt--
- playsound(src, 'sound/items/bikehorn.ogg', 30, 1)
- return
-
-
-/obj/item/device/pda/ai/pai
- ttone = "assist"
-
-/obj/item/device/pda/ai/shell
- spam_proof = TRUE // Since empty shells get a functional PDA.
-
-// Used for the PDA multicaster, which mirrors messages sent to it to a specific department,
-/obj/item/device/pda/multicaster
- ownjob = "Relay"
- icon_state = "NONE"
- ttone = "data"
- detonate = 0
- news_silent = 1
- spam_proof = TRUE // Spam messages don't actually work and its difficult to disable these.
- var/list/cartridges_to_send_to = list()
-
-// This is what actually mirrors the message,
-/obj/item/device/pda/multicaster/new_message(var/sending_unit, var/sender, var/sender_job, var/message)
- if(sender)
- var/list/targets = list()
- for(var/obj/item/device/pda/pda in PDAs)
- if(pda.cartridge && pda.owner && is_type_in_list(pda.cartridge, cartridges_to_send_to))
- targets |= pda
- if(targets.len)
- for(var/obj/item/device/pda/target in targets)
- create_message(target, sender, sender_job, message)
-
-// This has so much copypasta,
-/obj/item/device/pda/multicaster/create_message(var/obj/item/device/pda/P, var/original_sender, var/original_job, var/t)
- t = sanitize(t, MAX_MESSAGE_LEN, 0)
- t = replace_characters(t, list(""" = "\""))
- if (!t || !istype(P))
- return
-
- if (isnull(P)||P.toff || toff)
- return
-
- last_text = world.time
- var/datum/reception/reception = get_reception(src, P, t)
- t = reception.message
-
- if(reception.message_server && (reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) // only send the message if it's stable,
- if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recipient have a broadcaster on their level?,
- return
- var/send_result = reception.message_server.send_pda_message("[P.owner]","[owner]","[t]")
- if (send_result)
- return
-
- P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]")))
-
- if(!P.conversations.Find("\ref[src]"))
- P.conversations.Add("\ref[src]")
-
- P.new_message(src, "[original_sender] \[Relayed\]", original_job, t, 0)
-
- else
- return
-
-/obj/item/device/pda/multicaster/command/New()
- ..()
- owner = "Command Department"
- name = "Command Department (Relay)"
- cartridges_to_send_to = command_cartridges
-
-/obj/item/device/pda/multicaster/security/New()
- ..()
- owner = "Security Department"
- name = "Security Department (Relay)"
- cartridges_to_send_to = security_cartridges
-
-/obj/item/device/pda/multicaster/engineering/New()
- ..()
- owner = "Engineering Department"
- name = "Engineering Department (Relay)"
- cartridges_to_send_to = engineering_cartridges
-
-/obj/item/device/pda/multicaster/medical/New()
- ..()
- owner = "Medical Department"
- name = "Medical Department (Relay)"
- cartridges_to_send_to = medical_cartridges
-
-/obj/item/device/pda/multicaster/research/New()
- ..()
- owner = "Research Department"
- name = "Research Department (Relay)"
- cartridges_to_send_to = research_cartridges
-
-/obj/item/device/pda/multicaster/cargo/New()
- ..()
- owner = "Cargo Department"
- name = "Cargo Department (Relay)"
- cartridges_to_send_to = cargo_cartridges
-
-/obj/item/device/pda/multicaster/civilian/New()
- ..()
- owner = "Civilian Services Department"
- name = "Civilian Services Department (Relay)"
- cartridges_to_send_to = civilian_cartridges
-
-/*
- * The Actual PDA
- */
-
-/obj/item/device/pda/New(var/mob/living/carbon/human/H)
- ..()
- PDAs += src
- PDAs = sortAtom(PDAs)
- if(default_cartridge)
- cartridge = new default_cartridge(src)
- new /obj/item/weapon/pen(src)
- pdachoice = isnull(H) ? 1 : (ishuman(H) ? H.pdachoice : 1)
- switch(pdachoice)
- if(1) icon = 'icons/obj/pda.dmi'
- if(2) icon = 'icons/obj/pda_slim.dmi'
- if(3) icon = 'icons/obj/pda_old.dmi'
- if(4) icon = 'icons/obj/pda_rugged.dmi'
- if(5) icon = 'icons/obj/pda_holo.dmi'
- if(6)
- icon = 'icons/obj/pda_wrist.dmi'
- item_state = icon_state
- item_icons = list(
- slot_belt_str = 'icons/mob/pda_wrist.dmi',
- slot_wear_id_str = 'icons/mob/pda_wrist.dmi',
- slot_gloves_str = 'icons/mob/pda_wrist.dmi'
- )
- desc = "A portable microcomputer by Thinktronic Systems, LTD. This model is a wrist-bound version."
- slot_flags = SLOT_ID | SLOT_BELT | SLOT_GLOVES
- sprite_sheets = list(
- SPECIES_TESHARI = 'icons/mob/species/seromi/pda_wrist.dmi',
- SPECIES_VR_TESHARI = 'icons/mob/species/seromi/pda_wrist.dmi',
- )
- else
- icon = 'icons/obj/pda_old.dmi'
- log_debug("Invalid switch for PDA, defaulting to old PDA icons. [pdachoice] chosen.")
-
-
-/obj/item/device/pda/proc/can_use()
-
- if(!ismob(loc))
- return 0
-
- var/mob/M = loc
- if(M.stat || M.restrained() || M.paralysis || M.stunned || M.weakened)
- return 0
- if((src in M.contents) || ( istype(loc, /turf) && in_range(src, M) ))
- return 1
- else
- return 0
-
-/obj/item/device/pda/GetAccess()
- if(id)
- return id.GetAccess()
- else
- return ..()
-
-/obj/item/device/pda/GetID()
- return id
-
-/obj/item/device/pda/MouseDrop(obj/over_object as obj, src_location, over_location)
- var/mob/M = usr
- if((!istype(over_object, /obj/screen)) && can_use())
- return attack_self(M)
- return
-
-
-/obj/item/device/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- ui_tick++
- var/datum/nanoui/old_ui = SSnanoui.get_open_ui(user, src, "main")
- var/auto_update = 1
- if(mode in no_auto_update)
- auto_update = 0
- if(old_ui && (mode == lastmode && ui_tick % 5 && mode in update_every_five))
- return
-
- lastmode = mode
-
- var/title = "Personal Data Assistant"
-
- var/data[0] // This is the data that will be sent to the PDA
-
- data["owner"] = owner // Who is your daddy...
- data["ownjob"] = ownjob // ...and what does he do?
-
- data["mode"] = mode // The current view
- data["scanmode"] = scanmode // Scanners
- data["fon"] = fon // Flashlight on?
- data["pai"] = (isnull(pai) ? 0 : 1) // pAI inserted?
- data["note"] = note // current pda notes
- data["message_silent"] = message_silent // does the pda make noise when it receives a message?
- data["news_silent"] = news_silent // does the pda make noise when it receives news?
- data["touch_silent"] = touch_silent // does the pda make noise when it receives news?
- data["toff"] = toff // is the messenger function turned off?
- data["active_conversation"] = active_conversation // Which conversation are we following right now?
-
-
- data["idInserted"] = (id ? 1 : 0)
- data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------")
-
- data["cart_loaded"] = cartridge ? 1:0
- if(cartridge)
- var/cartdata[0]
- cartdata["access"] = list(\
- "access_security" = cartridge.access_security,\
- "access_engine" = cartridge.access_engine,\
- "access_atmos" = cartridge.access_atmos,\
- "access_medical" = cartridge.access_medical,\
- "access_clown" = cartridge.access_clown,\
- "access_mime" = cartridge.access_mime,\
- "access_janitor" = cartridge.access_janitor,\
- "access_quartermaster" = cartridge.access_quartermaster,\
- "access_hydroponics" = cartridge.access_hydroponics,\
- "access_reagent_scanner" = cartridge.access_reagent_scanner,\
- "access_remote_door" = cartridge.access_remote_door,\
- "access_status_display" = cartridge.access_status_display,\
- "access_detonate_pda" = cartridge.access_detonate_pda\
- )
-
- if(mode in cartmodes)
- data["records"] = cartridge.create_NanoUI_values()
-
- if(mode == 0)
- cartdata["name"] = cartridge.name
- if(isnull(cartridge.radio))
- cartdata["radio"] = 0
- else
- if(istype(cartridge.radio, /obj/item/radio/integrated/beepsky))
- cartdata["radio"] = 1
- if(istype(cartridge.radio, /obj/item/radio/integrated/signal))
- cartdata["radio"] = 2
- //if(istype(cartridge.radio, /obj/item/radio/integrated/mule))
- // cartdata["radio"] = 3
-
- if(mode == 2)
- cartdata["charges"] = cartridge.charges ? cartridge.charges : 0
- data["cartridge"] = cartdata
-
- data["stationTime"] = stationtime2text()
- data["new_Message"] = new_message
- data["new_News"] = new_news
-
- var/datum/reception/reception = get_reception(src, do_sleep = 0)
- var/has_reception = reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER
- data["reception"] = has_reception
-
- if(mode==2)
- var/convopdas[0]
- var/pdas[0]
- var/count = 0
- for (var/obj/item/device/pda/P in PDAs)
- if (!P.owner||P.toff||P == src||P.hidden) continue
- if(conversations.Find("\ref[P]"))
- convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1")))
- else
- pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0")))
- count++
-
- data["convopdas"] = convopdas
- data["pdas"] = pdas
- data["pda_count"] = count
-
- if(mode==21)
- data["messagescount"] = tnote.len
- data["messages"] = tnote
- else
- data["messagescount"] = null
- data["messages"] = null
-
- if(active_conversation)
- for(var/c in tnote)
- if(c["target"] == active_conversation)
- data["convo_name"] = sanitize(c["owner"])
- data["convo_job"] = sanitize(c["job"])
- break
- if(mode==41)
- data_core.get_manifest_list()
-
-
- if(mode==3)
- data["aircontents"] = src.analyze_air()
- if(mode==6)
- if(has_reception)
- feeds.Cut()
- for(var/datum/feed_channel/channel in news_network.network_channels)
- feeds[++feeds.len] = list("name" = channel.channel_name, "censored" = channel.censored)
- data["feedChannels"] = feeds
- if(mode==61)
- var/datum/feed_channel/FC
- for(FC in news_network.network_channels)
- if(FC.channel_name == active_feed["name"])
- break
-
- var/list/feed = feed_info[active_feed]
- if(!feed)
- feed = list()
- feed["channel"] = FC.channel_name
- feed["author"] = "Unknown"
- feed["censored"]= 0
- feed["updated"] = -1
- feed_info[active_feed] = feed
-
- if(FC.updated > feed["updated"] && has_reception)
- feed["author"] = FC.author
- feed["updated"] = FC.updated
- feed["censored"] = FC.censored
-
- var/list/messages = list()
- if(!FC.censored)
- var/index = 0
- for(var/datum/feed_message/FM in FC.messages)
- index++
- if(FM.img)
- usr << browse_rsc(FM.img, "pda_news_tmp_photo_[feed["channel"]]_[index].png")
- // News stories are HTML-stripped but require newline replacement to be properly displayed in NanoUI
- var/body = replacetext(FM.body, "\n", "
")
- messages[++messages.len] = list("author" = FM.author, "body" = body, "message_type" = FM.message_type, "time_stamp" = FM.time_stamp, "has_image" = (FM.img != null), "caption" = FM.caption, "index" = index)
- feed["messages"] = messages
-
- data["feed"] = feed
-
- data["manifest"] = PDA_Manifest
-
- nanoUI = data
- // update the ui if it exists, returns null if no ui is passed/found
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
-
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "pda.tmpl", title, 520, 400, state = inventory_state)
- // add templates for screens in common with communicator.
- ui.add_template("atmosphericScan", "atmospheric_scan.tmpl")
- ui.add_template("crewManifest", "crew_manifest.tmpl")
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(auto_update)
-
-/obj/item/device/pda/attack_self(mob/user as mob)
- user.set_machine(src)
-
- if(active_uplink_check(user))
- return
-
- ui_interact(user) //NanoUI requires this proc
- return
-
-/obj/item/device/pda/Topic(href, href_list)
- if(href_list["cartmenu"] && !isnull(cartridge))
- cartridge.Topic(href, href_list)
- return 1
- if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio))
- cartridge.radio.Topic(href, href_list)
- return 1
-
-
- ..()
- var/mob/user = usr
- var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main")
- var/mob/living/U = usr
- //Looking for master was kind of pointless since PDAs don't appear to have one.
- //if ((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) ) )
- if (usr.stat == DEAD)
- return 0
- if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that.
- U.unset_machine()
- if(ui)
- ui.close()
- return 0
-
- add_fingerprint(U)
- U.set_machine(src)
-
- switch(href_list["choice"])
-
-//BASIC FUNCTIONS===================================
-
- if("Close")//Self explanatory
- U.unset_machine()
- ui.close()
- return 0
- if("Refresh")//Refresh, goes to the end of the proc.
- if("Return")//Return
- if(mode<=9)
- mode = 0
- else
- mode = round(mode/10)
- if(mode==2)
- active_conversation = null
- if(mode==4)//Fix for cartridges. Redirects to hub.
- mode = 0
- else if(mode >= 40 && mode <= 49)//Fix for cartridges. Redirects to refresh the menu.
- cartridge.mode = mode
- if ("Authenticate")//Checks for ID
- id_check(U, 1)
- if("UpdateInfo")
- ownjob = id.assignment
- ownrank = id.rank
- name = "PDA-[owner] ([ownjob])"
- if("Eject")//Ejects the cart, only done from hub.
- verb_remove_cartridge()
-
-//MENU FUNCTIONS===================================
-
- if("0")//Hub
- mode = 0
- if("1")//Notes
- mode = 1
- if("2")//Messenger
- mode = 2
- if("21")//Read messages
- mode = 21
- if("3")//Atmos scan
- mode = 3
- if("4")//Redirects to hub
- mode = 0
- if("chatroom") // chatroom hub
- mode = 5
- if("41") //Manifest
- mode = 41
-
-
-//MAIN FUNCTIONS===================================
-
- if("Light")
- if(fon)
- fon = 0
- set_light(0)
- else
- fon = 1
- set_light(f_lum)
- if("Medical Scan")
- if(scanmode == 1)
- scanmode = 0
- else if((!isnull(cartridge)) && (cartridge.access_medical))
- scanmode = 1
- if("Reagent Scan")
- if(scanmode == 3)
- scanmode = 0
- else if((!isnull(cartridge)) && (cartridge.access_reagent_scanner))
- scanmode = 3
- if("Halogen Counter")
- if(scanmode == 4)
- scanmode = 0
- else if((!isnull(cartridge)) && (cartridge.access_engine))
- scanmode = 4
- if("Honk")
- if ( !(last_honk && world.time < last_honk + 20) )
- playsound(src, 'sound/items/bikehorn.ogg', 50, 1)
- last_honk = world.time
- if("Gas Scan")
- if(scanmode == 5)
- scanmode = 0
- else if((!isnull(cartridge)) && (cartridge.access_atmos))
- scanmode = 5
- if("Toggle Beeping")
- touch_silent = !touch_silent
-
-//MESSENGER/NOTE FUNCTIONS===================================
-
- if ("Edit")
- var/n = input(U, "Please enter message", name, notehtml) as message
- if (in_range(src, U) && loc == U)
- n = sanitizeSafe(n, extra = 0)
- if (mode == 1)
- note = html_decode(n)
- notehtml = note
- note = replacetext(note, "\n", "
")
- else
- ui.close()
- if("Toggle Messenger")
- toff = !toff
- if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status
- message_silent = !message_silent
- if("Toggle News")
- news_silent = !news_silent
- if("Clear")//Clears messages
- if(href_list["option"] == "All")
- tnote.Cut()
- conversations.Cut()
- if(href_list["option"] == "Convo")
- var/new_tnote[0]
- for(var/i in tnote)
- if(i["target"] != active_conversation)
- new_tnote[++new_tnote.len] = i
- tnote = new_tnote
- conversations.Remove(active_conversation)
-
- active_conversation = null
- if(mode==21)
- mode=2
-
- if("Ringtone")
- var/t = input(U, "Please enter new ringtone", name, ttone) as text
- if (in_range(src, U) && loc == U)
- if (t)
- if(src.hidden_uplink && hidden_uplink.check_trigger(U, lowertext(t), lowertext(lock_code)))
- to_chat(U, "The PDA softly beeps.")
- ui.close()
- else
- t = sanitize(t, 20)
- ttone = t
- else
- ui.close()
- return 0
- if("Newstone")
- var/t = input(U, "Please enter new news tone", name, newstone) as text
- if (in_range(src, U) && loc == U)
- if (t)
- t = sanitize(t, 20)
- newstone = t
- else
- ui.close()
- return 0
- if("Message")
-
- var/obj/item/device/pda/P = locate(href_list["target"])
- src.create_message(U, P, !href_list["notap"])
- if(mode == 2)
- if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp.
- active_conversation = href_list["target"]
- mode = 21
-
- if("Select Conversation")
- var/P = href_list["convo"]
- for(var/n in conversations)
- if(P == n)
- active_conversation=P
- mode=21
- if("Select Feed")
- var/n = href_list["name"]
- for(var/f in feeds)
- if(f["name"] == n)
- active_feed = f
- mode=61
- if("Send Honk")//Honk virus
- if(cartridge && cartridge.access_clown)//Cartridge checks are kind of unnecessary since everything is done through switch.
- var/obj/item/device/pda/P = locate(href_list["target"])//Leaving it alone in case it may do something useful, I guess.
- if(!isnull(P))
- if (!P.toff && cartridge.charges > 0)
- cartridge.charges--
- U.show_message("Virus sent!", 1)
- P.honkamt = (rand(15,20))
- else
- to_chat(U, "PDA not found.")
- else
- ui.close()
- return 0
- if("Send Silence")//Silent virus
- if(cartridge && cartridge.access_mime)
- var/obj/item/device/pda/P = locate(href_list["target"])
- if(!isnull(P))
- if (!P.toff && cartridge.charges > 0)
- cartridge.charges--
- U.show_message("Virus sent!", 1)
- P.message_silent = 1
- P.news_silent = 1
- P.ttone = "silence"
- P.newstone = "silence"
- else
- to_chat(U, "PDA not found.")
- else
- ui.close()
- return 0
-
-
-//SYNDICATE FUNCTIONS===================================
-
- if("Toggle Door")
- if(cartridge && cartridge.access_remote_door)
- for(var/obj/machinery/door/blast/M in machines)
- if(M.id == cartridge.remote_door_id)
- if(M.density)
- M.open()
- else
- M.close()
-
- if("Detonate")//Detonate PDA... maybe
- if(cartridge && cartridge.access_detonate_pda)
- var/obj/item/device/pda/P = locate(href_list["target"])
- var/datum/reception/reception = get_reception(src, P, "", do_sleep = 0)
- if(!(reception.message_server && reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER))
- U.show_message("An error flashes on your [src]: Connection unavailable", 1)
- return
- if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recepient have a broadcaster on their level?
- U.show_message("An error flashes on your [src]: Recipient unavailable", 1)
- return
- if(!isnull(P))
- if (!P.toff && cartridge.charges > 0)
- cartridge.charges--
-
- var/difficulty = 2
-
- if(P.cartridge)
- difficulty += P.cartridge.access_medical
- difficulty += P.cartridge.access_security
- difficulty += P.cartridge.access_engine
- difficulty += P.cartridge.access_clown
- difficulty += P.cartridge.access_janitor
- if(P.hidden_uplink)
- difficulty += 3
-
- if(prob(difficulty))
- U.show_message("An error flashes on your [src].", 1)
- else if (prob(difficulty * 7))
- U.show_message("Energy feeds back into your [src]!", 1)
- ui.close()
- detonate_act(src)
- log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge but failed, blowing themselves up")
- message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge but failed.", 1)
- else
- U.show_message("Success!", 1)
- log_admin("[key_name(U)] just attempted to blow up [P] with the Detomatix cartridge and succeeded")
- message_admins("[key_name_admin(U)] just attempted to blow up [P] with the Detomatix cartridge and succeeded.", 1)
- detonate_act(P)
- else
- to_chat(U, "No charges left.")
-
- else
- to_chat(U, "PDA not found.")
- else
- U.unset_machine()
- ui.close()
- return 0
-
-//pAI FUNCTIONS===================================
- if("pai")
- if(pai)
- if(pai.loc != src)
- pai = null
- else
- switch(href_list["option"])
- if("1") // Configure pAI device
- pai.attack_self(U)
- if("2") // Eject pAI device
- var/turf/T = get_turf_or_move(src.loc)
- if(T)
- pai.loc = T
- pai = null
-
- else
- mode = text2num(href_list["choice"])
- if(cartridge)
- cartridge.mode = mode
-
-//EXTRA FUNCTIONS===================================
-
- if (mode == 2||mode == 21)//To clear message overlays.
- new_message = 0
- update_icon()
-
- if (mode == 6||mode == 61)//To clear news overlays.
- new_news = 0
- update_icon()
-
- if ((honkamt > 0) && (prob(60)))//For clown virus.
- honkamt--
- playsound(src, 'sound/items/bikehorn.ogg', 30, 1)
-
- return 1 // return 1 tells it to refresh the UI in NanoUI
-
-/obj/item/device/pda/update_icon()
- ..()
-
- overlays.Cut()
- if(new_message || new_news)
- overlays += image(icon, "pda-r")
-
-/obj/item/device/pda/proc/detonate_act(var/obj/item/device/pda/P)
- //TODO: sometimes these attacks show up on the message server
- var/i = rand(1,100)
- var/j = rand(0,1) //Possibility of losing the PDA after the detonation
- var/message = ""
- var/mob/living/M = null
- if(ismob(P.loc))
- M = P.loc
-
- //switch(i) //Yes, the overlapping cases are intended.
- if(i<=10) //The traditional explosion
- P.explode()
- j=1
- message += "Your [P] suddenly explodes!"
- if(i>=10 && i<= 20) //The PDA burns a hole in the holder.
- j=1
- if(M && isliving(M))
- M.apply_damage( rand(30,60) , BURN)
- message += "You feel a searing heat! Your [P] is burning!"
- if(i>=20 && i<=25) //EMP
- empulse(P.loc, 1, 2, 4, 6, 1)
- message += "Your [P] emits a wave of electromagnetic energy!"
- if(i>=25 && i<=40) //Smoke
- var/datum/effect/effect/system/smoke_spread/chem/S = new /datum/effect/effect/system/smoke_spread/chem
- S.attach(P.loc)
- S.set_up(P, 10, 0, P.loc)
- playsound(P, 'sound/effects/smoke.ogg', 50, 1, -3)
- S.start()
- message += "Large clouds of smoke billow forth from your [P]!"
- if(i>=40 && i<=45) //Bad smoke
- var/datum/effect/effect/system/smoke_spread/bad/B = new /datum/effect/effect/system/smoke_spread/bad
- B.attach(P.loc)
- B.set_up(P, 10, 0, P.loc)
- playsound(P, 'sound/effects/smoke.ogg', 50, 1, -3)
- B.start()
- message += "Large clouds of noxious smoke billow forth from your [P]!"
- if(i>=65 && i<=75) //Weaken
- if(M && isliving(M))
- M.apply_effects(0,1)
- message += "Your [P] flashes with a blinding white light! You feel weaker."
- if(i>=75 && i<=85) //Stun and stutter
- if(M && isliving(M))
- M.apply_effects(1,0,0,0,1)
- message += "Your [P] flashes with a blinding white light! You feel weaker."
- if(i>=85) //Sparks
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(2, 1, P.loc)
- s.start()
- message += "Your [P] begins to spark violently!"
- if(i>45 && i<65 && prob(50)) //Nothing happens
- message += "Your [P] bleeps loudly."
- j = prob(10)
-
- if(j && detonate) //This kills the PDA
- qdel(P)
- if(message)
- message += "It melts in a puddle of plastic."
- else
- message += "Your [P] shatters in a thousand pieces!"
-
- if(M && isliving(M))
- message = "[message]"
- M.show_message(message, 1)
-
-/obj/item/device/pda/proc/remove_id()
- if (id)
- if (ismob(loc))
- var/mob/M = loc
- M.put_in_hands(id)
- to_chat(usr, "You remove the ID from the [name].")
- playsound(src, 'sound/machines/id_swipe.ogg', 100, 1)
- else
- id.loc = get_turf(src)
- id = null
-
-/obj/item/device/pda/proc/remove_pen()
- var/obj/item/weapon/pen/O = locate() in src
- if(O)
- if(istype(loc, /mob))
- var/mob/M = loc
- if(M.get_active_hand() == null)
- M.put_in_hands(O)
- to_chat(usr, "You remove \the [O] from \the [src].")
- return
- O.loc = get_turf(src)
- else
- to_chat(usr, "This PDA does not have a pen in it.")
-
-/obj/item/device/pda/proc/create_message(var/mob/living/U = usr, var/obj/item/device/pda/P, var/tap = 1)
- if(tap)
- U.visible_message("\The [U] taps on their PDA's screen.")
- var/t = input(U, "Please enter message", P.name, null) as text
- t = sanitize(t)
- //t = readd_quotes(t)
- t = replace_characters(t, list(""" = "\""))
- if (!t || !istype(P))
- return
- if (!in_range(src, U) && loc != U)
- return
-
- if (isnull(P)||P.toff || toff)
- return
-
- if (last_text && world.time < last_text + 5)
- return
-
- if (!can_use())
- return
-
- if (is_jammed(src))
- return
-
- last_text = world.time
- var/datum/reception/reception = get_reception(src, P, t)
- t = reception.message
-
- if(reception.message_server && (reception.telecomms_reception & TELECOMMS_RECEPTION_SENDER)) // only send the message if it's stable
- if(reception.telecomms_reception & TELECOMMS_RECEPTION_RECEIVER == 0) // Does our recipient have a broadcaster on their level?
- to_chat(U, "ERROR: Cannot reach recipient.")
- return
- var/send_result = reception.message_server.send_pda_message("[P.owner]","[owner]","[t]")
- if (send_result)
- to_chat(U, "ERROR: Messaging server rejected your message. Reason: contains '[send_result]'.")
- return
-
- tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]")))
- P.tnote.Add(list(list("sent" = 0, "owner" = "[owner]", "job" = "[ownjob]", "message" = "[t]", "target" = "\ref[src]")))
- for(var/mob/M in player_list)
- if(M.stat == DEAD && M.client && (M.is_preference_enabled(/datum/client_preference/ghost_ears))) // src.client is so that ghosts don't have to listen to mice
- if(istype(M, /mob/new_player))
- continue
- if(M.forbid_seeing_deadchat)
- continue
- M.show_message("PDA Message - [owner] -> [P.owner]: [t]")
-
- if(!conversations.Find("\ref[P]"))
- conversations.Add("\ref[P]")
- if(!P.conversations.Find("\ref[src]"))
- P.conversations.Add("\ref[src]")
- to_chat(U, "[bicon(src)] Sent message to [P.owner] ([P.ownjob]), \"[t]\"")
-
- if (prob(5) && security_level >= SEC_LEVEL_BLUE) //Give the AI a chance of intercepting the message //VOREStation Edit: no spam interception on lower codes + lower interception chance
- var/who = src.owner
- if(prob(50))
- who = P.owner
- for(var/mob/living/silicon/ai/ai in mob_list)
- // Allows other AIs to intercept the message but the AI won't intercept their own message.
- if(ai.aiPDA != P && ai.aiPDA != src)
- ai.show_message("Intercepted message from [who]: [t]")
-
- P.new_message_from_pda(src, t)
- SSnanoui.update_user_uis(U, src) // Update the sending user's PDA UI so that they can see the new message
- else
- to_chat(U, "ERROR: Messaging server is not responding.")
-
-/obj/item/device/pda/proc/new_info(var/beep_silent, var/message_tone, var/reception_message)
- if (!beep_silent)
- playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
- for (var/mob/O in hearers(2, loc))
- O.show_message(text("[bicon(src)] *[message_tone]*"))
- //Search for holder of the PDA.
- var/mob/living/L = null
- if(loc && isliving(loc))
- L = loc
- //Maybe they are a pAI!
- else
- L = get(src, /mob/living/silicon)
-
- if(L)
- if(reception_message)
- to_chat(L,reception_message)
- SSnanoui.update_user_uis(L, src) // Update the receiving user's PDA UI so that they can see the new message
-
-/obj/item/device/pda/proc/new_news(var/message)
- new_info(news_silent, newstone, news_silent ? "" : "[bicon(src)] [message]")
-
- if(!news_silent)
- new_news = 1
- update_icon()
-
-/obj/item/device/pda/ai/new_news(var/message)
- // Do nothing
-
-/obj/item/device/pda/proc/new_message_from_pda(var/obj/item/device/pda/sending_device, var/message)
- if (is_jammed(src))
- return
- new_message(sending_device, sending_device.owner, sending_device.ownjob, message)
-
-/obj/item/device/pda/proc/new_message(var/sending_unit, var/sender, var/sender_job, var/message, var/reply = 1)
- var/reception_message = "[bicon(src)] Message from [sender] ([sender_job]), \"[message]\" ([reply ? "Reply" : "Unable to Reply"])"
- new_info(message_silent, ttone, reception_message)
-
- log_pda("(PDA: [sending_unit]) sent \"[message]\" to [name]", usr)
- new_message = 1
- update_icon()
-
-/obj/item/device/pda/ai/new_message(var/atom/movable/sending_unit, var/sender, var/sender_job, var/message)
- var/track = ""
- if(ismob(sending_unit.loc) && isAI(loc))
- track = "(Follow)"
-
- var/reception_message = "[bicon(src)] Message from [sender] ([sender_job]), \"[message]\" (Reply) [track]"
- new_info(message_silent, newstone, reception_message)
-
- log_pda("(PDA: [sending_unit]) sent \"[message]\" to [name]",usr)
- new_message = 1
-
-/obj/item/device/pda/proc/spam_message(sender, message)
- var/reception_message = "\icon[src] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)"
- new_info(message_silent, ttone, reception_message)
-
- if(prob(50)) // Give the AI an increased chance to intercept the message
- for(var/mob/living/silicon/ai/ai in mob_list)
- if(ai.aiPDA != src)
- ai.show_message("Intercepted message from [sender] (Unknown / spam?) to [owner]: [message]")
-
-/obj/item/device/pda/verb/verb_reset_pda()
- set category = "Object"
- set name = "Reset PDA"
- set src in usr
-
- if(issilicon(usr))
- return
-
- if(can_use(usr))
- mode = 0
- SSnanoui.update_uis(src)
- to_chat(usr, "You press the reset button on \the [src].")
- else
- to_chat(usr, "You cannot do this while restrained.")
-
-/obj/item/device/pda/verb/verb_remove_id()
- set category = "Object"
- set name = "Remove id"
- set src in usr
-
- if(issilicon(usr))
- return
-
- if ( can_use(usr) )
- if(id)
- remove_id()
- else
- to_chat(usr, "This PDA does not have an ID in it.")
- else
- to_chat(usr, "You cannot do this while restrained.")
-
-
-/obj/item/device/pda/verb/verb_remove_pen()
- set category = "Object"
- set name = "Remove pen"
- set src in usr
-
- if(issilicon(usr))
- return
-
- if ( can_use(usr) )
- remove_pen()
- else
- to_chat(usr, "You cannot do this while restrained.")
-
-/obj/item/device/pda/verb/verb_remove_cartridge()
- set category = "Object"
- set name = "Remove cartridge"
- set src in usr
-
- if(issilicon(usr))
- return
-
- if(!can_use(usr))
- to_chat(usr, "You cannot do this while restrained.")
- return
-
- if(isnull(cartridge))
- to_chat(usr, "There's no cartridge to eject.")
- return
-
- cartridge.forceMove(get_turf(src))
- if(ismob(loc))
- var/mob/M = loc
- M.put_in_hands(cartridge)
- mode = 0
- scanmode = 0
- if (cartridge.radio)
- cartridge.radio.hostpda = null
- to_chat(usr, "You remove \the [cartridge] from the [name].")
- playsound(src, 'sound/machines/id_swipe.ogg', 100, 1)
- cartridge = null
-
-/obj/item/device/pda/proc/id_check(mob/user as mob, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use.
- if(choice == 1)
- if (id)
- remove_id()
- return 1
- else
- var/obj/item/I = user.get_active_hand()
- if (istype(I, /obj/item/weapon/card/id) && user.unEquip(I))
- I.loc = src
- id = I
- return 1
- else
- var/obj/item/weapon/card/I = user.get_active_hand()
- if (istype(I, /obj/item/weapon/card/id) && I:registered_name && user.unEquip(I))
- var/obj/old_id = id
- I.loc = src
- id = I
- user.put_in_hands(old_id)
- return 1
- return 0
-
-// access to status display signals
-/obj/item/device/pda/attackby(obj/item/C as obj, mob/user as mob)
- ..()
- if(istype(C, /obj/item/weapon/cartridge) && !cartridge)
- cartridge = C
- user.drop_item()
- cartridge.loc = src
- to_chat(usr, "You insert [cartridge] into [src].")
- SSnanoui.update_uis(src) // update all UIs attached to src
- if(cartridge.radio)
- cartridge.radio.hostpda = src
-
- else if(istype(C, /obj/item/weapon/card/id))
- var/obj/item/weapon/card/id/idcard = C
- if(!idcard.registered_name)
- to_chat(user, "\The [src] rejects the ID.")
- return
- if(!owner)
- owner = idcard.registered_name
- ownjob = idcard.assignment
- ownrank = idcard.rank
- name = "PDA-[owner] ([ownjob])"
- to_chat(user, "Card scanned.")
- else
- //Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand.
- if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) )
- if(id_check(user, 2))
- to_chat(user, "You put the ID into \the [src]'s slot.")
- updateSelfDialog()//Update self dialog on success.
- return //Return in case of failed check or when successful.
- updateSelfDialog()//For the non-input related code.
- else if(istype(C, /obj/item/device/paicard) && !src.pai)
- user.drop_item()
- C.loc = src
- pai = C
- to_chat(user, "You slot \the [C] into \the [src].")
- SSnanoui.update_uis(src) // update all UIs attached to src
- else if(istype(C, /obj/item/weapon/pen))
- var/obj/item/weapon/pen/O = locate() in src
- if(O)
- to_chat(user, "There is already a pen in \the [src].")
- else
- user.drop_item()
- C.loc = src
- to_chat(user, "You slot \the [C] into \the [src].")
- return
-
-/obj/item/device/pda/attack(mob/living/C as mob, mob/living/user as mob)
- if (istype(C, /mob/living/carbon))
- switch(scanmode)
- if(1)
-
- for (var/mob/O in viewers(C, null))
- O.show_message("\The [user] has analyzed [C]'s vitals!", 1)
-
- user.show_message("Analyzing Results for [C]:")
- user.show_message(" Overall Status: [C.stat > 1 ? "dead" : "[C.health - C.halloss]% healthy"]", 1)
- user.show_message(text(" Damage Specifics: []-[]-[]-[]",
- (C.getOxyLoss() > 50) ? "warning" : "", C.getOxyLoss(),
- (C.getToxLoss() > 50) ? "warning" : "", C.getToxLoss(),
- (C.getFireLoss() > 50) ? "warning" : "", C.getFireLoss(),
- (C.getBruteLoss() > 50) ? "warning" : "", C.getBruteLoss()
- ), 1)
- user.show_message(" Key: Suffocation/Toxin/Burns/Brute", 1)
- user.show_message(" Body Temperature: [C.bodytemperature-T0C]°C ([C.bodytemperature*1.8-459.67]°F)", 1)
- if(C.tod && (C.stat == DEAD || (C.status_flags & FAKEDEATH)))
- user.show_message(" Time of Death: [C.tod]")
- if(istype(C, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = C
- var/list/damaged = H.get_damaged_organs(1,1)
- user.show_message("Localized Damage, Brute/Burn:",1)
- if(length(damaged)>0)
- for(var/obj/item/organ/external/org in damaged)
- user.show_message(text(" []: []-[]",
- capitalize(org.name), (org.brute_dam > 0) ? "warning" : "notice", org.brute_dam, (org.burn_dam > 0) ? "warning" : "notice", org.burn_dam),1)
- else
- user.show_message(" Limbs are OK.",1)
-
- if(2)
- if (!istype(C:dna, /datum/dna))
- to_chat(user, "No fingerprints found on [C]")
- else
- to_chat(user, text("\The [C]'s Fingerprints: [md5(C:dna.uni_identity)]"))
- if ( !(C:blood_DNA) )
- to_chat(user, "No blood found on [C]")
- if(C:blood_DNA)
- qdel(C:blood_DNA)
- else
- to_chat(user, "Blood found on [C]. Analysing...")
- spawn(15)
- for(var/blood in C:blood_DNA)
- to_chat(user, "Blood type: [C:blood_DNA[blood]]\nDNA: [blood]")
-
- if(4)
- user.visible_message("\The [user] has analyzed [C]'s radiation levels!", "You have analyzed [C]'s radiation levels!")
- to_chat(user, "Analyzing Results for [C]:")
- if(C.radiation)
- to_chat(user, "Radiation Level: [C.radiation]")
- else
- to_chat(user, "No radiation detected.")
-
-/obj/item/device/pda/afterattack(atom/A as mob|obj|turf|area, mob/user as mob, proximity)
- if(!proximity) return
- switch(scanmode)
-
- if(3)
- if(!isobj(A))
- return
- if(!isnull(A.reagents))
- if(A.reagents.reagent_list.len > 0)
- var/reagents_length = A.reagents.reagent_list.len
- to_chat(user, "[reagents_length] chemical agent[reagents_length > 1 ? "s" : ""] found.")
- for (var/re in A.reagents.reagent_list)
- to_chat(user, " [re]")
- else
- to_chat(user, "No active chemical agents found in [A].")
- else
- to_chat(user, "No significantchemical agents found in [A].")
-
- if(5)
- analyze_gases(A, user)
-
- if (!scanmode && istype(A, /obj/item/weapon/paper) && owner)
- // JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents,
- // as this will clobber the HTML, but at least it lets you scan a document. You can restore the original
- // notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.)
- var/raw_scan = (A:info)
- var/formatted_scan = ""
- // Scrub out the tags (replacing a few formatting ones along the way)
-
- // Find the beginning and end of the first tag.
- var/tag_start = findtext(raw_scan,"<")
- var/tag_stop = findtext(raw_scan,">")
-
- // Until we run out of complete tags...
- while(tag_start&&tag_stop)
- var/pre = copytext(raw_scan,1,tag_start) // Get the stuff that comes before the tag
- var/tag = lowertext(copytext(raw_scan,tag_start+1,tag_stop)) // Get the tag so we can do intellegent replacement
- var/tagend = findtext(tag," ") // Find the first space in the tag if there is one.
-
- // Anything that's before the tag can just be added as is.
- formatted_scan = formatted_scan+pre
-
- // If we have a space after the tag (and presumably attributes) just crop that off.
- if (tagend)
- tag=copytext(tag,1,tagend)
-
- if (tag=="p"||tag=="/p"||tag=="br") // Check if it's I vertical space tag.
- formatted_scan=formatted_scan+"
" // If so, add some padding in.
-
- raw_scan = copytext(raw_scan,tag_stop+1) // continue on with the stuff after the tag
-
- // Look for the next tag in what's left
- tag_start = findtext(raw_scan,"<")
- tag_stop = findtext(raw_scan,">")
-
- // Anything that is left in the page. just tack it on to the end as is
- formatted_scan=formatted_scan+raw_scan
-
- // If there is something in there already, pad it out.
- if (length(note)>0)
- note = note + "
"
-
- // Store the scanned document to the notes
- note = "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
"
- // notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents"
- // feature to the PDA, which would better convey the availability of the feature, but this will work for now.
-
- // Inform the user
- to_chat(user, "Paper scanned and OCRed to notekeeper.") //concept of scanning paper copyright brainoblivion 2009
-
-
-/obj/item/device/pda/proc/explode() //This needs tuning. //Sure did.
- if(!src.detonate) return
- var/turf/T = get_turf(src.loc)
- if(T)
- T.hotspot_expose(700,125)
- explosion(T, 0, 0, 1, rand(1,2))
- return
-
-/obj/item/device/pda/Destroy()
- PDAs -= src
- if (src.id && prob(100) && !delete_id) //IDs are kept in 90% of the cases //VOREStation Edit - 100% of the cases, excpet when specified otherwise
- src.id.forceMove(get_turf(src.loc))
- else
- QDEL_NULL(src.id)
- QDEL_NULL(src.cartridge)
- QDEL_NULL(src.pai)
- return ..()
-
-/obj/item/device/pda/clown/Crossed(atom/movable/AM as mob|obj) //Clown PDA is slippery.
- if(AM.is_incorporeal())
- return
- if (istype(AM, /mob/living))
- var/mob/living/M = AM
-
- if(M.slip("the PDA",8) && M.real_name != src.owner && istype(src.cartridge, /obj/item/weapon/cartridge/clown))
- if(src.cartridge.charges < 5)
- src.cartridge.charges++
-
-/obj/item/device/pda/proc/available_pdas()
- var/list/names = list()
- var/list/plist = list()
- var/list/namecounts = list()
-
- if (toff)
- to_chat(usr, "Turn on your receiver in order to send messages.")
- return
-
- for (var/obj/item/device/pda/P in PDAs)
- if (!P.owner)
- continue
- else if(P.hidden)
- continue
- else if (P == src)
- continue
- else if (P.toff)
- continue
-
- var/name = P.owner
- if (name in names)
- namecounts[name]++
- name = text("[name] ([namecounts[name]])")
- else
- names.Add(name)
- namecounts[name] = 1
-
- plist[text("[name]")] = P
- return plist
-
-
-//Some spare PDAs in a box
-/obj/item/weapon/storage/box/PDAs
- name = "box of spare PDAs"
- desc = "A box of spare PDA microcomputers."
- icon = 'icons/obj/pda.dmi'
- icon_state = "pdabox"
-
- New()
- ..()
- new /obj/item/device/pda(src)
- new /obj/item/device/pda(src)
- new /obj/item/device/pda(src)
- new /obj/item/device/pda(src)
- new /obj/item/weapon/cartridge/head(src)
-
- var/newcart = pick( /obj/item/weapon/cartridge/engineering,
- /obj/item/weapon/cartridge/security,
- /obj/item/weapon/cartridge/medical,
- /obj/item/weapon/cartridge/signal/science,
- /obj/item/weapon/cartridge/quartermaster)
- new newcart(src)
-
-// Pass along the pulse to atoms in contents, largely added so pAIs are vulnerable to EMP
-/obj/item/device/pda/emp_act(severity)
- for(var/atom/A in src)
- A.emp_act(severity)
-
-/obj/item/device/pda/proc/analyze_air()
- var/list/results = list()
- var/turf/T = get_turf(src.loc)
- if(!isnull(T))
- var/datum/gas_mixture/environment = T.return_air()
- var/pressure = environment.return_pressure()
- var/total_moles = environment.total_moles
- if (total_moles)
- var/o2_level = environment.gas["oxygen"]/total_moles
- var/n2_level = environment.gas["nitrogen"]/total_moles
- var/co2_level = environment.gas["carbon_dioxide"]/total_moles
- var/phoron_level = environment.gas["phoron"]/total_moles
- var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level)
-
- // entry is what the element is describing
- // Type identifies which unit or other special characters to use
- // Val is the information reported
- // Bad_high/_low are the values outside of which the entry reports as dangerous
- // Poor_high/_low are the values outside of which the entry reports as unideal
- // Values were extracted from the template itself
- results = list(
- list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
- list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
- list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
- list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
- list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
- list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0),
- list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0)
- )
-
- if(isnull(results))
- results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80))
- return results
diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm
deleted file mode 100644
index 5a404288e3..0000000000
--- a/code/game/objects/items/devices/PDA/cart.dm
+++ /dev/null
@@ -1,630 +0,0 @@
-var/list/command_cartridges = list(
- /obj/item/weapon/cartridge/captain,
- /obj/item/weapon/cartridge/hop,
- /obj/item/weapon/cartridge/hos,
- /obj/item/weapon/cartridge/ce,
- /obj/item/weapon/cartridge/rd,
- /obj/item/weapon/cartridge/cmo,
- /obj/item/weapon/cartridge/head,
- /obj/item/weapon/cartridge/lawyer // Internal Affaris,
- )
-
-var/list/security_cartridges = list(
- /obj/item/weapon/cartridge/security,
- /obj/item/weapon/cartridge/detective,
- /obj/item/weapon/cartridge/hos
- )
-
-var/list/engineering_cartridges = list(
- /obj/item/weapon/cartridge/engineering,
- /obj/item/weapon/cartridge/atmos,
- /obj/item/weapon/cartridge/ce
- )
-
-var/list/medical_cartridges = list(
- /obj/item/weapon/cartridge/medical,
- /obj/item/weapon/cartridge/chemistry,
- /obj/item/weapon/cartridge/cmo
- )
-
-var/list/research_cartridges = list(
- /obj/item/weapon/cartridge/signal/science,
- /obj/item/weapon/cartridge/rd
- )
-
-var/list/cargo_cartridges = list(
- /obj/item/weapon/cartridge/quartermaster, // This also covers cargo-techs, apparently,
- /obj/item/weapon/cartridge/miner,
- /obj/item/weapon/cartridge/hop
- )
-
-var/list/civilian_cartridges = list(
- /obj/item/weapon/cartridge/janitor,
- /obj/item/weapon/cartridge/service,
- /obj/item/weapon/cartridge/hop
- )
-
-/obj/item/weapon/cartridge
- name = "generic cartridge"
- desc = "A data cartridge for portable microcomputers."
- icon = 'icons/obj/pda.dmi'
- icon_state = "cart"
- item_state = "electronic"
- w_class = ITEMSIZE_TINY
- drop_sound = 'sound/items/drop/component.ogg'
- pickup_sound = 'sound/items/pickup/component.ogg'
-
- var/obj/item/radio/integrated/radio = null
- var/access_security = 0
- var/access_engine = 0
- var/access_atmos = 0
- var/access_medical = 0
- var/access_clown = 0
- var/access_mime = 0
- var/access_janitor = 0
-// var/access_flora = 0
- var/access_reagent_scanner = 0
- var/access_remote_door = 0 // Control some blast doors remotely!!
- var/remote_door_id = ""
- var/access_status_display = 0
- var/access_quartermaster = 0
- var/access_detonate_pda = 0
- var/access_hydroponics = 0
- var/charges = 0
- var/mode = null
- var/menu
- var/datum/data/record/active1 = null //General
- var/datum/data/record/active2 = null //Medical
- var/datum/data/record/active3 = null //Security
- var/selected_sensor = null // Power Sensor
- var/message1 // used for status_displays
- var/message2
- var/list/stored_data = list()
-
-/obj/item/weapon/cartridge/Destroy()
- QDEL_NULL(radio)
- return ..()
-
-/obj/item/weapon/cartridge/engineering
- name = "\improper Power-ON cartridge"
- icon_state = "cart-e"
- access_engine = 1
-
-/obj/item/weapon/cartridge/atmos
- name = "\improper BreatheDeep cartridge"
- icon_state = "cart-a"
- access_atmos = 1
-
-/obj/item/weapon/cartridge/medical
- name = "\improper Med-U cartridge"
- icon_state = "cart-m"
- access_medical = 1
-
-/obj/item/weapon/cartridge/chemistry
- name = "\improper ChemWhiz cartridge"
- icon_state = "cart-chem"
- access_reagent_scanner = 1
- access_medical = 1
-
-/obj/item/weapon/cartridge/security
- name = "\improper R.O.B.U.S.T. cartridge"
- icon_state = "cart-s"
- access_security = 1
-
-/obj/item/weapon/cartridge/security/Initialize()
- radio = new /obj/item/radio/integrated/beepsky(src)
- . = ..()
-
-/obj/item/weapon/cartridge/detective
- name = "\improper D.E.T.E.C.T. cartridge"
- icon_state = "cart-s"
- access_security = 1
- access_medical = 1
-
-
-/obj/item/weapon/cartridge/janitor
- name = "\improper CustodiPRO cartridge"
- desc = "The ultimate in clean-room design."
- icon_state = "cart-j"
- access_janitor = 1
-
-/obj/item/weapon/cartridge/lawyer
- name = "\improper P.R.O.V.E. cartridge"
- icon_state = "cart-s"
- access_security = 1
-
-/obj/item/weapon/cartridge/clown
- name = "\improper Honkworks 5.0 cartridge"
- icon_state = "cart-clown"
- access_clown = 1
- charges = 5
-
-/obj/item/weapon/cartridge/mime
- name = "\improper Gestur-O 1000 cartridge"
- icon_state = "cart-mi"
- access_mime = 1
- charges = 5
-/*
-/obj/item/weapon/cartridge/botanist
- name = "Green Thumb v4.20"
- icon_state = "cart-b"
- access_flora = 1
-*/
-
-/obj/item/weapon/cartridge/service
- name = "\improper Serv-U Pro cartridge"
- desc = "A data cartridge designed to serve YOU!"
-
-/obj/item/weapon/cartridge/signal
- name = "generic signaler cartridge"
- desc = "A data cartridge with an integrated radio signaler module."
- var/qdeled = 0
-
-/obj/item/weapon/cartridge/signal/science
- name = "\improper Signal Ace 2 cartridge"
- desc = "Complete with integrated radio signaler!"
- icon_state = "cart-tox"
- access_reagent_scanner = 1
- access_atmos = 1
-
-/obj/item/weapon/cartridge/signal/Initialize()
- radio = new /obj/item/radio/integrated/signal(src)
- . = ..()
-
-/obj/item/weapon/cartridge/quartermaster
- name = "\improper Space Parts & Space Vendors cartridge"
- desc = "Perfect for the Quartermaster on the go!"
- icon_state = "cart-q"
- access_quartermaster = 1
-
-/obj/item/weapon/cartridge/miner
- name = "\improper Drill-Jockey 4.5 cartridge"
- desc = "It's covered in some sort of sand."
- icon_state = "cart-q"
-
-/obj/item/weapon/cartridge/head
- name = "\improper Easy-Record DELUXE cartridge"
- icon_state = "cart-h"
- access_status_display = 1
-
-/obj/item/weapon/cartridge/hop
- name = "\improper HumanResources9001 cartridge"
- icon_state = "cart-h"
- access_status_display = 1
- access_quartermaster = 1
- access_janitor = 1
- access_security = 1
-
-/obj/item/weapon/cartridge/hos
- name = "\improper R.O.B.U.S.T. DELUXE cartridge"
- icon_state = "cart-hos"
- access_status_display = 1
- access_security = 1
-
-/obj/item/weapon/cartridge/hos/Initialize()
- radio = new /obj/item/radio/integrated/beepsky(src)
- . = ..()
-
-/obj/item/weapon/cartridge/ce
- name = "\improper Power-On DELUXE cartridge"
- icon_state = "cart-ce"
- access_status_display = 1
- access_engine = 1
- access_atmos = 1
-
-/obj/item/weapon/cartridge/cmo
- name = "\improper Med-U DELUXE cartridge"
- icon_state = "cart-cmo"
- access_status_display = 1
- access_reagent_scanner = 1
- access_medical = 1
-
-/obj/item/weapon/cartridge/rd
- name = "\improper Signal Ace DELUXE cartridge"
- icon_state = "cart-rd"
- access_status_display = 1
- access_reagent_scanner = 1
- access_atmos = 1
-
-/obj/item/weapon/cartridge/rd/Initialize()
- radio = new /obj/item/radio/integrated/signal(src)
- . = ..()
-
-/obj/item/weapon/cartridge/captain
- name = "\improper Value-PAK cartridge"
- desc = "Now with 200% more value!"
- icon_state = "cart-c"
- access_quartermaster = 1
- access_janitor = 1
- access_engine = 1
- access_security = 1
- access_medical = 1
- access_reagent_scanner = 1
- access_status_display = 1
- access_atmos = 1
-
-/obj/item/weapon/cartridge/syndicate
- name = "\improper Detomatix cartridge"
- icon_state = "cart"
- access_remote_door = 1
- access_detonate_pda = 1
- remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing.
- charges = 4
-
-/obj/item/weapon/cartridge/proc/post_status(var/command, var/data1, var/data2)
-
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
- if(!frequency) return
-
- var/datum/signal/status_signal = new
- status_signal.source = src
- status_signal.transmission_method = TRANSMISSION_RADIO
- status_signal.data["command"] = command
-
- switch(command)
- if("message")
- status_signal.data["msg1"] = data1
- status_signal.data["msg2"] = data2
- if(loc)
- var/obj/item/PDA = loc
- var/mob/user = PDA.fingerprintslast
- log_admin("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
- message_admins("STATUS: [user] set status screen with [PDA]. Message: [data1] [data2]")
-
- if("alert")
- status_signal.data["picture_state"] = data1
-
- frequency.post_signal(src, status_signal)
-
-
-/*
- This generates the nano values of the cart menus.
- Because we close the UI when we insert a new cart
- we don't have to worry about null values on items
- the user can't access. Well, unless they are href hacking.
- But in that case their UI will just lock up.
-*/
-
-
-/obj/item/weapon/cartridge/proc/create_NanoUI_values(mob/user as mob)
- var/values[0]
-
- /* Signaler (Mode: 40) */
-
-
- if(istype(radio,/obj/item/radio/integrated/signal) && (mode==40))
- var/obj/item/radio/integrated/signal/R = radio
- values["signal_freq"] = format_frequency(R.frequency)
- values["signal_code"] = R.code
-
-
- /* Station Display (Mode: 42) */
-
- if(mode==42)
- values["message1"] = message1 ? message1 : "(none)"
- values["message2"] = message2 ? message2 : "(none)"
-
-
-
- /* Power Monitor (Mode: 43 / 433) */
-
- if(mode==43 || mode==433)
- var/list/sensors = list()
- var/obj/machinery/power/sensor/MS = null
- var/my_z = get_z(user)
- var/list/levels = using_map.get_map_levels(my_z)
-
- for(var/obj/machinery/power/sensor/S in machines)
- if(!(get_z(S) in levels))
- continue
- sensors.Add(list(list("name_tag" = S.name_tag)))
- if(S.name_tag == selected_sensor)
- MS = S
- values["power_sensors"] = sensors
- if(selected_sensor && MS)
- values["sensor_reading"] = MS.return_reading_data()
-
-
- /* General Records (Mode: 44 / 441 / 45 / 451) */
- if(mode == 44 || mode == 441 || mode == 45 || mode ==451)
- if(istype(active1, /datum/data/record) && (active1 in data_core.general))
- values["general"] = active1.fields
- values["general_exists"] = 1
-
- else
- values["general_exists"] = 0
-
-
-
- /* Medical Records (Mode: 44 / 441) */
-
- if(mode == 44 || mode == 441)
- var/medData[0]
- for(var/datum/data/record/R in sortRecord(data_core.general))
- medData[++medData.len] = list(Name = R.fields["name"],"ref" = "\ref[R]")
- values["medical_records"] = medData
-
- if(istype(active2, /datum/data/record) && (active2 in data_core.medical))
- values["medical"] = active2.fields
- values["medical_exists"] = 1
- else
- values["medical_exists"] = 0
-
- /* Security Records (Mode:45 / 451) */
-
- if(mode == 45 || mode == 451)
- var/secData[0]
- for (var/datum/data/record/R in sortRecord(data_core.general))
- secData[++secData.len] = list(Name = R.fields["name"], "ref" = "\ref[R]")
- values["security_records"] = secData
-
- if(istype(active3, /datum/data/record) && (active3 in data_core.security))
- values["security"] = active3.fields
- values["security_exists"] = 1
- else
- values["security_exists"] = 0
-
- /* Security Bot Control (Mode: 46) */
-
- if(mode==46)
- var/botsData[0]
- var/beepskyData[0]
- if(istype(radio,/obj/item/radio/integrated/beepsky))
- var/obj/item/radio/integrated/beepsky/SC = radio
- beepskyData["active"] = SC.active
- if(SC.active && !isnull(SC.botstatus))
- var/area/loca = SC.botstatus["loca"]
- var/loca_name = sanitize(loca.name)
- beepskyData["botstatus"] = list("loca" = loca_name, "mode" = SC.botstatus["mode"])
- else
- beepskyData["botstatus"] = list("loca" = null, "mode" = -1)
- var/botsCount=0
- if(SC.botlist && SC.botlist.len)
- for(var/mob/living/bot/B in SC.botlist)
- botsCount++
- if(B.loc)
- botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
-
- if(!botsData.len)
- botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
-
- beepskyData["bots"] = botsData
- beepskyData["count"] = botsCount
-
- else
- beepskyData["active"] = 0
- botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
- beepskyData["botstatus"] = list("loca" = null, "mode" = null)
- beepskyData["bots"] = botsData
- beepskyData["count"] = 0
-
- values["beepsky"] = beepskyData
-
-
- /* MULEBOT Control (Mode: 48) */
-
- if(mode==48)
- var/mulebotsData[0]
- var/count = 0
-
- for(var/mob/living/bot/mulebot/M in living_mob_list)
- if(!M.on)
- continue
- ++count
- var/muleData[0]
- muleData["name"] = M.suffix
- muleData["location"] = get_area(M)
- muleData["paused"] = M.paused
- muleData["home"] = M.homeName
- muleData["target"] = M.targetName
- muleData["ref"] = "\ref[M]"
- muleData["load"] = M.load ? M.load.name : "Nothing"
-
- mulebotsData[++mulebotsData.len] = muleData.Copy()
-
- values["mulebotcount"] = count
- values["mulebots"] = mulebotsData
-
-
-
- /* Supply Shuttle Requests Menu (Mode: 47) */
-
- if(mode==47)
- var/supplyData[0]
- var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle
- if (shuttle)
- supplyData["shuttle_moving"] = shuttle.has_arrive_time()
- supplyData["shuttle_eta"] = shuttle.eta_minutes()
- supplyData["shuttle_loc"] = shuttle.at_station() ? "Station" : "Dock"
- var/supplyOrderCount = 0
- var/supplyOrderData[0]
- for(var/S in SSsupply.shoppinglist)
- var/datum/supply_order/SO = S
-
- supplyOrderData[++supplyOrderData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "ApprovedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment))
- if(!supplyOrderData.len)
- supplyOrderData[++supplyOrderData.len] = list("Number" = null, "Name" = null, "OrderedBy"=null)
-
- supplyData["approved"] = supplyOrderData
- supplyData["approved_count"] = supplyOrderCount
-
- var/requestCount = 0
- var/requestData[0]
- for(var/S in SSsupply.order_history)
- var/datum/supply_order/SO = S
- if(SO.status != SUP_ORDER_REQUESTED)
- continue
-
- requestCount++
- requestData[++requestData.len] = list("Number" = SO.ordernum, "Name" = html_encode(SO.object.name), "OrderedBy" = SO.ordered_by, "Comment" = html_encode(SO.comment))
- if(!requestData.len)
- requestData[++requestData.len] = list("Number" = null, "Name" = null, "orderedBy" = null, "Comment" = null)
-
- supplyData["requests"] = requestData
- supplyData["requests_count"] = requestCount
-
-
- values["supply"] = supplyData
-
-
-
- /* Janitor Supplies Locator (Mode: 49) */
- if(mode==49)
- var/JaniData[0]
- var/turf/cl = get_turf(src)
-
- if(cl)
- JaniData["user_loc"] = list("x" = cl.x, "y" = cl.y)
- else
- JaniData["user_loc"] = list("x" = 0, "y" = 0)
- var/MopData[0]
- for(var/obj/item/weapon/mop/M in all_mops)
- var/turf/ml = get_turf(M)
- if(ml)
- if(ml.z != cl.z)
- continue
- var/direction = get_dir(src, M)
- MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry")
-
- if(!MopData.len)
- MopData[++MopData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
-
-
- var/BucketData[0]
- for(var/obj/structure/mopbucket/B in all_mopbuckets)
- var/turf/bl = get_turf(B)
- if(bl)
- if(bl.z != cl.z)
- continue
- var/direction = get_dir(src,B)
- BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.reagents.total_volume/100)
-
- if(!BucketData.len)
- BucketData[++BucketData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
-
- var/CbotData[0]
- for(var/mob/living/bot/cleanbot/B in mob_list)
- var/turf/bl = get_turf(B)
- if(bl)
- if(bl.z != cl.z)
- continue
- var/direction = get_dir(src,B)
- CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline")
-
-
- if(!CbotData.len)
- CbotData[++CbotData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
- var/CartData[0]
- for(var/obj/structure/janitorialcart/B in all_janitorial_carts)
- var/turf/bl = get_turf(B)
- if(bl)
- if(bl.z != cl.z)
- continue
- var/direction = get_dir(src,B)
- var/status = "No Bucket"
- if(B.mybucket)
- status = B.mybucket.reagents.total_volume / 100
- CartData[++CartData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = status)
- if(!CartData.len)
- CartData[++CartData.len] = list("x" = 0, "y" = 0, dir=null, status = null)
-
-
-
-
- JaniData["mops"] = MopData
- JaniData["buckets"] = BucketData
- JaniData["cleanbots"] = CbotData
- JaniData["carts"] = CartData
- values["janitor"] = JaniData
-
- return values
-
-
-
-
-
-/obj/item/weapon/cartridge/Topic(href, href_list)
- ..()
-
- if (!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr))
- usr.unset_machine()
- usr << browse(null, "window=pda")
- return
-
-
-
-
- switch(href_list["choice"])
- if("Medical Records")
- var/datum/data/record/R = locate(href_list["target"])
- var/datum/data/record/M = locate(href_list["target"])
- loc:mode = 441
- mode = 441
- if (R in data_core.general)
- for (var/datum/data/record/E in data_core.medical)
- if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
- M = E
- break
- active1 = R
- active2 = M
-
- if("Security Records")
- var/datum/data/record/R = locate(href_list["target"])
- var/datum/data/record/S = locate(href_list["target"])
- loc:mode = 451
- mode = 451
- if (R in data_core.general)
- for (var/datum/data/record/E in data_core.security)
- if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
- S = E
- break
- active1 = R
- active3 = S
-
- if("Send Signal")
- if(is_jammed(src))
- return
- spawn( 0 )
- radio:send_signal("ACTIVATE")
- return
-
- if("Signal Frequency")
- var/new_frequency = sanitize_frequency(radio:frequency + text2num(href_list["sfreq"]))
- radio:set_frequency(new_frequency)
-
- if("Signal Code")
- radio:code += text2num(href_list["scode"])
- radio:code = round(radio:code)
- radio:code = min(100, radio:code)
- radio:code = max(1, radio:code)
-
- if("Status")
- switch(href_list["statdisp"])
- if("message")
- post_status("message", message1, message2)
- if("alert")
- post_status("alert", href_list["alert"])
- if("setmsg1")
- message1 = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", message1) as text|null, 40), 40)
- updateSelfDialog()
- if("setmsg2")
- message2 = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", message2) as text|null, 40), 40)
- updateSelfDialog()
- else
- post_status(href_list["statdisp"])
-
- if("Power Select")
- selected_sensor = href_list["target"]
- loc:mode = 433
- mode = 433
- if("Power Clear")
- selected_sensor = null
- loc:mode = 43
- mode = 43
-
- if("MULEbot")
- var/mob/living/bot/mulebot/M = locate(href_list["ref"])
- if(istype(M))
- M.obeyCommand(href_list["command"])
-
- return 1
diff --git a/code/game/objects/items/devices/PDA/cart_vr.dm b/code/game/objects/items/devices/PDA/cart_vr.dm
deleted file mode 100644
index fc4e3d098a..0000000000
--- a/code/game/objects/items/devices/PDA/cart_vr.dm
+++ /dev/null
@@ -1,17 +0,0 @@
-var/list/exploration_cartridges = list(
- /obj/item/weapon/cartridge/explorer,
- /obj/item/weapon/cartridge/sar
- )
-
-/obj/item/weapon/cartridge/explorer
- name = "\improper Explorator cartridge"
- icon_state = "cart-e"
- access_reagent_scanner = 1
- access_atmos = 1
-
-/obj/item/weapon/cartridge/sar
- name = "\improper Med-Exp cartridge"
- icon_state = "cart-m"
- access_medical = 1
- access_reagent_scanner = 1
- access_atmos = 1
diff --git a/code/game/objects/items/devices/PDA/chatroom.dm b/code/game/objects/items/devices/PDA/chatroom.dm
deleted file mode 100644
index 008dab6414..0000000000
--- a/code/game/objects/items/devices/PDA/chatroom.dm
+++ /dev/null
@@ -1,16 +0,0 @@
-var/list/chatrooms = list()
-
-/datum/chatroom
- var/name = "Generic Chatroom"
- var/list/logged_in = list()
- var/list/logs = list() // chat logs
- var/list/banned = list() // banned users
- var/list/whitelist = list() // whitelisted users
- var/list/muted = list()
- var/topic = "" // topic message for the chatroom
- var/password = "" // blank for no password.
- var/operator = "" // name of the operator
-
-/datum/chatroom/proc/attempt_connect(var/obj/item/device/pda/device, var/obj/password)
- if(!device)
- return
diff --git a/code/game/objects/items/devices/PDA/radio.dm b/code/game/objects/items/devices/PDA/radio.dm
deleted file mode 100644
index 133798e4b1..0000000000
--- a/code/game/objects/items/devices/PDA/radio.dm
+++ /dev/null
@@ -1,153 +0,0 @@
-/obj/item/radio/integrated
- name = "\improper PDA radio module"
- desc = "An electronic radio system."
- icon = 'icons/obj/module.dmi'
- icon_state = "power_mod"
- var/obj/item/device/pda/hostpda = null
-
- var/on = 0 //Are we currently active??
- var/menu_message = ""
-
- New()
- ..()
- if (istype(loc.loc, /obj/item/device/pda))
- hostpda = loc.loc
-
- proc/post_signal(var/freq, var/key, var/value, var/key2, var/value2, var/key3, var/value3, s_filter)
-
- //to_world("Post: [freq]: [key]=[value], [key2]=[value2]")
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(freq)
-
- if(!frequency) return
-
- var/datum/signal/signal = new()
- signal.source = src
- signal.transmission_method = TRANSMISSION_RADIO
- signal.data[key] = value
- if(key2)
- signal.data[key2] = value2
- if(key3)
- signal.data[key3] = value3
-
- frequency.post_signal(src, signal, radio_filter = s_filter)
-
- return
-
- proc/generate_menu()
-
-/obj/item/radio/integrated/beepsky
- var/list/botlist = null // list of bots
- var/mob/living/bot/secbot/active // the active bot; if null, show bot list
- var/list/botstatus // the status signal sent by the bot
-
- var/control_freq = BOT_FREQ
-
- // create a new QM cartridge, and register to receive bot control & beacon message
- New()
- ..()
- spawn(5)
- if(radio_controller)
- radio_controller.add_object(src, control_freq, radio_filter = RADIO_SECBOT)
-
- // receive radio signals
- // can detect bot status signals
- // create/populate list as they are recvd
-
- receive_signal(datum/signal/signal)
-// var/obj/item/device/pda/P = src.loc
-
- /*
- to_world("recvd:[P] : [signal.source]")
- for(var/d in signal.data)
- to_world("- [d] = [signal.data[d]]")
- */
- if (signal.data["type"] == "secbot")
- if(!botlist)
- botlist = new()
-
- if(!(signal.source in botlist))
- botlist += signal.source
-
- if(active == signal.source)
- var/list/b = signal.data
- botstatus = b.Copy()
-
-// if (istype(P)) P.updateSelfDialog()
-
- Topic(href, href_list)
- ..()
- var/obj/item/device/pda/PDA = src.hostpda
-
- switch(href_list["op"])
-
- if("control")
- active = locate(href_list["bot"])
- post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
-
- if("scanbots") // find all bots
- botlist = null
- post_signal(control_freq, "command", "bot_status", s_filter = RADIO_SECBOT)
-
- if("botlist")
- active = null
-
- if("stop", "go")
- post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = RADIO_SECBOT)
- post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
-
- if("summon")
- post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(PDA) , s_filter = RADIO_SECBOT)
- post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_SECBOT)
-
-
-/obj/item/radio/integrated/beepsky/Destroy()
- if(radio_controller)
- radio_controller.remove_object(src, control_freq)
- return ..()
-
-/*
- * Radio Cartridge, essentially a signaler.
- */
-
-
-/obj/item/radio/integrated/signal
- var/frequency = 1457
- var/code = 30.0
- var/last_transmission
- var/datum/radio_frequency/radio_connection
-
-/obj/item/radio/integrated/signal/Initialize()
- if(!radio_controller)
- return
-
- if (src.frequency < PUBLIC_LOW_FREQ || src.frequency > PUBLIC_HIGH_FREQ)
- src.frequency = sanitize_frequency(src.frequency)
-
- set_frequency(frequency)
-
-/obj/item/radio/integrated/signal/proc/set_frequency(new_frequency)
- radio_controller.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = radio_controller.add_object(src, frequency)
-
-/obj/item/radio/integrated/signal/proc/send_signal(message="ACTIVATE")
-
- if(last_transmission && world.time < (last_transmission + 5))
- return
- last_transmission = world.time
-
- var/time = time2text(world.realtime,"hh:mm:ss")
- var/turf/T = get_turf(src)
- lastsignalers.Add("[time] : [usr.key] used [src] @ location ([T.x],[T.y],[T.z]) : [format_frequency(frequency)]/[code]")
-
- var/datum/signal/signal = new
- signal.source = src
- signal.encryption = code
- signal.data["message"] = message
-
- radio_connection.post_signal(src, signal)
-
-/obj/item/radio/integrated/signal/Destroy()
- if(radio_controller)
- radio_controller.remove_object(src, frequency)
- return ..()
diff --git a/code/game/objects/items/devices/communicator/UI.dm b/code/game/objects/items/devices/communicator/UI.dm
deleted file mode 100644
index a4686e39de..0000000000
--- a/code/game/objects/items/devices/communicator/UI.dm
+++ /dev/null
@@ -1,292 +0,0 @@
-// Proc: ui_interact()
-// Parameters: 4 (standard NanoUI arguments)
-// Description: Uses a bunch of for loops to turn lists into lists of lists, so they can be displayed in nanoUI, then displays various buttons to the user.
-/obj/item/device/communicator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/key_state = null)
- // this is the data which will be sent to the ui
- var/data[0] //General nanoUI information
- var/communicators[0] //List of communicators
- var/invites[0] //Communicators and ghosts we've invited to our communicator.
- var/requests[0] //Communicators and ghosts wanting to go in our communicator.
- var/voices[0] //Current /mob/living/voice s inside the device.
- var/connected_communicators[0] //Current communicators connected to the device.
-
- var/im_contacts_ui[0] //List of communicators that have been messaged.
- var/im_list_ui[0] //List of messages.
-
- var/weather[0]
- var/modules_ui[0] //Home screen info.
-
- //First we add other 'local' communicators.
- for(var/obj/item/device/communicator/comm in known_devices)
- if(comm.network_visibility && comm.exonet)
- communicators[++communicators.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address)
-
- //Now for ghosts who we pretend have communicators.
- for(var/mob/observer/dead/O in known_devices)
- if(O.client && O.client.prefs.communicator_visibility == 1 && O.exonet)
- communicators[++communicators.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
-
- //Lists all the other communicators that we invited.
- for(var/obj/item/device/communicator/comm in voice_invites)
- if(comm.exonet)
- invites[++invites.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
-
- //Ghosts we invited.
- for(var/mob/observer/dead/O in voice_invites)
- if(O.exonet && O.client)
- invites[++invites.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
-
- //Communicators that want to talk to us.
- for(var/obj/item/device/communicator/comm in voice_requests)
- if(comm.exonet)
- requests[++requests.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
-
- //Ghosts that want to talk to us.
- for(var/mob/observer/dead/O in voice_requests)
- if(O.exonet && O.client)
- requests[++requests.len] = list("name" = sanitize("[O.client.prefs.real_name]'s communicator"), "address" = O.exonet.address, "ref" = "\ref[O]")
-
- //Now for all the voice mobs inside the communicator.
- for(var/mob/living/voice/voice in contents)
- voices[++voices.len] = list("name" = sanitize("[voice.name]'s communicator"), "true_name" = sanitize(voice.name))
-
- //Finally, all the communicators linked to this one.
- for(var/obj/item/device/communicator/comm in communicating)
- connected_communicators[++connected_communicators.len] = list("name" = sanitize(comm.name), "true_name" = sanitize(comm.name), "ref" = "\ref[comm]")
-
- //Devices that have been messaged or recieved messages from.
- for(var/obj/item/device/communicator/comm in im_contacts)
- if(comm.exonet)
- im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(comm.name), "address" = comm.exonet.address, "ref" = "\ref[comm]")
-
- for(var/mob/observer/dead/ghost in im_contacts)
- if(ghost.exonet)
- im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(ghost.name), "address" = ghost.exonet.address, "ref" = "\ref[ghost]")
-
- for(var/obj/item/integrated_circuit/input/EPv2/CIRC in im_contacts)
- if(CIRC.exonet && CIRC.assembly)
- im_contacts_ui[++im_contacts_ui.len] = list("name" = sanitize(CIRC.assembly.name), "address" = CIRC.exonet.address, "ref" = "\ref[CIRC]")
-
-
- //Actual messages.
- for(var/I in im_list)
- im_list_ui[++im_list_ui.len] = list("address" = I["address"], "to_address" = I["to_address"], "im" = I["im"])
-
- //Weather reports.
- for(var/datum/planet/planet in SSplanets.planets)
- if(planet.weather_holder && planet.weather_holder.current_weather)
- var/list/W = list(
- "Planet" = planet.name,
- "Time" = planet.current_time.show_time("hh:mm"),
- "Weather" = planet.weather_holder.current_weather.name,
- "Temperature" = planet.weather_holder.temperature - T0C,
- "High" = planet.weather_holder.current_weather.temp_high - T0C,
- "Low" = planet.weather_holder.current_weather.temp_low - T0C,
- "WindDir" = planet.weather_holder.wind_dir ? dir2text(planet.weather_holder.wind_dir) : "None",
- "WindSpeed" = planet.weather_holder.wind_speed ? "[planet.weather_holder.wind_speed > 2 ? "Severe" : "Normal"]" : "None",
- "Forecast" = english_list(planet.weather_holder.forecast, and_text = "→", comma_text = "→", final_comma_text = "→") // Unicode RIGHTWARDS ARROW.
- )
- weather[++weather.len] = W
-
- // Update manifest
- data_core.get_manifest_list()
-
- //Modules for homescreen.
- for(var/list/R in modules)
- modules_ui[++modules_ui.len] = R
-
- data["user"] = "\ref[user]" // For receiving input() via topic, because input(usr,...) wasn't working on cartridges
- data["owner"] = owner ? owner : "Unset"
- data["occupation"] = occupation ? occupation : "Swipe ID to set."
- data["connectionStatus"] = get_connection_to_tcomms()
- data["visible"] = network_visibility
- data["address"] = exonet.address ? exonet.address : "Unallocated"
- data["targetAddress"] = target_address
- data["targetAddressName"] = target_address_name
- data["currentTab"] = selected_tab
- data["knownDevices"] = communicators
- data["invitesSent"] = invites
- data["requestsReceived"] = requests
- data["voice_mobs"] = voices
- data["communicating"] = connected_communicators
- data["video_comm"] = video_source ? "\ref[video_source.loc]" : null
- data["imContacts"] = im_contacts_ui
- data["imList"] = im_list_ui
- data["time"] = stationtime2text()
- data["ring"] = ringer
- data["homeScreen"] = modules_ui
- data["note"] = note // current notes
- data["weather"] = weather
- data["aircontents"] = src.analyze_air()
- data["flashlight"] = fon
- data["manifest"] = PDA_Manifest
- data["feeds"] = compile_news()
- data["latest_news"] = get_recent_news()
- if(newsfeed_channel)
- data["target_feed"] = data["feeds"][newsfeed_channel]
- if(cartridge) // If there's a cartridge, we need to grab the information from it
- data["cart_devices"] = cartridge.get_device_status()
- data["cart_templates"] = cartridge.ui_templates
- for(var/list/L in cartridge.get_data())
- data[L["field"]] = L["value"]
- // cartridge.get_data() returns a list of tuples:
- // The field element is the tag used to access the information by the template
- // The value element is the actual data, and can take any form necessary for the template
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- data["currentTab"] = 1 // Reset the current tab, because we're going to home page
- ui = new(user, src, ui_key, "communicator_header.tmpl", "Communicator", 475, 700, state = key_state)
- // add templates for screens in common with communicator.
- ui.add_template("atmosphericScan", "atmospheric_scan.tmpl")
- ui.add_template("crewManifest", "crew_manifest.tmpl")
- ui.add_template("Body", "communicator.tmpl") // Main body
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every five Master Controller tick
- ui.set_auto_update(5)
-
-// Proc: Topic()
-// Parameters: 2 (standard Topic arguments)
-// Description: Responds to NanoUI button presses.
-/obj/item/device/communicator/Topic(href, href_list)
- if(..())
- return 1
- if(href_list["rename"])
- var/new_name = sanitizeSafe(input(usr,"Please enter your name.","Communicator",usr.name) )
- if(new_name)
- register_device(new_name)
-
- if(href_list["toggle_visibility"])
- switch(network_visibility)
- if(1) //Visible, becoming invisbile
- network_visibility = 0
- if(camera)
- camera.remove_network(NETWORK_COMMUNICATORS)
- if(0) //Invisible, becoming visible
- network_visibility = 1
- if(camera)
- camera.add_network(NETWORK_COMMUNICATORS)
-
- if(href_list["toggle_ringer"])
- ringer = !ringer
-
- if(href_list["add_hex"])
- var/hex = href_list["add_hex"]
- add_to_EPv2(hex)
-
- if(href_list["write_target_address"])
- var/new_address = sanitizeSafe(input(usr,"Please enter the desired target EPv2 address. Note that you must write the colons \
- yourself.","Communicator",src.target_address) )
- if(new_address)
- target_address = new_address
-
- if(href_list["clear_target_address"])
- target_address = ""
-
- if(href_list["dial"])
- if(!get_connection_to_tcomms())
- to_chat(usr, "Error: Cannot connect to Exonet node.")
- return
- var/their_address = href_list["dial"]
- exonet.send_message(their_address, "voice")
-
- if(href_list["decline"])
- var/ref_to_remove = href_list["decline"]
- var/atom/decline = locate(ref_to_remove)
- if(decline)
- del_request(decline)
-
- if(href_list["message"])
- if(!get_connection_to_tcomms())
- to_chat(usr, "Error: Cannot connect to Exonet node.")
- return
- var/their_address = href_list["message"]
- var/text = sanitizeSafe(input(usr,"Enter your message.","Text Message"))
- if(text)
- exonet.send_message(their_address, "text", text)
- im_list += list(list("address" = exonet.address, "to_address" = their_address, "im" = text))
- log_pda("(COMM: [src]) sent \"[text]\" to [exonet.get_atom_from_address(their_address)]", usr)
- for(var/mob/M in player_list)
- if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
- if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat)
- continue
- if(exonet.get_atom_from_address(their_address) == M)
- continue
- M.show_message("Comm IM - [src] -> [exonet.get_atom_from_address(their_address)]: [text]")
-
- if(href_list["disconnect"])
- var/name_to_disconnect = href_list["disconnect"]
- for(var/mob/living/voice/V in contents)
- if(name_to_disconnect == V.name)
- close_connection(usr, V, "[usr] hung up")
- for(var/obj/item/device/communicator/comm in communicating)
- if(name_to_disconnect == comm.name)
- close_connection(usr, comm, "[usr] hung up")
-
- if(href_list["startvideo"])
- var/ref_to_video = href_list["startvideo"]
- var/obj/item/device/communicator/comm = locate(ref_to_video)
- if(comm)
- connect_video(usr, comm)
-
- if(href_list["endvideo"])
- if(video_source)
- end_video()
-
- if(href_list["watchvideo"])
- if(video_source)
- watch_video(usr,video_source.loc)
-
- if(href_list["copy"])
- target_address = href_list["copy"]
-
- if(href_list["copy_name"])
- target_address_name = href_list["copy_name"]
-
- if(href_list["hang_up"])
- for(var/mob/living/voice/V in contents)
- close_connection(usr, V, "[usr] hung up")
- for(var/obj/item/device/communicator/comm in communicating)
- close_connection(usr, comm, "[usr] hung up")
-
- if(href_list["switch_tab"])
- selected_tab = href_list["switch_tab"]
-
- if(href_list["edit"])
- var/n = input(usr, "Please enter message", name, notehtml)
- n = sanitizeSafe(n, extra = 0)
- if(n)
- note = html_decode(n)
- notehtml = note
- note = replacetext(note, "\n", "
")
- else
- note = ""
- notehtml = note
-
- if(href_list["switch_template"])
- var/datum/nanoui/ui = SSnanoui.get_open_ui(usr, src, "main")
- if(ui)
- ui.add_template("Body", href_list["switch_template"])
-
- if(href_list["Light"])
- fon = !fon
- set_light(fon * flum)
-
- if(href_list["toggle_device"])
- var/obj/O = cartridge.internal_devices[text2num(href_list["toggle_device"])]
- cartridge.active_devices ^= list(O) // Exclusive or, will toggle its presence
-
- if(href_list["newsfeed"])
- newsfeed_channel = text2num(href_list["newsfeed"])
-
- if(href_list["cartridge_topic"] && cartridge) // Has to have a cartridge to perform these functions
- cartridge.Topic(href, href_list)
-
- SSnanoui.update_uis(src)
- add_fingerprint(usr)
diff --git a/code/game/objects/items/devices/communicator/UI_tgui.dm b/code/game/objects/items/devices/communicator/UI_tgui.dm
new file mode 100644
index 0000000000..8dabf77f42
--- /dev/null
+++ b/code/game/objects/items/devices/communicator/UI_tgui.dm
@@ -0,0 +1,326 @@
+// Proc: tgui_state()
+// Parameters: User
+// Description: This tells TGUI to only allow us to be interacted with while in a mob inventory.
+/obj/item/device/communicator/tgui_state(mob/user)
+ return GLOB.tgui_inventory_state
+
+// Proc: tgui_interact()
+// Parameters: User, UI, Parent UI
+// Description: This proc handles opening the UI. It's basically just a standard stub.
+/obj/item/device/communicator/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/tgui_state/custom_state)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Communicator", name)
+ if(custom_state)
+ ui.set_state(custom_state)
+ ui.open()
+ if(custom_state) // Just in case
+ ui.set_state(custom_state)
+
+// Proc: tgui_data()
+// Parameters: User, UI, State
+// Description: Uses a bunch of for loops to turn lists into lists of lists, so they can be displayed in nanoUI, then displays various buttons to the user.
+/obj/item/device/communicator/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ // this is the data which will be sent to the ui
+ var/list/data = list() //General nanoUI information
+ var/list/communicators = list() //List of communicators
+ var/list/invites = list() //Communicators and ghosts we've invited to our communicator.
+ var/list/requests = list() //Communicators and ghosts wanting to go in our communicator.
+ var/list/voices = list() //Current /mob/living/voice s inside the device.
+ var/list/connected_communicators = list() //Current communicators connected to the device.
+
+ var/list/im_contacts_ui = list() //List of communicators that have been messaged.
+ var/list/im_list_ui = list() //List of messages.
+
+ var/list/weather = list()
+ var/list/modules_ui = list() //Home screen info.
+
+ //First we add other 'local' communicators.
+ for(var/obj/item/device/communicator/comm in known_devices)
+ if(comm.network_visibility && comm.exonet)
+ communicators.Add(list(list(
+ "name" = sanitize(comm.name),
+ "address" = comm.exonet.address
+ )))
+
+ //Now for ghosts who we pretend have communicators.
+ for(var/mob/observer/dead/O in known_devices)
+ if(O.client && O.client.prefs.communicator_visibility == 1 && O.exonet)
+ communicators.Add(list(list(
+ "name" = sanitize("[O.client.prefs.real_name]'s communicator"),
+ "address" = O.exonet.address,
+ "ref" = "\ref[O]"
+ )))
+
+ //Lists all the other communicators that we invited.
+ for(var/obj/item/device/communicator/comm in voice_invites)
+ if(comm.exonet)
+ invites.Add(list(list(
+ "name" = sanitize(comm.name),
+ "address" = comm.exonet.address,
+ "ref" = "\ref[comm]"
+ )))
+
+ //Ghosts we invited.
+ for(var/mob/observer/dead/O in voice_invites)
+ if(O.exonet && O.client)
+ invites.Add(list(list(
+ "name" = sanitize("[O.client.prefs.real_name]'s communicator"),
+ "address" = O.exonet.address,
+ "ref" = "\ref[O]"
+ )))
+
+ //Communicators that want to talk to us.
+ for(var/obj/item/device/communicator/comm in voice_requests)
+ if(comm.exonet)
+ requests.Add(list(list(
+ "name" = sanitize(comm.name),
+ "address" = comm.exonet.address,
+ "ref" = "\ref[comm]"
+ )))
+
+ //Ghosts that want to talk to us.
+ for(var/mob/observer/dead/O in voice_requests)
+ if(O.exonet && O.client)
+ requests.Add(list(list(
+ "name" = sanitize("[O.client.prefs.real_name]'s communicator"),
+ "address" = O.exonet.address,
+ "ref" = "\ref[O]"
+ )))
+
+ //Now for all the voice mobs inside the communicator.
+ for(var/mob/living/voice/voice in contents)
+ voices.Add(list(list(
+ "name" = sanitize("[voice.name]'s communicator"),
+ "true_name" = sanitize(voice.name),
+ )))
+
+ //Finally, all the communicators linked to this one.
+ for(var/obj/item/device/communicator/comm in communicating)
+ connected_communicators.Add(list(list(
+ "name" = sanitize(comm.name),
+ "true_name" = sanitize(comm.name),
+ "ref" = "\ref[comm]",
+ )))
+
+ //Devices that have been messaged or recieved messages from.
+ for(var/obj/item/device/communicator/comm in im_contacts)
+ if(comm.exonet)
+ im_contacts_ui.Add(list(list(
+ "name" = sanitize(comm.name),
+ "address" = comm.exonet.address,
+ "ref" = "\ref[comm]"
+ )))
+
+ for(var/mob/observer/dead/ghost in im_contacts)
+ if(ghost.exonet)
+ im_contacts_ui.Add(list(list(
+ "name" = sanitize(ghost.name),
+ "address" = ghost.exonet.address,
+ "ref" = "\ref[ghost]"
+ )))
+
+ for(var/obj/item/integrated_circuit/input/EPv2/CIRC in im_contacts)
+ if(CIRC.exonet && CIRC.assembly)
+ im_contacts_ui.Add(list(list(
+ "name" = sanitize(CIRC.assembly.name),
+ "address" = CIRC.exonet.address,
+ "ref" = "\ref[CIRC]"
+ )))
+
+
+ //Actual messages.
+ for(var/I in im_list)
+ im_list_ui.Add(list(list(
+ "address" = I["address"],
+ "to_address" = I["to_address"],
+ "im" = I["im"]
+ )))
+
+ //Weather reports.
+ for(var/datum/planet/planet in SSplanets.planets)
+ if(planet.weather_holder && planet.weather_holder.current_weather)
+ var/list/W = list(
+ "Planet" = planet.name,
+ "Time" = planet.current_time.show_time("hh:mm"),
+ "Weather" = planet.weather_holder.current_weather.name,
+ "Temperature" = planet.weather_holder.temperature - T0C,
+ "High" = planet.weather_holder.current_weather.temp_high - T0C,
+ "Low" = planet.weather_holder.current_weather.temp_low - T0C,
+ "WindDir" = planet.weather_holder.wind_dir ? dir2text(planet.weather_holder.wind_dir) : "None",
+ "WindSpeed" = planet.weather_holder.wind_speed ? "[planet.weather_holder.wind_speed > 2 ? "Severe" : "Normal"]" : "None",
+ "Forecast" = english_list(planet.weather_holder.forecast, and_text = "→", comma_text = "→", final_comma_text = "→") // Unicode RIGHTWARDS ARROW.
+ )
+ weather.Add(list(W))
+
+
+ //Modules for homescreen.
+ for(var/list/R in modules)
+ modules_ui.Add(list(R))
+
+ data["user"] = "\ref[user]" // For receiving input() via topic, because input(usr,...) wasn't working on cartridges
+ data["owner"] = owner ? owner : "Unset"
+ data["occupation"] = occupation ? occupation : "Swipe ID to set."
+ data["connectionStatus"] = get_connection_to_tcomms()
+ data["visible"] = network_visibility
+ data["address"] = exonet.address ? exonet.address : "Unallocated"
+ data["targetAddress"] = target_address
+ data["targetAddressName"] = target_address_name
+ data["currentTab"] = selected_tab
+ data["knownDevices"] = communicators
+ data["invitesSent"] = invites
+ data["requestsReceived"] = requests
+ data["voice_mobs"] = voices
+ data["communicating"] = connected_communicators
+ data["video_comm"] = video_source ? "\ref[video_source.loc]" : null
+ data["imContacts"] = im_contacts_ui
+ data["imList"] = im_list_ui
+ data["time"] = stationtime2text()
+ data["ring"] = ringer
+ data["homeScreen"] = modules_ui
+ data["note"] = note // current notes
+ data["weather"] = weather
+ data["aircontents"] = src.analyze_air()
+ data["flashlight"] = fon
+ data["feeds"] = compile_news()
+ data["latest_news"] = get_recent_news()
+ if(newsfeed_channel)
+ data["target_feed"] = data["feeds"][newsfeed_channel]
+ else
+ data["target_feed"] = null
+
+ return data
+
+// Proc: tgui_static_data()
+// Parameters: User, UI, State
+// Description: Just like tgui_data, except it only gets called once when the user opens the UI, not every tick.
+/obj/item/device/communicator/tgui_static_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+ // Update manifest'
+ if(data_core)
+ data_core.get_manifest_list()
+ data["manifest"] = PDA_Manifest
+ return data
+
+// Proc: tgui-act()
+// Parameters: 4 (standard tgui_act arguments)
+// Description: Responds to UI button presses.
+/obj/item/device/communicator/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
+
+ add_fingerprint(usr)
+ . = TRUE
+ switch(action)
+ if("rename")
+ var/new_name = sanitizeSafe(input(usr,"Please enter your name.","Communicator",usr.name) )
+ if(new_name)
+ register_device(new_name)
+
+ if("toggle_visibility")
+ switch(network_visibility)
+ if(1) //Visible, becoming invisbile
+ network_visibility = 0
+ if(camera)
+ camera.remove_network(NETWORK_COMMUNICATORS)
+ if(0) //Invisible, becoming visible
+ network_visibility = 1
+ if(camera)
+ camera.add_network(NETWORK_COMMUNICATORS)
+
+ if("toggle_ringer")
+ ringer = !ringer
+
+ if("add_hex")
+ var/hex = params["add_hex"]
+ add_to_EPv2(hex)
+
+ if("write_target_address")
+ target_address = sanitizeSafe(params["val"])
+
+ if("clear_target_address")
+ target_address = ""
+
+ if("dial")
+ if(!get_connection_to_tcomms())
+ to_chat(usr, "Error: Cannot connect to Exonet node.")
+ return FALSE
+ var/their_address = params["dial"]
+ exonet.send_message(their_address, "voice")
+
+ if("decline")
+ var/ref_to_remove = params["decline"]
+ var/atom/decline = locate(ref_to_remove)
+ if(decline)
+ del_request(decline)
+
+ if("message")
+ if(!get_connection_to_tcomms())
+ to_chat(usr, "Error: Cannot connect to Exonet node.")
+ return FALSE
+ var/their_address = params["message"]
+ var/text = sanitizeSafe(input(usr,"Enter your message.","Text Message"))
+ if(text)
+ exonet.send_message(their_address, "text", text)
+ im_list += list(list("address" = exonet.address, "to_address" = their_address, "im" = text))
+ log_pda("(COMM: [src]) sent \"[text]\" to [exonet.get_atom_from_address(their_address)]", usr)
+ for(var/mob/M in player_list)
+ if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
+ if(istype(M, /mob/new_player) || M.forbid_seeing_deadchat)
+ continue
+ if(exonet.get_atom_from_address(their_address) == M)
+ continue
+ M.show_message("Comm IM - [src] -> [exonet.get_atom_from_address(their_address)]: [text]")
+
+ if("disconnect")
+ var/name_to_disconnect = params["disconnect"]
+ for(var/mob/living/voice/V in contents)
+ if(name_to_disconnect == sanitize(V.name))
+ close_connection(usr, V, "[usr] hung up")
+ for(var/obj/item/device/communicator/comm in communicating)
+ if(name_to_disconnect == sanitize(comm.name))
+ close_connection(usr, comm, "[usr] hung up")
+
+ if("startvideo")
+ var/ref_to_video = params["startvideo"]
+ var/obj/item/device/communicator/comm = locate(ref_to_video)
+ if(comm)
+ connect_video(usr, comm)
+
+ if("endvideo")
+ if(video_source)
+ end_video()
+
+ if("copy")
+ target_address = params["copy"]
+
+ if("copy_name")
+ target_address_name = params["copy_name"]
+
+ if("hang_up")
+ for(var/mob/living/voice/V in contents)
+ close_connection(usr, V, "[usr] hung up")
+ for(var/obj/item/device/communicator/comm in communicating)
+ close_connection(usr, comm, "[usr] hung up")
+
+ if("switch_tab")
+ selected_tab = params["switch_tab"]
+
+ if("edit")
+ var/n = input(usr, "Please enter message", name, notehtml) as message|null
+ n = sanitizeSafe(n, extra = 0)
+ if(n)
+ note = html_decode(n)
+ notehtml = note
+ note = replacetext(note, "\n", "
")
+ else
+ note = ""
+ notehtml = note
+
+ if("Light")
+ fon = !fon
+ set_light(fon * flum)
+
+ if("newsfeed")
+ newsfeed_channel = text2num(params["newsfeed"])
+
diff --git a/code/game/objects/items/devices/communicator/cartridge.dm b/code/game/objects/items/devices/communicator/cartridge.dm
deleted file mode 100644
index 120df593e9..0000000000
--- a/code/game/objects/items/devices/communicator/cartridge.dm
+++ /dev/null
@@ -1,952 +0,0 @@
-// Communicator peripheral devices
-// Internal devices that attack() can be relayed to
-// Additional UI menus for added functionality
-/obj/item/weapon/commcard
- name = "generic commcard"
- desc = "A peripheral plug-in for personal communicators."
- icon = 'icons/obj/pda.dmi'
- icon_state = "cart"
- item_state = "electronic"
- w_class = ITEMSIZE_TINY
-
- var/list/internal_devices = list() // Devices that can be toggled on to trigger on attack()
- var/list/active_devices = list() // Devices that will be triggered on attack()
- var/list/ui_templates = list() // List of ui templates the commcard can access
- var/list/internal_data = list() // Data that shouldn't be updated every time nanoUI updates, or needs to persist between updates
-
-
-/obj/item/weapon/commcard/proc/get_device_status()
- var/list/L = list()
- var/i = 1
- for(var/obj/I in internal_devices)
- if(I in active_devices)
- L[++L.len] = list("name" = "\proper[I.name]", "active" = 1, "index" = i++)
- else
- L[++L.len] = list("name" = I.name, "active" = 0, "index" = i++)
- return L
-
-
-// cartridge.get_data() returns a list of tuples:
-// The field element is the tag used to access the information by the template
-// The value element is the actual data, and can take any form necessary for the template
-/obj/item/weapon/commcard/proc/get_data()
- return list()
-
-// Handles cartridge-specific functions
-// The helper.link() MUST HAVE 'cartridge_topic' passed into the href in order for cartridge functions to be processed.
-// Doesn't matter what the value of it is for now, it's just a flag to say, "Hey, there's cartridge data to change!"
-/obj/item/weapon/commcard/Topic(href, href_list)
-
- // Signalers
- if(href_list["signaler_target"])
-
- var/obj/item/device/assembly/signaler/S = locate(href_list["signaler_target"]) // Should locate the correct signaler
-
- if(!istype(S)) // Ref is no longer valid
- return
-
- if(S.loc != src) // No longer within the cartridge
- return
-
- switch(href_list["signaler_action"])
- if("Pulse")
- S.activate()
-
- if("Edit")
- var/mob/user = locate(href_list["user"])
- if(!istype(user)) // Ref no longer valid
- return
-
- var/newVal = input(user, "Input a new [href_list["signaler_value"]].", href_list["signaler_value"], (href_list["signaler_value"] == "Code" ? S.code : S.frequency)) as num|null
- if(newVal)
- switch(href_list["signaler_value"])
- if("Code")
- S.code = newVal
-
- if("Frequency")
- S.frequency = newVal
-
- // Refresh list of powernet sensors
- if(href_list["powernet_refresh"])
- internal_data["grid_sensors"] = find_powernet_sensors()
-
- // Load apc's on targeted powernet
- if(href_list["powernet_target"])
- internal_data["powernet_target"] = href_list["powernet_target"]
-
- // GPS units
- if(href_list["gps_target"])
- var/obj/item/device/gps/G = locate(href_list["gps_target"])
-
- if(!istype(G)) // Ref is no longer valid
- return
-
- if(G.loc != src) // No longer within the cartridge
- return
-
- switch(href_list["gps_action"])
- if("Power")
- G.tracking = text2num(href_list["value"])
-
- if("Long_Range")
- G.local_mode = text2num(href_list["value"])
-
- if("Hide_Signal")
- G.hide_signal = text2num(href_list["value"])
-
- if("Tag")
- var/mob/user = locate(href_list["user"])
- if(!istype(user)) // Ref no longer valid
- return
-
- var/newTag = input(user, "Please enter desired tag.", G.tag) as text|null
-
- if(newTag)
- G.tag = newTag
-
- if(href_list["active_category"])
- internal_data["supply_category"] = href_list["active_category"]
-
- // Supply topic
- // Copied from /obj/machinery/computer/supplycomp/Topic()
- // code\game\machinery\computer\supply.dm, line 188
- // Unfortunately, in order to support complete functionality, the whole thing is necessary
- if(href_list["pack_ref"])
- var/datum/supply_pack/S = locate(href_list["pack_ref"])
-
- // Invalid ref
- if(!istype(S))
- return
-
- // Expand the supply pack's contents
- if(href_list["expand"])
- internal_data["supply_pack_expanded"] ^= S
-
- // Make a request for the pack
- if(href_list["request"])
- var/mob/user = locate(href_list["user"])
- if(!istype(user)) // Invalid ref
- return
-
- if(world.time < internal_data["supply_reqtime"])
- visible_message("[src] flashes, \"[internal_data["supply_reqtime"] - world.time] seconds remaining until another requisition form may be printed.\"")
- return
-
- var/timeout = world.time + 600
- var/reason = sanitize(input(user, "Reason:","Why do you require this item?","") as null|text)
- if(world.time > timeout)
- to_chat(user, "Error. Request timed out.")
- return
- if(!reason)
- return
-
- SSsupply.create_order(S, user, reason)
- internal_data["supply_reqtime"] = (world.time + 5) % 1e5
-
- if(href_list["order_ref"])
- var/datum/supply_order/O = locate(href_list["order_ref"])
-
- // Invalid ref
- if(!istype(O))
- return
-
- var/mob/user = locate(href_list["user"])
- if(!istype(user)) // Invalid ref
- return
-
- if(href_list["edit"])
- var/new_val = sanitize(input(user, href_list["edit"], "Enter the new value for this field:", href_list["default"]) as null|text)
- if(!new_val)
- return
-
- switch(href_list["edit"])
- if("Supply Pack")
- O.name = new_val
-
- if("Cost")
- var/num = text2num(new_val)
- if(num)
- O.cost = num
-
- if("Index")
- var/num = text2num(new_val)
- if(num)
- O.index = num
-
- if("Reason")
- O.comment = new_val
-
- if("Ordered by")
- O.ordered_by = new_val
-
- if("Ordered at")
- O.ordered_at = new_val
-
- if("Approved by")
- O.approved_by = new_val
-
- if("Approved at")
- O.approved_at = new_val
-
- if(href_list["approve"])
- SSsupply.approve_order(O, user)
-
- if(href_list["deny"])
- SSsupply.deny_order(O, user)
-
- if(href_list["delete"])
- SSsupply.delete_order(O, user)
-
- if(href_list["clear_all_requests"])
- var/mob/user = locate(href_list["user"])
- if(!istype(user)) // Invalid ref
- return
-
- SSsupply.deny_all_pending(user)
-
- if(href_list["export_ref"])
- var/datum/exported_crate/E = locate(href_list["export_ref"])
-
- // Invalid ref
- if(!istype(E))
- return
-
- var/mob/user = locate(href_list["user"])
- if(!istype(user)) // Invalid ref
- return
-
- if(href_list["index"])
- var/list/L = E.contents[href_list["index"]]
-
- if(href_list["edit"])
- var/field = alert(user, "Select which field to edit", , "Name", "Quantity", "Value")
-
- var/new_val = sanitize(input(user, href_list["edit"], "Enter the new value for this field:", href_list["default"]) as null|text)
- if(!new_val)
- return
-
- switch(field)
- if("Name")
- L["object"] = new_val
-
- if("Quantity")
- var/num = text2num(new_val)
- if(num)
- L["quantity"] = num
-
- if("Value")
- var/num = text2num(new_val)
- if(num)
- L["value"] = num
-
- if(href_list["delete"])
- E.contents.Cut(href_list["index"], href_list["index"] + 1)
-
- // Else clause means they're editing/deleting the whole export report, rather than a specific item in it
- else if(href_list["edit"])
- var/new_val = sanitize(input(user, href_list["edit"], "Enter the new value for this field:", href_list["default"]) as null|text)
- if(!new_val)
- return
-
- switch(href_list["edit"])
- if("Name")
- E.name = new_val
-
- if("Value")
- var/num = text2num(new_val)
- if(num)
- E.value = num
-
- else if(href_list["delete"])
- SSsupply.delete_export(E, user)
-
- else if(href_list["add_item"])
- SSsupply.add_export_item(E, user)
-
- if(SSsupply && SSsupply.shuttle)
- switch(href_list["send_shuttle"])
- if("send_away")
- if(SSsupply.shuttle.forbidden_atoms_check())
- to_chat(usr, "For safety reasons the automated supply shuttle cannot transport live organisms, classified nuclear weaponry or homing beacons.")
- else
- SSsupply.shuttle.launch(src)
- to_chat(usr, "Initiating launch sequence.")
-
- if("send_to_station")
- SSsupply.shuttle.launch(src)
- to_chat(usr, "The supply shuttle has been called and will arrive in approximately [round(SSsupply.movetime/600,1)] minutes.")
-
- if("cancel_shuttle")
- SSsupply.shuttle.cancel_launch(src)
-
- if("force_shuttle")
- SSsupply.shuttle.force_launch(src)
-
- // Status display
- switch(href_list["stat_display"])
- if("message")
- post_status("message", internal_data["stat_display_line1"], internal_data["stat_display_line2"])
- internal_data["stat_display_special"] = "message"
- if("alert")
- post_status("alert", href_list["alert"])
- internal_data["stat_display_special"] = href_list["alert"]
- if("setmsg")
- internal_data["stat_display_line[href_list["line"]]"] = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", internal_data["stat_display_line[href_list["line"]]"]) as text|null, 40), 40)
- else
- post_status(href_list["stat_display"])
- internal_data["stat_display_special"] = href_list["stat_display"]
-
- // Merc shuttle blast door controls
- switch(href_list["all_blast_doors"])
- if("open")
- for(var/obj/machinery/door/blast/B in internal_data["shuttle_doors"])
- B.open()
- if("close")
- for(var/obj/machinery/door/blast/B in internal_data["shuttle_doors"])
- B.close()
-
- if(href_list["scan_blast_doors"])
- internal_data["shuttle_doors"] = find_blast_doors()
-
- if(href_list["toggle_blast_door"])
- var/obj/machinery/door/blast/B = locate(href_list["toggle_blast_door"])
- if(!B)
- return
- spawn(0)
- if(B.density)
- B.open()
- else
- B.close()
-
-
-// Updates status displays with a new message
-// Copied from /obj/item/weapon/cartridge/proc/post_status(),
-// code/game/objects/items/devices/PDA/cart.dm, line 251
-/obj/item/weapon/commcard/proc/post_status(var/command, var/data1, var/data2)
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
- if(!frequency)
- return
-
- var/datum/signal/status_signal = new
- status_signal.source = src
- status_signal.transmission_method = TRANSMISSION_RADIO
- status_signal.data["command"] = command
-
- switch(command)
- if("message")
- status_signal.data["msg1"] = data1
- status_signal.data["msg2"] = data2
- internal_data["stat_display_active1"] = data1 // Update the internally stored message, we won't get receive_signal if we're the sender
- internal_data["stat_display_active2"] = data2
- if(loc)
- var/obj/item/PDA = loc
- var/mob/user = PDA.fingerprintslast
- log_admin("STATUS: [user] set status screen with [src]. Message: [data1] [data2]")
- message_admins("STATUS: [user] set status screen with [src]. Message: [data1] [data2]")
-
- if("alert")
- status_signal.data["picture_state"] = data1
-
- frequency.post_signal(src, status_signal)
-
-// Receives updates by external devices to the status displays
-/obj/item/weapon/commcard/receive_signal(var/datum/signal/signal, var/receive_method, var/receive_param)
- internal_data["stat_display_special"] = signal.data["command"]
- switch(signal.data["command"])
- if("message")
- internal_data["stat_display_active1"] = signal.data["msg1"]
- internal_data["stat_display_active2"] = signal.data["msg2"]
- if("alert")
- internal_data["stat_display_special"] = signal.data["picture_state"]
-
-
-///////////////////////////
-// SUBTYPES
-///////////////////////////
-
-
-// Engineering Cartridge:
-// Devices
-// *- Halogen Counter
-// Templates
-// *- Power Monitor
-/obj/item/weapon/commcard/engineering
- name = "\improper Power-ON cartridge"
- icon_state = "cart-e"
- ui_templates = list(list("name" = "Power Monitor", "template" = "comm_power_monitor.tmpl"))
-
-/obj/item/weapon/commcard/engineering/New()
- ..()
- internal_devices |= new /obj/item/device/halogen_counter(src)
-
-/obj/item/weapon/commcard/engineering/Initialize()
- internal_data["grid_sensors"] = find_powernet_sensors()
- internal_data["powernet_target"] = ""
-
-/obj/item/weapon/commcard/engineering/get_data()
- return list(
- list("field" = "powernet_monitoring", "value" = get_powernet_monitoring_list()),
- list("field" = "powernet_target", "value" = get_powernet_target(internal_data["powernet_target"]))
- )
-
-// Atmospherics Cartridge:
-// Devices
-// *- Gas scanner
-/obj/item/weapon/commcard/atmos
- name = "\improper BreatheDeep cartridge"
- icon_state = "cart-a"
-
-/obj/item/weapon/commcard/atmos/New()
- ..()
- internal_devices |= new /obj/item/device/analyzer(src)
-
-
-// Medical Cartridge:
-// Devices
-// *- Halogen Counter
-// *- Health Analyzer
-// Templates
-// *- Medical Records
-/obj/item/weapon/commcard/medical
- name = "\improper Med-U cartridge"
- icon_state = "cart-m"
- ui_templates = list(list("name" = "Medical Records", "template" = "med_records.tmpl"))
-
-/obj/item/weapon/commcard/medical/New()
- ..()
- internal_devices |= new /obj/item/device/healthanalyzer(src)
- internal_devices |= new /obj/item/device/halogen_counter(src)
-
-/obj/item/weapon/commcard/medical/get_data()
- return list(list("field" = "med_records", "value" = get_med_records()))
-
-
-// Chemistry Cartridge:
-// Devices
-// *- Halogen Counter
-// *- Health Analyzer
-// *- Reagent Scanner
-// Templates
-// *- Medical Records
-/obj/item/weapon/commcard/medical/chemistry
- name = "\improper ChemWhiz cartridge"
- icon_state = "cart-chem"
-
-/obj/item/weapon/commcard/medical/chemistry/New()
- ..()
- internal_devices |= new /obj/item/device/reagent_scanner(src)
-
-
-// Detective Cartridge:
-// Devices
-// *- Halogen Counter
-// *- Health Analyzer
-// Templates
-// *- Medical Records
-// *- Security Records
-/obj/item/weapon/commcard/medical/detective
- name = "\improper D.E.T.E.C.T. cartridge"
- icon_state = "cart-s"
- ui_templates = list(
- list("name" = "Medical Records", "template" = "med_records.tmpl"),
- list("name" = "Security Records", "template" = "sec_records.tmpl")
- )
-
-/obj/item/weapon/commcard/medical/detective/get_data()
- var/list/data = ..()
- data[++data.len] = list("field" = "sec_records", "value" = get_sec_records())
- return data
-
-
-// Internal Affairs Cartridge:
-// Templates
-// *- Security Records
-// *- Employment Records
-/obj/item/weapon/commcard/int_aff
- name = "\improper P.R.O.V.E. cartridge"
- icon_state = "cart-s"
- ui_templates = list(
- list("name" = "Employment Records", "template" = "emp_records.tmpl"),
- list("name" = "Security Records", "template" = "sec_records.tmpl")
- )
-
-/obj/item/weapon/commcard/int_aff/get_data()
- return list(
- list("field" = "emp_records", "value" = get_emp_records()),
- list("field" = "sec_records", "value" = get_sec_records())
- )
-
-
-// Security Cartridge:
-// Templates
-// *- Security Records
-// *- Security Bot Access
-/obj/item/weapon/commcard/security
- name = "\improper R.O.B.U.S.T. cartridge"
- icon_state = "cart-s"
- ui_templates = list(
- list("name" = "Security Records", "template" = "sec_records.tmpl"),
- list("name" = "Security Bot Control", "template" = "sec_bot_access.tmpl")
- )
-
-/obj/item/weapon/commcard/security/get_data()
- return list(
- list("field" = "sec_records", "value" = get_sec_records()),
- list("field" = "sec_bot_access", "value" = get_sec_bot_access())
- )
-
-
-// Janitor Cartridge:
-// Templates
-// *- Janitorial Locator Magicbox
-/obj/item/weapon/commcard/janitor
- name = "\improper CustodiPRO cartridge"
- desc = "The ultimate in clean-room design."
- ui_templates = list(
- list("name" = "Janitorial Supply Locator", "template" = "janitorialLocator.tmpl")
- )
-
-/obj/item/weapon/commcard/janitor/get_data()
- return list(
- list("field" = "janidata", "value" = get_janitorial_locations())
- )
-
-
-// Signal Cartridge:
-// Devices
-// *- Signaler
-// Templates
-// *- Signaler Access
-/obj/item/weapon/commcard/signal
- name = "generic signaler cartridge"
- desc = "A data cartridge with an integrated radio signaler module."
- ui_templates = list(
- list("name" = "Integrated Signaler Control", "template" = "signaler_access.tmpl")
- )
-
-/obj/item/weapon/commcard/signal/New()
- ..()
- internal_devices |= new /obj/item/device/assembly/signaler(src)
-
-/obj/item/weapon/commcard/signal/get_data()
- return list(
- list("field" = "signaler_access", "value" = get_int_signalers())
- )
-
-
-// Science Cartridge:
-// Devices
-// *- Signaler
-// *- Reagent Scanner
-// *- Gas Scanner
-// Templates
-// *- Signaler Access
-/obj/item/weapon/commcard/signal/science
- name = "\improper Signal Ace 2 cartridge"
- desc = "Complete with integrated radio signaler!"
- icon_state = "cart-tox"
- // UI templates inherited
-
-/obj/item/weapon/commcard/signal/science/New()
- ..()
- internal_devices |= new /obj/item/device/reagent_scanner(src)
- internal_devices |= new /obj/item/device/analyzer(src)
-
-
-// Supply Cartridge:
-// Templates
-// *- Supply Records
-/obj/item/weapon/commcard/supply
- name = "\improper Space Parts & Space Vendors cartridge"
- desc = "Perfect for the Quartermaster on the go!"
- icon_state = "cart-q"
- ui_templates = list(
- list("name" = "Supply Records", "template" = "supply_records.tmpl")
- )
-
-/obj/item/weapon/commcard/supply/New()
- ..()
- internal_data["supply_category"] = null
- internal_data["supply_controls"] = FALSE // Cannot control the supply shuttle, cannot accept orders
- internal_data["supply_pack_expanded"] = list()
- internal_data["supply_reqtime"] = -1
-
-/obj/item/weapon/commcard/supply/get_data()
- // Supply records data
- var/list/shuttle_status = get_supply_shuttle_status()
- var/list/orders = get_supply_orders()
- var/list/receipts = get_supply_receipts()
- var/list/misc_supply_data = get_misc_supply_data() // Packaging this stuff externally so it's less hardcoded into the specific cartridge
- var/list/pack_list = list() // List of supply packs within the currently selected category
-
- if(internal_data["supply_category"])
- pack_list = get_supply_pack_list()
-
- return list(
- list("field" = "shuttle_auth", "value" = misc_supply_data["shuttle_auth"]),
- list("field" = "order_auth", "value" = misc_supply_data["order_auth"]),
- list("field" = "supply_points", "value" = misc_supply_data["supply_points"]),
- list("field" = "categories", "value" = misc_supply_data["supply_categories"]),
- list("field" = "contraband", "value" = misc_supply_data["contraband"]),
- list("field" = "active_category", "value" = internal_data["supply_category"]),
- list("field" = "shuttle", "value" = shuttle_status),
- list("field" = "orders", "value" = orders),
- list("field" = "receipts", "value" = receipts),
- list("field" = "supply_packs", "value" = pack_list)
- )
-
-
-// Command Cartridge:
-// Templates
-// *- Status Display Access
-// *- Employment Records
-/obj/item/weapon/commcard/head
- name = "\improper Easy-Record DELUXE"
- icon_state = "cart-h"
- ui_templates = list(
- list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
- list("name" = "Employment Records", "template" = "emp_records.tmpl")
- )
-
-/obj/item/weapon/commcard/head/New()
- ..()
- internal_data["stat_display_line1"] = null
- internal_data["stat_display_line2"] = null
- internal_data["stat_display_active1"] = null
- internal_data["stat_display_active2"] = null
- internal_data["stat_display_special"] = null
-
-/obj/item/weapon/commcard/head/Initialize()
- // Have to register the commcard with the Radio controller to receive updates to the status displays
- radio_controller.add_object(src, 1435)
- ..()
-
-/obj/item/weapon/commcard/head/Destroy()
- // Have to unregister the commcard for proper bookkeeping
- radio_controller.remove_object(src, 1435)
- ..()
-
-/obj/item/weapon/commcard/head/get_data()
- return list(
- list("field" = "emp_records", "value" = get_emp_records()),
- list("field" = "stat_display", "value" = get_status_display())
- )
-
-// Head of Personnel Cartridge:
-// Templates
-// *- Status Display Access
-// *- Employment Records
-// *- Security Records
-// *- Supply Records
-// ?- Supply Bot Access
-// *- Janitorial Locator Magicbox
-/obj/item/weapon/commcard/head/hop
- name = "\improper HumanResources9001 cartridge"
- icon_state = "cart-h"
- ui_templates = list(
- list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
- list("name" = "Employment Records", "template" = "emp_records.tmpl"),
- list("name" = "Security Records", "template" = "sec_records.tmpl"),
- list("name" = "Supply Records", "template" = "supply_records.tmpl"),
- list("name" = "Janitorial Supply Locator", "template" = "janitorialLocator.tmpl")
- )
-
-
-/obj/item/weapon/commcard/head/hop/get_data()
- var/list/data = ..()
-
- // Sec records
- data[++data.len] = list("field" = "sec_records", "value" = get_sec_records())
-
- // Supply records data
- var/list/shuttle_status = get_supply_shuttle_status()
- var/list/orders = get_supply_orders()
- var/list/receipts = get_supply_receipts()
- var/list/misc_supply_data = get_misc_supply_data() // Packaging this stuff externally so it's less hardcoded into the specific cartridge
- var/list/pack_list = list() // List of supply packs within the currently selected category
-
- if(internal_data["supply_category"])
- pack_list = get_supply_pack_list()
-
- data[++data.len] = list("field" = "shuttle_auth", "value" = misc_supply_data["shuttle_auth"])
- data[++data.len] = list("field" = "order_auth", "value" = misc_supply_data["order_auth"])
- data[++data.len] = list("field" = "supply_points", "value" = misc_supply_data["supply_points"])
- data[++data.len] = list("field" = "categories", "value" = misc_supply_data["supply_categories"])
- data[++data.len] = list("field" = "contraband", "value" = misc_supply_data["contraband"])
- data[++data.len] = list("field" = "active_category", "value" = internal_data["supply_category"])
- data[++data.len] = list("field" = "shuttle", "value" = shuttle_status)
- data[++data.len] = list("field" = "orders", "value" = orders)
- data[++data.len] = list("field" = "receipts", "value" = receipts)
- data[++data.len] = list("field" = "supply_packs", "value" = pack_list)
-
- // Janitorial locator magicbox
- data[++data.len] = list("field" = "janidata", "value" = get_janitorial_locations())
-
- return data
-
-
-// Head of Security Cartridge:
-// Templates
-// *- Status Display Access
-// *- Employment Records
-// *- Security Records
-// *- Security Bot Access
-/obj/item/weapon/commcard/head/hos
- name = "\improper R.O.B.U.S.T. DELUXE"
- icon_state = "cart-hos"
- ui_templates = list(
- list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
- list("name" = "Employment Records", "template" = "emp_records.tmpl"),
- list("name" = "Security Records", "template" = "sec_records.tmpl"),
- list("name" = "Security Bot Control", "template" = "sec_bot_access.tmpl")
- )
-
-/obj/item/weapon/commcard/head/hos/get_data()
- var/list/data = ..()
- // Sec records
- data[++data.len] = list("field" = "sec_records", "value" = get_sec_records())
- // Sec bot access
- data[++data.len] = list("field" = "sec_bot_access", "value" = get_sec_bot_access())
- return data
-
-
-// Research Director Cartridge:
-// Devices
-// *- Signaler
-// *- Gas Scanner
-// *- Reagent Scanner
-// Templates
-// *- Status Display Access
-// *- Employment Records
-// *- Signaler Access
-/obj/item/weapon/commcard/head/rd
- name = "\improper Signal Ace DELUXE"
- icon_state = "cart-rd"
- ui_templates = list(
- list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
- list("name" = "Employment Records", "template" = "emp_records.tmpl"),
- list("name" = "Integrated Signaler Control", "template" = "signaler_access.tmpl")
- )
-
-/obj/item/weapon/commcard/head/rd/New()
- ..()
- internal_devices |= new /obj/item/device/analyzer(src)
- internal_devices |= new /obj/item/device/reagent_scanner(src)
- internal_devices |= new /obj/item/device/assembly/signaler(src)
-
-/obj/item/weapon/commcard/head/rd/get_data()
- var/list/data = ..()
- // Signaler access
- data[++data.len] = list("field" = "signaler_access", "value" = get_int_signalers())
- return data
-
-
-// Chief Medical Officer Cartridge:
-// Devices
-// *- Health Analyzer
-// *- Reagent Scanner
-// *- Halogen Counter
-// Templates
-// *- Status Display Access
-// *- Employment Records
-// *- Medical Records
-/obj/item/weapon/commcard/head/cmo
- name = "\improper Med-U DELUXE"
- icon_state = "cart-cmo"
- ui_templates = list(
- list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
- list("name" = "Employment Records", "template" = "emp_records.tmpl"),
- list("name" = "Medical Records", "template" = "med_records.tmpl")
- )
-
-/obj/item/weapon/commcard/head/cmo/New()
- ..()
- internal_devices |= new /obj/item/device/healthanalyzer(src)
- internal_devices |= new /obj/item/device/reagent_scanner(src)
- internal_devices |= new /obj/item/device/halogen_counter(src)
-
-/obj/item/weapon/commcard/head/cmo/get_data()
- var/list/data = ..()
- // Med records
- data[++data.len] = list("field" = "med_records", "value" = get_med_records())
- return data
-
-// Chief Engineer Cartridge:
-// Devices
-// *- Gas Scanner
-// *- Halogen Counter
-// Templates
-// *- Status Display Access
-// *- Employment Records
-// *- Power Monitoring
-/obj/item/weapon/commcard/head/ce
- name = "\improper Power-On DELUXE"
- icon_state = "cart-ce"
- ui_templates = list(
- list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
- list("name" = "Employment Records", "template" = "emp_records.tmpl"),
- list("name" = "Power Monitor", "template" = "comm_power_monitor.tmpl")
- )
-
-/obj/item/weapon/commcard/head/ce/New()
- ..()
- internal_devices |= new /obj.item/device/analyzer(src)
- internal_devices |= new /obj/item/device/halogen_counter(src)
-
-/obj/item/weapon/commcard/head/ce/Initialize()
- internal_data["grid_sensors"] = find_powernet_sensors()
- internal_data["powernet_target"] = ""
-
-/obj/item/weapon/commcard/head/ce/get_data()
- var/list/data = ..()
- // Add power monitoring data
- data[++data.len] = list("field" = "powernet_monitoring", "value" = get_powernet_monitoring_list())
- data[++data.len] = list("field" = "powernet_target", "value" = get_powernet_target(internal_data["powernet_target"]))
- return data
-
-
-// Captain Cartridge:
-// Devices
-// *- Health analyzer
-// *- Gas Scanner
-// *- Reagent Scanner
-// *- Halogen Counter
-// X- GPS - Balance
-// *- Signaler
-// Templates
-// *- Status Display Access
-// *- Employment Records
-// *- Medical Records
-// *- Security Records
-// *- Power Monitoring
-// *- Supply Records
-// X- Supply Bot Access - Mulebots usually break when used
-// *- Security Bot Access
-// *- Janitorial Locator Magicbox
-// X- GPS Access - Balance
-// *- Signaler Access
-/obj/item/weapon/commcard/head/captain
- name = "\improper Value-PAK cartridge"
- desc = "Now with 200% more value!"
- icon_state = "cart-c"
- ui_templates = list(
- list("name" = "Status Display Access", "template" = "stat_display_access.tmpl"),
- list("name" = "Employment Records", "template" = "emp_records.tmpl"),
- list("name" = "Medical Records", "template" = "med_records.tmpl"),
- list("name" = "Security Records", "template" = "sec_records.tmpl"),
- list("name" = "Security Bot Control", "template" = "sec_bot_access.tmpl"),
- list("name" = "Power Monitor", "template" = "comm_power_monitor.tmpl"),
- list("name" = "Supply Records", "template" = "supply_records.tmpl"),
- list("name" = "Janitorial Supply Locator", "template" = "janitorialLocator.tmpl"),
- list("name" = "Integrated Signaler Control", "template" = "signaler_access.tmpl")
- )
-
-/obj/item/weapon/commcard/head/captain/New()
- ..()
- internal_devices |= new /obj.item/device/analyzer(src)
- internal_devices |= new /obj/item/device/healthanalyzer(src)
- internal_devices |= new /obj/item/device/reagent_scanner(src)
- internal_devices |= new /obj/item/device/halogen_counter(src)
- internal_devices |= new /obj/item/device/assembly/signaler(src)
-
-/obj/item/weapon/commcard/head/captain/get_data()
- var/list/data = ..()
- //Med records
- data[++data.len] = list("field" = "med_records", "value" = get_med_records())
-
- // Sec records
- data[++data.len] = list("field" = "sec_records", "value" = get_sec_records())
-
- // Sec bot access
- data[++data.len] = list("field" = "sec_bot_access", "value" = get_sec_bot_access())
-
- // Power Monitoring
- data[++data.len] = list("field" = "powernet_monitoring", "value" = get_powernet_monitoring_list())
- data[++data.len] = list("field" = "powernet_target", "value" = get_powernet_target(internal_data["powernet_target"]))
-
- // Supply records data
- var/list/shuttle_status = get_supply_shuttle_status()
- var/list/orders = get_supply_orders()
- var/list/receipts = get_supply_receipts()
- var/list/misc_supply_data = get_misc_supply_data() // Packaging this stuff externally so it's less hardcoded into the specific cartridge
- var/list/pack_list = list() // List of supply packs within the currently selected category
-
- if(internal_data["supply_category"])
- pack_list = get_supply_pack_list()
-
- data[++data.len] = list("field" = "shuttle_auth", "value" = misc_supply_data["shuttle_auth"])
- data[++data.len] = list("field" = "order_auth", "value" = misc_supply_data["order_auth"])
- data[++data.len] = list("field" = "supply_points", "value" = misc_supply_data["supply_points"])
- data[++data.len] = list("field" = "categories", "value" = misc_supply_data["supply_categories"])
- data[++data.len] = list("field" = "contraband", "value" = misc_supply_data["contraband"])
- data[++data.len] = list("field" = "active_category", "value" = internal_data["supply_category"])
- data[++data.len] = list("field" = "shuttle", "value" = shuttle_status)
- data[++data.len] = list("field" = "orders", "value" = orders)
- data[++data.len] = list("field" = "receipts", "value" = receipts)
- data[++data.len] = list("field" = "supply_packs", "value" = pack_list)
-
- // Janitorial locator magicbox
- data[++data.len] = list("field" = "janidata", "value" = get_janitorial_locations())
-
- // Signaler access
- data[++data.len] = list("field" = "signaler_access", "value" = get_int_signalers())
-
- return data
-
-
-// Mercenary Cartridge
-// Templates
-// *- Merc Shuttle Door Controller
-/obj/item/weapon/commcard/mercenary
- name = "\improper Detomatix cartridge"
- icon_state = "cart"
- ui_templates = list(
- list("name" = "Shuttle Blast Door Control", "template" = "merc_blast_door_control.tmpl")
- )
-
-/obj/item/weapon/commcard/mercenary/Initialize()
- internal_data["shuttle_door_code"] = "smindicate" // Copied from PDA code
- internal_data["shuttle_doors"] = find_blast_doors()
-
-/obj/item/weapon/commcard/mercenary/get_data()
- var/door_status[0]
- for(var/obj/machinery/door/blast/B in internal_data["shuttle_doors"])
- door_status[++door_status.len] += list(
- "open" = B.density,
- "name" = B.name,
- "ref" = "\ref[B]"
- )
-
- return list(
- list("field" = "blast_door", "value" = door_status)
- )
-
-
-// Explorer Cartridge
-// Devices
-// *- GPS
-// Templates
-// *- GPS Access
-
-// IMPORTANT: NOT MAPPED IN DUE TO BALANCE CONCERNS RE: FINDING THE VICTIMS OF ANTAGS.
-// See suit sensors, specifically ease of turning them off, and variable level of settings which may or may not give location
-// A GPS in your phone that is either broadcasting position or totally off, and can be hidden in pockets, coats, bags, boxes, etc, is much harder to disable
-/obj/item/weapon/commcard/explorer
- name = "\improper Explorator cartridge"
- icon_state = "cart-tox"
- ui_templates = list(
- list("name" = "Integrated GPS", "template" = "gps_access.tmpl")
- )
-
-/obj/item/weapon/commcard/explorer/New()
- ..()
- internal_devices |= new /obj/item/device/gps/explorer(src)
-
-/obj/item/weapon/commcard/explorer/get_data()
- var/list/GPS = get_GPS_lists()
-
- return list(
- list("field" = "gps_access", "value" = GPS[1]),
- list("field" = "gps_signal", "value" = GPS[2]),
- list("field" = "gps_status", "value" = GPS[3])
- )
\ No newline at end of file
diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm
index 392af1b870..358ef3b61b 100644
--- a/code/game/objects/items/devices/communicator/communicator.dm
+++ b/code/game/objects/items/devices/communicator/communicator.dm
@@ -14,7 +14,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
#define WTHRTAB 7
#define MANITAB 8
#define SETTTAB 9
-#define EXTRTAB 10
/obj/item/device/communicator
name = "communicator"
@@ -43,19 +42,18 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
var/note = "Thank you for choosing the T-14.2 Communicator, this is your notepad!" //Current note in the notepad function
var/notehtml = ""
- var/obj/item/weapon/commcard/cartridge = null //current cartridge
var/fon = 0 // Internal light
var/flum = 2 // Brightness
var/list/modules = list(
- list("module" = "Phone", "icon" = "phone64", "number" = PHONTAB),
- list("module" = "Contacts", "icon" = "person64", "number" = CONTTAB),
- list("module" = "Messaging", "icon" = "comment64", "number" = MESSTAB),
- list("module" = "News", "icon" = "note64", "number" = NEWSTAB), // Need a different icon,
- list("module" = "Note", "icon" = "note64", "number" = NOTETAB),
- list("module" = "Weather", "icon" = "sun64", "number" = WTHRTAB),
- list("module" = "Crew Manifest", "icon" = "note64", "number" = MANITAB), // Need a different icon,
- list("module" = "Settings", "icon" = "gear64", "number" = SETTTAB),
+ list("module" = "Phone", "icon" = "phone", "number" = PHONTAB),
+ list("module" = "Contacts", "icon" = "user", "number" = CONTTAB),
+ list("module" = "Messaging", "icon" = "comment-alt", "number" = MESSTAB),
+ list("module" = "News", "icon" = "newspaper", "number" = NEWSTAB), // Need a different icon,
+ list("module" = "Note", "icon" = "sticky-note", "number" = NOTETAB),
+ list("module" = "Weather", "icon" = "sun", "number" = WTHRTAB),
+ list("module" = "Crew Manifest", "icon" = "crown", "number" = MANITAB), // Need a different icon,
+ list("module" = "Settings", "icon" = "cog", "number" = SETTTAB),
) //list("module" = "Name of Module", "icon" = "icon name64", "number" = "what tab is the module")
var/selected_tab = HOMETAB
@@ -104,13 +102,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
register_device(S.loc.name)
initialize_exonet(S.loc)
-// Proc: examine()
-// Parameters: user - the user doing the examining
-// Description: Allows the user to click a link when examining to look at video if one is going.
-/obj/item/device/communicator/examine(mob/user)
- . = ..()
- if(Adjacent(user) && video_source)
- . += "It looks like it's on a video call: \[view\]"
// Proc: initialize_exonet()
// Parameters: 1 (user - the person the communicator belongs to)
@@ -132,6 +123,9 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
// Description: Shows all the voice mobs inside the device, and their status.
/obj/item/device/communicator/examine(mob/user)
. = ..()
+
+ if(Adjacent(user) && video_source)
+ . += "It looks like it's on a video call: \[view\]"
for(var/mob/living/voice/voice in contents)
. += "On the screen, you can see a image feed of [voice]."
@@ -148,6 +142,17 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
else
. += "The device doesn't appear to be transmitting any data."
+// Proc: Topic()
+// Parameters: href, href_list - Data from a link
+// Description: Used by the above examine.
+/obj/item/device/communicator/Topic(href, href_list)
+ if(..())
+ return 1
+
+ if(href_list["watchvideo"])
+ if(video_source)
+ watch_video(usr)
+
// Proc: emp_act()
// Parameters: None
// Description: Drops all calls when EMPed, so the holder can then get murdered by the antagonist.
@@ -203,17 +208,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
if(!get_connection_to_tcomms())
close_connection(reason = "Connection timed out")
-// Proc: attack()
-// Parameters: 2 (M - what is being attacked. user - the mob that has the communicator)
-// Description: When the communicator has an attached commcard with internal devices, relay the attack() through to those devices.
-// Contents of the for loop are copied from gripper code, because that does approximately what we want to do.
-/obj/item/device/communicator/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
- if(cartridge && cartridge.active_devices)
- for(var/obj/item/wrapped in cartridge.active_devices)
- if(wrapped) //The force of the wrapped obj gets set to zero during the attack() and afterattack().
- wrapped.attack(M,user)
- return 0
-
// Proc: attackby()
// Parameters: 2 (C - what is used on the communicator. user - the mob that has the communicator)
// Description: When an ID is swiped on the communicator, the communicator reads the job and checks it against the Owner name, if success, the occupation is added.
@@ -229,13 +223,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
occupation = idcard.assignment
to_chat(user, "Occupation updated.")
- if(istype(C, /obj/item/weapon/commcard) && !cartridge)
- cartridge = C
- user.drop_item()
- cartridge.forceMove(src)
- to_chat(usr, "You slot \the [cartridge] into \the [src].")
- modules[++modules.len] = list("module" = "External Device", "icon" = "external64", "number" = EXTRTAB)
- SSnanoui.update_uis(src) // update all UIs attached to src
return
// Proc: attack_self()
@@ -246,7 +233,7 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
initialize_exonet(user)
alert_called = 0
update_icon()
- ui_interact(user)
+ tgui_interact(user)
if(video_source)
watch_video(user)
@@ -358,38 +345,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
client_huds |= global_hud.whitense
client_huds |= global_hud.darkMask
-/obj/item/device/communicator/verb/verb_remove_cartridge()
- set category = "Object"
- set name = "Remove commcard"
- set src in usr
-
- // Can't remove what isn't there
- if(!cartridge)
- to_chat(usr, "There isn't a commcard to remove!")
- return
-
- // Can't remove if you're physically unable to
- if(usr.stat || usr.restrained() || usr.paralysis || usr.stunned || usr.weakened)
- to_chat(usr, "You cannot do this while restrained.")
- return
-
- var/turf/T = get_turf(src)
- cartridge.loc = T
- // If it's in someone, put the cartridge in their hands
- if (ismob(loc))
- var/mob/M = loc
- M.put_in_hands(cartridge)
- // Else just set it on the ground
- else
- cartridge.loc = get_turf(src)
- cartridge = null
- // We have to iterate through the modules to find EXTRTAB, because list procs don't play nice with a list of lists
- for(var/i = 1, i <= modules.len, i++)
- if(modules[i]["number"] == EXTRTAB)
- modules.Cut(i, i+1)
- break
- to_chat(usr, "You remove \the [cartridge] from the [name].")
-
//It's the 26th century. We should have smart watches by now.
/obj/item/device/communicator/watch
name = "communicator watch"
diff --git a/code/game/objects/items/devices/communicator/helper.dm b/code/game/objects/items/devices/communicator/helper.dm
index ec67686668..b406100456 100644
--- a/code/game/objects/items/devices/communicator/helper.dm
+++ b/code/game/objects/items/devices/communicator/helper.dm
@@ -20,7 +20,7 @@
// Values were extracted from the template itself
results = list(
list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
- list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
+ list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
@@ -44,19 +44,18 @@
var/index = 0
for(var/datum/feed_message/FM in channel.messages)
index++
+ var/list/msgdata = list(
+ "author" = FM.author,
+ "body" = FM.body,
+ "img" = null,
+ "message_type" = FM.message_type,
+ "time_stamp" = FM.time_stamp,
+ "caption" = FM.caption,
+ "index" = index
+ )
if(FM.img)
- usr << browse_rsc(FM.img, "pda_news_tmp_photo_[feeds["channel"]]_[index].png")
- // News stories are HTML-stripped but require newline replacement to be properly displayed in NanoUI
- var/body = replacetext(FM.body, "\n", "
")
- messages[++messages.len] = list(
- "author" = FM.author,
- "body" = body,
- "message_type" = FM.message_type,
- "time_stamp" = FM.time_stamp,
- "has_image" = (FM.img != null),
- "caption" = FM.caption,
- "index" = index
- )
+ msgdata["img"] = icon2base64(FM.img)
+ messages[++messages.len] = msgdata
feeds[++feeds.len] = list(
"name" = channel.channel_name,
@@ -96,448 +95,3 @@
news.Swap(1, 3) // List is sorted in ascending order of timestamp, we want descending
return news
-
-
-
-// Putting the commcard data harvesting helpers here
-// Not ideal to put all the procs on the base type
-// but it may open options for adminbus,
-// And it saves duplicated code
-
-
-// Medical records
-/obj/item/weapon/commcard/proc/get_med_records()
- var/med_records[0]
- for(var/datum/data/record/M in sortRecord(data_core.medical))
- var/record[0]
- record[++record.len] = list("tab" = "Name", "val" = M.fields["name"])
- record[++record.len] = list("tab" = "ID", "val" = M.fields["id"])
- record[++record.len] = list("tab" = "Blood Type", "val" = M.fields["b_type"])
- record[++record.len] = list("tab" = "DNA #", "val" = M.fields["b_dna"])
- record[++record.len] = list("tab" = "Gender", "val" = M.fields["id_gender"])
- record[++record.len] = list("tab" = "Entity Classification", "val" = M.fields["brain_type"])
- record[++record.len] = list("tab" = "Minor Disorders", "val" = M.fields["mi_dis"])
- record[++record.len] = list("tab" = "Major Disorders", "val" = M.fields["ma_dis"])
- record[++record.len] = list("tab" = "Allergies", "val" = M.fields["alg"])
- record[++record.len] = list("tab" = "Condition", "val" = M.fields["cdi"])
- record[++record.len] = list("tab" = "Notes", "val" = M.fields["notes"])
-
- med_records[++med_records.len] = list("name" = M.fields["name"], "record" = record)
- return med_records
-
-
-// Employment records
-/obj/item/weapon/commcard/proc/get_emp_records()
- var/emp_records[0]
- for(var/datum/data/record/G in sortRecord(data_core.general))
- var/record[0]
- record[++record.len] = list("tab" = "Name", "val" = G.fields["name"])
- record[++record.len] = list("tab" = "ID", "val" = G.fields["id"])
- record[++record.len] = list("tab" = "Rank", "val" = G.fields["rank"])
- record[++record.len] = list("tab" = "Fingerprint", "val" = G.fields["fingerprint"])
- record[++record.len] = list("tab" = "Entity Classification", "val" = G.fields["brain_type"])
- record[++record.len] = list("tab" = "Sex", "val" = G.fields["sex"])
- record[++record.len] = list("tab" = "Species", "val" = G.fields["species"])
- record[++record.len] = list("tab" = "Age", "val" = G.fields["age"])
- record[++record.len] = list("tab" = "Notes", "val" = G.fields["notes"])
-
- emp_records[++emp_records.len] = list("name" = G.fields["name"], "record" = record)
- return emp_records
-
-
-// Security records
-/obj/item/weapon/commcard/proc/get_sec_records()
- var/sec_records[0]
- for(var/datum/data/record/G in sortRecord(data_core.general))
- var/record[0]
- record[++record.len] = list("tab" = "Name", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Sex", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Species", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Age", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Rank", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Fingerprint", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Physical Status", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Mental Status", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Criminal Status", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Major Crimes", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Minor Crimes", "val" = G.fields[""])
- record[++record.len] = list("tab" = "Notes", "val" = G.fields["notes"])
-
- sec_records[++sec_records.len] = list("name" = G.fields["name"], "record" = record)
- return sec_records
-
-
-// Status of all secbots
-// Weaker than what PDAs appear to do, but as of 7/1/2018 PDA secbot access is nonfunctional
-/obj/item/weapon/commcard/proc/get_sec_bot_access()
- var/sec_bots[0]
- for(var/mob/living/bot/secbot/S in mob_list)
- // Get new bot
- var/status[0]
- status[++status.len] = list("tab" = "Name", "val" = sanitize(S.name))
-
- // If it's turned off, then it shouldn't be broadcasting any further info
- if(!S.on)
- status[++status.len] = list("tab" = "Power", "val" = "Off") // Encoding the span classes here so I don't have to do complicated switches in the ui template
- continue
- status[++status.len] = list("tab" = "Power", "val" = "On")
-
- // -- What it's doing
- // If it's engaged, then say who it thinks it's engaging
- if(S.target)
- status[++status.len] = list("tab" = "Status", "val" = "Apprehending Target")
- status[++status.len] = list("tab" = "Target", "val" = S.target_name(S.target))
- // Else if it's patrolling
- else if(S.will_patrol)
- status[++status.len] = list("tab" = "Status", "val" = "Patrolling")
- // Otherwise we don't know what it's doing
- else
- status[++status.len] = list("tab" = "Status", "val" = "Idle")
-
- // Where it is
- status[++status.len] = list("tab" = "Location", "val" = sanitize("[get_area(S.loc)]"))
-
- // Append bot to the list
- sec_bots[++sec_bots.len] = list("bot" = S.name, "status" = status)
- return sec_bots
-
-
-// Code and frequency of stored signalers
-// Supports multiple signalers within the device
-/obj/item/weapon/commcard/proc/get_int_signalers()
- var/signalers[0]
- for(var/obj/item/device/assembly/signaler/S in internal_devices)
- var/unit[0]
- unit[++unit.len] = list("tab" = "Code", "val" = S.code)
- unit[++unit.len] = list("tab" = "Frequency", "val" = S.frequency)
-
- signalers[++signalers.len] = list("ref" = "\ref[S]", "status" = unit)
-
- return signalers
-
-// Returns list of all powernet sensors currently visible to the commcard
-/obj/item/weapon/commcard/proc/find_powernet_sensors()
- var/grid_sensors[0]
-
- // Find all the powernet sensors we need to pull data from
- // Copied from /datum/nano_module/power_monitor/proc/refresh_sensors(),
- // located in '/code/modules/nano/modules/power_monitor.dm'
- // Minor tweaks for efficiency and cleanliness
- var/turf/T = get_turf(src)
- if(T)
- var/list/levels = using_map.get_map_levels(T.z, FALSE)
- for(var/obj/machinery/power/sensor/S in machines)
- if((S.long_range) || (S.loc.z in levels) || (S.loc.z == T.z)) // Consoles have range on their Z-Level. Sensors with long_range var will work between Z levels.
- if(S.name_tag == "#UNKN#") // Default name. Shouldn't happen!
- warning("Powernet sensor with unset ID Tag! [S.x]X [S.y]Y [S.z]Z")
- else
- grid_sensors += S
- return grid_sensors
-
-// List of powernets
-/obj/item/weapon/commcard/proc/get_powernet_monitoring_list()
- // Fetch power monitor data
- var/sensors[0]
-
- for(var/obj/machinery/power/sensor/S in internal_data["grid_sensors"])
- var/list/focus = S.return_reading_data()
-
- sensors[++sensors.len] = list(
- "name" = S.name_tag,
- "alarm" = focus["alarm"]
- )
-
- return sensors
-
-// Information about the targeted powernet
-/obj/item/weapon/commcard/proc/get_powernet_target(var/target_sensor)
- if(!target_sensor)
- return
-
- var/powernet_target[0]
-
- for(var/obj/machinery/power/sensor/S in internal_data["grid_sensors"])
- var/list/focus = S.return_reading_data()
-
- // Packages the span class here so it doesn't need to be interpreted w/in the for loop in the ui template
- var/load_stat = "Optimal"
- if(focus["load_percentage"] >= 95)
- load_stat = "DANGER: Overload"
- else if(focus["load_percentage"] >= 85)
- load_stat = "WARNING: High Load"
-
- var/alarm_stat = focus["alarm"] ? "WARNING: Abnormal activity detected!" : "Secure"
-
- if(target_sensor == S.name_tag)
- powernet_target = list(
- "name" = S.name_tag,
- "alarm" = focus["alarm"],
- "error" = focus["error"],
- "apc_data" = focus["apc_data"],
- "status" = list(
- list("field" = "Network Load Status", "statval" = load_stat),
- list("field" = "Network Security Status", "statval" = alarm_stat),
- list("field" = "Load Percentage", "statval" = focus["load_percentage"]),
- list("field" = "Available Power", "statval" = focus["total_avail"]),
- list("field" = "APC Power Usage", "statval" = focus["total_used_apc"]),
- list("field" = "Other Power Usage", "statval" = focus["total_used_other"]),
- list("field" = "Total Usage", "statval" = focus["total_used_all"])
- )
- )
-
- return powernet_target
-
-// Compiles the locations of all janitorial paraphernalia, as used by janitorialLocator.tmpl
-/obj/item/weapon/commcard/proc/get_janitorial_locations()
- // Fetch janitorial locator
- var/janidata[0]
- var/list/cleaningList = list()
- cleaningList += all_mops + all_mopbuckets + all_janitorial_carts
-
- // User's location
- var/turf/userloc = get_turf(src)
- if(isturf(userloc))
- janidata[++janidata.len] = list("field" = "Current Location", "val" = "[userloc.x], [userloc.y], [using_map.get_zlevel_name(userloc.z)]")
- else
- janidata[++janidata.len] = list("field" = "Current Location", "val" = "Unknown")
- return janidata // If the user isn't on a valid turf, then it shouldn't be able to find anything anyways
-
- // Mops, mop buckets, janitorial carts.
- for(var/obj/C in cleaningList)
- var/turf/T = get_turf(C)
- if(isturf(T) )//&& T.z in using_map.get_map_levels(userloc, FALSE))
- if(T.z == userloc.z)
- janidata[++janidata.len] = list("field" = apply_text_macros("\proper [C.name]"), "val" = "[T.x], [T.y], [using_map.get_zlevel_name(T.z)]")
- else
- janidata[++janidata.len] = list("field" = apply_text_macros("\proper [C.name]"), "val" = "[T.x], [T.y], [using_map.get_zlevel_name(T.z)]")
-
- // Cleanbots
- for(var/mob/living/bot/cleanbot/B in living_mob_list)
- var/turf/T = get_turf(B)
- if(isturf(T) )//&& T.z in using_map.get_map_levels(userloc, FALSE))
- var/textout = ""
- if(B.on)
- textout += "Status: Online
"
- if(T.z == userloc.z)
- textout += "[T.x], [T.y], [using_map.get_zlevel_name(T.z)]"
- else
- textout += "[T.x], [T.y], [using_map.get_zlevel_name(T.z)]"
- else
- textout += "Status: Offline"
-
- janidata[++janidata.len] = list("field" = "[B.name]", "val" = textout)
-
- return janidata
-
-// Compiles the three lists used by GPS_access.tmpl
-// The contents of the three lists are inherently related, so separating them into different procs would be largely redundant
-/obj/item/weapon/commcard/proc/get_GPS_lists()
- // GPS Access
- var/intgps[0] // Gps devices within the commcard -- Allow tag edits, turning on/off, etc
- var/extgps[0] // Gps devices not inside the commcard -- Print locations if a gps is on
- var/stagps[0] // Gps net status, location, whether it's on, if it's got long range
- var/obj/item/device/gps/cumulative = new(src)
- cumulative.tracking = FALSE
- cumulative.local_mode = TRUE // Won't detect long-range signals automatically
- cumulative.long_range = FALSE
- var/list/toggled_gps = list() // List of GPS units that are turned off before display_list() is called
-
- for(var/obj/item/device/gps/G in internal_devices)
- var/gpsdata[0]
- if(G.tracking && !G.emped)
- cumulative.tracking = TRUE // Turn it on
- if(G.long_range)
- cumulative.long_range = TRUE // It can detect long-range
- if(!G.local_mode)
- cumulative.local_mode = FALSE // It is detecting long-range
-
- gpsdata["ref"] = "\ref[G]"
- gpsdata["tag"] = G.gps_tag
- gpsdata["power"] = G.tracking
- gpsdata["local_mode"] = G.local_mode
- gpsdata["long_range"] = G.long_range
- gpsdata["hide_signal"] = G.hide_signal
- gpsdata["can_hide"] = G.can_hide_signal
-
- intgps[++intgps.len] = gpsdata // Add it to the list
-
- if(G.tracking)
- G.tracking = FALSE // Disable the internal gps units so they don't show up in the report
- toggled_gps += G
-
- var/list/remote_gps = cumulative.display_list() // Fetch information for all units except the ones inside of this device
-
- for(var/obj/item/device/gps/G in toggled_gps) // Reenable any internal GPS units
- G.tracking = TRUE
-
- stagps["enabled"] = cumulative.tracking
- stagps["long_range_en"] = (cumulative.long_range && !cumulative.local_mode)
-
- stagps["my_area_name"] = remote_gps["my_area_name"]
- stagps["curr_x"] = remote_gps["curr_x"]
- stagps["curr_y"] = remote_gps["curr_y"]
- stagps["curr_z"] = remote_gps["curr_z"]
- stagps["curr_z_name"] = remote_gps["curr_z_name"]
-
- extgps = remote_gps["gps_list"] // Compiled by the GPS
-
- qdel(cumulative) // Don't want spare GPS units building up in the contents
-
- return list(
- intgps,
- extgps,
- stagps
- )
-
-// Collects the current status of the supply shuttle
-// Copied from /obj/machinery/computer/supplycomp/ui_interact(),
-// code\game\machinery\computer\supply.dm, starting at line 55
-/obj/item/weapon/commcard/proc/get_supply_shuttle_status()
- var/shuttle_status[0]
- var/datum/shuttle/autodock/ferry/supply/shuttle = SSsupply.shuttle
- if(shuttle)
- if(shuttle.has_arrive_time())
- shuttle_status["location"] = "In transit"
- shuttle_status["mode"] = SUP_SHUTTLE_TRANSIT
- shuttle_status["time"] = shuttle.eta_minutes()
-
- else
- shuttle_status["time"] = 0
- if(shuttle.at_station())
- if(shuttle.shuttle_docking_controller)
- switch(shuttle.shuttle_docking_controller.get_docking_status())
- if("docked")
- shuttle_status["location"] = "Docked"
- shuttle_status["mode"] = SUP_SHUTTLE_DOCKED
- if("undocked")
- shuttle_status["location"] = "Undocked"
- shuttle_status["mode"] = SUP_SHUTTLE_UNDOCKED
- if("docking")
- shuttle_status["location"] = "Docking"
- shuttle_status["mode"] = SUP_SHUTTLE_DOCKING
- shuttle_status["force"] = shuttle.can_force()
- if("undocking")
- shuttle_status["location"] = "Undocking"
- shuttle_status["mode"] = SUP_SHUTTLE_UNDOCKING
- shuttle_status["force"] = shuttle.can_force()
-
- else
- shuttle_status["location"] = "Station"
- shuttle_status["mode"] = SUP_SHUTTLE_DOCKED
-
- else
- shuttle_status["location"] = "Away"
- shuttle_status["mode"] = SUP_SHUTTLE_AWAY
-
- if(shuttle.can_launch())
- shuttle_status["launch"] = 1
- else if(shuttle.can_cancel())
- shuttle_status["launch"] = 2
- else
- shuttle_status["launch"] = 0
-
- switch(shuttle.moving_status)
- if(SHUTTLE_IDLE)
- shuttle_status["engine"] = "Idle"
- if(SHUTTLE_WARMUP)
- shuttle_status["engine"] = "Warming up"
- if(SHUTTLE_INTRANSIT)
- shuttle_status["engine"] = "Engaged"
-
- else
- shuttle["mode"] = SUP_SHUTTLE_ERROR
-
- return shuttle_status
-
-// Compiles the list of supply orders
-// Copied from /obj/machinery/computer/supplycomp/ui_interact(),
-// code\game\machinery\computer\supply.dm, starting at line 130
-/obj/item/weapon/commcard/proc/get_supply_orders()
- var/orders[0]
- for(var/datum/supply_order/S in SSsupply.order_history)
- orders[++orders.len] = list(
- "ref" = "\ref[S]",
- "status" = S.status,
- "entries" = list(
- list("field" = "Supply Pack", "entry" = S.name),
- list("field" = "Cost", "entry" = S.cost),
- list("field" = "Index", "entry" = S.index),
- list("field" = "Reason", "entry" = S.comment),
- list("field" = "Ordered by", "entry" = S.ordered_by),
- list("field" = "Ordered at", "entry" = S.ordered_at),
- list("field" = "Approved by", "entry" = S.approved_by),
- list("field" = "Approved at", "entry" = S.approved_at)
- )
- )
-
- return orders
-
-// Compiles the list of supply export receipts
-// Copied from /obj/machinery/computer/supplycomp/ui_interact(),
-// code\game\machinery\computer\supply.dm, starting at line 147
-/obj/item/weapon/commcard/proc/get_supply_receipts()
- var/receipts[0]
- for(var/datum/exported_crate/E in SSsupply.exported_crates)
- receipts[++receipts.len] = list(
- "ref" = "\ref[E]",
- "contents" = E.contents,
- "error" = E.contents["error"],
- "title" = list(
- list("field" = "Name", "entry" = E.name),
- list("field" = "Value", "entry" = E.value)
- )
- )
- return receipts
-
-
-// Compiles the list of supply packs for the category currently stored in internal_data["supply_category"]
-// Copied from /obj/machinery/computer/supplycomp/ui_interact(),
-// code\game\machinery\computer\supply.dm, starting at line 147
-/obj/item/weapon/commcard/proc/get_supply_pack_list()
- var/supply_packs[0]
- for(var/pack_name in SSsupply.supply_pack)
- var/datum/supply_pack/P = SSsupply.supply_pack[pack_name]
- if(P.group == internal_data["supply_category"])
- var/list/pack = list(
- "name" = P.name,
- "cost" = P.cost,
- "contraband" = P.contraband,
- "manifest" = uniquelist(P.manifest),
- "random" = P.num_contained,
- "expand" = 0,
- "ref" = "\ref[P]"
- )
-
- if(P in internal_data["supply_pack_expanded"])
- pack["expand"] = 1
-
- supply_packs[++supply_packs.len] = pack
-
- return supply_packs
-
-
-// Compiles miscellaneous data and permissions used by the supply template
-/obj/item/weapon/commcard/proc/get_misc_supply_data()
- return list(
- "shuttle_auth" = (internal_data["supply_controls"] & SUP_SEND_SHUTTLE),
- "order_auth" = (internal_data["supply_controls"] & SUP_ACCEPT_ORDERS),
- "supply_points" = SSsupply.points,
- "supply_categories" = all_supply_groups
- )
-
-/obj/item/weapon/commcard/proc/get_status_display()
- return list(
- "line1" = internal_data["stat_display_line1"],
- "line2" = internal_data["stat_display_line2"],
- "active_line1" = internal_data["stat_display_active1"],
- "active_line2" = internal_data["stat_display_active2"],
- "active" = internal_data["stat_display_special"]
- )
-
-/obj/item/weapon/commcard/proc/find_blast_doors()
- var/target_doors[0]
- for(var/obj/machinery/door/blast/B in machines)
- if(B.id == internal_data["shuttle_door_code"])
- target_doors += B
-
- return target_doors
\ No newline at end of file
diff --git a/code/game/objects/items/devices/hacktool.dm b/code/game/objects/items/devices/hacktool.dm
index a48a3da024..b221ff875c 100644
--- a/code/game/objects/items/devices/hacktool.dm
+++ b/code/game/objects/items/devices/hacktool.dm
@@ -5,7 +5,7 @@
var/in_hack_mode = 0
var/list/known_targets
var/list/supported_types
- var/datum/topic_state/default/must_hack/hack_state
+ var/datum/tgui_state/default/must_hack/hack_state
/obj/item/device/multitool/hacktool/New()
..()
@@ -30,7 +30,7 @@
else
..()
-/obj/item/device/multitool/hacktool/resolve_attackby(atom/A, mob/user)
+/obj/item/device/multitool/hacktool/afterattack(atom/A, mob/user)
sanity_check()
if(!in_hack_mode)
@@ -39,7 +39,8 @@
if(!attempt_hack(user, A))
return 0
- A.ui_interact(user, state = hack_state)
+ // Note, if you ever want to expand supported_types, you must manually add the custom state argument to their tgui_interact
+ A.tgui_interact(user, custom_state = hack_state)
return 1
/obj/item/device/multitool/hacktool/proc/attempt_hack(var/mob/user, var/atom/target)
@@ -83,18 +84,18 @@
/obj/item/device/multitool/hacktool/proc/on_target_destroy(var/target)
known_targets -= target
-/datum/topic_state/default/must_hack
+/datum/tgui_state/default/must_hack
var/obj/item/device/multitool/hacktool/hacktool
-/datum/topic_state/default/must_hack/New(var/hacktool)
+/datum/tgui_state/default/must_hack/New(var/hacktool)
src.hacktool = hacktool
..()
-/datum/topic_state/default/must_hack/Destroy()
+/datum/tgui_state/default/must_hack/Destroy()
hacktool = null
return ..()
-/datum/topic_state/default/must_hack/can_use_topic(var/src_object, var/mob/user)
+/datum/tgui_state/default/must_hack/can_use_topic(src_object, mob/user)
if(!hacktool || !hacktool.in_hack_mode || !(src_object in hacktool.known_targets))
return STATUS_CLOSE
return ..()
diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm
index 8b7f55e0a9..77e463c0d0 100644
--- a/code/game/objects/items/devices/paicard.dm
+++ b/code/game/objects/items/devices/paicard.dm
@@ -33,6 +33,24 @@ GLOBAL_LIST_BOILERPLATE(all_pai_cards, /obj/item/device/paicard)
QDEL_NULL(radio)
return ..()
+/obj/item/device/paicard/attack_ghost(mob/observer/dead/user)
+ if(istype(user) && user.can_admin_interact())
+ switch(alert(user, "Would you like to become a pAI by force? (Admin)", "pAI Creation", "Yes", "No"))
+ if("Yes")
+ // Copied from paiController/Topic
+ var/mob/living/silicon/pai/pai = new(src)
+ pai.name = user.name
+ pai.real_name = pai.name
+ pai.key = user.key
+
+ setPersonality(pai)
+ looking_for_personality = FALSE
+
+ if(pai.mind)
+ update_antag_icons(pai.mind)
+ return ..()
+
+
/obj/item/device/paicard/attack_self(mob/user)
if (!in_range(src, user))
return
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index f1990c7fe2..d2511038dc 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -151,18 +151,10 @@ var/global/list/default_medbay_channels = list(
return tgui_interact(user)
-/obj/item/device/radio/ui_interact(mob/user, ui_key, datum/nanoui/ui, force_open, datum/nano_ui/master_ui, datum/topic_state/state)
- log_runtime(EXCEPTION("Warning: [user] attempted to call ui_interact on radio [src] [type]. This is deprecated. Please update the caller to tgui_interact."))
-
-/obj/item/device/radio/Topic(href, href_list)
- if(href_list["track"])
- log_runtime(EXCEPTION("Warning: Topic() was improperly called on radio [src] [type], with the track href and \[[href] [json_encode(href_list)]]. Please update the caller to use tgui_act."))
- . = ..()
-
-/obj/item/device/radio/tgui_interact(mob/user, datum/tgui/ui)
+/obj/item/device/radio/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, "Radio", name)
+ ui = new(user, src, "Radio", name, parent_ui)
ui.open()
/obj/item/device/radio/tgui_data(mob/user)
diff --git a/code/game/objects/items/devices/tvcamera.dm b/code/game/objects/items/devices/tvcamera.dm
index e8b6df0b98..acf4b7cc3a 100644
--- a/code/game/objects/items/devices/tvcamera.dm
+++ b/code/game/objects/items/devices/tvcamera.dm
@@ -54,7 +54,7 @@
popup.set_content(jointext(dat,null))
popup.open()
-/obj/item/device/tvcamera/Topic(bred, href_list, state = physical_state)
+/obj/item/device/tvcamera/Topic(bred, href_list, state = GLOB.tgui_physical_state)
if(..())
return 1
if(href_list["channel"])
diff --git a/code/game/objects/items/devices/uplink.dm b/code/game/objects/items/devices/uplink.dm
index 5a19c72742..5b6e55290e 100644
--- a/code/game/objects/items/devices/uplink.dm
+++ b/code/game/objects/items/devices/uplink.dm
@@ -1,13 +1,23 @@
GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
+// I placed this here because of how relevant it is.
+// You place this in your uplinkable item to check if an uplink is active or not.
+// If it is, it will display the uplink menu and return 1, else it'll return false.
+// If it returns true, I recommend closing the item's normal menu with "user << browse(null, "window=name")"
+/obj/item/proc/active_uplink_check(mob/user as mob)
+ // Activates the uplink if it's active
+ if(hidden_uplink)
+ if(hidden_uplink.active)
+ hidden_uplink.trigger(user)
+ return TRUE
+ return FALSE
+
/obj/item/device/uplink
var/welcome = "Welcome, Operative" // Welcoming menu message
var/uses // Numbers of crystals
var/list/ItemsCategory // List of categories with lists of items
var/list/ItemsReference // List of references with an associated item
var/list/nanoui_items // List of items for NanoUI use
- var/nanoui_menu = 0 // The current menu we are in
- var/list/nanoui_data = new // Additional data for NanoUI use
var/faction = "" //Antag faction holder.
var/list/purchase_log = new
@@ -17,9 +27,7 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
var/next_offer_time
var/datum/uplink_item/discount_item //The item to be discounted
var/discount_amount //The amount as a percent the item will be discounted by
-
-/obj/item/device/uplink/nano_host()
- return loc
+ var/compact_mode = FALSE
/obj/item/device/uplink/Initialize(var/mapload, var/datum/mind/owner = null, var/telecrystals = DEFAULT_TELECRYSTAL_AMOUNT)
. = ..()
@@ -53,23 +61,20 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
name = "hidden uplink"
desc = "There is something wrong if you're examining this."
var/active = 0
- var/datum/uplink_category/category = 0 // The current category we are in
var/exploit_id // Id of the current exploit record we are viewing
+ var/selected_cat
// The hidden uplink MUST be inside an obj/item's contents.
/obj/item/device/uplink/hidden/Initialize()
. = ..()
if(!isitem(loc))
return INITIALIZE_HINT_QDEL
- nanoui_data = list()
- update_nano_data()
/obj/item/device/uplink/hidden/next_offer()
discount_item = default_uplink_selection.get_random_item(INFINITY)
discount_amount = pick(90;0.9, 80;0.8, 70;0.7, 60;0.6, 50;0.5, 40;0.4, 30;0.3, 20;0.2, 10;0.1)
- update_nano_data()
- SSnanoui.update_uis(src)
next_offer_time = world.time + offer_time
+ SStgui.update_uis(src)
addtimer(CALLBACK(src, .proc/next_offer), offer_time)
// Toggles the uplink on and off. Normally this will bypass the item's normal functions and go to the uplink menu, if activated.
@@ -91,136 +96,137 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
return 1
return 0
-/*
- NANO UI FOR UPLINK WOOP WOOP
-*/
-/obj/item/device/uplink/hidden/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- var/title = "Remote Uplink"
- var/data[0]
- uses = user.mind.tcrystals
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- faction = H.antag_faction
+// Legacy
+/obj/item/device/uplink/hidden/interact(mob/user)
+ tgui_interact(user)
- data["welcome"] = welcome
- data["crystals"] = uses
- data["menu"] = nanoui_menu
- data += nanoui_data
+/*****************
+ * Uplink TGUI
+ *****************/
+/obj/item/device/uplink/tgui_host()
+ return loc
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui) // No auto-refresh
- ui = new(user, src, ui_key, "uplink.tmpl", title, 630, 700, state = inventory_state)
- data["menu"] = 0
- ui.set_initial_data(data)
+/obj/item/device/uplink/hidden/tgui_state(mob/user)
+ return GLOB.tgui_inventory_state
+
+/obj/item/device/uplink/hidden/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ if(!active)
+ toggle()
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Uplink", "Remote Uplink")
+ // This UI is only ever opened by one person,
+ // and never is updated outside of user input.
+ ui.set_autoupdate(FALSE)
ui.open()
+/obj/item/device/uplink/hidden/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ if(!user.mind)
+ return
-// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button.
-/obj/item/device/uplink/hidden/interact(mob/user)
- ui_interact(user)
+ var/list/data = ..()
-/obj/item/device/uplink/hidden/CanUseTopic()
+ data["telecrystals"] = uses
+ data["lockable"] = TRUE
+ data["compactMode"] = compact_mode
+
+ data["discount_name"] = discount_item ? discount_item.name : ""
+ data["discount_amount"] = (1-discount_amount)*100
+ data["offer_expiry"] = worldtime2stationtime(next_offer_time)
+
+ data["exploit"] = null
+ data["locked_records"] = null
+
+ if(exploit_id)
+ for(var/datum/data/record/L in data_core.locked)
+ if(L.fields["id"] == exploit_id)
+ data["exploit"] = list() // Setting this to equal L.fields passes it's variables that are lists as reference instead of value.
+ // We trade off being able to automatically add shit for more control over what gets passed to json
+ // and if it's sanitized for html.
+ data["exploit"]["nanoui_exploit_record"] = html_encode(L.fields["exploit_record"]) // Change stuff into html
+ data["exploit"]["nanoui_exploit_record"] = replacetext(data["exploit"]["nanoui_exploit_record"], "\n", "
") // change line breaks into
+ data["exploit"]["name"] = html_encode(L.fields["name"])
+ data["exploit"]["sex"] = html_encode(L.fields["sex"])
+ data["exploit"]["age"] = html_encode(L.fields["age"])
+ data["exploit"]["species"] = html_encode(L.fields["species"])
+ data["exploit"]["rank"] = html_encode(L.fields["rank"])
+ data["exploit"]["home_system"] = html_encode(L.fields["home_system"])
+ data["exploit"]["citizenship"] = html_encode(L.fields["citizenship"])
+ data["exploit"]["faction"] = html_encode(L.fields["faction"])
+ data["exploit"]["religion"] = html_encode(L.fields["religion"])
+ data["exploit"]["fingerprint"] = html_encode(L.fields["fingerprint"])
+ if(L.fields["antagvis"] == ANTAG_KNOWN || (faction == L.fields["antagfac"] && (L.fields["antagvis"] == ANTAG_SHARED)))
+ data["exploit"]["antagfaction"] = html_encode(L.fields["antagfac"])
+ else
+ data["exploit"]["antagfaction"] = html_encode("None")
+ break
+ else
+ var/list/permanentData = list()
+ for(var/datum/data/record/L in sortRecord(data_core.locked))
+ permanentData.Add(list(list(
+ "name" = L.fields["name"],
+ "id" = L.fields["id"]
+ )))
+ data["locked_records"] = permanentData
+
+ return data
+
+/obj/item/device/uplink/hidden/tgui_static_data(mob/user)
+ var/list/data = ..()
+
+ data["categories"] = list()
+ for(var/datum/uplink_category/category in uplink.categories)
+ if(category.can_view(src))
+ var/list/cat = list(
+ "name" = category.name,
+ "items" = (category == selected_cat ? list() : null)
+ )
+ for(var/datum/uplink_item/item in category.items)
+ if(!item.can_view(src))
+ continue
+ var/cost = item.cost(uses, src) || "???"
+ cat["items"] += list(list(
+ "name" = item.name,
+ "cost" = cost,
+ "desc" = item.description(),
+ "ref" = REF(item),
+ ))
+ data["categories"] += list(cat)
+
+ return data
+
+/obj/item/device/uplink/hidden/tgui_status(mob/user, datum/tgui_state/state)
if(!active)
return STATUS_CLOSE
return ..()
-// The purchasing code.
-/obj/item/device/uplink/hidden/Topic(href, href_list)
+/obj/item/device/uplink/hidden/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
+ return TRUE
- var/mob/user = usr
- if(href_list["buy_item"])
- var/datum/uplink_item/UI = (locate(href_list["buy_item"]) in uplink.items)
- UI.buy(src, usr)
- else if(href_list["lock"])
- toggle()
- var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main")
- ui.close()
- else if(href_list["return"])
- nanoui_menu = round(nanoui_menu/10)
- else if(href_list["menu"])
- nanoui_menu = text2num(href_list["menu"])
- if(href_list["id"])
- exploit_id = href_list["id"]
- else if(href_list["category"])
- category = locate(href_list["category"]) in uplink.categories
-
- update_nano_data()
- return 1
-
-/obj/item/device/uplink/hidden/proc/update_nano_data()
- if(nanoui_menu == 0)
- var/categories[0]
- for(var/datum/uplink_category/category in uplink.categories)
- if(category.can_view(src))
- categories[++categories.len] = list("name" = category.name, "ref" = "\ref[category]")
- nanoui_data["categories"] = categories
- nanoui_data["discount_name"] = discount_item ? discount_item.name : ""
- nanoui_data["discount_amount"] = (1-discount_amount)*100
- nanoui_data["offer_expiry"] = worldtime2stationtime(next_offer_time)
-
- if(category)
- nanoui_data["current_category"] = category.name
- var/items[0]
- for(var/datum/uplink_item/item in category.items)
- if(item.can_view(src))
- var/cost = item.cost(uses, src)
- if(!cost) cost = "???"
- items[++items.len] = list("name" = item.name, "description" = replacetext(item.description(), "\n", "
"), "can_buy" = item.can_buy(src), "cost" = cost, "ref" = "\ref[item]")
- nanoui_data["items"] = items
-
- else if(nanoui_menu == 2)
- var/permanentData[0]
- for(var/datum/data/record/L in sortRecord(data_core.locked))
- permanentData[++permanentData.len] = list(Name = L.fields["name"],"id" = L.fields["id"])
- nanoui_data["exploit_records"] = permanentData
- else if(nanoui_menu == 21)
- nanoui_data["exploit_exists"] = 0
-
- for(var/datum/data/record/L in data_core.locked)
- if(L.fields["id"] == exploit_id)
- nanoui_data["exploit"] = list() // Setting this to equal L.fields passes it's variables that are lists as reference instead of value.
- // We trade off being able to automatically add shit for more control over what gets passed to json
- // and if it's sanitized for html.
- nanoui_data["exploit"]["nanoui_exploit_record"] = html_encode(L.fields["exploit_record"]) // Change stuff into html
- nanoui_data["exploit"]["nanoui_exploit_record"] = replacetext(nanoui_data["exploit"]["nanoui_exploit_record"], "\n", "
") // change line breaks into
- nanoui_data["exploit"]["name"] = html_encode(L.fields["name"])
- nanoui_data["exploit"]["sex"] = html_encode(L.fields["sex"])
- nanoui_data["exploit"]["age"] = html_encode(L.fields["age"])
- nanoui_data["exploit"]["species"] = html_encode(L.fields["species"])
- nanoui_data["exploit"]["rank"] = html_encode(L.fields["rank"])
- nanoui_data["exploit"]["home_system"] = html_encode(L.fields["home_system"])
- nanoui_data["exploit"]["citizenship"] = html_encode(L.fields["citizenship"])
- nanoui_data["exploit"]["faction"] = html_encode(L.fields["faction"])
- nanoui_data["exploit"]["religion"] = html_encode(L.fields["religion"])
- nanoui_data["exploit"]["fingerprint"] = html_encode(L.fields["fingerprint"])
- if(L.fields["antagvis"] == ANTAG_KNOWN || (faction == L.fields["antagfac"] && (L.fields["antagvis"] == ANTAG_SHARED)))
- nanoui_data["exploit"]["antagfaction"] = html_encode(L.fields["antagfac"])
- else
- nanoui_data["exploit"]["antagfaction"] = html_encode("None")
- nanoui_data["exploit_exists"] = 1
- break
-
-// I placed this here because of how relevant it is.
-// You place this in your uplinkable item to check if an uplink is active or not.
-// If it is, it will display the uplink menu and return 1, else it'll return false.
-// If it returns true, I recommend closing the item's normal menu with "user << browse(null, "window=name")"
-/obj/item/proc/active_uplink_check(mob/user as mob)
- // Activates the uplink if it's active
- if(src.hidden_uplink)
- if(src.hidden_uplink.active)
- src.hidden_uplink.trigger(user)
- return 1
- return 0
+ switch(action)
+ if("buy")
+ var/datum/uplink_item/UI = (locate(params["ref"]) in uplink.items)
+ UI.buy(src, usr)
+ return TRUE
+ if("lock")
+ toggle()
+ SStgui.close_uis(src)
+ if("select")
+ selected_cat = params["category"]
+ return TRUE
+ if("compact_toggle")
+ compact_mode = !compact_mode
+ return TRUE
+ if("view_exploits")
+ exploit_id = params["id"]
+ return TRUE
// PRESET UPLINKS
// A collection of preset uplinks.
//
// Includes normal radio uplink, multitool uplink,
// implant uplink (not the implant tool) and a preset headset uplink.
-
/obj/item/device/radio/uplink/New(atom/loc, datum/mind/target_mind, telecrystals)
..(loc)
hidden_uplink = new(src, target_mind, telecrystals)
diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
index 782df54346..8bf366268a 100644
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ b/code/game/objects/items/stacks/sheets/leather.dm
@@ -4,8 +4,8 @@
singular_name = "human skin piece"
icon_state = "sheet-hide"
no_variants = FALSE
- drop_sound = 'sound/items/drop/cloth.ogg'
- pickup_sound = 'sound/items/pickup/cloth.ogg'
+ drop_sound = 'sound/items/drop/leather.ogg'
+ pickup_sound = 'sound/items/pickup/leather.ogg'
/obj/item/stack/animalhide/human
amount = 50
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index ad187265c2..0c2cf53961 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -66,63 +66,81 @@
else
. += "There is enough charge for [get_amount()]."
-/obj/item/stack/attack_self(mob/user as mob)
- list_recipes(user)
+/obj/item/stack/attack_self(mob/user)
+ tgui_interact(user)
-/obj/item/stack/proc/list_recipes(mob/user as mob, recipes_sublist)
- if (!recipes)
- return
- if (!src || get_amount() <= 0)
- user << browse(null, "window=stack")
- user.set_machine(src) //for correct work of onclose
- var/list/recipe_list = recipes
- if (recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list))
- var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist]
- recipe_list = srl.recipes
- var/t1 = text("Constructions from []Amount Left: []
", src, src.get_amount())
- for(var/i=1;i<=recipe_list.len,i++)
- var/E = recipe_list[i]
- if (isnull(E))
- t1 += "
"
- continue
+/obj/item/stack/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Stack", name)
+ ui.open()
- if (i>1 && !isnull(recipe_list[i-1]))
- t1+="
"
+/obj/item/stack/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
+ data["amount"] = get_amount()
- if (istype(E, /datum/stack_recipe_list))
- var/datum/stack_recipe_list/srl = E
- t1 += "[srl.title]"
+ return data
- if (istype(E, /datum/stack_recipe))
- var/datum/stack_recipe/R = E
- var/max_multiplier = round(src.get_amount() / R.req_amount)
- var/title as text
- var/can_build = 1
- can_build = can_build && (max_multiplier>0)
- if (R.res_amount>1)
- title+= "[R.res_amount]x [R.title]\s"
- else
- title+= "[R.title]"
- title+= " ([R.req_amount] [src.singular_name]\s)"
- if (can_build)
- t1 += text("[title] ")
- else
- t1 += text("[]", title)
- continue
- if (R.max_res_amount>1 && max_multiplier>1)
- max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount))
- t1 += " |"
- var/list/multipliers = list(5,10,25)
- for (var/n in multipliers)
- if (max_multiplier>=n)
- t1 += " [n*R.res_amount]x"
- if (!(max_multiplier in multipliers))
- t1 += " [max_multiplier*R.res_amount]x"
+/obj/item/stack/tgui_static_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- t1 += ""
- user << browse(t1, "window=stack")
- onclose(user, "stack")
- return
+ data["recipes"] = recursively_build_recipes(recipes)
+
+ return data
+
+/obj/item/stack/proc/recursively_build_recipes(list/recipe_to_iterate)
+ var/list/L = list()
+ for(var/recipe in recipe_to_iterate)
+ if(istype(recipe, /datum/stack_recipe_list))
+ var/datum/stack_recipe_list/R = recipe
+ L["[R.title]"] = recursively_build_recipes(R.recipes)
+ if(istype(recipe, /datum/stack_recipe))
+ var/datum/stack_recipe/R = recipe
+ L["[R.title]"] = build_recipe(R)
+
+ return L
+
+/obj/item/stack/proc/build_recipe(datum/stack_recipe/R)
+ return list(
+ "res_amount" = R.res_amount,
+ "max_res_amount" = R.max_res_amount,
+ "req_amount" = R.req_amount,
+ "ref" = "\ref[R]",
+ )
+
+/obj/item/stack/tgui_state(mob/user)
+ return GLOB.tgui_hands_state
+
+/obj/item/stack/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
+
+ switch(action)
+ if("make")
+ if(get_amount() < 1)
+ qdel(src)
+ return
+
+ var/datum/stack_recipe/R = locate(params["ref"])
+ if(!is_valid_recipe(R, recipes)) //href exploit protection
+ return FALSE
+ var/multiplier = text2num(params["multiplier"])
+ if(!multiplier || (multiplier <= 0)) //href exploit protection
+ return
+ produce_recipe(R, multiplier, usr)
+ return TRUE
+
+/obj/item/stack/proc/is_valid_recipe(datum/stack_recipe/R, list/recipe_list)
+ for(var/S in recipe_list)
+ if(S == R)
+ return TRUE
+ if(istype(S, /datum/stack_recipe_list))
+ var/datum/stack_recipe_list/L = S
+ if(is_valid_recipe(R, L.recipes))
+ return TRUE
+
+ return FALSE
/obj/item/stack/proc/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user)
var/required = quantity*recipe.req_amount
@@ -177,35 +195,6 @@
else
O.color = color
-/obj/item/stack/Topic(href, href_list)
- ..()
- if ((usr.restrained() || usr.stat || usr.get_active_hand() != src))
- return
-
- if (href_list["sublist"] && !href_list["make"])
- list_recipes(usr, text2num(href_list["sublist"]))
-
- if (href_list["make"])
- if (src.get_amount() < 1) qdel(src) //Never should happen
-
- var/list/recipes_list = recipes
- if (href_list["sublist"])
- var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])]
- recipes_list = srl.recipes
-
- var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])]
- var/multiplier = text2num(href_list["multiplier"])
- if (!multiplier || (multiplier <= 0)) //href exploit protection
- return
-
- src.produce_recipe(R, multiplier, usr)
-
- if (src && usr.machine==src) //do not reopen closed window
- spawn( 0 )
- src.interact(usr)
- return
- return
-
//Return 1 if an immediate subsequent call to use() would succeed.
//Ensures that code dealing with stacks uses the same logic
/obj/item/stack/proc/can_use(var/used)
diff --git a/code/game/objects/items/stacks/tickets.dm b/code/game/objects/items/stacks/tickets.dm
new file mode 100644
index 0000000000..1d9cbf047e
--- /dev/null
+++ b/code/game/objects/items/stacks/tickets.dm
@@ -0,0 +1,32 @@
+/obj/item/stack/arcadeticket
+ name = "arcade tickets"
+ desc = "Wow! With enough of these, you could buy a bike! ...Pssh, yeah right."
+ singular_name = "arcade ticket"
+ icon_state = "arcade-ticket"
+ item_state = "tickets"
+ w_class = ITEMSIZE_TINY
+ max_amount = 30
+
+/obj/item/stack/arcadeticket/New(loc, amount = null)
+ . = ..()
+ update_icon()
+
+/obj/item/stack/arcadeticket/update_icon()
+ var/amount = get_amount()
+ switch(amount)
+ if(12 to INFINITY)
+ icon_state = "arcade-ticket_4"
+ if(6 to 12)
+ icon_state = "arcade-ticket_3"
+ if(2 to 6)
+ icon_state = "arcade-ticket_2"
+ else
+ icon_state = "arcade-ticket"
+
+/obj/item/stack/arcadeticket/proc/pay_tickets()
+ amount -= 2
+ if(amount == 0)
+ qdel(src)
+
+/obj/item/stack/arcadeticket/thirty
+ amount = 30
\ No newline at end of file
diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm
index 73d3dd45e7..36c8c6e7ec 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -126,11 +126,13 @@
name = "empty cup"
icon_state = "coffee_vended"
drop_sound = 'sound/items/drop/papercup.ogg'
+ pickup_sound = 'sound/items/pickup/papercup.ogg'
/obj/item/trash/ramen
name = "cup ramen"
icon_state = "ramen"
drop_sound = 'sound/items/drop/papercup.ogg'
+ pickup_sound = 'sound/items/pickup/papercup.ogg'
/obj/item/trash/tray
name = "tray"
@@ -141,6 +143,8 @@
name = "candle"
icon = 'icons/obj/candle.dmi'
icon_state = "candle4"
+ drop_sound = 'sound/items/drop/gloves.ogg'
+ pickup_sound = 'sound/items/pickup/gloves.ogg'
/obj/item/trash/liquidfood
name = "\improper \"LiquidFood\" ration packet"
@@ -162,18 +166,26 @@
/obj/item/trash/brownies
name = "brownie tray"
icon_state = "brownies"
+ drop_sound = 'sound/items/drop/soda.ogg'
+ pickup_sound = 'sound/items/pickup/soda.ogg'
/obj/item/trash/snacktray
name = "snacktray"
icon_state = "snacktray"
+ drop_sound = 'sound/items/drop/soda.ogg'
+ pickup_sound = 'sound/items/pickup/soda.ogg'
/obj/item/trash/dipbowl
name = "dip bowl"
icon_state = "dipbowl"
+ drop_sound = 'sound/items/drop/food.ogg'
+ pickup_sound = 'sound/items/pickup/food.ogg'
/obj/item/trash/chipbasket
name = "empty basket"
icon_state = "chipbasket_empty"
+ drop_sound = 'sound/items/drop/food.ogg'
+ pickup_sound = 'sound/items/pickup/food.ogg'
/obj/item/trash/spitgum
name = "old gum"
@@ -181,12 +193,15 @@
icon = 'icons/obj/clothing/masks.dmi'
icon_state = "spit-gum"
drop_sound = 'sound/items/drop/flesh.ogg'
+ pickup_sound = 'sound/items/pickup/flesh.ogg'
/obj/item/trash/lollibutt
name = "lollipop stick"
desc = "A lollipop stick devoid of pop."
icon = 'icons/obj/clothing/masks.dmi'
icon_state = "pop-stick"
+ drop_sound = 'sound/items/drop/component.ogg'
+ pickup_sound = 'sound/items/pickup/component.ogg'
/obj/item/trash/spitwad
name = "spit wad"
@@ -194,6 +209,7 @@
icon = 'icons/obj/clothing/masks.dmi'
icon_state = "spit-chew"
drop_sound = 'sound/items/drop/flesh.ogg'
+ pickup_sound = 'sound/items/pickup/flesh.ogg'
slot_flags = SLOT_EARS | SLOT_MASK
/obj/item/trash/attack(mob/M as mob, mob/living/user as mob)
diff --git a/code/game/objects/items/weapons/augment_items.dm b/code/game/objects/items/weapons/augment_items.dm
new file mode 100644
index 0000000000..c0df9c9688
--- /dev/null
+++ b/code/game/objects/items/weapons/augment_items.dm
@@ -0,0 +1,37 @@
+// **For augment items that aren't subtypes of other things.**
+
+/obj/item/weapon/melee/augment
+ name = "integrated item"
+ desc = "A surprisingly non-descript item, integrated into its user. You probably shouldn't be seeing this."
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "augment_box"
+
+
+/obj/item/weapon/melee/augment/blade
+ name = "handblade"
+ desc = "A sleek-looking telescopic blade that fits inside the hand. Favored by infiltration specialists and assassins."
+ icon_state = "augment_handblade"
+ item_icons = list(
+ slot_l_hand_str = 'icons/mob/items/lefthand_melee.dmi',
+ slot_r_hand_str = 'icons/mob/items/righthand_melee.dmi',
+ )
+ w_class = ITEMSIZE_SMALL
+ force = 15
+ armor_penetration = 25
+ sharp = 1
+ attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ defend_chance = 10
+ projectile_parry_chance = 5
+ hitsound = 'sound/weapons/bladeslice.ogg'
+
+/obj/item/weapon/melee/augment/blade/arm
+ name = "armblade"
+ desc = "A sleek-looking cybernetic blade that cleaves through people like butter. Favored by psychopaths and assassins."
+ icon_state = "augment_armblade"
+ w_class = ITEMSIZE_HUGE
+ force = 30
+ armor_penetration = 15
+ edge = 1
+ pry = 1
+ defend_chance = 40
+ projectile_parry_chance = 20
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/autopsy.dm b/code/game/objects/items/weapons/autopsy.dm
index 94a2636798..352a3955a3 100644
--- a/code/game/objects/items/weapons/autopsy.dm
+++ b/code/game/objects/items/weapons/autopsy.dm
@@ -14,6 +14,8 @@
var/list/datum/autopsy_data_scanner/chemtraces = list()
var/target_name = null
var/timeofdeath = null
+ drop_sound = 'sound/items/drop/device.ogg'
+ pickup_sound = 'sound/items/pickup/device.ogg'
/datum/autopsy_data_scanner
var/weapon = null // this is the DEFINITE weapon type that was used
diff --git a/code/game/objects/items/weapons/circuitboards/circuitboard.dm b/code/game/objects/items/weapons/circuitboards/circuitboard.dm
index f049197d88..8b913eaf45 100644
--- a/code/game/objects/items/weapons/circuitboards/circuitboard.dm
+++ b/code/game/objects/items/weapons/circuitboards/circuitboard.dm
@@ -20,6 +20,8 @@
var/board_type = new /datum/frame/frame_types/computer
var/list/req_components = null
var/contain_parts = 1
+ drop_sound = 'sound/items/drop/device.ogg'
+ pickup_sound = 'sound/items/pickup/device.ogg'
//Called when the circuitboard is used to contruct a new machine.
/obj/item/weapon/circuitboard/proc/construct(var/obj/machinery/M)
diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm
index 6cd2a65774..b2e783ba69 100644
--- a/code/game/objects/items/weapons/flamethrower.dm
+++ b/code/game/objects/items/weapons/flamethrower.dm
@@ -110,10 +110,6 @@
update_icon()
return
- if(istype(W, /obj/item/device/analyzer))
- var/obj/item/device/analyzer/A = W
- A.analyze_gases(src, user)
- return
..()
return
diff --git a/code/game/objects/items/weapons/id cards/syndicate_ids.dm b/code/game/objects/items/weapons/id cards/syndicate_ids.dm
index 68cb0298a4..afb85ecb7a 100644
--- a/code/game/objects/items/weapons/id cards/syndicate_ids.dm
+++ b/code/game/objects/items/weapons/id cards/syndicate_ids.dm
@@ -6,8 +6,11 @@
var/electronic_warfare = 1
var/mob/registered_user = null
+ var/datum/tgui_module/agentcard/agentcard_module
+
/obj/item/weapon/card/id/syndicate/Initialize()
. = ..()
+ agentcard_module = new(src)
access = syndicate_access.Copy()
/obj/item/weapon/card/id/syndicate/station_access/Initialize()
@@ -15,6 +18,7 @@
access |= get_all_station_access()
/obj/item/weapon/card/id/syndicate/Destroy()
+ QDEL_NULL(agentcard_module)
unset_registered_user(registered_user)
return ..()
@@ -36,33 +40,12 @@
if(registered_user == user)
switch(alert("Would you like edit the ID, or show it?","Show or Edit?", "Edit","Show"))
if("Edit")
- ui_interact(user)
+ agentcard_module.tgui_interact(user)
if("Show")
..()
else
..()
-/obj/item/weapon/card/id/syndicate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- var/data[0]
- var/entries[0]
- entries[++entries.len] = list("name" = "Age", "value" = age)
- entries[++entries.len] = list("name" = "Appearance", "value" = "Set")
- entries[++entries.len] = list("name" = "Assignment", "value" = assignment)
- entries[++entries.len] = list("name" = "Blood Type", "value" = blood_type)
- entries[++entries.len] = list("name" = "DNA Hash", "value" = dna_hash)
- entries[++entries.len] = list("name" = "Fingerprint Hash", "value" = fingerprint_hash)
- entries[++entries.len] = list("name" = "Name", "value" = registered_name)
- entries[++entries.len] = list("name" = "Photo", "value" = "Update")
- entries[++entries.len] = list("name" = "Sex", "value" = sex)
- entries[++entries.len] = list("name" = "Factory Reset", "value" = "Use With Care")
- data["electronic_warfare"] = electronic_warfare
- data["entries"] = entries
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "agent_id_card.tmpl", "Fake ID", 600, 400)
- ui.set_initial_data(data)
- ui.open()
/obj/item/weapon/card/id/syndicate/proc/register_user(var/mob/user)
if(!istype(user) || user == registered_user)
@@ -79,114 +62,6 @@
registered_user.unregister(OBSERVER_EVENT_DESTROY, src)
registered_user = null
-/obj/item/weapon/card/id/syndicate/CanUseTopic(mob/user)
- if(user != registered_user)
- return STATUS_CLOSE
- return ..()
-
-/obj/item/weapon/card/id/syndicate/Topic(href, href_list, var/datum/topic_state/state)
- if(..())
- return 1
-
- var/user = usr
- if(href_list["electronic_warfare"])
- electronic_warfare = text2num(href_list["electronic_warfare"])
- to_chat(user, "Electronic warfare [electronic_warfare ? "enabled" : "disabled"].")
- else if(href_list["set"])
- switch(href_list["set"])
- if("Age")
- var/new_age = input(user,"What age would you like to put on this card?","Agent Card Age", age) as null|num
- if(!isnull(new_age) && CanUseTopic(user, state))
- if(new_age < 0)
- age = initial(age)
- else
- age = new_age
- to_chat(user, "Age has been set to '[age]'.")
- . = 1
- if("Appearance")
- var/datum/card_state/choice = input(user, "Select the appearance for this card.", "Agent Card Appearance") as null|anything in id_card_states()
- if(choice && CanUseTopic(user, state))
- src.icon_state = choice.icon_state
- src.item_state = choice.item_state
- to_chat(usr, "Appearance changed to [choice].")
- . = 1
- if("Assignment")
- var/new_job = sanitize(input(user,"What assignment would you like to put on this card?\nChanging assignment will not grant or remove any access levels.","Agent Card Assignment", assignment) as null|text)
- if(!isnull(new_job) && CanUseTopic(user, state))
- src.assignment = new_job
- to_chat(user, "Occupation changed to '[new_job]'.")
- update_name()
- . = 1
- if("Blood Type")
- var/default = blood_type
- if(default == initial(blood_type) && ishuman(user))
- var/mob/living/carbon/human/H = user
- if(H.dna)
- default = H.dna.b_type
- var/new_blood_type = sanitize(input(user,"What blood type would you like to be written on this card?","Agent Card Blood Type",default) as null|text)
- if(!isnull(new_blood_type) && CanUseTopic(user, state))
- src.blood_type = new_blood_type
- to_chat(user, "Blood type changed to '[new_blood_type]'.")
- . = 1
- if("DNA Hash")
- var/default = dna_hash
- if(default == initial(dna_hash) && ishuman(user))
- var/mob/living/carbon/human/H = user
- if(H.dna)
- default = H.dna.unique_enzymes
- var/new_dna_hash = sanitize(input(user,"What DNA hash would you like to be written on this card?","Agent Card DNA Hash",default) as null|text)
- if(!isnull(new_dna_hash) && CanUseTopic(user, state))
- src.dna_hash = new_dna_hash
- to_chat(user, "DNA hash changed to '[new_dna_hash]'.")
- . = 1
- if("Fingerprint Hash")
- var/default = fingerprint_hash
- if(default == initial(fingerprint_hash) && ishuman(user))
- var/mob/living/carbon/human/H = user
- if(H.dna)
- default = md5(H.dna.uni_identity)
- var/new_fingerprint_hash = sanitize(input(user,"What fingerprint hash would you like to be written on this card?","Agent Card Fingerprint Hash",default) as null|text)
- if(!isnull(new_fingerprint_hash) && CanUseTopic(user, state))
- src.fingerprint_hash = new_fingerprint_hash
- to_chat(user, "Fingerprint hash changed to '[new_fingerprint_hash]'.")
- . = 1
- if("Name")
- var/new_name = sanitizeName(input(user,"What name would you like to put on this card?","Agent Card Name", registered_name) as null|text)
- if(!isnull(new_name) && CanUseTopic(user, state))
- src.registered_name = new_name
- update_name()
- to_chat(user, "Name changed to '[new_name]'.")
- . = 1
- if("Photo")
- set_id_photo(user)
- to_chat(user, "Photo changed.")
- . = 1
- if("Sex")
- var/new_sex = sanitize(input(user,"What sex would you like to put on this card?","Agent Card Sex", sex) as null|text)
- if(!isnull(new_sex) && CanUseTopic(user, state))
- src.sex = new_sex
- to_chat(user, "Sex changed to '[new_sex]'.")
- . = 1
- if("Factory Reset")
- if(alert("This will factory reset the card, including access and owner. Continue?", "Factory Reset", "No", "Yes") == "Yes" && CanUseTopic(user, state))
- age = initial(age)
- access = syndicate_access.Copy()
- assignment = initial(assignment)
- blood_type = initial(blood_type)
- dna_hash = initial(dna_hash)
- electronic_warfare = initial(electronic_warfare)
- fingerprint_hash = initial(fingerprint_hash)
- icon_state = initial(icon_state)
- name = initial(name)
- registered_name = initial(registered_name)
- unset_registered_user()
- sex = initial(sex)
- to_chat(user, "All information has been deleted from \the [src].")
- . = 1
-
- // Always update the UI, or buttons will spin indefinitely
- SSnanoui.update_uis(src)
-
/var/global/list/id_card_states
/proc/id_card_states()
if(!id_card_states)
diff --git a/code/game/objects/items/weapons/implants/implantaugment.dm b/code/game/objects/items/weapons/implants/implantaugment.dm
index be6c8721ee..020976447d 100644
--- a/code/game/objects/items/weapons/implants/implantaugment.dm
+++ b/code/game/objects/items/weapons/implants/implantaugment.dm
@@ -169,6 +169,10 @@
organ_to_implant = /obj/item/organ/internal/augment/armmounted/hand/sword
organ_display_name = "weapon augment"
+/obj/item/weapon/implant/organ/limbaugment/wrist/blade
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/hand/blade
+ organ_display_name = "weapon augment"
+
// Fore-arm
/obj/item/weapon/implant/organ/limbaugment/laser
organ_to_implant = /obj/item/organ/internal/augment/armmounted
@@ -185,6 +189,10 @@
/obj/item/weapon/implant/organ/limbaugment/upperarm/surge
organ_to_implant = /obj/item/organ/internal/augment/armmounted/shoulder/surge
+/obj/item/weapon/implant/organ/limbaugment/upperarm/blade
+ organ_to_implant = /obj/item/organ/internal/augment/armmounted/shoulder/blade
+ organ_display_name = "weapon augment"
+
/*
* Others
*/
diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm
index 3bcb295e2a..c404089028 100644
--- a/code/game/objects/items/weapons/implants/implantcase.dm
+++ b/code/game/objects/items/weapons/implants/implantcase.dm
@@ -279,3 +279,23 @@
src.imp = new /obj/item/weapon/implant/organ/pelvic( src )
..()
return
+
+/obj/item/weapon/implantcase/armblade
+ name = "glass case - 'Armblade'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/armblade/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/upperarm/blade( src )
+ ..()
+ return
+
+/obj/item/weapon/implantcase/handblade
+ name = "glass case - 'Handblade'"
+ desc = "A case containing a nanite fabricator implant."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/handblade/New()
+ src.imp = new /obj/item/weapon/implant/organ/limbaugment/wrist/blade( src )
+ ..()
+ return
diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm
index bfcbd695e5..4759b06667 100644
--- a/code/game/objects/items/weapons/storage/storage.dm
+++ b/code/game/objects/items/weapons/storage/storage.dm
@@ -362,6 +362,8 @@
usr.client.screen -= W
W.dropped(usr)
add_fingerprint(usr)
+ if (use_sound)
+ playsound(src, src.use_sound, 50, 0, -5) //Something broke "add item to container" sounds, this is a hacky fix.
if(!prevent_warning)
for(var/mob/M in viewers(usr, null))
diff --git a/code/game/objects/items/weapons/storage/uplink_kits.dm b/code/game/objects/items/weapons/storage/uplink_kits.dm
index abae12ed8a..324fb93dd8 100644
--- a/code/game/objects/items/weapons/storage/uplink_kits.dm
+++ b/code/game/objects/items/weapons/storage/uplink_kits.dm
@@ -128,6 +128,12 @@
/obj/item/weapon/storage/box/syndie_kit/imp_aug/sprinter
case_type = /obj/item/weapon/implantcase/sprinter
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/armblade
+ case_type = /obj/item/weapon/implantcase/armblade
+
+/obj/item/weapon/storage/box/syndie_kit/imp_aug/handblade
+ case_type = /obj/item/weapon/implantcase/handblade
/obj/item/weapon/storage/box/syndie_kit/space
name = "boxed space suit and helmet"
diff --git a/code/game/objects/items/weapons/storage/wallets.dm b/code/game/objects/items/weapons/storage/wallets.dm
index 83bb322e0e..274ea23ab8 100644
--- a/code/game/objects/items/weapons/storage/wallets.dm
+++ b/code/game/objects/items/weapons/storage/wallets.dm
@@ -42,9 +42,9 @@
slot_flags = SLOT_ID
var/obj/item/weapon/card/id/front_id = null
-
- drop_sound = 'sound/items/drop/cloth.ogg'
- pickup_sound = 'sound/items/pickup/cloth.ogg'
+
+ drop_sound = 'sound/items/drop/leather.ogg'
+ pickup_sound = 'sound/items/pickup/leather.ogg'
/obj/item/weapon/storage/wallet/remove_from_storage(obj/item/W as obj, atom/new_location)
. = ..(W, new_location)
diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm
index 358e650b2d..5f587fccf2 100644
--- a/code/game/objects/items/weapons/tanks/tanks.dm
+++ b/code/game/objects/items/weapons/tanks/tanks.dm
@@ -120,9 +120,6 @@ var/list/global/tank_gauge_cache = list()
if (istype(src.loc, /obj/item/assembly))
icon = src.loc
- if ((istype(W, /obj/item/device/analyzer)) && get_dist(user, src) <= 1)
- var/obj/item/device/analyzer/A = W
- A.analyze_gases(src, user)
else if (istype(W,/obj/item/latexballon))
var/obj/item/latexballon/LB = W
LB.blow(src)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 9bca1c2933..688236eda8 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -42,7 +42,7 @@
old_turf.unregister_dangerous_object(src)
new_turf.register_dangerous_object(src)
-/obj/Topic(href, href_list, var/datum/topic_state/state = default_state)
+/obj/Topic(href, href_list, var/datum/tgui_state/state = GLOB.tgui_default_state)
if(usr && ..())
return 1
@@ -55,7 +55,7 @@
CouldNotUseTopic(usr)
return 1
-/obj/CanUseTopic(var/mob/user, var/datum/topic_state/state = default_state)
+/obj/CanUseTopic(var/mob/user, var/datum/tgui_state/state = GLOB.tgui_default_state)
if(user.CanUseObjTopic(src))
return ..()
to_chat(user, "[bicon(src)]Access Denied!")
@@ -69,7 +69,7 @@
return 1
/obj/proc/CouldUseTopic(var/mob/user)
- var/atom/host = nano_host()
+ var/atom/host = tgui_host()
host.add_hiddenprint(user)
/obj/proc/CouldNotUseTopic(var/mob/user)
@@ -135,7 +135,6 @@
in_use = 0
/obj/attack_ghost(mob/user)
- ui_interact(user)
tgui_interact(user)
..()
diff --git a/code/game/objects/random/guns_and_ammo.dm b/code/game/objects/random/guns_and_ammo.dm
index 43a166a647..736565b14d 100644
--- a/code/game/objects/random/guns_and_ammo.dm
+++ b/code/game/objects/random/guns_and_ammo.dm
@@ -153,6 +153,65 @@
prob(2);/obj/item/ammo_magazine/m9mmt,
prob(6);/obj/item/ammo_magazine/m9mmt/rubber)
+/obj/random/grenade
+ name = "Random Grenade"
+ desc = "This is random thrown grenades (no C4/etc.)."
+ icon = 'icons/obj/grenade.dmi'
+ icon_state = "clusterbang_segment"
+
+/obj/random/grenade/item_to_spawn()
+ return pick( prob(15);/obj/item/weapon/grenade/concussion,
+ prob(5);/obj/item/weapon/grenade/empgrenade,
+ prob(15);/obj/item/weapon/grenade/empgrenade/low_yield,
+ prob(5);/obj/item/weapon/grenade/chem_grenade/metalfoam,
+ prob(2);/obj/item/weapon/grenade/chem_grenade/incendiary,
+ prob(10);/obj/item/weapon/grenade/chem_grenade/antiweed,
+ prob(10);/obj/item/weapon/grenade/chem_grenade/cleaner,
+ prob(10);/obj/item/weapon/grenade/chem_grenade/teargas,
+ prob(5);/obj/item/weapon/grenade/explosive,
+ prob(10);/obj/item/weapon/grenade/explosive/mini,
+ prob(2);/obj/item/weapon/grenade/explosive/frag,
+ prob(15);/obj/item/weapon/grenade/flashbang,
+ prob(1);/obj/item/weapon/grenade/flashbang/clusterbang, //I can't not do this.
+ prob(15);/obj/item/weapon/grenade/shooter/rubber,
+ prob(10);/obj/item/weapon/grenade/shooter/energy/flash,
+ prob(15);/obj/item/weapon/grenade/smokebomb
+ )
+
+/obj/random/grenade/less_lethal
+ name = "Random Security Grenade"
+ desc = "This is a random thrown grenade that shouldn't kill anyone."
+ icon = 'icons/obj/grenade.dmi'
+ icon_state = "clusterbang_segment"
+
+/obj/random/grenade/less_lethal/item_to_spawn()
+ return pick( prob(20);/obj/item/weapon/grenade/concussion,
+ prob(15);/obj/item/weapon/grenade/empgrenade/low_yield,
+ prob(15);/obj/item/weapon/grenade/chem_grenade/metalfoam,
+ prob(20);/obj/item/weapon/grenade/chem_grenade/teargas,
+ prob(20);/obj/item/weapon/grenade/flashbang,
+ prob(1);/obj/item/weapon/grenade/flashbang/clusterbang, //I *still* can't not do this.
+ prob(15);/obj/item/weapon/grenade/shooter/rubber,
+ prob(10);/obj/item/weapon/grenade/shooter/energy/flash
+ )
+
+/obj/random/grenade/box
+ name = "Random Grenade Box"
+ desc = "This is a random box of grenades. Not to be mistaken for a box of random grenades. Or a grenade of random boxes - but that would just be silly."
+ icon = 'icons/obj/grenade.dmi'
+ icon_state = "clusterbang_segment"
+
+/obj/random/grenade/box/item_to_spawn()
+ return pick( prob(20);/obj/item/weapon/storage/box/flashbangs,
+ prob(10);/obj/item/weapon/storage/box/emps,
+ prob(20);/obj/item/weapon/storage/box/empslite,
+ prob(15);/obj/item/weapon/storage/box/smokes,
+ prob(5);/obj/item/weapon/storage/box/anti_photons,
+ prob(5);/obj/item/weapon/storage/box/frags,
+ prob(10);/obj/item/weapon/storage/box/metalfoam,
+ prob(15);/obj/item/weapon/storage/box/teargas
+ )
+
/obj/random/projectile/random
name = "Random Projectile Weapon"
desc = "This is a random weapon."
diff --git a/code/game/objects/random/mapping.dm b/code/game/objects/random/mapping.dm
index 7319ca42e5..16be9dff94 100644
--- a/code/game/objects/random/mapping.dm
+++ b/code/game/objects/random/mapping.dm
@@ -585,7 +585,7 @@
/obj/item/clothing/mask/breath,
/obj/structure/closet/crate/aether //AETHER AIRSUPPLY
),
- prob(10);list(
+ prob(5);list(
/obj/random/multiple/voidsuit/vintage,
/obj/random/multiple/voidsuit/vintage,
/obj/random/tank,
@@ -625,13 +625,20 @@
/obj/random/powercell,
/obj/structure/closet/crate/einstein //EINSTEIN BATTERYPACK
),
- prob(10);list(
+ prob(5);list(
/obj/item/weapon/circuitboard/smes,
/obj/random/smes_coil,
/obj/random/smes_coil,
/obj/structure/closet/crate/focalpoint //FOCAL SMES
),
- prob(15);list(
+ prob(10);list(
+ /obj/item/weapon/module/power_control,
+ /obj/item/stack/cable_coil,
+ /obj/item/frame/apc,
+ /obj/item/weapon/cell/apc,
+ /obj/structure/closet/crate/focalpoint //FOCAL APC
+ ),
+ prob(5);list(
/obj/random/drinkbottle,
/obj/random/drinkbottle,
/obj/random/drinkbottle,
@@ -640,7 +647,7 @@
/obj/random/cigarettes,
/obj/structure/closet/crate/gilthari //GILTHARI LUXURY
),
- prob(15);list(
+ prob(10);list(
/obj/random/tech_supply/nofail,
/obj/random/tech_supply/component/nofail,
/obj/random/tech_supply/component/nofail,
@@ -655,7 +662,7 @@
/obj/random/multiple/ore_pile,
/obj/structure/closet/crate/grayson //GRAYSON ORES
),
- prob(15);list(
+ prob(10);list(
/obj/random/material/refined,
/obj/random/material/refined,
/obj/random/material/refined,
@@ -671,24 +678,48 @@
/obj/item/weapon/cell/device/weapon,
/obj/structure/closet/crate/secure/heph //HEPHAESTUS ENERGY
),
- prob(2);list(
- /obj/random/projectile/random,
- /obj/random/projectile/random,
- /obj/structure/closet/crate/secure/heph //HEPHAESTUS PROJECTILE
+ prob(1);list(
+ /obj/random/grenade/box,
+ /obj/random/grenade/box,
+ /obj/structure/closet/crate/secure/heph //HEPHAESTUS GRENADES
),
prob(2);list(
+ /obj/random/projectile/random,
+ /obj/random/projectile/random,
+ /obj/structure/closet/crate/secure/lawson //LAWSON PROJECTILE
+ ),
+ prob(3);list(
+ /obj/random/grenade/less_lethal,
+ /obj/random/grenade/less_lethal,
+ /obj/random/grenade/less_lethal,
+ /obj/random/grenade/less_lethal,
+ /obj/structure/closet/crate/secure/nanotrasen //NTSEC CROWD GRENADES
+ ),
+ prob(5);list(
/obj/random/multiple/voidsuit/security,
/obj/random/tank,
/obj/item/clothing/mask/breath,
/obj/structure/closet/crate/secure/nanotrasen //NTSEC SUIT
),
- prob(2);list(
+ prob(5);list(
/obj/random/multiple/voidsuit/medical,
/obj/random/tank,
/obj/item/clothing/mask/breath,
/obj/structure/closet/crate/secure/veymed //VM SUIT
),
prob(5);list(
+ /obj/random/multiple/voidsuit/mining,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/grayson //GRAYSON SUIT
+ ),
+ prob(5);list(
+ /obj/random/multiple/voidsuit/engineering,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/xion //XION SUIT
+ ),
+ prob(10);list(
/obj/random/firstaid,
/obj/random/medical,
/obj/random/medical,
@@ -697,11 +728,13 @@
/obj/random/medical/lite,
/obj/structure/closet/crate/veymed //VM GRABBAG
),
- prob(5);list(
+ prob(10);list(
/obj/random/firstaid,
/obj/random/firstaid,
/obj/random/firstaid,
/obj/random/firstaid,
+ /obj/random/unidentified_medicine/fresh_medicine,
+ /obj/random/unidentified_medicine/fresh_medicine,
/obj/structure/closet/crate/veymed //VM FAKS
),
prob(10);list(
@@ -726,19 +759,337 @@
/obj/random/medical/pillbottle,
/obj/random/medical/pillbottle,
/obj/random/medical/pillbottle,
- /obj/random/medical/pillbottle,
+ /obj/random/unidentified_medicine/fresh_medicine,
+ /obj/random/unidentified_medicine/fresh_medicine,
/obj/structure/closet/crate/zenghu //ZENGHU PILLS
),
+ prob(10);list(
+ /obj/item/device/toner,
+ /obj/item/device/toner,
+ /obj/item/device/toner,
+ /obj/item/weapon/clipboard,
+ /obj/item/weapon/clipboard,
+ /obj/item/weapon/pen/red,
+ /obj/item/weapon/pen/blue,
+ /obj/item/weapon/pen/blue,
+ /obj/item/device/camera_film,
+ /obj/item/weapon/folder/blue,
+ /obj/item/weapon/folder/red,
+ /obj/item/weapon/folder/yellow,
+ /obj/item/weapon/hand_labeler,
+ /obj/item/weapon/tape_roll,
+ /obj/item/weapon/paper_bin,
+ /obj/item/sticky_pad/random,
+ /obj/structure/closet/crate/ummarcar //UMMARCAR OFFICE TRASH
+ ),
+ prob(5);list(
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/structure/closet/crate/unathi //UNAJERKY
+ ),
+ prob(10);list(
+ /obj/item/weapon/reagent_containers/glass/bucket,
+ /obj/item/weapon/mop,
+ /obj/item/clothing/under/rank/janitor,
+ /obj/item/weapon/cartridge/janitor,
+ /obj/item/clothing/gloves/black,
+ /obj/item/clothing/head/soft/purple,
+ /obj/item/weapon/storage/belt/janitor,
+ /obj/item/clothing/shoes/galoshes,
+ /obj/item/weapon/storage/bag/trash,
+ /obj/item/device/lightreplacer,
+ /obj/item/weapon/reagent_containers/spray/cleaner,
+ /obj/item/weapon/reagent_containers/glass/rag,
+ /obj/item/weapon/grenade/chem_grenade/cleaner,
+ /obj/item/weapon/grenade/chem_grenade/cleaner,
+ /obj/item/weapon/grenade/chem_grenade/cleaner,
+ /obj/structure/closet/crate/galaksi //GALAKSI JANITOR SUPPLIES
+ ),
+ prob(5);list(
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/structure/closet/crate/allico //GUMMIES
+ ),
prob(2);list(
+ /obj/item/weapon/tank/phoron/pressurized,
+ /obj/item/weapon/tank/phoron/pressurized,
+ /obj/structure/closet/crate/secure/phoron //HQ FUEL TANKS
+ ),
+ prob(1);list(
/obj/random/contraband/nofail,
/obj/random/contraband/nofail,
- /obj/random/contraband/nofail,
+ /obj/random/unidentified_medicine/combat_medicine,
+ /obj/random/unidentified_medicine/combat_medicine,
/obj/random/projectile/random,
/obj/random/projectile/random,
/obj/random/mre,
/obj/random/mre,
+ /obj/structure/closet/crate/secure/saare //SAARE GRAB BAG
+ ),
+ prob(2);list(
+ /obj/random/grenade,
+ /obj/random/grenade,
+ /obj/random/grenade,
+ /obj/random/grenade,
+ /obj/random/grenade,
+ /obj/random/grenade,
+ /obj/structure/closet/crate/secure/saare //SAARE GRENADES
+ ),
+ prob(1);list(
+ /obj/random/cash/big,
+ /obj/random/cash/big,
+ /obj/random/cash/big,
+ /obj/random/cash/huge,
+ /obj/random/cash/huge,
+ /obj/random/cash/huge,
+ /obj/structure/closet/crate/secure/saare //SAARE CASH CRATE
+ )
+ )
+
+/obj/random/multiple/corp_crate/no_weapons
+ name = "random corporate crate (no weapons)"
+ desc = "A random corporate crate with thematic contents. No weapons."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "crate"
+
+/obj/random/multiple/corp_crate/no_weapons/item_to_spawn()
+ return pick(
+ prob(10);list(
+ /obj/random/tank,
+ /obj/random/tank,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/item/clothing/mask/breath,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/aether //AETHER AIRSUPPLY
+ ),
+ prob(5);list(
+ /obj/random/multiple/voidsuit/vintage,
+ /obj/random/multiple/voidsuit/vintage,
+ /obj/random/tank,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/aether //AETHER OLDSUITS
+ ),
+ prob(10);list(
/obj/random/mre,
- /obj/structure/closet/crate/secure/saare //SAARE GUNS
+ /obj/random/mre,
+ /obj/random/mre,
+ /obj/random/mre,
+ /obj/random/mre,
+ /obj/structure/closet/crate/centauri //CENTAURI MRES
+ ),
+ prob(10);list(
+ /obj/random/drinksoft,
+ /obj/random/drinksoft,
+ /obj/random/drinksoft,
+ /obj/random/drinksoft,
+ /obj/random/drinksoft,
+ /obj/structure/closet/crate/freezer/centauri //CENTAURI SODA
+ ),
+ prob(10);list(
+ /obj/random/snack,
+ /obj/random/snack,
+ /obj/random/snack,
+ /obj/random/snack,
+ /obj/random/snack,
+ /obj/structure/closet/crate/freezer/centauri //CENTAURI SNACKS
+ ),
+ prob(10);list(
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/structure/closet/crate/einstein //EINSTEIN BATTERYPACK
+ ),
+ prob(5);list(
+ /obj/item/weapon/circuitboard/smes,
+ /obj/random/smes_coil,
+ /obj/random/smes_coil,
+ /obj/structure/closet/crate/focalpoint //FOCAL SMES
+ ),
+ prob(10);list(
+ /obj/item/weapon/module/power_control,
+ /obj/item/stack/cable_coil,
+ /obj/item/frame/apc,
+ /obj/item/weapon/cell/apc,
+ /obj/structure/closet/crate/focalpoint //FOCAL APC
+ ),
+ prob(5);list(
+ /obj/random/drinkbottle,
+ /obj/random/drinkbottle,
+ /obj/random/drinkbottle,
+ /obj/random/cigarettes,
+ /obj/random/cigarettes,
+ /obj/random/cigarettes,
+ /obj/structure/closet/crate/gilthari //GILTHARI LUXURY
+ ),
+ prob(10);list(
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/structure/closet/crate/grayson //GRAYSON TECH
+ ),
+ prob(15);list(
+ /obj/random/multiple/ore_pile,
+ /obj/random/multiple/ore_pile,
+ /obj/random/multiple/ore_pile,
+ /obj/random/multiple/ore_pile,
+ /obj/structure/closet/crate/grayson //GRAYSON ORES
+ ),
+ prob(10);list(
+ /obj/random/material/refined,
+ /obj/random/material/refined,
+ /obj/random/material/refined,
+ /obj/random/material/refined,
+ /obj/structure/closet/crate/grayson //GRAYSON MATS
+ ),
+ prob(5);list(
+ /obj/random/multiple/voidsuit/security,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/secure/nanotrasen //NTSEC SUIT
+ ),
+ prob(5);list(
+ /obj/random/multiple/voidsuit/medical,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/secure/veymed //VM SUIT
+ ),
+ prob(5);list(
+ /obj/random/multiple/voidsuit/mining,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/grayson //GRAYSON SUIT
+ ),
+ prob(5);list(
+ /obj/random/multiple/voidsuit/engineering,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/xion //XION SUIT
+ ),
+ prob(10);list(
+ /obj/random/firstaid,
+ /obj/random/medical,
+ /obj/random/medical,
+ /obj/random/medical,
+ /obj/random/medical/lite,
+ /obj/random/medical/lite,
+ /obj/structure/closet/crate/veymed //VM GRABBAG
+ ),
+ prob(10);list(
+ /obj/random/firstaid,
+ /obj/random/firstaid,
+ /obj/random/firstaid,
+ /obj/random/firstaid,
+ /obj/random/unidentified_medicine/fresh_medicine,
+ /obj/random/unidentified_medicine/fresh_medicine,
+ /obj/structure/closet/crate/veymed //VM FAKS
+ ),
+ prob(10);list(
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/structure/closet/crate/xion //XION SUPPLY
+ ),
+ prob(10);list(
+ /obj/random/firstaid,
+ /obj/random/medical,
+ /obj/random/medical/pillbottle,
+ /obj/random/medical/pillbottle,
+ /obj/random/medical/lite,
+ /obj/random/medical/lite,
+ /obj/structure/closet/crate/zenghu //ZENGHU GRABBAG
+ ),
+ prob(10);list(
+ /obj/random/medical/pillbottle,
+ /obj/random/medical/pillbottle,
+ /obj/random/medical/pillbottle,
+ /obj/random/medical/pillbottle,
+ /obj/random/unidentified_medicine/fresh_medicine,
+ /obj/random/unidentified_medicine/fresh_medicine,
+ /obj/structure/closet/crate/zenghu //ZENGHU PILLS
+ ),
+ prob(10);list(
+ /obj/item/device/toner,
+ /obj/item/device/toner,
+ /obj/item/device/toner,
+ /obj/item/weapon/clipboard,
+ /obj/item/weapon/clipboard,
+ /obj/item/weapon/pen/red,
+ /obj/item/weapon/pen/blue,
+ /obj/item/weapon/pen/blue,
+ /obj/item/device/camera_film,
+ /obj/item/weapon/folder/blue,
+ /obj/item/weapon/folder/red,
+ /obj/item/weapon/folder/yellow,
+ /obj/item/weapon/hand_labeler,
+ /obj/item/weapon/tape_roll,
+ /obj/item/weapon/paper_bin,
+ /obj/item/sticky_pad/random,
+ /obj/structure/closet/crate/ummarcar //UMMARCAR OFFICE TRASH
+ ),
+ prob(5);list(
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/structure/closet/crate/unathi //UNAJERKY
+ ),
+ prob(10);list(
+ /obj/item/weapon/reagent_containers/glass/bucket,
+ /obj/item/weapon/mop,
+ /obj/item/clothing/under/rank/janitor,
+ /obj/item/weapon/cartridge/janitor,
+ /obj/item/clothing/gloves/black,
+ /obj/item/clothing/head/soft/purple,
+ /obj/item/weapon/storage/belt/janitor,
+ /obj/item/clothing/shoes/galoshes,
+ /obj/item/weapon/storage/bag/trash,
+ /obj/item/device/lightreplacer,
+ /obj/item/weapon/reagent_containers/spray/cleaner,
+ /obj/item/weapon/reagent_containers/glass/rag,
+ /obj/item/weapon/grenade/chem_grenade/cleaner,
+ /obj/item/weapon/grenade/chem_grenade/cleaner,
+ /obj/item/weapon/grenade/chem_grenade/cleaner,
+ /obj/structure/closet/crate/galaksi //GALAKSI JANITOR SUPPLIES
+ ),
+ prob(5);list(
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/structure/closet/crate/allico //GUMMIES
+ ),
+ prob(2);list(
+ /obj/item/weapon/tank/phoron/pressurized,
+ /obj/item/weapon/tank/phoron/pressurized,
+ /obj/structure/closet/crate/secure/phoron //HQ FUEL TANKS
),
prob(1);list(
/obj/random/cash/big,
@@ -849,6 +1200,100 @@
/obj/structure/closet/crate/large/secure/xion //XION TECH COMPS
)
)
+
+/obj/random/multiple/large_corp_crate/no_weapons
+ name = "random large corporate crate (no weapons)"
+ desc = "A random large corporate crate with thematic contents. No weapons."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "largermetal"
+
+/obj/random/multiple/large_corp_crate/no_weapons/item_to_spawn()
+ return pick(
+ prob(30);list(
+ /obj/random/multiple/voidsuit/vintage,
+ /obj/random/multiple/voidsuit/vintage,
+ /obj/random/tank,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/item/clothing/mask/breath,
+ /obj/random/multiple/voidsuit/vintage,
+ /obj/random/multiple/voidsuit/vintage,
+ /obj/random/tank,
+ /obj/random/tank,
+ /obj/item/clothing/mask/breath,
+ /obj/item/clothing/mask/breath,
+ /obj/structure/closet/crate/large/aether //AETHER SUITSBOX
+ ),
+ prob(30);list(
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/random/powercell,
+ /obj/structure/closet/crate/large/einstein //EIN BATTERY MEGAPACK
+ ),
+ prob(20);list(
+ /obj/item/weapon/circuitboard/smes,
+ /obj/item/weapon/circuitboard/smes,
+ /obj/random/smes_coil,
+ /obj/random/smes_coil,
+ /obj/random/smes_coil,
+ /obj/random/smes_coil,
+ /obj/random/smes_coil,
+ /obj/random/smes_coil,
+ /obj/structure/closet/crate/large/einstein //EIN SMESBOX
+ ),
+ prob(20);list(
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/random/tech_supply/nofail,
+ /obj/structure/closet/crate/large/xion //XION TECH SUPPLY
+ ),
+ prob(20);list(
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/random/tech_supply/component/nofail,
+ /obj/structure/closet/crate/large/secure/xion //XION TECH COMPS
+ )
+ )
+
+//recursion crate!
+/obj/random/multiple/random_size_crate
+ name = "random size corporate crate"
+ desc = "A random size corporate crate with thematic contents: prefers small crates."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "largermetal"
+
+/obj/random/multiple/random_size_crate/item_to_spawn()
+ return pick(
+ prob(85);list(
+ /obj/random/multiple/corp_crate
+ ),
+ prob(15);list(
+ /obj/random/multiple/large_corp_crate
+ )
+ )
/*
* Turf swappers.
*/
diff --git a/code/game/objects/random/mapping_vr.dm b/code/game/objects/random/mapping_vr.dm
new file mode 100644
index 0000000000..43431a8b16
--- /dev/null
+++ b/code/game/objects/random/mapping_vr.dm
@@ -0,0 +1,10 @@
+/obj/random/empty_or_lootable_crate
+ name = "random crate"
+ desc = "Spawns a random crate which may or may not have contents. Sometimes spawns nothing."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "moneybag"
+ spawn_nothing_percentage = 20
+
+/obj/random/empty_or_lootable_crate/item_to_spawn()
+ return pick(/obj/random/crate,
+ /obj/random/multiple/corp_crate)
\ No newline at end of file
diff --git a/code/game/objects/random/spacesuits.dm b/code/game/objects/random/spacesuits.dm
index 84cf74fb48..da380f2842 100644
--- a/code/game/objects/random/spacesuits.dm
+++ b/code/game/objects/random/spacesuits.dm
@@ -29,6 +29,10 @@
/obj/item/clothing/suit/space/void/engineering/alt,
/obj/item/clothing/head/helmet/space/void/engineering/alt
),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/engineering/hazmat,
+ /obj/item/clothing/head/helmet/space/void/engineering/hazmat
+ ),
prob(5);list(
/obj/item/clothing/suit/space/void/engineering/construction,
/obj/item/clothing/head/helmet/space/void/engineering/construction
@@ -109,7 +113,35 @@
)
)
+/obj/random/multiple/voidsuit/engineering
+ name = "Random Engineering Voidsuit"
+ desc = "This is a random engineering voidsuit."
+ icon = 'icons/obj/clothing/spacesuits.dmi'
+ icon_state = "rig-engineering"
+/obj/random/multiple/voidsuit/engineering/item_to_spawn()
+ return pick(
+ prob(35);list(
+ /obj/item/clothing/suit/space/void/engineering,
+ /obj/item/clothing/head/helmet/space/void/engineering
+ ),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/engineering/alt,
+ /obj/item/clothing/head/helmet/space/void/engineering/alt
+ ),
+ prob(15);list(
+ /obj/item/clothing/suit/space/void/engineering/hazmat,
+ /obj/item/clothing/head/helmet/space/void/engineering/hazmat
+ ),
+ prob(15);list(
+ /obj/item/clothing/suit/space/void/engineering/construction,
+ /obj/item/clothing/head/helmet/space/void/engineering/construction
+ ),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/engineering/salvage,
+ /obj/item/clothing/head/helmet/space/void/engineering/salvage
+ )
+ )
/obj/random/multiple/voidsuit/security
name = "Random Security Voidsuit"
diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm
index fc136cfda8..29498bb2df 100644
--- a/code/game/objects/structures/bedsheet_bin.dm
+++ b/code/game/objects/structures/bedsheet_bin.dm
@@ -16,8 +16,8 @@ LINEN BINS
throw_speed = 1
throw_range = 2
w_class = ITEMSIZE_SMALL
- drop_sound = 'sound/items/drop/cloth.ogg'
- pickup_sound = 'sound/items/pickup/cloth.ogg'
+ drop_sound = 'sound/items/drop/clothing.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
/obj/item/weapon/bedsheet/attack_self(mob/user as mob)
user.drop_item()
diff --git a/code/game/objects/structures/janicart.dm b/code/game/objects/structures/janicart.dm
index de07aa8de8..a6dc8e42ac 100644
--- a/code/game/objects/structures/janicart.dm
+++ b/code/game/objects/structures/janicart.dm
@@ -20,8 +20,90 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart)
var/has_items = FALSE
var/dismantled = TRUE
var/signs = 0 //maximum capacity hardcoded below
+ var/list/tgui_icons = list()
+ var/static/list/equippable_item_whitelist
+/obj/structure/janitorialcart/proc/equip_janicart_item(mob/user, obj/item/I)
+ if(!equippable_item_whitelist)
+ equippable_item_whitelist = typecacheof(list(
+ /obj/item/weapon/storage/bag/trash,
+ /obj/item/weapon/mop,
+ /obj/item/weapon/reagent_containers/spray,
+ /obj/item/device/lightreplacer,
+ /obj/item/clothing/suit/caution,
+ ))
+
+ if(!is_type_in_typecache(I, equippable_item_whitelist))
+ to_chat(user, "There's no room in [src] for [I].")
+ return FALSE
+
+ if(!user.unEquip(I, 0, src))
+ to_chat(user, "[I] is stuck to your hand.")
+ return FALSE
+
+ if(istype(I, /obj/item/weapon/storage/bag/trash))
+ if(mybag)
+ to_chat(user, "[src] already has \an [I].")
+ return FALSE
+ mybag = I
+ setTguiIcon("mybag", mybag)
+
+ else if(istype(I, /obj/item/weapon/mop))
+ if(mymop)
+ to_chat(user, "[src] already has \an [I].")
+ return FALSE
+ mymop = I
+ setTguiIcon("mymop", mymop)
+
+ else if(istype(I, /obj/item/weapon/reagent_containers/spray))
+ if(myspray)
+ to_chat(user, "[src] already has \an [I].")
+ return FALSE
+ myspray = I
+ setTguiIcon("myspray", myspray)
+
+ else if(istype(I, /obj/item/device/lightreplacer))
+ if(myreplacer)
+ to_chat(user, "[src] already has \an [I].")
+ return FALSE
+ myreplacer = I
+ setTguiIcon("myreplacer", myreplacer)
+
+ else if(istype(I, /obj/item/clothing/suit/caution))
+ if(signs < 4)
+ signs++
+ setTguiIcon("signs", I)
+ else
+ to_chat(user, "[src] can't hold any more signs.")
+ return FALSE
+ else
+ // This may look like duplicate code, but it's important that we don't call unEquip *and* warn the user if
+ // something horrible goes wrong. (this else is never supposed to happen)
+ to_chat(user, "There's no room in [src] for [I].")
+ return FALSE
+
+ update_icon()
+ to_chat(user, "You put [I] into [src].")
+ return TRUE
+
+/obj/structure/janitorialcart/proc/setTguiIcon(key, atom/A)
+ if(!istype(A) || !key)
+ return
+
+ var/icon/F = getFlatIcon(A, defdir = SOUTH, no_anim = TRUE)
+ tgui_icons["[key]"] = "'data:image/png;base64,[icon2base64(F)]'"
+ SStgui.update_uis(src)
+
+/obj/structure/janitorialcart/proc/nullTguiIcon(key)
+ if(!key)
+ return
+ tgui_icons.Remove(key)
+ SStgui.update_uis(src)
+
+/obj/structure/janitorialcart/proc/clearTguiIcons()
+ tgui_icons.Cut()
+ SStgui.update_uis(src)
/obj/structure/janitorialcart/Destroy()
QDEL_NULL(mybag)
@@ -29,20 +111,22 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart)
QDEL_NULL(myspray)
QDEL_NULL(myreplacer)
QDEL_NULL(mybucket)
+ clearTguiIcons()
return ..()
/obj/structure/janitorialcart/examine(mob/user)
- if(..(user, 1))
- if (mybucket)
- var/contains = mybucket.reagents.total_volume
- to_chat(user, "\icon[src] The bucket contains [contains] unit\s of liquid!")
- else
- to_chat(user, "\icon[src] There is no bucket mounted on it!")
+ . = ..(user)
+ if(istype(mybucket))
+ var/contains = mybucket.reagents.total_volume
+ . += "[bicon(src)] The bucket contains [contains] unit\s of liquid!"
+ else
+ . += "[bicon(src)] There is no bucket mounted on it!"
/obj/structure/janitorialcart/MouseDrop_T(atom/movable/O as mob|obj, mob/living/user as mob)
if (istype(O, /obj/structure/mopbucket) && !mybucket)
O.forceMove(src)
mybucket = O
+ setTguiIcon("mybucket", mybucket)
to_chat(user, "You mount the [O] on the janicart.")
update_icon()
else
@@ -70,38 +154,19 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart)
return 1
else if(istype(I, /obj/item/weapon/reagent_containers/spray) && !myspray)
- user.unEquip(I, 0, src)
- myspray = I
- update_icon()
- updateUsrDialog()
- to_chat(user, "You put [I] into [src].")
+ equip_janicart_item(user, I)
return 1
else if(istype(I, /obj/item/device/lightreplacer) && !myreplacer)
- user.unEquip(I, 0, src)
- myreplacer = I
- update_icon()
- updateUsrDialog()
- to_chat(user, "You put [I] into [src].")
+ equip_janicart_item(user, I)
return 1
else if(istype(I, /obj/item/weapon/storage/bag/trash) && !mybag)
- user.unEquip(I, 0, src)
- mybag = I
- update_icon()
- updateUsrDialog()
- to_chat(user, "You put [I] into [src].")
+ equip_janicart_item(user, I)
return 1
else if(istype(I, /obj/item/clothing/suit/caution))
- if(signs < 4)
- user.unEquip(I, 0, src)
- signs++
- update_icon()
- updateUsrDialog()
- to_chat(user, "You put [I] into [src].")
- else
- to_chat(user, "[src] can't hold any more signs.")
+ equip_janicart_item(user, I)
return 1
else if(mybag)
@@ -124,16 +189,7 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart)
if(user.incapacitated() || !Adjacent(user)) return
var/obj/I = usr.get_active_hand()
if(istype(I, /obj/item/weapon/mop))
- if(!mymop)
- usr.drop_from_inventory(I,src)
- mymop = I
- update_icon()
- updateUsrDialog()
- to_chat(usr, "You put [I] into [src].")
- update_icon()
- else
- to_chat(usr, "The cart already has a mop attached")
- return
+ equip_janicart_item(user, I)
else if(istype(I, /obj/item/weapon/reagent_containers) && mybucket)
var/obj/item/weapon/reagent_containers/C = I
C.afterattack(mybucket, usr, 1)
@@ -141,75 +197,95 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart)
/obj/structure/janitorialcart/attack_hand(mob/user)
- ui_interact(user)
+ tgui_interact(user)
return
-/obj/structure/janitorialcart/ui_interact(var/mob/user, var/ui_key = "main", var/datum/nanoui/ui = null, var/force_open = TRUE)
- var/data[0]
- data["name"] = capitalize(name)
- data["bag"] = mybag ? capitalize(mybag.name) : null
- data["bucket"] = mybucket ? capitalize(mybucket.name) : null
- data["mop"] = mymop ? capitalize(mymop.name) : null
- data["spray"] = myspray ? capitalize(myspray.name) : null
- data["replacer"] = myreplacer ? capitalize(myreplacer.name) : null
- data["signs"] = signs ? "[signs] sign\s" : null
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+/obj/structure/janitorialcart/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, ui_key, "janitorcart.tmpl", "Janitorial cart", 240, 160)
- ui.set_initial_data(data)
+ ui = new(user, src, "JanitorCart", name) // 240, 160
+ ui.set_autoupdate(FALSE)
ui.open()
+/obj/structure/janitorialcart/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
-/obj/structure/janitorialcart/Topic(href, href_list)
- if(!in_range(src, usr))
- return
- if(!isliving(usr))
- return
- var/mob/living/user = usr
+ data["mybag"] = mybag ? capitalize(mybag.name) : null
+ data["mybucket"] = mybucket ? capitalize(mybucket.name) : null
+ data["mymop"] = mymop ? capitalize(mymop.name) : null
+ data["myspray"] = myspray ? capitalize(myspray.name) : null
+ data["myreplacer"] = myreplacer ? capitalize(myreplacer.name) : null
+ data["signs"] = signs ? "[signs] sign\s" : null
- if(href_list["take"])
- switch(href_list["take"])
- if("garbage")
- if(mybag)
- user.put_in_hands(mybag)
- to_chat(user, "You take [mybag] from [src].")
- mybag = null
- if("mop")
- if(mymop)
- user.put_in_hands(mymop)
- to_chat(user, "You take [mymop] from [src].")
- mymop = null
- if("spray")
- if(myspray)
- user.put_in_hands(myspray)
- to_chat(user, "You take [myspray] from [src].")
- myspray = null
- if("replacer")
- if(myreplacer)
- user.put_in_hands(myreplacer)
- to_chat(user, "You take [myreplacer] from [src].")
- myreplacer = null
- if("sign")
- if(signs)
- var/obj/item/clothing/suit/caution/Sign = locate() in src
- if(Sign)
- user.put_in_hands(Sign)
- to_chat(user, "You take \a [Sign] from [src].")
- signs--
- else
- warning("[src] signs ([signs]) didn't match contents")
- signs = 0
- if("bucket")
- if(mybucket)
- mybucket.forceMove(get_turf(user))
- to_chat(user, "You unmount [mybucket] from [src].")
- mybucket = null
+ data["icons"] = tgui_icons
+ return data
+
+/obj/structure/janitorialcart/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
+
+ var/obj/item/I = usr.get_active_hand()
+
+ switch(action)
+ if("bag")
+ if(mybag)
+ usr.put_in_hands(mybag)
+ to_chat(usr, "You take [mybag] from [src].")
+ mybag = null
+ nullTguiIcon("mybag")
+ else if(is_type_in_typecache(I, equippable_item_whitelist))
+ equip_janicart_item(usr, I)
+ if("mop")
+ if(mymop)
+ usr.put_in_hands(mymop)
+ to_chat(usr, "You take [mymop] from [src].")
+ mymop = null
+ nullTguiIcon("mymop")
+ else if(is_type_in_typecache(I, equippable_item_whitelist))
+ equip_janicart_item(usr, I)
+ if("spray")
+ if(myspray)
+ usr.put_in_hands(myspray)
+ to_chat(usr, "You take [myspray] from [src].")
+ myspray = null
+ nullTguiIcon("myspray")
+ else if(is_type_in_typecache(I, equippable_item_whitelist))
+ equip_janicart_item(usr, I)
+ if("replacer")
+ if(myreplacer)
+ usr.put_in_hands(myreplacer)
+ to_chat(usr, "You take [myreplacer] from [src].")
+ myreplacer = null
+ nullTguiIcon("myreplacer")
+ else if(is_type_in_typecache(I, equippable_item_whitelist))
+ equip_janicart_item(usr, I)
+ if("sign")
+ if(istype(I, /obj/item/clothing/suit/caution) && signs < 4)
+ equip_janicart_item(usr, I)
+ else if(signs)
+ var/obj/item/clothing/suit/caution/sign = locate() in src
+ if(sign)
+ usr.put_in_hands(sign)
+ to_chat(usr, "You take \a [sign] from [src].")
+ signs--
+ if(!signs)
+ nullTguiIcon("signs")
+ else
+ to_chat(usr, "[src] doesn't have any signs left.")
+ if("bucket")
+ if(mybucket)
+ mybucket.forceMove(get_turf(usr))
+ to_chat(usr, "You unmount [mybucket] from [src].")
+ mybucket = null
+ nullTguiIcon("mybucket")
+ else
+ to_chat(usr, "((Drag and drop a mop bucket onto [src] to equip it.))")
+ return FALSE
+ else
+ return FALSE
update_icon()
- updateUsrDialog()
-
-
+ return TRUE
/obj/structure/janitorialcart/update_icon()
overlays.Cut()
@@ -229,11 +305,6 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart)
if(signs)
overlays += "cart_sign[signs]"
-
-
-
-
-
//This is called if the cart is caught in an explosion, or destroyed by weapon fire
/obj/structure/janitorialcart/proc/spill(var/chance = 100)
var/turf/dropspot = get_turf(src)
@@ -275,6 +346,7 @@ GLOBAL_LIST_BOILERPLATE(all_janitorial_carts, /obj/structure/janitorialcart)
mybag = null
update_icon()
+ clearTguiIcons()
diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm
index e68fa43640..a9815a4070 100644
--- a/code/game/objects/structures/safe.dm
+++ b/code/game/objects/structures/safe.dm
@@ -172,7 +172,7 @@ obj/structure/safe/ex_act(severity)
icon_state = "floorsafe"
density = 0
level = 1 //underfloor
- plane = TURF_PLANE
+ plane = PLATING_PLANE
layer = ABOVE_UTILITY
/obj/structure/safe/floor/Initialize()
diff --git a/code/game/objects/structures/under_wardrobe.dm b/code/game/objects/structures/under_wardrobe.dm
index cb5db5411d..c919663eaa 100644
--- a/code/game/objects/structures/under_wardrobe.dm
+++ b/code/game/objects/structures/under_wardrobe.dm
@@ -67,7 +67,7 @@
if(!UWC)
return
var/datum/category_item/underwear/selected_underwear = input(H, "Choose underwear:", "Choose underwear", H.all_underwear[UWC.name]) as null|anything in UWC.items
- if(selected_underwear && CanUseTopic(H, default_state))
+ if(selected_underwear && CanUseTopic(H, GLOB.tgui_default_state))
H.all_underwear[UWC.name] = selected_underwear
H.hide_underwear[UWC.name] = FALSE
. = TRUE
diff --git a/code/game/objects/weapons.dm b/code/game/objects/weapons.dm
index 19fe4eb03c..cd0190c71e 100644
--- a/code/game/objects/weapons.dm
+++ b/code/game/objects/weapons.dm
@@ -36,6 +36,8 @@
continue
if(!SM.Adjacent(user) || !SM.Adjacent(target)) // Cleaving only hits mobs near the target mob and user.
continue
+ if(!attack_can_reach(user, SM, 1))
+ continue
if(resolve_attackby(SM, user, attack_modifier = 0.5)) // Hit them with the weapon. This won't cause recursive cleaving due to the cleaving variable being set to true.
hit_mobs++
diff --git a/code/game/sound.dm b/code/game/sound.dm
index eabbca5c84..415a26c78c 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -266,6 +266,15 @@
soundin = pick('sound/machines/sm/accent/normal/1.ogg', 'sound/machines/sm/accent/normal/2.ogg', 'sound/machines/sm/accent/normal/3.ogg', 'sound/machines/sm/accent/normal/4.ogg', 'sound/machines/sm/accent/normal/5.ogg', 'sound/machines/sm/accent/normal/6.ogg', 'sound/machines/sm/accent/normal/7.ogg', 'sound/machines/sm/accent/normal/8.ogg', 'sound/machines/sm/accent/normal/9.ogg', 'sound/machines/sm/accent/normal/10.ogg', 'sound/machines/sm/accent/normal/11.ogg', 'sound/machines/sm/accent/normal/12.ogg', 'sound/machines/sm/accent/normal/13.ogg', 'sound/machines/sm/accent/normal/14.ogg', 'sound/machines/sm/accent/normal/15.ogg', 'sound/machines/sm/accent/normal/16.ogg', 'sound/machines/sm/accent/normal/17.ogg', 'sound/machines/sm/accent/normal/18.ogg', 'sound/machines/sm/accent/normal/19.ogg', 'sound/machines/sm/accent/normal/20.ogg', 'sound/machines/sm/accent/normal/21.ogg', 'sound/machines/sm/accent/normal/22.ogg', 'sound/machines/sm/accent/normal/23.ogg', 'sound/machines/sm/accent/normal/24.ogg', 'sound/machines/sm/accent/normal/25.ogg', 'sound/machines/sm/accent/normal/26.ogg', 'sound/machines/sm/accent/normal/27.ogg', 'sound/machines/sm/accent/normal/28.ogg', 'sound/machines/sm/accent/normal/29.ogg', 'sound/machines/sm/accent/normal/30.ogg', 'sound/machines/sm/accent/normal/31.ogg', 'sound/machines/sm/accent/normal/32.ogg', 'sound/machines/sm/accent/normal/33.ogg', 'sound/machines/sm/supermatter1.ogg', 'sound/machines/sm/supermatter2.ogg', 'sound/machines/sm/supermatter3.ogg')
if("smdelam")
soundin = pick('sound/machines/sm/accent/delam/1.ogg', 'sound/machines/sm/accent/normal/2.ogg', 'sound/machines/sm/accent/normal/3.ogg', 'sound/machines/sm/accent/normal/4.ogg', 'sound/machines/sm/accent/normal/5.ogg', 'sound/machines/sm/accent/normal/6.ogg', 'sound/machines/sm/accent/normal/7.ogg', 'sound/machines/sm/accent/normal/8.ogg', 'sound/machines/sm/accent/normal/9.ogg', 'sound/machines/sm/accent/normal/10.ogg', 'sound/machines/sm/accent/normal/11.ogg', 'sound/machines/sm/accent/normal/12.ogg', 'sound/machines/sm/accent/normal/13.ogg', 'sound/machines/sm/accent/normal/14.ogg', 'sound/machines/sm/accent/normal/15.ogg', 'sound/machines/sm/accent/normal/16.ogg', 'sound/machines/sm/accent/normal/17.ogg', 'sound/machines/sm/accent/normal/18.ogg', 'sound/machines/sm/accent/normal/19.ogg', 'sound/machines/sm/accent/normal/20.ogg', 'sound/machines/sm/accent/normal/21.ogg', 'sound/machines/sm/accent/normal/22.ogg', 'sound/machines/sm/accent/normal/23.ogg', 'sound/machines/sm/accent/normal/24.ogg', 'sound/machines/sm/accent/normal/25.ogg', 'sound/machines/sm/accent/normal/26.ogg', 'sound/machines/sm/accent/normal/27.ogg', 'sound/machines/sm/accent/normal/28.ogg', 'sound/machines/sm/accent/normal/29.ogg', 'sound/machines/sm/accent/normal/30.ogg', 'sound/machines/sm/accent/normal/31.ogg', 'sound/machines/sm/accent/normal/32.ogg', 'sound/machines/sm/accent/normal/33.ogg', 'sound/machines/sm/supermatter1.ogg', 'sound/machines/sm/supermatter2.ogg', 'sound/machines/sm/supermatter3.ogg')
+ if ("generic_drop")
+ soundin = pick(
+ 'sound/items/drop/generic1.ogg',
+ 'sound/items/drop/generic2.ogg' )
+ if ("generic_pickup")
+ soundin = pick(
+ 'sound/items/pickup/generic1.ogg',
+ 'sound/items/pickup/generic2.ogg',
+ 'sound/items/pickup/generic3.ogg')
return soundin
//Are these even used?
diff --git a/code/game/turfs/simulated/floor_types_vr.dm b/code/game/turfs/simulated/floor_types_vr.dm
index c4315b29b2..78e417fdc1 100644
--- a/code/game/turfs/simulated/floor_types_vr.dm
+++ b/code/game/turfs/simulated/floor_types_vr.dm
@@ -41,4 +41,16 @@
set_light(3,3,"#26c5a9")
spawn(5 SECONDS)
icon_state = "floor"
- set_light(0,0,"#ffffff")
\ No newline at end of file
+ set_light(0,0,"#ffffff")
+
+/turf/simulated/floor/gorefloor
+ name = "infected tile"
+ desc = "Slick, sickly-squirming meat has grown in and out of cracks once empty. It pulsates intermittently, and with every beat, blood seeps out of pores."
+ icon_state = "bloodfloor_1"
+ icon = 'icons/goonstation/turf/meatland.dmi'
+
+/turf/simulated/floor/gorefloor2
+ name = "putrid mass"
+ desc = "It is entirely made of sick, gurgling flesh. It is releasing a sickly odour."
+ icon_state = "bloodfloor_2"
+ icon = 'icons/goonstation/turf/meatland.dmi'
\ No newline at end of file
diff --git a/code/game/turfs/simulated/wall_types_vr.dm b/code/game/turfs/simulated/wall_types_vr.dm
index 21bea538dc..d2461282e2 100644
--- a/code/game/turfs/simulated/wall_types_vr.dm
+++ b/code/game/turfs/simulated/wall_types_vr.dm
@@ -61,6 +61,24 @@ var/list/flesh_overlay_cache = list()
var/turf/simulated/flesh/F = get_step(src, direction)
F.update_icon()
+/turf/simulated/gore
+ name = "wall of viscera"
+ desc = "Its veins pulse in a sickeningly rapid fashion, while certain spots of the wall rise and fall gently, much like slow, deliberate breathing."
+ icon = 'icons/goonstation/turf/meatland.dmi'
+ icon_state = "bloodwall_2"
+ opacity = 1
+ density = 1
+ blocks_air = 1
+
+/turf/simulated/goreeyes
+ name = "wall of viscera"
+ desc = "Strangely observant eyes dot the wall. Getting too close has the eyes fixate on you, while their pupils shake violently. Each socket is connected by a series of winding, writhing veins."
+ icon = 'icons/goonstation/turf/meatland.dmi'
+ icon_state = "bloodwall_4"
+ opacity = 1
+ density = 1
+ blocks_air = 1
+
/turf/simulated/shuttle/wall/flock
icon = 'icons/goonstation/featherzone.dmi'
icon_state = "flockwall0"
@@ -94,4 +112,4 @@ var/list/flesh_overlay_cache = list()
icon_state = "hull-plastitanium"
icon = 'icons/turf/wall_masks_vr.dmi'
/turf/simulated/wall/plastihull/Initialize(mapload)
- . = ..(mapload, MAT_PLASTITANIUMHULL, null,MAT_PLASTITANIUMHULL)
\ No newline at end of file
+ . = ..(mapload, MAT_PLASTITANIUMHULL, null,MAT_PLASTITANIUMHULL)
diff --git a/code/modules/admin/admin_verb_lists.dm b/code/modules/admin/admin_verb_lists.dm
index b576bec44a..0eaedc9fbe 100644
--- a/code/modules/admin/admin_verb_lists.dm
+++ b/code/modules/admin/admin_verb_lists.dm
@@ -181,7 +181,6 @@ var/list/admin_verbs_server = list(
/datum/admins/proc/toggle_space_ninja,
/client/proc/toggle_random_events,
/client/proc/check_customitem_activity,
- /client/proc/nanomapgen_DumpImage,
/client/proc/modify_server_news,
/client/proc/recipe_dump,
/client/proc/panicbunker,
diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm
index 384dcbcd9b..815d250dcc 100644
--- a/code/modules/asset_cache/asset_list_items.dm
+++ b/code/modules/asset_cache/asset_list_items.dm
@@ -6,36 +6,36 @@
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
)
-// /datum/asset/simple/headers
-// assets = list(
-// "alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
-// "alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
-// "batt_5.gif" = 'icons/program_icons/batt_5.gif',
-// "batt_20.gif" = 'icons/program_icons/batt_20.gif',
-// "batt_40.gif" = 'icons/program_icons/batt_40.gif',
-// "batt_60.gif" = 'icons/program_icons/batt_60.gif',
-// "batt_80.gif" = 'icons/program_icons/batt_80.gif',
-// "batt_100.gif" = 'icons/program_icons/batt_100.gif',
-// "charging.gif" = 'icons/program_icons/charging.gif',
-// "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
-// "downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
-// "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
-// "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
-// "power_norm.gif" = 'icons/program_icons/power_norm.gif',
-// "power_warn.gif" = 'icons/program_icons/power_warn.gif',
-// "sig_high.gif" = 'icons/program_icons/sig_high.gif',
-// "sig_low.gif" = 'icons/program_icons/sig_low.gif',
-// "sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
-// "sig_none.gif" = 'icons/program_icons/sig_none.gif',
-// "smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
-// "smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
-// "smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
-// "smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
-// "smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
-// "smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
-// "smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
-// "borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
-// )
+/datum/asset/simple/headers
+ assets = list(
+ "alarm_green.gif" = 'icons/program_icons/alarm_green.gif',
+ "alarm_red.gif" = 'icons/program_icons/alarm_red.gif',
+ "batt_5.gif" = 'icons/program_icons/batt_5.gif',
+ "batt_20.gif" = 'icons/program_icons/batt_20.gif',
+ "batt_40.gif" = 'icons/program_icons/batt_40.gif',
+ "batt_60.gif" = 'icons/program_icons/batt_60.gif',
+ "batt_80.gif" = 'icons/program_icons/batt_80.gif',
+ "batt_100.gif" = 'icons/program_icons/batt_100.gif',
+ "charging.gif" = 'icons/program_icons/charging.gif',
+ "downloader_finished.gif" = 'icons/program_icons/downloader_finished.gif',
+ "downloader_running.gif" = 'icons/program_icons/downloader_running.gif',
+ "ntnrc_idle.gif" = 'icons/program_icons/ntnrc_idle.gif',
+ "ntnrc_new.gif" = 'icons/program_icons/ntnrc_new.gif',
+ "power_norm.gif" = 'icons/program_icons/power_norm.gif',
+ "power_warn.gif" = 'icons/program_icons/power_warn.gif',
+ "sig_high.gif" = 'icons/program_icons/sig_high.gif',
+ "sig_low.gif" = 'icons/program_icons/sig_low.gif',
+ "sig_lan.gif" = 'icons/program_icons/sig_lan.gif',
+ "sig_none.gif" = 'icons/program_icons/sig_none.gif',
+ "smmon_0.gif" = 'icons/program_icons/smmon_0.gif',
+ "smmon_1.gif" = 'icons/program_icons/smmon_1.gif',
+ "smmon_2.gif" = 'icons/program_icons/smmon_2.gif',
+ "smmon_3.gif" = 'icons/program_icons/smmon_3.gif',
+ "smmon_4.gif" = 'icons/program_icons/smmon_4.gif',
+ "smmon_5.gif" = 'icons/program_icons/smmon_5.gif',
+ "smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
+ // "borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
+ )
// /datum/asset/simple/radar_assets
// assets = list(
@@ -206,15 +206,15 @@
// "none_button.png" = 'html/none_button.png',
// )
-// /datum/asset/simple/arcade
-// assets = list(
-// "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
-// "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
-// "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
-// "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
-// "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
-// "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
-// )
+/datum/asset/simple/arcade
+ assets = list(
+ "boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
+ "boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
+ "boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
+ "boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
+ "boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
+ "boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
+ )
// /datum/asset/spritesheet/simple/achievements
// name ="achievements"
@@ -433,45 +433,6 @@
// Insert("polycrystal", 'icons/obj/telescience.dmi', "polycrystal")
// ..()
-/datum/asset/nanoui
- var/list/common = list()
-
- var/list/common_dirs = list(
- "nano/css/",
- "nano/images/",
- "nano/images/modular_computers/",
- "nano/js/"
- )
- var/list/template_dirs = list(
- "nano/templates/"
- )
-
-/datum/asset/nanoui/register()
- // Crawl the directories to find files.
- for(var/path in common_dirs)
- var/list/filenames = flist(path)
- for(var/filename in filenames)
- if(copytext(filename, length(filename)) != "/") // Ignore directories.
- if(fexists(path + filename))
- common[filename] = fcopy_rsc(path + filename)
- register_asset(filename, common[filename])
- // Combine all templates into a single bundle.
- var/list/template_data = list()
- for(var/path in template_dirs)
- var/list/filenames = flist(path)
- for(var/filename in filenames)
- if(copytext(filename, length(filename) - 4) == ".tmpl") // Ignore directories.
- template_data[filename] = file2text(path + filename)
- var/template_bundle = "function nanouiTemplateBundle(){return [json_encode(template_data)];}"
- var/fname = "data/nano_templates_bundle.js"
- fdel(fname)
- text2file(template_bundle, fname)
- register_asset("nano_templates_bundle.js", fcopy_rsc(fname))
- fdel(fname)
-
-/datum/asset/nanoui/send(client)
- send_asset_list(client, common)
-
//Pill sprites for UIs
/datum/asset/chem_master
var/assets = list()
@@ -522,4 +483,31 @@
/datum/asset/spritesheet/sheetmaterials/register()
InsertAll("", 'icons/obj/stacks.dmi')
- ..()
\ No newline at end of file
+ ..()
+
+// Nanomaps
+/datum/asset/simple/nanomaps
+ // It REALLY doesnt matter too much if these arent up to date
+ // They are relatively big
+ assets = list(
+ // VOREStation Edit: We don't need Southern Cross
+ // "southern_cross_nanomap_z1.png" = 'icons/_nanomaps/southern_cross_nanomap_z1.png',
+ // "southern_cross_nanomap_z10.png" = 'icons/_nanomaps/southern_cross_nanomap_z10.png',
+ // "southern_cross_nanomap_z2.png" = 'icons/_nanomaps/southern_cross_nanomap_z2.png',
+ // "southern_cross_nanomap_z3.png" = 'icons/_nanomaps/southern_cross_nanomap_z3.png',
+ // "southern_cross_nanomap_z5.png" = 'icons/_nanomaps/southern_cross_nanomap_z5.png',
+ // "southern_cross_nanomap_z6.png" = 'icons/_nanomaps/southern_cross_nanomap_z6.png',
+ "tether_nanomap_z1.png" = 'icons/_nanomaps/tether_nanomap_z1.png',
+ "tether_nanomap_z2.png" = 'icons/_nanomaps/tether_nanomap_z2.png',
+ "tether_nanomap_z3.png" = 'icons/_nanomaps/tether_nanomap_z3.png',
+ "tether_nanomap_z4.png" = 'icons/_nanomaps/tether_nanomap_z4.png',
+ "tether_nanomap_z5.png" = 'icons/_nanomaps/tether_nanomap_z5.png',
+ "tether_nanomap_z6.png" = 'icons/_nanomaps/tether_nanomap_z6.png',
+ "tether_nanomap_z7.png" = 'icons/_nanomaps/tether_nanomap_z7.png',
+ "tether_nanomap_z8.png" = 'icons/_nanomaps/tether_nanomap_z8.png',
+ "tether_nanomap_z9.png" = 'icons/_nanomaps/tether_nanomap_z9.png',
+ "tether_nanomap_z10.png" = 'icons/_nanomaps/tether_nanomap_z10.png',
+ "tether_nanomap_z13.png" = 'icons/_nanomaps/tether_nanomap_z13.png',
+ "tether_nanomap_z14.png" = 'icons/_nanomaps/tether_nanomap_z14.png',
+ // VOREStation Edit End
+ )
\ No newline at end of file
diff --git a/code/modules/awaymissions/loot_vr.dm b/code/modules/awaymissions/loot_vr.dm
index d48c65bd61..2fecbbded8 100644
--- a/code/modules/awaymissions/loot_vr.dm
+++ b/code/modules/awaymissions/loot_vr.dm
@@ -391,4 +391,9 @@
/obj/structure/symbol/sa
desc = "It looks like a right triangle with a dot to the side. It reminds you of a wooden strut between a wall and ceiling."
- icon_state = "sa"
\ No newline at end of file
+ icon_state = "sa"
+
+/obj/structure/symbol/maint
+ name = "maintenance panel"
+ desc = "This sign suggests that the wall it's attached to can be opened somehow."
+ icon_state = "maintenance_panel"
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes.dm b/code/modules/client/preference_setup/loadout/loadout_eyes.dm
index 989ed954d3..cc171a08b1 100644
--- a/code/modules/client/preference_setup/loadout/loadout_eyes.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_eyes.dm
@@ -5,6 +5,16 @@
slot = slot_glasses
sort_category = "Glasses and Eyewear"
+/datum/gear/eyes/eyepatchwhite
+ display_name = "eyepatch (recolorable)"
+ path = /obj/item/clothing/glasses/eyepatchwhite
+ slot = slot_glasses
+ sort_category = "Glasses and Eyewear"
+
+/datum/gear/eyes/eyepatchwhite/New()
+ ..()
+ gear_tweaks += gear_tweak_free_color_choice
+
/datum/gear/eyes/glasses
display_name = "Glasses, prescription"
path = /obj/item/clothing/glasses/regular
diff --git a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
index a01f2ff64a..c0211f71e6 100644
--- a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
@@ -911,6 +911,13 @@
ckeywhitelist = list("theskringdinger")
character_name = list("Monty Kopic")
+/datum/gear/fluff/shadow_laptop
+ path = /obj/item/modular_computer/laptop/preset/custom_loadout/advanced/shadowlarkens
+ display_name = "Shadow's Laptop"
+ ckeywhitelist = list("tigercat2000")
+ character_name = list("Shadow Larkens")
+ cost = 5
+
/datum/gear/fluff/konor_medal
path = /obj/item/clothing/accessory/medal/silver/unity
display_name = "Konor's Unity Medal"
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 102280055a..c8e9f3414c 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -2,7 +2,7 @@
name = "clothing"
siemens_coefficient = 0.9
drop_sound = 'sound/items/drop/clothing.ogg'
- pickup_sound = 'sound/items/pickup/cloth.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
var/list/species_restricted = null //Only these species can wear this kit.
var/gunshot_residue //Used by forensics.
@@ -435,6 +435,8 @@
fingerprint_chance = 100
punch_force = 2
body_parts_covered = 0
+ drop_sound = 'sound/items/drop/ring.ogg'
+ pickup_sound = 'sound/items/pickup/ring.ogg'
///////////////////////////////////////////////////////////////////////
//Head
@@ -573,6 +575,9 @@
var/list/say_messages
var/list/say_verbs
+ drop_sound = "generic_drop"
+ pickup_sound = "generic_pickup"
+
/obj/item/clothing/mask/update_clothing_icon()
if (ismob(src.loc))
var/mob/M = src.loc
@@ -733,6 +738,7 @@
siemens_coefficient = 0.9
w_class = ITEMSIZE_NORMAL
preserve_item = 1
+ equip_sound = 'sound/items/jumpsuit_equip.ogg'
sprite_sheets = list(
diff --git a/code/modules/clothing/ears/ears.dm b/code/modules/clothing/ears/ears.dm
index 8fdd6deb94..07e74d7321 100644
--- a/code/modules/clothing/ears/ears.dm
+++ b/code/modules/clothing/ears/ears.dm
@@ -53,8 +53,8 @@
desc = "A delicate golden chain worn by female skrell to decorate their head tails."
icon_state = "skrell_chain"
item_state_slots = list(slot_r_hand_str = "egg5", slot_l_hand_str = "egg5")
- drop_sound = 'sound/items/drop/accessory.ogg'
- pickup_sound = 'sound/items/pickup/accessory.ogg'
+ drop_sound = 'sound/items/drop/ring.ogg'
+ pickup_sound = 'sound/items/pickup/ring.ogg'
/obj/item/clothing/ears/skrell/chain/silver
name = "Silver headtail chains"
@@ -85,8 +85,8 @@
desc = "Golden metallic bands worn by male skrell to adorn their head tails."
icon_state = "skrell_band"
item_state_slots = list(slot_r_hand_str = "egg5", slot_l_hand_str = "egg5")
- drop_sound = 'sound/items/drop/accessory.ogg'
- pickup_sound = 'sound/items/pickup/accessory.ogg'
+ drop_sound = 'sound/items/drop/ring.ogg'
+ pickup_sound = 'sound/items/pickup/ring.ogg'
/obj/item/clothing/ears/skrell/band/silver
name = "Silver headtail bands"
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index ff9a69fea8..e65590f86c 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -199,6 +199,30 @@ BLIND // can't see anything
icon_state = initial(icon_state)
update_clothing_icon()
+/obj/item/clothing/glasses/eyepatchwhite
+ name = "eyepatch"
+ desc = "A simple eyepatch made of a strip of cloth tied around the head."
+ icon_state = "eyepatch_white"
+ item_state_slots = list(slot_r_hand_str = "blindfold", slot_l_hand_str = "blindfold")
+ body_parts_covered = 0
+ var/eye = null
+ drop_sound = 'sound/items/drop/gloves.ogg'
+ pickup_sound = 'sound/items/pickup/gloves.ogg'
+
+/obj/item/clothing/glasses/eyepatchwhite/verb/switcheye()
+ set name = "Switch Eyepatch"
+ set category = "Object"
+ set src in usr
+ if(!istype(usr, /mob/living)) return
+ if(usr.stat) return
+
+ eye = !eye
+ if(eye)
+ icon_state = "[icon_state]_1"
+ else
+ icon_state = initial(icon_state)
+ update_clothing_icon()
+
/obj/item/clothing/glasses/monocle
name = "monocle"
desc = "Such a dapper eyepiece!"
diff --git a/code/modules/clothing/glasses/hud_vr.dm b/code/modules/clothing/glasses/hud_vr.dm
index 613c09e91e..718b9e6908 100644
--- a/code/modules/clothing/glasses/hud_vr.dm
+++ b/code/modules/clothing/glasses/hud_vr.dm
@@ -8,8 +8,6 @@
var/obj/item/clothing/glasses/hud/omni/hud = null
var/mode = "civ"
icon_state = "glasses"
- var/datum/nano_module/arscreen
- var/arscreen_path
var/datum/tgui_module/tgarscreen
var/tgarscreen_path
var/flash_prot = 0 //0 for none, 1 for flash weapon protection, 2 for welder protection
@@ -18,34 +16,24 @@
/obj/item/clothing/glasses/omnihud/New()
..()
- if(arscreen_path)
- arscreen = new arscreen_path(src)
if(tgarscreen_path)
tgarscreen = new tgarscreen_path(src)
/obj/item/clothing/glasses/omnihud/Destroy()
- QDEL_NULL(arscreen)
QDEL_NULL(tgarscreen)
. = ..()
/obj/item/clothing/glasses/omnihud/dropped()
- if(arscreen)
- SSnanoui.close_uis(src)
if(tgarscreen)
SStgui.close_uis(src)
..()
/obj/item/clothing/glasses/omnihud/emp_act(var/severity)
- if(arscreen)
- SSnanoui.close_uis(src)
if(tgarscreen)
SStgui.close_uis(src)
- var/disconnect_ar = arscreen
var/disconnect_tgar = tgarscreen
- arscreen = null
tgarscreen = null
spawn(20 SECONDS)
- arscreen = disconnect_ar
tgarscreen = disconnect_tgar
//extra fun for non-sci variants; a small chance flip the state to the dumb 3d glasses when EMP'd
diff --git a/code/modules/clothing/head/flowercrowns.dm b/code/modules/clothing/head/flowercrowns.dm
index 15bfe16162..81193f337d 100644
--- a/code/modules/clothing/head/flowercrowns.dm
+++ b/code/modules/clothing/head/flowercrowns.dm
@@ -37,6 +37,7 @@
icon_state = "sunflower_crown"
body_parts_covered = 0
drop_sound = 'sound/items/drop/herb.ogg'
+ pickup_sound = 'sound/items/pickup/herb.ogg'
/obj/item/clothing/head/lavender_crown
name = "lavender crown"
@@ -44,6 +45,7 @@
icon_state = "lavender_crown"
body_parts_covered = 0
drop_sound = 'sound/items/drop/herb.ogg'
+ pickup_sound = 'sound/items/pickup/herb.ogg'
/obj/item/clothing/head/poppy_crown
name = "poppy crown"
@@ -51,6 +53,7 @@
icon_state = "poppy_crown"
body_parts_covered = 0
drop_sound = 'sound/items/drop/herb.ogg'
+ pickup_sound = 'sound/items/pickup/herb.ogg'
/obj/item/clothing/head/rose_crown
name = "rose crown"
@@ -58,3 +61,4 @@
icon_state = "poppy_crown"
body_parts_covered = 0
drop_sound = 'sound/items/drop/herb.ogg'
+ pickup_sound = 'sound/items/pickup/herb.ogg'
diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm
index 818c91eda5..dff571c50f 100644
--- a/code/modules/clothing/head/misc.dm
+++ b/code/modules/clothing/head/misc.dm
@@ -17,8 +17,8 @@
desc = "A nice hair pin."
slot_flags = SLOT_HEAD | SLOT_EARS
body_parts_covered = 0
- drop_sound = 'sound/items/drop/ring.ogg'
- pickup_sound = 'sound/items/pickup/ring.ogg'
+ drop_sound = 'sound/items/drop/accessory.ogg'
+ pickup_sound = 'sound/items/pickup/accessory.ogg'
/obj/item/clothing/head/pin/pink
icon_state = "pinkpin"
@@ -424,7 +424,8 @@
desc = "A jeweled headpiece originating in India."
icon_state = "maangtikka"
body_parts_covered = 0
- drop_sound = 'sound/items/drop/accessory.ogg'
+ drop_sound = 'sound/items/drop/ring.ogg'
+ pickup_sound = 'sound/items/pickup/ring.ogg'
/obj/item/clothing/head/jingasa
name = "jingasa"
diff --git a/code/modules/clothing/masks/breath.dm b/code/modules/clothing/masks/breath.dm
index b64f437207..cf7a0bc939 100644
--- a/code/modules/clothing/masks/breath.dm
+++ b/code/modules/clothing/masks/breath.dm
@@ -10,6 +10,8 @@
permeability_coefficient = 0.50
var/hanging = 0
action_button_name = "Adjust Breath Mask"
+ pickup_sound = 'sound/items/pickup/component.ogg'
+ drop_sound = 'sound/items/drop/component.ogg'
/obj/item/clothing/mask/breath/proc/adjust_mask(mob/user)
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index 116a54e494..25b9e00f68 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -13,6 +13,7 @@
var/gas_filter_strength = 1 //For gas mask filters
var/list/filtered_gases = list("phoron", "nitrous_oxide")
armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 75, rad = 0)
+ pickup_sound = 'sound/items/pickup/rubber.ogg'
/obj/item/clothing/mask/gas/filter_air(datum/gas_mixture/air)
var/datum/gas_mixture/gas_filtered = new
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index 25b8558da9..996b2a9761 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -108,7 +108,7 @@ obj/item/clothing/shoes/sandal/clogs
species_restricted = null
w_class = ITEMSIZE_SMALL
drop_sound = 'sound/items/drop/clothing.ogg'
- pickup_sound = 'sound/items/pickup/cloth.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
/obj/item/clothing/shoes/slippers/worn
name = "worn bunny slippers"
@@ -172,7 +172,7 @@ obj/item/clothing/shoes/sandal/clogs
w_class = ITEMSIZE_SMALL
species_restricted = null
drop_sound = 'sound/items/drop/clothing.ogg'
- pickup_sound = 'sound/items/pickup/cloth.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
/obj/item/clothing/shoes/boots/ranger
var/bootcolor = "white"
diff --git a/code/modules/clothing/spacesuits/rig/modules/computer.dm b/code/modules/clothing/spacesuits/rig/modules/computer.dm
index cf055ae9c0..fbf08479f4 100644
--- a/code/modules/clothing/spacesuits/rig/modules/computer.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/computer.dm
@@ -23,7 +23,7 @@
to_chat(usr, "Your module is not installed in a hardsuit.")
return
- module.holder.ui_interact(usr, nano_state = contained_state)
+ module.holder.tgui_interact(usr, custom_state = GLOB.tgui_contained_state)
/obj/item/rig_module/ai_container
diff --git a/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm b/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm
index e6848a66d0..4f7dfef043 100644
--- a/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/specific/ai_container.dm
@@ -134,7 +134,7 @@
if(!target)
if(ai_card)
if(istype(ai_card,/obj/item/device/aicard))
- ai_card.tgui_interact(H, custom_state = deep_inventory_state)
+ ai_card.tgui_interact(H, custom_state = GLOB.tgui_deep_inventory_state)
else
eject_ai(H)
update_verb_holder()
diff --git a/code/modules/clothing/under/accessories/badges.dm b/code/modules/clothing/under/accessories/badges.dm
index e6a0a787a9..085279c424 100644
--- a/code/modules/clothing/under/accessories/badges.dm
+++ b/code/modules/clothing/under/accessories/badges.dm
@@ -13,9 +13,6 @@
var/stored_name
var/badge_string = "Corporate Security"
-
- drop_sound = 'sound/items/drop/ring.ogg'
- pickup_sound = 'sound/items/pickup/ring.ogg'
/obj/item/clothing/accessory/badge/old
name = "faded badge"
diff --git a/code/modules/economy/Accounts_DB.dm b/code/modules/economy/Accounts_DB.dm
index 9e116ecf60..68f71184e9 100644
--- a/code/modules/economy/Accounts_DB.dm
+++ b/code/modules/economy/Accounts_DB.dm
@@ -15,7 +15,7 @@
var/const/fund_cap = 1000000
/obj/machinery/account_database/proc/get_access_level()
- if (!held_card)
+ if(!held_card)
return 0
if(access_cent_captain in held_card.access)
return 2
@@ -53,19 +53,24 @@
O.loc = src
held_card = O
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
attack_hand(user)
/obj/machinery/account_database/attack_hand(mob/user as mob)
if(stat & (NOPOWER|BROKEN)) return
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/account_database/ui_interact(mob/user, ui_key="main", var/datum/nanoui/ui = null, var/force_open = 1)
- user.set_machine(src)
+/obj/machinery/account_database/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "AccountsTerminal", name)
+ ui.open()
+
+
+/obj/machinery/account_database/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- var/data[0]
- data["src"] = "\ref[src]"
data["id_inserted"] = !!held_card
data["id_card"] = held_card ? text("[held_card.registered_name], [held_card.assignment]") : "-----"
data["access_level"] = get_access_level()
@@ -73,10 +78,14 @@
data["creating_new_account"] = creating_new_account
data["detailed_account_view"] = !!detailed_account_view
data["station_account_number"] = station_account.account_number
- data["transactions"] = null
- data["accounts"] = null
- if (detailed_account_view)
+ data["account_number"] = null
+ data["owner_name"] = null
+ data["money"] = null
+ data["suspended"] = null
+ data["transactions"] = list()
+
+ if(detailed_account_view)
data["account_number"] = detailed_account_view.account_number
data["owner_name"] = detailed_account_view.owner_name
data["money"] = detailed_account_view.money
@@ -92,11 +101,10 @@
"amount" = T.amount, \
"source_terminal" = T.source_terminal)))
- if (trx.len > 0)
- data["transactions"] = trx
+ data["transactions"] = trx
- var/list/accounts[0]
- for(var/i=1, i<=all_money_accounts.len, i++)
+ var/list/accounts = list()
+ for(var/i in 1 to LAZYLEN(all_money_accounts))
var/datum/money_account/D = all_money_accounts[i]
if(D.offmap)
continue
@@ -106,174 +114,168 @@
"suspended"=D.suspended ? "SUSPENDED" : "",\
"account_index"=i)))
- if (accounts.len > 0)
- data["accounts"] = accounts
+ data["accounts"] = accounts
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "accounts_terminal.tmpl", src.name, 400, 640)
- ui.set_initial_data(data)
- ui.open()
+ return data
-/obj/machinery/account_database/Topic(href, href_list)
+/obj/machinery/account_database/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
+ return TRUE
- var/datum/nanoui/ui = SSnanoui.get_open_ui(usr, src, "main")
+ switch(action)
+ if("create_account")
+ creating_new_account = 1
- if(href_list["choice"])
- switch(href_list["choice"])
- if("create_account")
- creating_new_account = 1
+ if("add_funds")
+ var/amount = input("Enter the amount you wish to add", "Silently add funds") as num
+ if(detailed_account_view)
+ detailed_account_view.money = min(detailed_account_view.money + amount, fund_cap)
- if("add_funds")
- var/amount = input("Enter the amount you wish to add", "Silently add funds") as num
- if(detailed_account_view)
- detailed_account_view.money = min(detailed_account_view.money + amount, fund_cap)
+ if("remove_funds")
+ var/amount = input("Enter the amount you wish to remove", "Silently remove funds") as num
+ if(detailed_account_view)
+ detailed_account_view.money = max(detailed_account_view.money - amount, -fund_cap)
- if("remove_funds")
- var/amount = input("Enter the amount you wish to remove", "Silently remove funds") as num
- if(detailed_account_view)
- detailed_account_view.money = max(detailed_account_view.money - amount, -fund_cap)
+ if("toggle_suspension")
+ if(detailed_account_view)
+ detailed_account_view.suspended = !detailed_account_view.suspended
+ callHook("change_account_status", list(detailed_account_view))
- if("toggle_suspension")
- if(detailed_account_view)
- detailed_account_view.suspended = !detailed_account_view.suspended
- callHook("change_account_status", list(detailed_account_view))
+ if("finalise_create_account")
+ var/account_name = params["holder_name"]
+ var/starting_funds = max(text2num(params["starting_funds"]), 0)
- if("finalise_create_account")
- var/account_name = href_list["holder_name"]
- var/starting_funds = max(text2num(href_list["starting_funds"]), 0)
+ starting_funds = CLAMP(starting_funds, 0, station_account.money) // Not authorized to put the station in debt.
+ starting_funds = min(starting_funds, fund_cap) // Not authorized to give more than the fund cap.
- starting_funds = CLAMP(starting_funds, 0, station_account.money) // Not authorized to put the station in debt.
- starting_funds = min(starting_funds, fund_cap) // Not authorized to give more than the fund cap.
+ create_account(account_name, starting_funds, src)
+ if(starting_funds > 0)
+ //subtract the money
+ station_account.money -= starting_funds
- create_account(account_name, starting_funds, src)
- if(starting_funds > 0)
- //subtract the money
- station_account.money -= starting_funds
-
- //create a transaction log entry
- var/trx = create_transation(account_name, "New account activation", "([starting_funds])")
- station_account.transaction_log.Add(trx)
-
- creating_new_account = 0
- ui.close()
+ //create a transaction log entry
+ var/trx = create_transation(account_name, "New account activation", "([starting_funds])")
+ station_account.transaction_log.Add(trx)
creating_new_account = 0
- if("insert_card")
- if(held_card)
- held_card.loc = src.loc
- if(ishuman(usr) && !usr.get_active_hand())
- usr.put_in_hands(held_card)
- held_card = null
+ creating_new_account = 0
+ if("insert_card")
+ if(held_card)
+ held_card.loc = src.loc
- else
- var/obj/item/I = usr.get_active_hand()
- if (istype(I, /obj/item/weapon/card/id))
- var/obj/item/weapon/card/id/C = I
- usr.drop_item()
- C.loc = src
- held_card = C
+ if(ishuman(usr) && !usr.get_active_hand())
+ usr.put_in_hands(held_card)
+ held_card = null
- if("view_account_detail")
- var/index = text2num(href_list["account_index"])
- if(index && index <= all_money_accounts.len)
- detailed_account_view = all_money_accounts[index]
+ else
+ var/obj/item/I = usr.get_active_hand()
+ if(istype(I, /obj/item/weapon/card/id))
+ var/obj/item/weapon/card/id/C = I
+ usr.drop_item()
+ C.loc = src
+ held_card = C
- if("view_accounts_list")
- detailed_account_view = null
- creating_new_account = 0
+ if("view_account_detail")
+ var/index = text2num(params["account_index"])
+ if(index && index <= all_money_accounts.len)
+ detailed_account_view = all_money_accounts[index]
- if("revoke_payroll")
- var/funds = detailed_account_view.money
- var/account_trx = create_transation(station_account.owner_name, "Revoke payroll", "([funds])")
- var/station_trx = create_transation(detailed_account_view.owner_name, "Revoke payroll", funds)
+ if("view_accounts_list")
+ detailed_account_view = null
+ creating_new_account = 0
- station_account.money += funds
- detailed_account_view.money = 0
+ if("revoke_payroll")
+ var/funds = detailed_account_view.money
+ var/account_trx = create_transation(station_account.owner_name, "Revoke payroll", "([funds])")
+ var/station_trx = create_transation(detailed_account_view.owner_name, "Revoke payroll", funds)
- detailed_account_view.transaction_log.Add(account_trx)
- station_account.transaction_log.Add(station_trx)
+ station_account.money += funds
+ detailed_account_view.money = 0
- callHook("revoke_payroll", list(detailed_account_view))
+ detailed_account_view.transaction_log.Add(account_trx)
+ station_account.transaction_log.Add(station_trx)
- if("print")
- var/text
- var/obj/item/weapon/paper/P = new(loc)
- if (detailed_account_view)
- P.name = "account #[detailed_account_view.account_number] details"
- var/title = "Account #[detailed_account_view.account_number] Details"
- text = {"
- [accounting_letterhead(title)]
- Holder: [detailed_account_view.owner_name]
- Balance: $[detailed_account_view.money]
- Status: [detailed_account_view.suspended ? "Suspended" : "Active"]
- Transactions: ([detailed_account_view.transaction_log.len])
-
-
-
- | Timestamp |
- Target |
- Reason |
- Value |
- Terminal |
-
-
-
- "}
+ callHook("revoke_payroll", list(detailed_account_view))
- for (var/datum/transaction/T in detailed_account_view.transaction_log)
- text += {"
-
- | [T.date] [T.time] |
- [T.target_name] |
- [T.purpose] |
- [T.amount] |
- [T.source_terminal] |
-
- "}
+ if("print")
+ print()
- text += {"
-
-
- "}
+ return TRUE
- else
- P.name = "financial account list"
- text = {"
- [accounting_letterhead("Financial Account List")]
+/obj/machinery/account_database/proc/print()
+ var/text
+ var/obj/item/weapon/paper/P = new(loc)
+ if(detailed_account_view)
+ P.name = "account #[detailed_account_view.account_number] details"
+ var/title = "Account #[detailed_account_view.account_number] Details"
+ text = {"
+ [accounting_letterhead(title)]
+ Holder: [detailed_account_view.owner_name]
+ Balance: $[detailed_account_view.money]
+ Status: [detailed_account_view.suspended ? "Suspended" : "Active"]
+ Transactions: ([detailed_account_view.transaction_log.len])
+
+
+
+ | Timestamp |
+ Target |
+ Reason |
+ Value |
+ Terminal |
+
+
+
+ "}
-
-
-
- | Account Number |
- Holder |
- Balance |
- Status |
-
-
-
- "}
+ for (var/datum/transaction/T in detailed_account_view.transaction_log)
+ text += {"
+
+ | [T.date] [T.time] |
+ [T.target_name] |
+ [T.purpose] |
+ [T.amount] |
+ [T.source_terminal] |
+
+ "}
- for(var/i=1, i<=all_money_accounts.len, i++)
- var/datum/money_account/D = all_money_accounts[i]
- text += {"
-
- | #[D.account_number] |
- [D.owner_name] |
- $[D.money] |
- [D.suspended ? "Suspended" : "Active"] |
-
- "}
+ text += {"
+
+
+ "}
- text += {"
-
-
- "}
+ else
+ P.name = "financial account list"
+ text = {"
+ [accounting_letterhead("Financial Account List")]
- P.info = text
- state("The terminal prints out a report.")
+
+
+
+ | Account Number |
+ Holder |
+ Balance |
+ Status |
+
+
+
+ "}
- return 1
+ for(var/i=1, i<=all_money_accounts.len, i++)
+ var/datum/money_account/D = all_money_accounts[i]
+ text += {"
+
+ | #[D.account_number] |
+ [D.owner_name] |
+ $[D.money] |
+ [D.suspended ? "Suspended" : "Active"] |
+
+ "}
+
+ text += {"
+
+
+ "}
+
+ P.info = text
+ state("The terminal prints out a report.")
\ No newline at end of file
diff --git a/code/modules/events/money_spam.dm b/code/modules/events/money_spam.dm
index 0b877cef3d..ad8a1bbc3f 100644
--- a/code/modules/events/money_spam.dm
+++ b/code/modules/events/money_spam.dm
@@ -36,7 +36,11 @@
var/obj/item/device/pda/P
var/list/viables = list()
for(var/obj/item/device/pda/check_pda in sortAtom(PDAs))
- if (!check_pda.owner||check_pda.toff||check_pda == src||check_pda.hidden)
+ if (!check_pda.owner || check_pda == src || check_pda.hidden)
+ continue
+
+ var/datum/data/pda/app/messenger/M = check_pda.find_program(/datum/data/pda/app/messenger)
+ if(!M || M.toff)
continue
viables.Add(check_pda)
@@ -112,17 +116,5 @@
//Commented out because we don't send messages like this anymore. Instead it will just popup in their chat window.
//P.tnote += "← From [sender] (Unknown / spam?):
[message]
"
- if (!P.message_silent)
- playsound(P, 'sound/machines/twobeep.ogg', 50, 1)
- for (var/mob/O in hearers(3, P.loc))
- if(!P.message_silent) O.show_message(text("[bicon(P)] *[P.ttone]*"))
- //Search for holder of the PDA.
- var/mob/living/L = null
- if(P.loc && isliving(P.loc))
- L = P.loc
- //Maybe they are a pAI!
- else
- L = get(P, /mob/living/silicon)
-
- if(L)
- to_chat(L, "[bicon(P)] Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)")
+ var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger)
+ PM.notify("Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)", 0)
diff --git a/code/modules/events/supply_demand_vr.dm b/code/modules/events/supply_demand_vr.dm
index 6c59145fe5..6447630c9e 100644
--- a/code/modules/events/supply_demand_vr.dm
+++ b/code/modules/events/supply_demand_vr.dm
@@ -84,17 +84,9 @@
var/datum/supply_demand_order/random = pick(required_items)
command_announcement.Announce("What happened? Accounting is here right now and they're already asking where that [random.name] is. Damn, I gotta go", my_department)
var/message = "The delivery deadline was reached with the following needs outstanding:
"
- for (var/datum/supply_demand_order/req in required_items)
+ for(var/datum/supply_demand_order/req in required_items)
message += req.describe() + "
"
- for (var/obj/machinery/computer/communications/C in machines)
- if(C.operable())
- var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( C.loc )
- P.name = "'[my_department] Mission Summary'"
- P.info = message
- P.update_space(P.info)
- P.update_icon()
- C.messagetitle.Add("[my_department] Mission Summary")
- C.messagetext.Add(P.info)
+ post_comm_message("'[my_department] Mission Summary'", message)
/**
* Event Handler for responding to the supply shuttle arriving at centcom.
*/
diff --git a/code/modules/food/food/drinks.dm b/code/modules/food/food/drinks.dm
index 044bd74491..2723df7fe2 100644
--- a/code/modules/food/food/drinks.dm
+++ b/code/modules/food/food/drinks.dm
@@ -5,8 +5,8 @@
name = "drink"
desc = "yummy"
icon = 'icons/obj/drinks.dmi'
- drop_sound = 'sound/items/drop/bottle.ogg'
- pickup_sound = 'sound/items/pickup/bottle.ogg'
+ drop_sound = 'sound/items/drop/drinkglass.ogg'
+ pickup_sound = 'sound/items/pickup/drinkglass.ogg'
icon_state = null
flags = OPENCONTAINER
amount_per_transfer_from_this = 5
@@ -234,6 +234,7 @@
trash = /obj/item/trash/coffee
center_of_mass = list("x"=15, "y"=13)
drop_sound = 'sound/items/drop/papercup.ogg'
+ pickup_sound = 'sound/items/pickup/papercup.ogg'
/obj/item/weapon/reagent_containers/food/drinks/h_chocolate/Initialize()
..()
@@ -248,6 +249,7 @@
trash = /obj/item/trash/coffee
center_of_mass = list("x"=16, "y"=14)
drop_sound = 'sound/items/drop/papercup.ogg'
+ pickup_sound = 'sound/items/pickup/papercup.ogg'
/obj/item/weapon/reagent_containers/food/drinks/greentea/Initialize()
. = ..()
@@ -262,6 +264,7 @@
trash = /obj/item/trash/coffee
center_of_mass = list("x"=16, "y"=14)
drop_sound = 'sound/items/drop/papercup.ogg'
+ pickup_sound = 'sound/items/pickup/papercup.ogg'
/obj/item/weapon/reagent_containers/food/drinks/chaitea/Initialize()
. = ..()
@@ -276,6 +279,7 @@
trash = /obj/item/trash/coffee
center_of_mass = list("x"=16, "y"=14)
drop_sound = 'sound/items/drop/papercup.ogg'
+ pickup_sound = 'sound/items/pickup/papercup.ogg'
/obj/item/weapon/reagent_containers/food/drinks/decaf/Initialize()
. = ..()
@@ -289,6 +293,7 @@
trash = /obj/item/trash/ramen
center_of_mass = list("x"=16, "y"=11)
drop_sound = 'sound/items/drop/papercup.ogg'
+ pickup_sound = 'sound/items/pickup/papercup.ogg'
/obj/item/weapon/reagent_containers/food/drinks/dry_ramen/Initialize()
..()
@@ -302,6 +307,7 @@
volume = 10
center_of_mass = list("x"=16, "y"=12)
drop_sound = 'sound/items/drop/papercup.ogg'
+ pickup_sound = 'sound/items/pickup/papercup.ogg'
/obj/item/weapon/reagent_containers/food/drinks/sillycup/Initialize()
. = ..()
diff --git a/code/modules/food/food/drinks/bottle.dm b/code/modules/food/food/drinks/bottle.dm
index b5d72d733f..a5fd76417b 100644
--- a/code/modules/food/food/drinks/bottle.dm
+++ b/code/modules/food/food/drinks/bottle.dm
@@ -19,6 +19,7 @@
if(isGlass)
unacidable = 1
drop_sound = 'sound/items/drop/bottle.ogg'
+ pickup_sound = 'sound/items/pickup/bottle.ogg'
/obj/item/weapon/reagent_containers/food/drinks/bottle/Destroy()
if(rag)
diff --git a/code/modules/food/food/drinks/drinkingglass.dm b/code/modules/food/food/drinks/drinkingglass.dm
index 260c4a7ae6..7324dc8ad8 100644
--- a/code/modules/food/food/drinks/drinkingglass.dm
+++ b/code/modules/food/food/drinks/drinkingglass.dm
@@ -8,8 +8,6 @@
volume = 30
unacidable = 1 //glass
center_of_mass = list("x"=16, "y"=10)
- drop_sound = 'sound/items/drop/drinkglass.ogg'
- pickup_sound = 'sound/items/pickup/drinkglass.ogg'
matter = list("glass" = 500)
on_reagent_change()
diff --git a/code/modules/food/food/snacks.dm b/code/modules/food/food/snacks.dm
index 65492f0109..ad30c244f2 100644
--- a/code/modules/food/food/snacks.dm
+++ b/code/modules/food/food/snacks.dm
@@ -318,6 +318,7 @@
nutriment_amt = 1
nutriment_desc = list("candy" = 1)
+
/obj/item/weapon/reagent_containers/food/snacks/candy/Initialize()
. = ..()
reagents.add_reagent("sugar", 3)
@@ -4161,6 +4162,8 @@
trash = /obj/item/trash/unajerky
filling_color = "#631212"
center_of_mass = list("x"=15, "y"=9)
+ drop_sound = 'sound/items/drop/soda.ogg'
+ pickup_sound = 'sound/items/pickup/soda.ogg'
/obj/item/weapon/reagent_containers/food/snacks/unajerky/Initialize()
. =..()
diff --git a/code/modules/food/kitchen/cooking_machines/_appliance.dm b/code/modules/food/kitchen/cooking_machines/_appliance.dm
index a0be64fff9..b2f51eacd7 100644
--- a/code/modules/food/kitchen/cooking_machines/_appliance.dm
+++ b/code/modules/food/kitchen/cooking_machines/_appliance.dm
@@ -16,7 +16,7 @@
use_power = USE_POWER_IDLE
idle_power_usage = 5 // Power used when turned on, but not processing anything
active_power_usage = 1000 // Power used when turned on and actively cooking something
-
+
var/cooking_power = 0 // Effectiveness/speed at cooking
var/cooking_coeff = 0 // Optimal power * proximity to optimal temp; used to calc. cooking power.
var/heating_power = 1000 // Effectiveness at heating up; not used for mixers, should be equal to active_power_usage
@@ -44,9 +44,9 @@
/obj/machinery/appliance/Initialize()
. = ..()
-
+
default_apply_parts()
-
+
if(output_options.len)
verbs += /obj/machinery/appliance/proc/choose_output
@@ -206,7 +206,7 @@
//Handles all validity checking and error messages for inserting things
/obj/machinery/appliance/proc/can_insert(var/obj/item/I, var/mob/user)
- if (istype(I, /obj/item/weapon/gripper))
+ if(istype(I.loc, /mob/living/silicon))
return 0
else if (istype(I.loc, /obj/item/rig_module))
return 0
@@ -266,26 +266,52 @@
to_chat(user, "\The [src] is not working.")
return FALSE
- var/result = can_insert(I, user)
- if(!result)
- if(!(default_deconstruction_screwdriver(user, I)))
- default_part_replacement(user, I)
- return FALSE
+ var/obj/item/ToCook = I
- if(result == 2)
- var/obj/item/weapon/grab/G = I
- if (G && istype(G) && G.affecting)
- cook_mob(G.affecting, user)
- return FALSE
+ if(istype(I, /obj/item/weapon/gripper))
+ var/obj/item/weapon/gripper/GR = I
+ var/obj/item/Wrap = GR.wrapped
+ if(Wrap)
+ Wrap.loc = get_turf(src)
+ var/result = can_insert(Wrap, user)
+ if(!result)
+ Wrap.forceMove(GR)
+ if(!(default_deconstruction_screwdriver(user, I)))
+ default_part_replacement(user, I)
+ return
+
+ if(QDELETED(GR.wrapped))
+ GR.wrapped = null
+
+ if(GR?.wrapped.loc != src)
+ GR.drop_item_nm()
+
+ ToCook = Wrap
+ else
+ attack_hand(user)
+ return
+
+ else
+ var/result = can_insert(I, user)
+ if(!result)
+ if(!(default_deconstruction_screwdriver(user, I)))
+ default_part_replacement(user, I)
+ return
+
+ if(result == 2)
+ var/obj/item/weapon/grab/G = I
+ if (G && istype(G) && G.affecting)
+ cook_mob(G.affecting, user)
+ return
//From here we can start cooking food
- . = add_content(I, user)
+ add_content(ToCook, user)
update_icon()
//Override for container mechanics
/obj/machinery/appliance/proc/add_content(var/obj/item/I, var/mob/user)
- if(!user.unEquip(I))
- return FALSE
+ if(!user.unEquip(I) && !isturf(I.loc))
+ return
var/datum/cooking_item/CI = has_space(I)
if (istype(I, /obj/item/weapon/reagent_containers/cooking_container) && CI == 1)
@@ -458,7 +484,7 @@
//Final step. Cook function just cooks batter for now.
for (var/obj/item/weapon/reagent_containers/food/snacks/S in CI.container)
S.cook()
-
+
//Combination cooking involves combining the names and reagents of ingredients into a predefined output object
//The ingredients represent flavours or fillings. EG: donut pizza, cheese bread
@@ -566,7 +592,7 @@
smoke.attach(src)
smoke.set_up(10, 0, get_turf(src), 300)
smoke.start()
-
+
// Set off fire alarms!
var/obj/machinery/firealarm/FA = locate() in get_area(src)
if(FA)
diff --git a/code/modules/food/kitchen/cooking_machines/container.dm b/code/modules/food/kitchen/cooking_machines/container.dm
index d650a2266e..408835a4da 100644
--- a/code/modules/food/kitchen/cooking_machines/container.dm
+++ b/code/modules/food/kitchen/cooking_machines/container.dm
@@ -32,13 +32,26 @@
/obj/item/weapon/reagent_containers/cooking_container/attackby(var/obj/item/I as obj, var/mob/user as mob)
+ if(istype(I, /obj/item/weapon/gripper))
+ var/obj/item/weapon/gripper/GR = I
+ if(GR.wrapped)
+ GR.wrapped.forceMove(get_turf(src))
+ attackby(GR.wrapped, user)
+ if(QDELETED(GR.wrapped))
+ GR.wrapped = null
+
+ if(GR?.wrapped.loc != src)
+ GR.wrapped = null
+
+ return
+
for (var/possible_type in insertable)
if (istype(I, possible_type))
if (!can_fit(I))
to_chat(user, "There's no more space in the [src] for that!")
return 0
- if(!user.unEquip(I))
+ if(!user.unEquip(I) && !isturf(I.loc))
return
I.forceMove(src)
to_chat(user, "You put the [I] into the [src].")
@@ -152,7 +165,7 @@
/obj/item/weapon/reagent_containers/cooking_container/oven/Initialize()
. = ..()
-
+
// We add to the insertable list specifically for the oven trays, to allow specialty cakes.
insertable += list(
/obj/item/clothing/head/cakehat, // This is because we want to allow birthday cakes to be makeable.
@@ -164,7 +177,7 @@
shortname = "basket"
desc = "Put ingredients in this; designed for use with a deep fryer. Warranty void if used incorrectly. Alt click to remove contents."
icon_state = "basket"
-
+
/obj/item/weapon/reagent_containers/cooking_container/grill
name = "grill rack"
shortname = "rack"
diff --git a/code/modules/food/recipes_oven.dm b/code/modules/food/recipes_oven.dm
index 7a477cf943..6524763a96 100644
--- a/code/modules/food/recipes_oven.dm
+++ b/code/modules/food/recipes_oven.dm
@@ -81,7 +81,7 @@
/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough
)
result = /obj/item/weapon/reagent_containers/food/snacks/flatbread
-
+
/datum/recipe/tortilla
appliance = OVEN
reagents = list("flour" = 5)
@@ -408,7 +408,7 @@
/obj/item/weapon/reagent_containers/food/snacks/cheesewedge
)
result = /obj/item/weapon/reagent_containers/food/snacks/sliceable/cheesecake
-
+
/datum/recipe/cake/peanut
fruit = list("peanut" = 3)
reagents = list("milk" = 5, "flour" = 10, "sugar" = 5, "egg" = 6, "peanutbutter" = 5)
@@ -458,7 +458,7 @@
/datum/recipe/pancakes
appliance = OVEN
- fruit = list("blueberries" = 2)
+ fruit = list("berries" = 2)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough,
/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough
diff --git a/code/modules/gamemaster/event2/events/everyone/pda_spam.dm b/code/modules/gamemaster/event2/events/everyone/pda_spam.dm
index b56687283c..c6a1532d0e 100644
--- a/code/modules/gamemaster/event2/events/everyone/pda_spam.dm
+++ b/code/modules/gamemaster/event2/events/everyone/pda_spam.dm
@@ -35,7 +35,11 @@
var/list/viables = list()
for(var/obj/item/device/pda/check_pda in sortAtom(PDAs))
- if(!check_pda.owner || check_pda.toff || check_pda.hidden || check_pda.spam_proof)
+ if (!check_pda.owner || check_pda == src || check_pda.hidden)
+ continue
+
+ var/datum/data/pda/app/messenger/M = check_pda.find_program(/datum/data/pda/app/messenger)
+ if(!M || M.toff)
continue
viables += check_pda
@@ -93,7 +97,7 @@
message = pick("Luxury watches for Blowout sale prices!",\
"Watches, Jewelry & Accessories, Bags & Wallets !",\
"Deposit 100$ and get 300$ totally free!",\
- " 100K NT.|WOWGOLD õnly $89 ",\
+ " 100K NT.|WOWGOLD �nly $89 ",\
"We have been filed with a complaint from one of your customers in respect of their business relations with you.",\
"We kindly ask you to open the COMPLAINT REPORT (attached) to reply on this complaint..")
if(4)
@@ -127,7 +131,8 @@
/datum/event2/event/pda_spam/proc/send_spam(obj/item/device/pda/P, sender, message)
last_spam_time = world.time
- P.spam_message(sender, message)
+ var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger)
+ PM.notify("Message from [sender] (Unknown / spam?), \"[message]\" (Unable to Reply)", 0)
if(spam_debug)
log_debug("PDA Spam event sent spam to \the [P].")
diff --git a/code/modules/gamemaster/event2/events/security/prison_break.dm b/code/modules/gamemaster/event2/events/security/prison_break.dm
index ec07302f13..9cf3e9aac6 100644
--- a/code/modules/gamemaster/event2/events/security/prison_break.dm
+++ b/code/modules/gamemaster/event2/events/security/prison_break.dm
@@ -218,7 +218,7 @@
/datum/event2/event/prison_break/start()
for(var/area/A in areas_to_break)
spawn(0) // So we don't block the ticker.
- A.prison_break(open_blast_doors = !ignore_blast_doors)
+ A.prison_break(TRUE, TRUE, !ignore_blast_doors) // Naming `open_blast_doors` causes mysterious runtimes.
// There's between 40 seconds and one minute before the whole station knows.
// If there's a baddie engineer, they can choose to keep their early announcement to themselves and get a minute to exploit it.
diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm
deleted file mode 100644
index cbdeaca55c..0000000000
--- a/code/modules/hydroponics/seed_datums.dm
+++ /dev/null
@@ -1,1544 +0,0 @@
-// Chili plants/variants.
-/datum/seed/chili
- name = "chili"
- seed_name = "chili"
- display_name = "chili plants"
- kitchen_tag = "chili"
- chems = list("capsaicin" = list(3,5), "nutriment" = list(1,25))
- mutants = list("icechili")
-
-/datum/seed/chili/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,20)
- set_trait(TRAIT_PRODUCT_ICON,"chili")
- set_trait(TRAIT_PRODUCT_COLOUR,"#ED3300")
- set_trait(TRAIT_PLANT_ICON,"bush2")
- set_trait(TRAIT_IDEAL_HEAT, 298)
- set_trait(TRAIT_IDEAL_LIGHT, 7)
-
-/datum/seed/chili/ice
- name = "icechili"
- seed_name = "ice pepper"
- display_name = "ice-pepper plants"
- kitchen_tag = "icechili"
- mutants = null
- chems = list("frostoil" = list(3,5), "nutriment" = list(1,50))
-
-/datum/seed/chili/ice/New()
- ..()
- set_trait(TRAIT_MATURATION,4)
- set_trait(TRAIT_PRODUCTION,4)
- set_trait(TRAIT_PRODUCT_COLOUR,"#00EDC6")
-
-// Berry plants/variants.
-/datum/seed/berry
- name = "berries"
- seed_name = "berry"
- display_name = "berry bush"
- kitchen_tag = "berries"
- mutants = list("glowberries","poisonberries")
- chems = list("nutriment" = list(1,10), "berryjuice" = list(10,10))
-
-/datum/seed/berry/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_JUICY,1)
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"berry")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FA1616")
- set_trait(TRAIT_PLANT_ICON,"bush")
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/berry/glow
- name = "glowberries"
- seed_name = "glowberry"
- display_name = "glowberry bush"
- mutants = null
- chems = list("nutriment" = list(1,10), "uranium" = list(3,5))
-
-/datum/seed/berry/glow/New()
- ..()
- set_trait(TRAIT_SPREAD,1)
- set_trait(TRAIT_BIOLUM,1)
- set_trait(TRAIT_BIOLUM_COLOUR,"#006622")
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_COLOUR,"#c9fa16")
- set_trait(TRAIT_WATER_CONSUMPTION, 3)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25)
-
-/datum/seed/berry/poison
- name = "poisonberries"
- seed_name = "poison berry"
- kitchen_tag = "poisonberries"
- display_name = "poison berry bush"
- mutants = list("deathberries")
- chems = list("nutriment" = list(1), "toxin" = list(3,5), "poisonberryjuice" = list(10,5))
-
-/datum/seed/berry/poison/New()
- ..()
- set_trait(TRAIT_PRODUCT_COLOUR,"#6DC961")
- set_trait(TRAIT_WATER_CONSUMPTION, 3)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25)
-
-/datum/seed/berry/poison/death
- name = "deathberries"
- seed_name = "death berry"
- display_name = "death berry bush"
- mutants = null
- chems = list("nutriment" = list(1), "toxin" = list(3,3), "lexorin" = list(1,5))
-
-/datum/seed/berry/poison/death/New()
- ..()
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,50)
- set_trait(TRAIT_PRODUCT_COLOUR,"#7A5454")
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35)
-
-// Nettles/variants.
-/datum/seed/nettle
- name = "nettle"
- seed_name = "nettle"
- display_name = "nettles"
- mutants = list("deathnettle")
- chems = list("nutriment" = list(1,50), "sacid" = list(0,1))
- kitchen_tag = "nettle"
-
-/datum/seed/nettle/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_STINGS,1)
- set_trait(TRAIT_PLANT_ICON,"bush5")
- set_trait(TRAIT_PRODUCT_ICON,"nettles")
- set_trait(TRAIT_PRODUCT_COLOUR,"#728A54")
-
-/datum/seed/nettle/death
- name = "deathnettle"
- seed_name = "death nettle"
- display_name = "death nettles"
- kitchen_tag = "deathnettle"
- mutants = null
- chems = list("nutriment" = list(1,50), "pacid" = list(0,1))
-
-/datum/seed/nettle/death/New()
- ..()
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_PRODUCT_COLOUR,"#8C5030")
- set_trait(TRAIT_PLANT_COLOUR,"#634941")
-
-//Tomatoes/variants.
-/datum/seed/tomato
- name = "tomato"
- seed_name = "tomato"
- display_name = "tomato plant"
- mutants = list("bluetomato","bloodtomato")
- chems = list("nutriment" = list(1,10), "tomatojuice" = list(10,10))
- kitchen_tag = "tomato"
-
-/datum/seed/tomato/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_JUICY,1)
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"tomato")
- set_trait(TRAIT_PRODUCT_COLOUR,"#D10000")
- set_trait(TRAIT_PLANT_ICON,"bush3")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25)
-
-/datum/seed/tomato/blood
- name = "bloodtomato"
- seed_name = "blood tomato"
- display_name = "blood tomato plant"
- mutants = list("killertomato")
- chems = list("nutriment" = list(1,10), "blood" = list(1,5))
- splat_type = /obj/effect/decal/cleanable/blood/splatter
-
-/datum/seed/tomato/blood/New()
- ..()
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_PRODUCT_COLOUR,"#FF0000")
-
-/datum/seed/tomato/killer
- name = "killertomato"
- seed_name = "killer tomato"
- display_name = "killer tomato plant"
- mutants = null
- can_self_harvest = 1
- has_mob_product = /mob/living/simple_mob/tomato
-
-/datum/seed/tomato/killer/New()
- ..()
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_PRODUCT_COLOUR,"#A86747")
-
-/datum/seed/tomato/blue
- name = "bluetomato"
- seed_name = "blue tomato"
- display_name = "blue tomato plant"
- mutants = list("bluespacetomato")
- chems = list("nutriment" = list(1,20), "lube" = list(1,5))
-
-/datum/seed/tomato/blue/New()
- ..()
- set_trait(TRAIT_PRODUCT_COLOUR,"#4D86E8")
- set_trait(TRAIT_PLANT_COLOUR,"#070AAD")
-
-/datum/seed/tomato/blue/teleport
- name = "bluespacetomato"
- seed_name = "bluespace tomato"
- display_name = "bluespace tomato plant"
- mutants = null
- chems = list("nutriment" = list(1,20), "singulo" = list(10,5))
-
-/datum/seed/tomato/blue/teleport/New()
- ..()
- set_trait(TRAIT_TELEPORTING,1)
- set_trait(TRAIT_PRODUCT_COLOUR,"#00E5FF")
- set_trait(TRAIT_BIOLUM,1)
- set_trait(TRAIT_BIOLUM_COLOUR,"#4DA4A8")
-
-//Eggplants/varieties.
-/datum/seed/eggplant
- name = "eggplant"
- seed_name = "eggplant"
- display_name = "eggplants"
- kitchen_tag = "eggplant"
- mutants = list("egg-plant")
- chems = list("nutriment" = list(1,10))
-
-/datum/seed/eggplant/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,20)
- set_trait(TRAIT_PRODUCT_ICON,"eggplant")
- set_trait(TRAIT_PRODUCT_COLOUR,"#892694")
- set_trait(TRAIT_PLANT_ICON,"bush4")
- set_trait(TRAIT_IDEAL_HEAT, 298)
- set_trait(TRAIT_IDEAL_LIGHT, 7)
-
-// Return of Eggy. Just makes purple eggs. If the reagents are separated from the egg production by xenobotany or RNG, it's still an Egg plant.
-/datum/seed/eggplant/egg
- name = "egg-plant"
- seed_name = "egg-plant"
- display_name = "egg-plants"
- kitchen_tag = "egg-plant"
- mutants = null
- chems = list("nutriment" = list(1,5), "egg" = list(3,12))
- has_item_product = /obj/item/weapon/reagent_containers/food/snacks/egg/purple
-
-//Apples/varieties.
-/datum/seed/apple
- name = "apple"
- seed_name = "apple"
- display_name = "apple tree"
- kitchen_tag = "apple"
- mutants = list("poisonapple","goldapple")
- chems = list("nutriment" = list(1,10),"applejuice" = list(10,20))
-
-/datum/seed/apple/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,5)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"apple")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FF540A")
- set_trait(TRAIT_PLANT_ICON,"tree2")
- set_trait(TRAIT_FLESH_COLOUR,"#E8E39B")
- set_trait(TRAIT_IDEAL_LIGHT, 4)
-
-/datum/seed/apple/poison
- name = "poisonapple"
- mutants = null
- chems = list("cyanide" = list(1,5))
-
-/datum/seed/apple/gold
- name = "goldapple"
- seed_name = "golden apple"
- display_name = "gold apple tree"
- kitchen_tag = "goldapple"
- mutants = null
- chems = list("nutriment" = list(1,10), "gold" = list(1,5))
-
-/datum/seed/apple/gold/New()
- ..()
- set_trait(TRAIT_MATURATION,10)
- set_trait(TRAIT_PRODUCTION,10)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_PRODUCT_COLOUR,"#FFDD00")
- set_trait(TRAIT_PLANT_COLOUR,"#D6B44D")
-
-/datum/seed/apple/sif
- name = "sifbulb"
- seed_name = "sivian tree"
- display_name = "sivian tree"
- kitchen_tag = "apple"
- chems = list("nutriment" = list(1,5),"sifsap" = list(10,20))
-
-/datum/seed/apple/sif/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,3)
- set_trait(TRAIT_PRODUCTION,10)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,12)
- set_trait(TRAIT_PRODUCT_ICON,"alien3")
- set_trait(TRAIT_PRODUCT_COLOUR,"#0720c3")
- set_trait(TRAIT_PLANT_ICON,"tree5")
- set_trait(TRAIT_FLESH_COLOUR,"#05157d")
- set_trait(TRAIT_IDEAL_LIGHT, 1)
-
-//Ambrosia/varieties.
-/datum/seed/ambrosia
- name = "ambrosia"
- seed_name = "ambrosia vulgaris"
- display_name = "ambrosia vulgaris"
- kitchen_tag = "ambrosia"
- mutants = list("ambrosiadeus")
- chems = list("nutriment" = list(1), "space_drugs" = list(1,8), "kelotane" = list(1,8,1), "bicaridine" = list(1,10,1), "toxin" = list(1,10))
-
-/datum/seed/ambrosia/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,6)
- set_trait(TRAIT_POTENCY,5)
- set_trait(TRAIT_PRODUCT_ICON,"ambrosia")
- set_trait(TRAIT_PRODUCT_COLOUR,"#9FAD55")
- set_trait(TRAIT_PLANT_ICON,"ambrosia")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
-
-/datum/seed/ambrosia/deus
- name = "ambrosiadeus"
- seed_name = "ambrosia deus"
- display_name = "ambrosia deus"
- kitchen_tag = "ambrosiadeus"
- mutants = list("ambrosiainfernus")
- chems = list("nutriment" = list(1), "bicaridine" = list(1,8), "synaptizine" = list(1,8,1), "hyperzine" = list(1,10,1), "space_drugs" = list(1,10))
-
-/datum/seed/ambrosia/deus/New()
- ..()
- set_trait(TRAIT_PRODUCT_COLOUR,"#A3F0AD")
- set_trait(TRAIT_PLANT_COLOUR,"#2A9C61")
-
-/datum/seed/ambrosia/infernus
- name = "ambrosiainfernus"
- seed_name = "ambrosia infernus"
- display_name = "ambrosia infernus"
- kitchen_tag = "ambrosiainfernus"
- mutants = null
- chems = list("nutriment" = list(1,3), "oxycodone" = list(1,8), "impedrezene" = list(1,10), "mindbreaker" = list(1,10))
-
-/datum/seed/ambrosia/infernus/New()
- ..()
- set_trait(TRAIT_PRODUCT_COLOUR,"#dc143c")
- set_trait(TRAIT_PLANT_COLOUR,"#b22222")
-
-//Mushrooms/varieties.
-/datum/seed/mushroom
- name = "mushrooms"
- seed_name = "chanterelle"
- seed_noun = "spores"
- display_name = "chanterelle mushrooms"
- mutants = list("reishi","amanita","plumphelmet")
- chems = list("nutriment" = list(1,25))
- splat_type = /obj/effect/plant
- kitchen_tag = "mushroom"
-
-/datum/seed/mushroom/New()
- ..()
- set_trait(TRAIT_MATURATION,7)
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,5)
- set_trait(TRAIT_POTENCY,1)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom4")
- set_trait(TRAIT_PRODUCT_COLOUR,"#DBDA72")
- set_trait(TRAIT_PLANT_COLOUR,"#D9C94E")
- set_trait(TRAIT_PLANT_ICON,"mushroom")
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
- set_trait(TRAIT_IDEAL_HEAT, 288)
- set_trait(TRAIT_LIGHT_TOLERANCE, 6)
-
-/datum/seed/mushroom/mold
- name = "mold"
- seed_name = "brown mold"
- display_name = "brown mold"
- mutants = null
-
-/datum/seed/mushroom/mold/New()
- ..()
- set_trait(TRAIT_SPREAD,1)
- set_trait(TRAIT_MATURATION,10)
- set_trait(TRAIT_YIELD,-1)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom5")
- set_trait(TRAIT_PRODUCT_COLOUR,"#7A5F20")
- set_trait(TRAIT_PLANT_COLOUR,"#7A5F20")
- set_trait(TRAIT_PLANT_ICON,"mushroom9")
-
-/datum/seed/mushroom/plump
- name = "plumphelmet"
- seed_name = "plump helmet"
- display_name = "plump helmet mushrooms"
- mutants = list("walkingmushroom","towercap")
- chems = list("nutriment" = list(2,10))
- kitchen_tag = "plumphelmet"
-
-/datum/seed/mushroom/plump/New()
- ..()
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,0)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom10")
- set_trait(TRAIT_PRODUCT_COLOUR,"#B57BB0")
- set_trait(TRAIT_PLANT_COLOUR,"#9E4F9D")
- set_trait(TRAIT_PLANT_ICON,"mushroom2")
-
-/datum/seed/mushroom/hallucinogenic
- name = "reishi"
- seed_name = "reishi"
- display_name = "reishi"
- mutants = list("libertycap","glowshroom")
- chems = list("nutriment" = list(1,50), "psilocybin" = list(3,5))
-
-/datum/seed/mushroom/hallucinogenic/New()
- ..()
- set_trait(TRAIT_MATURATION,10)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,15)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom11")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FFB70F")
- set_trait(TRAIT_PLANT_COLOUR,"#F58A18")
- set_trait(TRAIT_PLANT_ICON,"mushroom6")
-
-/datum/seed/mushroom/hallucinogenic/strong
- name = "libertycap"
- seed_name = "liberty cap"
- display_name = "liberty cap mushrooms"
- mutants = null
- chems = list("nutriment" = list(1), "stoxin" = list(3,3), "space_drugs" = list(1,25))
-
-/datum/seed/mushroom/hallucinogenic/strong/New()
- ..()
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_POTENCY,15)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom8")
- set_trait(TRAIT_PRODUCT_COLOUR,"#F2E550")
- set_trait(TRAIT_PLANT_COLOUR,"#D1CA82")
- set_trait(TRAIT_PLANT_ICON,"mushroom3")
-
-/datum/seed/mushroom/poison
- name = "amanita"
- seed_name = "fly amanita"
- display_name = "fly amanita mushrooms"
- mutants = list("destroyingangel","plastic")
- chems = list("nutriment" = list(1), "amatoxin" = list(3,3), "psilocybin" = list(1,25))
-
-/datum/seed/mushroom/poison/New()
- ..()
- set_trait(TRAIT_MATURATION,10)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FF4545")
- set_trait(TRAIT_PLANT_COLOUR,"#E0DDBA")
- set_trait(TRAIT_PLANT_ICON,"mushroom4")
-
-/datum/seed/mushroom/poison/death
- name = "destroyingangel"
- seed_name = "destroying angel"
- display_name = "destroying angel mushrooms"
- mutants = null
- chems = list("nutriment" = list(1,50), "amatoxin" = list(13,3), "psilocybin" = list(1,25))
-
-/datum/seed/mushroom/poison/death/New()
- ..()
- set_trait(TRAIT_MATURATION,12)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,35)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom3")
- set_trait(TRAIT_PRODUCT_COLOUR,"#EDE8EA")
- set_trait(TRAIT_PLANT_COLOUR,"#E6D8DD")
- set_trait(TRAIT_PLANT_ICON,"mushroom5")
-
-/datum/seed/mushroom/towercap
- name = "towercap"
- seed_name = "tower cap"
- display_name = "tower caps"
- chems = list("woodpulp" = list(10,1))
- mutants = null
- has_item_product = /obj/item/stack/material/log
-
-/datum/seed/mushroom/towercap/New()
- ..()
- set_trait(TRAIT_MATURATION,15)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom7")
- set_trait(TRAIT_PRODUCT_COLOUR,"#79A36D")
- set_trait(TRAIT_PLANT_COLOUR,"#857F41")
- set_trait(TRAIT_PLANT_ICON,"mushroom8")
-
-/datum/seed/mushroom/glowshroom
- name = "glowshroom"
- seed_name = "glowshroom"
- display_name = "glowshrooms"
- mutants = null
- chems = list("radium" = list(1,20))
-
-/datum/seed/mushroom/glowshroom/New()
- ..()
- set_trait(TRAIT_SPREAD,1)
- set_trait(TRAIT_MATURATION,15)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,30)
- set_trait(TRAIT_BIOLUM,1)
- set_trait(TRAIT_BIOLUM_COLOUR,"#006622")
- set_trait(TRAIT_PRODUCT_ICON,"mushroom2")
- set_trait(TRAIT_PRODUCT_COLOUR,"#DDFAB6")
- set_trait(TRAIT_PLANT_COLOUR,"#EFFF8A")
- set_trait(TRAIT_PLANT_ICON,"mushroom7")
-
-/datum/seed/mushroom/plastic
- name = "plastic"
- seed_name = "plastellium"
- display_name = "plastellium"
- mutants = null
- chems = list("plasticide" = list(1,10))
-
-/datum/seed/mushroom/plastic/New()
- ..()
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,6)
- set_trait(TRAIT_POTENCY,20)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom6")
- set_trait(TRAIT_PRODUCT_COLOUR,"#E6E6E6")
- set_trait(TRAIT_PLANT_COLOUR,"#E6E6E6")
- set_trait(TRAIT_PLANT_ICON,"mushroom10")
-
-/datum/seed/mushroom/spore
- name = "sporeshroom"
- seed_name = "corpellian"
- display_name = "corpellian"
- mutants = null
- chems = list("serotrotium" = list(5,10), "mold" = list(1,10))
-
-/datum/seed/mushroom/spore/New()
- ..()
- set_trait(TRAIT_MATURATION,15)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,20)
- set_trait(TRAIT_PRODUCT_ICON,"mushroom5")
- set_trait(TRAIT_PRODUCT_COLOUR,"#e29cd2")
- set_trait(TRAIT_PLANT_COLOUR,"#f8e6f4")
- set_trait(TRAIT_PLANT_ICON,"mushroom9")
- set_trait(TRAIT_SPORING, TRUE)
-
-//Flowers/varieties
-/datum/seed/flower
- name = "harebells"
- seed_name = "harebell"
- display_name = "harebells"
- kitchen_tag = "harebell"
- chems = list("nutriment" = list(1,20))
-
-/datum/seed/flower/New()
- ..()
- set_trait(TRAIT_MATURATION,7)
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_PRODUCT_ICON,"flower5")
- set_trait(TRAIT_PRODUCT_COLOUR,"#C492D6")
- set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E")
- set_trait(TRAIT_PLANT_ICON,"flower")
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/flower/poppy
- name = "poppies"
- seed_name = "poppy"
- display_name = "poppies"
- kitchen_tag = "poppy"
- chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10))
-
-/datum/seed/flower/poppy/New()
- ..()
- set_trait(TRAIT_POTENCY,20)
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,6)
- set_trait(TRAIT_PRODUCT_ICON,"flower3")
- set_trait(TRAIT_PRODUCT_COLOUR,"#B33715")
- set_trait(TRAIT_PLANT_ICON,"flower3")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
- set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/flower/sunflower
- name = "sunflowers"
- seed_name = "sunflower"
- display_name = "sunflowers"
- kitchen_tag = "sunflower"
-
-/datum/seed/flower/sunflower/New()
- ..()
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCT_ICON,"flower2")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FFF700")
- set_trait(TRAIT_PLANT_ICON,"flower2")
- set_trait(TRAIT_IDEAL_LIGHT, 7)
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/flower/lavender
- name = "lavender"
- seed_name = "lavender"
- display_name = "lavender"
- kitchen_tag = "lavender"
- chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10))
-
-/datum/seed/flower/lavender/New()
- ..()
- set_trait(TRAIT_MATURATION,7)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,5)
- set_trait(TRAIT_PRODUCT_ICON,"flower6")
- set_trait(TRAIT_PRODUCT_COLOUR,"#B57EDC")
- set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E")
- set_trait(TRAIT_PLANT_ICON,"flower4")
- set_trait(TRAIT_IDEAL_LIGHT, 7)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.05)
- set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
-
-/datum/seed/flower/rose
- name = "rose"
- seed_name = "rose"
- display_name = "rose"
- kitchen_tag = "rose"
- mutants = list("bloodrose")
- chems = list("nutriment" = list(1,5), "stoxin" = list(0,2))
-
-/datum/seed/flower/rose/New()
- ..()
- set_trait(TRAIT_MATURATION,7)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_PRODUCT_ICON,"flowers")
- set_trait(TRAIT_PRODUCT_COLOUR,"#ce0e0e")
- set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E")
- set_trait(TRAIT_PLANT_ICON,"bush5")
- set_trait(TRAIT_IDEAL_LIGHT, 7)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.1)
- set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
- set_trait(TRAIT_STINGS,1)
-
-/datum/seed/flower/rose/blood
- name = "bloodrose"
- display_name = "bleeding rose"
- mutants = null
- chems = list("nutriment" = list(1,5), "stoxin" = list(1,5), "blood" = list(0,2))
-
-/datum/seed/flower/rose/blood/New()
- ..()
- set_trait(TRAIT_IDEAL_LIGHT, 1)
- set_trait(TRAIT_PLANT_COLOUR,"#5e0303")
- set_trait(TRAIT_CARNIVOROUS,1)
-
-//Grapes/varieties
-/datum/seed/grapes
- name = "grapes"
- seed_name = "grape"
- display_name = "grapevines"
- kitchen_tag = "grapes"
- mutants = list("greengrapes")
- chems = list("nutriment" = list(1,10), "sugar" = list(1,5), "grapejuice" = list(10,10))
-
-/datum/seed/grapes/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,3)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"grapes")
- set_trait(TRAIT_PRODUCT_COLOUR,"#BB6AC4")
- set_trait(TRAIT_PLANT_COLOUR,"#378F2E")
- set_trait(TRAIT_PLANT_ICON,"vine")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/grapes/green
- name = "greengrapes"
- seed_name = "green grape"
- display_name = "green grapevines"
- mutants = null
- chems = list("nutriment" = list(1,10), "kelotane" = list(3,5), "grapejuice" = list(10,10))
-
-/datum/seed/grapes/green/New()
- ..()
- set_trait(TRAIT_PRODUCT_COLOUR,"42ed2f")
-
-// Lettuce/varieties.
-/datum/seed/lettuce
- name = "lettuce"
- seed_name = "lettuce"
- display_name = "lettuce"
- kitchen_tag = "cabbage"
- chems = list("nutriment" = list(1,15))
-
-/datum/seed/lettuce/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,4)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,6)
- set_trait(TRAIT_POTENCY,8)
- set_trait(TRAIT_PRODUCT_ICON,"lettuce")
- set_trait(TRAIT_PRODUCT_COLOUR,"#A8D0A7")
- set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B")
- set_trait(TRAIT_PLANT_ICON,"vine2")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
- set_trait(TRAIT_WATER_CONSUMPTION, 8)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.13)
-
-/datum/seed/lettuce/ice
- name = "siflettuce"
- seed_name = "glacial lettuce"
- display_name = "glacial lettuce"
- kitchen_tag = "icelettuce"
- chems = list("nutriment" = list(1,5), "paracetamol" = list(0,2))
-
-/datum/seed/lettuce/ice/New()
- ..()
- set_trait(TRAIT_ALTER_TEMP, -5)
- set_trait(TRAIT_PRODUCT_COLOUR,"#9ABCC9")
-
-//Wabback / varieties.
-/datum/seed/wabback
- name = "whitewabback"
- seed_name = "white wabback"
- seed_noun = "nodes"
- display_name = "white wabback"
- chems = list("nutriment" = list(1,10), "protein" = list(1,5), "enzyme" = list(0,3))
- kitchen_tag = "wabback"
- mutants = list("blackwabback","wildwabback")
- has_item_product = /obj/item/stack/material/cloth
-
-/datum/seed/wabback/New()
- ..()
- set_trait(TRAIT_IDEAL_LIGHT, 5)
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_PRODUCTION,3)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,5)
- set_trait(TRAIT_PRODUCT_ICON,"carrot2")
- set_trait(TRAIT_PRODUCT_COLOUR,"#E6EDFA")
- set_trait(TRAIT_PLANT_ICON,"chute")
- set_trait(TRAIT_PLANT_COLOUR, "#0650ce")
- set_trait(TRAIT_WATER_CONSUMPTION, 10)
- set_trait(TRAIT_ALTER_TEMP, -1)
- set_trait(TRAIT_CARNIVOROUS,1)
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_SPREAD,1)
-
-/datum/seed/wabback/vine
- name = "blackwabback"
- seed_name = "black wabback"
- display_name = "black wabback"
- mutants = null
- chems = list("nutriment" = list(1,3), "protein" = list(1,10), "serotrotium_v" = list(0,1))
-
-/datum/seed/wabback/vine/New()
- ..()
- set_trait(TRAIT_PRODUCT_COLOUR,"#2E2F32")
- set_trait(TRAIT_CARNIVOROUS,2)
-
-/datum/seed/wabback/wild
- name = "wildwabback"
- seed_name = "wild wabback"
- display_name = "wild wabback"
- mutants = list("whitewabback")
- has_item_product = null
- chems = list("nutriment" = list(1,15), "protein" = list(0,2), "enzyme" = list(0,1))
-
-/datum/seed/wabback/wild/New()
- ..()
- set_trait(TRAIT_IDEAL_LIGHT, 3)
- set_trait(TRAIT_WATER_CONSUMPTION, 7)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.1)
- set_trait(TRAIT_YIELD,5)
-
-//Everything else
-/datum/seed/peanuts
- name = "peanut"
- seed_name = "peanut"
- display_name = "peanut vines"
- kitchen_tag = "peanut"
- chems = list("nutriment" = list(1,10), "peanutoil" = list(3,10))
-
-/datum/seed/peanuts/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,6)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"nuts")
- set_trait(TRAIT_PRODUCT_COLOUR,"#C4AE7A")
- set_trait(TRAIT_PLANT_ICON,"bush2")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
-
-/datum/seed/vanilla
- name = "vanilla"
- seed_name = "vanilla"
- display_name = "vanilla"
- kitchen_tag = "vanilla"
- chems = list("nutriment" = list(1,10), "vanilla" = list(2,8), "sugar" = list(1, 4))
-
-/datum/seed/vanilla/New()
- ..()
- set_trait(TRAIT_MATURATION,7)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_PRODUCT_ICON,"chili")
- set_trait(TRAIT_PRODUCT_COLOUR,"#B57EDC")
- set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E")
- set_trait(TRAIT_PLANT_ICON,"bush5")
- set_trait(TRAIT_IDEAL_LIGHT, 8)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.3)
- set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
-
-/datum/seed/cabbage
- name = "cabbage"
- seed_name = "cabbage"
- display_name = "cabbages"
- kitchen_tag = "cabbage"
- chems = list("nutriment" = list(1,10))
-
-/datum/seed/cabbage/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,3)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"cabbage")
- set_trait(TRAIT_PRODUCT_COLOUR,"#84BD82")
- set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B")
- set_trait(TRAIT_PLANT_ICON,"vine2")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/banana
- name = "banana"
- seed_name = "banana"
- display_name = "banana tree"
- kitchen_tag = "banana"
- chems = list("banana" = list(10,10))
- trash_type = /obj/item/weapon/bananapeel
-
-/datum/seed/banana/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_PRODUCT_ICON,"bananas")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FFEC1F")
- set_trait(TRAIT_PLANT_COLOUR,"#69AD50")
- set_trait(TRAIT_PLANT_ICON,"tree4")
- set_trait(TRAIT_IDEAL_HEAT, 298)
- set_trait(TRAIT_IDEAL_LIGHT, 7)
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/corn
- name = "corn"
- seed_name = "corn"
- display_name = "ears of corn"
- kitchen_tag = "corn"
- chems = list("nutriment" = list(1,10), "cornoil" = list(3,15))
- trash_type = /obj/item/weapon/corncob
-
-/datum/seed/corn/New()
- ..()
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,20)
- set_trait(TRAIT_PRODUCT_ICON,"corn")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B")
- set_trait(TRAIT_PLANT_COLOUR,"#87C969")
- set_trait(TRAIT_PLANT_ICON,"corn")
- set_trait(TRAIT_IDEAL_HEAT, 298)
- set_trait(TRAIT_IDEAL_LIGHT, 6)
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/potato
- name = "potato"
- seed_name = "potato"
- display_name = "potatoes"
- kitchen_tag = "potato"
- chems = list("nutriment" = list(1,10), "potatojuice" = list(10,10))
-
-/datum/seed/potato/New()
- ..()
- set_trait(TRAIT_PRODUCES_POWER,1)
- set_trait(TRAIT_MATURATION,10)
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"potato")
- set_trait(TRAIT_PRODUCT_COLOUR,"#D4CAB4")
- set_trait(TRAIT_PLANT_ICON,"bush2")
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/onion
- name = "onion"
- seed_name = "onion"
- display_name = "onions"
- kitchen_tag = "onion"
- chems = list("nutriment" = list(1,10))
-
-/datum/seed/onion/New()
- ..()
- set_trait(TRAIT_MATURATION,10)
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"onion")
- set_trait(TRAIT_PRODUCT_COLOUR,"#E0C367")
- set_trait(TRAIT_PLANT_ICON,"carrot")
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/soybean
- name = "soybean"
- seed_name = "soybean"
- display_name = "soybeans"
- kitchen_tag = "soybeans"
- chems = list("nutriment" = list(1,20), "soymilk" = list(10,20))
-
-/datum/seed/soybean/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,4)
- set_trait(TRAIT_PRODUCTION,4)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,5)
- set_trait(TRAIT_PRODUCT_ICON,"bean")
- set_trait(TRAIT_PRODUCT_COLOUR,"#EBE7C0")
- set_trait(TRAIT_PLANT_ICON,"stalk")
-
-/datum/seed/wheat
- name = "wheat"
- seed_name = "wheat"
- display_name = "wheat stalks"
- kitchen_tag = "wheat"
- chems = list("nutriment" = list(1,25), "flour" = list(10,30))
-
-/datum/seed/wheat/New()
- ..()
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,5)
- set_trait(TRAIT_PRODUCT_ICON,"wheat")
- set_trait(TRAIT_PRODUCT_COLOUR,"#DBD37D")
- set_trait(TRAIT_PLANT_COLOUR,"#BFAF82")
- set_trait(TRAIT_PLANT_ICON,"stalk2")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/rice
- name = "rice"
- seed_name = "rice"
- display_name = "rice stalks"
- kitchen_tag = "rice"
- chems = list("nutriment" = list(1,25), "rice" = list(10,15))
-
-/datum/seed/rice/New()
- ..()
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,5)
- set_trait(TRAIT_PRODUCT_ICON,"rice")
- set_trait(TRAIT_PRODUCT_COLOUR,"#D5E6D1")
- set_trait(TRAIT_PLANT_COLOUR,"#8ED17D")
- set_trait(TRAIT_PLANT_ICON,"stalk2")
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/carrots
- name = "carrot"
- seed_name = "carrot"
- display_name = "carrots"
- kitchen_tag = "carrot"
- chems = list("nutriment" = list(1,20), "imidazoline" = list(3,5), "carrotjuice" = list(10,20))
-
-/datum/seed/carrots/New()
- ..()
- set_trait(TRAIT_MATURATION,10)
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,5)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"carrot")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FFDB4A")
- set_trait(TRAIT_PLANT_ICON,"carrot")
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/weeds
- name = "weeds"
- seed_name = "weed"
- display_name = "weeds"
-
-/datum/seed/weeds/New()
- ..()
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,-1)
- set_trait(TRAIT_POTENCY,-1)
- set_trait(TRAIT_IMMUTABLE,-1)
- set_trait(TRAIT_PRODUCT_ICON,"flower4")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FCEB2B")
- set_trait(TRAIT_PLANT_COLOUR,"#59945A")
- set_trait(TRAIT_PLANT_ICON,"bush6")
-
-/datum/seed/whitebeets
- name = "whitebeet"
- seed_name = "white-beet"
- display_name = "white-beets"
- kitchen_tag = "whitebeet"
- chems = list("nutriment" = list(0,20), "sugar" = list(1,5))
-
-/datum/seed/whitebeets/New()
- ..()
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,6)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"carrot2")
- set_trait(TRAIT_PRODUCT_COLOUR,"#EEF5B0")
- set_trait(TRAIT_PLANT_COLOUR,"#4D8F53")
- set_trait(TRAIT_PLANT_ICON,"carrot2")
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/sugarcane
- name = "sugarcane"
- seed_name = "sugarcane"
- display_name = "sugarcanes"
- kitchen_tag = "sugarcanes"
- chems = list("sugar" = list(4,5))
-
-/datum/seed/sugarcane/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,3)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"stalk")
- set_trait(TRAIT_PRODUCT_COLOUR,"#B4D6BD")
- set_trait(TRAIT_PLANT_COLOUR,"#6BBD68")
- set_trait(TRAIT_PLANT_ICON,"stalk3")
- set_trait(TRAIT_IDEAL_HEAT, 298)
-
-/datum/seed/rhubarb
- name = "rhubarb"
- seed_name = "rhubarb"
- display_name = "rhubarb"
- kitchen_tag = "rhubarb"
- chems = list("nutriment" = list(1,15))
-
-/datum/seed/rhubarb/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,3)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,5)
- set_trait(TRAIT_POTENCY,6)
- set_trait(TRAIT_PRODUCT_ICON,"stalk")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FD5656")
- set_trait(TRAIT_PLANT_ICON,"stalk3")
-
-/datum/seed/celery
- name = "celery"
- seed_name = "celery"
- display_name = "celery"
- kitchen_tag = "celery"
- chems = list("nutriment" = list(5,20))
-
-/datum/seed/celery/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,4)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,8)
- set_trait(TRAIT_PRODUCT_ICON,"stalk")
- set_trait(TRAIT_PRODUCT_COLOUR,"#56FD56")
- set_trait(TRAIT_PLANT_ICON,"stalk3")
-
-/datum/seed/spineapple
- name = "spineapple"
- seed_name = "spineapple"
- display_name = "spineapple"
- kitchen_tag = "pineapple"
- chems = list("nutriment" = list(1,5), "enzyme" = list(1,5), "pineapplejuice" = list(1, 20))
-
-/datum/seed/spineapple/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,10)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,1)
- set_trait(TRAIT_POTENCY,13)
- set_trait(TRAIT_PRODUCT_ICON,"pineapple")
- set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B")
- set_trait(TRAIT_PLANT_COLOUR,"#87C969")
- set_trait(TRAIT_PLANT_ICON,"corn")
- set_trait(TRAIT_IDEAL_HEAT, 298)
- set_trait(TRAIT_IDEAL_LIGHT, 4)
- set_trait(TRAIT_WATER_CONSUMPTION, 8)
- set_trait(TRAIT_STINGS,1)
-
-/datum/seed/durian
- name = "durian"
- seed_name = "durian"
- seed_noun = "pits"
- display_name = "durian"
- kitchen_tag = "durian"
- chems = list("nutriment" = list(1,5), "durianpaste" = list(1, 20))
-
-/datum/seed/durian/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"spinefruit")
- set_trait(TRAIT_PRODUCT_COLOUR,"#757631")
- set_trait(TRAIT_PLANT_COLOUR,"#87C969")
- set_trait(TRAIT_PLANT_ICON,"tree")
- set_trait(TRAIT_IDEAL_LIGHT, 8)
- set_trait(TRAIT_WATER_CONSUMPTION, 8)
-
-/datum/seed/watermelon
- name = "watermelon"
- seed_name = "watermelon"
- display_name = "watermelon vine"
- kitchen_tag = "watermelon"
- chems = list("nutriment" = list(1,6), "watermelonjuice" = list(10,6))
-
-/datum/seed/watermelon/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_JUICY,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,1)
- set_trait(TRAIT_PRODUCT_ICON,"vine")
- set_trait(TRAIT_PRODUCT_COLOUR,"#3D8C3A")
- set_trait(TRAIT_PLANT_COLOUR,"#257522")
- set_trait(TRAIT_PLANT_ICON,"vine2")
- set_trait(TRAIT_FLESH_COLOUR,"#F22C2C")
- set_trait(TRAIT_IDEAL_HEAT, 298)
- set_trait(TRAIT_IDEAL_LIGHT, 6)
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/pumpkin
- name = "pumpkin"
- seed_name = "pumpkin"
- display_name = "pumpkin vine"
- kitchen_tag = "pumpkin"
- chems = list("nutriment" = list(1,6))
-
-/datum/seed/pumpkin/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"vine2")
- set_trait(TRAIT_PRODUCT_COLOUR,"#DBAC02")
- set_trait(TRAIT_PLANT_COLOUR,"#21661E")
- set_trait(TRAIT_PLANT_ICON,"vine2")
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/citrus
- name = "lime"
- seed_name = "lime"
- display_name = "lime trees"
- kitchen_tag = "lime"
- chems = list("nutriment" = list(1,20), "limejuice" = list(10,20))
-
-/datum/seed/citrus/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_JUICY,1)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,15)
- set_trait(TRAIT_PRODUCT_ICON,"treefruit")
- set_trait(TRAIT_PRODUCT_COLOUR,"#3AF026")
- set_trait(TRAIT_PLANT_ICON,"tree")
- set_trait(TRAIT_FLESH_COLOUR,"#3AF026")
-
-/datum/seed/citrus/lemon
- name = "lemon"
- seed_name = "lemon"
- display_name = "lemon trees"
- kitchen_tag = "lemon"
- chems = list("nutriment" = list(1,20), "lemonjuice" = list(10,20))
-
-/datum/seed/citrus/lemon/New()
- ..()
- set_trait(TRAIT_PRODUCES_POWER,1)
- set_trait(TRAIT_PRODUCT_ICON,"lemon")
- set_trait(TRAIT_PRODUCT_COLOUR,"#F0E226")
- set_trait(TRAIT_FLESH_COLOUR,"#F0E226")
- set_trait(TRAIT_IDEAL_LIGHT, 6)
-
-/datum/seed/citrus/orange
- name = "orange"
- seed_name = "orange"
- display_name = "orange trees"
- kitchen_tag = "orange"
- chems = list("nutriment" = list(1,20), "orangejuice" = list(10,20))
-
-/datum/seed/citrus/orange/New()
- ..()
- set_trait(TRAIT_PRODUCT_COLOUR,"#FFC20A")
- set_trait(TRAIT_FLESH_COLOUR,"#FFC20A")
-
-/datum/seed/grass
- name = "grass"
- seed_name = "grass"
- display_name = "grass"
- kitchen_tag = "grass"
- chems = list("nutriment" = list(1,20))
-
-/datum/seed/grass/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,2)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,5)
- set_trait(TRAIT_PRODUCT_ICON,"grass")
- set_trait(TRAIT_PRODUCT_COLOUR,"#09FF00")
- set_trait(TRAIT_PLANT_COLOUR,"#07D900")
- set_trait(TRAIT_PLANT_ICON,"grass")
- set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/cocoa
- name = "cocoa"
- seed_name = "cacao"
- display_name = "cacao tree"
- kitchen_tag = "cocoa"
- chems = list("nutriment" = list(1,10), "coco" = list(4,5))
-
-/datum/seed/cocoa/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"treefruit")
- set_trait(TRAIT_PRODUCT_COLOUR,"#CCA935")
- set_trait(TRAIT_PLANT_ICON,"tree2")
- set_trait(TRAIT_IDEAL_HEAT, 298)
- set_trait(TRAIT_WATER_CONSUMPTION, 6)
-
-/datum/seed/cherries
- name = "cherry"
- seed_name = "cherry"
- seed_noun = "pits"
- display_name = "cherry tree"
- kitchen_tag = "cherries"
- chems = list("nutriment" = list(1,15), "sugar" = list(1,15), "cherryjelly" = list(10,15))
-
-/datum/seed/cherries/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_JUICY,1)
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"cherry")
- set_trait(TRAIT_PRODUCT_COLOUR,"#A80000")
- set_trait(TRAIT_PLANT_ICON,"tree2")
- set_trait(TRAIT_PLANT_COLOUR,"#2F7D2D")
-
-/datum/seed/kudzu
- name = "kudzu"
- seed_name = "kudzu"
- display_name = "kudzu vines"
- kitchen_tag = "kudzu"
- chems = list("nutriment" = list(1,50), "anti_toxin" = list(1,25))
-
-/datum/seed/kudzu/New()
- ..()
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_SPREAD,2)
- set_trait(TRAIT_PRODUCT_ICON,"treefruit")
- set_trait(TRAIT_PRODUCT_COLOUR,"#96D278")
- set_trait(TRAIT_PLANT_COLOUR,"#6F7A63")
- set_trait(TRAIT_PLANT_ICON,"vine2")
- set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
-
-/datum/seed/diona
- name = "diona"
- seed_name = "diona"
- seed_noun = "nodes"
- display_name = "replicant pods"
- can_self_harvest = 1
- apply_color_to_mob = FALSE
- has_mob_product = /mob/living/carbon/alien/diona
-
-/datum/seed/diona/New()
- ..()
- set_trait(TRAIT_IMMUTABLE,1)
- set_trait(TRAIT_ENDURANCE,8)
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,10)
- set_trait(TRAIT_YIELD,1)
- set_trait(TRAIT_POTENCY,30)
- set_trait(TRAIT_PRODUCT_ICON,"diona")
- set_trait(TRAIT_PRODUCT_COLOUR,"#799957")
- set_trait(TRAIT_PLANT_COLOUR,"#66804B")
- set_trait(TRAIT_PLANT_ICON,"alien4")
-
-/datum/seed/shand
- name = "shand"
- seed_name = "Selem's hand"
- display_name = "Selem's hand leaves"
- kitchen_tag = "shand"
- chems = list("bicaridine" = list(0,10))
-
-/datum/seed/shand/New()
- ..()
- set_trait(TRAIT_MATURATION,3)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"alien3")
- set_trait(TRAIT_PRODUCT_COLOUR,"#378C61")
- set_trait(TRAIT_PLANT_COLOUR,"#378C61")
- set_trait(TRAIT_PLANT_ICON,"tree5")
- set_trait(TRAIT_IDEAL_HEAT, 283)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/mtear
- name = "mtear"
- seed_name = "Malani's tear"
- display_name = "Malani's tear leaves"
- kitchen_tag = "mtear"
- chems = list("honey" = list(1,10), "kelotane" = list(3,5))
-
-/datum/seed/mtear/New()
- ..()
- set_trait(TRAIT_MATURATION,3)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_PRODUCT_ICON,"alien4")
- set_trait(TRAIT_PRODUCT_COLOUR,"#4CC5C7")
- set_trait(TRAIT_PLANT_COLOUR,"#4CC789")
- set_trait(TRAIT_PLANT_ICON,"bush7")
- set_trait(TRAIT_IDEAL_HEAT, 283)
- set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
-
-/datum/seed/telriis
- name = "telriis"
- seed_name = "telriis"
- display_name = "telriis grass"
- kitchen_tag = "telriis"
- chems = list("pwine" = list(1,5), "nutriment" = list(1,6))
-
-/datum/seed/telriis/New()
- ..()
- set_trait(TRAIT_PLANT_ICON,"ambrosia")
- set_trait(TRAIT_PRODUCT_ICON,"ambrosia")
- set_trait(TRAIT_ENDURANCE,50)
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,5)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,5)
-
-/datum/seed/thaadra
- name = "thaadra"
- seed_name = "thaa'dra"
- display_name = "thaa'dra lichen"
- kitchen_tag = "thaadra"
- chems = list("frostoil" = list(1,5),"nutriment" = list(1,5))
-
-/datum/seed/thaadra/New()
- ..()
- set_trait(TRAIT_PLANT_ICON,"grass")
- set_trait(TRAIT_PLANT_COLOUR,"#ABC7D2")
- set_trait(TRAIT_ENDURANCE,10)
- set_trait(TRAIT_MATURATION,5)
- set_trait(TRAIT_PRODUCTION,9)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,5)
-
-/datum/seed/jurlmah
- name = "jurlmah"
- seed_name = "jurl'mah"
- display_name = "jurl'mah reeds"
- kitchen_tag = "jurlmah"
- chems = list("serotrotium" = list(1,5),"nutriment" = list(1,5))
-
-/datum/seed/jurlmah/New()
- ..()
- set_trait(TRAIT_PLANT_ICON,"mushroom9")
- set_trait(TRAIT_ENDURANCE,12)
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_PRODUCTION,9)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,10)
-
-/datum/seed/amauri
- name = "amauri"
- seed_name = "amauri"
- display_name = "amauri plant"
- kitchen_tag = "amauri"
- chems = list("zombiepowder" = list(1,10),"condensedcapsaicin" = list(1,5),"nutriment" = list(1,5))
-
-/datum/seed/amauri/New()
- ..()
- set_trait(TRAIT_PLANT_ICON,"bush4")
- set_trait(TRAIT_ENDURANCE,10)
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_PRODUCTION,9)
- set_trait(TRAIT_YIELD,4)
- set_trait(TRAIT_POTENCY,10)
-
-/datum/seed/gelthi
- name = "gelthi"
- seed_name = "gelthi"
- display_name = "gelthi plant"
- kitchen_tag = "gelthi"
- chems = list("stoxin" = list(1,5),"capsaicin" = list(1,5),"nutriment" = list(1,5))
-
-/datum/seed/gelthi/New()
- ..()
- set_trait(TRAIT_PLANT_ICON,"mushroom3")
- set_trait(TRAIT_ENDURANCE,15)
- set_trait(TRAIT_MATURATION,6)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_POTENCY,1)
-
-/datum/seed/vale
- name = "vale"
- seed_name = "vale"
- display_name = "vale bush"
- kitchen_tag = "vale"
- chems = list("paracetamol" = list(1,5),"dexalin" = list(1,2),"nutriment"= list(1,5))
-
-/datum/seed/vale/New()
- ..()
- set_trait(TRAIT_PLANT_ICON,"flower4")
- set_trait(TRAIT_ENDURANCE,15)
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_PRODUCTION,10)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,3)
-
-/datum/seed/surik
- name = "surik"
- seed_name = "surik"
- display_name = "surik vine"
- kitchen_tag = "surik"
- chems = list("impedrezene" = list(1,3),"synaptizine" = list(1,2),"nutriment" = list(1,5))
-
-/datum/seed/surik/New()
- ..()
- set_trait(TRAIT_PLANT_ICON,"bush6")
- set_trait(TRAIT_ENDURANCE,18)
- set_trait(TRAIT_MATURATION,7)
- set_trait(TRAIT_PRODUCTION,7)
- set_trait(TRAIT_YIELD,3)
- set_trait(TRAIT_POTENCY,3)
-
-// Alien weeds.
-/datum/seed/xenomorph
- name = "xenomorph"
- seed_name = "alien weed"
- display_name = "alien weeds"
- force_layer = 3
- chems = list("phoron" = list(1,3))
-
-/datum/seed/xenomorph/New()
- ..()
- set_trait(TRAIT_PLANT_ICON,"vine2")
- set_trait(TRAIT_IMMUTABLE,1)
- set_trait(TRAIT_PRODUCT_COLOUR,"#3D1934")
- set_trait(TRAIT_FLESH_COLOUR,"#3D1934")
- set_trait(TRAIT_PLANT_COLOUR,"#3D1934")
- set_trait(TRAIT_PRODUCTION,1)
- set_trait(TRAIT_YIELD,-1)
- set_trait(TRAIT_SPREAD,2)
- set_trait(TRAIT_POTENCY,50)
-
-// Gnomes
-/datum/seed/gnomes
- name = "gnomes"
- seed_name = "gnomes"
- display_name = "gnomes"
- force_layer = 3
- chems = list("magicdust" = list(5,20))
-
-/datum/seed/gnomes/New()
- ..()
- set_trait(TRAIT_HARVEST_REPEAT,1)
- set_trait(TRAIT_PLANT_ICON,"gnomes")
- set_trait(TRAIT_PRODUCT_ICON,"gnomes")
- set_trait(TRAIT_PRODUCT_COLOUR,"")
- set_trait(TRAIT_FLESH_COLOUR,"")
- set_trait(TRAIT_PLANT_COLOUR,"")
- set_trait(TRAIT_BIOLUM_COLOUR,"#fff200")
- set_trait(TRAIT_MATURATION,8)
- set_trait(TRAIT_PRODUCTION,6)
- set_trait(TRAIT_BIOLUM,1)
- set_trait(TRAIT_YIELD,2)
- set_trait(TRAIT_SPREAD,1)
- set_trait(TRAIT_POTENCY,10)
- set_trait(TRAIT_REQUIRES_NUTRIENTS,0)
- set_trait(TRAIT_REQUIRES_WATER,0)
diff --git a/code/modules/hydroponics/seed_packets.dm b/code/modules/hydroponics/seed_packets.dm
index 45d74e26fd..3db8840058 100644
--- a/code/modules/hydroponics/seed_packets.dm
+++ b/code/modules/hydroponics/seed_packets.dm
@@ -337,3 +337,6 @@ GLOBAL_LIST_BOILERPLATE(all_seed_packs, /obj/item/seeds)
/obj/item/seeds/sifbulb
seed_type = "sifbulb"
+
+/obj/item/seeds/wurmwoad
+ seed_type = "wurmwoad"
diff --git a/code/modules/hydroponics/seed_storage.dm b/code/modules/hydroponics/seed_storage.dm
index 39b9dc3ebc..f75d17f63e 100644
--- a/code/modules/hydroponics/seed_storage.dm
+++ b/code/modules/hydroponics/seed_storage.dm
@@ -138,7 +138,8 @@
/obj/item/seeds/wabback = 2,
/obj/item/seeds/watermelonseed = 3,
/obj/item/seeds/wheatseed = 3,
- /obj/item/seeds/whitebeetseed = 3
+ /obj/item/seeds/whitebeetseed = 3,
+ /obj/item/seeds/wurmwoad = 3
)
/obj/machinery/seed_storage/xenobotany
@@ -195,7 +196,8 @@
/obj/item/seeds/wabback = 2,
/obj/item/seeds/watermelonseed = 3,
/obj/item/seeds/wheatseed = 3,
- /obj/item/seeds/whitebeetseed = 3
+ /obj/item/seeds/whitebeetseed = 3,
+ /obj/item/seeds/wurmwoad = 3
)
/obj/machinery/seed_storage/attack_hand(mob/user as mob)
diff --git a/code/modules/hydroponics/seedtypes/amauri.dm b/code/modules/hydroponics/seedtypes/amauri.dm
new file mode 100644
index 0000000000..0ad44e7862
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/amauri.dm
@@ -0,0 +1,15 @@
+/datum/seed/amauri
+ name = "amauri"
+ seed_name = "amauri"
+ display_name = "amauri plant"
+ kitchen_tag = "amauri"
+ chems = list("zombiepowder" = list(1,10),"condensedcapsaicin" = list(1,5),"nutriment" = list(1,5))
+
+/datum/seed/amauri/New()
+ ..()
+ set_trait(TRAIT_PLANT_ICON,"bush4")
+ set_trait(TRAIT_ENDURANCE,10)
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,9)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/ambrosia.dm b/code/modules/hydroponics/seedtypes/ambrosia.dm
new file mode 100644
index 0000000000..535d5129a3
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/ambrosia.dm
@@ -0,0 +1,46 @@
+//Ambrosia/varieties.
+/datum/seed/ambrosia
+ name = "ambrosia"
+ seed_name = "ambrosia vulgaris"
+ display_name = "ambrosia vulgaris"
+ kitchen_tag = "ambrosia"
+ mutants = list("ambrosiadeus")
+ chems = list("nutriment" = list(1), "space_drugs" = list(1,8), "kelotane" = list(1,8,1), "bicaridine" = list(1,10,1), "toxin" = list(1,10))
+
+/datum/seed/ambrosia/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,6)
+ set_trait(TRAIT_POTENCY,5)
+ set_trait(TRAIT_PRODUCT_ICON,"ambrosia")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#9FAD55")
+ set_trait(TRAIT_PLANT_ICON,"ambrosia")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+
+/datum/seed/ambrosia/deus
+ name = "ambrosiadeus"
+ seed_name = "ambrosia deus"
+ display_name = "ambrosia deus"
+ kitchen_tag = "ambrosiadeus"
+ mutants = list("ambrosiainfernus")
+ chems = list("nutriment" = list(1), "bicaridine" = list(1,8), "synaptizine" = list(1,8,1), "hyperzine" = list(1,10,1), "space_drugs" = list(1,10))
+
+/datum/seed/ambrosia/deus/New()
+ ..()
+ set_trait(TRAIT_PRODUCT_COLOUR,"#A3F0AD")
+ set_trait(TRAIT_PLANT_COLOUR,"#2A9C61")
+
+/datum/seed/ambrosia/infernus
+ name = "ambrosiainfernus"
+ seed_name = "ambrosia infernus"
+ display_name = "ambrosia infernus"
+ kitchen_tag = "ambrosiainfernus"
+ mutants = null
+ chems = list("nutriment" = list(1,3), "oxycodone" = list(1,8), "impedrezene" = list(1,10), "mindbreaker" = list(1,10))
+
+/datum/seed/ambrosia/infernus/New()
+ ..()
+ set_trait(TRAIT_PRODUCT_COLOUR,"#dc143c")
+ set_trait(TRAIT_PLANT_COLOUR,"#b22222")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/apples.dm b/code/modules/hydroponics/seedtypes/apples.dm
new file mode 100644
index 0000000000..7044a0c6dc
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/apples.dm
@@ -0,0 +1,62 @@
+//Apples/varieties.
+/datum/seed/apple
+ name = "apple"
+ seed_name = "apple"
+ display_name = "apple tree"
+ kitchen_tag = "apple"
+ mutants = list("poisonapple","goldapple")
+ chems = list("nutriment" = list(1,10),"applejuice" = list(10,20))
+
+/datum/seed/apple/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,5)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"apple")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FF540A")
+ set_trait(TRAIT_PLANT_ICON,"tree2")
+ set_trait(TRAIT_FLESH_COLOUR,"#E8E39B")
+ set_trait(TRAIT_IDEAL_LIGHT, 4)
+
+/datum/seed/apple/poison
+ name = "poisonapple"
+ mutants = null
+ chems = list("cyanide" = list(1,5))
+
+/datum/seed/apple/gold
+ name = "goldapple"
+ seed_name = "golden apple"
+ display_name = "gold apple tree"
+ kitchen_tag = "goldapple"
+ mutants = null
+ chems = list("nutriment" = list(1,10), "gold" = list(1,5))
+
+/datum/seed/apple/gold/New()
+ ..()
+ set_trait(TRAIT_MATURATION,10)
+ set_trait(TRAIT_PRODUCTION,10)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FFDD00")
+ set_trait(TRAIT_PLANT_COLOUR,"#D6B44D")
+
+/datum/seed/apple/sif
+ name = "sifbulb"
+ seed_name = "sivian tree"
+ display_name = "sivian pod"
+ kitchen_tag = "apple"
+ chems = list("nutriment" = list(1,5),"sifsap" = list(10,20))
+
+/datum/seed/apple/sif/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,3)
+ set_trait(TRAIT_PRODUCTION,10)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,12)
+ set_trait(TRAIT_PRODUCT_ICON,"alien3")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#0720c3")
+ set_trait(TRAIT_PLANT_ICON,"tree5")
+ set_trait(TRAIT_FLESH_COLOUR,"#05157d")
+ set_trait(TRAIT_IDEAL_LIGHT, 1)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/banana.dm b/code/modules/hydroponics/seedtypes/banana.dm
new file mode 100644
index 0000000000..9259318d77
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/banana.dm
@@ -0,0 +1,21 @@
+/datum/seed/banana
+ name = "banana"
+ seed_name = "banana"
+ display_name = "banana tree"
+ kitchen_tag = "banana"
+ chems = list("banana" = list(10,10))
+ trash_type = /obj/item/weapon/bananapeel
+
+/datum/seed/banana/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_PRODUCT_ICON,"bananas")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FFEC1F")
+ set_trait(TRAIT_PLANT_COLOUR,"#69AD50")
+ set_trait(TRAIT_PLANT_ICON,"tree4")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
+ set_trait(TRAIT_IDEAL_LIGHT, 7)
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/berries.dm b/code/modules/hydroponics/seedtypes/berries.dm
new file mode 100644
index 0000000000..2ad36353fe
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/berries.dm
@@ -0,0 +1,70 @@
+// Berry plants/variants.
+/datum/seed/berry
+ name = "berries"
+ seed_name = "berry"
+ display_name = "berry bush"
+ kitchen_tag = "berries"
+ mutants = list("glowberries","poisonberries")
+ chems = list("nutriment" = list(1,10), "berryjuice" = list(10,10))
+
+/datum/seed/berry/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_JUICY,1)
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"berry")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FA1616")
+ set_trait(TRAIT_PLANT_ICON,"bush")
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
+
+/datum/seed/berry/glow
+ name = "glowberries"
+ seed_name = "glowberry"
+ display_name = "glowberry bush"
+ mutants = null
+ chems = list("nutriment" = list(1,10), "uranium" = list(3,5))
+
+/datum/seed/berry/glow/New()
+ ..()
+ set_trait(TRAIT_SPREAD,1)
+ set_trait(TRAIT_BIOLUM,1)
+ set_trait(TRAIT_BIOLUM_COLOUR,"#006622")
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#c9fa16")
+ set_trait(TRAIT_WATER_CONSUMPTION, 3)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25)
+
+/datum/seed/berry/poison
+ name = "poisonberries"
+ seed_name = "poison berry"
+ kitchen_tag = "poisonberries"
+ display_name = "poison berry bush"
+ mutants = list("deathberries")
+ chems = list("nutriment" = list(1), "toxin" = list(3,5), "poisonberryjuice" = list(10,5))
+
+/datum/seed/berry/poison/New()
+ ..()
+ set_trait(TRAIT_PRODUCT_COLOUR,"#6DC961")
+ set_trait(TRAIT_WATER_CONSUMPTION, 3)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25)
+
+/datum/seed/berry/poison/death
+ name = "deathberries"
+ seed_name = "death berry"
+ display_name = "death berry bush"
+ mutants = null
+ chems = list("nutriment" = list(1), "toxin" = list(3,3), "lexorin" = list(1,5))
+
+/datum/seed/berry/poison/death/New()
+ ..()
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,50)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#7A5454")
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.35)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/cabbage.dm b/code/modules/hydroponics/seedtypes/cabbage.dm
new file mode 100644
index 0000000000..0ee7fb2693
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/cabbage.dm
@@ -0,0 +1,21 @@
+/datum/seed/cabbage
+ name = "cabbage"
+ seed_name = "cabbage"
+ display_name = "cabbages"
+ kitchen_tag = "cabbage"
+ chems = list("nutriment" = list(1,10))
+
+/datum/seed/cabbage/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,3)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"cabbage")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#84BD82")
+ set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B")
+ set_trait(TRAIT_PLANT_ICON,"vine2")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/carrots.dm b/code/modules/hydroponics/seedtypes/carrots.dm
new file mode 100644
index 0000000000..2b8ef7577b
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/carrots.dm
@@ -0,0 +1,17 @@
+/datum/seed/carrots
+ name = "carrot"
+ seed_name = "carrot"
+ display_name = "carrots"
+ kitchen_tag = "carrot"
+ chems = list("nutriment" = list(1,20), "imidazoline" = list(3,5), "carrotjuice" = list(10,20))
+
+/datum/seed/carrots/New()
+ ..()
+ set_trait(TRAIT_MATURATION,10)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,5)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"carrot")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FFDB4A")
+ set_trait(TRAIT_PLANT_ICON,"carrot")
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/celery.dm b/code/modules/hydroponics/seedtypes/celery.dm
new file mode 100644
index 0000000000..c404ed670f
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/celery.dm
@@ -0,0 +1,17 @@
+/datum/seed/celery
+ name = "celery"
+ seed_name = "celery"
+ display_name = "celery"
+ kitchen_tag = "celery"
+ chems = list("nutriment" = list(5,20))
+
+/datum/seed/celery/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,4)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,8)
+ set_trait(TRAIT_PRODUCT_ICON,"stalk")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#56FD56")
+ set_trait(TRAIT_PLANT_ICON,"stalk3")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/cherries.dm b/code/modules/hydroponics/seedtypes/cherries.dm
new file mode 100644
index 0000000000..ece8d793e7
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/cherries.dm
@@ -0,0 +1,20 @@
+/datum/seed/cherries
+ name = "cherry"
+ seed_name = "cherry"
+ seed_noun = "pits"
+ display_name = "cherry tree"
+ kitchen_tag = "cherries"
+ chems = list("nutriment" = list(1,15), "sugar" = list(1,15), "cherryjelly" = list(10,15))
+
+/datum/seed/cherries/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_JUICY,1)
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"cherry")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#A80000")
+ set_trait(TRAIT_PLANT_ICON,"tree2")
+ set_trait(TRAIT_PLANT_COLOUR,"#2F7D2D")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/chili.dm b/code/modules/hydroponics/seedtypes/chili.dm
new file mode 100644
index 0000000000..bee50a48bc
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/chili.dm
@@ -0,0 +1,35 @@
+// Chili plants/variants.
+/datum/seed/chili
+ name = "chili"
+ seed_name = "chili"
+ display_name = "chili plants"
+ kitchen_tag = "chili"
+ chems = list("capsaicin" = list(3,5), "nutriment" = list(1,25))
+ mutants = list("icechili")
+
+/datum/seed/chili/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,20)
+ set_trait(TRAIT_PRODUCT_ICON,"chili")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#ED3300")
+ set_trait(TRAIT_PLANT_ICON,"bush2")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
+ set_trait(TRAIT_IDEAL_LIGHT, 7)
+
+/datum/seed/chili/ice
+ name = "icechili"
+ seed_name = "ice pepper"
+ display_name = "ice-pepper plants"
+ kitchen_tag = "icechili"
+ mutants = null
+ chems = list("frostoil" = list(3,5), "nutriment" = list(1,50))
+
+/datum/seed/chili/ice/New()
+ ..()
+ set_trait(TRAIT_MATURATION,4)
+ set_trait(TRAIT_PRODUCTION,4)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#00EDC6")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/citrus.dm b/code/modules/hydroponics/seedtypes/citrus.dm
new file mode 100644
index 0000000000..ebc154aa40
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/citrus.dm
@@ -0,0 +1,46 @@
+/datum/seed/citrus
+ name = "lime"
+ seed_name = "lime"
+ display_name = "lime trees"
+ kitchen_tag = "lime"
+ chems = list("nutriment" = list(1,20), "limejuice" = list(10,20))
+
+/datum/seed/citrus/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_JUICY,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,15)
+ set_trait(TRAIT_PRODUCT_ICON,"treefruit")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#3AF026")
+ set_trait(TRAIT_PLANT_ICON,"tree")
+ set_trait(TRAIT_FLESH_COLOUR,"#3AF026")
+
+/datum/seed/citrus/lemon
+ name = "lemon"
+ seed_name = "lemon"
+ display_name = "lemon trees"
+ kitchen_tag = "lemon"
+ chems = list("nutriment" = list(1,20), "lemonjuice" = list(10,20))
+
+/datum/seed/citrus/lemon/New()
+ ..()
+ set_trait(TRAIT_PRODUCES_POWER,1)
+ set_trait(TRAIT_PRODUCT_ICON,"lemon")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#F0E226")
+ set_trait(TRAIT_FLESH_COLOUR,"#F0E226")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+
+/datum/seed/citrus/orange
+ name = "orange"
+ seed_name = "orange"
+ display_name = "orange trees"
+ kitchen_tag = "orange"
+ chems = list("nutriment" = list(1,20), "orangejuice" = list(10,20))
+
+/datum/seed/citrus/orange/New()
+ ..()
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FFC20A")
+ set_trait(TRAIT_FLESH_COLOUR,"#FFC20A")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/cocoa.dm b/code/modules/hydroponics/seedtypes/cocoa.dm
new file mode 100644
index 0000000000..7f7aa31b39
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/cocoa.dm
@@ -0,0 +1,19 @@
+/datum/seed/cocoa
+ name = "cocoa"
+ seed_name = "cacao"
+ display_name = "cacao tree"
+ kitchen_tag = "cocoa"
+ chems = list("nutriment" = list(1,10), "coco" = list(4,5))
+
+/datum/seed/cocoa/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"treefruit")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#CCA935")
+ set_trait(TRAIT_PLANT_ICON,"tree2")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/corn.dm b/code/modules/hydroponics/seedtypes/corn.dm
new file mode 100644
index 0000000000..2a4b2824f8
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/corn.dm
@@ -0,0 +1,21 @@
+/datum/seed/corn
+ name = "corn"
+ seed_name = "corn"
+ display_name = "ears of corn"
+ kitchen_tag = "corn"
+ chems = list("nutriment" = list(1,10), "cornoil" = list(3,15))
+ trash_type = /obj/item/weapon/corncob
+
+/datum/seed/corn/New()
+ ..()
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,20)
+ set_trait(TRAIT_PRODUCT_ICON,"corn")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B")
+ set_trait(TRAIT_PLANT_COLOUR,"#87C969")
+ set_trait(TRAIT_PLANT_ICON,"corn")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/diona.dm b/code/modules/hydroponics/seedtypes/diona.dm
new file mode 100644
index 0000000000..be3b80b6bf
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/diona.dm
@@ -0,0 +1,21 @@
+/datum/seed/diona
+ name = "diona"
+ seed_name = "diona"
+ seed_noun = "nodes"
+ display_name = "replicant pods"
+ can_self_harvest = 1
+ apply_color_to_mob = FALSE
+ has_mob_product = /mob/living/carbon/alien/diona
+
+/datum/seed/diona/New()
+ ..()
+ set_trait(TRAIT_IMMUTABLE,1)
+ set_trait(TRAIT_ENDURANCE,8)
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,10)
+ set_trait(TRAIT_YIELD,1)
+ set_trait(TRAIT_POTENCY,30)
+ set_trait(TRAIT_PRODUCT_ICON,"diona")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#799957")
+ set_trait(TRAIT_PLANT_COLOUR,"#66804B")
+ set_trait(TRAIT_PLANT_ICON,"alien4")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/durian.dm b/code/modules/hydroponics/seedtypes/durian.dm
new file mode 100644
index 0000000000..8963f4c9ec
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/durian.dm
@@ -0,0 +1,21 @@
+/datum/seed/durian
+ name = "durian"
+ seed_name = "durian"
+ seed_noun = "pits"
+ display_name = "durian"
+ kitchen_tag = "durian"
+ chems = list("nutriment" = list(1,5), "durianpaste" = list(1, 20))
+
+/datum/seed/durian/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"spinefruit")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#757631")
+ set_trait(TRAIT_PLANT_COLOUR,"#87C969")
+ set_trait(TRAIT_PLANT_ICON,"tree")
+ set_trait(TRAIT_IDEAL_LIGHT, 8)
+ set_trait(TRAIT_WATER_CONSUMPTION, 8)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/eggplant.dm b/code/modules/hydroponics/seedtypes/eggplant.dm
new file mode 100644
index 0000000000..c856f0d382
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/eggplant.dm
@@ -0,0 +1,31 @@
+//Eggplants/varieties.
+/datum/seed/eggplant
+ name = "eggplant"
+ seed_name = "eggplant"
+ display_name = "eggplants"
+ kitchen_tag = "eggplant"
+ mutants = list("egg-plant")
+ chems = list("nutriment" = list(1,10))
+
+/datum/seed/eggplant/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,20)
+ set_trait(TRAIT_PRODUCT_ICON,"eggplant")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#892694")
+ set_trait(TRAIT_PLANT_ICON,"bush4")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
+ set_trait(TRAIT_IDEAL_LIGHT, 7)
+
+// Return of Eggy. Just makes purple eggs. If the reagents are separated from the egg production by xenobotany or RNG, it's still an Egg plant.
+/datum/seed/eggplant/egg
+ name = "egg-plant"
+ seed_name = "egg-plant"
+ display_name = "egg-plants"
+ kitchen_tag = "egg-plant"
+ mutants = null
+ chems = list("nutriment" = list(1,5), "egg" = list(3,12))
+ has_item_product = /obj/item/weapon/reagent_containers/food/snacks/egg/purple
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/flowers.dm b/code/modules/hydroponics/seedtypes/flowers.dm
new file mode 100644
index 0000000000..2c2ffe13ec
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/flowers.dm
@@ -0,0 +1,108 @@
+//Flowers/varieties
+/datum/seed/flower
+ name = "harebells"
+ seed_name = "harebell"
+ display_name = "harebells"
+ kitchen_tag = "harebell"
+ chems = list("nutriment" = list(1,20))
+
+/datum/seed/flower/New()
+ ..()
+ set_trait(TRAIT_MATURATION,7)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_PRODUCT_ICON,"flower5")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#C492D6")
+ set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E")
+ set_trait(TRAIT_PLANT_ICON,"flower")
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
+
+/datum/seed/flower/poppy
+ name = "poppies"
+ seed_name = "poppy"
+ display_name = "poppies"
+ kitchen_tag = "poppy"
+ chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10))
+
+/datum/seed/flower/poppy/New()
+ ..()
+ set_trait(TRAIT_POTENCY,20)
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,6)
+ set_trait(TRAIT_PRODUCT_ICON,"flower3")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#B33715")
+ set_trait(TRAIT_PLANT_ICON,"flower3")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+ set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
+
+/datum/seed/flower/sunflower
+ name = "sunflowers"
+ seed_name = "sunflower"
+ display_name = "sunflowers"
+ kitchen_tag = "sunflower"
+
+/datum/seed/flower/sunflower/New()
+ ..()
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCT_ICON,"flower2")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FFF700")
+ set_trait(TRAIT_PLANT_ICON,"flower2")
+ set_trait(TRAIT_IDEAL_LIGHT, 7)
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
+
+/datum/seed/flower/lavender
+ name = "lavender"
+ seed_name = "lavender"
+ display_name = "lavender"
+ kitchen_tag = "lavender"
+ chems = list("nutriment" = list(1,20), "bicaridine" = list(1,10))
+
+/datum/seed/flower/lavender/New()
+ ..()
+ set_trait(TRAIT_MATURATION,7)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,5)
+ set_trait(TRAIT_PRODUCT_ICON,"flower6")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#B57EDC")
+ set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E")
+ set_trait(TRAIT_PLANT_ICON,"flower4")
+ set_trait(TRAIT_IDEAL_LIGHT, 7)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.05)
+ set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
+
+/datum/seed/flower/rose
+ name = "rose"
+ seed_name = "rose"
+ display_name = "rose"
+ kitchen_tag = "rose"
+ mutants = list("bloodrose")
+ chems = list("nutriment" = list(1,5), "stoxin" = list(0,2))
+
+/datum/seed/flower/rose/New()
+ ..()
+ set_trait(TRAIT_MATURATION,7)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_PRODUCT_ICON,"flowers")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#ce0e0e")
+ set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E")
+ set_trait(TRAIT_PLANT_ICON,"bush5")
+ set_trait(TRAIT_IDEAL_LIGHT, 7)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.1)
+ set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
+ set_trait(TRAIT_STINGS,1)
+
+/datum/seed/flower/rose/blood
+ name = "bloodrose"
+ display_name = "bleeding rose"
+ mutants = null
+ chems = list("nutriment" = list(1,5), "stoxin" = list(1,5), "blood" = list(0,2))
+
+/datum/seed/flower/rose/blood/New()
+ ..()
+ set_trait(TRAIT_IDEAL_LIGHT, 1)
+ set_trait(TRAIT_PLANT_COLOUR,"#5e0303")
+ set_trait(TRAIT_CARNIVOROUS,1)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/gelthi.dm b/code/modules/hydroponics/seedtypes/gelthi.dm
new file mode 100644
index 0000000000..1fa365c875
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/gelthi.dm
@@ -0,0 +1,15 @@
+/datum/seed/gelthi
+ name = "gelthi"
+ seed_name = "gelthi"
+ display_name = "gelthi plant"
+ kitchen_tag = "gelthi"
+ chems = list("stoxin" = list(1,5),"capsaicin" = list(1,5),"nutriment" = list(1,5))
+
+/datum/seed/gelthi/New()
+ ..()
+ set_trait(TRAIT_PLANT_ICON,"mushroom3")
+ set_trait(TRAIT_ENDURANCE,15)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,1)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/gnomes.dm b/code/modules/hydroponics/seedtypes/gnomes.dm
new file mode 100644
index 0000000000..2ee0901926
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/gnomes.dm
@@ -0,0 +1,25 @@
+// Gnomes
+/datum/seed/gnomes
+ name = "gnomes"
+ seed_name = "gnomes"
+ display_name = "gnomes"
+ force_layer = 3
+ chems = list("magicdust" = list(5,20))
+
+/datum/seed/gnomes/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_PLANT_ICON,"gnomes")
+ set_trait(TRAIT_PRODUCT_ICON,"gnomes")
+ set_trait(TRAIT_PRODUCT_COLOUR,"")
+ set_trait(TRAIT_FLESH_COLOUR,"")
+ set_trait(TRAIT_PLANT_COLOUR,"")
+ set_trait(TRAIT_BIOLUM_COLOUR,"#fff200")
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_BIOLUM,1)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_SPREAD,1)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_REQUIRES_NUTRIENTS,0)
+ set_trait(TRAIT_REQUIRES_WATER,0)
diff --git a/code/modules/hydroponics/seedtypes/grapes.dm b/code/modules/hydroponics/seedtypes/grapes.dm
new file mode 100644
index 0000000000..e61978e5f0
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/grapes.dm
@@ -0,0 +1,33 @@
+//Grapes/varieties
+/datum/seed/grapes
+ name = "grapes"
+ seed_name = "grape"
+ display_name = "grapevines"
+ kitchen_tag = "grapes"
+ mutants = list("greengrapes")
+ chems = list("nutriment" = list(1,10), "sugar" = list(1,5), "grapejuice" = list(10,10))
+
+/datum/seed/grapes/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,3)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"grapes")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#BB6AC4")
+ set_trait(TRAIT_PLANT_COLOUR,"#378F2E")
+ set_trait(TRAIT_PLANT_ICON,"vine")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
+
+/datum/seed/grapes/green
+ name = "greengrapes"
+ seed_name = "green grape"
+ display_name = "green grapevines"
+ mutants = null
+ chems = list("nutriment" = list(1,10), "kelotane" = list(3,5), "grapejuice" = list(10,10))
+
+/datum/seed/grapes/green/New()
+ ..()
+ set_trait(TRAIT_PRODUCT_COLOUR,"42ed2f")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/grass.dm b/code/modules/hydroponics/seedtypes/grass.dm
new file mode 100644
index 0000000000..0a94f9707f
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/grass.dm
@@ -0,0 +1,19 @@
+/datum/seed/grass
+ name = "grass"
+ seed_name = "grass"
+ display_name = "grass"
+ kitchen_tag = "grass"
+ chems = list("nutriment" = list(1,20))
+
+/datum/seed/grass/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,2)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,5)
+ set_trait(TRAIT_PRODUCT_ICON,"grass")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#09FF00")
+ set_trait(TRAIT_PLANT_COLOUR,"#07D900")
+ set_trait(TRAIT_PLANT_ICON,"grass")
+ set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/jurlmah.dm b/code/modules/hydroponics/seedtypes/jurlmah.dm
new file mode 100644
index 0000000000..61e810b9da
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/jurlmah.dm
@@ -0,0 +1,15 @@
+/datum/seed/jurlmah
+ name = "jurlmah"
+ seed_name = "jurl'mah"
+ display_name = "jurl'mah reeds"
+ kitchen_tag = "jurlmah"
+ chems = list("serotrotium" = list(1,5),"nutriment" = list(1,5))
+
+/datum/seed/jurlmah/New()
+ ..()
+ set_trait(TRAIT_PLANT_ICON,"mushroom9")
+ set_trait(TRAIT_ENDURANCE,12)
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,9)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,10)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/kudzu.dm b/code/modules/hydroponics/seedtypes/kudzu.dm
new file mode 100644
index 0000000000..336c205b25
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/kudzu.dm
@@ -0,0 +1,19 @@
+/datum/seed/kudzu
+ name = "kudzu"
+ seed_name = "kudzu"
+ display_name = "kudzu vines"
+ kitchen_tag = "kudzu"
+ chems = list("nutriment" = list(1,50), "anti_toxin" = list(1,25))
+
+/datum/seed/kudzu/New()
+ ..()
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_SPREAD,2)
+ set_trait(TRAIT_PRODUCT_ICON,"treefruit")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#96D278")
+ set_trait(TRAIT_PLANT_COLOUR,"#6F7A63")
+ set_trait(TRAIT_PLANT_ICON,"vine2")
+ set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/lettuce.dm b/code/modules/hydroponics/seedtypes/lettuce.dm
new file mode 100644
index 0000000000..ae2830f88a
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/lettuce.dm
@@ -0,0 +1,34 @@
+// Lettuce/varieties.
+/datum/seed/lettuce
+ name = "lettuce"
+ seed_name = "lettuce"
+ display_name = "lettuce"
+ kitchen_tag = "cabbage"
+ chems = list("nutriment" = list(1,15))
+
+/datum/seed/lettuce/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,4)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,6)
+ set_trait(TRAIT_POTENCY,8)
+ set_trait(TRAIT_PRODUCT_ICON,"lettuce")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#A8D0A7")
+ set_trait(TRAIT_PLANT_COLOUR,"#6D9C6B")
+ set_trait(TRAIT_PLANT_ICON,"vine2")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+ set_trait(TRAIT_WATER_CONSUMPTION, 8)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.13)
+
+/datum/seed/lettuce/ice
+ name = "siflettuce"
+ seed_name = "glacial lettuce"
+ display_name = "glacial lettuce"
+ kitchen_tag = "icelettuce"
+ chems = list("nutriment" = list(1,5), "paracetamol" = list(0,2))
+
+/datum/seed/lettuce/ice/New()
+ ..()
+ set_trait(TRAIT_ALTER_TEMP, -5)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#9ABCC9")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/malanitear.dm b/code/modules/hydroponics/seedtypes/malanitear.dm
new file mode 100644
index 0000000000..15b62d23d4
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/malanitear.dm
@@ -0,0 +1,19 @@
+/datum/seed/mtear
+ name = "mtear"
+ seed_name = "Malani's tear"
+ display_name = "Malani's tear leaves"
+ kitchen_tag = "mtear"
+ chems = list("honey" = list(1,10), "kelotane" = list(3,5))
+
+/datum/seed/mtear/New()
+ ..()
+ set_trait(TRAIT_MATURATION,3)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"alien4")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#4CC5C7")
+ set_trait(TRAIT_PLANT_COLOUR,"#4CC789")
+ set_trait(TRAIT_PLANT_ICON,"bush7")
+ set_trait(TRAIT_IDEAL_HEAT, 283)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/mushrooms.dm b/code/modules/hydroponics/seedtypes/mushrooms.dm
new file mode 100644
index 0000000000..ceb6b0a33b
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/mushrooms.dm
@@ -0,0 +1,200 @@
+//Mushrooms/varieties.
+/datum/seed/mushroom
+ name = "mushrooms"
+ seed_name = "chanterelle"
+ seed_noun = "spores"
+ display_name = "chanterelle mushrooms"
+ mutants = list("reishi","amanita","plumphelmet")
+ chems = list("nutriment" = list(1,25))
+ splat_type = /obj/effect/plant
+ kitchen_tag = "mushroom"
+
+/datum/seed/mushroom/New()
+ ..()
+ set_trait(TRAIT_MATURATION,7)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,5)
+ set_trait(TRAIT_POTENCY,1)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom4")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#DBDA72")
+ set_trait(TRAIT_PLANT_COLOUR,"#D9C94E")
+ set_trait(TRAIT_PLANT_ICON,"mushroom")
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
+ set_trait(TRAIT_IDEAL_HEAT, 288)
+ set_trait(TRAIT_LIGHT_TOLERANCE, 6)
+
+/datum/seed/mushroom/mold
+ name = "mold"
+ seed_name = "brown mold"
+ display_name = "brown mold"
+ mutants = null
+
+/datum/seed/mushroom/mold/New()
+ ..()
+ set_trait(TRAIT_SPREAD,1)
+ set_trait(TRAIT_MATURATION,10)
+ set_trait(TRAIT_YIELD,-1)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom5")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#7A5F20")
+ set_trait(TRAIT_PLANT_COLOUR,"#7A5F20")
+ set_trait(TRAIT_PLANT_ICON,"mushroom9")
+
+/datum/seed/mushroom/plump
+ name = "plumphelmet"
+ seed_name = "plump helmet"
+ display_name = "plump helmet mushrooms"
+ mutants = list("walkingmushroom","towercap")
+ chems = list("nutriment" = list(2,10))
+ kitchen_tag = "plumphelmet"
+
+/datum/seed/mushroom/plump/New()
+ ..()
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,0)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom10")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#B57BB0")
+ set_trait(TRAIT_PLANT_COLOUR,"#9E4F9D")
+ set_trait(TRAIT_PLANT_ICON,"mushroom2")
+
+/datum/seed/mushroom/hallucinogenic
+ name = "reishi"
+ seed_name = "reishi"
+ display_name = "reishi"
+ mutants = list("libertycap","glowshroom")
+ chems = list("nutriment" = list(1,50), "psilocybin" = list(3,5))
+
+/datum/seed/mushroom/hallucinogenic/New()
+ ..()
+ set_trait(TRAIT_MATURATION,10)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,15)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom11")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FFB70F")
+ set_trait(TRAIT_PLANT_COLOUR,"#F58A18")
+ set_trait(TRAIT_PLANT_ICON,"mushroom6")
+
+/datum/seed/mushroom/hallucinogenic/strong
+ name = "libertycap"
+ seed_name = "liberty cap"
+ display_name = "liberty cap mushrooms"
+ mutants = null
+ chems = list("nutriment" = list(1), "stoxin" = list(3,3), "space_drugs" = list(1,25))
+
+/datum/seed/mushroom/hallucinogenic/strong/New()
+ ..()
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_POTENCY,15)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom8")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#F2E550")
+ set_trait(TRAIT_PLANT_COLOUR,"#D1CA82")
+ set_trait(TRAIT_PLANT_ICON,"mushroom3")
+
+/datum/seed/mushroom/poison
+ name = "amanita"
+ seed_name = "fly amanita"
+ display_name = "fly amanita mushrooms"
+ mutants = list("destroyingangel","plastic")
+ chems = list("nutriment" = list(1), "amatoxin" = list(3,3), "psilocybin" = list(1,25))
+
+/datum/seed/mushroom/poison/New()
+ ..()
+ set_trait(TRAIT_MATURATION,10)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FF4545")
+ set_trait(TRAIT_PLANT_COLOUR,"#E0DDBA")
+ set_trait(TRAIT_PLANT_ICON,"mushroom4")
+
+/datum/seed/mushroom/poison/death
+ name = "destroyingangel"
+ seed_name = "destroying angel"
+ display_name = "destroying angel mushrooms"
+ mutants = null
+ chems = list("nutriment" = list(1,50), "amatoxin" = list(13,3), "psilocybin" = list(1,25))
+
+/datum/seed/mushroom/poison/death/New()
+ ..()
+ set_trait(TRAIT_MATURATION,12)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,35)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom3")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#EDE8EA")
+ set_trait(TRAIT_PLANT_COLOUR,"#E6D8DD")
+ set_trait(TRAIT_PLANT_ICON,"mushroom5")
+
+/datum/seed/mushroom/towercap
+ name = "towercap"
+ seed_name = "tower cap"
+ display_name = "tower caps"
+ chems = list("woodpulp" = list(10,1))
+ mutants = null
+ has_item_product = /obj/item/stack/material/log
+
+/datum/seed/mushroom/towercap/New()
+ ..()
+ set_trait(TRAIT_MATURATION,15)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom7")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#79A36D")
+ set_trait(TRAIT_PLANT_COLOUR,"#857F41")
+ set_trait(TRAIT_PLANT_ICON,"mushroom8")
+
+/datum/seed/mushroom/glowshroom
+ name = "glowshroom"
+ seed_name = "glowshroom"
+ display_name = "glowshrooms"
+ mutants = null
+ chems = list("radium" = list(1,20))
+
+/datum/seed/mushroom/glowshroom/New()
+ ..()
+ set_trait(TRAIT_SPREAD,1)
+ set_trait(TRAIT_MATURATION,15)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,30)
+ set_trait(TRAIT_BIOLUM,1)
+ set_trait(TRAIT_BIOLUM_COLOUR,"#006622")
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom2")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#DDFAB6")
+ set_trait(TRAIT_PLANT_COLOUR,"#EFFF8A")
+ set_trait(TRAIT_PLANT_ICON,"mushroom7")
+
+/datum/seed/mushroom/plastic
+ name = "plastic"
+ seed_name = "plastellium"
+ display_name = "plastellium"
+ mutants = null
+ chems = list("plasticide" = list(1,10))
+
+/datum/seed/mushroom/plastic/New()
+ ..()
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,6)
+ set_trait(TRAIT_POTENCY,20)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom6")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#E6E6E6")
+ set_trait(TRAIT_PLANT_COLOUR,"#E6E6E6")
+ set_trait(TRAIT_PLANT_ICON,"mushroom10")
+
+/datum/seed/mushroom/spore
+ name = "sporeshroom"
+ seed_name = "corpellian"
+ display_name = "corpellian"
+ mutants = null
+ chems = list("serotrotium" = list(5,10), "mold" = list(1,10))
+
+/datum/seed/mushroom/spore/New()
+ ..()
+ set_trait(TRAIT_MATURATION,15)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,20)
+ set_trait(TRAIT_PRODUCT_ICON,"mushroom5")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#e29cd2")
+ set_trait(TRAIT_PLANT_COLOUR,"#f8e6f4")
+ set_trait(TRAIT_PLANT_ICON,"mushroom9")
+ set_trait(TRAIT_SPORING, TRUE)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/nettles.dm b/code/modules/hydroponics/seedtypes/nettles.dm
new file mode 100644
index 0000000000..5a1073c6fc
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/nettles.dm
@@ -0,0 +1,35 @@
+// Nettles/variants.
+/datum/seed/nettle
+ name = "nettle"
+ seed_name = "nettle"
+ display_name = "nettles"
+ mutants = list("deathnettle")
+ chems = list("nutriment" = list(1,50), "sacid" = list(0,1))
+ kitchen_tag = "nettle"
+
+/datum/seed/nettle/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_STINGS,1)
+ set_trait(TRAIT_PLANT_ICON,"bush5")
+ set_trait(TRAIT_PRODUCT_ICON,"nettles")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#728A54")
+
+/datum/seed/nettle/death
+ name = "deathnettle"
+ seed_name = "death nettle"
+ display_name = "death nettles"
+ kitchen_tag = "deathnettle"
+ mutants = null
+ chems = list("nutriment" = list(1,50), "pacid" = list(0,1))
+
+/datum/seed/nettle/death/New()
+ ..()
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#8C5030")
+ set_trait(TRAIT_PLANT_COLOUR,"#634941")
diff --git a/code/modules/hydroponics/seedtypes/onion.dm b/code/modules/hydroponics/seedtypes/onion.dm
new file mode 100644
index 0000000000..2123ad2b38
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/onion.dm
@@ -0,0 +1,17 @@
+/datum/seed/onion
+ name = "onion"
+ seed_name = "onion"
+ display_name = "onions"
+ kitchen_tag = "onion"
+ chems = list("nutriment" = list(1,10))
+
+/datum/seed/onion/New()
+ ..()
+ set_trait(TRAIT_MATURATION,10)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"onion")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#E0C367")
+ set_trait(TRAIT_PLANT_ICON,"carrot")
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/peanuts.dm b/code/modules/hydroponics/seedtypes/peanuts.dm
new file mode 100644
index 0000000000..cc710d25ca
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/peanuts.dm
@@ -0,0 +1,19 @@
+//Everything else
+/datum/seed/peanuts
+ name = "peanut"
+ seed_name = "peanut"
+ display_name = "peanut vines"
+ kitchen_tag = "peanut"
+ chems = list("nutriment" = list(1,10), "peanutoil" = list(3,10))
+
+/datum/seed/peanuts/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,6)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"nuts")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#C4AE7A")
+ set_trait(TRAIT_PLANT_ICON,"bush2")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/potato.dm b/code/modules/hydroponics/seedtypes/potato.dm
new file mode 100644
index 0000000000..8aad55afc6
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/potato.dm
@@ -0,0 +1,18 @@
+/datum/seed/potato
+ name = "potato"
+ seed_name = "potato"
+ display_name = "potatoes"
+ kitchen_tag = "potato"
+ chems = list("nutriment" = list(1,10), "potatojuice" = list(10,10))
+
+/datum/seed/potato/New()
+ ..()
+ set_trait(TRAIT_PRODUCES_POWER,1)
+ set_trait(TRAIT_MATURATION,10)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"potato")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#D4CAB4")
+ set_trait(TRAIT_PLANT_ICON,"bush2")
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/pumpkin.dm b/code/modules/hydroponics/seedtypes/pumpkin.dm
new file mode 100644
index 0000000000..916d44e58b
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/pumpkin.dm
@@ -0,0 +1,19 @@
+/datum/seed/pumpkin
+ name = "pumpkin"
+ seed_name = "pumpkin"
+ display_name = "pumpkin vine"
+ kitchen_tag = "pumpkin"
+ chems = list("nutriment" = list(1,6))
+
+/datum/seed/pumpkin/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"vine2")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#DBAC02")
+ set_trait(TRAIT_PLANT_COLOUR,"#21661E")
+ set_trait(TRAIT_PLANT_ICON,"vine2")
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/rhubarb.dm b/code/modules/hydroponics/seedtypes/rhubarb.dm
new file mode 100644
index 0000000000..f3ee13ce41
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/rhubarb.dm
@@ -0,0 +1,17 @@
+/datum/seed/rhubarb
+ name = "rhubarb"
+ seed_name = "rhubarb"
+ display_name = "rhubarb"
+ kitchen_tag = "rhubarb"
+ chems = list("nutriment" = list(1,15))
+
+/datum/seed/rhubarb/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,3)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,5)
+ set_trait(TRAIT_POTENCY,6)
+ set_trait(TRAIT_PRODUCT_ICON,"stalk")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FD5656")
+ set_trait(TRAIT_PLANT_ICON,"stalk3")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/rice.dm b/code/modules/hydroponics/seedtypes/rice.dm
new file mode 100644
index 0000000000..413c43b9fc
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/rice.dm
@@ -0,0 +1,19 @@
+/datum/seed/rice
+ name = "rice"
+ seed_name = "rice"
+ display_name = "rice stalks"
+ kitchen_tag = "rice"
+ chems = list("nutriment" = list(1,25), "rice" = list(10,15))
+
+/datum/seed/rice/New()
+ ..()
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,5)
+ set_trait(TRAIT_PRODUCT_ICON,"rice")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#D5E6D1")
+ set_trait(TRAIT_PLANT_COLOUR,"#8ED17D")
+ set_trait(TRAIT_PLANT_ICON,"stalk2")
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/selemhand.dm b/code/modules/hydroponics/seedtypes/selemhand.dm
new file mode 100644
index 0000000000..5b49728c61
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/selemhand.dm
@@ -0,0 +1,19 @@
+/datum/seed/shand
+ name = "shand"
+ seed_name = "Selem's hand"
+ display_name = "Selem's hand leaves"
+ kitchen_tag = "shand"
+ chems = list("bicaridine" = list(0,10))
+
+/datum/seed/shand/New()
+ ..()
+ set_trait(TRAIT_MATURATION,3)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"alien3")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#378C61")
+ set_trait(TRAIT_PLANT_COLOUR,"#378C61")
+ set_trait(TRAIT_PLANT_ICON,"tree5")
+ set_trait(TRAIT_IDEAL_HEAT, 283)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/soybean.dm b/code/modules/hydroponics/seedtypes/soybean.dm
new file mode 100644
index 0000000000..22329be263
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/soybean.dm
@@ -0,0 +1,17 @@
+/datum/seed/soybean
+ name = "soybean"
+ seed_name = "soybean"
+ display_name = "soybeans"
+ kitchen_tag = "soybeans"
+ chems = list("nutriment" = list(1,20), "soymilk" = list(10,20))
+
+/datum/seed/soybean/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,4)
+ set_trait(TRAIT_PRODUCTION,4)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,5)
+ set_trait(TRAIT_PRODUCT_ICON,"bean")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#EBE7C0")
+ set_trait(TRAIT_PLANT_ICON,"stalk")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/spineapple.dm b/code/modules/hydroponics/seedtypes/spineapple.dm
new file mode 100644
index 0000000000..b8ff58f597
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/spineapple.dm
@@ -0,0 +1,22 @@
+/datum/seed/spineapple
+ name = "spineapple"
+ seed_name = "spineapple"
+ display_name = "spineapple"
+ kitchen_tag = "pineapple"
+ chems = list("nutriment" = list(1,5), "enzyme" = list(1,5), "pineapplejuice" = list(1, 20))
+
+/datum/seed/spineapple/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,10)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,1)
+ set_trait(TRAIT_POTENCY,13)
+ set_trait(TRAIT_PRODUCT_ICON,"pineapple")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FFF23B")
+ set_trait(TRAIT_PLANT_COLOUR,"#87C969")
+ set_trait(TRAIT_PLANT_ICON,"corn")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
+ set_trait(TRAIT_IDEAL_LIGHT, 4)
+ set_trait(TRAIT_WATER_CONSUMPTION, 8)
+ set_trait(TRAIT_STINGS,1)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/sugarcane.dm b/code/modules/hydroponics/seedtypes/sugarcane.dm
new file mode 100644
index 0000000000..c670500a1d
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/sugarcane.dm
@@ -0,0 +1,19 @@
+/datum/seed/sugarcane
+ name = "sugarcane"
+ seed_name = "sugarcane"
+ display_name = "sugarcanes"
+ kitchen_tag = "sugarcanes"
+ chems = list("sugar" = list(4,5))
+
+/datum/seed/sugarcane/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,3)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"stalk")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#B4D6BD")
+ set_trait(TRAIT_PLANT_COLOUR,"#6BBD68")
+ set_trait(TRAIT_PLANT_ICON,"stalk3")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/surik.dm b/code/modules/hydroponics/seedtypes/surik.dm
new file mode 100644
index 0000000000..8ea521995c
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/surik.dm
@@ -0,0 +1,15 @@
+/datum/seed/surik
+ name = "surik"
+ seed_name = "surik"
+ display_name = "surik vine"
+ kitchen_tag = "surik"
+ chems = list("impedrezene" = list(1,3),"synaptizine" = list(1,2),"nutriment" = list(1,5))
+
+/datum/seed/surik/New()
+ ..()
+ set_trait(TRAIT_PLANT_ICON,"bush6")
+ set_trait(TRAIT_ENDURANCE,18)
+ set_trait(TRAIT_MATURATION,7)
+ set_trait(TRAIT_PRODUCTION,7)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,3)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/telriis.dm b/code/modules/hydroponics/seedtypes/telriis.dm
new file mode 100644
index 0000000000..47c577b787
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/telriis.dm
@@ -0,0 +1,16 @@
+/datum/seed/telriis
+ name = "telriis"
+ seed_name = "telriis"
+ display_name = "telriis grass"
+ kitchen_tag = "telriis"
+ chems = list("pwine" = list(1,5), "nutriment" = list(1,6))
+
+/datum/seed/telriis/New()
+ ..()
+ set_trait(TRAIT_PLANT_ICON,"ambrosia")
+ set_trait(TRAIT_PRODUCT_ICON,"ambrosia")
+ set_trait(TRAIT_ENDURANCE,50)
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,5)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/thaadra.dm b/code/modules/hydroponics/seedtypes/thaadra.dm
new file mode 100644
index 0000000000..209b495c82
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/thaadra.dm
@@ -0,0 +1,16 @@
+/datum/seed/thaadra
+ name = "thaadra"
+ seed_name = "thaa'dra"
+ display_name = "thaa'dra lichen"
+ kitchen_tag = "thaadra"
+ chems = list("frostoil" = list(1,5),"nutriment" = list(1,5))
+
+/datum/seed/thaadra/New()
+ ..()
+ set_trait(TRAIT_PLANT_ICON,"grass")
+ set_trait(TRAIT_PLANT_COLOUR,"#ABC7D2")
+ set_trait(TRAIT_ENDURANCE,10)
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,9)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,5)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/tomatoes.dm b/code/modules/hydroponics/seedtypes/tomatoes.dm
new file mode 100644
index 0000000000..3454d69952
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/tomatoes.dm
@@ -0,0 +1,75 @@
+//Tomatoes/variants.
+/datum/seed/tomato
+ name = "tomato"
+ seed_name = "tomato"
+ display_name = "tomato plant"
+ mutants = list("bluetomato","bloodtomato")
+ chems = list("nutriment" = list(1,10), "tomatojuice" = list(10,10))
+ kitchen_tag = "tomato"
+
+/datum/seed/tomato/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_JUICY,1)
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"tomato")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#D10000")
+ set_trait(TRAIT_PLANT_ICON,"bush3")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25)
+
+/datum/seed/tomato/blood
+ name = "bloodtomato"
+ seed_name = "blood tomato"
+ display_name = "blood tomato plant"
+ mutants = list("killertomato")
+ chems = list("nutriment" = list(1,10), "blood" = list(1,5))
+ splat_type = /obj/effect/decal/cleanable/blood/splatter
+
+/datum/seed/tomato/blood/New()
+ ..()
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FF0000")
+
+/datum/seed/tomato/killer
+ name = "killertomato"
+ seed_name = "killer tomato"
+ display_name = "killer tomato plant"
+ mutants = null
+ can_self_harvest = 1
+ has_mob_product = /mob/living/simple_mob/tomato
+
+/datum/seed/tomato/killer/New()
+ ..()
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#A86747")
+
+/datum/seed/tomato/blue
+ name = "bluetomato"
+ seed_name = "blue tomato"
+ display_name = "blue tomato plant"
+ mutants = list("bluespacetomato")
+ chems = list("nutriment" = list(1,20), "lube" = list(1,5))
+
+/datum/seed/tomato/blue/New()
+ ..()
+ set_trait(TRAIT_PRODUCT_COLOUR,"#4D86E8")
+ set_trait(TRAIT_PLANT_COLOUR,"#070AAD")
+
+/datum/seed/tomato/blue/teleport
+ name = "bluespacetomato"
+ seed_name = "bluespace tomato"
+ display_name = "bluespace tomato plant"
+ mutants = null
+ chems = list("nutriment" = list(1,20), "singulo" = list(10,5))
+
+/datum/seed/tomato/blue/teleport/New()
+ ..()
+ set_trait(TRAIT_TELEPORTING,1)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#00E5FF")
+ set_trait(TRAIT_BIOLUM,1)
+ set_trait(TRAIT_BIOLUM_COLOUR,"#4DA4A8")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/vale.dm b/code/modules/hydroponics/seedtypes/vale.dm
new file mode 100644
index 0000000000..166fafcf97
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/vale.dm
@@ -0,0 +1,15 @@
+/datum/seed/vale
+ name = "vale"
+ seed_name = "vale"
+ display_name = "vale bush"
+ kitchen_tag = "vale"
+ chems = list("paracetamol" = list(1,5),"dexalin" = list(1,2),"nutriment"= list(1,5))
+
+/datum/seed/vale/New()
+ ..()
+ set_trait(TRAIT_PLANT_ICON,"flower4")
+ set_trait(TRAIT_ENDURANCE,15)
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,10)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,3)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/vanilla.dm b/code/modules/hydroponics/seedtypes/vanilla.dm
new file mode 100644
index 0000000000..a2bc5c8dcf
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/vanilla.dm
@@ -0,0 +1,19 @@
+/datum/seed/vanilla
+ name = "vanilla"
+ seed_name = "vanilla"
+ display_name = "vanilla"
+ kitchen_tag = "vanilla"
+ chems = list("nutriment" = list(1,10), "vanilla" = list(2,8), "sugar" = list(1, 4))
+
+/datum/seed/vanilla/New()
+ ..()
+ set_trait(TRAIT_MATURATION,7)
+ set_trait(TRAIT_PRODUCTION,5)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_PRODUCT_ICON,"chili")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#B57EDC")
+ set_trait(TRAIT_PLANT_COLOUR,"#6B8C5E")
+ set_trait(TRAIT_PLANT_ICON,"bush5")
+ set_trait(TRAIT_IDEAL_LIGHT, 8)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.3)
+ set_trait(TRAIT_WATER_CONSUMPTION, 0.5)
diff --git a/code/modules/hydroponics/seedtypes/wabback.dm b/code/modules/hydroponics/seedtypes/wabback.dm
new file mode 100644
index 0000000000..8c1e9411f0
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/wabback.dm
@@ -0,0 +1,54 @@
+//Wabback / varieties.
+/datum/seed/wabback
+ name = "whitewabback"
+ seed_name = "white wabback"
+ seed_noun = "nodes"
+ display_name = "white wabback"
+ chems = list("nutriment" = list(1,10), "protein" = list(1,5), "enzyme" = list(0,3))
+ kitchen_tag = "wabback"
+ mutants = list("blackwabback","wildwabback")
+ has_item_product = /obj/item/stack/material/cloth
+
+/datum/seed/wabback/New()
+ ..()
+ set_trait(TRAIT_IDEAL_LIGHT, 5)
+ set_trait(TRAIT_MATURATION,8)
+ set_trait(TRAIT_PRODUCTION,3)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,5)
+ set_trait(TRAIT_PRODUCT_ICON,"carrot2")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#E6EDFA")
+ set_trait(TRAIT_PLANT_ICON,"chute")
+ set_trait(TRAIT_PLANT_COLOUR, "#0650ce")
+ set_trait(TRAIT_WATER_CONSUMPTION, 10)
+ set_trait(TRAIT_ALTER_TEMP, -1)
+ set_trait(TRAIT_CARNIVOROUS,1)
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_SPREAD,1)
+
+/datum/seed/wabback/vine
+ name = "blackwabback"
+ seed_name = "black wabback"
+ display_name = "black wabback"
+ mutants = null
+ chems = list("nutriment" = list(1,3), "protein" = list(1,10), "serotrotium_v" = list(0,1))
+
+/datum/seed/wabback/vine/New()
+ ..()
+ set_trait(TRAIT_PRODUCT_COLOUR,"#2E2F32")
+ set_trait(TRAIT_CARNIVOROUS,2)
+
+/datum/seed/wabback/wild
+ name = "wildwabback"
+ seed_name = "wild wabback"
+ display_name = "wild wabback"
+ mutants = list("whitewabback")
+ has_item_product = null
+ chems = list("nutriment" = list(1,15), "protein" = list(0,2), "enzyme" = list(0,1))
+
+/datum/seed/wabback/wild/New()
+ ..()
+ set_trait(TRAIT_IDEAL_LIGHT, 3)
+ set_trait(TRAIT_WATER_CONSUMPTION, 7)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.1)
+ set_trait(TRAIT_YIELD,5)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/watermelon.dm b/code/modules/hydroponics/seedtypes/watermelon.dm
new file mode 100644
index 0000000000..79ae157295
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/watermelon.dm
@@ -0,0 +1,23 @@
+/datum/seed/watermelon
+ name = "watermelon"
+ seed_name = "watermelon"
+ display_name = "watermelon vine"
+ kitchen_tag = "watermelon"
+ chems = list("nutriment" = list(1,6), "watermelonjuice" = list(10,6))
+
+/datum/seed/watermelon/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_JUICY,1)
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,3)
+ set_trait(TRAIT_POTENCY,1)
+ set_trait(TRAIT_PRODUCT_ICON,"vine")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#3D8C3A")
+ set_trait(TRAIT_PLANT_COLOUR,"#257522")
+ set_trait(TRAIT_PLANT_ICON,"vine2")
+ set_trait(TRAIT_FLESH_COLOUR,"#F22C2C")
+ set_trait(TRAIT_IDEAL_HEAT, 298)
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/weeds.dm b/code/modules/hydroponics/seedtypes/weeds.dm
new file mode 100644
index 0000000000..9a867174b8
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/weeds.dm
@@ -0,0 +1,16 @@
+/datum/seed/weeds
+ name = "weeds"
+ seed_name = "weed"
+ display_name = "weeds"
+
+/datum/seed/weeds/New()
+ ..()
+ set_trait(TRAIT_MATURATION,5)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,-1)
+ set_trait(TRAIT_POTENCY,-1)
+ set_trait(TRAIT_IMMUTABLE,-1)
+ set_trait(TRAIT_PRODUCT_ICON,"flower4")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#FCEB2B")
+ set_trait(TRAIT_PLANT_COLOUR,"#59945A")
+ set_trait(TRAIT_PLANT_ICON,"bush6")
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/wheat.dm b/code/modules/hydroponics/seedtypes/wheat.dm
new file mode 100644
index 0000000000..a657490c15
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/wheat.dm
@@ -0,0 +1,19 @@
+/datum/seed/wheat
+ name = "wheat"
+ seed_name = "wheat"
+ display_name = "wheat stalks"
+ kitchen_tag = "wheat"
+ chems = list("nutriment" = list(1,25), "flour" = list(10,30))
+
+/datum/seed/wheat/New()
+ ..()
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,4)
+ set_trait(TRAIT_POTENCY,5)
+ set_trait(TRAIT_PRODUCT_ICON,"wheat")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#DBD37D")
+ set_trait(TRAIT_PLANT_COLOUR,"#BFAF82")
+ set_trait(TRAIT_PLANT_ICON,"stalk2")
+ set_trait(TRAIT_IDEAL_LIGHT, 6)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.15)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/whitebeets.dm b/code/modules/hydroponics/seedtypes/whitebeets.dm
new file mode 100644
index 0000000000..3534fcc7ff
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/whitebeets.dm
@@ -0,0 +1,18 @@
+/datum/seed/whitebeets
+ name = "whitebeet"
+ seed_name = "white-beet"
+ display_name = "white-beets"
+ kitchen_tag = "whitebeet"
+ chems = list("nutriment" = list(0,20), "sugar" = list(1,5))
+
+/datum/seed/whitebeets/New()
+ ..()
+ set_trait(TRAIT_MATURATION,6)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,6)
+ set_trait(TRAIT_POTENCY,10)
+ set_trait(TRAIT_PRODUCT_ICON,"carrot2")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#EEF5B0")
+ set_trait(TRAIT_PLANT_COLOUR,"#4D8F53")
+ set_trait(TRAIT_PLANT_ICON,"carrot2")
+ set_trait(TRAIT_WATER_CONSUMPTION, 6)
\ No newline at end of file
diff --git a/code/modules/hydroponics/seedtypes/wurmwoad.dm b/code/modules/hydroponics/seedtypes/wurmwoad.dm
new file mode 100644
index 0000000000..bb4df620a2
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/wurmwoad.dm
@@ -0,0 +1,23 @@
+// Wurmwoad, the Space Spice maker. Totally is actually, 100% literal worms.
+
+/datum/seed/wurmwoad
+ name = "wurmwoad"
+ seed_name = "wurmwoad"
+ display_name = "wurmwoad growth"
+ chems = list("nutriment" = list(1,10), "spacespice" = list(5,15))
+ kitchen_tag = "wurmwoad"
+
+/datum/seed/wurmwoad/New()
+ ..()
+ set_trait(TRAIT_HARVEST_REPEAT,1)
+ set_trait(TRAIT_MATURATION,7)
+ set_trait(TRAIT_PRODUCTION,6)
+ set_trait(TRAIT_YIELD,2)
+ set_trait(TRAIT_POTENCY,8)
+ set_trait(TRAIT_PRODUCT_ICON,"eyepod")
+ set_trait(TRAIT_PRODUCT_COLOUR,"#e08702")
+ set_trait(TRAIT_PLANT_COLOUR,"#f1d1d2")
+ set_trait(TRAIT_PLANT_ICON,"worm")
+ set_trait(TRAIT_IDEAL_LIGHT, 1)
+ set_trait(TRAIT_WATER_CONSUMPTION, 8)
+ set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0.25)
diff --git a/code/modules/hydroponics/seedtypes/xeno.dm b/code/modules/hydroponics/seedtypes/xeno.dm
new file mode 100644
index 0000000000..2b1acd76b0
--- /dev/null
+++ b/code/modules/hydroponics/seedtypes/xeno.dm
@@ -0,0 +1,19 @@
+// Alien weeds.
+/datum/seed/xenomorph
+ name = "xenomorph"
+ seed_name = "alien weed"
+ display_name = "alien weeds"
+ force_layer = 3
+ chems = list("phoron" = list(1,3))
+
+/datum/seed/xenomorph/New()
+ ..()
+ set_trait(TRAIT_PLANT_ICON,"vine2")
+ set_trait(TRAIT_IMMUTABLE,1)
+ set_trait(TRAIT_PRODUCT_COLOUR,"#3D1934")
+ set_trait(TRAIT_FLESH_COLOUR,"#3D1934")
+ set_trait(TRAIT_PLANT_COLOUR,"#3D1934")
+ set_trait(TRAIT_PRODUCTION,1)
+ set_trait(TRAIT_YIELD,-1)
+ set_trait(TRAIT_SPREAD,2)
+ set_trait(TRAIT_POTENCY,50)
\ No newline at end of file
diff --git a/code/modules/hydroponics/trays/tray_tools.dm b/code/modules/hydroponics/trays/tray_tools.dm
index d05922b2f9..cedcc3f8b9 100644
--- a/code/modules/hydroponics/trays/tray_tools.dm
+++ b/code/modules/hydroponics/trays/tray_tools.dm
@@ -19,6 +19,10 @@
var/datum/seed/last_seed
var/list/last_reagents
+/obj/item/device/analyzer/plant_analyzer/Destroy()
+ . = ..()
+ QDEL_NULL(last_seed)
+
/obj/item/device/analyzer/plant_analyzer/attack_self(mob/user)
tgui_interact(user)
@@ -34,7 +38,7 @@
/obj/item/device/analyzer/plant_analyzer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
- var/datum/seed/grown_seed = locate(last_seed)
+ var/datum/seed/grown_seed = last_seed
if(!istype(grown_seed))
return list("no_seed" = TRUE)
@@ -95,7 +99,9 @@
to_chat(user, "[src] can tell you nothing about \the [target].")
return
- last_seed = REF(grown_seed)
+ last_seed = grown_seed.diverge()
+ if(!istype(last_seed))
+ last_seed = grown_seed // TRAIT_IMMUTABLE makes diverge() return null
user.visible_message("[user] runs the scanner over \the [target].")
@@ -119,7 +125,7 @@
print_report(usr)
/obj/item/device/analyzer/plant_analyzer/proc/print_report(var/mob/living/user)
- var/datum/seed/grown_seed = locate(last_seed)
+ var/datum/seed/grown_seed = last_seed
if(!istype(grown_seed))
to_chat(user, "There is no scan data to print.")
return
diff --git a/code/modules/integrated_electronics/core/assemblies/device.dm b/code/modules/integrated_electronics/core/assemblies/device.dm
index 3170393fc3..8500f4dafc 100644
--- a/code/modules/integrated_electronics/core/assemblies/device.dm
+++ b/code/modules/integrated_electronics/core/assemblies/device.dm
@@ -78,7 +78,7 @@
output.assembly = src
/obj/item/device/electronic_assembly/device/check_interactivity(mob/user)
- if(!CanInteract(user, state = deep_inventory_state))
+ if(!CanInteract(user, state = GLOB.tgui_deep_inventory_state))
return 0
return 1
diff --git a/code/modules/integrated_electronics/core/pins.dm b/code/modules/integrated_electronics/core/pins.dm
index ddc0b06f8a..c194b4a8a2 100644
--- a/code/modules/integrated_electronics/core/pins.dm
+++ b/code/modules/integrated_electronics/core/pins.dm
@@ -40,8 +40,8 @@ D [1]/ ||
holder = null
. = ..()
-/datum/integrated_io/nano_host()
- return holder.nano_host()
+/datum/integrated_io/tgui_host()
+ return holder.tgui_host()
/datum/integrated_io/proc/data_as_type(var/as_type)
diff --git a/code/modules/integrated_electronics/core/special_pins/list_pin.dm b/code/modules/integrated_electronics/core/special_pins/list_pin.dm
index 77d83f82b5..4eeb756cd0 100644
--- a/code/modules/integrated_electronics/core/special_pins/list_pin.dm
+++ b/code/modules/integrated_electronics/core/special_pins/list_pin.dm
@@ -117,7 +117,7 @@
/datum/integrated_io/list/display_pin_type()
return IC_FORMAT_LIST
-/datum/integrated_io/list/Topic(href, href_list, state = interactive_state)
+/datum/integrated_io/list/Topic(href, href_list, state = GLOB.tgui_always_state)
if(!holder.check_interactivity(usr))
return
if(..())
diff --git a/code/modules/integrated_electronics/core/tools.dm b/code/modules/integrated_electronics/core/tools.dm
index 79533bfe25..5bf48370e2 100644
--- a/code/modules/integrated_electronics/core/tools.dm
+++ b/code/modules/integrated_electronics/core/tools.dm
@@ -115,7 +115,7 @@
/obj/item/device/integrated_electronics/debugger/attack_self(mob/user)
var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null")
- if(!CanInteract(user, physical_state))
+ if(!CanInteract(user, GLOB.tgui_physical_state))
return
var/new_data = null
@@ -124,13 +124,13 @@
accepting_refs = 0
new_data = input("Now type in a string.","[src] string writing") as null|text
new_data = sanitizeSafe(new_data, MAX_MESSAGE_LEN, 0, 0)
- if(istext(new_data) && CanInteract(user, physical_state))
+ if(istext(new_data) && CanInteract(user, GLOB.tgui_physical_state))
data_to_write = new_data
to_chat(user, "You set \the [src]'s memory to \"[new_data]\".")
if("number")
accepting_refs = 0
new_data = input("Now type in a number.","[src] number writing") as null|num
- if(isnum(new_data) && CanInteract(user, physical_state))
+ if(isnum(new_data) && CanInteract(user, GLOB.tgui_physical_state))
data_to_write = new_data
to_chat(user, "You set \the [src]'s memory to [new_data].")
if("ref")
diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm
index a084633642..9c140cedae 100644
--- a/code/modules/integrated_electronics/subtypes/input.dm
+++ b/code/modules/integrated_electronics/subtypes/input.dm
@@ -54,7 +54,7 @@
/obj/item/integrated_circuit/input/numberpad/ask_for_input(mob/user)
var/new_input = input(user, "Enter a number, please.","Number pad", get_pin_data(IC_OUTPUT, 1)) as null|num
- if(isnum(new_input) && CanInteract(user, physical_state))
+ if(isnum(new_input) && CanInteract(user, GLOB.tgui_physical_state))
set_pin_data(IC_OUTPUT, 1, new_input)
push_data()
activate_pin(1)
@@ -73,7 +73,7 @@
/obj/item/integrated_circuit/input/textpad/ask_for_input(mob/user)
var/new_input = input(user, "Enter some words, please.","Number pad", get_pin_data(IC_OUTPUT, 1)) as null|text
- if(istext(new_input) && CanInteract(user, physical_state))
+ if(istext(new_input) && CanInteract(user, GLOB.tgui_physical_state))
set_pin_data(IC_OUTPUT, 1, new_input)
push_data()
activate_pin(1)
@@ -92,7 +92,7 @@
/obj/item/integrated_circuit/input/colorpad/ask_for_input(mob/user)
var/new_color = input(user, "Enter a color, please.", "Color pad", get_pin_data(IC_OUTPUT, 1)) as color|null
- if(new_color && CanInteract(user, physical_state))
+ if(new_color && CanInteract(user, GLOB.tgui_physical_state))
set_pin_data(IC_OUTPUT, 1, new_color)
push_data()
activate_pin(1)
diff --git a/code/modules/integrated_electronics/subtypes/memory.dm b/code/modules/integrated_electronics/subtypes/memory.dm
index 630136e7d0..90cb23de35 100644
--- a/code/modules/integrated_electronics/subtypes/memory.dm
+++ b/code/modules/integrated_electronics/subtypes/memory.dm
@@ -89,7 +89,7 @@
/obj/item/integrated_circuit/memory/constant/attack_self(mob/user)
var/datum/integrated_io/O = outputs[1]
var/type_to_use = input("Please choose a type to use.","[src] type setting") as null|anything in list("string","number","ref", "null")
- if(!CanInteract(user, physical_state))
+ if(!CanInteract(user, GLOB.tgui_physical_state))
return
var/new_data = null
@@ -97,13 +97,13 @@
if("string")
accepting_refs = 0
new_data = input("Now type in a string.","[src] string writing") as null|text
- if(istext(new_data) && CanInteract(user, physical_state))
+ if(istext(new_data) && CanInteract(user, GLOB.tgui_physical_state))
O.data = new_data
to_chat(user, "You set \the [src]'s memory to [O.display_data(O.data)].")
if("number")
accepting_refs = 0
new_data = input("Now type in a number.","[src] number writing") as null|num
- if(isnum(new_data) && CanInteract(user, physical_state))
+ if(isnum(new_data) && CanInteract(user, GLOB.tgui_physical_state))
O.data = new_data
to_chat(user, "You set \the [src]'s memory to [O.display_data(O.data)].")
if("ref")
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index 153e023ad0..68bb201552 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -403,8 +403,8 @@
no_variants = FALSE
pass_color = TRUE
strict_color_stacking = TRUE
- drop_sound = 'sound/items/drop/cloth.ogg'
- pickup_sound = 'sound/items/pickup/cloth.ogg'
+ drop_sound = 'sound/items/drop/clothing.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
/obj/item/stack/material/cloth/diyaab
color = "#c6ccf0"
diff --git a/code/modules/mob/living/bot/cleanbot.dm b/code/modules/mob/living/bot/cleanbot.dm
index de4c2a2d78..cdcba151bc 100644
--- a/code/modules/mob/living/bot/cleanbot.dm
+++ b/code/modules/mob/living/bot/cleanbot.dm
@@ -220,6 +220,7 @@
target_types += /obj/effect/decal/cleanable/liquid_fuel
target_types += /obj/effect/decal/cleanable/mucus
target_types += /obj/effect/decal/cleanable/dirt
+ target_types += /obj/effect/decal/cleanable/filth
if(blood)
target_types += /obj/effect/decal/cleanable/blood
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 41a43324ff..889f5281cb 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -210,7 +210,7 @@
return
spread_fire(AM)
-
+
..() // call parent because we moved behavior to parent
// Get rank from ID, ID inside PDA, PDA, ID in wallet, etc.
@@ -220,7 +220,7 @@
if (pda.id)
return pda.id.rank ? pda.id.rank : if_no_job
else
- return pda.ownrank
+ return pda.ownrank ? pda.ownrank : if_no_job
else
var/obj/item/weapon/card/id/id = get_idcard()
if(id)
@@ -236,7 +236,7 @@
if (pda.id)
return pda.id.assignment
else
- return pda.ownjob
+ return pda.ownjob ? pda.ownjob : if_no_job
else
var/obj/item/weapon/card/id/id = get_idcard()
if(id)
@@ -252,7 +252,7 @@
if (pda.id)
return pda.id.registered_name
else
- return pda.owner
+ return pda.owner ? pda.owner : if_no_id
else
var/obj/item/weapon/card/id/id = get_idcard()
if(id)
@@ -285,7 +285,7 @@
. = if_no_id
if(istype(wear_id,/obj/item/device/pda))
var/obj/item/device/pda/P = wear_id
- return P.owner
+ return P.owner ? P.owner : if_no_id
if(wear_id)
var/obj/item/weapon/card/id/I = wear_id.GetID()
if(I)
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 39ad53458b..fbf1b76b90 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -1290,13 +1290,19 @@
clear_fullscreen("blind")
clear_alert("blind")
- if(disabilities & NEARSIGHTED) //this looks meh but saves a lot of memory by not requiring to add var/prescription
- if(glasses) //to every /obj/item
+ var/apply_nearsighted_overlay = FALSE
+ if(disabilities & NEARSIGHTED)
+ apply_nearsighted_overlay = TRUE
+
+ if(glasses)
var/obj/item/clothing/glasses/G = glasses
- if(!G.prescription)
- set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
- else if (!nif || !nif.flag_check(NIF_V_CORRECTIVE,NIF_FLAGS_VISION)) //VOREStation Edit - NIF
- set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
+ if(G.prescription)
+ apply_nearsighted_overlay = FALSE
+
+ if(nif && nif.flag_check(NIF_V_CORRECTIVE, NIF_FLAGS_VISION)) // VOREStation Edit - NIF
+ apply_nearsighted_overlay = FALSE
+
+ set_fullscreen(apply_nearsighted_overlay, "nearsighted", /obj/screen/fullscreen/impaired, 1)
set_fullscreen(eye_blurry, "blurry", /obj/screen/fullscreen/blurry)
set_fullscreen(druggy, "high", /obj/screen/fullscreen/high)
diff --git a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm
index 632d45ea4d..c1c9ad064b 100644
--- a/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm
+++ b/code/modules/mob/living/carbon/human/species/shadekin/shadekin_abilities.dm
@@ -95,7 +95,7 @@
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
- if(istype(target) && vore_selected)
+ if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected)
target.forceMove(vore_selected)
to_chat(target,"\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!")
diff --git a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
index 282f8b6c3d..98f0a3190d 100644
--- a/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
+++ b/code/modules/mob/living/carbon/human/species/station/protean_vr/protean_blob.dm
@@ -257,7 +257,7 @@
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
- if(istype(target) && vore_selected)
+ if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected)
if(target.buckled)
target.buckled.unbuckle_mob(target, force = TRUE)
target.forceMove(vore_selected)
diff --git a/code/modules/mob/living/carbon/human/stripping.dm b/code/modules/mob/living/carbon/human/stripping.dm
index 61bb766140..9f926272be 100644
--- a/code/modules/mob/living/carbon/human/stripping.dm
+++ b/code/modules/mob/living/carbon/human/stripping.dm
@@ -58,14 +58,22 @@
var/stripping
var/obj/item/held = user.get_active_hand()
if(!istype(held) || is_robot_module(held))
+ stripping = TRUE
+ else
+ var/obj/item/weapon/holder/holder = held
+ if(istype(holder) && src == holder.held_mob)
+ stripping = TRUE
+ else
+ var/obj/item/weapon/grab/grab = held
+ if(istype(grab) && grab.affecting == src)
+ stripping = TRUE
+
+ if(stripping)
if(!istype(target_slot)) // They aren't holding anything valid and there's nothing to remove, why are we even here?
return
if(!target_slot.canremove)
to_chat(user, "You cannot remove \the [src]'s [target_slot.name].")
return
- stripping = 1
-
- if(stripping)
visible_message("\The [user] is trying to remove \the [src]'s [target_slot.name]!")
else
if(slot_to_strip == slot_wear_mask && istype(held, /obj/item/weapon/grenade))
@@ -76,8 +84,14 @@
if(!do_after(user,HUMAN_STRIP_DELAY,src))
return
- if(!stripping && user.get_active_hand() != held)
- return
+ if(!stripping)
+ if(user.get_active_hand() != held)
+ return
+ var/obj/item/weapon/holder/mobheld = held
+ if(istype(mobheld)&&mobheld.held_mob==src)
+ to_chat(user, "You can't put someone on themselves! Stop trying to break reality!")
+ return
+
if(stripping)
add_attack_logs(user,src,"Removed equipment from slot [target_slot]")
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index 063b4fe188..a88a434d96 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -10,9 +10,6 @@
if(!loc)
return
- if(machine && !CanMouseDrop(machine, src))
- machine = null
-
var/datum/gas_mixture/environment = loc.return_air()
//handle_modifiers() // Do this early since it might affect other things later. //VOREStation Edit
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 60966f6da2..0c20f6bf31 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -20,7 +20,6 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/ai_call_shuttle,
/mob/living/silicon/ai/proc/ai_camera_track,
/mob/living/silicon/ai/proc/ai_camera_list,
- /mob/living/silicon/ai/proc/ai_roster,
/mob/living/silicon/ai/proc/ai_checklaws,
/mob/living/silicon/ai/proc/toggle_camera_light,
/mob/living/silicon/ai/proc/take_image,
@@ -48,7 +47,7 @@ var/list/ai_verbs_default = list(
anchored = 1 // -- TLE
density = 1
status_flags = CANSTUN|CANPARALYSE|CANPUSH
- shouldnt_see = list(/obj/effect/rune)
+ shouldnt_see = list(/mob/observer/eye, /obj/effect/rune)
var/list/network = list(NETWORK_DEFAULT)
var/obj/machinery/camera/camera = null
var/aiRestorePowerRoutine = 0
@@ -355,12 +354,6 @@ var/list/ai_verbs_default = list(
if(new_sprite) selected_sprite = new_sprite
updateicon()
-// this verb lets the ai see the stations manifest
-/mob/living/silicon/ai/proc/ai_roster()
- set category = "AI Commands"
- set name = "Show Crew Manifest"
- show_station_manifest()
-
/mob/living/silicon/ai/var/message_cooldown = 0
/mob/living/silicon/ai/proc/ai_announcement()
set category = "AI Commands"
@@ -399,9 +392,7 @@ var/list/ai_verbs_default = list(
// hack to display shuttle timer
if(emergency_shuttle.online())
- var/obj/machinery/computer/communications/C = locate() in machines
- if(C)
- C.post_status("shuttle")
+ post_status(src, "shuttle", user = src)
/mob/living/silicon/ai/proc/ai_recall_shuttle()
set category = "AI Commands"
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 3a995ba19d..cf135f9d55 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -122,7 +122,10 @@
pda.ownjob = "Personal Assistant"
pda.owner = text("[]", src)
pda.name = pda.owner + " (" + pda.ownjob + ")"
- pda.toff = 1
+
+ var/datum/data/pda/app/messenger/M = pda.find_program(/datum/data/pda/app/messenger)
+ if(M)
+ M.toff = TRUE
..()
/mob/living/silicon/pai/Login()
@@ -210,7 +213,7 @@
medicalActive1 = null
medicalActive2 = null
medical_cannotfind = 0
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
to_chat(usr, "You reset your record-viewing software.")
/mob/living/silicon/pai/cancel_camera()
diff --git a/code/modules/mob/living/silicon/pai/software.dm b/code/modules/mob/living/silicon/pai/software.dm
index bbb038dead..cad5229097 100644
--- a/code/modules/mob/living/silicon/pai/software.dm
+++ b/code/modules/mob/living/silicon/pai/software.dm
@@ -41,27 +41,24 @@ var/global/list/default_pai_software = list()
set category = "pAI Commands"
set name = "Software Interface"
- ui_interact(src)
+ tgui_interact(src)
-/mob/living/silicon/pai/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
- if(user != src)
- if(ui) ui.set_status(STATUS_CLOSE, 0)
- return
+/mob/living/silicon/pai/tgui_state(mob/user)
+ return GLOB.tgui_self_state
- if(ui_key != "main")
- var/datum/pai_software/S = software[ui_key]
- if(S && !S.toggle)
- S.on_ui_interact(src, ui, force_open)
- else
- if(ui) ui.set_status(STATUS_CLOSE, 0)
- return
-
- var/data[0]
+/mob/living/silicon/pai/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "pAIInterface", "pAI Software Interface")
+ ui.open()
+/mob/living/silicon/pai/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
// Software we have bought
- var/bought_software[0]
+ var/list/bought_software = list()
// Software we have not bought
- var/not_bought_software[0]
+ var/list/not_bought_software = list()
for(var/key in pai_software_by_key)
var/datum/pai_software/S = pai_software_by_key[key]
@@ -70,62 +67,52 @@ var/global/list/default_pai_software = list()
software_data["id"] = S.id
if(key in software)
software_data["on"] = S.is_active(src)
- bought_software[++bought_software.len] = software_data
+ bought_software.Add(list(software_data))
else
software_data["ram"] = S.ram_cost
- not_bought_software[++not_bought_software.len] = software_data
+ not_bought_software.Add(list(software_data))
data["bought"] = bought_software
data["not_bought"] = not_bought_software
data["available_ram"] = ram
// Emotions
- var/emotions[0]
+ var/list/emotions = list()
for(var/name in pai_emotions)
- var/emote[0]
+ var/list/emote = list()
emote["name"] = name
emote["id"] = pai_emotions[name]
- emotions[++emotions.len] = emote
+ emotions.Add(list(emote))
data["emotions"] = emotions
data["current_emotion"] = card.current_emotion
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "pai_interface.tmpl", "pAI Software Interface", 450, 600)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ return data
-/mob/living/silicon/pai/Topic(href, href_list)
- . = ..()
- if(.) return
+/mob/living/silicon/pai/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
- if(href_list["software"])
- var/soft = href_list["software"]
- var/datum/pai_software/S = software[soft]
- if(S.toggle)
- S.toggle(src)
- else
- ui_interact(src, ui_key = soft)
- return 1
+ switch(action)
+ if("software")
+ var/soft = params["software"]
+ var/datum/pai_software/S = software[soft]
+ if(S.toggle)
+ S.toggle(src)
+ else
+ S.tgui_interact(src, parent_ui = ui)
+ return TRUE
- else if(href_list["stopic"])
- var/soft = href_list["stopic"]
- var/datum/pai_software/S = software[soft]
- if(S)
- return S.Topic(href, href_list)
+ if("purchase")
+ var/soft = params["purchase"]
+ var/datum/pai_software/S = pai_software_by_key[soft]
+ if(S && (ram >= S.ram_cost))
+ ram -= S.ram_cost
+ software[S.id] = S
+ return TRUE
- else if(href_list["purchase"])
- var/soft = href_list["purchase"]
- var/datum/pai_software/S = pai_software_by_key[soft]
- if(S && (ram >= S.ram_cost))
- ram -= S.ram_cost
- software[S.id] = S
- return 1
-
- else if(href_list["image"])
- var/img = text2num(href_list["image"])
- if(1 <= img && img <= (pai_emotions.len))
- card.setEmotion(img)
- return 1
+ if("image")
+ var/img = text2num(params["image"])
+ if(1 <= img && img <= (pai_emotions.len))
+ card.setEmotion(img)
+ return TRUE
diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm
index 8f7e8462de..e518e74a4a 100644
--- a/code/modules/mob/living/silicon/pai/software_modules.dm
+++ b/code/modules/mob/living/silicon/pai/software_modules.dm
@@ -12,14 +12,19 @@
// Whether pAIs should automatically receive this module at no cost
var/default = 0
- proc/on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
- return
+/datum/pai_software/proc/toggle(mob/living/silicon/pai/user)
+ return
- proc/toggle(mob/living/silicon/pai/user)
- return
+/datum/pai_software/proc/is_active(mob/living/silicon/pai/user)
+ return 0
- proc/is_active(mob/living/silicon/pai/user)
- return 0
+/datum/pai_software/tgui_state(mob/user)
+ return GLOB.tgui_always_state
+
+/datum/pai_software/tgui_status(mob/user)
+ if(!istype(user, /mob/living/silicon/pai))
+ return STATUS_CLOSE
+ return ..()
/datum/pai_software/directives
name = "Directives"
@@ -28,55 +33,58 @@
toggle = 0
default = 1
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
- var/data[0]
+/datum/pai_software/directives/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "pAIDirectives", name, parent_ui)
+ ui.open()
- data["master"] = user.master
- data["dna"] = user.master_dna
- data["prime"] = user.pai_law0
- data["supplemental"] = user.pai_laws
+/datum/pai_software/directives/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = list()
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- // Don't copy-paste this unless you're making a pAI software module!
- ui = new(user, user, id, "pai_directives.tmpl", "pAI Directives", 450, 600)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ data["master"] = user.master
+ data["dna"] = user.master_dna
+ data["prime"] = user.pai_law0
+ data["supplemental"] = user.pai_laws
- Topic(href, href_list)
- var/mob/living/silicon/pai/P = usr
- if(!istype(P)) return
+ return data
- if(href_list["getdna"])
- var/mob/living/M = P.loc
- var/count = 0
+/datum/pai_software/directives/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ var/mob/living/silicon/pai/P = usr
+ if(!istype(P))
+ return TRUE
+ if(..())
+ return TRUE
- // Find the carrier
- while(!istype(M, /mob/living))
- if(!M || !M.loc || count > 6)
- //For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
- to_chat(src, "You are not being carried by anyone!")
- return 0
- M = M.loc
- count++
+ if(action == "getdna")
+ var/mob/living/M = P.loc
- // Check the carrier
- var/datum/gender/TM = gender_datums[M.get_visible_gender()]
- var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
- if(answer == "Yes")
- var/turf/T = get_turf_or_move(P.loc)
- for (var/mob/v in viewers(T))
- v.show_message("[M] presses [TM.his] thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2)
- var/datum/dna/dna = M.dna
- to_chat(P, "[M]'s UE string : [dna.unique_enzymes]
")
- if(dna.unique_enzymes == P.master_dna)
- to_chat(P, "DNA is a match to stored Master DNA.")
- else
- to_chat(P, "DNA does not match stored Master DNA.")
+ var/count = 0
+ // Find the carrier
+ while(!istype(M, /mob/living))
+ if(!M || !M.loc || count > 6)
+ //For a runtime where M ends up in nullspace (similar to bluespace but less colourful)
+ to_chat(src, "You are not being carried by anyone!")
+ return 0
+ M = M.loc
+ count++
+
+ // Check the carrier
+ var/datum/gender/TM = gender_datums[M.get_visible_gender()]
+ var/answer = input(M, "[P] is requesting a DNA sample from you. Will you allow it to confirm your identity?", "[P] Check DNA", "No") in list("Yes", "No")
+ if(answer == "Yes")
+ var/turf/T = get_turf(P.loc)
+ for (var/mob/v in viewers(T))
+ v.show_message("[M] presses [TM.his] thumb against [P].", 3, "[P] makes a sharp clicking sound as it extracts DNA material from [M].", 2)
+ var/datum/dna/dna = M.dna
+ to_chat(P, "[M]'s UE string : [dna.unique_enzymes]
")
+ if(dna.unique_enzymes == P.master_dna)
+ to_chat(P, "DNA is a match to stored Master DNA.")
else
- to_chat(P, "[M] does not seem like [TM.he] is going to provide a DNA sample willingly.")
- return 1
+ to_chat(P, "DNA does not match stored Master DNA.")
+ else
+ to_chat(P, "[M] does not seem like [TM.he] is going to provide a DNA sample willingly.")
+ return TRUE
/datum/pai_software/radio_config
name = "Radio Configuration"
@@ -85,35 +93,8 @@
toggle = 0
default = 1
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui = null, force_open = 1)
- var/data[0]
-
- data["listening"] = user.radio.broadcasting
- data["frequency"] = format_frequency(user.radio.frequency)
-
- var/channels[0]
- for(var/ch_name in user.radio.channels)
- var/ch_stat = user.radio.channels[ch_name]
- var/ch_dat[0]
- ch_dat["name"] = ch_name
- // FREQ_LISTENING is const in /obj/item/device/radio
- ch_dat["listening"] = !!(ch_stat & user.radio.FREQ_LISTENING)
- channels[++channels.len] = ch_dat
-
- data["channels"] = channels
-
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- ui = new(user, user, id, "pai_radio.tmpl", "Radio Configuration", 300, 150)
- ui.set_initial_data(data)
- ui.open()
-
- Topic(href, href_list)
- var/mob/living/silicon/pai/P = usr
- if(!istype(P)) return
-
- P.radio.Topic(href, href_list)
- return 1
+/datum/pai_software/radio_config/tgui_interact(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui/parent_ui)
+ return user.radio.tgui_interact(user, parent_ui = parent_ui)
/datum/pai_software/crew_manifest
name = "Crew Manifest"
@@ -121,20 +102,18 @@
id = "manifest"
toggle = 0
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
+/datum/pai_software/crew_manifest/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "CrewManifest", name, parent_ui)
+ ui.open()
+
+/datum/pai_software/crew_manifest/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+ if(data_core)
data_core.get_manifest_list()
-
- var/data[0]
- // This is dumb, but NanoUI breaks if it has no data to send
- data["manifest"] = PDA_Manifest
-
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- // Don't copy-paste this unless you're making a pAI software module!
- ui = new(user, user, id, "crew_manifest.tmpl", "Crew Manifest", 450, 600)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ data["manifest"] = PDA_Manifest
+ return data
/datum/pai_software/messenger
name = "Digital Messenger"
@@ -142,75 +121,8 @@
id = "messenger"
toggle = 0
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
- var/data[0]
-
- data["receiver_off"] = user.pda.toff
- data["ringer_off"] = user.pda.message_silent
- data["current_ref"] = null
- data["current_name"] = user.current_pda_messaging
-
- var/pdas[0]
- if(!user.pda.toff)
- for(var/obj/item/device/pda/P in sortAtom(PDAs))
- if(!P.owner || P.toff || P == user.pda || P.hidden) continue
- var/pda[0]
- pda["name"] = "[P]"
- pda["owner"] = "[P.owner]"
- pda["ref"] = "\ref[P]"
- if(P.owner == user.current_pda_messaging)
- data["current_ref"] = "\ref[P]"
- pdas[++pdas.len] = pda
-
- data["pdas"] = pdas
-
- var/messages[0]
- if(user.current_pda_messaging)
- for(var/index in user.pda.tnote)
- if(index["owner"] != user.current_pda_messaging)
- continue
- var/msg[0]
- var/sent = index["sent"]
- msg["sent"] = sent ? 1 : 0
- msg["target"] = index["owner"]
- msg["message"] = index["message"]
- messages[++messages.len] = msg
-
- data["messages"] = messages
-
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- // Don't copy-paste this unless you're making a pAI software module!
- ui = new(user, user, id, "pai_messenger.tmpl", "Digital Messenger", 450, 600)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
-
- Topic(href, href_list)
- var/mob/living/silicon/pai/P = usr
- if(!istype(P)) return
-
- if(!isnull(P.pda))
- if(href_list["toggler"])
- P.pda.toff = href_list["toggler"] != "1"
- return 1
- else if(href_list["ringer"])
- P.pda.message_silent = href_list["ringer"] != "1"
- return 1
- else if(href_list["select"])
- var/s = href_list["select"]
- if(s == "*NONE*")
- P.current_pda_messaging = null
- else
- P.current_pda_messaging = s
- return 1
- else if(href_list["target"])
- if(P.silence_time)
- return alert("Communications circuits remain uninitialized.")
-
- var/target = locate(href_list["target"])
- P.pda.create_message(P, target, 1)
- return 1
+/datum/pai_software/messenger/tgui_interact(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui/parent_ui)
+ return user.pda.tgui_interact(user, parent_ui = parent_ui)
/datum/pai_software/med_records
name = "Medical Records"
@@ -218,53 +130,55 @@
id = "med_records"
toggle = 0
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
- var/data[0]
+/datum/pai_software/med_records/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "pAIMedrecords", name, parent_ui)
+ ui.open()
- var/records[0]
- for(var/datum/data/record/general in sortRecord(data_core.general))
- var/record[0]
- record["name"] = general.fields["name"]
- record["ref"] = "\ref[general]"
- records[++records.len] = record
+/datum/pai_software/med_records/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
+ var/list/records = list()
+ for(var/datum/data/record/general in sortRecord(data_core.general))
+ var/list/record = list()
+ record["name"] = general.fields["name"]
+ record["ref"] = "\ref[general]"
+ records.Add(list(record))
- data["records"] = records
+ data["records"] = records
- var/datum/data/record/G = user.medicalActive1
- var/datum/data/record/M = user.medicalActive2
- data["general"] = G ? G.fields : null
- data["medical"] = M ? M.fields : null
- data["could_not_find"] = user.medical_cannotfind
+ var/datum/data/record/G = user.medicalActive1
+ var/datum/data/record/M = user.medicalActive2
+ data["general"] = G ? G.fields : null
+ data["medical"] = M ? M.fields : null
+ data["could_not_find"] = user.medical_cannotfind
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- // Don't copy-paste this unless you're making a pAI software module!
- ui = new(user, user, id, "pai_medrecords.tmpl", "Medical Records", 450, 600)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ return data
- Topic(href, href_list)
- var/mob/living/silicon/pai/P = usr
- if(!istype(P)) return
+/datum/pai_software/med_records/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ . = ..()
+ var/mob/living/silicon/pai/P = usr
+ if(!istype(P))
+ return
- if(href_list["select"])
- var/datum/data/record/record = locate(href_list["select"])
- if(record)
- var/datum/data/record/R = record
- var/datum/data/record/M = null
- if (!( data_core.general.Find(R) ))
- P.medical_cannotfind = 1
- else
- P.medical_cannotfind = 0
- for(var/datum/data/record/E in data_core.medical)
- if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
- M = E
- P.medicalActive1 = R
- P.medicalActive2 = M
- else
+ if(action == "select")
+ var/datum/data/record/record = locate(params["select"])
+ if(record)
+ var/datum/data/record/R = record
+ var/datum/data/record/M = null
+ if (!( data_core.general.Find(R) ))
P.medical_cannotfind = 1
- return 1
+ else
+ P.medical_cannotfind = 0
+ for(var/datum/data/record/E in data_core.medical)
+ if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
+ M = E
+ P.medicalActive1 = R
+ P.medicalActive2 = M
+ else
+ P.medical_cannotfind = 1
+ return 1
/datum/pai_software/sec_records
name = "Security Records"
@@ -272,57 +186,59 @@
id = "sec_records"
toggle = 0
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
- var/data[0]
+/datum/pai_software/sec_records/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "pAISecrecords", name, parent_ui)
+ ui.open()
- var/records[0]
- for(var/datum/data/record/general in sortRecord(data_core.general))
- var/record[0]
- record["name"] = general.fields["name"]
- record["ref"] = "\ref[general]"
- records[++records.len] = record
+/datum/pai_software/sec_records/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
+ var/list/records = list()
+ for(var/datum/data/record/general in sortRecord(data_core.general))
+ var/list/record = list()
+ record["name"] = general.fields["name"]
+ record["ref"] = "\ref[general]"
+ records.Add(list(record))
- data["records"] = records
+ data["records"] = records
- var/datum/data/record/G = user.securityActive1
- var/datum/data/record/S = user.securityActive2
- data["general"] = G ? G.fields : null
- data["security"] = S ? S.fields : null
- data["could_not_find"] = user.security_cannotfind
+ var/datum/data/record/G = user.securityActive1
+ var/datum/data/record/S = user.securityActive2
+ data["general"] = G ? G.fields : null
+ data["security"] = S ? S.fields : null
+ data["could_not_find"] = user.security_cannotfind
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- // Don't copy-paste this unless you're making a pAI software module!
- ui = new(user, user, id, "pai_secrecords.tmpl", "Security Records", 450, 600)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ return data
- Topic(href, href_list)
- var/mob/living/silicon/pai/P = usr
- if(!istype(P)) return
+/datum/pai_software/sec_records/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ . = ..()
+ var/mob/living/silicon/pai/P = usr
+ if(!istype(P))
+ return
- if(href_list["select"])
- var/datum/data/record/record = locate(href_list["select"])
- if(record)
- var/datum/data/record/R = record
- var/datum/data/record/S = null
- if (!( data_core.general.Find(R) ))
- P.securityActive1 = null
- P.securityActive2 = null
- P.security_cannotfind = 1
- else
- P.security_cannotfind = 0
- for(var/datum/data/record/E in data_core.security)
- if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
- S = E
- P.securityActive1 = R
- P.securityActive2 = S
- else
+ if(action == "select")
+ var/datum/data/record/record = locate(params["select"])
+ if(record)
+ var/datum/data/record/R = record
+ var/datum/data/record/S = null
+ if (!( data_core.general.Find(R) ))
P.securityActive1 = null
P.securityActive2 = null
P.security_cannotfind = 1
- return 1
+ else
+ P.security_cannotfind = 0
+ for(var/datum/data/record/E in data_core.security)
+ if ((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"]))
+ S = E
+ P.securityActive1 = R
+ P.securityActive2 = S
+ else
+ P.securityActive1 = null
+ P.securityActive2 = null
+ P.security_cannotfind = 1
+ return TRUE
/datum/pai_software/door_jack
name = "Door Jack"
@@ -330,47 +246,49 @@
id = "door_jack"
toggle = 0
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
- var/data[0]
+/datum/pai_software/door_jack/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "pAIDoorjack", "Door Jack", parent_ui)
+ ui.open()
- data["cable"] = user.cable != null
- data["machine"] = user.cable && (user.cable.machine != null)
- data["inprogress"] = user.hackdoor != null
- data["progress_a"] = round(user.hackprogress / 10)
- data["progress_b"] = user.hackprogress % 10
- data["aborted"] = user.hack_aborted
+/datum/pai_software/door_jack/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- // Don't copy-paste this unless you're making a pAI software module!
- ui = new(user, user, id, "pai_doorjack.tmpl", "Door Jack", 300, 150)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ data["cable"] = user.cable != null
+ data["machine"] = user.cable && (user.cable.machine != null)
+ data["inprogress"] = user.hackdoor != null
+ data["progress_a"] = round(user.hackprogress / 10)
+ data["progress_b"] = user.hackprogress % 10
+ data["aborted"] = user.hack_aborted
- Topic(href, href_list)
- var/mob/living/silicon/pai/P = usr
- if(!istype(P)) return
+ return data
- if(href_list["jack"])
+/datum/pai_software/door_jack/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ var/mob/living/silicon/pai/P = usr
+ if(!istype(P) || ..())
+ return TRUE
+
+ switch(action)
+ if("jack")
if(P.cable && P.cable.machine)
P.hackdoor = P.cable.machine
P.hackloop()
return 1
- else if(href_list["cancel"])
+ if("cancel")
P.hackdoor = null
return 1
- else if(href_list["cable"])
- var/turf/T = get_turf_or_move(P.loc)
+ if("cable")
+ var/turf/T = get_turf(P)
P.hack_aborted = 0
P.cable = new /obj/item/weapon/pai_cable(T)
for(var/mob/M in viewers(T))
M.show_message("A port on [P] opens to reveal [P.cable], which promptly falls to the floor.", 3,
- "You hear the soft click of something light and hard falling to the ground.", 2)
+ "You hear the soft click of something light and hard falling to the ground.", 2)
return 1
/mob/living/silicon/pai/proc/hackloop()
- var/turf/T = get_turf_or_move(src.loc)
+ var/turf/T = get_turf(src)
for(var/mob/living/silicon/ai/AI in player_list)
if(T.loc)
to_chat(AI, "Network Alert: Brute-force encryption crack in progress in [T.loc].")
@@ -404,134 +322,155 @@
id = "atmos_sense"
toggle = 0
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
- var/data[0]
+/datum/pai_software/atmosphere_sensor/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "pAIAtmos", name, parent_ui)
+ ui.open()
- var/turf/T = get_turf_or_move(user.loc)
- if(!T)
- data["reading"] = 0
- data["pressure"] = 0
- data["temperature"] = 0
- data["temperatureC"] = 0
- data["gas"] = list()
- else
- var/datum/gas_mixture/env = T.return_air()
- data["reading"] = 1
- var/pres = env.return_pressure() * 10
- data["pressure"] = "[round(pres/10)].[pres%10]"
- data["temperature"] = round(env.temperature)
- data["temperatureC"] = round(env.temperature-T0C)
+/datum/pai_software/atmosphere_sensor/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- var/t_moles = env.total_moles
- var/gases[0]
- for(var/g in env.gas)
- var/gas[0]
- gas["name"] = gas_data.name[g]
- gas["percent"] = round((env.gas[g] / t_moles) * 100)
- gases[++gases.len] = gas
- data["gas"] = gases
+ var/list/results = list()
+ var/turf/T = get_turf(user)
+ if(!isnull(T))
+ var/datum/gas_mixture/environment = T.return_air()
+ var/pressure = environment.return_pressure()
+ var/total_moles = environment.total_moles
+ if (total_moles)
+ var/o2_level = environment.gas["oxygen"]/total_moles
+ var/n2_level = environment.gas["nitrogen"]/total_moles
+ var/co2_level = environment.gas["carbon_dioxide"]/total_moles
+ var/phoron_level = environment.gas["phoron"]/total_moles
+ var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level)
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- // Don't copy-paste this unless you're making a pAI software module!
- ui = new(user, user, id, "pai_atmosphere.tmpl", "Atmosphere Sensor", 350, 300)
- ui.set_initial_data(data)
- ui.open()
+ // entry is what the element is describing
+ // Type identifies which unit or other special characters to use
+ // Val is the information reported
+ // Bad_high/_low are the values outside of which the entry reports as dangerous
+ // Poor_high/_low are the values outside of which the entry reports as unideal
+ // Values were extracted from the template itself
+ results = list(
+ list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
+ list("entry" = "Temperature", "units" = "°C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
+ list("entry" = "Oxygen", "units" = "kPa", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
+ list("entry" = "Nitrogen", "units" = "kPa", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
+ list("entry" = "Carbon Dioxide", "units" = "kPa", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
+ list("entry" = "Phoron", "units" = "kPa", "val" = "[round(phoron_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0),
+ list("entry" = "Other", "units" = "kPa", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0)
+ )
+
+ if(isnull(results))
+ results = list(list("entry" = "pressure", "units" = "kPa", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80))
+
+ data["aircontents"] = results
+
+ return data
/datum/pai_software/sec_hud
name = "Security HUD"
ram_cost = 20
id = "sec_hud"
- toggle(mob/living/silicon/pai/user)
- user.secHUD = !user.secHUD
- user.plane_holder.set_vis(VIS_CH_ID, user.secHUD)
- user.plane_holder.set_vis(VIS_CH_WANTED, user.secHUD)
- user.plane_holder.set_vis(VIS_CH_IMPTRACK, user.secHUD)
- user.plane_holder.set_vis(VIS_CH_IMPLOYAL, user.secHUD)
- user.plane_holder.set_vis(VIS_CH_IMPCHEM, user.secHUD)
+/datum/pai_software/sec_hud/toggle(mob/living/silicon/pai/user)
+ user.secHUD = !user.secHUD
+ user.plane_holder.set_vis(VIS_CH_ID, user.secHUD)
+ user.plane_holder.set_vis(VIS_CH_WANTED, user.secHUD)
+ user.plane_holder.set_vis(VIS_CH_IMPTRACK, user.secHUD)
+ user.plane_holder.set_vis(VIS_CH_IMPLOYAL, user.secHUD)
+ user.plane_holder.set_vis(VIS_CH_IMPCHEM, user.secHUD)
- is_active(mob/living/silicon/pai/user)
- return user.secHUD
+/datum/pai_software/sec_hud/is_active(mob/living/silicon/pai/user)
+ return user.secHUD
/datum/pai_software/med_hud
name = "Medical HUD"
ram_cost = 20
id = "med_hud"
- toggle(mob/living/silicon/pai/user)
- user.medHUD = !user.medHUD
- user.plane_holder.set_vis(VIS_CH_STATUS, user.medHUD)
- user.plane_holder.set_vis(VIS_CH_HEALTH, user.medHUD)
+/datum/pai_software/med_hud/toggle(mob/living/silicon/pai/user)
+ user.medHUD = !user.medHUD
+ user.plane_holder.set_vis(VIS_CH_STATUS, user.medHUD)
+ user.plane_holder.set_vis(VIS_CH_HEALTH, user.medHUD)
- is_active(mob/living/silicon/pai/user)
- return user.medHUD
+/datum/pai_software/med_hud/is_active(mob/living/silicon/pai/user)
+ return user.medHUD
/datum/pai_software/translator
name = "Universal Translator"
ram_cost = 35
id = "translator"
- toggle(mob/living/silicon/pai/user)
- // Sol Common, Tradeband, Terminus and Gutter are added with New() and are therefore the current default, always active languages
- user.translator_on = !user.translator_on
- if(user.translator_on)
- user.add_language(LANGUAGE_UNATHI)
- user.add_language(LANGUAGE_SIIK)
- user.add_language(LANGUAGE_AKHANI)
- user.add_language(LANGUAGE_SKRELLIAN)
- user.add_language(LANGUAGE_ZADDAT)
- user.add_language(LANGUAGE_SCHECHI)
- else
- user.remove_language(LANGUAGE_UNATHI)
- user.remove_language(LANGUAGE_SIIK)
- user.remove_language(LANGUAGE_AKHANI)
- user.remove_language(LANGUAGE_SKRELLIAN)
- user.remove_language(LANGUAGE_ZADDAT)
- user.remove_language(LANGUAGE_SCHECHI)
+/datum/pai_software/translator/toggle(mob/living/silicon/pai/user)
+ // Sol Common, Tradeband, Terminus and Gutter are added with New() and are therefore the current default, always active languages
+ user.translator_on = !user.translator_on
+ if(user.translator_on)
+ user.add_language(LANGUAGE_UNATHI)
+ user.add_language(LANGUAGE_SIIK)
+ user.add_language(LANGUAGE_AKHANI)
+ user.add_language(LANGUAGE_SKRELLIAN)
+ user.add_language(LANGUAGE_ZADDAT)
+ user.add_language(LANGUAGE_SCHECHI)
+ else
+ user.remove_language(LANGUAGE_UNATHI)
+ user.remove_language(LANGUAGE_SIIK)
+ user.remove_language(LANGUAGE_AKHANI)
+ user.remove_language(LANGUAGE_SKRELLIAN)
+ user.remove_language(LANGUAGE_ZADDAT)
+ user.remove_language(LANGUAGE_SCHECHI)
- is_active(mob/living/silicon/pai/user)
- return user.translator_on
+/datum/pai_software/translator/is_active(mob/living/silicon/pai/user)
+ return user.translator_on
/datum/pai_software/signaller
- name = "Remote Signaller"
+ name = "Remote Signaler"
ram_cost = 5
id = "signaller"
toggle = 0
- on_ui_interact(mob/living/silicon/pai/user, datum/nanoui/ui=null, force_open=1)
- var/data[0]
+/datum/pai_software/signaller/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Signaler", "Signaler", parent_ui)
+ ui.open()
- data["frequency"] = format_frequency(user.sradio.frequency)
- data["code"] = user.sradio.code
+/datum/pai_software/signaller/tgui_data(mob/living/silicon/pai/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
+ var/obj/item/radio/integrated/signal/R = user.sradio
- ui = SSnanoui.try_update_ui(user, user, id, ui, data, force_open)
- if(!ui)
- // Don't copy-paste this unless you're making a pAI software module!
- ui = new(user, user, id, "pai_signaller.tmpl", "Signaller", 320, 150)
- ui.set_initial_data(data)
- ui.open()
+ data["frequency"] = R.frequency
+ data["minFrequency"] = RADIO_LOW_FREQ
+ data["maxFrequency"] = RADIO_HIGH_FREQ
+ data["code"] = R.code
- Topic(href, href_list)
- var/mob/living/silicon/pai/P = usr
- if(!istype(P)) return
+ return data
- if(href_list["send"])
- P.sradio.send_signal("ACTIVATE")
- for(var/mob/O in hearers(1, P.loc))
- O.show_message("[bicon(P)] *beep* *beep*", 3, "*beep* *beep*", 2)
- return 1
+/datum/pai_software/signaller/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
- else if(href_list["freq"])
- var/new_frequency = (P.sradio.frequency + text2num(href_list["freq"]))
- if(new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)
- new_frequency = sanitize_frequency(new_frequency)
- P.sradio.set_frequency(new_frequency)
- return 1
+ var/mob/living/silicon/pai/user = usr
+ if(istype(user))
+ var/obj/item/radio/integrated/signal/R = user.sradio
- else if(href_list["code"])
- P.sradio.code += text2num(href_list["code"])
- P.sradio.code = round(P.sradio.code)
- P.sradio.code = min(100, P.sradio.code)
- P.sradio.code = max(1, P.sradio.code)
- return 1
+ switch(action)
+ if("signal")
+ spawn(0)
+ R.send_signal("ACTIVATE")
+ for(var/mob/O in hearers(1, R.loc))
+ O.show_message("[bicon(R)] *beep* *beep*", 3, "*beep* *beep*", 2)
+ if("freq")
+ var/frequency = unformat_frequency(params["freq"])
+ frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ)
+ R.set_frequency(frequency)
+ . = TRUE
+ if("code")
+ R.code = clamp(round(text2num(params["code"])), 1, 100)
+ . = TRUE
+ if("reset")
+ if(params["reset"] == "freq")
+ R.set_frequency(initial(R.frequency))
+ else
+ R.code = initial(R.code)
+ . = TRUE
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index ad1e767aca..7d67ca3cc3 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -349,12 +349,6 @@
updatename()
updateicon()
-// this verb lets cyborgs see the stations manifest
-/mob/living/silicon/robot/verb/cmd_station_manifest()
- set category = "Robot Commands"
- set name = "Show Crew Manifest"
- show_station_manifest()
-
/mob/living/silicon/robot/proc/self_diagnosis()
if(!is_component_functioning("diagnosis unit"))
return null
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm
index e6dface45a..ef5336e5b9 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/station_vr.dm
@@ -149,7 +149,8 @@
pto_type = PTO_SCIENCE
vr_sprites = list(
"Acheron" = "mechoid-Science",
- "ZOOM-BA" = "zoomba-research"
+ "ZOOM-BA" = "zoomba-research",
+ "XI-GUS" = "spiderscience"
)
/obj/item/weapon/robot_module/robot/security/combat
diff --git a/code/modules/mob/living/silicon/robot/robot_vr.dm b/code/modules/mob/living/silicon/robot/robot_vr.dm
index 840026946f..21011e84c7 100644
--- a/code/modules/mob/living/silicon/robot/robot_vr.dm
+++ b/code/modules/mob/living/silicon/robot/robot_vr.dm
@@ -53,7 +53,8 @@
"zoomba-service",
"zoomba-combat",
"zoomba-combat-roll",
- "zoomba-combat-shield"
+ "zoomba-combat-shield",
+ "spiderscience"
) //List of all used sprites that are in robots_vr.dmi
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index b6cf748fb8..b9c2c60c47 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -153,18 +153,6 @@
show_malf_ai()
..()
-// this function displays the stations manifest in a separate window
-/mob/living/silicon/proc/show_station_manifest()
- var/dat = ""
- if(!data_core)
- to_chat(src, "
There is no data to form a manifest with. Contact your Nanotrasen administrator.")
- return
- dat += data_core.get_manifest(1) //The 1 makes it monochrome.
-
- var/datum/browser/popup = new(src, "Crew Manifest", "Crew Manifest", 370, 420, src)
- popup.set_content(dat)
- popup.open()
-
//can't inject synths
/mob/living/silicon/can_inject(var/mob/user, var/error_msg)
if(error_msg)
diff --git a/code/modules/mob/living/silicon/subystems.dm b/code/modules/mob/living/silicon/subystems.dm
index be6a68591d..890f1a8b37 100644
--- a/code/modules/mob/living/silicon/subystems.dm
+++ b/code/modules/mob/living/silicon/subystems.dm
@@ -2,6 +2,7 @@
var/register_alarms = 1
var/datum/tgui_module/alarm_monitor/all/robot/alarm_monitor
var/datum/tgui_module/atmos_control/robot/atmos_control
+ var/datum/tgui_module/crew_manifest/robot/crew_manifest
var/datum/tgui_module/crew_monitor/robot/crew_monitor
var/datum/tgui_module/law_manager/robot/law_manager
var/datum/tgui_module/power_monitor/robot/power_monitor
@@ -10,6 +11,7 @@
/mob/living/silicon
var/list/silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
+ /mob/living/silicon/proc/subsystem_crew_manifest,
/mob/living/silicon/proc/subsystem_law_manager
)
@@ -17,6 +19,7 @@
silicon_subsystems = list(
/mob/living/silicon/proc/subsystem_alarm_monitor,
/mob/living/silicon/proc/subsystem_atmos_control,
+ /mob/living/silicon/proc/subsystem_crew_manifest,
/mob/living/silicon/proc/subsystem_crew_monitor,
/mob/living/silicon/proc/subsystem_law_manager,
/mob/living/silicon/proc/subsystem_power_monitor,
@@ -30,6 +33,7 @@
/mob/living/silicon/proc/init_subsystems()
alarm_monitor = new(src)
atmos_control = new(src)
+ crew_manifest = new(src)
crew_monitor = new(src)
law_manager = new(src)
power_monitor = new(src)
@@ -60,6 +64,15 @@
atmos_control.tgui_interact(usr)
+/********************
+* Crew Manifest *
+********************/
+/mob/living/silicon/proc/subsystem_crew_manifest()
+ set category = "Subystems"
+ set name = "Crew Manifest"
+
+ crew_manifest.tgui_interact(usr)
+
/********************
* Crew Monitor *
********************/
diff --git a/code/modules/mob/living/simple_mob/simple_mob.dm b/code/modules/mob/living/simple_mob/simple_mob.dm
index 3a27d98d01..f3bf4543db 100644
--- a/code/modules/mob/living/simple_mob/simple_mob.dm
+++ b/code/modules/mob/living/simple_mob/simple_mob.dm
@@ -271,18 +271,22 @@
// Harvest an animal's delicious byproducts
-/mob/living/simple_mob/proc/harvest(var/mob/user)
+/mob/living/simple_mob/proc/harvest(var/mob/user, var/invisible)
var/actual_meat_amount = max(1,(meat_amount/2))
+ var/attacker_name = user.name
+ if(invisible)
+ attacker_name = "someone"
+
if(meat_type && actual_meat_amount>0 && (stat == DEAD))
for(var/i=0;i
[user] chops up \the [src]!")
+ user.visible_message("[attacker_name] chops up \the [src]!")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
qdel(src)
else
- user.visible_message("[user] butchers \the [src] messily!")
+ user.visible_message("[attacker_name] butchers \the [src] messily!")
gib()
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/farm animals/chicken.dm b/code/modules/mob/living/simple_mob/subtypes/animal/farm animals/chicken.dm
index d33e93e042..76d7bb9353 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/farm animals/chicken.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/farm animals/chicken.dm
@@ -25,7 +25,7 @@ GLOBAL_VAR_INIT(chicken_count, 0) // How mant chickens DO we have?
say_list_type = /datum/say_list/chicken
meat_amount = 2
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken
var/eggsleft = 0
var/body_color
@@ -125,7 +125,7 @@ GLOBAL_VAR_INIT(chicken_count, 0) // How mant chickens DO we have?
say_list_type = /datum/say_list/chick
meat_amount = 1
- meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
+ meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat/chicken
var/amount_grown = 0
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm b/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm
index 7c371e078d..d3cda1f22b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/space/alien.dm
@@ -18,6 +18,7 @@
maxHealth = 100
health = 100
+ see_in_dark = 7
harm_intent_damage = 5
melee_damage_lower = 25
@@ -122,4 +123,4 @@
/mob/living/simple_mob/animal/space/alien/death()
..()
visible_message("[src] lets out a waning guttural screech, green blood bubbling from its maw...")
- playsound(src, 'sound/voice/hiss6.ogg', 100, 1)
\ No newline at end of file
+ playsound(src, 'sound/voice/hiss6.ogg', 100, 1)
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm
index 3b39c4121e..4545057bc6 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm
@@ -89,7 +89,7 @@
return L.assess_perp(src, FALSE, FALSE, TRUE, FALSE) <= 3
// Variant that has high armor pen. Slightly slower attack speed and movement. Meant to be dispersed in groups with other ones
-/mob/living/simple_mob/mechanical/viscerator/piercing.
+/mob/living/simple_mob/mechanical/viscerator/piercing
attack_armor_pen = 20
base_attack_cooldown = 10 // One attack a second or so.
movement_cooldown = 0.5
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
index c95dbded2c..87200c0caf 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/demon/demon_abilities.dm
@@ -56,7 +56,7 @@
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
- if(istype(target) && vore_selected)
+ if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected)
target.forceMove(vore_selected)
to_chat(target,"\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!")
@@ -203,7 +203,7 @@
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
- if(istype(target) && vore_selected)
+ if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected)
target.forceMove(vore_selected)
to_chat(target,"\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!")
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm
index f5004db3c1..7b2da46008 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/morph/morph.dm
@@ -89,6 +89,10 @@
..()
/mob/living/simple_mob/vore/hostile/morph/proc/assume(atom/movable/target)
+ var/mob/living/carbon/human/humantarget = target
+ if(istype(humantarget) && humantarget.resleeve_lock && ckey != humantarget.resleeve_lock)
+ to_chat(src, "[target] cannot be impersonated!")
+ return
if(morphed)
to_chat(src, "You must restore to your original form first!")
return
diff --git a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm
index 491d0011d2..f1fc9914c2 100644
--- a/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/shadekin/ability_procs.dm
@@ -44,7 +44,7 @@
var/list/potentials = living_mobs(0)
if(potentials.len)
var/mob/living/target = pick(potentials)
- if(istype(target) && vore_selected)
+ if(istype(target) && target.devourable && target.can_be_drop_prey && vore_selected)
target.forceMove(vore_selected)
to_chat(target,"\The [src] phases in around you, [vore_selected.vore_verb]ing you into their [vore_selected.name]!")
diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm
index ffaeef3c09..d965956dfe 100644
--- a/code/modules/mob/logout.dm
+++ b/code/modules/mob/logout.dm
@@ -1,5 +1,4 @@
/mob/Logout()
- SSnanoui.user_logout(src) // this is used to clean up (remove) this user's Nano UIs
SStgui.on_logout(src) // Cleanup any TGUIs the user has open
player_list -= src
disconnect_time = world.realtime //VOREStation Addition: logging when we disappear.
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index bb61f345b6..2722a12f01 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -84,7 +84,7 @@
else
exclude_mobs = list(src)
src.show_message(self_message, 1, blind_message, 2)
- . = ..()
+ . = ..(message, blind_message, exclude_mobs)
// Returns an amount of power drawn from the object (-1 if it's not viable).
// If drain_check is set it will not actually drain power, just return a value.
diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm
index 7be3255cbd..c5066adb7c 100644
--- a/code/modules/mob/mob_defines.dm
+++ b/code/modules/mob/mob_defines.dm
@@ -202,7 +202,7 @@
var/mob/teleop = null
var/turf/listed_turf = null //the current turf being examined in the stat panel
- var/list/shouldnt_see = list() //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes
+ var/list/shouldnt_see = list(/mob/observer/eye) //list of objects that this mob shouldn't see in the stat panel. this silliness is needed because of AI alt+click and cult blood runes
var/list/active_genes=list()
var/mob_size = MOB_MEDIUM
diff --git a/code/modules/mob/new_player/sprite_accessories_vr.dm b/code/modules/mob/new_player/sprite_accessories_vr.dm
index e624351360..ad89abfd3b 100644
--- a/code/modules/mob/new_player/sprite_accessories_vr.dm
+++ b/code/modules/mob/new_player/sprite_accessories_vr.dm
@@ -240,13 +240,6 @@
icon_state = "hair_fingerwave"
species_allowed = list(SPECIES_VULPKANIN, SPECIES_XENOCHIMERA, SPECIES_TAJ, SPECIES_SERGAL, SPECIES_FENNEC, SPECIES_ZORREN_HIGH, SPECIES_PROTEAN)
- teshari_fluffymohawk
- name = "Teshari Fluffy Mohawk"
- icon = 'icons/mob/human_face_vr.dmi'
- icon_add = 'icons/mob/human_face_vr_add.dmi'
- icon_state = "teshari_fluffymohawk"
- species_allowed = list(SPECIES_TESHARI)
-
//Teshari things
teshari
icon_add = 'icons/mob/human_face_vr_add.dmi'
@@ -290,6 +283,22 @@
teshari_mushroom
icon_add = 'icons/mob/human_face_vr_add.dmi'
+ teshari_twies
+ icon_add = 'icons/mob/human_face_vr_add.dmi'
+
+ teshari_backstrafe
+ icon_add = 'icons/mob/human_face_vr_add.dmi'
+
+ teshari_longway
+ icon_add = 'icons/mob/human_face_vr_add.dmi'
+
+ teshari_tree
+ icon_add = 'icons/mob/human_face_vr_add.dmi'
+
+ teshari_fluffymohawk
+ icon = 'icons/mob/human_face_vr.dmi'
+ icon_add = 'icons/mob/human_face_vr_add.dmi'
+
//Skrell 'hairstyles' - these were requested for a chimera and screw it, if one wants to eat seafood, go nuts
skr_tentacle_veryshort
name = "Skrell Very Short Tentacles"
@@ -1166,3 +1175,8 @@
icon_state = "dnose"
color_blend_mode = ICON_MULTIPLY
body_parts = list(BP_HEAD)
+
+ bee_stripes
+ name = "bee stripes"
+ icon_state = "beestripes"
+ body_parts = list(BP_TORSO,BP_GROIN)
\ No newline at end of file
diff --git a/code/modules/modular_computers/NTNet/NTNet.dm b/code/modules/modular_computers/NTNet/NTNet.dm
index 8370683522..6479f92a21 100644
--- a/code/modules/modular_computers/NTNet/NTNet.dm
+++ b/code/modules/modular_computers/NTNet/NTNet.dm
@@ -181,5 +181,8 @@ var/global/datum/ntnet/ntnet_global = new()
return 1
return 0
-
+/datum/ntnet/proc/get_chat_channel_by_id(id)
+ for(var/datum/ntnet_conversation/chan in chat_channels)
+ if(chan.id == id)
+ return chan
diff --git a/code/modules/modular_computers/computers/modular_computer/core.dm b/code/modules/modular_computers/computers/modular_computer/core.dm
index 97b4cfe851..d4b311e8e2 100644
--- a/code/modules/modular_computers/computers/modular_computer/core.dm
+++ b/code/modules/modular_computers/computers/modular_computer/core.dm
@@ -42,6 +42,8 @@
return 1
/obj/item/modular_computer/Initialize()
+ if(!overlay_icon)
+ overlay_icon = icon
START_PROCESSING(SSobj, src)
install_default_hardware()
if(hard_drive)
@@ -72,20 +74,20 @@
overlays.Cut()
if(bsod)
- overlays.Add("bsod")
+ overlays += image(icon = overlay_icon, icon_state = "bsod")
return
if(!enabled)
if(icon_state_screensaver)
- overlays.Add(icon_state_screensaver)
+ overlays += image(icon = overlay_icon, icon_state = icon_state_screensaver)
set_light(0)
return
set_light(light_strength)
if(active_program)
- overlays.Add(active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
+ overlays += image(icon = overlay_icon, icon_state = active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu)
if(active_program.program_key_state)
- overlays.Add(active_program.program_key_state)
+ overlays += image(icon = overlay_icon, icon_state = active_program.program_key_state)
else
- overlays.Add(icon_state_menu)
+ overlays += image(icon = overlay_icon, icon_state = icon_state_menu)
/obj/item/modular_computer/proc/turn_on(var/mob/user)
if(bsod)
@@ -119,7 +121,7 @@
active_program = null
var/mob/user = usr
if(user && istype(user))
- ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
+ tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
update_icon()
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
@@ -154,7 +156,7 @@
run_program(autorun.stored_data)
if(user)
- ui_interact(user)
+ tgui_interact(user)
/obj/item/modular_computer/proc/minimize_program(mob/user)
if(!active_program || !processor_unit)
@@ -162,12 +164,11 @@
idle_threads.Add(active_program)
active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
- SSnanoui.close_uis(active_program.NM ? active_program.NM : active_program)
SStgui.close_uis(active_program.TM ? active_program.TM : active_program)
active_program = null
update_icon()
if(istype(user))
- ui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
+ tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
/obj/item/modular_computer/proc/run_program(prog)
@@ -207,12 +208,12 @@
return 1
/obj/item/modular_computer/proc/update_uis()
- if(active_program) //Should we update program ui or computer ui?
- SSnanoui.update_uis(active_program)
- if(active_program.NM)
- SSnanoui.update_uis(active_program.NM)
+ if(active_program)
+ SStgui.update_uis(active_program)
+ if(active_program.TM)
+ SStgui.update_uis(active_program.TM)
else
- SSnanoui.update_uis(src)
+ SStgui.update_uis(src)
/obj/item/modular_computer/proc/check_update_ui_need()
var/ui_update_needed = 0
diff --git a/code/modules/modular_computers/computers/modular_computer/interaction.dm b/code/modules/modular_computers/computers/modular_computer/interaction.dm
index c9ee11a77e..24c02c1add 100644
--- a/code/modules/modular_computers/computers/modular_computer/interaction.dm
+++ b/code/modules/modular_computers/computers/modular_computer/interaction.dm
@@ -99,7 +99,7 @@
/obj/item/modular_computer/attack_ghost(var/mob/observer/ghost/user)
if(enabled)
- ui_interact(user)
+ tgui_interact(user)
else if(check_rights(R_ADMIN|R_EVENT, 0, user))
var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No")
if(response == "Yes")
@@ -116,7 +116,7 @@
// On-click handling. Turns on the computer if it's off and opens the GUI.
/obj/item/modular_computer/attack_self(var/mob/user)
if(enabled && screen_on)
- ui_interact(user)
+ tgui_interact(user)
else if(!enabled && screen_on)
turn_on(user)
diff --git a/code/modules/modular_computers/computers/modular_computer/ui.dm b/code/modules/modular_computers/computers/modular_computer/ui.dm
index 81081c0cb1..5166d0d777 100644
--- a/code/modules/modular_computers/computers/modular_computer/ui.dm
+++ b/code/modules/modular_computers/computers/modular_computer/ui.dm
@@ -1,5 +1,10 @@
-// Operates NanoUI
-/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+// Operates TGUI
+/obj/item/modular_computer/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/simple/headers)
+ )
+
+/obj/item/modular_computer/tgui_interact(mob/user, datum/tgui/ui)
if(!screen_on || !enabled)
if(ui)
ui.close()
@@ -13,7 +18,7 @@
if(active_program)
if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now.
ui.close()
- active_program.ui_interact(user)
+ active_program.tgui_interact(user)
return
// We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it.
@@ -22,80 +27,100 @@
visible_message("\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.")
return // No HDD, No HDD files list or no stored files. Something is very broken.
- var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun")
-
- var/list/data = get_header_data()
-
- var/list/programs = list()
- for(var/datum/computer_file/program/P in hard_drive.stored_files)
- var/list/program = list()
- program["name"] = P.filename
- program["desc"] = P.filedesc
- program["icon"] = P.program_menu_icon
- program["autorun"] = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0
- if(P in idle_threads)
- program["running"] = 1
- programs.Add(list(program))
-
- data["programs"] = programs
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "laptop_mainscreen.tmpl", "NTOS Main Menu", 400, 500)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "NtosMain")
+ ui.set_autoupdate(TRUE)
ui.open()
- ui.set_auto_update(1)
+
+/obj/item/modular_computer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = get_header_data()
+ data["device_theme"] = device_theme
+
+ data["login"] = list()
+ var/obj/item/weapon/computer_hardware/card_slot/cardholder = card_slot
+ if(cardholder)
+ var/obj/item/weapon/card/id/stored_card = cardholder.stored_card
+ if(stored_card)
+ var/stored_name = stored_card.registered_name
+ var/stored_title = stored_card.assignment
+ if(!stored_name)
+ stored_name = "Unknown"
+ if(!stored_title)
+ stored_title = "Unknown"
+ data["login"] = list(
+ IDName = stored_name,
+ IDJob = stored_title,
+ )
+
+ data["removable_media"] = list()
+
+ var/datum/computer_file/data/autorun = hard_drive.find_file_by_name("autorun")
+ data["programs"] = list()
+ for(var/datum/computer_file/program/P in hard_drive.stored_files)
+ var/running = FALSE
+ if(P in idle_threads)
+ running = TRUE
+
+ data["programs"] += list(list(
+ "name" = P.filename,
+ "desc" = P.filedesc,
+ "icon" = P.program_menu_icon,
+ "running" = running,
+ "autorun" = (istype(autorun) && (autorun.stored_data == P.filename)) ? 1 : 0
+ ))
+
+ data["has_light"] = FALSE // has_light
+ data["light_on"] = FALSE // light_on
+ data["comp_light_color"] = null // comp_light_color
+
+ return data
// Handles user's GUI input
-/obj/item/modular_computer/Topic(href, href_list)
+/obj/item/modular_computer/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
- if( href_list["PC_exit"] )
- kill_program()
- return 1
- if( href_list["PC_enable_component"] )
- var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(href_list["PC_enable_component"])
- if(H && istype(H) && !H.enabled)
- H.enabled = 1
- . = 1
- if( href_list["PC_disable_component"] )
- var/obj/item/weapon/computer_hardware/H = find_hardware_by_name(href_list["PC_disable_component"])
- if(H && istype(H) && H.enabled)
- H.enabled = 0
- . = 1
- if( href_list["PC_shutdown"] )
- shutdown_computer()
- return 1
- if( href_list["PC_minimize"] )
- var/mob/user = usr
- minimize_program(user)
+ return TRUE
+
+ switch(action)
+ if("PC_exit")
+ kill_program()
+ return TRUE
+ if("PC_shutdown")
+ shutdown_computer()
+ return TRUE
+ if("PC_minimize")
+ var/mob/user = usr
+ minimize_program(user)
+ if("PC_killprogram")
+ var/prog = params["name"]
+ var/datum/computer_file/program/P = null
+ var/mob/user = usr
+ if(hard_drive)
+ P = hard_drive.find_file_by_name(prog)
- if( href_list["PC_killprogram"] )
- var/prog = href_list["PC_killprogram"]
- var/datum/computer_file/program/P = null
- var/mob/user = usr
- if(hard_drive)
- P = hard_drive.find_file_by_name(prog)
+ if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
+ return
- if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED)
+ P.kill_program(1)
+ to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.")
+ return TRUE
+ if("PC_runprogram")
+ return run_program(params["name"])
+ if("PC_setautorun")
+ if(!hard_drive)
+ return
+ set_autorun(params["name"])
+ return TRUE
+ if("PC_Eject_Disk")
+ var/param = params["name"]
+ switch(param)
+ if("ID")
+ proc_eject_id(usr)
+ return TRUE
+ else
return
- P.kill_program(1)
- update_uis()
- to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.")
-
- if( href_list["PC_runprogram"] )
- return run_program(href_list["PC_runprogram"])
-
- if( href_list["PC_setautorun"] )
- if(!hard_drive)
- return
- set_autorun(href_list["PC_setautorun"])
-
- if(.)
- update_uis()
-
-// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_"
+// Function used by TGUI's to obtain data for header. All relevant entries begin with "PC_"
/obj/item/modular_computer/proc/get_header_data()
var/list/data = list()
@@ -152,4 +177,4 @@
data["PC_stationtime"] = stationtime2text()
data["PC_hasheader"] = 1
data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen
- return data
\ No newline at end of file
+ return data
diff --git a/code/modules/modular_computers/computers/modular_computer/variables.dm b/code/modules/modular_computers/computers/modular_computer/variables.dm
index 8a1641a125..373d2ad3e1 100644
--- a/code/modules/modular_computers/computers/modular_computer/variables.dm
+++ b/code/modules/modular_computers/computers/modular_computer/variables.dm
@@ -6,6 +6,7 @@
var/enabled = 0 // Whether the computer is turned on.
var/screen_on = 1 // Whether the computer is active/opened/it's screen is on.
+ var/device_theme = "ntos" // Sets the theme for the main menu, hardware config, and file browser apps. Overridden by certain non-NT devices.
var/datum/computer_file/program/active_program = null // A currently active program running on the computer.
var/hardware_flag = 0 // A flag that describes this device type
var/last_power_usage = 0 // Last tick power usage of this computer
@@ -23,6 +24,7 @@
// If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example.
icon = null // This thing isn't meant to be used on it's own. Subtypes should supply their own icon.
+ var/overlay_icon = null // Icon file used for overlays
icon_state = null
center_of_mass = null // No pixelshifting by placing on tables, etc.
randpixel = 0 // And no random pixelshifting on-creation either.
diff --git a/code/modules/modular_computers/file_system/news_article.dm b/code/modules/modular_computers/file_system/news_article.dm
index 833ba382e9..dffb978383 100644
--- a/code/modules/modular_computers/file_system/news_article.dm
+++ b/code/modules/modular_computers/file_system/news_article.dm
@@ -17,7 +17,7 @@
// NEWS DEFINITIONS BELOW THIS LINE
-/* KEPT HERE AS AN EXAMPLE
+/*
/datum/computer_file/data/news_article/space/vol_one
filename = "SPACE Magazine vol. 1"
server_file_path = 'news_articles/space_magazine_1.html'
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index 08589fb13c..d5e55940d0 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -5,9 +5,6 @@
var/required_access = null // List of required accesses to run/download the program.
var/requires_access_to_run = 1 // Whether the program checks for required_access when run.
var/requires_access_to_download = 1 // Whether the program checks for required_access when downloading.
- // NanoModule
- var/datum/nano_module/NM = null // If the program uses NanoModule, put it here and it will be automagically opened. Otherwise implement ui_interact.
- var/nanomodule_path = null // Path to nanomodule, make sure to set this if implementing new program.
// TGUIModule
var/datum/tgui_module/TM = null // If the program uses TGUIModule, put it here and it will be automagically opened. Otherwise implement tgui_interact.
var/tguimodule_path = null // Path to tguimodule, make sure to set this if implementing new program.
@@ -29,6 +26,8 @@
var/computer_emagged = 0 // Set to 1 if computer that's running us was emagged. Computer updates this every Process() tick
var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /nano/images/status_icons. Be careful not to use too large images!
var/ntnet_speed = 0 // GQ/s - current network connectivity transfer rate
+ /// Name of the tgui interface
+ var/tgui_id
/datum/computer_file/program/New(var/obj/item/modular_computer/comp = null)
..()
@@ -39,16 +38,12 @@
computer = null
. = ..()
-/datum/computer_file/program/nano_host()
- return computer.nano_host()
-
/datum/computer_file/program/tgui_host()
return computer.tgui_host()
/datum/computer_file/program/clone()
var/datum/computer_file/program/temp = ..()
temp.required_access = required_access
- temp.nanomodule_path = nanomodule_path
temp.filedesc = filedesc
temp.program_icon_state = program_icon_state
temp.requires_ntnet = requires_ntnet
@@ -134,13 +129,9 @@
/datum/computer_file/program/proc/run_program(var/mob/living/user)
if(can_run(user, 1) || !requires_access_to_run)
computer.active_program = src
- if(nanomodule_path)
- NM = new nanomodule_path(src, new /datum/topic_manager/program(src), src)
- NM.using_access = user.GetAccess()
if(tguimodule_path)
TM = new tguimodule_path(src)
TM.using_access = user.GetAccess()
- TM.tgui_interact(user)
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
@@ -152,26 +143,28 @@
program_state = PROGRAM_STATE_KILLED
if(network_destination)
generate_network_log("Connection to [network_destination] closed.")
- QDEL_NULL(NM)
if(TM)
SStgui.close_uis(TM)
- qdel(TM)
- TM = null
+ QDEL_NULL(TM)
return 1
-// This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation.
-// It returns 0 if it can't run or if NanoModule was used instead. I suggest using NanoModules where applicable.
-/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists.
+/datum/computer_file/program/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/simple/headers)
+ )
+
+/datum/computer_file/program/tgui_interact(mob/user, datum/tgui/ui)
+ if(program_state != PROGRAM_STATE_ACTIVE)
if(ui)
ui.close()
- return computer.ui_interact(user)
- if(istype(NM))
- NM.ui_interact(user, ui_key, null, force_open)
- return 0
+ return computer.tgui_interact(user)
if(istype(TM))
TM.tgui_interact(user)
return 0
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui && tgui_id)
+ ui = new(user, src, tgui_id, filedesc)
+ ui.open()
return 1
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
@@ -185,49 +178,56 @@
if(computer)
return computer.Topic(href, href_list)
+// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
+// Topic calls are automagically forwarded from NanoModule this program contains.
+// Calls beginning with "PRG_" are reserved for programs handling.
+// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program)
+// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE.
+/datum/computer_file/program/tgui_act(action,list/params, datum/tgui/ui)
+ if(..())
+ return 1
+ if(computer)
+ switch(action)
+ if("PC_exit")
+ computer.kill_program()
+ ui.close()
+ return 1
+ if("PC_shutdown")
+ computer.shutdown_computer()
+ ui.close()
+ return 1
+ if("PC_minimize")
+ var/mob/user = usr
+ if(!computer.active_program)
+ return
+
+ computer.idle_threads.Add(computer.active_program)
+ program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
+
+ computer.active_program = null
+ computer.update_icon()
+ ui.close()
+
+ if(user && istype(user))
+ computer.tgui_interact(user) // Re-open the UI on this computer. It should show the main screen now.
+
+
+
// Relays the call to nano module, if we have one
/datum/computer_file/program/proc/check_eye(var/mob/user)
- if(NM)
- return NM.check_eye(user)
if(TM)
return TM.check_eye(user)
else
return -1
-/obj/item/modular_computer/initial_data()
- return get_header_data()
-
-/obj/item/modular_computer/update_layout()
- return TRUE
-
-/datum/nano_module/program
- //available_to_ai = FALSE
- var/datum/computer_file/program/program = null // Program-Based computer program that runs this nano module. Defaults to null.
-
-/datum/nano_module/program/New(var/host, var/topic_manager, var/program)
- ..()
- src.program = program
-
-/datum/topic_manager/program
- var/datum/program
-
-/datum/topic_manager/program/New(var/datum/program)
- ..()
- src.program = program
-
-// Calls forwarded to PROGRAM itself should begin with "PRG_"
-// Calls forwarded to COMPUTER running the program should begin with "PC_"
-/datum/topic_manager/program/Topic(href, href_list)
- return program && program.Topic(href, href_list)
-
/datum/computer_file/program/apply_visual(mob/M)
- if(NM)
- return NM.apply_visual(M)
+ if(TM)
+ return TM.apply_visual(M)
/datum/computer_file/program/remove_visual(mob/M)
- if(NM)
- return NM.remove_visual(M)
+ if(TM)
+ return TM.remove_visual(M)
/datum/computer_file/program/proc/relaymove(var/mob/M, direction)
- if(NM)
- return NM.relaymove(M, direction)
\ No newline at end of file
+ if(TM)
+ return TM.relaymove(M, direction)
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm
index 04bf931593..11547e3426 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/access_decrypter.dm
@@ -6,15 +6,17 @@
program_menu_icon = "unlocked"
extended_desc = "This highly advanced script can very slowly decrypt operational codes used in almost any network. These codes can be downloaded to an ID card to expand the available access. The system administrator will probably notice this."
size = 34
- requires_ntnet = 1
- available_on_ntnet = 0
- available_on_syndinet = 1
- nanomodule_path = /datum/nano_module/program/access_decrypter/
+ requires_ntnet = TRUE
+ available_on_ntnet = FALSE
+ available_on_syndinet = TRUE
+ tgui_id = "NtosAccessDecrypter"
+
var/message = ""
var/running = FALSE
var/progress = 0
var/target_progress = 300
var/datum/access/target_access = null
+ var/list/restricted_access_codes = list(access_change_ids, access_network) // access codes that are not hackable due to balance reasons
/datum/computer_file/program/access_decrypter/kill_program(var/forced)
reset()
@@ -48,82 +50,63 @@
message = "Successfully decrypted and saved operational key codes. Downloaded access codes for: [target_access.desc]"
target_access = null
-/datum/computer_file/program/access_decrypter/Topic(href, href_list)
+/datum/computer_file/program/access_decrypter/tgui_act(action, list/params, datum/tgui/ui)
if(..())
- return 1
- if(href_list["PRG_reset"])
- reset()
- return 1
- if(href_list["PRG_execute"])
- if(running)
- return 1
- if(text2num(href_list["allowed"]))
- return 1
- var/obj/item/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit
- var/obj/item/weapon/computer_hardware/card_slot/RFID = computer.card_slot
- if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality())
- message = "A fatal hardware error has been detected."
- return
- if(!istype(RFID.stored_card))
- message = "RFID card is not present in the device. Operation aborted."
- return
- running = TRUE
- target_access = get_access_by_id(href_list["PRG_execute"])
- if(ntnet_global.intrusion_detection_enabled)
- ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]")
- ntnet_global.intrusion_detection_alarm = 1
- return 1
+ return TRUE
+ switch(action)
+ if("PRG_reset")
+ reset()
+ return TRUE
+ if("PRG_execute")
+ if(running)
+ return TRUE
+ if(text2num(params["allowed"]))
+ return TRUE
+ var/obj/item/weapon/computer_hardware/processor_unit/CPU = computer.processor_unit
+ var/obj/item/weapon/computer_hardware/card_slot/RFID = computer.card_slot
+ if(!istype(CPU) || !CPU.check_functionality() || !istype(RFID) || !RFID.check_functionality())
+ message = "A fatal hardware error has been detected."
+ return
+ if(!istype(RFID.stored_card))
+ message = "RFID card is not present in the device. Operation aborted."
+ return
+ running = TRUE
+ target_access = get_access_by_id("[params["access_target"]]")
+ if(ntnet_global.intrusion_detection_enabled)
+ ntnet_global.add_log("IDS WARNING - Unauthorised access attempt to primary keycode database from device: [computer.network_card.get_network_tag()]")
+ ntnet_global.intrusion_detection_alarm = TRUE
+ return TRUE
-/datum/nano_module/program/access_decrypter
- name = "NTNet Access Decrypter"
- var/list/restricted_access_codes = list(access_change_ids, access_network) // access codes that are not hackable due to balance reasons
-
-/datum/nano_module/program/access_decrypter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
+/datum/computer_file/program/access_decrypter/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
if(!ntnet_global)
return
- var/datum/computer_file/program/access_decrypter/PRG = program
- var/list/data = list()
- if(!istype(PRG))
- return
- data = PRG.get_header_data()
+ var/list/data = get_header_data()
- if(PRG.message)
- data["message"] = PRG.message
- else if(PRG.running)
+ var/list/regions = list()
+ data["message"] = null
+ data["running"] = running
+ if(message)
+ data["message"] = message
+ else if(running)
data["running"] = 1
- data["rate"] = PRG.computer.processor_unit.max_idle_programs
-
- // Stolen from DOS traffic generator, generates strings of 1s and 0s
- var/percentage = (PRG.progress / PRG.target_progress) * 100
- var/list/strings[0]
- for(var/j, j<10, j++)
- var/string = ""
- for(var/i, i<20, i++)
- string = "[string][prob(percentage)]"
- strings.Add(string)
- data["dos_strings"] = strings
- else if(program.computer.card_slot && program.computer.card_slot.stored_card)
- var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
- var/list/regions = list()
+ data["rate"] = computer.processor_unit.max_idle_programs
+ data["factor"] = (progress / target_progress)
+ else if(computer?.card_slot?.stored_card)
+ var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
for(var/i = 1; i <= 7; i++)
var/list/accesses = list()
for(var/access in get_region_accesses(i))
- if (get_access_desc(access))
+ if(get_access_desc(access) && !(access in restricted_access_codes))
accesses.Add(list(list(
- "desc" = replacetext(get_access_desc(access), " ", " "),
+ "desc" = replacetext(get_access_desc(access), " ", " "),
"ref" = access,
- "allowed" = (access in id_card.access) ? 1 : 0,
- "blocked" = (access in restricted_access_codes) ? 1 : 0)))
+ "allowed" = (access in id_card.access) ? 1 : 0
+ )))
regions.Add(list(list(
"name" = get_region_accesses_name(i),
- "accesses" = accesses)))
- data["regions"] = regions
+ "accesses" = accesses
+ )))
+ data["regions"] = regions
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "access_decrypter.tmpl", "NTNet Access Decrypter", 550, 400, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
\ No newline at end of file
+ return data
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
index 0e0a1381bd..e1fa0cfa8a 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
@@ -6,10 +6,11 @@
program_menu_icon = "arrow-4-diag"
extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect"
size = 20
- requires_ntnet = 1
- available_on_ntnet = 0
- available_on_syndinet = 1
- nanomodule_path = /datum/nano_module/program/computer_dos/
+ requires_ntnet = TRUE
+ available_on_ntnet = FALSE
+ available_on_syndinet = TRUE
+ tgui_id = "NtosNetDos"
+
var/obj/machinery/ntnet_relay/target = null
var/dos_speed = 0
var/error = ""
@@ -39,70 +40,51 @@
..(forced)
-/datum/nano_module/program/computer_dos
- name = "DoS Traffic Generator"
-
-/datum/nano_module/program/computer_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
+/datum/computer_file/program/ntnet_dos/tgui_data(mob/user)
if(!ntnet_global)
return
- var/datum/computer_file/program/ntnet_dos/PRG = program
- var/list/data = list()
- if(!istype(PRG))
- return
- data = PRG.get_header_data()
- if(PRG.error)
- data["error"] = PRG.error
- else if(PRG.target && PRG.executed)
- data["target"] = 1
- data["speed"] = PRG.dos_speed
+ var/list/data = get_header_data()
- // This is mostly visual, generate some strings of 1s and 0s
- // Probability of 1 is equal of completion percentage of DoS attack on this relay.
- // Combined with UI updates this adds quite nice effect to the UI
- var/percentage = PRG.target.dos_overload * 100 / PRG.target.dos_capacity
- var/list/strings[0]
- for(var/j, j<10, j++)
- var/string = ""
- for(var/i, i<20, i++)
- string = "[string][prob(percentage)]"
- strings.Add(string)
- data["dos_strings"] = strings
+ data["error"] = error
+ if(target && executed)
+ data["target"] = TRUE
+ data["speed"] = dos_speed
+
+ data["overload"] = target.dos_overload
+ data["capacity"] = target.dos_capacity
else
- var/list/relays[0]
+ data["target"] = FALSE
+ data["relays"] = list()
for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
- relays.Add(R.uid)
- data["relays"] = relays
- data["focus"] = PRG.target ? PRG.target.uid : null
+ data["relays"] += list(list("id" = R.uid))
+ data["focus"] = target ? target.uid : null
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "ntnet_dos.tmpl", "DoS Traffic Generator", 400, 250, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ return data
-/datum/computer_file/program/ntnet_dos/Topic(href, href_list)
+/datum/computer_file/program/ntnet_dos/tgui_act(action, params)
if(..())
- return 1
- if(href_list["PRG_target_relay"])
- for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
- if("[R.uid]" == href_list["PRG_target_relay"])
- target = R
- return 1
- if(href_list["PRG_reset"])
- if(target)
- target.dos_sources.Remove(src)
- target = null
- executed = 0
- error = ""
- return 1
- if(href_list["PRG_execute"])
- if(target)
- executed = 1
- target.dos_sources.Add(src)
- if(ntnet_global.intrusion_detection_enabled)
- ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [computer.network_card.get_network_tag()]")
- ntnet_global.intrusion_detection_alarm = 1
- return 1
+ return TRUE
+ switch(action)
+ if("PRG_target_relay")
+ for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
+ if(R.uid == text2num(params["targid"]))
+ target = R
+ break
+ return TRUE
+ if("PRG_reset")
+ if(target)
+ target.dos_sources.Remove(src)
+ target = null
+ executed = FALSE
+ error = ""
+ return TRUE
+ if("PRG_execute")
+ if(target)
+ executed = TRUE
+ target.dos_sources.Add(src)
+ if(ntnet_global.intrusion_detection_enabled)
+ var/obj/item/weapon/computer_hardware/network_card/network_card = computer.network_card
+ ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]")
+ ntnet_global.intrusion_detection_alarm = TRUE
+ return TRUE
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
index 17199c3b18..5d0e291336 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
@@ -6,10 +6,10 @@
program_menu_icon = "home"
extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution."
size = 13
- requires_ntnet = 0
- available_on_ntnet = 0
- available_on_syndinet = 1
- nanomodule_path = /datum/nano_module/program/revelation/
+ requires_ntnet = FALSE
+ available_on_ntnet = FALSE
+ available_on_syndinet = TRUE
+ tgui_id = "NtosRevelation"
var/armed = 0
/datum/computer_file/program/revelation/run_program(var/mob/living/user)
@@ -37,48 +37,31 @@
if(computer.tesla_link && prob(50))
qdel(computer.tesla_link)
-/datum/computer_file/program/revelation/Topic(href, href_list)
+/datum/computer_file/program/revelation/tgui_act(action, params)
if(..())
- return 1
- else if(href_list["PRG_arm"])
- armed = !armed
- else if(href_list["PRG_activate"])
- activate()
- else if(href_list["PRG_obfuscate"])
- var/mob/living/user = usr
- var/newname = sanitize(input(user, "Enter new program name: "))
- if(!newname)
- return
- filedesc = newname
- for(var/datum/computer_file/program/P in ntnet_global.available_station_software)
- if(filedesc == P.filedesc)
- program_menu_icon = P.program_menu_icon
- break
- return 1
+ return
+ switch(action)
+ if("PRG_arm")
+ armed = !armed
+ return TRUE
+ if("PRG_activate")
+ activate()
+ return TRUE
+ if("PRG_obfuscate")
+ var/newname = params["new_name"]
+ if(!newname)
+ return
+ filedesc = newname
+ return TRUE
/datum/computer_file/program/revelation/clone()
var/datum/computer_file/program/revelation/temp = ..()
temp.armed = armed
return temp
-/datum/nano_module/program/revelation
- name = "Revelation Virus"
+/datum/computer_file/program/revelation/tgui_data(mob/user)
+ var/list/data = get_header_data()
-/datum/nano_module/program/revelation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- var/list/data = list()
- var/datum/computer_file/program/revelation/PRG = program
- if(!istype(PRG))
- return
-
- data = PRG.get_header_data()
-
- data["armed"] = PRG.armed
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "revelation.tmpl", "Revelation Virus", 400, 250, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ data["armed"] = armed
+ return data
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/command/card.dm b/code/modules/modular_computers/file_system/programs/command/card.dm
index aa122c0abf..47fe4ea2b3 100644
--- a/code/modules/modular_computers/file_system/programs/command/card.dm
+++ b/code/modules/modular_computers/file_system/programs/command/card.dm
@@ -1,7 +1,7 @@
/datum/computer_file/program/card_mod
filename = "cardmod"
filedesc = "ID card modification program"
- nanomodule_path = /datum/nano_module/program/card_mod
+ tguimodule_path = /datum/tgui_module/cardmod
program_icon_state = "id"
program_key_state = "id_key"
program_menu_icon = "key"
@@ -9,220 +9,3 @@
required_access = access_change_ids
requires_ntnet = 0
size = 8
-
-/datum/nano_module/program/card_mod
- name = "ID card modification program"
- var/mod_mode = 1
- var/is_centcom = 0
- var/show_assignments = 0
-
-/datum/nano_module/program/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- var/list/data = host.initial_data()
-
- data["src"] = "\ref[src]"
- data["station_name"] = station_name()
- data["manifest"] = data_core ? data_core.get_manifest(0) : null
- data["assignments"] = show_assignments
- if(program && program.computer)
- data["have_id_slot"] = !!program.computer.card_slot
- data["have_printer"] = !!program.computer.nano_printer
- data["authenticated"] = program.can_run(user)
- if(!program.computer.card_slot)
- mod_mode = 0 //We can't modify IDs when there is no card reader
- else
- data["have_id_slot"] = 0
- data["have_printer"] = 0
- data["authenticated"] = 0
- data["mmode"] = mod_mode
- data["centcom_access"] = is_centcom
-
- if(program && program.computer && program.computer.card_slot)
- var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
- data["has_id"] = !!id_card
- data["id_account_number"] = id_card ? id_card.associated_account_number : null
- data["id_rank"] = id_card && id_card.assignment ? id_card.assignment : "Unassigned"
- data["id_owner"] = id_card && id_card.registered_name ? id_card.registered_name : "-----"
- data["id_name"] = id_card ? id_card.name : "-----"
-
- var/list/departments = list()
- for(var/D in SSjob.get_all_department_datums())
- var/datum/department/dept = D
- if(!dept.assignable) // No AI ID cards for you.
- continue
- if(dept.centcom_only && !is_centcom)
- continue
- departments[++departments.len] = list("department_name" = dept.name, "jobs" = format_jobs(SSjob.get_job_titles_in_department(dept.name)) )
-
- data["departments"] = departments
-
- data["all_centcom_access"] = is_centcom ? get_accesses(1) : null
- data["regions"] = get_accesses()
-
- if(program.computer.card_slot && program.computer.card_slot.stored_card)
- var/obj/item/weapon/card/id/id_card = program.computer.card_slot.stored_card
- if(is_centcom)
- var/list/all_centcom_access = list()
- for(var/access in get_all_centcom_access())
- all_centcom_access.Add(list(list(
- "desc" = replacetext(get_centcom_access_desc(access), " ", " "),
- "ref" = access,
- "allowed" = (access in id_card.access) ? 1 : 0)))
- data["all_centcom_access"] = all_centcom_access
- else
- var/list/regions = list()
- for(var/i = 1; i <= 7; i++)
- var/list/accesses = list()
- for(var/access in get_region_accesses(i))
- if (get_access_desc(access))
- accesses.Add(list(list(
- "desc" = replacetext(get_access_desc(access), " ", " "),
- "ref" = access,
- "allowed" = (access in id_card.access) ? 1 : 0)))
-
- regions.Add(list(list(
- "name" = get_region_accesses_name(i),
- "accesses" = accesses)))
- data["regions"] = regions
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "mod_identification_computer.tmpl", name, 600, 700, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
-
-/datum/nano_module/program/card_mod/proc/format_jobs(list/jobs)
- var/obj/item/weapon/card/id/id_card = program.computer.card_slot ? program.computer.card_slot.stored_card : null
- var/list/formatted = list()
- for(var/job in jobs)
- formatted.Add(list(list(
- "display_name" = replacetext(job, " ", " "),
- "target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned",
- "job" = job)))
-
- return formatted
-
-/datum/nano_module/program/card_mod/proc/get_accesses(var/is_centcom = 0)
- return null
-
-
-/datum/computer_file/program/card_mod/Topic(href, href_list)
- if(..())
- return 1
-
- var/mob/user = usr
- var/obj/item/weapon/card/id/user_id_card = user.GetIdCard()
- var/obj/item/weapon/card/id/id_card
- if (computer.card_slot)
- id_card = computer.card_slot.stored_card
-
- var/datum/nano_module/program/card_mod/module = NM
- switch(href_list["action"])
- if("switchm")
- if(href_list["target"] == "mod")
- module.mod_mode = 1
- else if (href_list["target"] == "manifest")
- module.mod_mode = 0
- if("togglea")
- if(module.show_assignments)
- module.show_assignments = 0
- else
- module.show_assignments = 1
- if("print")
- if(computer && computer.nano_printer) //This option should never be called if there is no printer
- if(module.mod_mode)
- if(can_run(user, 1))
- var/contents = {"Access Report
- Prepared By: [user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]
- For: [id_card.registered_name ? id_card.registered_name : "Unregistered"]
-
- Assignment: [id_card.assignment]
- Account Number: #[id_card.associated_account_number]
- Blood Type: [id_card.blood_type]
- Access:
- "}
-
- var/known_access_rights = get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM)
- for(var/A in id_card.access)
- if(A in known_access_rights)
- contents += " [get_access_desc(A)]"
-
- if(!computer.nano_printer.print_text(contents,"access report"))
- to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.")
- return
- else
- computer.visible_message("\The [computer] prints out paper.")
- else
- var/contents = {"Crew Manifest
-
- [data_core ? data_core.get_manifest(0) : ""]
- "}
- if(!computer.nano_printer.print_text(contents,text("crew manifest ([])", stationtime2text())))
- to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.")
- return
- else
- computer.visible_message("\The [computer] prints out paper.")
- if("eject")
- if(computer && computer.card_slot)
- if(id_card)
- data_core.manifest_modify(id_card.registered_name, id_card.assignment)
- computer.proc_eject_id(user)
- if("terminate")
- if(computer && can_run(user, 1))
- id_card.assignment = "Dismissed" //VOREStation Edit: setting adjustment
- id_card.access = list()
- callHook("terminate_employee", list(id_card))
- if("edit")
- if(computer && can_run(user, 1))
- if(href_list["name"])
- var/temp_name = sanitizeName(input("Enter name.", "Name", id_card.registered_name),allow_numbers=TRUE)
- if(temp_name)
- id_card.registered_name = temp_name
- else
- computer.visible_message("[computer] buzzes rudely.")
- else if(href_list["account"])
- var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number))
- id_card.associated_account_number = account_num
- if("assign")
- if(computer && can_run(user, 1) && id_card)
- var/t1 = href_list["assign_target"]
- if(t1 == "Custom")
- var/temp_t = sanitize(input("Enter a custom job assignment.","Assignment", id_card.assignment), 45)
- //let custom jobs function as an impromptu alt title, mainly for sechuds
- if(temp_t)
- id_card.assignment = temp_t
- else
- var/list/access = list()
- if(module.is_centcom)
- access = get_centcom_access(t1)
- else
- var/datum/job/jobdatum
- for(var/jobtype in typesof(/datum/job))
- var/datum/job/J = new jobtype
- if(ckey(J.title) == ckey(t1))
- jobdatum = J
- break
- if(!jobdatum)
- to_chat(usr, "No log exists for this job: [t1]")
- return
-
- access = jobdatum.get_access()
-
- id_card.access = access
- id_card.assignment = t1
- id_card.rank = t1
-
- callHook("reassign_employee", list(id_card))
- if("access")
- if(href_list["allowed"] && computer && can_run(user, 1))
- var/access_type = text2num(href_list["access_target"])
- var/access_allowed = text2num(href_list["allowed"])
- if(access_type in get_access_ids(ACCESS_TYPE_STATION|ACCESS_TYPE_CENTCOM))
- id_card.access -= access_type
- if(!access_allowed)
- id_card.access += access_type
- if(id_card)
- id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])")
-
- SSnanoui.update_uis(NM)
- return 1
diff --git a/code/modules/modular_computers/file_system/programs/command/comm.dm b/code/modules/modular_computers/file_system/programs/command/comm.dm
index fc2efa8820..a2079ad494 100644
--- a/code/modules/modular_computers/file_system/programs/command/comm.dm
+++ b/code/modules/modular_computers/file_system/programs/command/comm.dm
@@ -9,7 +9,7 @@
program_icon_state = "comm"
program_key_state = "med_key"
program_menu_icon = "flag"
- nanomodule_path = /datum/nano_module/program/comm
+ tguimodule_path = /datum/tgui_module/communications/ntos
extended_desc = "Used to command and control. Can relay long-range communications. This program can not be run on tablet computers."
required_access = access_heads
requires_ntnet = 1
@@ -24,269 +24,6 @@
temp.message_core.messages = message_core.messages.Copy()
return temp
-/datum/nano_module/program/comm
- name = "Command and Communications Program"
- //available_to_ai = TRUE
- var/current_status = STATE_DEFAULT
- var/msg_line1 = ""
- var/msg_line2 = ""
- var/centcomm_message_cooldown = 0
- var/announcment_cooldown = 0
- var/datum/announcement/priority/crew_announcement = new
- var/current_viewing_message_id = 0
- var/current_viewing_message = null
-
-/datum/nano_module/program/comm/New()
- ..()
- crew_announcement.newscast = 1
-
-/datum/nano_module/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- var/list/data = host.initial_data()
-
- if(program)
- data["emagged"] = program.computer_emagged
- data["net_comms"] = !!program.get_signal(NTNET_COMMUNICATION) //Double !! is needed to get 1 or 0 answer
- data["net_syscont"] = !!program.get_signal(NTNET_SYSTEMCONTROL)
- if(program.computer)
- data["have_printer"] = !!program.computer.nano_printer
- else
- data["have_printer"] = 0
- else
- data["emagged"] = 0
- data["net_comms"] = 1
- data["net_syscont"] = 1
- data["have_printer"] = 0
-
- data["message_line1"] = msg_line1
- data["message_line2"] = msg_line2
- data["state"] = current_status
- data["isAI"] = issilicon(usr)
- data["authenticated"] = get_authentication_level(user)
- data["current_security_level"] = security_level
- data["current_security_level_title"] = num2seclevel(security_level)
-
- data["def_SEC_LEVEL_DELTA"] = SEC_LEVEL_DELTA
- data["def_SEC_LEVEL_YELLOW"] = SEC_LEVEL_YELLOW
- data["def_SEC_LEVEL_ORANGE"] = SEC_LEVEL_ORANGE
- data["def_SEC_LEVEL_VIOLET"] = SEC_LEVEL_VIOLET
- data["def_SEC_LEVEL_BLUE"] = SEC_LEVEL_BLUE
- data["def_SEC_LEVEL_GREEN"] = SEC_LEVEL_GREEN
-
- var/datum/comm_message_listener/l = obtain_message_listener()
- data["messages"] = l.messages
- data["message_deletion_allowed"] = l != global_message_listener
- data["message_current_id"] = current_viewing_message_id
- if(current_viewing_message)
- data["message_current"] = current_viewing_message
-
- if(emergency_shuttle.location())
- data["have_shuttle"] = 1
- if(emergency_shuttle.online())
- data["have_shuttle_called"] = 1
- else
- data["have_shuttle_called"] = 0
- else
- data["have_shuttle"] = 0
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "mod_communication.tmpl", name, 550, 420, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
-
-/datum/nano_module/program/comm/proc/get_authentication_level(var/mob/user)
- if(program)
- if(program.can_run(user, 0, access_captain))
- return 2
- else
- return program.can_run(user)
- return 1
-
-/datum/nano_module/program/comm/proc/obtain_message_listener()
- if(program)
- var/datum/computer_file/program/comm/P = program
- return P.message_core
- return global_message_listener
-
-/datum/nano_module/program/comm/Topic(href, href_list)
- if(..())
- return 1
- var/mob/user = usr
- var/ntn_comm = program ? !!program.get_signal(NTNET_COMMUNICATION) : 1
- var/ntn_cont = program ? !!program.get_signal(NTNET_SYSTEMCONTROL) : 1
- var/datum/comm_message_listener/l = obtain_message_listener()
- switch(href_list["action"])
- if("sw_menu")
- . = 1
- current_status = text2num(href_list["target"])
- if("announce")
- . = 1
- if(get_authentication_level(user) == 2 && !issilicon(usr) && ntn_comm)
- if(user)
- var/obj/item/weapon/card/id/id_card = user.GetIdCard()
- crew_announcement.announcer = GetNameAndAssignmentFromId(id_card)
- else
- crew_announcement.announcer = "Unknown"
- if(announcment_cooldown)
- to_chat(usr, "Please allow at least one minute to pass between announcements")
- return TRUE
- var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") as null|message
- if(!input || !can_still_topic())
- return 1
- crew_announcement.Announce(input)
- announcment_cooldown = 1
- spawn(600)//One minute cooldown
- announcment_cooldown = 0
- if("message")
- . = 1
- if(href_list["target"] == "emagged")
- if(program)
- if(get_authentication_level(user) == 2 && program.computer_emagged && !issilicon(usr) && ntn_comm)
- if(centcomm_message_cooldown)
- to_chat(usr, "Arrays recycling. Please stand by.")
- SSnanoui.update_uis(src)
- return
- var/input = sanitize(input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response. There is a 30 second delay before you may send another message, be clear, full and concise.", "To abort, send an empty message.", "") as null|text)
- if(!input || !can_still_topic())
- return 1
- Syndicate_announce(input, usr)
- to_chat(usr, "Message transmitted.")
- log_say("[key_name(usr)] has made an illegal announcement: [input]")
- centcomm_message_cooldown = 1
- spawn(300)//30 second cooldown
- centcomm_message_cooldown = 0
- else if(href_list["target"] == "regular")
- if(get_authentication_level(user) == 2 && !issilicon(usr) && ntn_comm)
- if(centcomm_message_cooldown)
- to_chat(usr, "Arrays recycling. Please stand by.")
- SSnanoui.update_uis(src)
- return
- if(!is_relay_online())//Contact Centcom has a check, Syndie doesn't to allow for Traitor funs.
- to_chat(usr, "No Emergency Bluespace Relay detected. Unable to transmit message.")
- return 1
- var/input = sanitize(input("Please choose a message to transmit to Centcomm via quantum entanglement. \
- Please be aware that this process is very expensive, and abuse will lead to... termination. \
- Transmission does not guarantee a response. There is a 30 second delay before you may send another message, \
- be clear, full and concise.", "Central Command Quantum Messaging") as null|message)
- if(!input || !can_still_topic())
- return 1
- CentCom_announce(input, usr)
- to_chat(usr, "Message transmitted.")
- log_say("[key_name(usr)] has made an IA Centcomm announcement: [input]")
- centcomm_message_cooldown = 1
- spawn(300) //30 second cooldown
- centcomm_message_cooldown = 0
- if("shuttle")
- . = 1
- if(get_authentication_level(user) && ntn_cont)
- if(href_list["target"] == "call")
- var/confirm = alert("Are you sure you want to call the shuttle?", name, "No", "Yes")
- if(confirm == "Yes" && can_still_topic())
- call_shuttle_proc(usr)
-
- if(href_list["target"] == "cancel" && !issilicon(usr))
- var/confirm = alert("Are you sure you want to cancel the shuttle?", name, "No", "Yes")
- if(confirm == "Yes" && can_still_topic())
- cancel_call_proc(usr)
- if("setstatus")
- . = 1
- if(get_authentication_level(user) && ntn_cont)
- switch(href_list["target"])
- if("line1")
- var/linput = reject_bad_text(sanitize(input("Line 1", "Enter Message Text", msg_line1) as text|null, 40), 40)
- if(can_still_topic())
- msg_line1 = linput
- if("line2")
- var/linput = reject_bad_text(sanitize(input("Line 2", "Enter Message Text", msg_line2) as text|null, 40), 40)
- if(can_still_topic())
- msg_line2 = linput
- if("message")
- post_status("message", msg_line1, msg_line2)
- if("alert")
- post_status("alert", href_list["alert"])
- else
- post_status(href_list["target"])
- if("setalert")
- . = 1
- if(get_authentication_level(user) && !issilicon(usr) && ntn_cont && ntn_comm)
- var/current_level = text2num(href_list["target"])
- var/confirm = alert("Are you sure you want to change alert level to [num2seclevel(current_level)]?", name, "No", "Yes")
- if(confirm == "Yes" && can_still_topic())
- var/old_level = security_level
- if(!current_level) current_level = SEC_LEVEL_GREEN
- if(current_level < SEC_LEVEL_GREEN) current_level = SEC_LEVEL_GREEN
- if(current_level > SEC_LEVEL_BLUE) current_level = SEC_LEVEL_BLUE //Cannot engage delta with this
- set_security_level(current_level)
- if(security_level != old_level)
- log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
- message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
- switch(security_level)
- if(SEC_LEVEL_GREEN)
- feedback_inc("alert_comms_green",1)
- if(SEC_LEVEL_YELLOW)
- feedback_inc("alert_comms_yellow",1)
- if(SEC_LEVEL_ORANGE)
- feedback_inc("alert_comms_orange",1)
- if(SEC_LEVEL_VIOLET)
- feedback_inc("alert_comms_violet",1)
- if(SEC_LEVEL_BLUE)
- feedback_inc("alert_comms_blue",1)
- else
- to_chat(usr, "You press button, but red light flashes and nothing happens.")//This should never happen
-
- current_status = STATE_DEFAULT
- if("viewmessage")
- . = 1
- if(get_authentication_level(user) && ntn_comm)
- current_viewing_message_id = text2num(href_list["target"])
- for(var/list/m in l.messages)
- if(m["id"] == current_viewing_message_id)
- current_viewing_message = m
- current_status = STATE_VIEWMESSAGE
- if("delmessage")
- . = 1
- if(get_authentication_level(user) && ntn_comm && l != global_message_listener)
- l.Remove(current_viewing_message)
- current_status = STATE_MESSAGELIST
- if("printmessage")
- . = 1
- if(get_authentication_level(user) && ntn_comm)
- if(program && program.computer && program.computer.nano_printer)
- if(!program.computer.nano_printer.print_text(current_viewing_message["contents"],current_viewing_message["title"]))
- to_chat(usr, "Hardware error: Printer was unable to print the file. It may be out of paper.")
- else
- program.computer.visible_message("\The [program.computer] prints out paper.")
-
-
-/datum/nano_module/program/comm/proc/post_status(var/command, var/data1, var/data2)
-
- var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
-
- if(!frequency) return
-
-
- var/datum/signal/status_signal = new
- status_signal.source = src
- status_signal.transmission_method = TRANSMISSION_RADIO
- status_signal.data["command"] = command
-
- switch(command)
- if("message")
- status_signal.data["msg1"] = data1
- status_signal.data["msg2"] = data2
- log_admin("STATUS: [key_name(usr)] set status screen message with [src]: [data1] [data2]")
- if("alert")
- status_signal.data["picture_state"] = data1
-
- frequency.post_signal(src, status_signal)
-
-#undef STATE_DEFAULT
-#undef STATE_MESSAGELIST
-#undef STATE_VIEWMESSAGE
-#undef STATE_STATUSDISPLAY
-#undef STATE_ALERT_LEVEL
-
/*
General message handling stuff
*/
@@ -304,19 +41,9 @@ proc/post_comm_message(var/message_title, var/message_text)
message["title"] = message_title
message["contents"] = message_text
- for (var/datum/comm_message_listener/l in comm_message_listeners)
+ for(var/datum/comm_message_listener/l in comm_message_listeners)
l.Add(message)
- //Old console support
- for (var/obj/machinery/computer/communications/comm in machines)
- if (!(comm.stat & (BROKEN | NOPOWER)) && comm.prints_intercept)
- var/obj/item/weapon/paper/intercept = new /obj/item/weapon/paper( comm.loc )
- intercept.name = message_title
- intercept.info = message_text
-
- comm.messagetitle.Add(message_title)
- comm.messagetext.Add(message_text)
-
/datum/comm_message_listener
var/list/messages
diff --git a/code/modules/modular_computers/file_system/programs/generic/configurator.dm b/code/modules/modular_computers/file_system/programs/generic/configurator.dm
index c3ce1e358a..2d660c8b7e 100644
--- a/code/modules/modular_computers/file_system/programs/generic/configurator.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/configurator.dm
@@ -14,51 +14,4 @@
size = 4
available_on_ntnet = 0
requires_ntnet = 0
- nanomodule_path = /datum/nano_module/program/computer_configurator/
-
-/datum/nano_module/program/computer_configurator
- name = "NTOS Computer Configuration Tool"
- var/obj/item/modular_computer/movable = null
-
-/datum/nano_module/program/computer_configurator/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- if(program)
- movable = program.computer
- if(!istype(movable))
- movable = null
-
- // No computer connection, we can't get data from that.
- if(!movable)
- return 0
-
- var/list/data = list()
-
- if(program)
- data = program.get_header_data()
-
- var/list/hardware = movable.get_all_components()
-
- data["disk_size"] = movable.hard_drive.max_capacity
- data["disk_used"] = movable.hard_drive.used_capacity
- data["power_usage"] = movable.last_power_usage
- data["battery_exists"] = movable.battery_module ? 1 : 0
- if(movable.battery_module)
- data["battery_rating"] = movable.battery_module.battery.maxcharge
- data["battery_percent"] = round(movable.battery_module.battery.percent())
-
- var/list/all_entries[0]
- for(var/obj/item/weapon/computer_hardware/H in hardware)
- all_entries.Add(list(list(
- "name" = H.name,
- "desc" = H.desc,
- "enabled" = H.enabled,
- "critical" = H.critical,
- "powerusage" = H.power_usage
- )))
-
- data["hardware"] = all_entries
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "laptop_configuration.tmpl", "NTOS Configuration Utility", 575, 700, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
\ No newline at end of file
+ tguimodule_path = /datum/tgui_module/computer_configurator
diff --git a/code/modules/modular_computers/file_system/programs/generic/email_client.dm b/code/modules/modular_computers/file_system/programs/generic/email_client.dm
index 3e2f979bb5..32d635fef4 100644
--- a/code/modules/modular_computers/file_system/programs/generic/email_client.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/email_client.dm
@@ -11,15 +11,15 @@
var/stored_login = ""
var/stored_password = ""
- nanomodule_path = /datum/nano_module/email_client
+ tguimodule_path = /datum/tgui_module/email_client
// Persistency. Unless you log out, or unless your password changes, this will pre-fill the login data when restarting the program
/datum/computer_file/program/email_client/kill_program()
- if(NM)
- var/datum/nano_module/email_client/NME = NM
- if(NME.current_account)
- stored_login = NME.stored_login
- stored_password = NME.stored_password
+ if(TM)
+ var/datum/tgui_module/email_client/TME = TM
+ if(TME.current_account)
+ stored_login = TME.stored_login
+ stored_password = TME.stored_password
else
stored_login = ""
stored_password = ""
@@ -27,473 +27,31 @@
/datum/computer_file/program/email_client/run_program()
. = ..()
- if(NM)
- var/datum/nano_module/email_client/NME = NM
- NME.stored_login = stored_login
- NME.stored_password = stored_password
- NME.log_in()
- NME.error = ""
- NME.check_for_new_messages(1)
+ if(TM)
+ var/datum/tgui_module/email_client/TME = TM
+ TME.stored_login = stored_login
+ TME.stored_password = stored_password
+ TME.log_in()
+ TME.error = ""
+ TME.check_for_new_messages(1)
/datum/computer_file/program/email_client/proc/new_mail_notify()
- computer.visible_message("\The [computer] beeps softly, indicating a new email has been received.", 1)
+ var/turf/T = get_turf(computer) // Because visible_message is being a butt
+ if(T)
+ T.visible_message("[computer] beeps softly, indicating a new email has been received.")
+ playsound(computer, 'sound/misc/server-ready.ogg', 100, 0)
/datum/computer_file/program/email_client/process_tick()
..()
- var/datum/nano_module/email_client/NME = NM
- if(!istype(NME))
+ var/datum/tgui_module/email_client/TME = TM
+ if(!istype(TME))
return
- NME.relayed_process(ntnet_speed)
+ TME.relayed_process(ntnet_speed)
- var/check_count = NME.check_for_new_messages()
+ var/check_count = TME.check_for_new_messages()
if(check_count)
if(check_count == 2)
new_mail_notify()
ui_header = "ntnrc_new.gif"
else
ui_header = "ntnrc_idle.gif"
-
-/datum/nano_module/email_client/
- name = "Email Client"
- var/stored_login = ""
- var/stored_password = ""
- var/error = ""
-
- var/msg_title = ""
- var/msg_body = ""
- var/msg_recipient = ""
- var/datum/computer_file/msg_attachment = null
- var/folder = "Inbox"
- var/addressbook = FALSE
- var/new_message = FALSE
-
- var/last_message_count = 0 // How many messages were there during last check.
- var/read_message_count = 0 // How many messages were there when user has last accessed the UI.
-
- var/datum/computer_file/downloading = null
- var/download_progress = 0
- var/download_speed = 0
-
- var/datum/computer_file/data/email_account/current_account = null
- var/datum/computer_file/data/email_message/current_message = null
-
-/datum/nano_module/email_client/proc/log_in()
- for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts)
- if(!account.can_login)
- continue
- if(account.login == stored_login)
- if(account.password == stored_password)
- if(account.suspended)
- error = "This account has been suspended. Please contact the system administrator for assistance."
- return 0
- current_account = account
- return 1
- else
- error = "Invalid Password"
- return 0
- error = "Invalid Login"
- return 0
-
-// Returns 0 if no new messages were received, 1 if there is an unread message but notification has already been sent.
-// and 2 if there is a new message that appeared in this tick (and therefore notification should be sent by the program).
-/datum/nano_module/email_client/proc/check_for_new_messages(var/messages_read = FALSE)
- if(!current_account)
- return 0
-
- var/list/allmails = current_account.all_emails()
-
- if(allmails.len > last_message_count)
- . = 2
- else if(allmails.len > read_message_count)
- . = 1
- else
- . = 0
-
- last_message_count = allmails.len
- if(messages_read)
- read_message_count = allmails.len
-
-
-/datum/nano_module/email_client/proc/log_out()
- current_account = null
- downloading = null
- download_progress = 0
- last_message_count = 0
- read_message_count = 0
-
-/datum/nano_module/email_client/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- var/list/data = host.initial_data()
-
- // Password has been changed by other client connected to this email account
- if(current_account)
- if(current_account.password != stored_password)
- log_out()
- error = "Invalid Password"
- // Banned.
- if(current_account.suspended)
- log_out()
- error = "This account has been suspended. Please contact the system administrator for assistance."
-
- if(error)
- data["error"] = error
- else if(downloading)
- data["downloading"] = 1
- data["down_filename"] = "[downloading.filename].[downloading.filetype]"
- data["down_progress"] = download_progress
- data["down_size"] = downloading.size
- data["down_speed"] = download_speed
-
- else if(istype(current_account))
- data["current_account"] = current_account.login
- if(addressbook)
- var/list/all_accounts = list()
- for(var/datum/computer_file/data/email_account/account in ntnet_global.email_accounts)
- if(!account.can_login)
- continue
- all_accounts.Add(list(list(
- "login" = account.login
- )))
- data["addressbook"] = 1
- data["accounts"] = all_accounts
- else if(new_message)
- data["new_message"] = 1
- data["msg_title"] = msg_title
- data["msg_body"] = pencode2html(msg_body)
- data["msg_recipient"] = msg_recipient
- if(msg_attachment)
- data["msg_hasattachment"] = 1
- data["msg_attachment_filename"] = "[msg_attachment.filename].[msg_attachment.filetype]"
- data["msg_attachment_size"] = msg_attachment.size
- else if (current_message)
- data["cur_title"] = current_message.title
- data["cur_body"] = pencode2html(current_message.stored_data)
- data["cur_timestamp"] = current_message.timestamp
- data["cur_source"] = current_message.source
- data["cur_uid"] = current_message.uid
- if(istype(current_message.attachment))
- data["cur_hasattachment"] = 1
- data["cur_attachment_filename"] = "[current_message.attachment.filename].[current_message.attachment.filetype]"
- data["cur_attachment_size"] = current_message.attachment.size
- else
- data["label_inbox"] = "Inbox ([current_account.inbox.len])"
- data["label_spam"] = "Spam ([current_account.spam.len])"
- data["label_deleted"] = "Deleted ([current_account.deleted.len])"
- var/list/message_source
- if(folder == "Inbox")
- message_source = current_account.inbox
- else if(folder == "Spam")
- message_source = current_account.spam
- else if(folder == "Deleted")
- message_source = current_account.deleted
-
- if(message_source)
- data["folder"] = folder
- var/list/all_messages = list()
- for(var/datum/computer_file/data/email_message/message in message_source)
- all_messages.Add(list(list(
- "title" = message.title,
- "body" = pencode2html(message.stored_data),
- "source" = message.source,
- "timestamp" = message.timestamp,
- "uid" = message.uid
- )))
- data["messages"] = all_messages
- data["messagecount"] = all_messages.len
- else
- data["stored_login"] = stored_login
- data["stored_password"] = stars(stored_password, 0)
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "email_client.tmpl", "Email Client", 600, 450, state = state)
- if(host.update_layout())
- ui.auto_update_layout = 1
- ui.set_auto_update(1)
- ui.set_initial_data(data)
- ui.open()
-
-/datum/nano_module/email_client/proc/find_message_by_fuid(var/fuid)
- if(!istype(current_account))
- return
-
- // href_list works with strings, so this makes it a bit easier for us
- if(istext(fuid))
- fuid = text2num(fuid)
-
- for(var/datum/computer_file/data/email_message/message in current_account.all_emails())
- if(message.uid == fuid)
- return message
-
-/datum/nano_module/email_client/proc/clear_message()
- new_message = FALSE
- msg_title = ""
- msg_body = ""
- msg_recipient = ""
- msg_attachment = null
- current_message = null
-
-/datum/nano_module/email_client/proc/relayed_process(var/netspeed)
- download_speed = netspeed
- if(!downloading)
- return
- download_progress = min(download_progress + netspeed, downloading.size)
- if(download_progress >= downloading.size)
- var/obj/item/modular_computer/MC = nano_host()
- if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
- error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?"
- downloading = null
- download_progress = 0
- return 1
-
- if(MC.hard_drive.store_file(downloading))
- error = "File successfully downloaded to local device."
- else
- error = "Error saving file: I/O Error: The hard drive may be full or nonfunctional."
- downloading = null
- download_progress = 0
- return 1
-
-
-/datum/nano_module/email_client/Topic(href, href_list)
- if(..())
- return 1
- var/mob/living/user = usr
- check_for_new_messages(1) // Any actual interaction (button pressing) is considered as acknowledging received message, for the purpose of notification icons.
- if(href_list["login"])
- log_in()
- return 1
-
- if(href_list["logout"])
- log_out()
- return 1
-
- if(href_list["reset"])
- error = ""
- return 1
-
- if(href_list["new_message"])
- new_message = TRUE
- return 1
-
- if(href_list["cancel"])
- if(addressbook)
- addressbook = FALSE
- else
- clear_message()
- return 1
-
- if(href_list["addressbook"])
- addressbook = TRUE
- return 1
-
- if(href_list["set_recipient"])
- msg_recipient = sanitize(href_list["set_recipient"])
- addressbook = FALSE
- return 1
-
- if(href_list["edit_title"])
- var/newtitle = sanitize(input(user,"Enter title for your message:", "Message title", msg_title), 100)
- if(newtitle)
- msg_title = newtitle
- return 1
-
- // This uses similar editing mechanism as the FileManager program, therefore it supports various paper tags and remembers formatting.
- if(href_list["edit_body"])
- var/oldtext = html_decode(msg_body)
- oldtext = replacetext(oldtext, "\[editorbr\]", "\n")
-
- var/newtext = sanitize(replacetext(input(usr, "Enter your message. You may use most tags from paper formatting", "Message Editor", oldtext) as message|null, "\n", "\[editorbr\]"), 20000)
- if(newtext)
- msg_body = newtext
- return 1
-
- if(href_list["edit_recipient"])
- var/newrecipient = sanitize(input(user,"Enter recipient's email address:", "Recipient", msg_recipient), 100)
- if(newrecipient)
- msg_recipient = newrecipient
- return 1
-
- if(href_list["edit_login"])
- var/newlogin = sanitize(input(user,"Enter login", "Login", stored_login), 100)
- if(newlogin)
- stored_login = newlogin
- return 1
-
- if(href_list["edit_password"])
- var/newpass = sanitize(input(user,"Enter password", "Password"), 100)
- if(newpass)
- stored_password = newpass
- return 1
-
- if(href_list["delete"])
- if(!istype(current_account))
- return 1
- var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["delete"])
- if(!istype(M))
- return 1
- if(folder == "Deleted")
- current_account.deleted.Remove(M)
- qdel(M)
- else
- current_account.deleted.Add(M)
- current_account.inbox.Remove(M)
- current_account.spam.Remove(M)
- if(current_message == M)
- current_message = null
- return 1
-
- if(href_list["send"])
- if(!current_account)
- return 1
- if((msg_title == "") || (msg_body == "") || (msg_recipient == ""))
- error = "Error sending mail: Title or message body is empty!"
- return 1
-
- var/datum/computer_file/data/email_message/message = new()
- message.title = msg_title
- message.stored_data = msg_body
- message.source = current_account.login
- message.attachment = msg_attachment
- if(!current_account.send_mail(msg_recipient, message))
- error = "Error sending email: this address doesn't exist."
- return 1
- else
- error = "Email successfully sent."
- clear_message()
- return 1
-
- if(href_list["set_folder"])
- folder = href_list["set_folder"]
- return 1
-
- if(href_list["reply"])
- var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["reply"])
- if(!istype(M))
- return 1
-
- new_message = TRUE
- msg_recipient = M.source
- msg_title = "Re: [M.title]"
- msg_body = "\[editorbr\]\[editorbr\]\[editorbr\]\[br\]==============================\[br\]\[editorbr\]"
- msg_body += "Received by [current_account.login] at [M.timestamp]\[br\]\[editorbr\][M.stored_data]"
- return 1
-
- if(href_list["view"])
- var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["view"])
- if(istype(M))
- current_message = M
- return 1
-
- if(href_list["changepassword"])
- var/oldpassword = sanitize(input(user,"Please enter your old password:", "Password Change"), 100)
- if(!oldpassword)
- return 1
- var/newpassword1 = sanitize(input(user,"Please enter your new password:", "Password Change"), 100)
- if(!newpassword1)
- return 1
- var/newpassword2 = sanitize(input(user,"Please re-enter your new password:", "Password Change"), 100)
- if(!newpassword2)
- return 1
-
- if(!istype(current_account))
- error = "Please log in before proceeding."
- return 1
-
- if(current_account.password != oldpassword)
- error = "Incorrect original password"
- return 1
-
- if(newpassword1 != newpassword2)
- error = "The entered passwords do not match."
- return 1
-
- current_account.password = newpassword1
- stored_password = newpassword1
- error = "Your password has been successfully changed!"
- return 1
-
- // The following entries are Modular Computer framework only, and therefore won't do anything in other cases (like AI View)
-
- if(href_list["save"])
- // Fully dependant on modular computers here.
- var/obj/item/modular_computer/MC = nano_host()
-
- if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
- error = "Error exporting file. Are you using a functional and NTOS-compliant device?"
- return 1
-
- var/filename = sanitize(input(user,"Please specify file name:", "Message export"), 100)
- if(!filename)
- return 1
-
- var/datum/computer_file/data/email_message/M = find_message_by_fuid(href_list["save"])
- var/datum/computer_file/data/mail = istype(M) ? M.export() : null
- if(!istype(mail))
- return 1
- mail.filename = filename
- if(!MC.hard_drive || !MC.hard_drive.store_file(mail))
- error = "Internal I/O error when writing file, the hard drive may be full."
- else
- error = "Email exported successfully"
- return 1
-
- if(href_list["addattachment"])
- var/obj/item/modular_computer/MC = nano_host()
- msg_attachment = null
-
- if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
- error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?"
- return 1
-
- var/list/filenames = list()
- for(var/datum/computer_file/CF in MC.hard_drive.stored_files)
- if(CF.unsendable)
- continue
- filenames.Add(CF.filename)
- var/picked_file = input(user, "Please pick a file to send as attachment (max 32GQ)") as null|anything in filenames
-
- if(!picked_file)
- return 1
-
- if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
- error = "Error uploading file. Are you using a functional and NTOSv2-compliant device?"
- return 1
-
- for(var/datum/computer_file/CF in MC.hard_drive.stored_files)
- if(CF.unsendable)
- continue
- if(CF.filename == picked_file)
- msg_attachment = CF.clone()
- break
- if(!istype(msg_attachment))
- msg_attachment = null
- error = "Unknown error when uploading attachment."
- return 1
-
- if(msg_attachment.size > 32)
- error = "Error uploading attachment: File exceeds maximal permitted file size of 32GQ."
- msg_attachment = null
- else
- error = "File [msg_attachment.filename].[msg_attachment.filetype] has been successfully uploaded."
- return 1
-
- if(href_list["downloadattachment"])
- if(!current_account || !current_message || !current_message.attachment)
- return 1
- var/obj/item/modular_computer/MC = nano_host()
- if(!istype(MC) || !MC.hard_drive || !MC.hard_drive.check_functionality())
- error = "Error downloading file. Are you using a functional and NTOSv2-compliant device?"
- return 1
-
- downloading = current_message.attachment.clone()
- download_progress = 0
- return 1
-
- if(href_list["canceldownload"])
- downloading = null
- download_progress = 0
- return 1
-
- if(href_list["remove_attachment"])
- msg_attachment = null
- return 1
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm
index 42dfdd622d..13a137993e 100644
--- a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm
@@ -6,202 +6,190 @@
program_key_state = "generic_key"
program_menu_icon = "folder-collapsed"
size = 8
- requires_ntnet = 0
- available_on_ntnet = 0
- undeletable = 1
- nanomodule_path = /datum/nano_module/program/computer_filemanager/
+ requires_ntnet = FALSE
+ available_on_ntnet = FALSE
+ undeletable = TRUE
+ tgui_id = "NtosFileManager"
+
var/open_file
var/error
-/datum/computer_file/program/filemanager/Topic(href, href_list)
+/datum/computer_file/program/filemanager/tgui_act(action, list/params, datum/tgui/ui)
if(..())
- return 1
+ return TRUE
- if(href_list["PRG_openfile"])
- . = 1
- open_file = href_list["PRG_openfile"]
- if(href_list["PRG_newtextfile"])
- . = 1
- var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename"))
- if(!newname)
- return 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- if(!HDD)
- return 1
- var/datum/computer_file/data/F = new/datum/computer_file/data()
- F.filename = newname
- F.filetype = "TXT"
- HDD.store_file(F)
- if(href_list["PRG_deletefile"])
- . = 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- if(!HDD)
- return 1
- var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_deletefile"])
- if(!file || file.undeletable)
- return 1
- HDD.remove_file(file)
- if(href_list["PRG_usbdeletefile"])
- . = 1
- var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive
- if(!RHDD)
- return 1
- var/datum/computer_file/file = RHDD.find_file_by_name(href_list["PRG_usbdeletefile"])
- if(!file || file.undeletable)
- return 1
- RHDD.remove_file(file)
- if(href_list["PRG_closefile"])
- . = 1
- open_file = null
- error = null
- if(href_list["PRG_clone"])
- . = 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- if(!HDD)
- return 1
- var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_clone"])
- if(!F || !istype(F))
- return 1
- var/datum/computer_file/C = F.clone(1)
- HDD.store_file(C)
- if(href_list["PRG_rename"])
- . = 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- if(!HDD)
- return 1
- var/datum/computer_file/file = HDD.find_file_by_name(href_list["PRG_rename"])
- if(!file || !istype(file))
- return 1
- var/newname = sanitize(input(usr, "Enter new file name:", "File rename", file.filename))
- if(file && newname)
+ var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
+ var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive
+
+ switch(action)
+ if("PRG_openfile")
+ open_file = params["name"]
+ return TRUE
+ if("PRG_newtextfile")
+ if(!HDD)
+ return
+ var/newname = sanitize(input(usr, "Enter file name or leave blank to cancel:", "File rename"))
+ if(!newname)
+ return
+ var/datum/computer_file/data/F = new/datum/computer_file/data()
+ F.filename = newname
+ F.filetype = "TXT"
+ HDD.store_file(F)
+ return TRUE
+ if("PRG_closefile")
+ open_file = null
+ error = null
+ return TRUE
+ if("PRG_clone")
+ if(!HDD)
+ return
+ var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
+ if(!F || !istype(F))
+ return
+ var/datum/computer_file/C = F.clone(1)
+ HDD.store_file(C)
+ return TRUE
+ if("PRG_edit")
+ if(!HDD)
+ return
+ if(!open_file)
+ return
+ var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
+ if(!F || !istype(F))
+ return
+ if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
+ return
+
+ var/oldtext = html_decode(F.stored_data)
+ oldtext = replacetext(oldtext, "\[br\]", "\n")
+
+ var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH)
+ if(!newtext)
+ return
+
+ if(F)
+ var/datum/computer_file/data/backup = F.clone()
+ HDD.remove_file(F)
+ F.stored_data = newtext
+ F.calculate_size()
+ // We can't store the updated file, it's probably too large. Print an error and restore backed up version.
+ // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
+ // They will be able to copy-paste the text from error screen and store it in notepad or something.
+ if(!HDD.store_file(F))
+ error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:
[html_decode(F.stored_data)]
"
+ HDD.store_file(backup)
+ return TRUE
+ if("PRG_printfile")
+ if(!HDD)
+ return
+ if(!open_file)
+ return
+ var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
+ if(!F || !istype(F))
+ return
+ if(!computer.nano_printer)
+ error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
+ return
+ if(!computer.nano_printer.print_text(pencode2html(F.stored_data)))
+ error = "Hardware error: Printer was unable to print the file. It may be out of paper."
+ return
+ return TRUE
+ if("PRG_deletefile")
+ if(!HDD)
+ return
+ var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
+ if(!file || file.undeletable)
+ return
+ HDD.remove_file(file)
+ return TRUE
+ if("PRG_usbdeletefile")
+ if(!RHDD)
+ return
+ var/datum/computer_file/file = RHDD.find_file_by_name(params["name"])
+ if(!file || file.undeletable)
+ return
+ RHDD.remove_file(file)
+ return TRUE
+ if("PRG_rename")
+ if(!HDD)
+ return
+ var/datum/computer_file/file = HDD.find_file_by_name(params["name"])
+ if(!file)
+ return
+ var/newname = params["new_name"]
+ if(!newname)
+ return
file.filename = newname
- if(href_list["PRG_edit"])
- . = 1
- if(!open_file)
- return 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- if(!HDD)
- return 1
- var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
- if(!F || !istype(F))
- return 1
- if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
- return 1
+ return TRUE
+ if("PRG_copytousb")
+ if(!HDD || !RHDD)
+ return
+ var/datum/computer_file/F = HDD.find_file_by_name(params["name"])
+ if(!F)
+ return
+ var/datum/computer_file/C = F.clone(FALSE)
+ RHDD.store_file(C)
+ return TRUE
+ if("PRG_copyfromusb")
+ if(!HDD || !RHDD)
+ return
+ var/datum/computer_file/F = RHDD.find_file_by_name(params["name"])
+ if(!F || !istype(F))
+ return
+ var/datum/computer_file/C = F.clone(FALSE)
+ HDD.store_file(C)
+ return TRUE
- var/oldtext = html_decode(F.stored_data)
- oldtext = replacetext(oldtext, "\[br\]", "\n")
+/datum/computer_file/program/filemanager/tgui_data(mob/user)
+ var/list/data = get_header_data()
- var/newtext = sanitize(replacetext(input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", oldtext) as message|null, "\n", "\[br\]"), MAX_TEXTFILE_LENGTH)
- if(!newtext)
- return
+ var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
+ var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
- if(F)
- var/datum/computer_file/data/backup = F.clone()
- HDD.remove_file(F)
- F.stored_data = newtext
- F.calculate_size()
- // We can't store the updated file, it's probably too large. Print an error and restore backed up version.
- // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
- // They will be able to copy-paste the text from error screen and store it in notepad or something.
- if(!HDD.store_file(F))
- error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:
[html_decode(F.stored_data)]
"
- HDD.store_file(backup)
- if(href_list["PRG_printfile"])
- . = 1
- if(!open_file)
- return 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- if(!HDD)
- return 1
- var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
- if(!F || !istype(F))
- return 1
- if(!computer.nano_printer)
- error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
- return 1
- if(!computer.nano_printer.print_text(pencode2html(F.stored_data)))
- error = "Hardware error: Printer was unable to print the file. It may be out of paper."
- return 1
- if(href_list["PRG_copytousb"])
- . = 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
- if(!HDD || !RHDD)
- return 1
- var/datum/computer_file/F = HDD.find_file_by_name(href_list["PRG_copytousb"])
- if(!F || !istype(F))
- return 1
- var/datum/computer_file/C = F.clone(0)
- RHDD.store_file(C)
- if(href_list["PRG_copyfromusb"])
- . = 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.portable_drive
- if(!HDD || !RHDD)
- return 1
- var/datum/computer_file/F = RHDD.find_file_by_name(href_list["PRG_copyfromusb"])
- if(!F || !istype(F))
- return 1
- var/datum/computer_file/C = F.clone(0)
- HDD.store_file(C)
- if(.)
- SSnanoui.update_uis(NM)
+ data["error"] = null
+ if(error)
+ data["error"] = error
+ if(!computer || !HDD)
+ data["error"] = "I/O ERROR: Unable to access hard drive."
+
+ data["filedata"] = null
+ data["filename"] = null
+ data["files"] = list()
+ data["usbconnected"] = FALSE
+ data["usbfiles"] = list()
-/datum/nano_module/program/computer_filemanager
- name = "NTOS File Manager"
-
-/datum/nano_module/program/computer_filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- var/list/data = host.initial_data()
- var/datum/computer_file/program/filemanager/PRG
- PRG = program
-
- var/obj/item/weapon/computer_hardware/hard_drive/HDD
- var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD
- if(PRG.error)
- data["error"] = PRG.error
- if(PRG.open_file)
+ if(open_file)
var/datum/computer_file/data/file
- if(!PRG.computer || !PRG.computer.hard_drive)
+ if(!computer || !computer.hard_drive)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
- HDD = PRG.computer.hard_drive
- file = HDD.find_file_by_name(PRG.open_file)
+ file = HDD.find_file_by_name(open_file)
if(!istype(file))
data["error"] = "I/O ERROR: Unable to open file."
else
data["filedata"] = pencode2html(file.stored_data)
data["filename"] = "[file.filename].[file.filetype]"
else
- if(!PRG.computer || !PRG.computer.hard_drive)
- data["error"] = "I/O ERROR: Unable to access hard drive."
- else
- HDD = PRG.computer.hard_drive
- RHDD = PRG.computer.portable_drive
- var/list/files[0]
- for(var/datum/computer_file/F in HDD.stored_files)
- files.Add(list(list(
+ var/list/files = list()
+ for(var/datum/computer_file/F in HDD.stored_files)
+ files += list(list(
+ "name" = F.filename,
+ "type" = F.filetype,
+ "size" = F.size,
+ "undeletable" = F.undeletable
+ ))
+ data["files"] = files
+ if(RHDD)
+ data["usbconnected"] = TRUE
+ var/list/usbfiles = list()
+ for(var/datum/computer_file/F in RHDD.stored_files)
+ usbfiles += list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
- )))
- data["files"] = files
- if(RHDD)
- data["usbconnected"] = 1
- var/list/usbfiles[0]
- for(var/datum/computer_file/F in RHDD.stored_files)
- usbfiles.Add(list(list(
- "name" = F.filename,
- "type" = F.filetype,
- "size" = F.size,
- "undeletable" = F.undeletable
- )))
- data["usbfiles"] = usbfiles
+ ))
+ data["usbfiles"] = usbfiles
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "file_manager.tmpl", "NTOS File Manager", 575, 700, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
\ No newline at end of file
+ return data
diff --git a/code/modules/modular_computers/file_system/programs/generic/game.dm b/code/modules/modular_computers/file_system/programs/generic/game.dm
index b4c0688c29..4d21095f9d 100644
--- a/code/modules/modular_computers/file_system/programs/generic/game.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/game.dm
@@ -1,152 +1,188 @@
// This file is used as a reference for Modular Computers Development guide on the wiki. It contains a lot of excess comments, as it is intended as explanation
// for someone who may not be as experienced in coding. When making changes, please try to keep it this way.
-// An actual program definition.
/datum/computer_file/program/game
- filename = "arcadec" // File name, as shown in the file browser program.
- filedesc = "Unknown Game" // User-Friendly name. In this case, we will generate a random name in constructor.
- program_icon_state = "game" // Icon state of this program's screen.
- program_menu_icon = "script"
- extended_desc = "Fun for the whole family! Probably not an AAA title, but at least you can download it on the corporate network.." // A nice description.
- size = 5 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs.
- requires_ntnet = 0 // This particular program does not require NTNet network conectivity...
- available_on_ntnet = 1 // ... but we want it to be available for download.
- nanomodule_path = /datum/nano_module/arcade_classic/ // Path of relevant nano module. The nano module is defined further in the file.
- var/picked_enemy_name
+ filename = "dsarcade" // File name, as shown in the file browser program.
+ filedesc = "Donksoft Micro Arcade" // User-Friendly name.
+ program_icon_state = "arcade" // Icon state of this program's screen.
+ extended_desc = "This is a port of the classic game 'Outbomb Cuban Pete', redesigned to run on tablets; Now with thrilling graphics and chilling storytelling." // A nice description.
+ size = 6 // Size in GQ. Integers only. Smaller sizes should be used for utility/low use programs (like this one), while large sizes are for important programs.
+ requires_ntnet = FALSE // This particular program does not require NTNet network conectivity...
+ available_on_ntnet = TRUE // ... but we want it to be available for download.
+ tgui_id = "NtosArcade" // Path of relevant tgui template.js file.
-// Blatantly stolen and shortened version from arcade machines. Generates a random enemy name
-/datum/computer_file/program/game/proc/random_enemy_name()
- var/name_part1 = pick("the Automatic ", "Farmer ", "Lord ", "Professor ", "the Cuban ", "the Evil ", "the Dread King ", "the Space ", "Lord ", "the Great ", "Duke ", "General ")
- var/name_part2 = pick("Melonoid", "Murdertron", "Sorcerer", "Ruin", "Jeff", "Ectoplasm", "Crushulon", "Uhangoid", "Vhakoid", "Peteoid", "Slime", "Lizard Man", "Unicorn")
- return "[name_part1] [name_part2]"
+ ///Returns TRUE if the game is being played.
+ var/game_active = TRUE
+ ///This disables buttom actions from having any impact if TRUE. Resets to FALSE when the player is allowed to make an action again.
+ var/pause_state = FALSE
+ var/boss_hp = 45
+ var/boss_mp = 15
+ var/player_hp = 30
+ var/player_mp = 10
+ var/ticket_count = 0
+ ///Shows what text is shown on the app, usually showing the log of combat actions taken by the player.
+ var/heads_up = "Nanotrasen says, winners make us money."
+ var/boss_name = "Cuban Pete's Minion"
+ ///Determines which boss image to use on the UI.
+ var/boss_id = 1
-// When the program is first created, we generate a new enemy name and name ourselves accordingly.
-/datum/computer_file/program/game/New()
- ..()
- picked_enemy_name = random_enemy_name()
- filedesc = "Defeat [picked_enemy_name]"
+// This is the primary game loop, which handles the logic of being defeated or winning.
+/datum/computer_file/program/game/proc/game_check(mob/user)
+ sleep(5)
+ if(boss_hp <= 0)
+ heads_up = "You have crushed [boss_name]! Rejoice!"
+ playsound(computer.loc, 'sound/arcade/win.ogg', 50, TRUE, extrarange = -3, falloff = 10)
+ game_active = FALSE
+ program_icon_state = "arcade_off"
+ if(istype(computer))
+ computer.update_icon()
+ ticket_count += 1
+ // user?.mind?.adjust_experience(/datum/skill/gaming, 50)
+ sleep(10)
+ else if(player_hp <= 0 || player_mp <= 0)
+ heads_up = "You have been defeated... how will the station survive?"
+ playsound(computer.loc, 'sound/arcade/lose.ogg', 50, TRUE, extrarange = -3, falloff = 10)
+ game_active = FALSE
+ program_icon_state = "arcade_off"
+ if(istype(computer))
+ computer.update_icon()
+ // user?.mind?.adjust_experience(/datum/skill/gaming, 10)
+ sleep(10)
-// Important in order to ensure that copied versions will have the same enemy name.
-/datum/computer_file/program/game/clone()
- var/datum/computer_file/program/game/G = ..()
- G.picked_enemy_name = picked_enemy_name
- return G
-
-// When running the program, we also want to pass our enemy name to the nano module.
-/datum/computer_file/program/game/run_program()
- . = ..()
- if(. && NM)
- var/datum/nano_module/arcade_classic/NMC = NM
- NMC.enemy_name = picked_enemy_name
-
-
-// Nano module the program uses.
-// This can be either /datum/nano_module/ or /datum/nano_module/program. The latter is intended for nano modules that are suposed to be exclusively used with modular computers,
-// and should generally not be used, as such nano modules are hard to use on other places.
-/datum/nano_module/arcade_classic/
- name = "Classic Arcade"
- var/player_mana // Various variables specific to the nano module. In this case, the nano module is a simple arcade game, so the variables store health and other stats.
- var/player_health
- var/enemy_mana
- var/enemy_health
- var/enemy_name = "Greytide Horde"
- var/gameover
- var/information
-
-/datum/nano_module/arcade_classic/New()
- ..()
- new_game()
-
-// ui_interact handles transfer of data to NanoUI. Keep in mind that data you pass from here is actually sent to the client. In other words, don't send anything you don't want a client
-// to see, and don't send unnecessarily large amounts of data (due to laginess).
-/datum/nano_module/arcade_classic/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- var/list/data = host.initial_data()
-
- data["player_health"] = player_health
- data["player_mana"] = player_mana
- data["enemy_health"] = enemy_health
- data["enemy_mana"] = enemy_mana
- data["enemy_name"] = enemy_name
- data["gameover"] = gameover
- data["information"] = information
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "arcade_classic.tmpl", "Defeat [enemy_name]", 500, 350, state = state)
- if(host.update_layout())
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
-
-// Three helper procs i've created. These are unique to this particular nano module. If you are creating your own nano module, you'll most likely create similar procs too.
-/datum/nano_module/arcade_classic/proc/enemy_play()
- if((enemy_mana < 5) && prob(60))
- var/steal = rand(2, 3)
- player_mana -= steal
- enemy_mana += steal
- information += "[enemy_name] steals [steal] of your power!"
- else if((enemy_health < 15) && (enemy_mana > 3) && prob(80))
- var/healamt = min(rand(3, 5), enemy_mana)
- enemy_mana -= healamt
- enemy_health += healamt
- information += "[enemy_name] heals for [healamt] health!"
+// This handles the boss "AI".
+/datum/computer_file/program/game/proc/enemy_check(mob/user)
+ var/boss_attackamt = 0 //Spam protection from boss attacks as well.
+ var/boss_mpamt = 0
+ var/bossheal = 0
+ if(pause_state == TRUE)
+ boss_attackamt = rand(3,6)
+ boss_mpamt = rand (2,4)
+ bossheal = rand (4,6)
+ if(game_active == FALSE)
+ return
+ if(boss_mp <= 5)
+ heads_up = "[boss_mpamt] magic power has been stolen from you!"
+ playsound(computer.loc, 'sound/arcade/steal.ogg', 50, TRUE, extrarange = -3, falloff = 10)
+ player_mp -= boss_mpamt
+ boss_mp += boss_mpamt
+ else if(boss_mp > 5 && boss_hp <12)
+ heads_up = "[boss_name] heals for [bossheal] health!"
+ playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10)
+ boss_hp += bossheal
+ boss_mp -= boss_mpamt
else
- var/dam = rand(3,6)
- player_health -= dam
- information += "[enemy_name] attacks for [dam] damage!"
+ heads_up = "[boss_name] attacks you for [boss_attackamt] damage!"
+ playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10)
+ player_hp -= boss_attackamt
-/datum/nano_module/arcade_classic/proc/check_gameover()
- if((player_health <= 0) || player_mana <= 0)
- if(enemy_health <= 0)
- information += "You have defeated [enemy_name], but you have died in the fight!"
- else
- information += "You have been defeated by [enemy_name]!"
- gameover = 1
+ pause_state = FALSE
+ game_check()
+
+/**
+ * UI assets define a list of asset datums to be sent with the UI.
+ * In this case, it's a bunch of cute enemy sprites.
+ */
+/datum/computer_file/program/game/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/simple/arcade),
+ )
+
+/**
+ * This provides all of the relevant data to the UI in a list().
+ */
+/datum/computer_file/program/game/tgui_data(mob/user)
+ var/list/data = get_header_data()
+ data["Hitpoints"] = boss_hp
+ data["PlayerHitpoints"] = player_hp
+ data["PlayerMP"] = player_mp
+ data["TicketCount"] = ticket_count
+ data["GameActive"] = game_active
+ data["PauseState"] = pause_state
+ data["Status"] = heads_up
+ data["BossID"] = "boss[boss_id].gif"
+ return data
+
+/**
+ * This is tgui's replacement for Topic(). It handles any user input from the UI.
+ */
+/datum/computer_file/program/game/tgui_act(action, list/params)
+ if(..()) // Always call parent in tgui_act, it handles making sure the user is allowed to interact with the UI.
return TRUE
- else if(enemy_health <= 0)
- gameover = 1
- information += "Congratulations! You have defeated [enemy_name]!"
- return TRUE
- return FALSE
-/datum/nano_module/arcade_classic/proc/new_game()
- player_mana = 10
- player_health = 30
- enemy_mana = 20
- enemy_health = 45
- gameover = FALSE
- information = "A new game has started!"
+ var/obj/item/weapon/computer_hardware/nano_printer/printer
+ if(computer)
+ printer = computer.nano_printer
-
-
-/datum/nano_module/arcade_classic/Topic(href, href_list)
- if(..()) // Always begin your Topic() calls with a parent call!
- return 1
- if(href_list["new_game"])
- new_game()
- return 1 // Returning 1 (TRUE) in Topic automatically handles UI updates.
- if(gameover) // If the game has already ended, we don't want the following three topic calls to be processed at all.
- return 1 // Instead of adding checks into each of those three, we can easily add this one check here to reduce on code copy-paste.
- if(href_list["attack"])
- var/damage = rand(2, 6)
- information = "You attack for [damage] damage."
- enemy_health -= damage
- enemy_play()
- check_gameover()
- return 1
- if(href_list["heal"])
- var/healfor = rand(6, 8)
- var/cost = rand(1, 3)
- information = "You heal yourself for [healfor] damage, using [cost] energy in the process."
- player_health += healfor
- player_mana -= cost
- enemy_play()
- check_gameover()
- return 1
- if(href_list["regain_mana"])
- var/regen = rand(4, 7)
- information = "You rest of a while, regaining [regen] energy."
- player_mana += regen
- enemy_play()
- check_gameover()
- return 1
\ No newline at end of file
+ // var/gamerSkillLevel = usr.mind?.get_skill_level(/datum/skill/gaming)
+ // var/gamerSkill = usr.mind?.get_skill_modifier(/datum/skill/gaming, SKILL_RANDS_MODIFIER)
+ switch(action)
+ if("Attack")
+ var/attackamt = 0 //Spam prevention.
+ if(pause_state == FALSE)
+ attackamt = rand(2,6) // + rand(0, gamerSkill)
+ pause_state = TRUE
+ heads_up = "You attack for [attackamt] damage."
+ playsound(computer.loc, 'sound/arcade/hit.ogg', 50, TRUE, extrarange = -3, falloff = 10)
+ boss_hp -= attackamt
+ sleep(10)
+ game_check()
+ enemy_check()
+ return TRUE
+ if("Heal")
+ var/healamt = 0 //More Spam Prevention.
+ var/healcost = 0
+ if(pause_state == FALSE)
+ healamt = rand(6,8) // + rand(0, gamerSkill)
+ var/maxPointCost = 3
+ // if(gamerSkillLevel >= SKILL_LEVEL_JOURNEYMAN)
+ // maxPointCost = 2
+ healcost = rand(1, maxPointCost)
+ pause_state = TRUE
+ heads_up = "You heal for [healamt] damage."
+ playsound(computer.loc, 'sound/arcade/heal.ogg', 50, TRUE, extrarange = -3, falloff = 10)
+ player_hp += healamt
+ player_mp -= healcost
+ sleep(10)
+ game_check()
+ enemy_check()
+ return TRUE
+ if("Recharge_Power")
+ var/rechargeamt = 0 //As above.
+ if(pause_state == FALSE)
+ rechargeamt = rand(4,7) // + rand(0, gamerSkill)
+ pause_state = TRUE
+ heads_up = "You regain [rechargeamt] magic power."
+ playsound(computer.loc, 'sound/arcade/mana.ogg', 50, TRUE, extrarange = -3, falloff = 10)
+ player_mp += rechargeamt
+ sleep(10)
+ game_check()
+ enemy_check()
+ return TRUE
+ if("Dispense_Tickets")
+ if(!printer)
+ to_chat(usr, "Hardware error: A printer is required to redeem tickets.")
+ return
+ if(printer.stored_paper <= 0)
+ to_chat(usr, "Hardware error: Printer is out of paper.")
+ return
+ else
+ computer.visible_message("\The [computer] prints out paper.")
+ if(ticket_count >= 1)
+ new /obj/item/stack/arcadeticket((get_turf(computer)), 1)
+ to_chat(usr, "[src] dispenses a ticket!")
+ ticket_count -= 1
+ printer.stored_paper -= 1
+ else
+ to_chat(usr, "You don't have any stored tickets!")
+ return TRUE
+ if("Start_Game")
+ game_active = TRUE
+ boss_hp = 45
+ player_hp = 30
+ player_mp = 10
+ heads_up = "You stand before [boss_name]! Prepare for battle!"
+ program_icon_state = "arcade"
+ boss_id = rand(1,6)
+ pause_state = FALSE
+ if(istype(computer))
+ computer.update_icon()
diff --git a/code/modules/modular_computers/file_system/programs/generic/news_browser.dm b/code/modules/modular_computers/file_system/programs/generic/news_browser.dm
index 1d4da6d4d5..e72e30fd38 100644
--- a/code/modules/modular_computers/file_system/programs/generic/news_browser.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/news_browser.dm
@@ -6,16 +6,17 @@
program_key_state = "generic_key"
program_menu_icon = "contact"
size = 4
- requires_ntnet = 1
- available_on_ntnet = 1
+ requires_ntnet = TRUE
+ available_on_ntnet = TRUE
+
+ tgui_id = "NtosNewsBrowser"
- nanomodule_path = /datum/nano_module/program/computer_newsbrowser/
var/datum/computer_file/data/news_article/loaded_article
var/download_progress = 0
var/download_netspeed = 0
- var/downloading = 0
+ var/downloading = FALSE
var/message = ""
- var/show_archived = 0
+ var/show_archived = FALSE
/datum/computer_file/program/newsbrowser/process_tick()
if(!downloading)
@@ -33,86 +34,31 @@
if(download_progress >= loaded_article.size)
downloading = 0
requires_ntnet = 0 // Turn off NTNet requirement as we already loaded the file into local memory.
- SSnanoui.update_uis(NM)
+ SStgui.update_uis(src)
-/datum/computer_file/program/newsbrowser/kill_program()
- ..()
- requires_ntnet = 1
- loaded_article = null
- download_progress = 0
- downloading = 0
- show_archived = 0
+/datum/computer_file/program/newsbrowser/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = get_header_data()
-/datum/computer_file/program/newsbrowser/Topic(href, href_list)
- if(..())
- return 1
- if(href_list["PRG_openarticle"])
- . = 1
- if(downloading || loaded_article)
- return 1
-
- for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news)
- if(N.uid == text2num(href_list["PRG_openarticle"]))
- loaded_article = N.clone()
- downloading = 1
- break
- if(href_list["PRG_reset"])
- . = 1
- downloading = 0
- download_progress = 0
- requires_ntnet = 1
- loaded_article = null
- if(href_list["PRG_clearmessage"])
- . = 1
- message = ""
- if(href_list["PRG_savearticle"])
- . = 1
- if(downloading || !loaded_article)
- return
-
- var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename))
- if(!savename)
- return 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- if(!HDD)
- return 1
- var/datum/computer_file/data/news_article/N = loaded_article.clone()
- N.filename = savename
- HDD.store_file(N)
- if(href_list["PRG_toggle_archived"])
- . = 1
- show_archived = !show_archived
- if(.)
- SSnanoui.update_uis(NM)
-
-
-/datum/nano_module/program/computer_newsbrowser
- name = "NTNet/ExoNet News Browser"
-
-/datum/nano_module/program/computer_newsbrowser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
-
- var/datum/computer_file/program/newsbrowser/PRG
- var/list/data = list()
- if(program)
- data = program.get_header_data()
- PRG = program
- else
- return
-
- data["message"] = PRG.message
- if(PRG.loaded_article && !PRG.downloading) // Viewing an article.
- data["title"] = PRG.loaded_article.filename
- data["cover"] = PRG.loaded_article.cover
- data["article"] = PRG.loaded_article.stored_data
- else if(PRG.downloading) // Downloading an article.
- data["download_running"] = 1
- data["download_progress"] = PRG.download_progress
- data["download_maxprogress"] = PRG.loaded_article.size
- data["download_rate"] = PRG.download_netspeed
+ var/list/all_articles = list()
+ data["message"] = message
+ data["showing_archived"] = show_archived
+ data["download"] = null
+ data["article"] = null
+ if(loaded_article && !downloading) // Viewing an article.
+ data["article"] = list(
+ "title" = loaded_article.filename,
+ "cover" = loaded_article.cover,
+ "content" = loaded_article.stored_data,
+ )
+ else if(downloading) // Downloading an article.
+ data["download"] = list(
+ "download_progress" = download_progress,
+ "download_maxprogress" = loaded_article.size,
+ "download_rate" = download_netspeed
+ )
else // Viewing list of articles
- var/list/all_articles[0]
for(var/datum/computer_file/data/news_article/F in ntnet_global.available_news)
- if(!PRG.show_archived && F.archived)
+ if(!show_archived && F.archived)
continue
all_articles.Add(list(list(
"name" = F.filename,
@@ -120,12 +66,56 @@
"uid" = F.uid,
"archived" = F.archived
)))
- data["all_articles"] = all_articles
- data["showing_archived"] = PRG.show_archived
+ data["all_articles"] = all_articles
+
+ return data
+
+/datum/computer_file/program/newsbrowser/kill_program()
+ ..()
+ requires_ntnet = TRUE
+ loaded_article = null
+ download_progress = 0
+ downloading = FALSE
+ show_archived = FALSE
+
+/datum/computer_file/program/newsbrowser/tgui_act(action, list/params, datum/tgui/ui)
+ if(..())
+ return TRUE
+ switch(action)
+ if("PRG_openarticle")
+ . = TRUE
+ if(downloading || loaded_article)
+ return TRUE
+
+ for(var/datum/computer_file/data/news_article/N in ntnet_global.available_news)
+ if(N.uid == text2num(params["uid"]))
+ loaded_article = N.clone()
+ downloading = 1
+ break
+ if("PRG_reset")
+ . = TRUE
+ downloading = 0
+ download_progress = 0
+ requires_ntnet = 1
+ loaded_article = null
+ if("PRG_clearmessage")
+ . = TRUE
+ message = ""
+ if("PRG_savearticle")
+ . = TRUE
+ if(downloading || !loaded_article)
+ return
+
+ var/savename = sanitize(input(usr, "Enter file name or leave blank to cancel:", "Save article", loaded_article.filename))
+ if(!savename)
+ return TRUE
+ var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
+ if(!HDD)
+ return TRUE
+ var/datum/computer_file/data/news_article/N = loaded_article.clone()
+ N.filename = savename
+ HDD.store_file(N)
+ if("PRG_toggle_archived")
+ . = TRUE
+ show_archived = !show_archived
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "news_browser.tmpl", "NTNet/ExoNet News Browser", 575, 750, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
diff --git a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm
index a0b2194168..14e2343e66 100644
--- a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm
@@ -5,29 +5,26 @@
program_key_state = "generic_key"
program_menu_icon = "arrowthickstop-1-s"
extended_desc = "This program allows downloads of software from official NT repositories"
- unsendable = 1
- undeletable = 1
+ unsendable = TRUE
+ undeletable = TRUE
size = 4
- requires_ntnet = 1
+ requires_ntnet = TRUE
requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD
- available_on_ntnet = 0
- nanomodule_path = /datum/nano_module/program/computer_ntnetdownload/
+ available_on_ntnet = FALSE
ui_header = "downloader_finished.gif"
+ tgui_id = "NtosNetDownloader"
+
var/datum/computer_file/program/downloaded_file = null
var/hacked_download = 0
var/download_completion = 0 //GQ of downloaded data.
var/download_netspeed = 0
var/downloaderror = ""
+ var/obj/item/modular_computer/my_computer = null
var/list/downloads_queue[0]
/datum/computer_file/program/ntnetdownload/kill_program()
..()
- downloaded_file = null
- download_completion = 0
- download_netspeed = 0
- downloaderror = ""
- ui_header = "downloader_finished.gif"
-
+ abort_file_download()
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(var/filename)
if(downloaded_file)
@@ -108,93 +105,85 @@
download_netspeed = NTNETSPEED_ETHERNET
download_completion += download_netspeed
-/datum/computer_file/program/ntnetdownload/Topic(href, href_list)
+/datum/computer_file/program/ntnetdownload/tgui_act(action, params)
if(..())
- return 1
- if(href_list["PRG_downloadfile"])
- if(!downloaded_file)
- begin_file_download(href_list["PRG_downloadfile"])
- else if(check_file_download(href_list["PRG_downloadfile"]) && !downloads_queue.Find(href_list["PRG_downloadfile"]) && downloaded_file.filename != href_list["PRG_downloadfile"])
- downloads_queue += href_list["PRG_downloadfile"]
- return 1
- if(href_list["PRG_removequeued"])
- downloads_queue.Remove(href_list["PRG_removequeued"])
- return 1
- if(href_list["PRG_reseterror"])
- if(downloaderror)
- download_completion = 0
- download_netspeed = 0
- downloaded_file = null
- downloaderror = ""
- return 1
- return 0
-
-/datum/nano_module/program/computer_ntnetdownload
- name = "Network Downloader"
- var/obj/item/modular_computer/my_computer = null
-
-/datum/nano_module/program/computer_ntnetdownload/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- if(program)
- my_computer = program.computer
+ return TRUE
+ switch(action)
+ if("PRG_downloadfile")
+ if(!downloaded_file)
+ begin_file_download(params["filename"])
+ else if(check_file_download(params["filename"]) && !downloads_queue.Find(params["filename"]) && downloaded_file.filename != params["filename"])
+ downloads_queue += params["filename"]
+ return TRUE
+ if("PRG_removequeued")
+ downloads_queue.Remove(params["filename"])
+ return TRUE
+ if("PRG_reseterror")
+ if(downloaderror)
+ download_completion = 0
+ download_netspeed = 0
+ downloaded_file = null
+ downloaderror = ""
+ return TRUE
+ return FALSE
+/datum/computer_file/program/ntnetdownload/tgui_data(mob/user)
+ my_computer = computer
if(!istype(my_computer))
return
- var/list/data = list()
- var/datum/computer_file/program/ntnetdownload/prog = program
- // For now limited to execution by the downloader program
- if(!prog || !istype(prog))
- return
- if(program)
- data = program.get_header_data()
+ var/list/data = get_header_data()
- // This IF cuts on data transferred to client, so i guess it's worth it.
- if(prog.downloaderror) // Download errored. Wait until user resets the program.
- data["error"] = prog.downloaderror
- if(prog.downloaded_file) // Download running. Wait please..
- data["downloadname"] = prog.downloaded_file.filename
- data["downloaddesc"] = prog.downloaded_file.filedesc
- data["downloadsize"] = prog.downloaded_file.size
- data["downloadspeed"] = prog.download_netspeed
- data["downloadcompletion"] = round(prog.download_completion, 0.1)
+ data["downloading"] = !!downloaded_file
+ data["error"] = downloaderror || FALSE
+
+ if(downloaded_file) // Download running. Wait please..
+ data["downloadname"] = downloaded_file.filename
+ data["downloaddesc"] = downloaded_file.filedesc
+ data["downloadsize"] = downloaded_file.size
+ data["downloadspeed"] = download_netspeed
+ data["downloadcompletion"] = round(download_completion, 0.1)
data["disk_size"] = my_computer.hard_drive.max_capacity
data["disk_used"] = my_computer.hard_drive.used_capacity
var/list/all_entries[0]
for(var/datum/computer_file/program/P in ntnet_global.available_station_software)
// Only those programs our user can run will show in the list
- if(!P.can_run(user) && P.requires_access_to_download)
+ if(!P.can_run(user) && P.requires_access_to_download || my_computer.hard_drive.find_file_by_name(P.filename))
continue
all_entries.Add(list(list(
- "filename" = P.filename,
- "filedesc" = P.filedesc,
- "fileinfo" = P.extended_desc,
- "size" = P.size,
- "icon" = P.program_menu_icon
- )))
- data["hackedavailable"] = 0
- if(prog.computer_emagged) // If we are running on emagged computer we have access to some "bonus" software
- var/list/hacked_programs[0]
- for(var/datum/computer_file/program/P in ntnet_global.available_antag_software)
- data["hackedavailable"] = 1
- hacked_programs.Add(list(list(
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
+ "compatibility" = check_compatibility(P),
"size" = P.size,
"icon" = P.program_menu_icon
+ )))
+ data["hackedavailable"] = FALSE
+ if(computer_emagged) // If we are running on emagged computer we have access to some "bonus" software
+ var/list/hacked_programs[0]
+ for(var/datum/computer_file/program/P in ntnet_global.available_antag_software)
+ if(my_computer.hard_drive.find_file_by_name(P.filename))
+ continue
+ data["hackedavailable"] = TRUE
+ hacked_programs.Add(list(list(
+ "filename" = P.filename,
+ "filedesc" = P.filedesc,
+ "fileinfo" = P.extended_desc,
+ "compatibility" = check_compatibility(P),
+ "size" = P.size,
+ "icon" = P.program_menu_icon
)))
data["hacked_programs"] = hacked_programs
data["downloadable_programs"] = all_entries
+ data["downloads_queue"] = downloads_queue
- if(prog.downloads_queue.len > 0)
- data["downloads_queue"] = prog.downloads_queue
+ return data
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "ntnet_downloader.tmpl", "NTNet Download Program", 575, 700, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+/datum/computer_file/program/ntnetdownload/proc/check_compatibility(datum/computer_file/program/P)
+ var/hardflag = computer.hardware_flag
+
+ if(P && P.is_supported_by_hardware(hardflag,0))
+ return "Compatible"
+ return "Incompatible!"
diff --git a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm
index 6c67c02c0d..f2466213f3 100644
--- a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm
@@ -11,222 +11,220 @@
network_destination = "NTNRC server"
ui_header = "ntnrc_idle.gif"
available_on_ntnet = 1
- nanomodule_path = /datum/nano_module/program/computer_chatclient/
- var/last_message = null // Used to generate the toolbar icon
+ tgui_id = "NtosNetChat"
+ var/last_message // Used to generate the toolbar icon
var/username
- var/datum/ntnet_conversation/channel = null
- var/operator_mode = 0 // Channel operator mode
- var/netadmin_mode = 0 // Administrator mode (invisible to other users + bypasses passwords)
+ var/active_channel
+ var/list/channel_history = list()
+ var/operator_mode = FALSE // Channel operator mode
+ var/netadmin_mode = FALSE // Administrator mode (invisible to other users + bypasses passwords)
/datum/computer_file/program/chatclient/New()
username = "DefaultUser[rand(100, 999)]"
-/datum/computer_file/program/chatclient/Topic(href, href_list)
+/datum/computer_file/program/chatclient/tgui_act(action, params)
if(..())
- return 1
+ return
- if(href_list["PRG_speak"])
- . = 1
- if(!channel)
- return 1
- var/mob/living/user = usr
- var/message = sanitize(input(user, "Enter message or leave blank to cancel: "), 512)
- if(!message || !channel)
- return
- channel.add_message(message, username)
+ var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel)
+ var/authed = FALSE
+ if(channel && ((channel.operator == src) || netadmin_mode))
+ authed = TRUE
+ switch(action)
+ if("PRG_speak")
+ if(!channel || isnull(active_channel))
+ return
+ var/message = reject_bad_text(params["message"])
+ if(!message)
+ return
+ if(channel.password && !(src in channel.clients))
+ if(channel.password == message)
+ channel.add_client(src)
+ return TRUE
- if(href_list["PRG_joinchannel"])
- . = 1
- var/datum/ntnet_conversation/C
- for(var/datum/ntnet_conversation/chan in ntnet_global.chat_channels)
- if(chan.id == text2num(href_list["PRG_joinchannel"]))
- C = chan
- break
+ channel.add_message(message, username)
+ // var/mob/living/user = usr
+ // user.log_talk(message, LOG_CHAT, tag="as [username] to channel [channel.title]")
+ return TRUE
+ if("PRG_joinchannel")
+ var/new_target = text2num(params["id"])
+ if(isnull(new_target) || new_target == active_channel)
+ return
- if(!C)
- return 1
+ if(netadmin_mode)
+ active_channel = new_target // Bypasses normal leave/join and passwords. Technically makes the user invisible to others.
+ return TRUE
- if(netadmin_mode)
- channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others.
- return 1
-
- if(C.password)
+ active_channel = new_target
+ channel = ntnet_global.get_chat_channel_by_id(new_target)
+ if(!(src in channel.clients) && !channel.password)
+ channel.add_client(src)
+ return TRUE
+ if("PRG_leavechannel")
+ if(channel)
+ channel.remove_client(src)
+ active_channel = null
+ return TRUE
+ if("PRG_newchannel")
+ var/channel_title = reject_bad_text(params["new_channel_name"])
+ if(!channel_title)
+ return
+ var/datum/ntnet_conversation/C = new /datum/ntnet_conversation()
+ C.add_client(src)
+ C.operator = src
+ C.title = channel_title
+ active_channel = C.id
+ return TRUE
+ if("PRG_toggleadmin")
+ if(netadmin_mode)
+ netadmin_mode = FALSE
+ if(channel)
+ channel.remove_client(src) // We shouldn't be in channel's user list, but just in case...
+ return TRUE
var/mob/living/user = usr
- var/password = sanitize(input(user,"Access Denied. Enter password:"))
- if(C && (password == C.password))
- C.add_client(src)
- channel = C
- return 1
- C.add_client(src)
- channel = C
- if(href_list["PRG_leavechannel"])
- . = 1
- if(channel)
- channel.remove_client(src)
- channel = null
- if(href_list["PRG_newchannel"])
- . = 1
- var/mob/living/user = usr
- var/channel_title = sanitizeSafe(input(user,"Enter channel name or leave blank to cancel:"), 64)
- if(!channel_title)
- return
- var/datum/ntnet_conversation/C = new/datum/ntnet_conversation()
- C.add_client(src)
- C.operator = src
- channel = C
- C.title = channel_title
- if(href_list["PRG_toggleadmin"])
- . = 1
- if(netadmin_mode)
- netadmin_mode = 0
- if(channel)
- channel.remove_client(src) // We shouldn't be in channel's user list, but just in case...
- channel = null
- return 1
- var/mob/living/user = usr
- if(can_run(usr, 1, access_network))
- if(channel)
- var/response = alert(user, "Really engage admin-mode? You will be disconnected from your current channel!", "NTNRC Admin mode", "Yes", "No")
- if(response == "Yes")
- if(channel)
- channel.remove_client(src)
- channel = null
- else
- return
- netadmin_mode = 1
- if(href_list["PRG_changename"])
- . = 1
- var/mob/living/user = usr
- var/newname = sanitize(input(user,"Enter new nickname or leave blank to cancel:"), 20)
- if(!newname)
- return 1
- if(channel)
- channel.add_status_message("[username] is now known as [newname].")
- username = newname
+ if(can_run(user, TRUE, access_network))
+ for(var/C in ntnet_global.chat_channels)
+ var/datum/ntnet_conversation/chan = C
+ chan.remove_client(src)
+ netadmin_mode = TRUE
+ return TRUE
+ if("PRG_changename")
+ var/newname = sanitize(params["new_name"])
+ if(!newname)
+ return
+ for(var/C in ntnet_global.chat_channels)
+ var/datum/ntnet_conversation/chan = C
+ if(src in chan.clients)
+ chan.add_status_message("[username] is now known as [newname].")
+ username = newname
+ return TRUE
+ if("PRG_savelog")
+ if(!channel)
+ return
+ var/logname = stripped_input(params["log_name"])
+ if(!logname)
+ return
+ var/datum/computer_file/data/logfile = new /datum/computer_file/data/logfile()
+ // Now we will generate HTML-compliant file that can actually be viewed/printed.
+ logfile.filename = logname
+ logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]"
+ for(var/logstring in channel.messages)
+ logfile.stored_data = "[logfile.stored_data][logstring]\[BR\]"
+ logfile.stored_data = "[logfile.stored_data]\[b\]Logfile dump completed.\[/b\]"
+ logfile.calculate_size()
+ if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile))
+ if(!computer)
+ // This program shouldn't even be runnable without computer.
+ CRASH("Var computer is null!")
+ if(!computer.hard_drive)
+ computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.")
+ else // In 99.9% cases this will mean our HDD is full
+ computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.")
+ return TRUE
+ if("PRG_renamechannel")
+ if(!authed)
+ return
+ var/newname = reject_bad_text(params["new_name"])
+ if(!newname || !channel)
+ return
+ channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.")
+ channel.title = newname
+ return TRUE
+ if("PRG_deletechannel")
+ if(authed)
+ qdel(channel)
+ active_channel = null
+ return TRUE
+ if("PRG_setpassword")
+ if(!authed)
+ return
- if(href_list["PRG_savelog"])
- . = 1
- if(!channel)
- return
- var/mob/living/user = usr
- var/logname = input(user,"Enter desired logfile name (.log) or leave blank to cancel:")
- if(!logname || !channel)
- return 1
- var/datum/computer_file/data/logfile = new/datum/computer_file/data/logfile()
- // Now we will generate HTML-compliant file that can actually be viewed/printed.
- logfile.filename = logname
- logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]"
- for(var/logstring in channel.messages)
- logfile.stored_data += "[logstring]\[BR\]"
- logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]"
- logfile.calculate_size()
- if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile))
- if(!computer)
- // This program shouldn't even be runnable without computer.
- CRASH("Var computer is null!")
- return 1
- if(!computer.hard_drive)
- computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.")
- else // In 99.9% cases this will mean our HDD is full
- computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.")
- if(href_list["PRG_renamechannel"])
- . = 1
- if(!operator_mode || !channel)
- return 1
- var/mob/living/user = usr
- var/newname = sanitize(input(user, "Enter new channel name or leave blank to cancel:"), 64)
- if(!newname || !channel)
- return
- channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.")
- channel.title = newname
- if(href_list["PRG_deletechannel"])
- . = 1
- if(channel && ((channel.operator == src) || netadmin_mode))
- qdel(channel)
- channel = null
- if(href_list["PRG_setpassword"])
- . = 1
- if(!channel || ((channel.operator != src) && !netadmin_mode))
- return 1
+ var/new_password = sanitize(params["new_password"])
+ if(!authed)
+ return
- var/mob/living/user = usr
- var/newpassword = sanitize(input(user, "Enter new password for this channel. Leave blank to cancel, enter 'nopassword' to remove password completely:"))
- if(!channel || !newpassword || ((channel.operator != src) && !netadmin_mode))
- return 1
-
- if(newpassword == "nopassword")
- channel.password = ""
- else
- channel.password = newpassword
+ channel.password = new_password
+ return TRUE
/datum/computer_file/program/chatclient/process_tick()
..()
+ var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel)
if(program_state != PROGRAM_STATE_KILLED)
ui_header = "ntnrc_idle.gif"
if(channel)
// Remember the last message. If there is no message in the channel remember null.
- last_message = channel.messages.len ? channel.messages[channel.messages.len - 1] : null
+ last_message = length(channel.messages) ? channel.messages[channel.messages.len - 1] : null
else
last_message = null
return 1
- if(channel && channel.messages && channel.messages.len)
+ if(channel?.messages?.len)
ui_header = last_message == channel.messages[channel.messages.len - 1] ? "ntnrc_idle.gif" : "ntnrc_new.gif"
else
ui_header = "ntnrc_idle.gif"
-/datum/computer_file/program/chatclient/kill_program(var/forced = 0)
- if(channel)
+/datum/computer_file/program/chatclient/kill_program(forced = FALSE)
+ for(var/C in ntnet_global.chat_channels)
+ var/datum/ntnet_conversation/channel = C
channel.remove_client(src)
- channel = null
- ..(forced)
-
-/datum/nano_module/program/computer_chatclient
- name = "NTNet Relay Chat Client"
-
-/datum/nano_module/program/computer_chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- if(!ntnet_global || !ntnet_global.chat_channels)
- return
+ ..()
+/datum/computer_file/program/chatclient/tgui_static_data(mob/user)
var/list/data = list()
- if(program)
- data = program.get_header_data()
+ data["can_admin"] = can_run(user, FALSE, access_network)
+ return data
+
+/datum/computer_file/program/chatclient/tgui_data(mob/user)
+ if(!ntnet_global || !ntnet_global.chat_channels)
+ return list()
- var/datum/computer_file/program/chatclient/C = program
- if(!istype(C))
- return
+ var/list/data = get_header_data()
- data["adminmode"] = C.netadmin_mode
- if(C.channel)
- data["title"] = C.channel.title
- var/list/messages[0]
- for(var/M in C.channel.messages)
- messages.Add(list(list(
- "msg" = M
+ var/list/all_channels = list()
+ for(var/C in ntnet_global.chat_channels)
+ var/datum/ntnet_conversation/conv = C
+ if(conv && conv.title)
+ all_channels.Add(list(list(
+ "chan" = conv.title,
+ "id" = conv.id
)))
- data["messages"] = messages
- var/list/clients[0]
- for(var/datum/computer_file/program/chatclient/cl in C.channel.clients)
+ data["all_channels"] = all_channels
+
+ data["active_channel"] = active_channel
+ data["username"] = username
+ data["adminmode"] = netadmin_mode
+ var/datum/ntnet_conversation/channel = ntnet_global.get_chat_channel_by_id(active_channel)
+ if(channel)
+ data["title"] = channel.title
+ var/authed = FALSE
+ if(!channel.password)
+ authed = TRUE
+ if(netadmin_mode)
+ authed = TRUE
+ var/list/clients = list()
+ for(var/C in channel.clients)
+ if(C == src)
+ authed = TRUE
+ var/datum/computer_file/program/chatclient/cl = C
clients.Add(list(list(
"name" = cl.username
)))
- data["clients"] = clients
- C.operator_mode = (C.channel.operator == C) ? 1 : 0
- data["is_operator"] = C.operator_mode || C.netadmin_mode
-
- else // Channel selection screen
- var/list/all_channels[0]
- for(var/datum/ntnet_conversation/conv in ntnet_global.chat_channels)
- if(conv && conv.title)
- all_channels.Add(list(list(
- "chan" = conv.title,
- "id" = conv.id
+ data["authed"] = authed
+ //no fishing for ui data allowed
+ if(authed)
+ data["clients"] = clients
+ var/list/messages = list()
+ for(var/M in channel.messages)
+ messages.Add(list(list(
+ "msg" = M
)))
- data["all_channels"] = all_channels
+ data["messages"] = messages
+ data["is_operator"] = (channel.operator == src) || netadmin_mode
+ else
+ data["clients"] = list()
+ data["messages"] = list()
+ else
+ data["clients"] = list()
+ data["authed"] = FALSE
+ data["messages"] = list()
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "ntnet_chat.tmpl", "NTNet Relay Chat Client", 575, 700, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ return data
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm
index 0efed986ae..ea88d3597e 100644
--- a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm
@@ -12,7 +12,7 @@ var/global/nttransfer_uid = 0
requires_ntnet_feature = NTNET_PEERTOPEER
network_destination = "other device via P2P tunnel"
available_on_ntnet = 1
- nanomodule_path = /datum/nano_module/program/computer_nttransfer/
+ tgui_id = "NtosNetTransfer"
var/error = "" // Error screen
var/server_password = "" // Optional password to download the file.
@@ -75,111 +75,101 @@ var/global/nttransfer_uid = 0
remote = null
download_completion = 0
+/datum/computer_file/program/nttransfer/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = get_header_data()
-/datum/nano_module/program/computer_nttransfer
- name = "NTNet P2P Transfer Client"
+ data["error"] = error
-/datum/nano_module/program/computer_nttransfer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state)
- if(!program)
- return
- var/datum/computer_file/program/nttransfer/PRG = program
- if(!istype(PRG))
- return
-
- var/list/data = program.get_header_data()
-
- if(PRG.error)
- data["error"] = PRG.error
- else if(PRG.downloaded_file)
- data["downloading"] = 1
- data["download_size"] = PRG.downloaded_file.size
- data["download_progress"] = PRG.download_completion
- data["download_netspeed"] = PRG.actual_netspeed
- data["download_name"] = "[PRG.downloaded_file.filename].[PRG.downloaded_file.filetype]"
- else if (PRG.provided_file)
- data["uploading"] = 1
- data["upload_uid"] = PRG.unique_token
- data["upload_clients"] = PRG.connected_clients.len
- data["upload_haspassword"] = PRG.server_password ? 1 : 0
- data["upload_filename"] = "[PRG.provided_file.filename].[PRG.provided_file.filetype]"
- else if (PRG.upload_menu)
- var/list/all_files[0]
- for(var/datum/computer_file/F in PRG.computer.hard_drive.stored_files)
+ data["downloading"] = !!downloaded_file
+ if(downloaded_file)
+ data["download_size"] = downloaded_file.size
+ data["download_progress"] = download_completion
+ data["download_netspeed"] = actual_netspeed
+ data["download_name"] = "[downloaded_file.filename].[downloaded_file.filetype]"
+
+ data["uploading"] = !!provided_file
+ if(provided_file)
+ data["upload_uid"] = unique_token
+ data["upload_clients"] = connected_clients.len
+ data["upload_haspassword"] = server_password ? 1 : 0
+ data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]"
+
+ data["upload_filelist"] = list()
+ if(upload_menu)
+ var/list/all_files = list()
+ for(var/datum/computer_file/F in computer.hard_drive.stored_files)
all_files.Add(list(list(
"uid" = F.uid,
"filename" = "[F.filename].[F.filetype]",
"size" = F.size
)))
data["upload_filelist"] = all_files
- else
- var/list/all_servers[0]
+
+ data["servers"] = list()
+ if(!(downloaded_file || provided_file || upload_menu))
+ var/list/all_servers = list()
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
if(!P.provided_file)
continue
all_servers.Add(list(list(
- "uid" = P.unique_token,
- "filename" = "[P.provided_file.filename].[P.provided_file.filetype]",
- "size" = P.provided_file.size,
- "haspassword" = P.server_password ? 1 : 0
+ "uid" = P.unique_token,
+ "filename" = "[P.provided_file.filename].[P.provided_file.filetype]",
+ "size" = P.provided_file.size,
+ "haspassword" = P.server_password ? 1 : 0
)))
data["servers"] = all_servers
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "ntnet_transfer.tmpl", "NTNet P2P Transfer Client", 575, 700, state = state)
- ui.auto_update_layout = 1
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
+ return data
-/datum/computer_file/program/nttransfer/Topic(href, href_list)
+/datum/computer_file/program/nttransfer/tgui_act(action, list/params, datum/tgui/ui)
if(..())
- return 1
- if(href_list["PRG_downloadfile"])
- for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
- if("[P.unique_token]" == href_list["PRG_downloadfile"])
- remote = P
- break
- if(!remote || !remote.provided_file)
- return
- if(remote.server_password)
- var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required"))
- if(pass != remote.server_password)
- error = "Incorrect Password"
+ return TRUE
+ switch(action)
+ if("PRG_downloadfile")
+ for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
+ if(P.unique_token == text2num(params["uid"]))
+ remote = P
+ break
+ if(!remote || !remote.provided_file)
return
- downloaded_file = remote.provided_file.clone()
- remote.connected_clients.Add(src)
- return 1
- if(href_list["PRG_reset"])
- error = ""
- upload_menu = 0
- finalize_download()
- if(src in ntnet_global.fileservers)
- ntnet_global.fileservers.Remove(src)
- for(var/datum/computer_file/program/nttransfer/T in connected_clients)
- T.crash_download("Remote server has forcibly closed the connection")
- provided_file = null
- return 1
- if(href_list["PRG_setpassword"])
- var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none"))
- if(!pass)
- return
- if(pass == "none")
- server_password = ""
- return
- server_password = pass
- return 1
- if(href_list["PRG_uploadfile"])
- for(var/datum/computer_file/F in computer.hard_drive.stored_files)
- if("[F.uid]" == href_list["PRG_uploadfile"])
- if(F.unsendable)
- error = "I/O Error: File locked."
+ if(remote.server_password)
+ var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required"))
+ if(pass != remote.server_password)
+ error = "Incorrect Password"
return
- provided_file = F
- ntnet_global.fileservers.Add(src)
+ downloaded_file = remote.provided_file.clone()
+ remote.connected_clients.Add(src)
+ return TRUE
+ if("PRG_reset")
+ error = ""
+ upload_menu = 0
+ finalize_download()
+ if(src in ntnet_global.fileservers)
+ ntnet_global.fileservers.Remove(src)
+ for(var/datum/computer_file/program/nttransfer/T in connected_clients)
+ T.crash_download("Remote server has forcibly closed the connection")
+ provided_file = null
+ return TRUE
+ if("PRG_setpassword")
+ var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none"))
+ if(!pass)
return
- error = "I/O Error: Unable to locate file on hard drive."
- return 1
- if(href_list["PRG_uploadmenu"])
- upload_menu = 1
- return 0
+ if(pass == "none")
+ server_password = ""
+ return
+ server_password = pass
+ return TRUE
+ if("PRG_uploadfile")
+ for(var/datum/computer_file/F in computer.hard_drive.stored_files)
+ if(F.uid == text2num(params["uid"]))
+ if(F.unsendable)
+ error = "I/O Error: File locked."
+ return
+ provided_file = F
+ ntnet_global.fileservers |= src
+ return
+ error = "I/O Error: Unable to locate file on hard drive."
+ return TRUE
+ if("PRG_uploadmenu")
+ upload_menu = 1
+ return TRUE
diff --git a/code/modules/modular_computers/file_system/programs/generic/uav.dm b/code/modules/modular_computers/file_system/programs/generic/uav.dm
index 0e98d0e0ea..24d677b679 100644
--- a/code/modules/modular_computers/file_system/programs/generic/uav.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/uav.dm
@@ -4,7 +4,7 @@
/datum/computer_file/program/uav
filename = "rigger"
filedesc = "UAV Control"
- nanomodule_path = /datum/nano_module/uav
+ tguimodule_path = /datum/tgui_module/uav
program_icon_state = "comm_monitor"
program_key_state = "generic_key"
program_menu_icon = "link"
@@ -12,255 +12,3 @@
size = 12
available_on_ntnet = 1
//requires_ntnet = 1
-
-/datum/nano_module/uav
- name = "UAV Control program"
- var/obj/item/device/uav/current_uav = null //The UAV we're watching
- var/signal_strength = 0 //Our last signal strength report (cached for a few seconds)
- var/signal_test_counter = 0 //How long until next signal strength check
- var/list/viewers //Who's viewing a UAV through us
- var/adhoc_range = 30 //How far we can operate on a UAV without NTnet
-
-/datum/nano_module/uav/Destroy()
- if(LAZYLEN(viewers))
- for(var/weakref/W in viewers)
- var/M = W.resolve()
- if(M)
- unlook(M)
- . = ..()
-
-/datum/nano_module/uav/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, state = default_state)
- var/list/data = host.initial_data()
-
- if(current_uav)
- if(QDELETED(current_uav))
- set_current(null)
- else if(signal_test_counter-- <= 0)
- signal_strength = get_signal_to(current_uav)
- if(!signal_strength)
- set_current(null)
- else // Don't reset counter until we find a UAV that's actually in range we can stay connected to
- signal_test_counter = 20
-
- data["current_uav"] = null
- if(current_uav)
- data["current_uav"] = list("status" = current_uav.get_status_string(), "power" = current_uav.state == 1 ? 1 : null)
- data["signal_strength"] = signal_strength ? signal_strength >= 2 ? "High" : "Low" : "None"
- data["in_use"] = LAZYLEN(viewers)
-
- var/list/paired_map = list()
- var/obj/item/modular_computer/mc_host = nano_host()
- if(istype(mc_host))
- for(var/puav in mc_host.paired_uavs)
- var/weakref/wr = puav
- var/obj/item/device/uav/U = wr.resolve()
- paired_map[++paired_map.len] = list("name" = "[U ? U.nickname : "!!Missing!!"]", "uavref" = "\ref[U]")
-
- data["paired_uavs"] = paired_map
-
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "mod_uav.tmpl", "UAV Control", 600, 500, state = state)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(1)
-
-/datum/nano_module/uav/Topic(var/href, var/href_list = list(), var/datum/topic_state/state)
- if((. = ..()))
- return
- state = state || DefaultTopicState() || global.default_state
- if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE)
- CouldUseTopic(usr)
- return OnTopic(usr, href_list, state)
- CouldNotUseTopic(usr)
- return TRUE
-
-/datum/nano_module/uav/proc/OnTopic(var/mob/user, var/list/href_list)
- if(href_list["switch_uav"])
- var/obj/item/device/uav/U = locate(href_list["switch_uav"]) //This is a \ref to the UAV itself
- if(!istype(U))
- to_chat(usr,"Something is blocking the connection to that UAV. In-person investigation is required.")
- return TOPIC_NOACTION
-
- if(!get_signal_to(U))
- to_chat(usr,"The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.")
- return TOPIC_NOACTION
-
- set_current(U)
- return TOPIC_REFRESH
-
- if(href_list["del_uav"])
- var/refstring = href_list["del_uav"] //This is a \ref to the UAV itself
- var/obj/item/modular_computer/mc_host = nano_host()
- //This is so we can really scrape up any weakrefs that can't resolve
- for(var/weakref/wr in mc_host.paired_uavs)
- if(wr.ref == refstring)
- if(current_uav?.weakref == wr)
- set_current(null)
- LAZYREMOVE(mc_host.paired_uavs, wr)
-
- else if(href_list["view_uav"])
- if(!current_uav)
- return TOPIC_NOACTION
-
- if(current_uav.check_eye(user) < 0)
- to_chat(usr,"The screen freezes for a moment, before returning to the UAV selection menu. It's not able to connect to that UAV.")
- else
- viewing_uav(user) ? unlook(user) : look(user)
- return TOPIC_NOACTION
-
- else if(href_list["power_uav"])
- if(!current_uav)
- return TOPIC_NOACTION
- else if(current_uav.toggle_power())
- //Clean up viewers faster
- if(LAZYLEN(viewers))
- for(var/weakref/W in viewers)
- var/M = W.resolve()
- if(M)
- unlook(M)
- return TOPIC_REFRESH
-
-/datum/nano_module/uav/proc/DefaultTopicState()
- return global.default_state
-
-/datum/nano_module/uav/proc/CouldNotUseTopic(mob/user)
- . = ..()
- unlook(user)
-
-/datum/nano_module/uav/proc/CouldUseTopic(mob/user)
- . = ..()
- if(viewing_uav(user))
- look(user)
-
-/datum/nano_module/uav/proc/set_current(var/obj/item/device/uav/U)
- if(current_uav == U)
- return
-
- signal_strength = 0
- current_uav = U
-
- if(LAZYLEN(viewers))
- for(var/weakref/W in viewers)
- var/M = W.resolve()
- if(M)
- if(current_uav)
- to_chat(M, "You're disconnected from the UAV's camera!")
- unlook(M)
- else
- look(M)
-
-////
-//// Finding signal strength between us and the UAV
-////
-/datum/nano_module/uav/proc/get_signal_to(var/atom/movable/AM)
- // Following roughly the ntnet signal levels
- // 0 is none
- // 1 is weak
- // 2 is strong
- var/obj/item/modular_computer/host = nano_host() //Better not add this to anything other than modular computers.
- if(!istype(host))
- return
- var/our_signal = host.get_ntnet_status() //1 low, 2 good, 3 wired, 0 none
- var/their_z = get_z(AM)
-
- //If we have no NTnet connection don't bother getting theirs
- if(!our_signal)
- if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range))
- return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs
- else
- return 0
-
- var/list/zlevels_in_range = using_map.get_map_levels(their_z, FALSE)
- var/list/zlevels_in_long_range = using_map.get_map_levels(their_z, TRUE, om_range = DEFAULT_OVERMAP_RANGE) - zlevels_in_range
- var/their_signal = 0
- for(var/relay in ntnet_global.relays)
- var/obj/machinery/ntnet_relay/R = relay
- if(!R.operable())
- continue
- if(R.z == their_z)
- their_signal = 2
- break
- if(R.z in zlevels_in_range)
- their_signal = 2
- break
- if(R.z in zlevels_in_long_range)
- their_signal = 1
- break
-
- if(!their_signal) //They have no NTnet at all
- if(get_z(host) == their_z && (get_dist(host, AM) < adhoc_range))
- return 1 //We can connect (with weak signal) in same z without ntnet, within 30 turfs
- else
- return 0
- else
- return max(our_signal, their_signal)
-
-////
-//// UAV viewer handling
-////
-/datum/nano_module/uav/proc/viewing_uav(mob/user)
- return (weakref(user) in viewers)
-
-/datum/nano_module/uav/proc/look(var/mob/user)
- if(issilicon(user)) //Too complicated for me to want to mess with at the moment
- to_chat(user, "Regulations prevent you from controlling several corporeal forms at the same time!")
- return
-
- if(!current_uav)
- return
-
- user.set_machine(nano_host())
- user.reset_view(current_uav)
- current_uav.add_master(user)
- LAZYDISTINCTADD(viewers, weakref(user))
-
-/datum/nano_module/uav/proc/unlook(var/mob/user)
- user.unset_machine()
- user.reset_view()
- if(current_uav)
- current_uav.remove_master(user)
- LAZYREMOVE(viewers, weakref(user))
-
-/datum/nano_module/uav/check_eye(var/mob/user)
- if(get_dist(user, nano_host()) > 1 || user.blinded || !current_uav)
- unlook(user)
- return -1
-
- var/viewflag = current_uav.check_eye(user)
- if (viewflag < 0) //camera doesn't work
- unlook(user)
- return -1
-
- return viewflag
-
-////
-//// Relaying movements to the UAV
-////
-/datum/nano_module/uav/relaymove(var/mob/user, direction)
- if(current_uav)
- return current_uav.relaymove(user, direction, signal_strength)
-
-////
-//// The effects when looking through a UAV
-////
-/datum/nano_module/uav/apply_visual(var/mob/M)
- if(!M.client)
- return
- if(weakref(M) in viewers)
- M.overlay_fullscreen("fishbed",/obj/screen/fullscreen/fishbed)
- M.overlay_fullscreen("scanlines",/obj/screen/fullscreen/scanline)
-
- if(signal_strength <= 1)
- M.overlay_fullscreen("whitenoise",/obj/screen/fullscreen/noise)
- else
- M.clear_fullscreen("whitenoise", 0)
- else
- remove_visual(M)
-
-/datum/nano_module/uav/remove_visual(mob/M)
- if(!M.client)
- return
- M.clear_fullscreen("fishbed",0)
- M.clear_fullscreen("scanlines",0)
- M.clear_fullscreen("whitenoise",0)
diff --git a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm
index 1a4d7a1871..61f3b43da8 100644
--- a/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm
+++ b/code/modules/modular_computers/file_system/programs/generic/wordprocessor.dm
@@ -5,9 +5,10 @@
program_icon_state = "word"
program_key_state = "atmos_key"
size = 4
- requires_ntnet = 0
- available_on_ntnet = 1
- nanomodule_path = /datum/nano_module/program/computer_wordprocessor/
+ requires_ntnet = FALSE
+ available_on_ntnet = TRUE
+ tgui_id = "NtosWordProcessor"
+
var/browsing
var/open_file
var/loaded_data
@@ -28,7 +29,7 @@
if(F)
open_file = F.filename
loaded_data = F.stored_data
- return 1
+ return TRUE
/datum/computer_file/program/wordprocessor/proc/save_file(var/filename)
var/datum/computer_file/data/F = get_file(filename)
@@ -46,7 +47,7 @@
HDD.store_file(backup)
return 0
is_edited = 0
- return 1
+ return TRUE
/datum/computer_file/program/wordprocessor/proc/create_file(var/newname, var/data = "")
if(!newname)
@@ -64,142 +65,144 @@
if(HDD.store_file(F))
return F
-/datum/computer_file/program/wordprocessor/Topic(href, href_list)
+/datum/computer_file/program/wordprocessor/tgui_act(action, list/params, datum/tgui/ui)
if(..())
- return 1
+ return TRUE
- if(href_list["PRG_txtrpeview"])
- show_browser(usr,"[open_file][pencode2html(loaded_data)]", "window=[open_file]")
- return 1
+ switch(action)
+ if("PRG_txtrpeview")
+ show_browser(usr,"[open_file][pencode2html(loaded_data)]