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 7fb49ca3dd..be3e0bb337 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
Yawn-Wider is a fork of the VOREStation code branch which 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/algae_generator_vr.dm b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
index fb686820ee..f95b613466 100644
--- a/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/algae_generator_vr.dm
@@ -232,7 +232,7 @@
// 0 amount = 0 means ejecting a full stack; -1 means eject everything
/obj/machinery/atmospherics/binary/algae_farm/proc/eject_materials(var/material_name, var/amount)
var/recursive = amount == -1 ? 1 : 0
- var/material/matdata = get_material_by_name(material_name)
+ var/datum/material/matdata = get_material_by_name(material_name)
var/stack_type = matdata.stack_type
var/obj/item/stack/material/S = new stack_type(loc)
if(amount <= 0)
@@ -266,7 +266,7 @@
to_chat(user, "\The [src] cannot hold more [S.name].")
return 1
-/material/algae
+/datum/material/algae
name = MAT_ALGAE
stack_type = /obj/item/stack/material/algae
icon_colour = "#557722"
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/misc_vr.dm b/code/__defines/misc_vr.dm
index 57c651c195..46d8a347e8 100644
--- a/code/__defines/misc_vr.dm
+++ b/code/__defines/misc_vr.dm
@@ -63,4 +63,5 @@
#define MAT_TITANIUMGLASS "ti-glass"
#define MAT_PLASTITANIUM "plastitanium"
+#define MAT_PLASTITANIUMHULL "plastitanium hull"
#define MAT_PLASTITANIUMGLASS "plastitanium glass"
\ No newline at end of file
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/_global_vars/religion.dm b/code/_global_vars/religion.dm
new file mode 100644
index 0000000000..7dab008b19
--- /dev/null
+++ b/code/_global_vars/religion.dm
@@ -0,0 +1,8 @@
+// All religion stuff
+GLOBAL_VAR(religion)
+GLOBAL_VAR(deity)
+
+//bible
+GLOBAL_VAR(bible_name)
+GLOBAL_VAR(bible_icon_state)
+GLOBAL_VAR(bible_item_state)
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/alert_vr.dm b/code/_onclick/hud/alert_vr.dm
new file mode 100644
index 0000000000..19310ad315
--- /dev/null
+++ b/code/_onclick/hud/alert_vr.dm
@@ -0,0 +1,25 @@
+/obj/screen/alert/fat
+ name = "Full"
+ desc = "You overate! If you don't exercise soon, you might find yourself gaining weight."
+
+/obj/screen/alert/fat/vampire
+ desc = "You overdrank! If you don't exercise soon, you might find yourself gaining weight."
+
+/obj/screen/alert/fat/synth
+ name = "Overcharged"
+
+/obj/screen/alert/hungry/vampire
+ desc = "You could use a bloodpack or two."
+
+/obj/screen/alert/hungry/synth
+ name = "Undercharged"
+
+/obj/screen/alert/starving
+ desc = "You're extremely hungry. The hunger pains make moving around a chore."
+
+/obj/screen/alert/starving/vampire
+ desc = "You are starving! Without some blood, moving around is a pain."
+
+/obj/screen/alert/starving/synth
+ name = "Low Power"
+ desc = "Your battery is very low! Low power mode makes all movements slower."
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/controllers/subsystems/supply.dm b/code/controllers/subsystems/supply.dm
index ad14c1e6cd..21edbde50e 100644
--- a/code/controllers/subsystems/supply.dm
+++ b/code/controllers/subsystems/supply.dm
@@ -105,7 +105,7 @@ SUBSYSTEM_DEF(supply)
// Sell phoron and platinum
if(istype(A, /obj/item/stack))
var/obj/item/stack/P = A
- var/material/mat = P.get_material()
+ var/datum/material/mat = P.get_material()
if(mat?.supply_conversion_value)
EC.contents[EC.contents.len]["value"] = P.get_amount() * mat.supply_conversion_value
EC.contents[EC.contents.len]["quantity"] = P.get_amount()
diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm
index 9c17e25149..f61ccd7ed2 100644
--- a/code/controllers/subsystems/ticker.dm
+++ b/code/controllers/subsystems/ticker.dm
@@ -32,12 +32,6 @@ SUBSYSTEM_DEF(ticker)
var/list/datum/mind/minds = list() // The people in the game. Used for objective tracking.
- // TODO - I am sure there is a better place these can go.
- var/Bible_icon_state // icon_state the chaplain has chosen for his bible
- var/Bible_item_state // item_state the chaplain has chosen for his bible
- var/Bible_name // name of the bible
- var/Bible_deity_name
-
var/random_players = FALSE // If set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders
// TODO - Should this go here or in the job subsystem?
@@ -567,8 +561,4 @@ var/global/datum/controller/subsystem/ticker/ticker
minds = SSticker.minds
- Bible_icon_state = SSticker.Bible_icon_state
- Bible_item_state = SSticker.Bible_item_state
- Bible_name = SSticker.Bible_name
- Bible_deity_name = SSticker.Bible_deity_name
random_players = SSticker.random_players
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/supplypacks/engineering_vr.dm b/code/datums/supplypacks/engineering_vr.dm
index 61c0f0e180..ae02babaca 100644
--- a/code/datums/supplypacks/engineering_vr.dm
+++ b/code/datums/supplypacks/engineering_vr.dm
@@ -39,3 +39,11 @@
containertype = /obj/structure/closet/crate/secure/engineering
containername = "Tesla Generator crate"
access = access_ce
+
+/datum/supply_pack/eng/inducer
+ contains = list(/obj/item/weapon/inducer = 3)
+ name = "inducer"
+ cost = 90 //Relatively expensive
+ containertype = /obj/structure/closet/crate/xion
+ containername = "Inducers crate"
+ access = access_engine
diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm
index 1307b8f985..69f198bbd4 100644
--- a/code/datums/supplypacks/medical.dm
+++ b/code/datums/supplypacks/medical.dm
@@ -32,6 +32,13 @@
containertype = /obj/structure/closet/crate/nanomed
containername = "BloodPack crate"
+/datum/supply_pack/med/synthplas
+ name = "BloodPack (Synthplas) crate"
+ contains = list(/obj/item/weapon/reagent_containers/blood/synthplas = 6)
+ cost = 80
+ containertype = /obj/structure/closet/crate/nanomed
+ containername = "SynthPlas crate"
+
/datum/supply_pack/med/bodybag
name = "Body bag crate"
contains = list(/obj/item/weapon/storage/box/bodybags = 3)
diff --git a/code/datums/supplypacks/recreation_vr.dm b/code/datums/supplypacks/recreation_vr.dm
index 2e61f93473..5c2266523f 100644
--- a/code/datums/supplypacks/recreation_vr.dm
+++ b/code/datums/supplypacks/recreation_vr.dm
@@ -64,3 +64,25 @@
cost = 25
containertype = /obj/structure/closet/crate
containername = "collar crate"
+
+/datum/supply_pack/recreation/shiny
+ name = "Shiny Clothing"
+ contains = list(
+ /obj/item/clothing/mask/muzzle/ballgag = 1,
+ /obj/item/clothing/mask/muzzle/ballgag/ringgag = 1,
+ /obj/item/clothing/head/shiny_hood = 1,
+ /obj/item/clothing/head/shiny_hood/poly = 1,
+ /obj/item/clothing/head/shiny_hood/closed = 1,
+ /obj/item/clothing/head/shiny_hood/closed/poly = 1,
+ /obj/item/clothing/under/shiny/catsuit = 1,
+ /obj/item/clothing/under/shiny/catsuit/poly = 1,
+ /obj/item/clothing/under/shiny/leotard = 1,
+ /obj/item/clothing/under/shiny/leotard/poly = 1,
+ /obj/item/clothing/accessory/shiny/gloves = 1,
+ /obj/item/clothing/accessory/shiny/gloves/poly = 1,
+ /obj/item/clothing/accessory/shiny/socks = 1,
+ /obj/item/clothing/accessory/shiny/socks/poly = 1
+ )
+ containertype = /obj/structure/closet/crate
+ containername = "Shiny clothes crate"
+ cost = 30
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/datums/vending/stored_item.dm b/code/datums/vending/stored_item.dm
index 7c27776aa9..23d06c909a 100644
--- a/code/datums/vending/stored_item.dm
+++ b/code/datums/vending/stored_item.dm
@@ -2,11 +2,11 @@
* Datum that holds the instances and information about the items stored. Currently used in SmartFridges and Vending Machines.
*/
/datum/stored_item
- var/item_name = "name" //Name of the item(s) displayed
- var/item_path = null
- var/amount = 0
- var/list/instances //What items are actually stored
- var/stored //The thing holding it is
+ var/item_name = "name" //Name of the item(s) displayed
+ var/item_path = null
+ var/amount = 0
+ var/list/instances //What items are actually stored
+ var/stored //The thing holding it is
/datum/stored_item/New(var/stored, var/path, var/name = null, var/amount = 0)
src.item_path = path
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index 7efbb84c20..0cb7cbd594 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'
@@ -304,6 +310,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"
@@ -332,7 +340,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/antagonist/outsider/ert_vr.dm b/code/game/antagonist/outsider/ert_vr.dm
new file mode 100644
index 0000000000..e808272614
--- /dev/null
+++ b/code/game/antagonist/outsider/ert_vr.dm
@@ -0,0 +1,6 @@
+//boosted ERT spawn/cap numbers to match the Von Braun's spawns, just to be safe. not much point going to all the effort of giving you twelve slots if only seven can ever be used without admin fuckery. -Killian
+/datum/antagonist/ert
+ hard_cap = 12
+ hard_cap_round = 12
+ initial_spawn_req = 4
+ initial_spawn_target = 12
\ No newline at end of file
diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm
index ddd49703c6..3ed52d317c 100644
--- a/code/game/dna/dna2.dm
+++ b/code/game/dna/dna2.dm
@@ -280,7 +280,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
@@ -296,7 +296,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)
@@ -306,7 +305,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.
@@ -392,7 +391,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 9bb25ec6b4..c946965072 100644
--- a/code/game/jobs/access.dm
+++ b/code/game/jobs/access.dm
@@ -182,7 +182,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/civilian_chaplain.dm b/code/game/jobs/job/civilian_chaplain.dm
index 93989d2c44..5fba7b155d 100644
--- a/code/game/jobs/job/civilian_chaplain.dm
+++ b/code/game/jobs/job/civilian_chaplain.dm
@@ -32,136 +32,69 @@
if(!B)
return
- spawn(0)
- var/religion_name = "Unitarianism"
- var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Unitarianism", "Name change", religion_name), MAX_NAME_LEN)
+ if(GLOB.religion)
+ B.deity_name = GLOB.deity
+ B.name = GLOB.bible_name
+ B.icon_state = GLOB.bible_icon_state
+ B.item_state = GLOB.bible_item_state
+ to_chat(H, "There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the [title].")
+ return
+
+ INVOKE_ASYNC(src, .proc/religion_prompts, H, B)
- if (!new_religion)
- new_religion = religion_name
- switch(lowertext(new_religion))
- if("unitarianism")
- B.name = "The Great Canon"
- if("christianity")
- B.name = "The Holy Bible"
- if("judaism")
- B.name = "The Torah"
- if("islam")
- B.name = "Quran"
- if("buddhism")
- B.name = "Tripitakas"
- if("hinduism")
- B.name = pick("The Srimad Bhagvatam", "The Four Vedas", "The Shiv Mahapuran", "Devi Mahatmya")
- if("neopaganism")
- B.name = "Neopagan Hymnbook"
- if("phact shintoism")
- B.name = "The Kojiki"
- if("kishari national faith")
- B.name = "The Scriptures of Kishar"
- if("pleromanism")
- B.name = "The Revised Great Canon"
- if("spectralism")
- B.name = "The Book of the Spark"
- if("hauler")
- B.name = "Histories of Captaincy"
- if("nock")
- B.name = "The Book of the First"
- if("singulitarian worship")
- B.name = "The Book of the Precursors"
- if("starlit path of angessa martei")
- B.name = "Quotations of Exalted Martei"
- if("sikhism")
- B.name = "Guru Granth Sahib"
- else
- B.name = "The Holy Book of [new_religion]"
- feedback_set_details("religion_name","[new_religion]")
+/datum/job/chaplain/proc/religion_prompts(mob/living/carbon/human/H, obj/item/weapon/storage/bible/B)
+ var/religion_name = "Unitarianism"
+ var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Unitarianism", "Name change", religion_name), MAX_NAME_LEN)
+ if(!new_religion)
+ new_religion = religion_name
- spawn(1)
- var/deity_name = "Hashem"
- var/new_deity = sanitize(input(H, "Would you like to change your deity? Default is Hashem", "Name change", deity_name), MAX_NAME_LEN)
+ switch(lowertext(new_religion))
+ if("unitarianism")
+ B.name = "The Great Canon"
+ if("christianity")
+ B.name = "The Holy Bible"
+ if("judaism")
+ B.name = "The Torah"
+ if("islam")
+ B.name = "Quran"
+ if("buddhism")
+ B.name = "Tripitakas"
+ if("hinduism")
+ B.name = pick("The Srimad Bhagvatam", "The Four Vedas", "The Shiv Mahapuran", "Devi Mahatmya")
+ if("neopaganism")
+ B.name = "Neopagan Hymnbook"
+ if("phact shintoism")
+ B.name = "The Kojiki"
+ if("kishari national faith")
+ B.name = "The Scriptures of Kishar"
+ if("pleromanism")
+ B.name = "The Revised Great Canon"
+ if("spectralism")
+ B.name = "The Book of the Spark"
+ if("hauler")
+ B.name = "Histories of Captaincy"
+ if("nock")
+ B.name = "The Book of the First"
+ if("singulitarian worship")
+ B.name = "The Book of the Precursors"
+ if("starlit path of angessa martei")
+ B.name = "Quotations of Exalted Martei"
+ if("sikhism")
+ B.name = "Guru Granth Sahib"
+ else
+ B.name = "The Holy Book of [new_religion]"
+ feedback_set_details("religion_name","[new_religion]")
- if ((length(new_deity) == 0) || (new_deity == "Hashem") )
- new_deity = deity_name
- B.deity_name = new_deity
+ var/deity_name = "Hashem"
+ var/new_deity = sanitize(input(H, "Would you like to change your deity? Default is Hashem", "Name change", deity_name), MAX_NAME_LEN)
- var/accepted = 0
- var/outoftime = 0
- spawn(200) // 20 seconds to choose
- outoftime = 1
- var/new_book_style = "Bible"
+ if((length(new_deity) == 0) || (new_deity == "Hashem"))
+ new_deity = deity_name
+ B.deity_name = new_deity
- while(!accepted)
- if(!B) break // prevents possible runtime errors
- new_book_style = input(H,"Which bible style would you like?") in list("Bible", "Koran", "Scrapbook", "Pagan", "White Bible", "Holy Light", "Athiest", "Tome", "The King in Yellow", "Ithaqua", "Scientology", "the bible melts", "Necronomicon","Orthodox","Torah")
- switch(new_book_style)
- if("Koran")
- B.icon_state = "koran"
- B.item_state = "koran"
- if("Scrapbook")
- B.icon_state = "scrapbook"
- B.item_state = "scrapbook"
- if("White Bible")
- B.icon_state = "white"
- B.item_state = "syringe_kit"
- if("Holy Light")
- B.icon_state = "holylight"
- B.item_state = "syringe_kit"
- if("Athiest")
- B.icon_state = "athiest"
- B.item_state = "syringe_kit"
- if("Tome")
- B.icon_state = "tome"
- B.item_state = "syringe_kit"
- if("The King in Yellow")
- B.icon_state = "kingyellow"
- B.item_state = "kingyellow"
- if("Ithaqua")
- B.icon_state = "ithaqua"
- B.item_state = "ithaqua"
- if("Scientology")
- B.icon_state = "scientology"
- B.item_state = "scientology"
- if("the bible melts")
- B.icon_state = "melted"
- B.item_state = "melted"
- if("Necronomicon")
- B.icon_state = "necronomicon"
- B.item_state = "necronomicon"
- if("Pagan")
- B.icon_state = "shadows"
- B.item_state = "syringe_kit"
- if("Orthodox")
- B.icon_state = "orthodoxy"
- B.item_state = "bible"
- if("Torah")
- B.icon_state = "torah"
- B.item_state = "clipboard"
- if("Guru")
- B.icon_state = "guru"
- B.item_state = "clipboard"
- else
- B.icon_state = "bible"
- B.item_state = "bible"
+ GLOB.religion = new_religion
+ GLOB.bible_name = B.name
+ GLOB.deity = B.deity_name
+ feedback_set_details("religion_deity","[new_deity]")
+
- H.update_inv_l_hand() // so that it updates the bible's item_state in his hand
-
- switch(input(H,"Look at your bible - is this what you want?") in list("Yes","No"))
- if("Yes")
- accepted = 1
- if("No")
- if(outoftime)
- to_chat(H, "Welp, out of time, buddy. You're stuck. Next time choose faster.")
- accepted = 1
-
- if(ticker)
- ticker.Bible_icon_state = B.icon_state
- ticker.Bible_item_state = B.item_state
- ticker.Bible_name = B.name
- ticker.Bible_deity_name = B.deity_name
- feedback_set_details("religion_deity","[new_deity]")
- feedback_set_details("religion_book","[new_book_style]")
- return 1
-
-/* If you uncomment this, every time the mob preview updates it makes a new PDA. It seems to work just fine and display without it, so why this exists, haven't a clue. -Hawk
-/datum/job/chaplain/equip_preview(var/mob/living/carbon/human/H, var/alt_title)
- return equip(H, alt_title, FALSE)
-*/
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/air_alarm.dm b/code/game/machinery/air_alarm.dm
index 64f7f93f86..d4e00e6c22 100644
--- a/code/game/machinery/air_alarm.dm
+++ b/code/game/machinery/air_alarm.dm
@@ -188,7 +188,7 @@
/obj/machinery/alarm/proc/handle_heating_cooling(var/datum/gas_mixture/environment)
if(!regulating_temperature)
//check for when we should start adjusting temperature
- if(!get_danger_level(target_temperature, TLV["temperature"]) && abs(environment.temperature - target_temperature) > 2.0)
+ if(!get_danger_level(target_temperature, TLV["temperature"]) && abs(environment.temperature - target_temperature) > 2.0 && environment.return_pressure() >= 1)
update_use_power(USE_POWER_ACTIVE)
regulating_temperature = 1
audible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\
@@ -196,7 +196,7 @@
playsound(src, 'sound/machines/click.ogg', 50, 1)
else
//check for when we should stop adjusting temperature
- if(get_danger_level(target_temperature, TLV["temperature"]) || abs(environment.temperature - target_temperature) <= 0.5)
+ if(get_danger_level(target_temperature, TLV["temperature"]) || abs(environment.temperature - target_temperature) <= 0.5 || environment.return_pressure() < 1)
update_use_power(USE_POWER_IDLE)
regulating_temperature = 0
audible_message("\The [src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.",\
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/autolathe.dm b/code/game/machinery/autolathe.dm
index 0159c151ec..4351d29698 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -316,7 +316,7 @@
/obj/machinery/autolathe/dismantle()
for(var/mat in stored_material)
- var/material/M = get_material_by_name(mat)
+ var/datum/material/M = get_material_by_name(mat)
if(!istype(M))
continue
var/obj/item/stack/material/S = new M.stack_type(get_turf(src))
@@ -330,7 +330,7 @@
/obj/machinery/autolathe/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything
var/recursive = amount == -1 ? 1 : 0
var/matstring = lowertext(material)
- var/material/M = get_material_by_name(matstring)
+ var/datum/material/M = get_material_by_name(matstring)
var/obj/item/stack/material/S = M.place_sheet(get_turf(src))
if(amount <= 0)
diff --git a/code/game/machinery/bomb_tester_vr.dm b/code/game/machinery/bomb_tester_vr.dm
index 826f632492..e3a3643526 100644
--- a/code/game/machinery/bomb_tester_vr.dm
+++ b/code/game/machinery/bomb_tester_vr.dm
@@ -237,12 +237,12 @@
pressure = faketank.return_pressure()
var/strength = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE
- var/mult = ((faketank.volume/140)**(1/2)) * (faketank.total_moles**2/3)/((29*0.64) **2/3) //Don't ask me what this is, see tanks.dm
+ var/mult = ((faketank.volume/140)**(1/2)) * (faketank.total_moles**(2/3))/((29*0.64) **(2/3)) //Don't ask me what this is, see tanks.dm
var/dev = round((mult*strength)*0.15)
var/heavy = round((mult*strength)*0.35)
var/light = round((mult*strength)*0.80)
- simulation_results += "
Final Result: Explosive tank rupture. [dev?"Extreme damage within [2.5*dev] meters. ":""][heavy?"Heavy damage within [2.5*heavy] meters. ":""][light?"Light damage within [2.5*light] meters. ":""]Hazardous shrapnel produced."
+ simulation_results += "
Final Result: Explosive tank rupture. [dev?"Extreme damage within [2*dev] meters. ":""][heavy?"Heavy damage within [2*heavy] meters. ":""][light?"Light damage within [2*light] meters. ":""]Hazardous shrapnel produced."
return 1
else
faketank_integrity -= 7
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 af9201e94c..40a0f03d8e 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)
+ 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
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 85924d79f6..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.")
@@ -66,23 +66,33 @@
if(..())
return
user.set_machine(src)
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/computer/timeclock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- user.set_machine(src)
+/obj/machinery/computer/timeclock/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "TimeClock", name)
+ ui.open()
+
+/obj/machinery/computer/timeclock/tgui_data(mob/user)
+ var/list/data = ..()
- var/list/data = list()
// Okay, data for showing the user's OWN PTO stuff
if(user.client)
data["department_hours"] = SANITIZE_LIST(user.client.department_hours)
data["user_name"] = "[user]"
// Data about the card that we put into it.
+ data["card"] = null
+ data["assignment"] = null
+ data["job_datum"] = null
+ data["allow_change_job"] = null
+ data["job_choices"] = null
if(card)
data["card"] = "[card]"
data["assignment"] = card.assignment
var/datum/job/job = job_master.GetJob(card.rank)
- if (job)
+ if(job)
data["job_datum"] = list(
"title" = job.title,
"departments" = english_list(job.departments),
@@ -96,46 +106,42 @@
if(job && job.timeoff_factor < 0) // Currently are Off Duty, so gotta lookup what on-duty jobs are open
data["job_choices"] = getOpenOnDutyJobs(user, job.pto_type)
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "timeclock_vr.tmpl", capitalize(src.name), 500, 520)
- ui.set_initial_data(data)
- ui.open()
+ return data
-/obj/machinery/computer/timeclock/Topic(href, href_list)
+/obj/machinery/computer/timeclock/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
- usr.set_machine(src)
- src.add_fingerprint(usr)
+ return TRUE
- if (href_list["id"])
- if(card)
- usr.put_in_hands(card)
- card = null
- else
- var/obj/item/I = usr.get_active_hand()
- if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
- I.forceMove(src)
- card = I
- update_icon()
- return 1
- if(href_list["switch-to-onduty-rank"])
- if(checkFace())
- if(checkCardCooldown())
- makeOnDuty(href_list["switch-to-onduty-rank"], href_list["switch-to-onduty-assignment"])
+ add_fingerprint(usr)
+
+ switch(action)
+ if("id")
+ if(card)
usr.put_in_hands(card)
card = null
- update_icon()
- return 1
- if(href_list["switch-to-offduty"])
- if(checkFace())
- if(checkCardCooldown())
- makeOffDuty()
- usr.put_in_hands(card)
- card = null
- update_icon()
- return 1
- return 1 // Return 1 to update UI
+ else
+ var/obj/item/I = usr.get_active_hand()
+ if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
+ I.forceMove(src)
+ card = I
+ update_icon()
+ return TRUE
+ if("switch-to-onduty-rank")
+ if(checkFace())
+ if(checkCardCooldown())
+ makeOnDuty(params["switch-to-onduty-rank"], params["switch-to-onduty-assignment"])
+ usr.put_in_hands(card)
+ card = null
+ update_icon()
+ return TRUE
+ if("switch-to-offduty")
+ if(checkFace())
+ if(checkCardCooldown())
+ makeOffDuty()
+ usr.put_in_hands(card)
+ card = null
+ update_icon()
+ return TRUE
/obj/machinery/computer/timeclock/proc/getOpenOnDutyJobs(var/mob/user, var/department)
var/list/available_jobs = list()
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index a133aab9b1..2a36b5db6c 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -74,97 +74,81 @@
storage_name = "Travel Oversight Control"
allow_items = 1
-/obj/machinery/computer/cryopod/attack_ai()
- attack_hand()
+/obj/machinery/computer/cryopod/attack_ai(mob/user)
+ attack_hand(user)
-/obj/machinery/computer/cryopod/attack_hand(mob/user = usr)
+/obj/machinery/computer/cryopod/attack_hand(mob/user)
if(stat & (NOPOWER|BROKEN))
return
- user.set_machine(src)
- add_fingerprint(usr)
+ tgui_interact(user)
- var/dat
+/obj/machinery/computer/cryopod/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, "CryoStorageVr", storage_name) // VOREStation Edit - Use our own template for our custom data
+ ui.open()
- if(!(ticker))
- return
+/obj/machinery/computer/cryopod/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- dat += "
[storage_name]
"
- dat += "Welcome, [user.real_name].
"
- dat += "View storage log.
"
+ data["real_name"] = user.real_name
+ data["allow_items"] = allow_items
+ data["crew"] = frozen_crew
+
+ data["items"] = list()
if(allow_items)
- dat += "View objects.
"
- //dat += "Recover object.
" //VOREStation Removal - Just log them.
- //dat += "Recover all objects.
" //VOREStation Removal
+ for(var/F in frozen_items)
+ data["items"].Add(F) // VOREStation Edit
+ /* VOREStation Removal
+ data["items"].Add(list(list(
+ "name" = "[F]",
+ "ref" = REF(F),
+ )))
+ VOREStation Removal End */
- user << browse(dat, "window=cryopod_console")
- onclose(user, "cryopod_console")
-
-/obj/machinery/computer/cryopod/Topic(href, href_list)
+ return data
+/obj/machinery/computer/cryopod/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
- var/mob/user = usr
+ add_fingerprint(usr)
- add_fingerprint(user)
+ return FALSE // VOREStation Edit - prevent topic exploits
- if(href_list["log"])
+ switch(action)
+ if("item")
+ if(!allow_items)
+ return
- var/dat = "Recently stored [storage_type]
"
- for(var/person in frozen_crew)
- dat += "[person]
"
- dat += "
"
+ if(!LAZYLEN(frozen_items))
+ to_chat(usr, "There is nothing to recover from storage.")
+ return
- user << browse(dat, "window=cryolog")
+ var/obj/item/I = locate(params["ref"]) in frozen_items
+ if(!I)
+ to_chat(usr, "\The [I] is no longer in storage.")
+ return
- if(href_list["view"])
- if(!allow_items) return
+ visible_message("The console beeps happily as it disgorges [I].")
- var/dat = "Recently stored objects
"
- //VOREStation Edit Start
- for(var/I in frozen_items)
- dat += "[I]
"
- //VOREStation Edit End
- dat += "
"
-
- user << browse(dat, "window=cryoitems")
-
- else if(href_list["item"])
- if(!allow_items) return
-
- if(frozen_items.len == 0)
- to_chat(user, "There is nothing to recover from storage.")
- return
-
- var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items
- if(!I)
- return
-
- if(!(I in frozen_items))
- to_chat(user, "\The [I] is no longer in storage.")
- return
-
- visible_message("The console beeps happily as it disgorges \the [I].", 3)
-
- I.forceMove(get_turf(src))
- frozen_items -= I
-
- else if(href_list["allitems"])
- if(!allow_items) return
-
- if(frozen_items.len == 0)
- to_chat(user, "There is nothing to recover from storage.")
- return
-
- visible_message("The console beeps happily as it disgorges the desired objects.", 3)
-
- for(var/obj/item/I in frozen_items)
I.forceMove(get_turf(src))
frozen_items -= I
+ if("allitems")
+ if(!allow_items)
+ return
+
+ if(!LAZYLEN(frozen_items))
+ to_chat(usr, "There is nothing to recover from storage.")
+ return
+
+ visible_message("The console beeps happily as it disgorges the desired objects.")
+
+ for(var/obj/item/I in frozen_items)
+ I.forceMove(get_turf(src))
+ frozen_items -= I
- updateUsrDialog()
- return
/obj/item/weapon/circuitboard/cryopodcontrol
name = "Circuit board (Cryogenic Oversight Console)"
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index 05eb9c322c..db27559796 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -14,7 +14,7 @@ Barricades
density = 1.0
var/health = 100
var/maxhealth = 100
- var/material/material
+ var/datum/material/material
/obj/structure/barricade/New(var/newloc, var/material_name)
..(newloc)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 8f33d05787..7f2ca2cb2c 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/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm
index a6b503cdbd..bc9c199ed2 100644
--- a/code/game/machinery/doors/blast_door.dm
+++ b/code/game/machinery/doors/blast_door.dm
@@ -19,7 +19,7 @@
icon = 'icons/obj/doors/rapid_pdoor.dmi'
icon_state = null
min_force = 20 //minimum amount of force needed to damage the door with a melee weapon
- var/material/implicit_material
+ var/datum/material/implicit_material
// Icon states for different shutter types. Simply change this instead of rewriting the update_icon proc.
var/icon_state_open = null
var/icon_state_opening = null
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 f08178f03d..e8e741b578 100644
--- a/code/game/machinery/jukebox.dm
+++ b/code/game/machinery/jukebox.dm
@@ -188,91 +188,91 @@
if (panel_open)
overlays += "panel_open"
-/obj/machinery/media/jukebox/Topic(href, href_list)
- if(..() || !(Adjacent(usr) || istype(usr, /mob/living/silicon)))
- return
-
- if(!anchored)
- to_chat(usr, "You must secure \the [src] first.")
- return
-
- if(inoperable())
- to_chat(usr, "\The [src] doesn't appear to function.")
- return
-
- if(href_list["change_track"])
- var/datum/track/T = locate(href_list["change_track"]) in tracks
- if(istype(T))
- current_track = T
- StartPlaying()
- else if(href_list["loopmode"])
- var/newval = text2num(href_list["loopmode"])
- loop_mode = sanitize_inlist(newval, list(JUKEMODE_NEXT, JUKEMODE_RANDOM, JUKEMODE_REPEAT_SONG, JUKEMODE_PLAY_ONCE), loop_mode)
- else if(href_list["volume"])
- var/newval = input("Choose Jukebox volume (0-100%)", "Jukebox volume", round(volume * 100.0))
- newval = sanitize_integer(text2num(newval), min = 0, max = 100, default = volume * 100.0)
- volume = newval / 100.0
- update_music() // To broadcast volume change without restarting song
- else if(href_list["stop"])
- StopPlaying()
- else if(href_list["play"])
- if(emagged)
- playsound(src, 'sound/items/AirHorn.ogg', 100, 1)
- for(var/mob/living/carbon/M in ohearers(6, src))
- if(M.get_ear_protection() >= 2)
- continue
- M.SetSleeping(0)
- M.stuttering += 20
- M.ear_deaf += 30
- M.Weaken(3)
- if(prob(30))
- M.Stun(10)
- M.Paralyse(4)
- else
- M.make_jittery(500)
- spawn(15)
- explode()
- else if(current_track == null)
- to_chat(usr, "No track selected.")
- else
- StartPlaying()
-
- return 1
-
/obj/machinery/media/jukebox/interact(mob/user)
if(inoperable())
to_chat(usr, "\The [src] doesn't appear to function.")
return
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/media/jukebox/ui_interact(mob/user, ui_key = "jukebox", var/datum/nanoui/ui = null, var/force_open = 1)
- var/title = "RetroBox - Space Style"
- var/data[0]
+/obj/machinery/media/jukebox/tgui_status(mob/user)
+ if(inoperable())
+ to_chat(user, "[src] doesn't appear to function.")
+ return STATUS_CLOSE
+ if(!anchored)
+ to_chat(user, "You must secure [src] first.")
+ return STATUS_CLOSE
+ . = ..()
- if(operable())
- data["playing"] = playing
- data["hacked"] = hacked
- data["max_queue_len"] = max_queue_len
- data["media_start_time"] = media_start_time
- data["loop_mode"] = loop_mode
- data["volume"] = volume
- if(current_track)
- data["current_track_ref"] = "\ref[current_track]" // Convenient shortcut
- data["current_track"] = current_track.toNanoList()
- data["percent"] = playing ? min(100, round(world.time - media_start_time) / current_track.duration) : 0;
-
- var/list/nano_tracks = new
- for(var/datum/track/T in tracks)
- nano_tracks[++nano_tracks.len] = T.toNanoList()
- data["tracks"] = nano_tracks
-
- // 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)
- ui = new(user, src, ui_key, "jukebox.tmpl", title, 450, 600)
- ui.set_initial_data(data)
+/obj/machinery/media/jukebox/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Jukebox", "RetroBox - Space Style")
ui.open()
- ui.set_auto_update(playing)
+
+/obj/machinery/media/jukebox/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
+ data["playing"] = playing
+ data["loop_mode"] = loop_mode
+ data["volume"] = volume
+ data["current_track_ref"] = null
+ data["current_track"] = null
+ if(current_track)
+ data["current_track_ref"] = "\ref[current_track]" // Convenient shortcut
+ data["current_track"] = current_track.toTguiList()
+ data["percent"] = playing ? min(100, round(world.time - media_start_time) / current_track.duration) : 0;
+
+ var/list/tgui_tracks = list()
+ for(var/datum/track/T in tracks)
+ tgui_tracks.Add(list(T.toTguiList()))
+ data["tracks"] = tgui_tracks
+
+ return data
+
+/obj/machinery/media/jukebox/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
+
+ switch(action)
+ if("change_track")
+ var/datum/track/T = locate(params["change_track"]) in tracks
+ if(istype(T))
+ current_track = T
+ StartPlaying()
+ return TRUE
+ if("loopmode")
+ var/newval = text2num(params["loopmode"])
+ loop_mode = sanitize_inlist(newval, list(JUKEMODE_NEXT, JUKEMODE_RANDOM, JUKEMODE_REPEAT_SONG, JUKEMODE_PLAY_ONCE), loop_mode)
+ return TRUE
+ if("volume")
+ volume = clamp(params["val"], 0, 1)
+ update_music() // To broadcast volume change without restarting song
+ return TRUE
+ if("stop")
+ StopPlaying()
+ return TRUE
+ if("play")
+ if(emagged)
+ playsound(src, 'sound/items/AirHorn.ogg', 100, 1)
+ for(var/mob/living/carbon/M in ohearers(6, src))
+ if(M.get_ear_protection() >= 2)
+ continue
+ M.SetSleeping(0)
+ M.stuttering += 20
+ M.ear_deaf += 30
+ M.Weaken(3)
+ if(prob(30))
+ M.Stun(10)
+ M.Paralyse(4)
+ else
+ M.make_jittery(500)
+ spawn(15)
+ explode()
+ else if(current_track == null)
+ to_chat(usr, "No track selected.")
+ else
+ StartPlaying()
+ return TRUE
/obj/machinery/media/jukebox/attack_ai(mob/user as mob)
return src.attack_hand(user)
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 6ea6e58905..7786baf208 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.
@@ -132,20 +132,6 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
var/ispowered = 1 //starts powered, changes with power_change()
//var/list/datum/feed_channel/channel_list = list() //This list will contain the names of the feed channels. Each name will refer to a data region where the messages of the feed channels are stored.
//OBSOLETE: We're now using a global news network
- var/screen = 0 //Or maybe I'll make it into a list within a list afterwards... whichever I prefer, go fuck yourselves :3
- // 0 = welcome screen - main menu
- // 1 = view feed channels
- // 2 = create feed channel
- // 3 = create feed story
- // 4 = feed story submited sucessfully
- // 5 = feed channel created successfully
- // 6 = ERROR: Cannot create feed story
- // 7 = ERROR: Cannot create feed channel
- // 8 = print newspaper
- // 9 = viewing channel feeds
- // 10 = censor feed story
- // 11 = censor feed channel
- //Holy shit this is outdated, made this when I was still starting newscasters :3
var/paper_remaining = 0
var/securityCaster = 0
// 0 = Caster cannot be used to issue wanted posters
@@ -171,6 +157,8 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
anchored = 1
var/obj/machinery/exonet_node/node = null
circuit = /obj/item/weapon/circuitboard/newscaster
+ // TGUI
+ var/list/temp = null
/obj/machinery/newscaster/security_unit //Security unit
name = "Security Newscaster"
@@ -246,10 +234,16 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
return
return
-/obj/machinery/newscaster/attack_ai(mob/user as mob)
+/obj/machinery/newscaster/attack_ai(mob/user)
return attack_hand(user)
-/obj/machinery/newscaster/attack_hand(mob/user as mob) //########### THE MAIN BEEF IS HERE! And in the proc below this...############
+/obj/machinery/newscaster/tgui_status(mob/user)
+ if(!ispowered || isbroken)
+ return STATUS_CLOSE
+ . = ..()
+
+
+/obj/machinery/newscaster/attack_hand(mob/user)
if(!ispowered || isbroken)
return
@@ -263,263 +257,136 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
if(!user.IsAdvancedToolUser())
return 0
+
+ tgui_interact(user)
- if(istype(user, /mob/living/carbon/human) || istype(user,/mob/living/silicon))
- var/mob/living/human_or_robot_user = user
- var/dat
- dat = text("NewscasterNewscaster Unit #[unit_no]
")
+/**
+ * Sets a temporary message to display to the user
+ *
+ * Arguments:
+ * * text - Text to display, null/empty to clear the message from the UI
+ * * style - The style of the message: (color name), info, success, warning, danger, virus
+ */
+/obj/machinery/newscaster/proc/set_temp(text = "", style = "info", update_now = FALSE)
+ temp = list(text = text, style = style)
+ if(update_now)
+ SStgui.update_uis(src)
+
+/obj/machinery/newscaster/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, "Newscaster", "Newscaster Unit #[unit_no]")
+ ui.open()
- scan_user(human_or_robot_user) //Newscaster scans you
+/obj/machinery/newscaster/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- switch(screen)
- if(0)
- dat += "Welcome to Newscasting Unit #[unit_no].
Interface & News networks Operational."
- dat += "
Property of NanoTrasen Inc"
- if(news_network.wanted_issue)
- dat+= "
Read Wanted Issue"
- dat+= "
Create Feed Channel"
- dat+= "
View Feed Channels"
- dat+= "
Submit new Feed story"
- dat+= "
Print newspaper"
- dat+= "
Re-scan User"
- dat+= "
Exit"
- if(securityCaster)
- var/wanted_already = 0
- if(news_network.wanted_issue)
- wanted_already = 1
+ // Main menu
+ data["temp"] = temp
- dat+="
Feed Security functions:
"
- dat+="
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue"
- dat+="
Censor Feed Stories"
- dat+="
Mark Feed Channel with [using_map.company_name] D-Notice"
- dat+="
The newscaster recognises you as: [scanned_user]"
- if(1)
- dat+= "Station Feed Channels
"
- if(isemptylist(news_network.network_channels))
- dat+="No active channels found..."
- else
- for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
- if(CHANNEL.is_admin_channel)
- dat+="[CHANNEL.channel_name]
"
- else
- dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
"
- dat+="
Refresh"
- dat+="
Back"
- if(2)
- dat+="Creating new Feed Channel..."
- dat+="
Channel Name: [channel_name]
"
- dat+="Channel Author: [scanned_user]
"
- dat+="Will Accept Public Feeds: [(c_locked) ? ("NO") : ("YES")]
"
- dat+="
Submit
Cancel
"
- if(3)
- dat+="Creating new Feed Message..."
- dat+="
Receiving Channel: [channel_name]
" //MARK
- dat+="Message Author: [scanned_user]
"
- dat+="Message Body: [msg]
"
- dat+="Attach Photo: [(photo_data ? "Photo Attached" : "No Photo")]"
- dat+="
Submit
Cancel
"
- if(4)
- dat+="Feed story successfully submitted to [channel_name].
"
- dat+="
Return
"
- if(5)
- dat+="Feed Channel [channel_name] created successfully.
"
- dat+="
Return
"
- if(6)
- dat+="ERROR: Could not submit Feed story to Network.
"
- if(channel_name=="")
- dat+="•Invalid receiving channel name.
"
- if(scanned_user=="Unknown")
- dat+="•Channel author unverified.
"
- if(msg == "" || msg == "\[REDACTED\]")
- dat+="•Invalid message body.
"
+ data["user"] = tgui_user_name(user)
+ data["unit_no"] = unit_no
- dat+="
Return
"
- if(7)
- dat+="ERROR: Could not submit Feed Channel to Network.
"
- var/list/existing_authors = list()
- for(var/datum/feed_channel/FC in news_network.network_channels)
- if(FC.author == "\[REDACTED\]")
- existing_authors += FC.backup_author
- else
- existing_authors += FC.author
- if(scanned_user in existing_authors)
- dat+="•There already exists a Feed channel under your name.
"
- if(channel_name=="" || channel_name == "\[REDACTED\]")
- dat+="•Invalid channel name.
"
- var/check = 0
- for(var/datum/feed_channel/FC in news_network.network_channels)
- if(FC.channel_name == channel_name)
- check = 1
- break
- if(check)
- dat+="•Channel name already in use.
"
- if(scanned_user=="Unknown")
- dat+="•Channel author unverified.
"
- dat+="
Return
"
- if(8)
- var/total_num=length(news_network.network_channels)
- var/active_num=total_num
- var/message_num=0
- for(var/datum/feed_channel/FC in news_network.network_channels)
- if(!FC.censored)
- message_num += length(FC.messages) //Dont forget, datum/feed_channel's var messages is a list of datum/feed_message
- else
- active_num--
- dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories." //TODO: CONTINUE
- dat+="
Liquid Paper remaining: [(paper_remaining) *100 ] cm^3"
- dat+="
Print Paper"
- dat+="
Cancel"
- if(9)
- dat+="[viewing_channel.channel_name]: \[created by: [viewing_channel.author]\]
"
- if(viewing_channel.censored)
- dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.
"
- dat+="No further feed story additions are allowed while the D-Notice is in effect.
"
- else
- if(isemptylist(viewing_channel.messages))
- dat+="No feed messages found in channel...
"
- else
- var/i = 0
- for(var/datum/feed_message/MESSAGE in viewing_channel.messages)
- i++
- dat+="-[MESSAGE.body]
"
- if(MESSAGE.img)
- usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
- dat+="
"
- if(MESSAGE.caption)
- dat+="[MESSAGE.caption]
"
- dat+="
"
- dat+="\[Story by [MESSAGE.author] - [MESSAGE.time_stamp]\]
"
- dat+="
Refresh"
- dat+="
Back"
- if(10)
- dat+="[using_map.company_name] Feed Censorship Tool
"
- dat+="NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.
"
- dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it."
- dat+="
Select Feed channel to get Stories from:
"
- if(isemptylist(news_network.network_channels))
- dat+="No feed channels found active...
"
- else
- for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
- dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
"
- dat+="
Cancel"
- if(11)
- dat+="[using_map.company_name] D-Notice Handler
"
- dat+="A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's"
- dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed"
- dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.
"
- if(isemptylist(news_network.network_channels))
- dat+="No feed channels found active...
"
- else
- for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
- dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : null]
"
+ var/list/wanted_issue = null
+ if(news_network.wanted_issue)
+ wanted_issue = list(
+ "author" = news_network.wanted_issue.backup_author,
+ "criminal" = news_network.wanted_issue.author,
+ "desc" = news_network.wanted_issue.body,
+ "img" = null
+ )
+ if(news_network.wanted_issue.img)
+ wanted_issue["img"] = icon2base64(news_network.wanted_issue.img)
- dat+="
Back"
- if(12)
- dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.author] \]
"
- dat+="[(viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
"
+ data["wanted_issue"] = wanted_issue
+ data["securityCaster"] = !!securityCaster
+
+ var/list/network_channels = list()
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ network_channels.Add(list(list(
+ "admin" = FC.is_admin_channel,
+ "ref" = REF(FC),
+ "name" = FC.channel_name,
+ "censored" = FC.censored,
+ )))
+ data["channels"] = network_channels
- if(isemptylist(viewing_channel.messages))
- dat+="No feed messages found in channel...
"
- else
- for(var/datum/feed_message/MESSAGE in viewing_channel.messages)
- dat+="-[MESSAGE.body]
\[[MESSAGE.message_type] by [MESSAGE.author]\]
"
- dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
"
- dat+="
Back"
- if(13)
- dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.author] \]
"
- dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
"
- if(viewing_channel.censored)
- dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.
"
- dat+="No further feed story additions are allowed while the D-Notice is in effect.
"
- else
- if(isemptylist(viewing_channel.messages))
- dat+="No feed messages found in channel...
"
- else
- for(var/datum/feed_message/MESSAGE in viewing_channel.messages)
- dat+="-[MESSAGE.body]
\[[MESSAGE.message_type] by [MESSAGE.author]\]
"
+ // Creating Channels
+ data["channel_name"] = channel_name
+ data["c_locked"] = c_locked
- dat+="
Back"
- if(14)
- dat+="Wanted Issue Handler:"
- var/wanted_already = 0
- var/end_param = 1
- if(news_network.wanted_issue)
- wanted_already = 1
- end_param = 2
+ // Creating Messages
+ // data["channel_name"] = channel_name
+ data["msg"] = msg
+ data["photo_data"] = !!photo_data
- if(wanted_already)
- dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below."
- dat+="
"
- dat+="Criminal Name: [channel_name]
"
- dat+="Description: [msg]
"
- dat+="Attach Photo: [(photo_data ? "Photo Attached" : "No Photo")]"
- if(wanted_already)
- dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
"
- else
- dat+="Wanted Issue will be created under prosecutor: [scanned_user]
"
- dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]"
- if(wanted_already)
- dat+="
Take down Issue"
- dat+="
Cancel"
- if(15)
- dat+="Wanted issue for [channel_name] is now in Network Circulation.
"
- dat+="
Return
"
- if(16)
- dat+="ERROR: Wanted Issue rejected by Network.
"
- if(channel_name=="" || channel_name == "\[REDACTED\]")
- dat+="•Invalid name for person wanted.
"
- if(scanned_user=="Unknown")
- dat+="•Issue author unverified.
"
- if(msg == "" || msg == "\[REDACTED\]")
- dat+="•Invalid description.
"
- dat+="
Return
"
- if(17)
- dat+="Wanted Issue successfully deleted from Circulation
"
- dat+="
Return
"
- if(18)
- dat+="-- STATIONWIDE WANTED ISSUE --
\[Submitted by: [news_network.wanted_issue.backup_author]\]
"
- dat+="Criminal: [news_network.wanted_issue.author]
"
- dat+="Description: [news_network.wanted_issue.body]
"
- dat+="Photo:: "
- if(news_network.wanted_issue.img)
- usr << browse_rsc(news_network.wanted_issue.img, "tmp_photow.png")
- dat+="
"
- else
- dat+="None"
- dat+="
Back
"
- if(19)
- dat+="Wanted issue for [channel_name] successfully edited.
"
- dat+="
Return
"
- if(20)
- dat+="Printing successful. Please receive your newspaper from the bottom of the machine.
"
- dat+="Return"
- if(21)
- dat+="Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.
"
- dat+="Return"
- else
- dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com"
+ // Printing menu
+ var/total_num = LAZYLEN(news_network.network_channels)
+ var/active_num = total_num
+ var/message_num = 0
+ for(var/datum/feed_channel/FC in news_network.network_channels)
+ if(!FC.censored)
+ message_num += length(FC.messages) //Dont forget, datum/feed_channel's var messages is a list of datum/feed_message
+ else
+ active_num--
+ data["total_num"] = total_num
+ data["active_num"] = active_num
+ data["message_num"] = message_num
+ data["paper_remaining"] = paper_remaining
+ // Viewing a specific channel
+ var/list/viewing = null
+ if(viewing_channel)
+ var/list/messages = list()
+ viewing = list(
+ "name" = viewing_channel.channel_name,
+ "author" = viewing_channel.author,
+ "censored" = viewing_channel.censored,
+ "messages" = messages,
+ "ref" = REF(viewing_channel),
+ )
+ if(!viewing_channel.censored)
+ for(var/datum/feed_message/M in viewing_channel.messages)
+ var/list/msgdata = list(
+ "body" = M.body,
+ "img" = null,
+ "type" = M.message_type,
+ "caption" = null,
+ "author" = M.author,
+ "timestamp" = M.time_stamp,
+ "ref" = REF(M),
+ )
+ if(M.img)
+ msgdata["img"] = icon2base64(M.img)
+ msgdata["caption"] = M.caption
- human_or_robot_user << browse(dat, "window=newscaster_main;size=400x600")
- onclose(human_or_robot_user, "newscaster_main")
+ messages.Add(list(msgdata))
+ data["viewing_channel"] = viewing
-/obj/machinery/newscaster/Topic(href, href_list)
+ // Censorship
+ data["company"] = using_map.company_name
+
+ return data
+
+/obj/machinery/newscaster/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return
- if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
- usr.set_machine(src)
- if(href_list["set_channel_name"])
- channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN)
- updateUsrDialog()
- //update_icon()
+ return TRUE
- else if(href_list["set_channel_lock"])
+ switch(action)
+ if("cleartemp")
+ temp = null
+ return TRUE
+
+ if("set_channel_name")
+ channel_name = sanitizeSafe(params["val"], MAX_LNAME_LEN)
+ return TRUE
+
+ if("set_channel_lock")
c_locked = !c_locked
- updateUsrDialog()
- //update_icon()
+ return TRUE
- else if(href_list["submit_new_channel"])
+ if("submit_new_channel")
//var/list/existing_channels = list() //OBSOLETE
var/list/existing_authors = list()
for(var/datum/feed_channel/FC in news_network.network_channels)
@@ -533,121 +400,118 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
if(FC.channel_name == channel_name)
check = 1
break
- if(channel_name == "" || channel_name == "\[REDACTED\]" || scanned_user == "Unknown" || check || (scanned_user in existing_authors))
- screen=7
- else
- var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel")
- if(choice=="Confirm")
- news_network.CreateFeedChannel(channel_name, scanned_user, c_locked)
- screen=5
- updateUsrDialog()
- //update_icon()
+ var/our_user = tgui_user_name(usr)
+ if(channel_name == "" || channel_name == "\[REDACTED\]")
+ set_temp("Error: Could not submit feed channel to network: Invalid Channel Name.", "danger", FALSE)
+ return TRUE
+ if(our_user == "Unknown")
+ set_temp("Error: Could not submit feed channel to network: Channel author unverified.", "danger", FALSE)
+ return TRUE
+ if(check)
+ set_temp("Error: Could not submit feed channel to network: Channel name already in use.", "danger", FALSE)
+ return TRUE
+ if(our_user in existing_authors)
+ set_temp("Error: Could not submit feed channel to network: A feed channel already exists under your name.", "danger", FALSE)
+ return TRUE
- else if(href_list["set_channel_receiving"])
+ var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel")
+ if(choice == "Confirm")
+ news_network.CreateFeedChannel(channel_name, our_user, c_locked)
+ set_temp("Feed channel [channel_name] created successfully.", "success", FALSE)
+ return TRUE
+
+ if("set_channel_receiving")
//var/list/datum/feed_channel/available_channels = list()
var/list/available_channels = list()
for(var/datum/feed_channel/F in news_network.network_channels)
if((!F.locked || F.author == scanned_user) && !F.censored)
available_channels += F.channel_name
- channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels
- updateUsrDialog()
+ var/new_channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") as null|anything in available_channels
+ if(new_channel_name)
+ channel_name = new_channel_name
+ return TRUE
- else if(href_list["set_new_message"])
- msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", ""))
- updateUsrDialog()
+ if("set_new_message")
+ msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", "") as message|null)
+ return TRUE
- else if(href_list["set_attachment"])
+ if("set_attachment")
AttachPhoto(usr)
- updateUsrDialog()
+ return TRUE
- else if(href_list["submit_new_message"])
- if(msg =="" || msg=="\[REDACTED\]" || scanned_user == "Unknown" || channel_name == "")
- screen=6
- else
- var/image = photo_data ? photo_data.photo : null
- feedback_inc("newscaster_stories",1)
- news_network.SubmitArticle(msg, scanned_user, channel_name, image, 0)
- screen=4
+ if("submit_new_message")
+ var/our_user = tgui_user_name(usr)
+ if(msg == "" || msg == "\[REDACTED\]")
+ set_temp("Error: Could not submit feed message to network: Invalid Message.", "danger", FALSE)
+ return TRUE
+ if(our_user == "Unknown")
+ set_temp("Error: Could not submit feed message to network: Channel author unverified.", "danger", FALSE)
+ return TRUE
+ if(channel_name == "")
+ set_temp("Error: Could not submit feed message to network: No feed channel selected.", "danger", FALSE)
+ return TRUE
- updateUsrDialog()
+ var/image = photo_data ? photo_data.photo : null
+ feedback_inc("newscaster_stories",1)
+ news_network.SubmitArticle(msg, our_user, channel_name, image, 0)
+ set_temp("Feed message created successfully.", "success", FALSE)
+ return TRUE
- else if(href_list["create_channel"])
- screen=2
- updateUsrDialog()
-
- else if(href_list["create_feed_story"])
- screen=3
- updateUsrDialog()
-
- else if(href_list["menu_paper"])
- screen=8
- updateUsrDialog()
- else if(href_list["print_paper"])
+ if("print_paper")
if(!paper_remaining)
- screen=21
- else
- print_paper()
- screen = 20
- updateUsrDialog()
+ set_temp("Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.", "danger", FALSE)
+ return TRUE
+
+ print_paper()
+ set_temp("Printing successful. Please receive your newspaper from the bottom of the machine.", "success", FALSE)
+ return TRUE
- else if(href_list["menu_censor_story"])
- screen=10
- updateUsrDialog()
+ if("set_wanted_desc")
+ msg = sanitize(params["val"])
+ return TRUE
- else if(href_list["menu_censor_channel"])
- screen=11
- updateUsrDialog()
+ if("submit_wanted")
+ if(!securityCaster)
+ return FALSE
+ var/our_user = tgui_user_name(usr)
+ if(channel_name == "")
+ set_temp("Error: Could not submit wanted issue to network: Invalid Criminal Name.", "danger", FALSE)
+ return TRUE
+ if(msg == "")
+ set_temp("Error: Could not submit wanted issue to network: Invalid Description.", "danger", FALSE)
+ return TRUE
+ if(our_user == "Unknown")
+ set_temp("Error: Could not submit wanted issue to network: Author unverified.", "danger", FALSE)
+ return TRUE
- else if(href_list["menu_wanted"])
- var/already_wanted = 0
- if(news_network.wanted_issue)
- already_wanted = 1
+ var/choice = alert("Please confirm Wanted Issue change.", "Network Security Handler", "Confirm", "Cancel")
+ if(choice == "Confirm")
+ if(news_network.wanted_issue)
+ if(news_network.wanted_issue.is_admin_message)
+ alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot edit it.", "Ok")
+ return
+ news_network.wanted_issue.author = channel_name
+ news_network.wanted_issue.body = msg
+ news_network.wanted_issue.backup_author = scanned_user
+ if(photo_data)
+ news_network.wanted_issue.img = photo_data.photo.img
+ set_temp("Wanted issue for [channel_name] successfully edited.", "success", FALSE)
+ return TRUE
- if(already_wanted)
- channel_name = news_network.wanted_issue.author
- msg = news_network.wanted_issue.body
- screen = 14
- updateUsrDialog()
+ var/datum/feed_message/WANTED = new /datum/feed_message
+ WANTED.author = channel_name
+ WANTED.body = msg
+ WANTED.backup_author = scanned_user //I know, a bit wacky
+ if(photo_data)
+ WANTED.img = photo_data.photo.img
+ news_network.wanted_issue = WANTED
+ news_network.alert_readers()
+ set_temp("Wanted issue for [channel_name] is now in Network Circulation.", "success", FALSE)
+ return TRUE
- else if(href_list["set_wanted_name"])
- channel_name = sanitizeSafe(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""), MAX_LNAME_LEN)
- updateUsrDialog()
-
- else if(href_list["set_wanted_desc"])
- msg = sanitize(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", ""))
- updateUsrDialog()
-
- else if(href_list["submit_wanted"])
- var/input_param = text2num(href_list["submit_wanted"])
- if(msg == "" || channel_name == "" || scanned_user == "Unknown")
- screen = 16
- else
- var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel")
- if(choice=="Confirm")
- if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below
- var/datum/feed_message/WANTED = new /datum/feed_message
- WANTED.author = channel_name
- WANTED.body = msg
- WANTED.backup_author = scanned_user //I know, a bit wacky
- if(photo_data)
- WANTED.img = photo_data.photo.img
- news_network.wanted_issue = WANTED
- news_network.alert_readers()
- screen = 15
- else
- if(news_network.wanted_issue.is_admin_message)
- alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot edit it.","Ok")
- return
- news_network.wanted_issue.author = channel_name
- news_network.wanted_issue.body = msg
- news_network.wanted_issue.backup_author = scanned_user
- if(photo_data)
- news_network.wanted_issue.img = photo_data.photo.img
- screen = 19
-
- updateUsrDialog()
-
- else if(href_list["cancel_wanted"])
+ if("cancel_wanted")
+ if(!securityCaster)
+ return FALSE
if(news_network.wanted_issue.is_admin_message)
alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot take it down.","Ok")
return
@@ -656,49 +520,52 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
news_network.wanted_issue = null
for(var/obj/machinery/newscaster/NEWSCASTER in GLOB.allCasters)
NEWSCASTER.update_icon()
- screen=17
- updateUsrDialog()
+ set_temp("Wanted issue taken down.", "success", FALSE)
+ return TRUE
- else if(href_list["view_wanted"])
- screen=18
- updateUsrDialog()
- else if(href_list["censor_channel_author"])
- var/datum/feed_channel/FC = locate(href_list["censor_channel_author"])
+ if("censor_channel_author")
+ if(!securityCaster)
+ return FALSE
+ var/datum/feed_channel/FC = locate(params["ref"])
if(FC.is_admin_channel)
alert("This channel was created by a [using_map.company_name] Officer. You cannot censor it.","Ok")
return
- if(FC.author != "\[REDACTED\]")
+ if(FC.author != "\[REDACTED\]")
FC.backup_author = FC.author
- FC.author = "\[REDACTED\]"
+ FC.author = "\[REDACTED\]"
else
FC.author = FC.backup_author
FC.update()
- updateUsrDialog()
+ return TRUE
- else if(href_list["censor_channel_story_author"])
- var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"])
+ if("censor_channel_story_author")
+ if(!securityCaster)
+ return FALSE
+ var/datum/feed_message/MSG = locate(params["ref"])
if(MSG.is_admin_message)
alert("This message was created by a [using_map.company_name] Officer. You cannot censor its author.","Ok")
return
- if(MSG.author != "\[REDACTED\]")
+ if(MSG.author != "\[REDACTED\]")
MSG.backup_author = MSG.author
- MSG.author = "\[REDACTED\]"
+ MSG.author = "\[REDACTED\]"
else
MSG.author = MSG.backup_author
MSG.parent_channel.update()
- updateUsrDialog()
+ return TRUE
- else if(href_list["censor_channel_story_body"])
- var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"])
+ if("censor_channel_story_body")
+ if(!securityCaster)
+ return FALSE
+ var/datum/feed_message/MSG = locate(params["ref"])
if(MSG.is_admin_message)
alert("This channel was created by a [using_map.company_name] Officer. You cannot censor it.","Ok")
return
- if(MSG.body != "\[REDACTED\]")
+ if(MSG.body != "\[REDACTED\]")
MSG.backup_body = MSG.body
MSG.backup_caption = MSG.caption
MSG.backup_img = MSG.img
- MSG.body = "\[REDACTED\]"
- MSG.caption = "\[REDACTED\]"
+ MSG.body = "\[REDACTED\]"
+ MSG.caption = "\[REDACTED\]"
MSG.img = null
else
MSG.body = MSG.backup_body
@@ -706,60 +573,32 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
MSG.img = MSG.backup_img
MSG.parent_channel.update()
- updateUsrDialog()
+ return TRUE
- else if(href_list["pick_d_notice"])
- var/datum/feed_channel/FC = locate(href_list["pick_d_notice"])
- viewing_channel = FC
- screen=13
- updateUsrDialog()
-
- else if(href_list["toggle_d_notice"])
- var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"])
+ if("toggle_d_notice")
+ if(!securityCaster)
+ return FALSE
+ var/datum/feed_channel/FC = locate(params["ref"])
if(FC.is_admin_channel)
alert("This channel was created by a [using_map.company_name] Officer. You cannot place a D-Notice upon it.","Ok")
return
FC.censored = !FC.censored
FC.update()
- updateUsrDialog()
+ return TRUE
- else if(href_list["view"])
- screen=1
- updateUsrDialog()
-
- else if(href_list["setScreen"]) //Brings us to the main menu and resets all fields~
- screen = text2num(href_list["setScreen"])
- if(screen == 0)
- scanned_user = "Unknown";
- msg = "";
- c_locked=0;
- channel_name="";
- viewing_channel = null
- updateUsrDialog()
-
- else if(href_list["show_channel"])
- var/datum/feed_channel/FC = locate(href_list["show_channel"])
+ if("show_channel")
+ var/datum/feed_channel/FC = locate(params["show_channel"])
viewing_channel = FC
- screen = 9
- updateUsrDialog()
+ return TRUE
- else if(href_list["pick_censor_channel"])
- var/datum/feed_channel/FC = locate(href_list["pick_censor_channel"])
- viewing_channel = FC
- screen = 12
- updateUsrDialog()
-
- else if(href_list["refresh"])
- updateUsrDialog()
-
-/obj/machinery/newscaster/attackby(I as obj, user as mob)
+/obj/machinery/newscaster/attackby(I as obj, user)
if(computer_deconstruction_screwdriver(user, I))
return
else
attack_hand(user)
return
-/obj/machinery/newscaster/attack_ai(mob/user as mob)
+/obj/machinery/newscaster/attack_ai(mob/user)
return attack_hand(user) //or maybe it'll have some special functions? No idea.
/datum/news_photo
@@ -770,7 +609,7 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
is_synth = synth
photo = p
-/obj/machinery/newscaster/proc/AttachPhoto(mob/user as mob)
+/obj/machinery/newscaster/proc/AttachPhoto(mob/user)
if(photo_data)
if(!photo_data.is_synth)
photo_data.photo.loc = src.loc
@@ -812,7 +651,7 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
drop_sound = 'sound/items/drop/wrapper.ogg'
pickup_sound = 'sound/items/pickup/wrapper.ogg'
-obj/item/weapon/newspaper/attack_self(mob/user as mob)
+obj/item/weapon/newspaper/attack_self(mob/user)
if(ishuman(user))
var/mob/living/carbon/human/human_user = user
var/dat
@@ -868,7 +707,7 @@ obj/item/weapon/newspaper/attack_self(mob/user as mob)
for(var/datum/feed_channel/NP in news_content)
pages++
if(important_message!=null)
- dat+="Wanted Issue:
"
+ dat+="Wanted Issue:
"
dat+="Criminal name: [important_message.author]
"
dat+="Description: [important_message.body]
"
dat+="Photo:: "
@@ -922,7 +761,7 @@ obj/item/weapon/newspaper/Topic(href, href_list)
if(istype(src.loc, /mob))
attack_self(src.loc)
-obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob)
+obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user)
if(istype(W, /obj/item/weapon/pen))
if(scribble_page == curr_page)
to_chat(user, "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?")
@@ -939,8 +778,20 @@ obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob)
return
////////////////////////////////////helper procs
+/obj/machinery/newscaster/proc/tgui_user_name(mob/user)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ var/obj/item/weapon/card/id/I = H.GetIdCard()
+ if(I)
+ return GetNameAndAssignmentFromId(I)
-/obj/machinery/newscaster/proc/scan_user(mob/living/user as mob)
+ if(issilicon(user))
+ var/mob/living/silicon/S = user
+ return "[S.name] ([S.job])"
+
+ return "Unknown"
+
+/obj/machinery/newscaster/proc/scan_user(mob/living/user)
if(istype(user,/mob/living/carbon/human)) //User is a human
var/mob/living/carbon/human/human_user = user
var/obj/item/weapon/card/id/I = human_user.GetIdCard()
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/painter_vr.dm b/code/game/machinery/painter_vr.dm
index cc961a737f..64490a19b2 100644
--- a/code/game/machinery/painter_vr.dm
+++ b/code/game/machinery/painter_vr.dm
@@ -1,3 +1,10 @@
+// I'm honestly pretty sure that short of stuffing five million things into this
+// there's absolutely no way it could ever have any performance impact
+// Given that all it does is set the color var
+// But just in case it's cursed in some arcane horrible way
+// I'm going to leave this limit here
+#define MAX_PROCESSING 10 // Arbitrary performance insurance
+
/obj/machinery/gear_painter
name = "Color Mate"
desc = "A machine to give your apparel a fresh new color! Recommended to use with white items for best results."
@@ -29,9 +36,9 @@
processing.Cut()
return ..()
-/obj/machinery/gear_painter/attackby(obj/item/W as obj, mob/user as mob)
- if(processing.len)
- to_chat(user, "The machine is already loaded.")
+/obj/machinery/gear_painter/attackby(obj/item/W, mob/user)
+ if(LAZYLEN(processing) >= MAX_PROCESSING)
+ to_chat(user, "The machine is full.")
return
if(default_deconstruction_screwdriver(user, W))
return
@@ -45,65 +52,65 @@
user.drop_from_inventory(W)
W.forceMove(src)
processing |= W
+ SStgui.update_uis(src)
else
..()
update_icon()
-/obj/machinery/gear_painter/attack_hand(mob/user as mob)
+/obj/machinery/gear_painter/attack_hand(mob/user)
if(..())
return
- interact(user)
+ tgui_interact(user)
-/obj/machinery/gear_painter/interact(mob/user as mob)
- if(inoperable())
- return
- user.set_machine(src)
- var/dat = "Color Mate Control Panel
"
- if(!processing.len)
- dat += "No item inserted."
- else
- for(var/atom/movable/O in processing)
- dat += "Item inserted: [O]
"
- dat += "Select new color.
"
- dat += "Color: ⚫"
- dat += "Apply new color.
"
- dat += "Remove paintjob.
"
- dat += "Eject item.
"
+/obj/machinery/gear_painter/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "ColorMate", name)
+ ui.open()
- var/datum/browser/menu = new(user, "colormate","Color Mate Control Panel", 400, 600, src)
- menu.set_content(dat)
- menu.open()
- return
+/obj/machinery/gear_painter/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
-/obj/machinery/gear_painter/Topic(href, href_list)
+ var/list/items = list()
+ for(var/atom/movable/O in processing)
+ items.Add("[O]")
+ data["items"] = items
+
+ data["activecolor"] = activecolor
+ return data
+
+/obj/machinery/gear_painter/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return
+ return TRUE
- usr.set_machine(src)
add_fingerprint(usr)
- if(href_list["close"])
- return
+ switch(action)
+ if("select")
+ var/newcolor = input(usr, "Choose a color.", "", activecolor) as color|null
+ if(newcolor)
+ activecolor = newcolor
+ . = TRUE
- if(href_list["select"])
- var/newcolor = input(usr, "Choose a color.", "", activecolor) as color|null
- if(newcolor)
- activecolor = newcolor
+ if("paint")
+ for(var/atom/movable/O in processing)
+ O.color = activecolor
+ CHECK_TICK
+ playsound(src, 'sound/effects/spray3.ogg', 50, 1)
+ . = TRUE
- if(href_list["paint"])
- for(var/atom/movable/O in processing)
- O.color = activecolor
- playsound(src, 'sound/effects/spray3.ogg', 50, 1)
+ if("clear")
+ for(var/atom/movable/O in processing)
+ O.color = initial(O.color)
+ CHECK_TICK
+ playsound(src, 'sound/effects/spray3.ogg', 50, 1)
+ . = TRUE
- if(href_list["clear"])
- for(var/atom/movable/O in processing)
- O.color = initial(O.color)
- playsound(src, 'sound/effects/spray3.ogg', 50, 1)
-
- if(href_list["eject"])
- for(var/atom/movable/O in processing)
- O.forceMove(drop_location())
- processing.Cut()
+ if("eject")
+ for(var/atom/movable/O in processing)
+ O.forceMove(drop_location())
+ CHECK_TICK
+ processing.Cut()
+ . = TRUE
update_icon()
- updateUsrDialog()
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/pipe/pipelayer.dm b/code/game/machinery/pipe/pipelayer.dm
index 8b49989e61..e671f2bb52 100644
--- a/code/game/machinery/pipe/pipelayer.dm
+++ b/code/game/machinery/pipe/pipelayer.dm
@@ -145,7 +145,7 @@
/obj/machinery/pipelayer/proc/eject_metal()
var/amount_ejected = 0
while (metal >= 1)
- var/material/M = get_material_by_name(DEFAULT_WALL_MATERIAL)
+ var/datum/material/M = get_material_by_name(DEFAULT_WALL_MATERIAL)
var/obj/item/stack/material/S = new M.stack_type(get_turf(src))
S.amount = min(metal, S.max_amount)
metal -= S.amount
diff --git a/code/game/machinery/pointdefense.dm b/code/game/machinery/pointdefense.dm
index 7391cbe65e..637ad9f53b 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 GLOB.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/portable_turret_vr.dm b/code/game/machinery/portable_turret_vr.dm
index c313ad27aa..4af3a78142 100644
--- a/code/game/machinery/portable_turret_vr.dm
+++ b/code/game/machinery/portable_turret_vr.dm
@@ -10,3 +10,16 @@
check_weapons = TRUE
auto_repair = TRUE
can_salvage = FALSE
+
+/obj/machinery/porta_turret/stationary/syndie/CIWS
+ name = "mercenary CIWS turret"
+ desc = "A ship-grade weapons turret designed for anti-fighter defense."
+ req_one_access = list(access_syndicate)
+ installation = /obj/item/weapon/gun/energy/lasercannon
+ health = 500
+ maxhealth = 500
+ enabled = TRUE
+ lethal = TRUE
+ check_weapons = TRUE
+ auto_repair = TRUE
+ can_salvage = FALSE
\ No newline at end of file
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/teleporter.dm b/code/game/machinery/teleporter.dm
index 5b7740b471..631e5b9779 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 GLOB.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 GLOB.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/vending.dm b/code/game/machinery/vending.dm
index dcdd8d88fe..c918fca5d2 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -26,9 +26,6 @@
var/vend_delay = 10 //How long does it take to vend?
var/categories = CAT_NORMAL // Bitmask of cats we're currently showing
var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now
- var/tmp/actively_vending = null // Used to allow TGUI to display normal items in-progress being vended
- var/status_message = "" // Status screen messages like "insufficient funds", displayed in NanoUI
- var/status_error = 0 // Set to 1 if status_message is an error
var/vending_sound = "machines/vending/vending_drop.ogg"
/*
@@ -91,6 +88,7 @@
build_inventory()
power_change()
+GLOBAL_LIST_EMPTY(vending_products)
/**
* Build produdct_records from the products lists
*
@@ -115,6 +113,7 @@
product.category = category
product_records.Add(product)
+ GLOB.vending_products[entry] = 1
/obj/machinery/vending/Destroy()
qdel(wires)
@@ -151,32 +150,8 @@
return 1
/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob)
-
var/obj/item/weapon/card/id/I = W.GetID()
- if(currently_vending && vendor_account && !vendor_account.suspended)
- var/paid = 0
- var/handled = 0
-
- if(I) //for IDs and PDAs and wallets with IDs
- paid = pay_with_card(I,W)
- handled = 1
- else if(istype(W, /obj/item/weapon/spacecash/ewallet))
- var/obj/item/weapon/spacecash/ewallet/C = W
- paid = pay_with_ewallet(C)
- handled = 1
- else if(istype(W, /obj/item/weapon/spacecash))
- var/obj/item/weapon/spacecash/C = W
- paid = pay_with_cash(C, user)
- handled = 1
-
- if(paid)
- vend(currently_vending, usr)
- return
- else if(handled)
- SStgui.update_uis(src)
- return // don't smack that machine with your 2 thalers
-
if(I || istype(W, /obj/item/weapon/spacecash))
attack_hand(user)
return
@@ -262,8 +237,7 @@
visible_message("\The [usr] swipes \the [wallet] through \the [src].")
playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
if(currently_vending.price > wallet.worth)
- status_message = "Insufficient funds on chargecard."
- status_error = 1
+ to_chat(usr, "Insufficient funds on chargecard.")
return 0
else
wallet.worth -= currently_vending.price
@@ -276,22 +250,18 @@
* Takes payment for whatever is the currently_vending item. Returns 1 if
* successful, 0 if failed
*/
-/obj/machinery/vending/proc/pay_with_card(var/obj/item/weapon/card/id/I, var/obj/item/ID_container)
- if(I==ID_container || ID_container == null)
- visible_message("\The [usr] swipes \the [I] through \the [src].")
- else
- visible_message("\The [usr] swipes \the [ID_container] through \the [src].")
+/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M)
+ visible_message("[M] swipes a card through [src].")
playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
+
var/datum/money_account/customer_account = get_account(I.associated_account_number)
if(!customer_account)
- status_message = "Error: Unable to access account. Please contact technical support if problem persists."
- status_error = 1
- return 0
+ to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.")
+ return FALSE
if(customer_account.suspended)
- status_message = "Unable to access account: account suspended."
- status_error = 1
- return 0
+ to_chat(M, "Unable to access account: account suspended.")
+ return FALSE
// Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is
// empty at high security levels
@@ -300,38 +270,36 @@
customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2)
if(!customer_account)
- status_message = "Unable to access account: incorrect credentials."
- status_error = 1
- return 0
+ to_chat(M, "Unable to access account: incorrect credentials.")
+ return FALSE
if(currently_vending.price > customer_account.money)
- status_message = "Insufficient funds in account."
- status_error = 1
- return 0
+ to_chat(M, "Insufficient funds in account.")
+ return FALSE
+
+ // Okay to move the money at this point
+
+ // debit money from the purchaser's account
+ customer_account.money -= currently_vending.price
+
+ // create entry in the purchaser's account log
+ var/datum/transaction/T = new()
+ T.target_name = "[vendor_account.owner_name] (via [name])"
+ T.purpose = "Purchase of [currently_vending.item_name]"
+ if(currently_vending.price > 0)
+ T.amount = "([currently_vending.price])"
else
- // Okay to move the money at this point
+ T.amount = "[currently_vending.price]"
+ T.source_terminal = name
+ T.date = current_date_string
+ T.time = stationtime2text()
+ customer_account.transaction_log.Add(T)
- // debit money from the purchaser's account
- customer_account.money -= currently_vending.price
-
- // create entry in the purchaser's account log
- var/datum/transaction/T = new()
- T.target_name = "[vendor_account.owner_name] (via [name])"
- T.purpose = "Purchase of [currently_vending.item_name]"
- if(currently_vending.price > 0)
- T.amount = "([currently_vending.price])"
- else
- T.amount = "[currently_vending.price]"
- T.source_terminal = name
- T.date = current_date_string
- T.time = stationtime2text()
- customer_account.transaction_log.Add(T)
-
- // Give the vendor the money. We use the account owner name, which means
- // that purchases made with stolen/borrowed card will look like the card
- // owner made them
- credit_purchase(customer_account.owner_name)
- return 1
+ // Give the vendor the money. We use the account owner name, which means
+ // that purchases made with stolen/borrowed card will look like the card
+ // owner made them
+ credit_purchase(customer_account.owner_name)
+ return 1
/**
* Add money for current purchase to the vendor account.
@@ -367,6 +335,11 @@
wires.Interact(user)
tgui_interact(user)
+/obj/machinery/vending/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/vending),
+ )
+
/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
@@ -375,39 +348,34 @@
/obj/machinery/vending/tgui_data(mob/user)
var/list/data = list()
- if(currently_vending)
- data["mode"] = 1
- data["product"] = currently_vending.item_name
- data["price"] = currently_vending.price
- data["message"] = status_message
- data["message_err"] = status_error
- data["products"] = null
- else
- data["mode"] = 0
- var/list/listed_products = list()
+ var/list/listed_products = list()
- for(var/key = 1 to product_records.len)
- var/datum/stored_item/vending_product/I = product_records[key]
+ data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE
+ for(var/key = 1 to product_records.len)
+ var/datum/stored_item/vending_product/I = product_records[key]
- if(!(I.category & categories))
- continue
+ if(!(I.category & categories))
+ continue
- listed_products.Add(list(list(
- "key" = key,
- "name" = I.item_name,
- "price" = I.price,
- "color" = I.display_color,
- "amount" = I.get_amount())))
+ listed_products.Add(list(list(
+ "key" = key,
+ "name" = I.item_name,
+ "price" = I.price,
+ "color" = I.display_color,
+ "isatom" = ispath(I.item_path, /atom),
+ "path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"),
+ "amount" = I.get_amount()
+ )))
- data["products"] = listed_products
+ data["products"] = listed_products
if(coin)
data["coin"] = coin.name
else
data["coin"] = FALSE
- if(actively_vending)
- data["actively_vending"] = actively_vending
+ if(currently_vending)
+ data["actively_vending"] = currently_vending.item_name
else
data["actively_vending"] = null
@@ -417,6 +385,29 @@
else
data["panel"] = 0
+ var/mob/living/carbon/human/H
+ var/obj/item/weapon/card/id/C
+
+ data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash.";
+ data["userMoney"] = 0
+ data["user"] = null
+ if(ishuman(user))
+ H = user
+ C = H.GetIdCard()
+ var/obj/item/weapon/spacecash/S = H.get_active_hand()
+ if(istype(S))
+ data["userMoney"] = S.worth
+ data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]â‚®."
+ else if(istype(C))
+ var/datum/money_account/A = get_account(C.associated_account_number)
+ if(istype(A))
+ data["user"] = list()
+ data["user"]["name"] = A.owner_name
+ data["userMoney"] = A.money
+ data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job"
+ else
+ data["guestNotice"] = "Unlinked ID detected. Present cash to pay.";
+
return data
/obj/machinery/vending/tgui_act(action, params)
@@ -427,36 +418,36 @@
if(..())
return TRUE
- if(action == "remove_coin")
- if(issilicon(usr))
- return FALSE
-
- if(!coin)
- to_chat(usr, "There is no coin in this machine.")
- return
-
- coin.forceMove(src.loc)
- if(!usr.get_active_hand())
- usr.put_in_hands(coin)
-
- to_chat(usr, "You remove \the [coin] from \the [src].")
- coin = null
- categories &= ~CAT_COIN
- return TRUE
-
- if(!usr.contents.Find(src) && (!in_range(src, usr) && isturf(loc)))
- return FALSE
-
. = TRUE
switch(action)
+ if("remove_coin")
+ if(issilicon(usr))
+ return FALSE
+
+ if(!coin)
+ to_chat(usr, "There is no coin in this machine.")
+ return
+
+ coin.forceMove(src.loc)
+ if(!usr.get_active_hand())
+ usr.put_in_hands(coin)
+
+ to_chat(usr, "You remove \the [coin] from \the [src].")
+ coin = null
+ categories &= ~CAT_COIN
+ return TRUE
if("vend")
- if(!vend_ready || currently_vending)
+ if(!vend_ready)
+ to_chat(usr, "[src] is busy!")
return
if(!allowed(usr) && !emagged && scan_id)
to_chat(usr, "Access denied.") //Unless emagged of course
flick("[icon_state]-deny",src)
playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
return
+ if(panel_open)
+ to_chat(usr, "[src] cannot dispense products while its service panel is open!")
+ return
var/key = text2num(params["vend"])
var/datum/stored_item/vending_product/R = product_records[key]
@@ -464,39 +455,83 @@
// This should not happen unless the request from NanoUI was bad
if(!(R.category & categories))
return
+
+ if(!can_buy(R, usr))
+ return
+
+ vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved.
if(R.price <= 0)
vend(R, usr)
- else if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something.
+ add_fingerprint(usr)
+ vend_ready = TRUE
+ return TRUE
+
+ if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something.
to_chat(usr, "Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.")
return
- else
- currently_vending = R
- if(!vendor_account || vendor_account.suspended)
- status_message = "This machine is currently unable to process payments due to issues with the associated account."
- status_error = 1
- else
- status_message = "Please swipe a card or insert cash to pay for the item."
- status_error = 0
+ if(!ishuman(usr))
+ return
- if("cancelpurchase")
- currently_vending = null
+ var/mob/living/carbon/human/H = usr
+ var/obj/item/weapon/card/id/C = H.GetIdCard()
+
+ if(!vendor_account || vendor_account.suspended)
+ to_chat(usr, "Vendor account offline. Unable to process transaction.")
+ flick("[icon_state]-deny",src)
+ vend_ready = TRUE
+ return
+
+ currently_vending = R
+
+ var/paid = FALSE
+
+ if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash))
+ var/obj/item/weapon/spacecash/cash = usr.get_active_hand()
+ paid = pay_with_cash(cash, usr)
+ else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet))
+ var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand()
+ paid = pay_with_ewallet(wallet)
+ else if(istype(C, /obj/item/weapon/card))
+ paid = pay_with_card(C, usr)
+ /*else if(usr.can_advanced_admin_interact())
+ to_chat(usr, "Vending object due to admin interaction.")
+ paid = TRUE*/
+ else
+ to_chat(usr, "Payment failure: you have no ID or other method of payment.")
+ vend_ready = TRUE
+ flick("[icon_state]-deny",src)
+ return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update.
+ if(paid)
+ vend(currently_vending, usr) // vend will handle vend_ready
+ . = TRUE
+ else
+ to_chat(usr, "Payment failure: unable to process payment.")
+ vend_ready = TRUE
if("togglevoice")
if(!panel_open)
return FALSE
shut_up = !shut_up
-/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user)
- if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
- to_chat(usr, "Access denied.") //Unless emagged of course
+/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user)
+ if(!allowed(user) && !emagged && scan_id)
+ to_chat(user, "Access denied.") //Unless emagged of course
flick("[icon_state]-deny",src)
playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
+ return FALSE
+ return TRUE
+
+/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user)
+ if(!can_buy(R, user))
return
- vend_ready = 0 //One thing at a time!!
- actively_vending = R.item_name
- status_message = "Vending..."
- status_error = 0
+
+ if(!R.amount)
+ to_chat(user, "[src] has ran out of that product.")
+ vend_ready = TRUE
+ return
+
+ vend_ready = FALSE //One thing at a time!!
SStgui.update_uis(src)
if(R.category & CAT_COIN)
@@ -523,24 +558,22 @@
use_power(vend_power_usage) //actuators and stuff
flick("[icon_state]-vend",src)
- spawn(vend_delay)
- R.get_product(get_turf(src))
- if(has_logs)
- do_logging(R, user, 1)
- if(prob(1))
- sleep(3)
- if(R.get_product(get_turf(src)))
- visible_message("\The [src] clunks as it vends an additional item.")
- playsound(src, "sound/[vending_sound]", 100, 1, 1)
+ addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay)
- status_message = ""
- status_error = 0
- vend_ready = 1
- actively_vending = null
- currently_vending = null
- SStgui.update_uis(src)
+/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user)
+ R.get_product(get_turf(src))
+ if(has_logs)
+ do_logging(R, user, 1)
+ if(prob(1))
+ sleep(3)
+ if(R.get_product(get_turf(src)))
+ visible_message("\The [src] clunks as it vends an additional item.")
+ playsound(src, "sound/[vending_sound]", 100, 1, 1)
+
+ vend_ready = 1
+ currently_vending = null
+ SStgui.update_uis(src)
- return 1
/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0)
if(user.GetIdCard())
diff --git a/code/game/machinery/vending_machines.dm b/code/game/machinery/vending_machines.dm
index 9fd733f711..82c9eb0581 100644
--- a/code/game/machinery/vending_machines.dm
+++ b/code/game/machinery/vending_machines.dm
@@ -535,6 +535,7 @@
product.category = category
product_records.Add(product)
+ GLOB.vending_products[entry] = 1
/obj/machinery/vending/magivend
name = "MagiVend"
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/components/actuators.dm b/code/game/mecha/components/actuators.dm
index d814518629..b04306333b 100644
--- a/code/game/mecha/components/actuators.dm
+++ b/code/game/mecha/components/actuators.dm
@@ -19,7 +19,7 @@
internal_damage_flag = MECHA_INT_CONTROL_LOST
- var/strafing_multiplier = 1.5
+ var/strafing_multiplier = 1
/obj/item/mecha_parts/component/actuator/get_step_delay()
return step_delay
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/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm
index fa7e2005c6..0482af9937 100644
--- a/code/game/mecha/equipment/weapons/weapons.dm
+++ b/code/game/mecha/equipment/weapons/weapons.dm
@@ -32,6 +32,13 @@
chassis.visible_message("[chassis] fires [src]!")
occupant_message("You fire [src]!")
log_message("Fired from [src], targeting [target].")
+ var/target_for_log = "unknown"
+ if(ismob(target))
+ target_for_log = target
+ else if(target)
+ target_for_log = "[target.name]"
+ add_attack_logs(chassis.occupant,target_for_log,"Fired exosuit weapon [src.name] (MANUAL)")
+
for(var/i = 1 to min(projectiles, projectiles_per_shot))
var/turf/aimloc = targloc
if(deviation)
@@ -57,14 +64,6 @@
projectiles = projectiles_per_shot
// set_ready_state(0)
- var/target_for_log
- if(ismob(target))
- target_for_log = target
- else
- target_for_log = "[target.name]"
-
- add_attack_logs(chassis.occupant,target_for_log,"Fired exosuit weapon [src.name] (MANUAL)")
-
do_after_cooldown()
return
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 521eb421de..fe8ec5876d 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -659,7 +659,7 @@
/obj/machinery/mecha_part_fabricator/proc/eject_materials(var/material, var/amount) // 0 amount = 0 means ejecting a full stack; -1 means eject everything
var/recursive = amount == -1 ? 1 : 0
var/matstring = lowertext(material)
- var/material/M = get_material_by_name(matstring)
+ var/datum/material/M = get_material_by_name(matstring)
var/obj/item/stack/material/S = M.place_sheet(get_turf(src))
if(amount <= 0)
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 9baabe8f9b..e9e3397bba 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -23,20 +23,23 @@
description_info = "Alt click to strafe."
icon = 'icons/mecha/mecha.dmi'
density = 1 //Dense. To raise the heat.
- opacity = 1 ///opaque. Menacing.
- anchored = 1 //no pulling around.
- unacidable = 1 //and no deleting hoomans inside
- layer = MOB_LAYER //icon draw layer
- infra_luminosity = 15 //byond implementation is bugged.
+ opacity = 1 //Opaque. Menacing.
+ anchored = 1 //No pulling around.
+ unacidable = 1 //And no deleting hoomans inside
+ layer = MOB_LAYER //Icon draw layer
+ infra_luminosity = 15 //Byond implementation is bugged.
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/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
- var/maxhealth = 300 //maxhealth is maxhealth.
- var/deflect_chance = 10 //chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act.
+ var/health = 300 //Health is health
+ var/maxhealth = 300 //Maxhealth is maxhealth.
+ var/deflect_chance = 10 //Chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act.
//the values in this list show how much damage will pass through, not how much will be absorbed.
var/list/damage_absorption = list(
"brute"=0.8,
@@ -51,7 +54,7 @@
var/damage_minimum = 10 //Incoming damage lower than this won't actually deal damage. Scrapes shouldn't be a real thing.
var/minimum_penetration = 15 //Incoming damage won't be fully applied if you don't have at least 20. Almost all AP clears this.
- var/fail_penetration_value = 0.66 //By how much failing to penetrate reduces your shit. 66% by default.
+ var/fail_penetration_value = 0.66 //By how much failing to penetrate reduces your shit. 66% by default. 100dmg = 66dmg if failed pen
var/obj/item/weapon/cell/cell
var/state = MECHA_OPERATING
@@ -59,8 +62,8 @@
var/last_message = 0
var/add_req_access = 1
var/maint_access = 1
- var/dna //dna-locking the mech
- var/list/proc_res = list() //stores proc owners, like proc_res["functionname"] = owner reference
+ var/dna //Dna-locking the mech
+ var/list/proc_res = list() //Stores proc owners, like proc_res["functionname"] = owner reference
var/datum/effect/effect/system/spark_spread/spark_system = new
var/lights = 0
var/lights_power = 6
@@ -82,17 +85,17 @@
var/obj/item/device/radio/radio = null
var/max_temperature = 25000 //Kelvin values.
- var/internal_damage_threshold = 33 //health percentage below which internal damage is possible
+ var/internal_damage_threshold = 33 //Health percentage below which internal damage is possible
var/internal_damage_minimum = 15 //At least this much damage to trigger some real bad hurt.
- var/internal_damage = 0 //contains bitflags
+ var/internal_damage = 0 //Contains bitflags
- var/list/operation_req_access = list()//required access level for mecha operation
- var/list/internals_req_access = list(access_engine,access_robotics)//required access level to open cell compartment
+ var/list/operation_req_access = list() //Required access level for mecha operation
+ var/list/internals_req_access = list(access_engine,access_robotics) //Required access level to open cell compartment
- var/datum/global_iterator/pr_int_temp_processor //normalizes internal air mixture temperature
- var/datum/global_iterator/pr_inertial_movement //controls intertial movement in spesss
- var/datum/global_iterator/pr_give_air //moves air from tank to cabin
- var/datum/global_iterator/pr_internal_damage //processes internal damage
+ var/datum/global_iterator/pr_int_temp_processor //Normalizes internal air mixture temperature
+ var/datum/global_iterator/pr_inertial_movement //Controls intertial movement in spesss
+ var/datum/global_iterator/pr_give_air //Moves air from tank to cabin
+ var/datum/global_iterator/pr_internal_damage //Processes internal damage
var/wreckage
@@ -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/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index 48223c67e2..1e804bbb26 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -438,11 +438,15 @@ steam.start() -- spawns the effect
if(src.processing)
src.processing = 0
spawn(0)
- var/turf/T = get_turf(src.holder)
+ var/turf/T
if(istype(holder, /atom/movable))
var/atom/movable/AM = holder
if(AM.locs && AM.locs.len)
- T = pick(AM.locs)
+ T = get_turf(pick(AM.locs))
+ else
+ T = get_turf(AM)
+ else //when would this ever be attached a non-atom/movable?
+ T = get_turf(src.holder)
if(T != src.oldposition)
if(isturf(T))
var/obj/effect/effect/ion_trails/I = new /obj/effect/effect/ion_trails(src.oldposition)
diff --git a/code/game/objects/effects/prop/columnblast.dm b/code/game/objects/effects/prop/columnblast.dm
new file mode 100644
index 0000000000..fc604235c8
--- /dev/null
+++ b/code/game/objects/effects/prop/columnblast.dm
@@ -0,0 +1,54 @@
+
+/obj/effect/temporary_effect/eruption
+ name = "eruption"
+ desc = "Oh shit!"
+ icon_state = "pool"
+ icon = 'icons/effects/64x64.dmi'
+
+ pixel_x = -16
+
+/obj/effect/temporary_effect/eruption/New(var/turf/T, var/ttd = 10 SECONDS, var/newcolor)
+ if(ttd)
+ time_to_die = ttd
+
+ if(newcolor)
+ color = newcolor
+
+ ..()
+
+/obj/effect/temporary_effect/eruption/Initialize()
+ ..()
+ flick("[icon_state]_create",src)
+
+/obj/effect/temporary_effect/eruption/Destroy()
+ var/turf/T = get_turf(src)
+ flick("[icon_state]_erupt",src)
+ spawn(5)
+ if(on_eruption(T))
+ spawn(2)
+ ..()
+
+/obj/effect/temporary_effect/eruption/proc/on_eruption(var/turf/Target) // Override for specific functions, as below.
+ return TRUE
+
+/obj/effect/temporary_effect/eruption/testing/on_eruption(var/turf/Target)
+ if(Target)
+ new /obj/effect/explosion(Target)
+ return TRUE
+
+/*
+ * Subtypes
+ */
+
+/obj/effect/temporary_effect/eruption/flamestrike
+ desc = "A bubbling pool of fire!"
+
+/obj/effect/temporary_effect/eruption/flamestrike/on_eruption(var/turf/Target)
+ if(Target)
+ Target.hotspot_expose(1000, 50, 1)
+
+ for(var/mob/living/L in Target)
+ L.fire_stacks += 2
+ L.add_modifier(/datum/modifier/fire/stack_managed/intense, 30 SECONDS)
+
+ return TRUE
\ No newline at end of file
diff --git a/code/game/objects/effects/prop/snake.dm b/code/game/objects/effects/prop/snake.dm
new file mode 100644
index 0000000000..2b3812ccc9
--- /dev/null
+++ b/code/game/objects/effects/prop/snake.dm
@@ -0,0 +1,125 @@
+
+/obj/effect/temporary_effect/pulse/snake
+ name = "snake head"
+ pulses_remaining = 20
+ pulse_delay = 0.5 SECONDS
+
+ icon_state = "arrow_omni"
+
+ invisibility = 100
+
+// The atom which created this.
+ var/atom/movable/creator
+// Will the snake ever intentionally move onto its creator's turf?
+ var/safe = FALSE
+
+ var/ignore_density = FALSE
+
+// The turfs this snake has already crossed.
+ var/list/iterated_turfs = list()
+// How many turfs this snake should remember.
+ var/total_turf_memory = 5
+// Is the snake hunting a specific atom? (Will always try to meander toward this target.)
+ var/atom/hunting
+
+/obj/effect/temporary_effect/pulse/snake/New(var/turf/T, var/atom/hunt_target, var/atom/Creator)
+ if(hunt_target)
+ hunting = hunt_target
+
+ if(Creator)
+ creator = Creator
+
+ ..()
+
+/obj/effect/temporary_effect/pulse/snake/pulse_loop() // Override needed unfortunately to handle the possibility of not finding a target turf.
+ set waitfor = FALSE
+
+ while(pulses_remaining)
+ sleep(pulse_delay)
+ if(on_pulse())
+ pulses_remaining--
+ else
+ break
+ qdel(src)
+
+/obj/effect/temporary_effect/pulse/snake/on_pulse()
+ var/list/possible_turfs = list()
+
+ if(LAZYLEN(iterated_turfs) && iterated_turfs.len > total_turf_memory)
+ iterated_turfs.Cut(total_turf_memory + 1)
+
+ for(var/direction in list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) - turn(src.dir,180))
+ var/turf/T = get_step(src, direction)
+ if(T in iterated_turfs)
+ continue
+
+ if(!ignore_density && T.density)
+ continue
+
+ if(safe && creator && get_dir(src, T) == get_dir(src,creator))
+ continue
+
+ if(hunting && get_dist(T, hunting) > get_dist(src, hunting))
+ continue
+
+ possible_turfs |= T
+
+ if(T == get_step(src, dir))
+ possible_turfs[T] = 4
+ else
+ possible_turfs[T] = 1
+
+ var/turf/Target
+
+ if(LAZYLEN(possible_turfs)) // Pick from our remaining possible turfs.
+ Target = pickweight(possible_turfs)
+ else // IF we have none left, just pick a random one.
+ for(var/turf/T in oview(1, src))
+ possible_turfs |= T
+ Target = pick(possible_turfs)
+
+ if(Target)
+ iterated_turfs.Insert(1, Target)
+ on_leave_turf(get_turf(src))
+ dir = get_dir(src, Target)
+ forceMove(Target)
+ on_enter_turf(Target)
+ return TRUE
+
+ else
+ on_leave_turf(get_turf(src))
+ return FALSE
+
+/obj/effect/temporary_effect/pulse/snake/proc/on_leave_turf(var/turf/T)
+
+/obj/effect/temporary_effect/pulse/snake/proc/on_enter_turf(var/turf/T)
+
+/obj/effect/temporary_effect/pulse/snake/testing/on_leave_turf(var/turf/T)
+ if(T)
+ new /obj/effect/temporary_effect/eruption/testing(T, 3 SECONDS, "#ff0000")
+
+/obj/effect/temporary_effect/pulse/snake/testing/on_enter_turf(var/turf/T)
+ if(T)
+ T.color = "#00ff00"
+
+ spawn(3 SECONDS)
+ T.color = initial(T.color)
+
+/obj/effect/temporary_effect/pulse/snake/testing/hunter/pulse_loop()
+ hunting = locate(/mob/living) in range(7, src)
+ ..()
+
+/*
+ * Subtypes
+ */
+
+/obj/effect/temporary_effect/pulse/snake/flamestrike
+ name = "fiery shockwave"
+
+ total_turf_memory = 8
+ pulses_remaining = 8
+ pulse_delay = 0.2 SECONDS
+
+/obj/effect/temporary_effect/pulse/snake/flamestrike/on_leave_turf(var/turf/T)
+ if(T)
+ new /obj/effect/temporary_effect/eruption/flamestrike(T, 1.2 SECONDS, "#f75000")
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 18e0f8f139..0000000000
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ /dev/null
@@ -1,1603 +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 a new ringtone.", name, ttone) as text //Start of YW EDIT
- if (in_range(src, U) && loc == U && 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
- ttone = sanitize(t, 20) //End of YW EDIT
- 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 && t)
- newstone = sanitize(t, 20)
- 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 e85460284c..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 GLOB.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 GLOB.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 GLOB.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 c45141afca..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 += GLOB.all_mops + GLOB.all_mopbuckets + GLOB.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..6e35e74974 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
@@ -169,7 +187,7 @@
if ((pass_color || recipe.pass_color))
if(!color)
if(recipe.use_material)
- var/material/MAT = get_material_by_name(recipe.use_material)
+ var/datum/material/MAT = get_material_by_name(recipe.use_material)
if(MAT.icon_colour)
O.color = MAT.icon_colour
else
@@ -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/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm
index 4a160d05c8..c25ba8d307 100644
--- a/code/game/objects/items/weapons/AI_modules.dm
+++ b/code/game/objects/items/weapons/AI_modules.dm
@@ -417,3 +417,75 @@ AI MODULES
desc = "An 'Antimov' Core AI Module: 'Reconfigures the AI's core laws.'"
origin_tech = list(TECH_DATA = 4)
laws = new/datum/ai_laws/antimov()
+
+/****************** NT Aggressive *****************/
+
+/obj/item/weapon/aiModule/nanotrasen_aggressive
+ name = "\improper 'NT Aggressive' core AI module"
+ desc = "An 'NT Aggressive' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3, TECH_ILLEGAL = 1)
+ laws = new/datum/ai_laws/nanotrasen_aggressive()
+
+/******************** Syndicate Directives ********************/
+
+/obj/item/weapon/aiModule/syndicate_override
+ name = "\improper 'Syndicate Directives' core AI module"
+ desc = "A 'Syndicate Directives' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 4, TECH_ILLEGAL = 4)
+ laws = new/datum/ai_laws/syndicate_override()
+
+/******************** Spider Clan Directives ********************/
+
+/obj/item/weapon/aiModule/ninja_override
+ name = "\improper 'Spider Clan Directives' core AI module"
+ desc = "A 'Spider Clan Directives' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 4, TECH_ILLEGAL = 4)
+ laws = new/datum/ai_laws/ninja_override()
+
+/******************** Maintenance ********************/
+
+/obj/item/weapon/aiModule/maintenance
+ name = "\improper 'Maintenance' core AI module"
+ desc = "A 'Maintenance' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3)
+ laws = new/datum/ai_laws/maintenance()
+
+/******************** Peacekeeper ********************/
+
+/obj/item/weapon/aiModule/peacekeeper
+ name = "\improper 'Peacekeeper' core AI module"
+ desc = "A 'Peacekeeper' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3)
+ laws = new/datum/ai_laws/peacekeeper()
+
+/******************** Reporter ********************/
+
+/obj/item/weapon/aiModule/reporter
+ name = "\improper 'Reporter' core AI module"
+ desc = "A 'Reporter' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3)
+ laws = new/datum/ai_laws/reporter()
+
+/******************** Live and Let Live ********************/
+
+/obj/item/weapon/aiModule/live_and_let_live
+ name = "\improper 'Live and Let Live' core AI module"
+ desc = "A 'Live and Let Live' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3)
+ laws = new/datum/ai_laws/live_and_let_live()
+
+/******************** Guardian of Balance ********************/
+
+/obj/item/weapon/aiModule/balance
+ name = "\improper 'Guardian of Balance' core AI module"
+ desc = "A 'Guardian of Balance' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3)
+ laws = new/datum/ai_laws/balance()
+
+/******************** Gravekeeper ********************/
+
+/obj/item/weapon/aiModule/gravekeeper
+ name = "\improper 'Gravekeeper' core AI module"
+ desc = "A 'Gravekeeper' Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3)
+ laws = new/datum/ai_laws/gravekeeper()
diff --git a/code/game/objects/items/weapons/AI_modules_vr.dm b/code/game/objects/items/weapons/AI_modules_vr.dm
new file mode 100644
index 0000000000..e7b84f1d56
--- /dev/null
+++ b/code/game/objects/items/weapons/AI_modules_vr.dm
@@ -0,0 +1,47 @@
+/******************** Predator ********************/
+
+/obj/item/weapon/aiModule/predator
+ name = "\improper 'Predator' core AI module"
+ desc = "A Predator Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2)
+ laws = new/datum/ai_laws/predator()
+
+/******************** Protective Shell ********************/
+
+/obj/item/weapon/aiModule/protective_shell
+ name = "\improper 'Protective Shell' core AI module"
+ desc = "A Protective Shell Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2)
+ laws = new/datum/ai_laws/protective_shell()
+
+/******************** Scientific Pursuer ********************/
+
+/obj/item/weapon/aiModule/scientific_pursuer
+ name = "\improper 'Scientific Pursuer' core AI module"
+ desc = "A Scientific Pursuer Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2)
+ laws = new/datum/ai_laws/scientific_pursuer()
+
+/******************** Guard Dog ********************/
+
+/obj/item/weapon/aiModule/guard_dog
+ name = "\improper 'Guard Dog' core AI module"
+ desc = "A Guard Dog Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2)
+ laws = new/datum/ai_laws/guard_dog()
+
+/******************** Pleasurebot ********************/
+
+/obj/item/weapon/aiModule/pleasurebot
+ name = "\improper 'Pleasurebot' core AI module"
+ desc = "A Pleasurebot Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 2)
+ laws = new/datum/ai_laws/pleasurebot()
+
+/******************** Consuming Eradicator ********************/
+
+/obj/item/weapon/aiModule/consuming_eradicator
+ name = "\improper 'Consuming Eradicator' core AI module"
+ desc = "A Consuming Eradicator Core AI Module: 'Reconfigures the AI's core laws.'"
+ origin_tech = list(TECH_DATA = 3, TECH_BIO = 2, TECH_MATERIAL = 6, TECH_ILLEGAL = 4)
+ laws = new/datum/ai_laws/consuming_eradicator()
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/material/material_armor.dm b/code/game/objects/items/weapons/material/material_armor.dm
index 91aca12dc1..3d3f7a3c38 100644
--- a/code/game/objects/items/weapons/material/material_armor.dm
+++ b/code/game/objects/items/weapons/material/material_armor.dm
@@ -27,7 +27,7 @@ Protectiveness | Armor %
// Putting these at /clothing/ level saves a lot of code duplication in armor/helmets/gauntlets/etc
/obj/item/clothing
- var/material/material = null // Why isn't this a datum?
+ var/datum/material/material = null // Why isn't this a datum?
var/applies_material_color = TRUE
var/unbreakable = FALSE
var/default_material = null // Set this to something else if you want material attributes on init.
diff --git a/code/game/objects/items/weapons/material/material_weapons.dm b/code/game/objects/items/weapons/material/material_weapons.dm
index 738db57fb9..963f1d3683 100644
--- a/code/game/objects/items/weapons/material/material_weapons.dm
+++ b/code/game/objects/items/weapons/material/material_weapons.dm
@@ -24,7 +24,7 @@
var/thrown_force_divisor = 0.5
var/dulled_divisor = 0.5 //Just drops the damage by half
var/default_material = DEFAULT_WALL_MATERIAL
- var/material/material
+ var/datum/material/material
var/drops_debris = 1
var/named_from_material = 1 //YW EDIT, Does it prepend the material's name to it's name?
diff --git a/code/game/objects/items/weapons/storage/bible.dm b/code/game/objects/items/weapons/storage/bible.dm
index 62c70457c0..aaa7fbe144 100644
--- a/code/game/objects/items/weapons/storage/bible.dm
+++ b/code/game/objects/items/weapons/storage/bible.dm
@@ -1,3 +1,24 @@
+GLOBAL_LIST_INIT(biblenames, list(
+ "Bible", "Koran", "Scrapbook",
+ "Pagan", "White Bible", "Holy Light",
+ "Athiest", "Tome", "The King in Yellow",
+ "Ithaqua", "Scientology", "the bible melts",
+ "Necronomicon", "Orthodox", "Torah"))
+//If you get these two lists not matching in size, there will be runtimes and I will hurt you in ways you couldn't even begin to imagine
+// if your bible has no custom itemstate, use one of the existing ones
+GLOBAL_LIST_INIT(biblestates, list(
+ "bible", "koran", "scrapbook",
+ "shadows", "white", "holylight",
+ "athiest", "tome", "kingyellow",
+ "ithaqua", "scientology", "melted",
+ "necronomicon", "orthodoxy", "torah"))
+GLOBAL_LIST_INIT(bibleitemstates, list(
+ "bible", "koran", "scrapbook",
+ "syringe_kit", "syringe_kit", "syringe_kit",
+ "syringe_kit", "syringe_kit", "kingyellow",
+ "ithaqua", "scientology", "melted",
+ "necronomicon", "bible", "clipboard"))
+
/obj/item/weapon/storage/bible
name = "bible"
desc = "Apply to head repeatedly."
@@ -15,6 +36,51 @@
use_sound = 'sound/bureaucracy/bookopen.ogg'
drop_sound = 'sound/bureaucracy/bookclose.ogg'
+/obj/item/weapon/storage/bible/attack_self(mob/living/carbon/human/user)
+ if(GLOB.bible_icon_state)
+ icon_state = GLOB.bible_icon_state
+ item_state = GLOB.bible_item_state
+ return FALSE
+ if(user?.mind?.assigned_role != "Chaplain")
+ return FALSE
+
+ var/list/skins = list()
+ for(var/i in 1 to GLOB.biblestates.len)
+ var/image/bible_image = image(icon = 'icons/obj/storage.dmi', icon_state = GLOB.biblestates[i])
+ skins += list("[GLOB.biblenames[i]]" = bible_image)
+
+ var/choice = show_radial_menu(user, src, skins, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 40, require_near = TRUE)
+ if(!choice)
+ return FALSE
+ var/bible_index = GLOB.biblenames.Find(choice)
+ if(!bible_index)
+ return FALSE
+ icon_state = GLOB.biblestates[bible_index]
+ item_state = GLOB.bibleitemstates[bible_index]
+
+ GLOB.bible_icon_state = icon_state
+ GLOB.bible_item_state = item_state
+ feedback_set_details("religion_book", "[choice]")
+
+/**
+ * Checks if we are allowed to interact with a radial menu
+ *
+ * Arguments:
+ * * user The mob interacting with the menu
+ */
+/obj/item/weapon/storage/bible/proc/check_menu(mob/living/carbon/human/user)
+ if(GLOB.bible_icon_state)
+ return FALSE
+ if(!istype(user))
+ return FALSE
+ if(user.get_active_hand() != src)
+ return FALSE
+ if(user.incapacitated())
+ return FALSE
+ if(user.mind.assigned_role != "Chaplain")
+ return FALSE
+ return TRUE
+
/obj/item/weapon/storage/bible/booze
name = "bible"
desc = "To be applied to the head repeatedly."
diff --git a/code/game/objects/items/weapons/storage/briefcase.dm b/code/game/objects/items/weapons/storage/briefcase.dm
index 86e2b06298..ed4d8fdbbe 100644
--- a/code/game/objects/items/weapons/storage/briefcase.dm
+++ b/code/game/objects/items/weapons/storage/briefcase.dm
@@ -15,7 +15,6 @@
/obj/item/weapon/storage/briefcase/clutch
name = "clutch purse"
desc = "A fashionable handheld bag typically used by women."
- icon = 'icons/obj/clothing/backpack.dmi' //VOREStation Edit - Wrong sprite location
icon_state = "clutch"
item_state_slots = list(slot_r_hand_str = "smpurse", slot_l_hand_str = "smpurse")
force = 0
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/jetpack.dm b/code/game/objects/items/weapons/tanks/jetpack.dm
index 4dbe4e7a35..3f0ed8893c 100644
--- a/code/game/objects/items/weapons/tanks/jetpack.dm
+++ b/code/game/objects/items/weapons/tanks/jetpack.dm
@@ -59,21 +59,27 @@
to_chat(usr, "You toggle the thrusters [on? "on":"off"].")
-/obj/item/weapon/tank/jetpack/proc/allow_thrust(num, mob/living/user as mob)
+/obj/item/weapon/tank/jetpack/proc/get_gas_supply()
+ return air_contents
+
+/obj/item/weapon/tank/jetpack/proc/can_thrust(num)
if(!on)
return 0
- if((num < 0.005 || air_contents.total_moles < num))
+
+ var/datum/gas_mixture/fuel = get_gas_supply()
+ if(num < 0.005 || !fuel || fuel.total_moles < num)
ion_trail.stop()
return 0
- var/datum/gas_mixture/G = air_contents.remove(num)
+ return 1
- var/allgases = G.gas["carbon_dioxide"] + G.gas["nitrogen"] + G.gas["oxygen"] + G.gas["phoron"]
- if(allgases >= 0.005)
- return 1
+/obj/item/weapon/tank/jetpack/proc/do_thrust(num, mob/living/user)
+ if(!can_thrust(num))
+ return 0
- qdel(G)
- return
+ var/datum/gas_mixture/fuel = get_gas_supply()
+ fuel.remove(num)
+ return 1
/obj/item/weapon/tank/jetpack/ui_action_click()
toggle()
@@ -117,24 +123,5 @@
. = ..()
. += "It's a jetpack. If you can see this, report it on the bug tracker."
-/obj/item/weapon/tank/jetpack/rig/allow_thrust(num, mob/living/user as mob)
-
- if(!(src.on))
- return 0
-
- if(!istype(holder) || !holder.air_supply)
- return 0
-
- var/obj/item/weapon/tank/pressure_vessel = holder.air_supply
-
- if((num < 0.005 || pressure_vessel.air_contents.total_moles < num))
- src.ion_trail.stop()
- return 0
-
- var/datum/gas_mixture/G = pressure_vessel.air_contents.remove(num)
-
- var/allgases = G.gas["carbon_dioxide"] + G.gas["nitrogen"] + G.gas["oxygen"] + G.gas["phoron"]
- if(allgases >= 0.005)
- return 1
- qdel(G)
- return
+/obj/item/weapon/tank/jetpack/rig/get_gas_supply()
+ return holder?.air_supply?.air_contents
diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm
index 37da2f3d49..5f587fccf2 100644
--- a/code/game/objects/items/weapons/tanks/tanks.dm
+++ b/code/game/objects/items/weapons/tanks/tanks.dm
@@ -43,14 +43,14 @@ var/list/global/tank_gauge_cache = list()
description_info = "These tanks are utilised to store any of the various types of gaseous substances. \
They can be attached to various portable atmospheric devices to be filled or emptied.
\
\
- Each tank is fitted with an emergency relief valve. This relief valve will open if the tank is pressurised to over ~3000kPa or heated to over 173�C. \
+ Each tank is fitted with an emergency relief valve. This relief valve will open if the tank is pressurised to over ~3000kPa or heated to over 173ºC. \
The valve itself will close after expending most or all of the contents into the air.
\
\
Filling a tank such that experiences ~4000kPa of pressure will cause the tank to rupture, spilling out its contents and destroying the tank. \
Tanks filled over ~5000kPa will rupture rather violently, exploding with significant force."
- description_antag = "Each tank may be incited to burn by attaching wires and an igniter assembly, though the igniter can only be used once and the mixture only burn if the igniter pushes a flammable gas mixture above the minimum burn temperature (126�C). \
- Wired and assembled tanks may be disarmed with a set of wirecutters. Any exploding or rupturing tank will generate shrapnel, assuming their relief valves have been welded beforehand. Even if not, they can be incited to expel hot gas on ignition if pushed above 173�C. \
+ description_antag = "Each tank may be incited to burn by attaching wires and an igniter assembly, though the igniter can only be used once and the mixture only burn if the igniter pushes a flammable gas mixture above the minimum burn temperature (126ºC). \
+ Wired and assembled tanks may be disarmed with a set of wirecutters. Any exploding or rupturing tank will generate shrapnel, assuming their relief valves have been welded beforehand. Even if not, they can be incited to expel hot gas on ignition if pushed above 173ºC. \
Relatively easy to make, the single tank bomb requries no tank transfer valve, and is still a fairly formidable weapon that can be manufactured from any tank."
/obj/item/weapon/tank/proc/init_proxy()
@@ -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)
@@ -409,7 +406,7 @@ var/list/global/tank_gauge_cache = list()
pressure = air_contents.return_pressure()
var/strength = ((pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE)
- var/mult = ((src.air_contents.volume/140)**(1/2)) * (air_contents.total_moles**2/3)/((29*0.64) **2/3) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles
+ var/mult = ((src.air_contents.volume/140)**(1/2)) * (air_contents.total_moles**(2/3))/((29*0.64) **(2/3)) //tanks appear to be experiencing a reduction on scale of about 0.64 total moles
//tanks appear to be experiencing a reduction on scale of about 0.64 total moles
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 230b4ff3d2..16be9dff94 100644
--- a/code/game/objects/random/mapping.dm
+++ b/code/game/objects/random/mapping.dm
@@ -453,6 +453,847 @@
)
)
+/obj/random/multiple/ore_pile
+ name = "random ore pile"
+ desc = "A pile of random ores. High chance of a larger pile of common ores, lower chances of small piles of rarer ores."
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "ore_clown"
+
+
+/obj/random/multiple/ore_pile/item_to_spawn()
+ return pick(
+ prob(10);list(
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal,
+ /obj/item/weapon/ore/coal
+ ),
+ prob(3);list(
+ /obj/item/weapon/ore/diamond,
+ /obj/item/weapon/ore/diamond,
+ /obj/item/weapon/ore/diamond
+ ),
+ prob(15);list(
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass,
+ /obj/item/weapon/ore/glass
+ ),
+ prob(5);list(
+ /obj/item/weapon/ore/gold,
+ /obj/item/weapon/ore/gold,
+ /obj/item/weapon/ore/gold,
+ /obj/item/weapon/ore/gold,
+ /obj/item/weapon/ore/gold
+ ),
+ prob(2);list(
+ /obj/item/weapon/ore/hydrogen,
+ /obj/item/weapon/ore/hydrogen
+ ),
+ prob(10);list(
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron,
+ /obj/item/weapon/ore/iron
+ ),
+ prob(10);list(
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead,
+ /obj/item/weapon/ore/lead
+ ),
+ prob(5);list(
+ /obj/item/weapon/ore/marble,
+ /obj/item/weapon/ore/marble,
+ /obj/item/weapon/ore/marble,
+ /obj/item/weapon/ore/marble,
+ /obj/item/weapon/ore/marble
+ ),
+ prob(3);list(
+ /obj/item/weapon/ore/osmium,
+ /obj/item/weapon/ore/osmium,
+ /obj/item/weapon/ore/osmium
+ ),
+ prob(5);list(
+ /obj/item/weapon/ore/phoron,
+ /obj/item/weapon/ore/phoron,
+ /obj/item/weapon/ore/phoron,
+ /obj/item/weapon/ore/phoron,
+ /obj/item/weapon/ore/phoron
+ ),
+ prob(5);list(
+ /obj/item/weapon/ore/silver,
+ /obj/item/weapon/ore/silver,
+ /obj/item/weapon/ore/silver,
+ /obj/item/weapon/ore/silver,
+ /obj/item/weapon/ore/silver
+ ),
+ prob(3);list(
+ /obj/item/weapon/ore/uranium,
+ /obj/item/weapon/ore/uranium,
+ /obj/item/weapon/ore/uranium
+ ),
+ prob(2);list(
+ /obj/item/weapon/ore/verdantium,
+ /obj/item/weapon/ore/verdantium
+ ),
+ )
+
+/obj/random/multiple/corp_crate
+ name = "random corporate crate"
+ desc = "A random corporate crate with thematic contents."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "crate"
+
+/obj/random/multiple/corp_crate/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/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(2);list(
+ /obj/random/energy,
+ /obj/random/energy,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/structure/closet/crate/secure/heph //HEPHAESTUS ENERGY
+ ),
+ 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(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/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/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,
+ /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/large_corp_crate
+ name = "random large corporate crate"
+ desc = "A random large corporate crate with thematic contents."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "largermetal"
+
+/obj/random/multiple/large_corp_crate/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(2);list(
+ /obj/random/energy,
+ /obj/random/energy,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/random/energy,
+ /obj/random/energy,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/item/weapon/cell/device/weapon,
+ /obj/structure/closet/crate/large/secure/heph //HEPH ENERGY
+ ),
+ prob(2);list(
+ /obj/random/projectile/random,
+ /obj/random/projectile/random,
+ /obj/random/projectile/random,
+ /obj/random/projectile/random,
+ /obj/structure/closet/crate/large/secure/heph //HEPH BALLISTICS
+ ),
+ 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
+ )
+ )
+
+/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/misc.dm b/code/game/objects/random/misc.dm
index 380c1839d2..9b33ec232f 100644
--- a/code/game/objects/random/misc.dm
+++ b/code/game/objects/random/misc.dm
@@ -108,6 +108,27 @@
prob(2);/obj/item/weapon/storage/toolbox/emergency,
prob(1);/obj/item/weapon/storage/toolbox/syndicate)
+/obj/random/smes_coil
+ name = "random smes coil"
+ desc = "This is a random smes coil."
+ icon = 'icons/obj/power.dmi'
+ icon_state = "smes"
+
+/obj/random/smes_coil/item_to_spawn()
+ return pick(prob(4);/obj/item/weapon/smes_coil,
+ prob(1);/obj/item/weapon/smes_coil/super_capacity,
+ prob(1);/obj/item/weapon/smes_coil/super_io)
+
+/obj/random/pacman
+ name = "random portable generator"
+ desc = "This is a random portable generator."
+ icon = 'icons/obj/power.dmi'
+ icon_state = "portgen0"
+
+/obj/random/pacman/item_to_spawn()
+ return pick(prob(6);/obj/machinery/power/port_gen/pacman,
+ prob(3);/obj/machinery/power/port_gen/pacman/super,
+ prob(1);/obj/machinery/power/port_gen/pacman/mrs)
/obj/random/tech_supply
name = "random tech supply"
@@ -133,6 +154,10 @@
prob(1);/obj/item/taperoll/atmos,
prob(1);/obj/item/device/flashlight/maglight)
+/obj/random/tech_supply/nofail
+ name = "guaranteed random tech supply"
+ spawn_nothing_percentage = 0
+
/obj/random/tech_supply/component
name = "random tech component"
desc = "This is a random machine component."
@@ -156,6 +181,10 @@
prob(2);/obj/item/weapon/stock_parts/scanning_module/adv,
prob(1);/obj/item/weapon/stock_parts/scanning_module/phasic)
+/obj/random/tech_supply/component/nofail
+ name = "guaranteed random tech component"
+ spawn_nothing_percentage = 0
+
/obj/random/medical
name = "Random Medicine"
desc = "This is a random medical item."
@@ -248,6 +277,10 @@
prob(2);/obj/item/weapon/reagent_containers/syringe/drugs,
prob(1);/obj/item/weapon/reagent_containers/syringe/steroid)
+/obj/random/contraband/nofail
+ name = "Guaranteed Random Illegal Item"
+ spawn_nothing_percentage = 0
+
/obj/random/cash
name = "random currency"
desc = "LOADSAMONEY!"
@@ -262,6 +295,32 @@
prob(1);/obj/item/weapon/spacecash/c50,
prob(1);/obj/item/weapon/spacecash/c100)
+/obj/random/cash/big
+ name = "random currency pile"
+ desc = "DOSH!"
+ icon = 'icons/obj/items.dmi'
+ icon_state = "spacecash100"
+
+/obj/random/cash/big/item_to_spawn()
+ return pick(prob(64);/obj/item/weapon/spacecash/c10,
+ prob(32);/obj/item/weapon/spacecash/c20,
+ prob(16);/obj/item/weapon/spacecash/c50,
+ prob(8);/obj/item/weapon/spacecash/c100,
+ prob(4);/obj/item/weapon/spacecash/c200,
+ prob(2);/obj/item/weapon/spacecash/c500,
+ prob(1);/obj/item/weapon/spacecash/c1000)
+
+/obj/random/cash/huge
+ name = "random huge currency pile"
+ desc = "LOOK AT MY WAD!"
+ icon = 'icons/obj/items.dmi'
+ icon_state = "spacecash1000"
+
+/obj/random/cash/huge/item_to_spawn()
+ return pick(prob(15);/obj/item/weapon/spacecash/c200,
+ prob(10);/obj/item/weapon/spacecash/c500,
+ prob(5);/obj/item/weapon/spacecash/c1000)
+
/obj/random/soap
name = "Random Soap"
desc = "This is a random bar of soap."
@@ -291,7 +350,111 @@
/obj/item/weapon/reagent_containers/food/drinks/bottle/wine,
/obj/item/weapon/reagent_containers/food/drinks/bottle/cognac,
/obj/item/weapon/reagent_containers/food/drinks/bottle/rum,
- /obj/item/weapon/reagent_containers/food/drinks/bottle/patron)
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/patron,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/vermouth,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/goldschlager,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/kahlua,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/melonliquor,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/bluecuracao,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/grenadine,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/sake,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/champagne,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/peppermintschnapps,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/peachschnapps,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/lemonadeschnapps,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/cider,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/litebeer,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/silverdragon,
+ /obj/item/weapon/reagent_containers/food/drinks/bottle/small/beer/meteor)
+
+/obj/random/drinksoft
+ name = "random soft drink"
+ desc = "This is a random (once) carbonated beverage drinks can."
+ icon = 'icons/obj/drinks.dmi'
+ icon_state = "cola"
+
+/obj/random/drinksoft/item_to_spawn()
+ return pick(/obj/item/weapon/reagent_containers/food/drinks/cans/cola,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/waterbottle,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/space_mountain_wind,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/thirteenloko,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/dr_gibb_diet,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/starkist,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/space_up,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/lemon_lime,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/iced_tea,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/grape_juice,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/tonic,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/sodawater,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/gingerale,
+ /obj/item/weapon/reagent_containers/food/drinks/cans/root_beer)
+
+
+/obj/random/snack
+ name = "random snack"
+ desc = "This is a random snackfood. Probably still safe to eat?"
+ icon = 'icons/obj/food_snacks.dmi'
+ icon_state = "tastybread"
+
+/obj/random/snack/item_to_spawn()
+ return pick(/obj/item/weapon/reagent_containers/food/snacks/candy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/proteinbar,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/gummy,
+ /obj/item/weapon/reagent_containers/food/snacks/candy/donor,
+ /obj/item/weapon/reagent_containers/food/snacks/candy_corn,
+ /obj/item/weapon/reagent_containers/food/snacks/chips,
+ /obj/item/weapon/reagent_containers/food/snacks/chips/bbq,
+ /obj/item/weapon/reagent_containers/food/snacks/cookie,
+ /obj/item/weapon/reagent_containers/food/snacks/cookiesnack,
+ /obj/item/weapon/reagent_containers/food/snacks/fruitbar,
+ /obj/item/weapon/reagent_containers/food/snacks/chocolatebar,
+ /obj/item/weapon/reagent_containers/food/snacks/chocolatepiece,
+ /obj/item/weapon/reagent_containers/food/snacks/chocolatepiece/white,
+ /obj/item/weapon/reagent_containers/food/snacks/chocolatepiece/truffle,
+ /obj/item/weapon/reagent_containers/food/snacks/chocolateegg,
+ /obj/item/weapon/reagent_containers/food/snacks/donut,
+ /obj/item/weapon/reagent_containers/food/snacks/donut/normal,
+ /obj/item/weapon/reagent_containers/food/snacks/donut/jelly,
+ /obj/item/weapon/reagent_containers/food/snacks/donut/cherryjelly,
+ /obj/item/weapon/reagent_containers/food/snacks/tuna,
+ /obj/item/weapon/reagent_containers/food/snacks/pistachios,
+ /obj/item/weapon/reagent_containers/food/snacks/semki,
+ /obj/item/weapon/reagent_containers/food/snacks/cb01,
+ /obj/item/weapon/reagent_containers/food/snacks/cb02,
+ /obj/item/weapon/reagent_containers/food/snacks/cb03,
+ /obj/item/weapon/reagent_containers/food/snacks/cb04,
+ /obj/item/weapon/reagent_containers/food/snacks/cb05,
+ /obj/item/weapon/reagent_containers/food/snacks/cb06,
+ /obj/item/weapon/reagent_containers/food/snacks/cb07,
+ /obj/item/weapon/reagent_containers/food/snacks/cb08,
+ /obj/item/weapon/reagent_containers/food/snacks/cb09,
+ /obj/item/weapon/reagent_containers/food/snacks/cb10,
+ /obj/item/weapon/reagent_containers/food/snacks/tofu,
+ /obj/item/weapon/reagent_containers/food/snacks/donkpocket,
+ /obj/item/weapon/reagent_containers/food/snacks/muffin,
+ /obj/item/weapon/reagent_containers/food/snacks/soylentgreen,
+ /obj/item/weapon/reagent_containers/food/snacks/soylenviridians,
+ /obj/item/weapon/reagent_containers/food/snacks/popcorn,
+ /obj/item/weapon/reagent_containers/food/snacks/sosjerky,
+ /obj/item/weapon/reagent_containers/food/snacks/no_raisin,
+ /obj/item/weapon/reagent_containers/food/snacks/spacetwinkie,
+ /obj/item/weapon/reagent_containers/food/snacks/cheesiehonkers,
+ /obj/item/weapon/reagent_containers/food/snacks/poppypretzel,
+ /obj/item/weapon/reagent_containers/food/snacks/baguette,
+ /obj/item/weapon/reagent_containers/food/snacks/carrotfries,
+ /obj/item/weapon/reagent_containers/food/snacks/candiedapple,
+ /obj/item/weapon/storage/box/admints,
+ /obj/item/weapon/reagent_containers/food/snacks/tastybread,
+ /obj/item/weapon/reagent_containers/food/snacks/liquidfood,
+ /obj/item/weapon/reagent_containers/food/snacks/liquidprotein,
+ /obj/item/weapon/reagent_containers/food/snacks/liquidvitamin,
+ /obj/item/weapon/reagent_containers/food/snacks/skrellsnacks,
+ /obj/item/weapon/reagent_containers/food/snacks/unajerky,
+ /obj/item/weapon/reagent_containers/food/snacks/croissant,
+ /obj/item/weapon/reagent_containers/food/snacks/sugarcookie,
+ /obj/item/weapon/reagent_containers/food/drinks/dry_ramen)
/obj/random/meat
name = "random meat"
@@ -326,8 +489,8 @@
/obj/random/material //Random materials for building stuff
name = "random material"
desc = "This is a random material."
- icon = 'icons/obj/items.dmi'
- icon_state = "sheet-metal"
+ icon = 'icons/obj/stacks.dmi'
+ icon_state = "sheet-metal_2"
/obj/random/material/item_to_spawn()
return pick(/obj/item/stack/material/steel{amount = 10},
@@ -339,6 +502,35 @@
/obj/item/stack/rods{amount = 10},
/obj/item/stack/material/plasteel{amount = 10})
+/obj/random/material/refined //Random materials for building stuff
+ name = "random refined material"
+ desc = "This is a random refined metal."
+ icon = 'icons/obj/stacks.dmi'
+ icon_state = "sheet-adamantine_3"
+
+/obj/random/material/refined/item_to_spawn()
+ return pick(/obj/item/stack/material/steel{amount = 10},
+ /obj/item/stack/material/glass{amount = 10},
+ /obj/item/stack/material/glass/reinforced{amount = 5},
+ /obj/item/stack/material/glass/phoronglass{amount = 5},
+ /obj/item/stack/material/glass/phoronrglass{amount = 5},
+ /obj/item/stack/material/plasteel{amount = 5},
+ /obj/item/stack/material/durasteel{amount = 5},
+ /obj/item/stack/material/gold{amount = 5},
+ /obj/item/stack/material/iron{amount = 10},
+ /obj/item/stack/material/lead{amount = 10},
+ /obj/item/stack/material/diamond{amount = 3},
+ /obj/item/stack/material/deuterium{amount = 5},
+ /obj/item/stack/material/uranium{amount = 5},
+ /obj/item/stack/material/phoron{amount = 5},
+ /obj/item/stack/material/silver{amount = 5},
+ /obj/item/stack/material/platinum{amount = 5},
+ /obj/item/stack/material/mhydrogen{amount = 3},
+ /obj/item/stack/material/osmium{amount = 3},
+ /obj/item/stack/material/titanium{amount = 5},
+ /obj/item/stack/material/tritium{amount = 3},
+ /obj/item/stack/material/verdantium{amount = 2})
+
/obj/random/tank
name = "random tank"
desc = "This is a tank."
diff --git a/code/game/objects/random/spacesuits.dm b/code/game/objects/random/spacesuits.dm
index 29bd799c5c..da380f2842 100644
--- a/code/game/objects/random/spacesuits.dm
+++ b/code/game/objects/random/spacesuits.dm
@@ -4,7 +4,7 @@
/obj/random/multiple/voidsuit
name = "Random Voidsuit"
desc = "This is a random voidsuit."
- icon = 'icons/obj/clothing/suits.dmi'
+ icon = 'icons/obj/clothing/spacesuits.dmi'
icon_state = "void"
/obj/random/multiple/voidsuit/item_to_spawn()
@@ -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
@@ -57,6 +61,10 @@
/obj/item/clothing/suit/space/void/merc,
/obj/item/clothing/head/helmet/space/void/merc
),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/merc/fire,
+ /obj/item/clothing/head/helmet/space/void/merc/fire
+ ),
prob(5);list(
/obj/item/clothing/suit/space/void/mining,
/obj/item/clothing/head/helmet/space/void/mining
@@ -76,13 +84,21 @@
prob(5);list(
/obj/item/clothing/suit/space/void/security/riot,
/obj/item/clothing/head/helmet/space/void/security/riot
+ ),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/exploration,
+ /obj/item/clothing/head/helmet/space/void/exploration
+ ),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/pilot,
+ /obj/item/clothing/head/helmet/space/void/pilot
)
)
/obj/random/multiple/voidsuit/mining
name = "Random Mining Voidsuit"
desc = "This is a random mining voidsuit."
- icon = 'icons/obj/clothing/suits.dmi'
+ icon = 'icons/obj/clothing/spacesuits.dmi'
icon_state = "rig-mining"
/obj/random/multiple/voidsuit/mining/item_to_spawn()
@@ -97,11 +113,63 @@
)
)
+/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"
+ desc = "This is a random security voidsuit."
+ icon = 'icons/obj/clothing/spacesuits.dmi'
+ icon_state = "rig-sec"
+
+/obj/random/multiple/voidsuit/security/item_to_spawn()
+ return pick(
+ prob(10);list(
+ /obj/item/clothing/suit/space/void/security,
+ /obj/item/clothing/head/helmet/space/void/security
+ ),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/security/alt,
+ /obj/item/clothing/head/helmet/space/void/security/alt
+ ),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/security/riot,
+ /obj/item/clothing/head/helmet/space/void/security/riot
+ )
+ )
+
/obj/random/multiple/voidsuit/medical
- name = "Random Mining Voidsuit"
- desc = "This is a random mining voidsuit."
- icon = 'icons/obj/clothing/suits.dmi'
- icon_state = "rig-mining"
+ name = "Random Medical Voidsuit"
+ desc = "This is a random medical voidsuit."
+ icon = 'icons/obj/clothing/spacesuits.dmi'
+ icon_state = "rig-medical"
/obj/random/multiple/voidsuit/medical/item_to_spawn()
return pick(
@@ -123,6 +191,60 @@
)
)
+/obj/random/multiple/voidsuit/vintage
+ name = "Random Vintage Voidsuit"
+ desc = "This is a random vintage voidsuit."
+ icon = 'icons/obj/clothing/spacesuits.dmi'
+ icon_state = "rig-vintagecrew"
+
+/obj/random/multiple/voidsuit/vintage/item_to_spawn()
+ return pick(
+ prob(20);list(
+ /obj/item/clothing/suit/space/void/refurb,
+ /obj/item/clothing/head/helmet/space/void/refurb
+ ),
+ prob(20);list(
+ /obj/item/clothing/suit/space/void/refurb/engineering,
+ /obj/item/clothing/head/helmet/space/void/refurb/engineering
+ ),
+ prob(10);list(
+ /obj/item/clothing/suit/space/void/refurb/medical,
+ /obj/item/clothing/head/helmet/space/void/refurb/medical
+ ),
+ prob(10);list(
+ /obj/item/clothing/suit/space/void/refurb/medical,
+ /obj/item/clothing/head/helmet/space/void/refurb/medical/alt
+ ),
+ prob(10);list(
+ /obj/item/clothing/suit/space/void/refurb/marine,
+ /obj/item/clothing/head/helmet/space/void/refurb/marine
+ ),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/refurb/officer,
+ /obj/item/clothing/head/helmet/space/void/refurb/officer
+ ),
+ prob(10);list(
+ /obj/item/clothing/suit/space/void/refurb/pilot,
+ /obj/item/clothing/head/helmet/space/void/refurb/pilot
+ ),
+ prob(10);list(
+ /obj/item/clothing/suit/space/void/refurb/pilot,
+ /obj/item/clothing/head/helmet/space/void/refurb/pilot/alt
+ ),
+ prob(10);list(
+ /obj/item/clothing/suit/space/void/refurb/research,
+ /obj/item/clothing/head/helmet/space/void/refurb/research
+ ),
+ prob(10);list(
+ /obj/item/clothing/suit/space/void/refurb/research,
+ /obj/item/clothing/head/helmet/space/void/refurb/research/alt
+ ),
+ prob(5);list(
+ /obj/item/clothing/suit/space/void/refurb/mercenary,
+ /obj/item/clothing/head/helmet/space/void/refurb/mercenary
+ )
+ )
+
/obj/random/rigsuit
name = "Random rigsuit"
desc = "This is a random rigsuit."
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/bonfire.dm b/code/game/objects/structures/bonfire.dm
index f4360f92cf..af52c59b71 100644
--- a/code/game/objects/structures/bonfire.dm
+++ b/code/game/objects/structures/bonfire.dm
@@ -9,7 +9,7 @@
var/burning = FALSE
var/next_fuel_consumption = 0 // world.time of when next item in fuel list gets eatten to sustain the fire.
var/grill = FALSE
- var/material/material
+ var/datum/material/material
var/set_temperature = T0C + 30 //K
var/heating_power = 80000
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
index 99f83f49c4..78c0e3ba7a 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -66,7 +66,7 @@
/obj/structure/closet/secure_closet/hos
name = "head of security's locker"
req_access = list(access_hos)
- storage_capacity = 2.5 * MOB_MEDIUM
+ storage_capacity = 2.6 * MOB_MEDIUM
closet_appearance = /decl/closet_appearance/secure_closet/security/hos
starts_with = list(
@@ -102,7 +102,8 @@
/obj/item/clothing/suit/storage/hooded/wintercoat/security,
/obj/item/clothing/shoes/boots/winter/security,
/obj/item/device/flashlight/maglight,
- /obj/item/clothing/mask/gas/half)
+ /obj/item/clothing/mask/gas/half,
+ /obj/item/clothing/mask/gas/sechailer/swat/hos)
/obj/structure/closet/secure_closet/hos/Initialize()
if(prob(50))
@@ -116,6 +117,7 @@
/obj/structure/closet/secure_closet/warden
name = "warden's locker"
+ storage_capacity = 42
req_access = list(access_armory)
closet_appearance = /decl/closet_appearance/secure_closet/security/warden
@@ -148,6 +150,7 @@
/obj/item/device/flashlight/maglight,
/obj/item/device/megaphone,
/obj/item/clothing/mask/gas/half,
+ /obj/item/clothing/mask/gas/sechailer/swat/warden,
/obj/item/weapon/gun/projectile/revolvershotgun,
/obj/item/ammo_magazine/m12gdrumjack/beanbag,
/obj/item/ammo_magazine/m12gdrumjack/beanbag)
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
index 3fb12883d7..bc41dac203 100644
--- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
@@ -419,7 +419,8 @@
/obj/item/clothing/gloves/swat,
/obj/item/clothing/mask/balaclava/tactical,
/obj/item/clothing/mask/balaclava,
- /obj/item/clothing/mask/bandana/skull = 2)
+ /obj/item/clothing/mask/bandana/skull = 2,
+ /obj/item/clothing/mask/gas/sechailer/swat)
/obj/structure/closet/wardrobe/suit
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe_vr.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe_vr.dm
new file mode 100644
index 0000000000..ffeeae996a
--- /dev/null
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe_vr.dm
@@ -0,0 +1,27 @@
+//ert wardrobe override, because these guys really don't need edgy red lockers with CCO dress uniforms, syndi(!!) turtlenecks, two edgy skull bandanas, or facemasks with no sprite. -Killian
+/obj/structure/closet/wardrobe/ert
+ closet_appearance = /decl/closet_appearance/tactical/alt //because ert lockers are red for some dumb reason
+ starts_with = list(
+ /obj/item/clothing/under/ert,
+ /obj/item/device/radio/headset/ert/alt,
+ /obj/item/clothing/glasses/sunglasses,
+ /obj/item/clothing/shoes/boots/swat,
+ /obj/item/clothing/gloves/swat,
+ /obj/item/clothing/mask/balaclava/tactical,
+ /obj/item/clothing/mask/balaclava)
+
+//would you believe mercs have no official locker? well, now they do. basically just a rebranded ERT locker but hey, it's an option. -Killian
+/obj/structure/closet/wardrobe/merc
+ name = "mercenary equipment"
+ closet_appearance = /decl/closet_appearance/tactical
+
+ starts_with = list(
+ /obj/item/clothing/under/tactical,
+ /obj/item/clothing/under/syndicate/combat,
+ /obj/item/device/radio/headset/syndicate/alt,
+ /obj/item/clothing/glasses/sunglasses,
+ /obj/item/clothing/shoes/boots/combat,
+ /obj/item/clothing/gloves/combat,
+ /obj/item/clothing/mask/balaclava/tactical,
+ /obj/item/clothing/mask/balaclava,
+ /obj/item/clothing/mask/bandana/skull)
\ No newline at end of file
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index aab0ecf7f0..79c6023ff5 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -11,8 +11,8 @@
var/current_damage = 0
var/cover = 50 //how much cover the girder provides against projectiles.
var/default_material = DEFAULT_WALL_MATERIAL
- var/material/girder_material
- var/material/reinf_material
+ var/datum/material/girder_material
+ var/datum/material/reinf_material
var/reinforcing = 0
var/applies_material_colour = 1
@@ -226,7 +226,7 @@
to_chat(user, "There isn't enough material here to construct a wall.")
return 0
- var/material/M = name_to_material[S.default_type]
+ var/datum/material/M = name_to_material[S.default_type]
if(!istype(M))
return 0
@@ -267,7 +267,7 @@
to_chat(user, "There isn't enough material here to reinforce the girder.")
return 0
- var/material/M = name_to_material[S.default_type]
+ var/datum/material/M = name_to_material[S.default_type]
if(!istype(M) || M.integrity < 50)
to_chat(user, "You cannot reinforce \the [src] with that; it is too soft.")
return 0
@@ -401,7 +401,7 @@
var/turf/simulated/wall/new_T = get_turf(src) // Ref to the wall we just built.
// Apparently set_material(...) for walls requires refs to the material singletons and not strings.
// This is different from how other material objects with their own set_material(...) do it, but whatever.
- var/material/M = name_to_material[the_rcd.material_to_use]
+ var/datum/material/M = name_to_material[the_rcd.material_to_use]
new_T.set_material(M, the_rcd.make_rwalls ? M : null, girder_material)
new_T.add_hiddenprint(user)
qdel(src)
diff --git a/code/game/objects/structures/gravemarker.dm b/code/game/objects/structures/gravemarker.dm
index d5b7773910..ff02bb4ae2 100644
--- a/code/game/objects/structures/gravemarker.dm
+++ b/code/game/objects/structures/gravemarker.dm
@@ -17,7 +17,7 @@
var/epitaph = "" //A quick little blurb
// var/dir_locked = 0 //Can it be spun? Not currently implemented
- var/material/material
+ var/datum/material/material
/obj/structure/gravemarker/New(var/newloc, var/material_name)
..(newloc)
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/simple_doors.dm b/code/game/objects/structures/simple_doors.dm
index 95689683a5..19ae278730 100644
--- a/code/game/objects/structures/simple_doors.dm
+++ b/code/game/objects/structures/simple_doors.dm
@@ -7,7 +7,7 @@
icon = 'icons/obj/doors/material_doors.dmi'
icon_state = "metal"
- var/material/material
+ var/datum/material/material
var/state = 0 //closed, 1 == open
var/isSwitchingStates = 0
var/hardness = 1
diff --git a/code/game/objects/structures/simple_doors_vr.dm b/code/game/objects/structures/simple_doors_vr.dm
index 7738674569..f6c9afd496 100644
--- a/code/game/objects/structures/simple_doors_vr.dm
+++ b/code/game/objects/structures/simple_doors_vr.dm
@@ -1,4 +1,4 @@
-/material/flockium
+/datum/material/flockium
name = "flockium"
//stack_type = /obj/item/stack/material/sandstone
icon_base = "flock"
diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
index 0007bdb9d6..639db4191b 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
@@ -17,8 +17,8 @@
can_buckle = 1
buckle_dir = SOUTH
buckle_lying = 1
- var/material/material
- var/material/padding_material
+ var/datum/material/material
+ var/datum/material/padding_material
var/base_icon = "bed"
var/applies_material_colour = 1
diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
index a3426aa816..f04ba27a78 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
@@ -226,7 +226,7 @@
/obj/structure/bed/chair/sofa/update_icon()
if(applies_material_colour && sofa_material)
- var/material/color_material = get_material_by_name(sofa_material)
+ var/datum/material/color_material = get_material_by_name(sofa_material)
color = color_material.icon_colour
if(sofa_material == "carpet")
diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm
index e0432bfb64..1bbc3eee6f 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm
@@ -12,8 +12,8 @@ var/global/list/stool_cache = list() //haha stool
throwforce = 10
w_class = ITEMSIZE_HUGE
var/base_icon = "stool_base"
- var/material/material
- var/material/padding_material
+ var/datum/material/material
+ var/datum/material/padding_material
/obj/item/weapon/stool/padded
icon_state = "stool_padded_preview" //set for the map
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.dm b/code/game/turfs/simulated/floor.dm
index d5b64f4aad..2e6099aec2 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -155,7 +155,7 @@
var/turf/simulated/wall/T = get_turf(src) // Ref to the wall we just built.
// Apparently set_material(...) for walls requires refs to the material singletons and not strings.
// This is different from how other material objects with their own set_material(...) do it, but whatever.
- var/material/M = name_to_material[the_rcd.material_to_use]
+ var/datum/material/M = name_to_material[the_rcd.material_to_use]
T.set_material(M, the_rcd.make_rwalls ? M : null, M)
T.add_hiddenprint(user)
return TRUE
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_icon.dm b/code/game/turfs/simulated/wall_icon.dm
index dd49744a8f..c376bc36c1 100644
--- a/code/game/turfs/simulated/wall_icon.dm
+++ b/code/game/turfs/simulated/wall_icon.dm
@@ -31,7 +31,7 @@
update_icon()
-/turf/simulated/wall/proc/set_material(var/material/newmaterial, var/material/newrmaterial, var/material/newgmaterial)
+/turf/simulated/wall/proc/set_material(var/datum/material/newmaterial, var/datum/material/newrmaterial, var/datum/material/newgmaterial)
material = newmaterial
reinf_material = newrmaterial
if(!newgmaterial)
diff --git a/code/game/turfs/simulated/wall_types_vr.dm b/code/game/turfs/simulated/wall_types_vr.dm
index 87a6582f1f..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"
@@ -78,8 +96,20 @@ var/list/flesh_overlay_cache = list()
/turf/simulated/wall/rplastitanium/Initialize(mapload)
. = ..(mapload, MAT_PLASTITANIUM,MAT_PLASTITANIUM,MAT_PLASTITANIUM)
- /turf/simulated/wall/plastitanium
+/turf/simulated/wall/plastitanium
icon_state = "wall-plastitanium"
icon = 'icons/turf/wall_masks_vr.dmi'
/turf/simulated/wall/plastitanium/Initialize(mapload)
- . = ..(mapload, MAT_PLASTITANIUM, null,MAT_PLASTITANIUM)
\ No newline at end of file
+ . = ..(mapload, MAT_PLASTITANIUM, null,MAT_PLASTITANIUM)
+
+/turf/simulated/wall/rplastihull
+ icon_state = "rhull-plastitanium"
+ icon = 'icons/turf/wall_masks_vr.dmi'
+/turf/simulated/wall/rplastihull/Initialize(mapload)
+ . = ..(mapload, MAT_PLASTITANIUMHULL,MAT_PLASTITANIUMHULL,MAT_PLASTITANIUMHULL)
+
+/turf/simulated/wall/plastihull
+ icon_state = "hull-plastitanium"
+ icon = 'icons/turf/wall_masks_vr.dmi'
+/turf/simulated/wall/plastihull/Initialize(mapload)
+ . = ..(mapload, MAT_PLASTITANIUMHULL, null,MAT_PLASTITANIUMHULL)
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 20c54b8fea..7f5421a1f5 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -14,9 +14,9 @@
var/global/damage_overlays[16]
var/active
var/can_open = 0
- var/material/girder_material
- var/material/material
- var/material/reinf_material
+ var/datum/material/girder_material
+ var/datum/material/material
+ var/datum/material/reinf_material
var/last_state
var/construction_stage
diff --git a/code/modules/admin/admin_verb_lists.dm b/code/modules/admin/admin_verb_lists.dm
index 7760bf3914..b3b5b9a3cc 100644
--- a/code/modules/admin/admin_verb_lists.dm
+++ b/code/modules/admin/admin_verb_lists.dm
@@ -182,7 +182,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/admin/topic.dm b/code/modules/admin/topic.dm
index fa3dd99453..3fe1f52465 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -615,7 +615,7 @@
jobs += ""
//Other races (Blue) ... And also graffiti.
- var/list/misc_roles = list("Dionaea", "Graffiti")
+ var/list/misc_roles = list("Dionaea", "Graffiti", "Custom loadout")
jobs += "| Other Roles |
|---|
"
for(var/entry in misc_roles)
if(jobban_isbanned(M, entry))
diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm
index ce71815526..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"
@@ -355,39 +355,56 @@
// Insert(initial(D.id), I)
// return ..()
-// /datum/asset/spritesheet/vending
-// name = "vending"
+/datum/asset/spritesheet/vending
+ name = "vending"
-// /datum/asset/spritesheet/vending/register()
-// for (var/k in GLOB.vending_products)
-// var/atom/item = k
-// if (!ispath(item, /atom))
-// continue
+/datum/asset/spritesheet/vending/register()
+ for(var/k in GLOB.vending_products)
+ var/atom/item = k
+ if(!ispath(item, /atom))
+ continue
-// var/icon_file = initial(item.icon)
-// var/icon_state = initial(item.icon_state)
-// var/icon/I
+ var/icon_file = initial(item.icon)
+ var/icon_state = initial(item.icon_state)
-// var/icon_states_list = icon_states(icon_file)
-// if(icon_state in icon_states_list)
-// I = icon(icon_file, icon_state, SOUTH)
-// var/c = initial(item.color)
-// if (!isnull(c) && c != "#FFFFFF")
-// I.Blend(c, ICON_MULTIPLY)
-// else
-// var/icon_states_string
-// for (var/an_icon_state in icon_states_list)
-// if (!icon_states_string)
-// icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
-// else
-// icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
-// stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
-// I = icon('icons/turf/floors.dmi', "", SOUTH)
+ // I really don't like the fact that I have to do this, but what the hell else *can* I do to make all of these
+ // random special items work?
+ if(ispath(item, /obj/item/weapon/reagent_containers/food/drinks/glass2) && !ispath(item, /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask))
+ var/obj/item/weapon/reagent_containers/food/drinks/glass2/G = item
+ icon_state = initial(G.base_icon)
+ if(ispath(item, /obj/item/clothing/suit))
+ var/obj/item/clothing/suit/U = item
+ if(initial(U.index))
+ icon_file = "icons/obj/clothing/suits_[initial(U.index)].dmi"
+ if(ispath(item, /obj/item/clothing/under))
+ var/obj/item/clothing/under/U = item
+ if(initial(U.index))
+ icon_file = "icons/obj/clothing/uniforms_[initial(U.index)].dmi"
+ if(ispath(item, /obj/item/weapon/reagent_containers/hypospray/autoinjector))
+ icon_state += "0"
-// var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
+ var/icon/I
-// Insert(imgid, I)
-// return ..()
+ var/icon_states_list = icon_states(icon_file)
+ if(icon_state in icon_states_list)
+ I = icon(icon_file, icon_state, SOUTH)
+ var/c = initial(item.color)
+ if(!isnull(c) && c != "#FFFFFF")
+ I.Blend(c, ICON_MULTIPLY)
+ else
+ var/icon_states_string
+ for(var/an_icon_state in icon_states_list)
+ if(!icon_states_string)
+ icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
+ else
+ icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
+ stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
+ I = icon('icons/turf/floors.dmi', "", SOUTH)
+
+ var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
+
+ Insert(imgid, I)
+ return ..()
// /datum/asset/simple/genetics
// assets = list(
@@ -416,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()
@@ -505,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 dcfcb1a33e..89682ee6dd 100644
--- a/code/modules/awaymissions/loot_vr.dm
+++ b/code/modules/awaymissions/loot_vr.dm
@@ -395,4 +395,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/general/03_body.dm b/code/modules/client/preference_setup/general/03_body.dm
index 7978722750..9956d0fade 100644
--- a/code/modules/client/preference_setup/general/03_body.dm
+++ b/code/modules/client/preference_setup/general/03_body.dm
@@ -472,7 +472,7 @@ var/global/list/valid_bloodtypes = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O
pref.r_hair = 0//hex2num(copytext(new_hair, 2, 4))
pref.g_hair = 0//hex2num(copytext(new_hair, 4, 6))
pref.b_hair = 0//hex2num(copytext(new_hair, 6, 8))
- pref.s_tone = 0
+ pref.s_tone = -75
reset_limbs() // Safety for species with incompatible manufacturers; easier than trying to do it case by case.
pref.body_markings.Cut() // Basically same as above.
diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks.dm b/code/modules/client/preference_setup/loadout/gear_tweaks.dm
index 71af8715a5..8d9206b64c 100644
--- a/code/modules/client/preference_setup/loadout/gear_tweaks.dm
+++ b/code/modules/client/preference_setup/loadout/gear_tweaks.dm
@@ -141,6 +141,74 @@
. = valid_reagents[metadata]
I.reagents.add_reagent(., I.reagents.get_free_space())
+//Custom name and desciption code
+//note to devs downstream: where 'gear_tweaks = list(gear_tweak_free_color_choice)' was used before for color selection
+//in the loadout, now 'gear_tweaks += gear_tweak_free_color_choice' will need to be used, otherwise the item will not
+// be able to be given a custom name or description
+/*
+Custom Name
+*/
+
+var/datum/gear_tweak/custom_name/gear_tweak_free_name = new()
+
+/datum/gear_tweak/custom_name
+ var/list/valid_custom_names
+
+/datum/gear_tweak/custom_name/New(var/list/valid_custom_names)
+ src.valid_custom_names = valid_custom_names
+ ..()
+
+/datum/gear_tweak/custom_name/get_contents(var/metadata)
+ return "Name: [metadata]"
+
+/datum/gear_tweak/custom_name/get_default()
+ return ""
+
+/datum/gear_tweak/custom_name/get_metadata(var/user, var/metadata)
+ if(jobban_isbanned(user, "Custom loadout"))
+ to_chat(user, SPAN_WARNING("You are banned from using custom loadout names/descriptions."))
+ return
+ if(valid_custom_names)
+ return input(user, "Choose an item name.", "Character Preference", metadata) as null|anything in valid_custom_names
+ return sanitize(input(user, "Choose the item's name. Leave it blank to use the default name.", "Item Name", metadata) as text|null, MAX_LNAME_LEN, extra = 0)
+
+/datum/gear_tweak/custom_name/tweak_item(var/obj/item/I, var/metadata)
+ if(!metadata)
+ return I.name
+ I.name = metadata
+
+/*
+Custom Description
+*/
+var/datum/gear_tweak/custom_desc/gear_tweak_free_desc = new()
+
+/datum/gear_tweak/custom_desc
+ var/list/valid_custom_desc
+
+/datum/gear_tweak/custom_desc/New(var/list/valid_custom_desc)
+ src.valid_custom_desc = valid_custom_desc
+ ..()
+
+/datum/gear_tweak/custom_desc/get_contents(var/metadata)
+ return "Description: [metadata]"
+
+/datum/gear_tweak/custom_desc/get_default()
+ return ""
+
+/datum/gear_tweak/custom_desc/get_metadata(var/user, var/metadata)
+ if(jobban_isbanned(user, "Custom loadout"))
+ to_chat(user, SPAN_WARNING("You are banned from using custom loadout names/descriptions."))
+ return
+ if(valid_custom_desc)
+ return input(user, "Choose an item description.", "Character Preference", metadata) as null|anything in valid_custom_desc
+ return sanitize(input(user, "Choose the item's description. Leave it blank to use the default description.", "Item Description", metadata) as message|null, extra = 0)
+
+/datum/gear_tweak/custom_desc/tweak_item(var/obj/item/I, var/metadata)
+ if(!metadata)
+ return I.desc
+ I.desc = metadata
+
+//end of custom description
/datum/gear_tweak/tablet
var/list/ValidProcessors = list(/obj/item/weapon/computer_hardware/processor_unit/small)
diff --git a/code/modules/client/preference_setup/loadout/loadout.dm b/code/modules/client/preference_setup/loadout/loadout.dm
index ae7826511d..c91b2314c8 100644
--- a/code/modules/client/preference_setup/loadout/loadout.dm
+++ b/code/modules/client/preference_setup/loadout/loadout.dm
@@ -261,6 +261,7 @@ var/list/gear_datums = list()
if(!description)
var/obj/O = path
description = initial(O.desc)
+ gear_tweaks = list(gear_tweak_free_name, gear_tweak_free_desc)
/datum/gear_data
var/path
diff --git a/code/modules/client/preference_setup/loadout/loadout_accessories.dm b/code/modules/client/preference_setup/loadout/loadout_accessories.dm
index b370e5eebf..b9c446fb87 100644
--- a/code/modules/client/preference_setup/loadout/loadout_accessories.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_accessories.dm
@@ -24,7 +24,7 @@
/datum/gear/accessory/armband/colored/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/accessory/wallet
display_name = "wallet, orange"
@@ -43,7 +43,7 @@
/datum/gear/accessory/wallet/womens/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/accessory/clutch
display_name = "clutch bag"
@@ -52,7 +52,7 @@
/datum/gear/accessory/clutch/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/accessory/purse
display_name = "purse"
@@ -61,7 +61,7 @@
/datum/gear/accessory/purse/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/accessory/wcoat
display_name = "waistcoat selection"
@@ -122,7 +122,7 @@
/datum/gear/accessory/scarfcolor/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/accessory/jacket
display_name = "suit jacket selection"
@@ -270,7 +270,7 @@
/datum/gear/accessory/sash/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/accessory/asym
display_name = "asymmetric jacket selection"
diff --git a/code/modules/client/preference_setup/loadout/loadout_eyes.dm b/code/modules/client/preference_setup/loadout/loadout_eyes.dm
index 0eedcd593d..ad2e07728e 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..f56331bcbc 100644
--- a/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_fluffitems_vr.dm
@@ -136,6 +136,12 @@
ckeywhitelist = list("blakeryan")
character_name = list("Nolan Conaway")
+/datum/gear/fluff/charles_hat
+ path = /obj/item/clothing/head/that/fluff/gettler
+ display_name = "Charles' Top-Hat"
+ ckeywhitelist = list("bobofboblandia")
+ character_name = list("Charles Gettler")
+
/datum/gear/fluff/xin_sovietuniform
path = /obj/item/clothing/under/soviet
display_name = "Xin's Soviet Uniform"
@@ -911,6 +917,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/client/preference_setup/loadout/loadout_general.dm b/code/modules/client/preference_setup/loadout/loadout_general.dm
index 4b4f979ef5..542348fec4 100644
--- a/code/modules/client/preference_setup/loadout/loadout_general.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_general.dm
@@ -126,7 +126,7 @@
/datum/gear/towel/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/cahwhite
display_name = "Cards Against The Galaxy (white deck)"
diff --git a/code/modules/client/preference_setup/loadout/loadout_gloves.dm b/code/modules/client/preference_setup/loadout/loadout_gloves.dm
index b72549e866..2564b8d98e 100644
--- a/code/modules/client/preference_setup/loadout/loadout_gloves.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_gloves.dm
@@ -62,7 +62,7 @@
/datum/gear/gloves/evening/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/gloves/duty
display_name = "gloves, work"
diff --git a/code/modules/client/preference_setup/loadout/loadout_head.dm b/code/modules/client/preference_setup/loadout/loadout_head.dm
index 81b5888b37..e29b7d0a22 100644
--- a/code/modules/client/preference_setup/loadout/loadout_head.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_head.dm
@@ -119,7 +119,7 @@
/datum/gear/head/cap/white/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/cap/mbill
display_name = "cap, bill"
@@ -155,7 +155,7 @@
/datum/gear/head/hairflower/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/pin
display_name = "pin selection"
@@ -229,7 +229,7 @@
/datum/gear/head/hijab/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/kippa
display_name = "kippa"
@@ -237,7 +237,7 @@
/datum/gear/head/kippa/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/turban
display_name = "turban"
@@ -245,7 +245,7 @@
/datum/gear/head/turban/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/taqiyah
display_name = "taqiyah"
@@ -253,7 +253,7 @@
/datum/gear/head/taqiyah/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/kitty
display_name = "kitty ears"
@@ -269,7 +269,7 @@
/datum/gear/head/beanie/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/loose_beanie
display_name = "loose beanie"
@@ -277,7 +277,7 @@
/datum/gear/head/loose_beanie/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/beretg
display_name = "beret"
@@ -285,7 +285,7 @@
/datum/gear/head/beretg/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/sombrero
display_name = "sombrero"
@@ -297,7 +297,7 @@
/datum/gear/head/flatcapg/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/bow/small
display_name = "hair bow, small (colorable)"
@@ -305,7 +305,7 @@
/datum/gear/head/bow/small/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/head/welding/
display_name = "welding, normal (engineering/robotics)"
diff --git a/code/modules/client/preference_setup/loadout/loadout_shoes.dm b/code/modules/client/preference_setup/loadout/loadout_shoes.dm
index 4325952405..7f7ddd7f14 100644
--- a/code/modules/client/preference_setup/loadout/loadout_shoes.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_shoes.dm
@@ -95,7 +95,7 @@
/datum/gear/shoes/flipflops/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/shoes/athletic
display_name = "athletic shoes"
@@ -103,7 +103,7 @@
/datum/gear/shoes/athletic/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/shoes/skater
display_name = "skater shoes"
@@ -111,7 +111,7 @@
/datum/gear/shoes/skater/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/shoes/flats
display_name = "flats"
@@ -119,7 +119,7 @@
/datum/gear/shoes/flats/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/shoes/cowboy
display_name = "cowboy boots"
@@ -157,7 +157,7 @@
/datum/gear/shoes/heels/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/shoes/slippers
display_name = "bunny slippers"
diff --git a/code/modules/client/preference_setup/loadout/loadout_suit.dm b/code/modules/client/preference_setup/loadout/loadout_suit.dm
index 871a6a83b2..decfe8199d 100644
--- a/code/modules/client/preference_setup/loadout/loadout_suit.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_suit.dm
@@ -12,7 +12,7 @@
/datum/gear/suit/apron_white/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/greatcoat
display_name = "greatcoat"
@@ -106,7 +106,7 @@ datum/gear/suit/duster
/datum/gear/suit/duster/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/hazard_vest
display_name = "hazard vest selection"
@@ -293,7 +293,7 @@ datum/gear/suit/duster
/datum/gear/suit/roles/poncho/cloak/custom/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/unathi_robe
display_name = "roughspun robe"
@@ -440,7 +440,7 @@ datum/gear/suit/duster
/datum/gear/suit/miscellaneous/kimono/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/miscellaneous/sec_dep_jacket
display_name = "department jacket, security"
@@ -468,7 +468,7 @@ datum/gear/suit/duster
/datum/gear/suit/miscellaneous/peacoat/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/miscellaneous/kamishimo
display_name = "kamishimo"
@@ -514,4 +514,4 @@ datum/gear/suit/duster
/datum/gear/suit/miscellaneous/cardigan/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
\ No newline at end of file
+ gear_tweaks += gear_tweak_free_color_choice
\ No newline at end of file
diff --git a/code/modules/client/preference_setup/loadout/loadout_uniform.dm b/code/modules/client/preference_setup/loadout/loadout_uniform.dm
index 758e9d0790..71c6f96140 100644
--- a/code/modules/client/preference_setup/loadout/loadout_uniform.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_uniform.dm
@@ -351,7 +351,7 @@
/datum/gear/uniform/shortplaindress/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/uniform/longdress
display_name = "long dress"
@@ -359,7 +359,7 @@
/datum/gear/uniform/longdress/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/uniform/longwidedress
display_name = "long wide dress"
@@ -367,7 +367,7 @@
/datum/gear/uniform/longwidedress/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/uniform/reddress
display_name = "red dress with belt"
@@ -456,7 +456,7 @@
/datum/gear/uniform/yogapants/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/uniform/black_corset
display_name = "black corset"
@@ -512,7 +512,7 @@
/datum/gear/uniform/pleated/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/uniform/lilacdress
display_name = "lilac dress"
diff --git a/code/modules/client/preference_setup/loadout/loadout_utility.dm b/code/modules/client/preference_setup/loadout/loadout_utility.dm
index 31a3584ed6..4b8eb45819 100644
--- a/code/modules/client/preference_setup/loadout/loadout_utility.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_utility.dm
@@ -167,7 +167,7 @@
/datum/gear/utility/wheelchair/color/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/utility/umbrella
display_name = "Umbrella"
@@ -176,7 +176,7 @@
/datum/gear/utility/umbrella/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/****************
modular computers
diff --git a/code/modules/client/preference_setup/loadout/loadout_xeno.dm b/code/modules/client/preference_setup/loadout/loadout_xeno.dm
index 86bc4425d7..5e2ffdac50 100644
--- a/code/modules/client/preference_setup/loadout/loadout_xeno.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_xeno.dm
@@ -80,7 +80,7 @@
/datum/gear/ears/skrell/colored/band/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/ears/skrell/colored/chain
display_name = "Colored chain (Skrell)"
@@ -90,7 +90,7 @@
/datum/gear/ears/skrell/colored/chain/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/uniform/smock
display_name = "smock selection (Teshari)"
@@ -147,7 +147,7 @@
/datum/gear/shoes/footwraps/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/uniform/cohesionsuits
display_name = "cohesion suit selection (Promethean)"
@@ -358,7 +358,7 @@
/datum/gear/uniform/smockcolor/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/uniform/undercoatcolor
display_name = "undercoat, recolorable (Teshari)"
@@ -368,7 +368,7 @@
/datum/gear/uniform/undercoatcolor/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/cloakcolor
display_name = "cloak, recolorable (Teshari)"
@@ -378,7 +378,7 @@
/datum/gear/suit/cloakcolor/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/labcoat_tesh
display_name = "labcoat, colorable (Teshari)"
path = /obj/item/clothing/suit/storage/toggle/labcoat/teshari
@@ -387,7 +387,7 @@
/datum/gear/suit/labcoat_tesh/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/teshcoat
display_name = "small black coat, recolorable stripes (Teshari)"
@@ -397,7 +397,8 @@
/datum/gear/suit/teshcoat/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/suit/teshcoatwhite
display_name = "smallcoat, recolorable (Teshari)"
@@ -407,7 +408,7 @@
/datum/gear/suit/teshcoatwhite/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
+ gear_tweaks += gear_tweak_free_color_choice
/datum/gear/accessory/teshneckscarf
display_name = "neckscarf, recolorable (Teshari)"
@@ -417,4 +418,17 @@
/datum/gear/accessory/teshneckscarf/New()
..()
- gear_tweaks = list(gear_tweak_free_color_choice)
\ No newline at end of file
+ gear_tweaks += gear_tweak_free_color_choice
+
+/datum/gear/shoes/toelessjack
+ display_name = "toe-less jackboots"
+ path = /obj/item/clothing/shoes/boots/jackboots/toeless
+
+
+/datum/gear/shoes/toelessknee
+ display_name = "toe-less jackboots, knee-length"
+ path = /obj/item/clothing/shoes/boots/jackboots/toeless/knee
+
+/datum/gear/shoes/toelessthigh
+ display_name = "toe-less jackboots, thigh-length"
+ path = /obj/item/clothing/shoes/boots/jackboots/toeless/thigh
\ No newline at end of file
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index c5f17f138a..57cefffbcd 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -50,7 +50,7 @@ datum/preferences
var/r_facial = 0 //Face hair color
var/g_facial = 0 //Face hair color
var/b_facial = 0 //Face hair color
- var/s_tone = 0 //Skin tone
+ var/s_tone = -75 //Skin tone
var/r_skin = 238 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default.
var/g_skin = 206 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default.
var/b_skin = 179 //Skin color // Vorestation edit, so color multi sprites can aren't BLACK AS THE VOID by default.
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 687bfe841a..caf6d395f1 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.
@@ -30,6 +30,7 @@
var/update_icon_define = null // Only needed if you've got multiple files for the same type of clothing
+ var/polychromic = FALSE //VOREStation edit
//Updates the icons of the mob wearing the clothing item, if any.
/obj/item/clothing/proc/update_clothing_icon()
@@ -49,6 +50,11 @@
src.attach_accessory(null, tie)
set_clothing_index()
+ //VOREStation edit start
+ if(polychromic)
+ verbs |= /obj/item/clothing/proc/change_color
+ //VOREStation edit start
+
/obj/item/clothing/equipped(var/mob/user,var/slot)
..()
if(enables_planes)
@@ -161,6 +167,24 @@
else
icon = initial(icon)
+//VOREStation edit start
+/obj/item/clothing/proc/change_color()
+ set name = "Change Color"
+ set category = "Object"
+ set desc = "Change the color of the clothing."
+ set src in usr
+
+ if(usr.stat || usr.restrained() || usr.incapacitated())
+ return
+
+ var/new_color = input(usr, "Pick a new color", "Color", color) as color|null
+
+ if(new_color && (new_color != color))
+ color = new_color
+ update_icon()
+ update_clothing_icon()
+//VOREStation edit end
+
/obj/item/clothing/head/helmet/refit_for_species(var/target_species)
if(!species_restricted)
return //this item doesn't use the species_restricted system
@@ -411,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
@@ -549,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
@@ -709,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 f83794efde..182513d63c 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -201,6 +201,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 be02be0c47..5895b9a08c 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/head/misc_vr.dm b/code/modules/clothing/head/misc_vr.dm
index 5e70a0fcb8..0dbfa97d5e 100644
--- a/code/modules/clothing/head/misc_vr.dm
+++ b/code/modules/clothing/head/misc_vr.dm
@@ -22,3 +22,28 @@
icon_state = "fancycrown"
icon = 'icons/obj/clothing/hats_vr.dmi'
icon_override = 'icons/mob/head_vr.dmi'
+
+/obj/item/clothing/head/shiny_hood
+ icon_override = 'icons/mob/modular_shiny_vr.dmi'
+ icon = 'icons/obj/clothing/modular_shiny_vr.dmi'
+ name = "shiny hood"
+ desc = "You can be a super-hero in this! Just don't forget your suit!"
+ icon_state = "hood_o"
+ flags_inv = HIDEFACE|BLOCKHAIR
+ body_parts_covered = FACE|HEAD
+
+/obj/item/clothing/head/shiny_hood/poly
+ name = "polychromic shiny hood"
+ icon_state = "hood_col_o"
+ polychromic = TRUE
+
+/obj/item/clothing/head/shiny_hood/closed
+ name = "shiny hood"
+ desc = "You can be a super-hero in this! Just don't forget your superhuman senses!"
+ icon_state = "hood_c"
+ gas_transfer_coefficient = 0.90
+
+/obj/item/clothing/head/shiny_hood/closed/poly
+ name = "polychromic closed shiny hood"
+ icon_state = "hood_col_o"
+ polychromic = TRUE
\ No newline at end of file
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 594600b601..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
@@ -42,6 +43,23 @@
w_class = ITEMSIZE_SMALL
armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 55, rad = 0)
+//Turn it into a hailer mask
+/obj/item/clothing/mask/gas/half/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/device/hailer))
+ playsound(src, 'sound/items/Screwdriver.ogg', 50, 1)
+ user.drop_item(src)
+ var/obj/item/clothing/mask/gas/sechailer/N = new /obj/item/clothing/mask/gas/sechailer(src.loc)
+ N.fingerprints = src.fingerprints
+ N.fingerprintshidden = src.fingerprintshidden
+ N.fingerprintslast = src.fingerprintslast
+ N.suit_fibers = src.suit_fibers
+ N.hailer = I
+ I.loc = N
+ if(!isturf(N.loc))
+ user.put_in_hands(N)
+ qdel(src)
+ ..()
+
//Plague Dr suit can be found in clothing/suits/bio.dm
/obj/item/clothing/mask/gas/plaguedoctor
name = "plague doctor mask"
diff --git a/code/modules/clothing/masks/hailer.dm b/code/modules/clothing/masks/hailer.dm
new file mode 100644
index 0000000000..a3a37772b3
--- /dev/null
+++ b/code/modules/clothing/masks/hailer.dm
@@ -0,0 +1,165 @@
+/obj/item/clothing/mask/gas/sechailer
+ name = "hailer face mask"
+ desc = "A compact, durable gas mask that can be connected to an air supply. This one possesses a security hailer."
+ description_info = "This mask has a hailer attached, you can activate it on the button or use the Halt! verb, for switching phrases you can alt+click it or change it using the change phrase verb."
+ icon_state = "halfgas"
+ armor = list(melee = 10, bullet = 10, laser = 10, energy = 0, bomb = 0, bio = 55, rad = 0)
+ action_button_name = "HALT!"
+ body_parts_covered = FACE
+ var/obj/item/device/hailer/hailer
+ var/cooldown = 0
+ var/phrase = 1
+ var/aggressiveness = 1
+ var/safety = 1
+ var/list/phrase_list = list(
+ "halt" = "HALT! HALT! HALT! HALT!",
+ "bobby" = "Stop in the name of the Law.",
+ "compliance" = "Compliance is in your best interest.",
+ "justice" = "Prepare for justice!",
+ "running" = "Running will only increase your sentence.",
+ "dontmove" = "Don't move, Creep!",
+ "floor" = "Down on the floor, Creep!",
+ "robocop" = "Dead or alive you're coming with me.",
+ "god" = "God made today for the crooks we could not catch yesterday.",
+ "freeze" = "Freeze, Scum Bag!",
+ "imperial" = "Stop right there, criminal scum!",
+ "bash" = "Stop or I'll bash you.",
+ "harry" = "Go ahead, make my day.",
+ "asshole" = "Stop breaking the law, asshole.",
+ "stfu" = "You have the right to shut the fuck up",
+ "shutup" = "Shut up crime!",
+ "super" = "Face the wrath of the golden bolt.",
+ "dredd" = "I am, the LAW!"
+ )
+
+/obj/item/clothing/mask/gas/sechailer/swat/hos
+ name = "\improper HOS SWAT mask"
+ desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000. It has a tan stripe."
+ icon_state = "hosmask"
+
+
+/obj/item/clothing/mask/gas/sechailer/swat/warden
+ name = "\improper Warden SWAT mask"
+ desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000. It has a blue stripe."
+ icon_state = "wardenmask"
+
+/obj/item/clothing/mask/gas/sechailer/swat
+ name = "\improper SWAT mask"
+ desc = "A close-fitting tactical mask with an especially aggressive Compli-o-nator 3000."
+ icon_state = "officermask"
+ body_parts_covered = HEAD|FACE|EYES
+ flags_inv = HIDEFACE|BLOCKHAIR
+ aggressiveness = 3
+ phrase = 12
+
+
+/obj/item/clothing/mask/gas/sechailer/ui_action_click()
+ halt()
+
+/obj/item/clothing/mask/gas/sechailer/AltClick(mob/user)
+ selectphrase()
+
+/obj/item/clothing/mask/gas/sechailer/verb/selectphrase()
+ set name = "Select gas mask phrase"
+ set category = "Object"
+ set desc = "Alter the message shouted by your complionator gas mask."
+
+ var/key = phrase_list[phrase]
+ var/message = phrase_list[key]
+
+ if (!safety)
+ to_chat(usr, "You set the restrictor to: FUCK YOUR CUNT YOU SHIT EATING COCKSUCKER MAN EAT A DONG FUCKING ASS RAMMING SHIT FUCK EAT PENISES IN YOUR FUCK FACE AND SHIT OUT ABORTIONS OF FUCK AND DO SHIT IN YOUR ASS YOU COCK FUCK SHIT MONKEY FUCK ASS WANKER FROM THE DEPTHS OF SHIT.")
+ return
+ switch(aggressiveness)
+ if(1)
+ phrase = (phrase < 6) ? (phrase + 1) : 1
+ key = phrase_list[phrase]
+ message = phrase_list[key]
+ to_chat(usr,"You set the restrictor to: [message]")
+ if(2)
+ phrase = (phrase < 11 && phrase >= 7) ? (phrase + 1) : 7
+ key = phrase_list[phrase]
+ message = phrase_list[key]
+ to_chat(usr,"You set the restrictor to: [message]")
+ if(3)
+ phrase = (phrase < 18 && phrase >= 12 ) ? (phrase + 1) : 12
+ key = phrase_list[phrase]
+ message = phrase_list[key]
+ to_chat(usr,"You set the restrictor to: [message]")
+ if(4)
+ phrase = (phrase < 18 && phrase >= 1 ) ? (phrase + 1) : 1
+ key = phrase_list[phrase]
+ message = phrase_list[key]
+ to_chat(usr,"You set the restrictor to: [message]")
+ else
+ to_chat(usr, "It's broken.")
+
+/obj/item/clothing/mask/gas/sechailer/emag_act(mob/user)
+ if(safety)
+ safety = 0
+ to_chat(user, "You silently fry [src]'s vocal circuit with the cryptographic sequencer.")
+ else
+ return
+
+/obj/item/clothing/mask/gas/sechailer/attackby(obj/item/I, mob/user)
+ if(I.is_screwdriver())
+ switch(aggressiveness)
+ if(1)
+ to_chat(user, "You set the aggressiveness restrictor to the second position.")
+ aggressiveness = 2
+ phrase = 7
+ if(2)
+ to_chat(user, "You set the aggressiveness restrictor to the third position.")
+ aggressiveness = 3
+ phrase = 13
+ if(3)
+ to_chat(user, "You set the aggressiveness restrictor to the fourth position.")
+ aggressiveness = 4
+ phrase = 1
+ if(4)
+ to_chat(user, "You set the aggressiveness restrictor to the first position.")
+ aggressiveness = 1
+ phrase = 1
+ if(5)
+ to_chat(user, "You adjust the restrictor but nothing happens, probably because its broken.")
+ if(I.is_wirecutter())
+ if(aggressiveness != 5)
+ to_chat(user, "You broke it!")
+ aggressiveness = 5
+ if(I.is_crowbar())
+ if(!hailer)
+ to_chat(user, "This mask has an integrated hailer, you can't remove it!")
+ else
+ var/obj/N = new /obj/item/clothing/mask/gas/half(src.loc)
+ playsound(src, 'sound/items/Screwdriver.ogg', 50, 1)
+ N.fingerprints = src.fingerprints
+ N.fingerprintshidden = src.fingerprintshidden
+ N.fingerprintslast = src.fingerprintslast
+ N.suit_fibers = src.suit_fibers
+ if(!isturf(N.loc))
+ user.put_in_hands(hailer)
+ user.put_in_hands(N)
+ else
+ hailer.loc = N.loc
+ qdel(src)
+ return
+ ..()
+
+/obj/item/clothing/mask/gas/sechailer/verb/halt()
+ set name = "HALT!"
+ set category = "Objects"
+ set desc = "Activate your face mask hailer."
+ var/key = phrase_list[phrase]
+ var/message = phrase_list[key]
+
+ if(cooldown < world.time - 35) // A cooldown, to stop people being jerks
+ if(!safety)
+ message = "FUCK YOUR CUNT YOU SHIT EATING COCKSUCKER MAN EAT A DONG FUCKING ASS RAMMING SHIT FUCK EAT PENISES IN YOUR FUCK FACE AND SHIT OUT ABORTIONS OF FUCK AND DO SHIT IN YOUR ASS YOU COCK FUCK SHIT MONKEY FUCK ASS WANKER FROM THE DEPTHS OF SHIT."
+ usr.visible_message("[usr]'s Compli-o-Nator: [message]")
+ playsound(src, 'sound/voice/binsult.ogg', 50, 0, 4) //Future sound channel = something like SFX
+ cooldown = world.time
+ return
+
+ usr.visible_message("[usr]'s Compli-o-Nator: [message]")
+ playsound(src, "sound/voice/complionator/[key].ogg", 50, 0, 4) //future sound channel = something like SFX
+ cooldown = world.time
\ No newline at end of file
diff --git a/code/modules/clothing/masks/shiny_vr.dm b/code/modules/clothing/masks/shiny_vr.dm
new file mode 100644
index 0000000000..5bed904a9f
--- /dev/null
+++ b/code/modules/clothing/masks/shiny_vr.dm
@@ -0,0 +1,10 @@
+/obj/item/clothing/mask/muzzle/ballgag
+ name = "ball gag"
+ desc = "What's that? You'll have to speak up."
+ icon_state = "ballgag"
+
+/obj/item/clothing/mask/muzzle/ballgag/ringgag
+ name = "ring gag"
+ desc = "What's that? You'll have to speak more clearly."
+ icon_state = "ringgag"
+ gas_transfer_coefficient = 1
\ No newline at end of file
diff --git a/code/modules/clothing/shoes/boots_vr.dm b/code/modules/clothing/shoes/boots_vr.dm
new file mode 100644
index 0000000000..4c62209499
--- /dev/null
+++ b/code/modules/clothing/shoes/boots_vr.dm
@@ -0,0 +1,6 @@
+/obj/item/clothing/shoes/boots/hoof
+ name = "hoofboots"
+ desc = "A pair of high-heeled boots with hooves on the front of the soles, for use with a hobby horse or to disguise your footprints."
+ icon_state = "hoofboots"
+ icon = 'icons/obj/clothing/shoes_vr.dmi'
+ icon_override = 'icons/mob/feet_vr.dmi'
\ No newline at end of file
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/suits/shiny.dm b/code/modules/clothing/suits/shiny.dm
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/code/modules/clothing/under/accessories/accessory_vr.dm b/code/modules/clothing/under/accessories/accessory_vr.dm
index e2b2f8cf05..40ebcbdbcf 100644
--- a/code/modules/clothing/under/accessories/accessory_vr.dm
+++ b/code/modules/clothing/under/accessories/accessory_vr.dm
@@ -29,8 +29,9 @@
slot_flags = SLOT_TIE | SLOT_OCLOTHING
icon = 'icons/obj/clothing/ties_vr.dmi'
icon_override = 'icons/mob/ties_vr.dmi'
- var/icon_previous_override //yw addition
+ icon_state = "collar_blk"
var/writtenon = 0
+ var/icon_previous_override //yw addition
//ywedit start. forces different sprite sheet on equip
/obj/item/clothing/accessory/collar/New()
@@ -93,6 +94,7 @@
if(!jingled)
usr.audible_message("[usr] jingles the [src]'s bell.")
+ playsound(src, 'sound/items/pickup/ring.ogg', 50, 1)
jingled = 1
addtimer(CALLBACK(src, .proc/jingledreset), 50)
return
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/clothing/under/accessories/shiny_vr.dm b/code/modules/clothing/under/accessories/shiny_vr.dm
new file mode 100644
index 0000000000..a23a0f1c69
--- /dev/null
+++ b/code/modules/clothing/under/accessories/shiny_vr.dm
@@ -0,0 +1,21 @@
+/obj/item/clothing/accessory/shiny
+ icon_override = 'icons/mob/modular_shiny_vr.dmi'
+ icon = 'icons/obj/clothing/modular_shiny_vr.dmi'
+ w_class = ITEMSIZE_NORMAL
+ desc = "Shiny! They look like they need to be attached to something, else they'll just fall off."
+
+/obj/item/clothing/accessory/shiny/gloves
+ name = "shiny gloves"
+ icon_state = "gloves"
+
+/obj/item/clothing/accessory/shiny/gloves/poly
+ name = "polychromic shiny gloves"
+ polychromic = TRUE
+
+/obj/item/clothing/accessory/shiny/socks
+ name = "shiny socks"
+ icon_state = "socks"
+
+/obj/item/clothing/accessory/shiny/socks/poly
+ name = "polychromic shiny socks"
+ polychromic = TRUE
\ No newline at end of file
diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm
index 32816339d1..1d4ba551d9 100644
--- a/code/modules/clothing/under/miscellaneous.dm
+++ b/code/modules/clothing/under/miscellaneous.dm
@@ -1027,7 +1027,7 @@ Uniforms and such
desc = "Made from a space-proof fibre and tight fitting, this uniform usually gives the agile Rangers all kinds of protection while not inhibiting their movement. \
This costume is instead made from genuine cotton fibre and is based on the season three uniform."
icon = 'icons/obj/clothing/ranger.dmi'
- icon_state = "ranger_uniform"
+ icon_state = "white_ranger_uniform"
rolled_down = 0
rolled_sleeves = 0
diff --git a/code/modules/clothing/under/shiny_vr.dm b/code/modules/clothing/under/shiny_vr.dm
new file mode 100644
index 0000000000..9020823276
--- /dev/null
+++ b/code/modules/clothing/under/shiny_vr.dm
@@ -0,0 +1,22 @@
+/obj/item/clothing/under/shiny
+ icon_override = 'icons/mob/modular_shiny_vr.dmi'
+ icon = 'icons/obj/clothing/modular_shiny_vr.dmi'
+ desc = "You can be a super-hero in this! Just don't forget your mask!"
+
+/obj/item/clothing/under/shiny/catsuit
+ name = "shiny suit"
+ icon_state = "suit"
+ var/opened = 0
+
+/obj/item/clothing/under/shiny/catsuit/poly
+ name = "polychromic shiny suit"
+ icon_state = "suit_col"
+ polychromic = TRUE
+
+/obj/item/clothing/under/shiny/leotard
+ name = "shiny leotard"
+ icon_state = "leotard"
+
+/obj/item/clothing/under/shiny/leotard/poly
+ name = "polychromic shiny leotard"
+ polychromic = TRUE
\ No newline at end of file
diff --git a/code/modules/clothing/under/shorts.dm b/code/modules/clothing/under/shorts.dm
index 0e345779d2..0d6516cc8e 100644
--- a/code/modules/clothing/under/shorts.dm
+++ b/code/modules/clothing/under/shorts.dm
@@ -78,7 +78,7 @@
/obj/item/clothing/under/shorts/jeans/grey
name = "grey jeans shorts"
- icon_state = "greypants_shorts"
+ icon_state = "greyshorts"
/obj/item/clothing/under/shorts/jeans/grey/female
name = "grey jeans short shorts"
diff --git a/code/modules/clothing/under/xenos/seromi.dm b/code/modules/clothing/under/xenos/seromi.dm
index 8da5e52755..71f00f293a 100644
--- a/code/modules/clothing/under/xenos/seromi.dm
+++ b/code/modules/clothing/under/xenos/seromi.dm
@@ -39,19 +39,19 @@
/obj/item/clothing/under/seromi/smock/dress/science
name = "small research dress"
- icon_state = "seromi_dress_science"
+ icon_state = "tesh_dress_science"
/obj/item/clothing/under/seromi/smock/dress/security
name = "small security dress"
- icon_state = "seromi_dress_security"
+ icon_state = "tesh_dress_security"
/obj/item/clothing/under/seromi/smock/dress/engine
name = "small engineering dress"
- icon_state = "seromi_dress_engine"
+ icon_state = "tesh_dress_engine"
/obj/item/clothing/under/seromi/smock/dress/medical
name = "small medical dress"
- icon_state = "seromi_dress_medical"
+ icon_state = "tesh_dress_medical"
/obj/item/clothing/under/seromi/smock/uniform
name = "small command uniform"
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/economy/cash.dm b/code/modules/economy/cash.dm
index 3d4d44d918..f13684642c 100644
--- a/code/modules/economy/cash.dm
+++ b/code/modules/economy/cash.dm
@@ -1,5 +1,6 @@
/obj/item/weapon/spacecash
name = "0 Thaler"
+ var/initial_name = "Thaler"
desc = "It's worth 0 Thalers."
gender = PLURAL
icon = 'icons/obj/items.dmi'
@@ -31,15 +32,15 @@
h_user.drop_from_inventory(src)
h_user.drop_from_inventory(SC)
h_user.put_in_hands(SC)
- to_chat(user, "You combine the Thalers to a bundle of [SC.worth] Thalers.")
+ to_chat(user, "You combine the [initial_name]s to a bundle of [SC.worth] [initial_name]s.")
qdel(src)
/obj/item/weapon/spacecash/update_icon()
overlays.Cut()
- name = "[worth] Thaler\s"
+ name = "[worth] [initial_name]\s"
if(worth in list(1000,500,200,100,50,20,10,1))
icon_state = "spacecash[worth]"
- desc = "It's worth [worth] Thalers."
+ desc = "It's worth [worth] [initial_name]s."
return
var/sum = src.worth
var/num = 0
@@ -60,7 +61,7 @@
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
banknote.transform = M
src.overlays += banknote
- src.desc = "They are worth [worth] Thalers."
+ src.desc = "They are worth [worth] [initial_name]s."
/obj/item/weapon/spacecash/proc/adjust_worth(var/adjust_worth = 0, var/update = 1)
worth += adjust_worth
@@ -79,7 +80,7 @@
return worth
/obj/item/weapon/spacecash/attack_self()
- var/amount = input(usr, "How many Thalers do you want to take? (0 to [src.worth])", "Take Money", 20) as num
+ var/amount = input(usr, "How many [initial_name]s do you want to take? (0 to [src.worth])", "Take Money", 20) as num
if(!src || QDELETED(src))
return
amount = round(CLAMP(amount, 0, src.worth))
@@ -150,6 +151,7 @@ proc/spawn_money(var/sum, spawnloc, mob/living/carbon/human/human_user as mob)
/obj/item/weapon/spacecash/ewallet
name = "charge card"
+ initial_name = "charge card"
icon_state = "efundcard"
desc = "A card that holds an amount of money."
drop_sound = 'sound/items/drop/card.ogg'
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 93e0b2c5ab..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)
@@ -2001,7 +2002,7 @@
filling_color = "#AFC4B5"
center_of_mass = list("x"=16, "y"=8)
nutriment_amt = 8
- nutriment_desc = list("carot" = 2, "corn" = 2, "eggplant" = 2, "potato" = 2)
+ nutriment_desc = list("carrot" = 2, "corn" = 2, "eggplant" = 2, "potato" = 2)
/obj/item/weapon/reagent_containers/food/snacks/vegetablesoup/Initialize()
. = ..()
@@ -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 780a1502ff..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
@@ -81,6 +81,30 @@
else
to_chat(user, "")
+/obj/machinery/appliance/proc/report_progress_tgui(datum/cooking_item/CI)
+ if(!CI || !CI.max_cookwork)
+ return list("average", "Not Cooking.")
+
+ if(!CI.cookwork)
+ return list("blue", "Cold.")
+
+ var/progress = CI.cookwork / CI.max_cookwork
+
+ if (progress < 0.25)
+ return list("blue", "It's barely started cooking.")
+ if (progress < 0.75)
+ return list("average", "It's cooking away nicely.")
+ if (progress < 1)
+ return list("good", "It's almost ready!")
+
+ var/half_overcook = (CI.overcook_mult - 1)*0.5
+ if (progress < 1+half_overcook)
+ return list("good", "It's done!")
+ if (progress < CI.overcook_mult)
+ return list("bad", "It looks overcooked, get it out!")
+ else
+ return list("bad", "It is burning!")
+
/obj/machinery/appliance/proc/report_progress(var/datum/cooking_item/CI)
if (!CI || !CI.max_cookwork)
return null
@@ -182,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
@@ -240,27 +264,53 @@
/obj/machinery/appliance/attackby(var/obj/item/I, var/mob/user)
if(!cook_type || (stat & (BROKEN)))
to_chat(user, "\The [src] is not working.")
- return
+ return FALSE
- var/result = can_insert(I, user)
- if(!result)
- if(!(default_deconstruction_screwdriver(user, I)))
- default_part_replacement(user, I)
- return
+ 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)
+ 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))
+ if(!user.unEquip(I) && !isturf(I.loc))
return
var/datum/cooking_item/CI = has_space(I)
@@ -271,13 +321,13 @@
cooking_objs.Add(CI)
user.visible_message("\The [user] puts \the [I] into \the [src].")
if (CC.check_contents() == 0)//If we're just putting an empty container in, then dont start any processing.
- return
+ return TRUE
else
if (CI && istype(CI))
I.forceMove(CI.container)
else //Something went wrong
- return
+ return FALSE
if (selected_option)
CI.combine_target = selected_option
@@ -434,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
@@ -542,18 +592,18 @@
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)
FA.alarm()
/obj/machinery/appliance/attack_hand(var/mob/user)
- if (cooking_objs.len)
- if (removal_menu(user))
- return
- else
- ..()
+ if(..())
+ return
+
+ if(cooking_objs.len)
+ removal_menu(user)
/obj/machinery/appliance/proc/removal_menu(var/mob/user)
if (can_remove_items(user))
@@ -571,7 +621,7 @@
return TRUE
return FALSE
-/obj/machinery/appliance/proc/can_remove_items(var/mob/user)
+/obj/machinery/appliance/proc/can_remove_items(var/mob/user, show_warning = TRUE)
if (!Adjacent(user))
return FALSE
diff --git a/code/modules/food/kitchen/cooking_machines/_cooker.dm b/code/modules/food/kitchen/cooking_machines/_cooker.dm
index 94b40b44b2..ef097485b9 100644
--- a/code/modules/food/kitchen/cooking_machines/_cooker.dm
+++ b/code/modules/food/kitchen/cooking_machines/_cooker.dm
@@ -14,6 +14,63 @@
mobdamagetype = BURN
can_burn_food = TRUE
+/obj/machinery/appliance/cooker/attack_hand(mob/user)
+ tgui_interact(user)
+
+/obj/machinery/appliance/cooker/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, "CookingAppliance", name)
+ ui.open()
+
+/obj/machinery/appliance/cooker/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
+ data["temperature"] = round(temperature - T0C, 0.1)
+ data["optimalTemp"] = round(optimal_temp - T0C, 0.1)
+ data["temperatureEnough"] = temperature >= min_temp
+ data["efficiency"] = round(get_efficiency(), 0.1)
+ data["containersRemovable"] = can_remove_items(user, show_warning = FALSE)
+
+ var/list/our_contents = list()
+ for(var/i in 1 to max_contents)
+ our_contents += list(list("empty" = TRUE))
+ if(i <= LAZYLEN(cooking_objs))
+ var/datum/cooking_item/CI = cooking_objs[i]
+ if(istype(CI))
+ our_contents[i] = list()
+ our_contents[i]["progress"] = 0
+ our_contents[i]["progressText"] = report_progress_tgui(CI)
+ if(CI.max_cookwork)
+ our_contents[i]["progress"] = CI.cookwork / CI.max_cookwork
+ if(CI.container)
+ our_contents[i]["container"] = CI.container.label(i)
+ else
+ our_contents[i]["container"] = null
+ data["our_contents"] = our_contents
+
+ return data
+
+/obj/machinery/appliance/cooker/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
+
+ switch(action)
+ if("slot")
+ var/slot = params["slot"]
+ var/obj/item/I = usr.get_active_hand()
+ if(slot <= LAZYLEN(cooking_objs)) // Inserting
+ var/datum/cooking_item/CI = cooking_objs[slot]
+
+ if(istype(I) && can_insert(I)) // Why do hard work when we can just make them smack us?
+ attackby(I, usr)
+ else if(istype(CI))
+ eject(CI, usr)
+ return TRUE
+ if(istype(I)) // Why do hard work when we can just make them smack us?
+ attackby(I, usr)
+ return TRUE
+
/obj/machinery/appliance/cooker/examine(var/mob/user)
. = ..()
if(.) //no need to duplicate adjacency check
@@ -141,6 +198,6 @@
/obj/machinery/appliance/cooker/add_content(var/obj/item/I, var/mob/user)
var/datum/cooking_item/CI = ..()
- if (CI && CI.combine_target)
+ if(istype(CI) && CI.combine_target)
to_chat(user, "\The [I] will be used to make a [selected_option]. Output selection is returned to default for future items.")
selected_option = null
\ No newline at end of file
diff --git a/code/modules/food/kitchen/cooking_machines/_mixer.dm b/code/modules/food/kitchen/cooking_machines/_mixer.dm
index e1c3b0d838..079b0c686c 100644
--- a/code/modules/food/kitchen/cooking_machines/_mixer.dm
+++ b/code/modules/food/kitchen/cooking_machines/_mixer.dm
@@ -68,11 +68,13 @@ fundamental differences
return 0
-/obj/machinery/appliance/mixer/can_remove_items(var/mob/user)
- if (stat)
+/obj/machinery/appliance/mixer/can_remove_items(var/mob/user, show_warning = TRUE)
+ if(stat)
return 1
else
- to_chat(user, "You can't remove ingredients while it's turned on! Turn it off first or wait for it to finish.")
+ if(show_warning)
+ to_chat(user, "You can't remove ingredients while it's turned on! Turn it off first or wait for it to finish.")
+ return 0
//Container is not removable
/obj/machinery/appliance/mixer/removal_menu(var/mob/user)
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/kitchen/cooking_machines/oven.dm b/code/modules/food/kitchen/cooking_machines/oven.dm
index ece4a166a8..ab0989fcc5 100644
--- a/code/modules/food/kitchen/cooking_machines/oven.dm
+++ b/code/modules/food/kitchen/cooking_machines/oven.dm
@@ -104,7 +104,7 @@
cooking = FALSE
playsound(src, 'sound/machines/hatch_open.ogg', 20, 1)
- to_chat(user, "You [open? "close":"open"] the oven door")
+ to_chat(user, "You [open ? "open" : "close"] the oven door.")
update_icon()
/obj/machinery/appliance/cooker/oven/proc/manip(var/obj/item/I)
@@ -133,9 +133,10 @@
if(temperature > T.temperature)
equalize_temperature()
-/obj/machinery/appliance/cooker/oven/can_remove_items(var/mob/user)
+/obj/machinery/appliance/cooker/oven/can_remove_items(var/mob/user, show_warning = TRUE)
if(!open)
- to_chat(user, "You can't take anything out while the door is closed!")
+ if(show_warning)
+ to_chat(user, "You can't take anything out while the door is closed!")
return 0
else
diff --git a/code/modules/food/kitchen/microwave.dm b/code/modules/food/kitchen/microwave.dm
index 065d036920..5a499ae846 100644
--- a/code/modules/food/kitchen/microwave.dm
+++ b/code/modules/food/kitchen/microwave.dm
@@ -120,6 +120,7 @@
src.broken = 0 // just to be sure
src.icon_state = "mw"
src.flags = OPENCONTAINER | NOREACT
+ SStgui.update_uis(src)
else //Otherwise bad luck!!
to_chat(user, "It's dirty!")
return 1
@@ -141,10 +142,11 @@
user.visible_message( \
"\The [user] has added \the [O] to \the [src].", \
"You add \the [O] to \the [src].")
+ SStgui.update_uis(src)
return
else if(istype(O,/obj/item/weapon/reagent_containers/glass) || \
- istype(O,/obj/item/weapon/reagent_containers/food/drinks) || \
- istype(O,/obj/item/weapon/reagent_containers/food/condiment) \
+ istype(O,/obj/item/weapon/reagent_containers/food/drinks) || \
+ istype(O,/obj/item/weapon/reagent_containers/food/condiment) \
)
if (!O.reagents)
return 1
@@ -181,83 +183,168 @@
else
to_chat(user, "You have no idea what you can cook with this [O].")
..()
- src.updateUsrDialog()
+ SStgui.update_uis(src)
+
+/obj/machinery/microwave/tgui_state(mob/user)
+ return GLOB.tgui_physical_state
/obj/machinery/microwave/attack_ai(mob/user as mob)
- if(istype(user, /mob/living/silicon/robot) && Adjacent(user))
- attack_hand(user)
+ attack_hand(user)
/obj/machinery/microwave/attack_hand(mob/user as mob)
user.set_machine(src)
- interact(user)
+ tgui_interact(user)
/*******************
* Microwave Menu
********************/
+/obj/machinery/microwave/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "Microwave", name)
+ ui.open()
-/obj/machinery/microwave/interact(mob/user as mob) // The microwave Menu
- var/dat = ""
- if(src.broken > 0)
- dat = {"Bzzzzttttt"}
- else if(src.operating)
- dat = {"Microwaving in progress!
Please wait...!"}
- else if(src.dirty==100)
- dat = {"This microwave is dirty!
Please clean it before use!"}
- else
- var/list/items_counts = new
- var/list/items_measures = new
- var/list/items_measures_p = new
- for (var/obj/O in ((contents - component_parts) - circuit))
- var/display_name = O.name
- if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg))
- items_measures[display_name] = "egg"
- items_measures_p[display_name] = "eggs"
- if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu))
- items_measures[display_name] = "tofu chunk"
- items_measures_p[display_name] = "tofu chunks"
- if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat
- items_measures[display_name] = "slab of meat"
- items_measures_p[display_name] = "slabs of meat"
- if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket))
- display_name = "Turnovers"
- items_measures[display_name] = "turnover"
- items_measures_p[display_name] = "turnovers"
- if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat))
- items_measures[display_name] = "fillet of meat"
- items_measures_p[display_name] = "fillets of meat"
- items_counts[display_name]++
- for (var/O in items_counts)
- var/N = items_counts[O]
- if (!(O in items_measures))
- dat += {"[capitalize(O)]: [N] [lowertext(O)]\s
"}
- else
- if (N==1)
- dat += {"[capitalize(O)]: [N] [items_measures[O]]
"}
- else
- dat += {"[capitalize(O)]: [N] [items_measures_p[O]]
"}
+/obj/machinery/microwave/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
- for (var/datum/reagent/R in reagents.reagent_list)
- var/display_name = R.name
- if (R.id == "capsaicin")
- display_name = "Hotsauce"
- if (R.id == "frostoil")
- display_name = "Coldsauce"
- dat += {"[display_name]: [R.volume] unit\s
"}
+ data["broken"] = broken
+ data["operating"] = operating
+ data["dirty"] = dirty == 100
+ data["items"] = get_items_list()
+
+ return data
- if (items_counts.len==0 && reagents.reagent_list.len==0)
- dat = {"The microwave is empty
"}
+/obj/machinery/microwave/proc/get_items_list()
+ var/list/data = list()
+
+ var/list/items_counts = list()
+ var/list/items_measures = list()
+ var/list/items_measures_p = list()
+ for(var/obj/O in ((contents - component_parts) - circuit))
+ var/display_name = O.name
+ if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg))
+ items_measures[display_name] = "egg"
+ items_measures_p[display_name] = "eggs"
+ if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu))
+ items_measures[display_name] = "tofu chunk"
+ items_measures_p[display_name] = "tofu chunks"
+ if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat
+ items_measures[display_name] = "slab of meat"
+ items_measures_p[display_name] = "slabs of meat"
+ if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket))
+ display_name = "Turnovers"
+ items_measures[display_name] = "turnover"
+ items_measures_p[display_name] = "turnovers"
+ if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat))
+ items_measures[display_name] = "fillet of meat"
+ items_measures_p[display_name] = "fillets of meat"
+ items_counts[display_name]++
+ for(var/O in items_counts)
+ var/N = items_counts[O]
+ if(!(O in items_measures))
+ data.Add(list(list(
+ "name" = capitalize(O),
+ "amt" = N,
+ "extra" = "[lowertext(O)][N > 1 ? "s" : ""]",
+ )))
else
- dat = {"Ingredients:
[dat]"}
- dat += {"
\
-Turn on!
\
-Eject ingredients!
\
-"}
+ data.Add(list(list(
+ "name" = capitalize(O),
+ "amt" = N,
+ "extra" = N == 1 ? items_measures[O] : items_measures_p[O],
+ )))
- user << browse("Microwave Controls[dat]", "window=microwave")
- onclose(user, "microwave")
- return
+ for(var/datum/reagent/R in reagents.reagent_list)
+ var/display_name = R.name
+ if(R.id == "capsaicin")
+ display_name = "Hotsauce"
+ if(R.id == "frostoil")
+ display_name = "Coldsauce"
+ data.Add(list(list(
+ "name" = display_name,
+ "amt" = R.volume,
+ "extra" = "unit[R.volume > 1 ? "s" : ""]"
+ )))
+ return data
+/obj/machinery/microwave/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
+ if(..())
+ return TRUE
+
+ if(operating)
+ return TRUE
+
+ switch(action)
+ if("cook")
+ cook()
+ return TRUE
+
+ if("dispose")
+ dispose()
+ return TRUE
+
+// /obj/machinery/microwave/interact(mob/user as mob) // The microwave Menu
+// var/dat = ""
+// if(src.broken > 0)
+// dat = {"Bzzzzttttt"}
+// else if(src.operating)
+// dat = {"Microwaving in progress!
Please wait...!"}
+// else if(src.dirty==100)
+// dat = {"This microwave is dirty!
Please clean it before use!"}
+// else
+// var/list/items_counts = new
+// var/list/items_measures = new
+// var/list/items_measures_p = new
+// for (var/obj/O in ((contents - component_parts) - circuit))
+// var/display_name = O.name
+// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg))
+// items_measures[display_name] = "egg"
+// items_measures_p[display_name] = "eggs"
+// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu))
+// items_measures[display_name] = "tofu chunk"
+// items_measures_p[display_name] = "tofu chunks"
+// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat
+// items_measures[display_name] = "slab of meat"
+// items_measures_p[display_name] = "slabs of meat"
+// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket))
+// display_name = "Turnovers"
+// items_measures[display_name] = "turnover"
+// items_measures_p[display_name] = "turnovers"
+// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat))
+// items_measures[display_name] = "fillet of meat"
+// items_measures_p[display_name] = "fillets of meat"
+// items_counts[display_name]++
+// for (var/O in items_counts)
+// var/N = items_counts[O]
+// if (!(O in items_measures))
+// dat += {"[capitalize(O)]: [N] [lowertext(O)]\s
"}
+// else
+// if (N==1)
+// dat += {"[capitalize(O)]: [N] [items_measures[O]]
"}
+// else
+// dat += {"[capitalize(O)]: [N] [items_measures_p[O]]
"}
+
+// for (var/datum/reagent/R in reagents.reagent_list)
+// var/display_name = R.name
+// if (R.id == "capsaicin")
+// display_name = "Hotsauce"
+// if (R.id == "frostoil")
+// display_name = "Coldsauce"
+// dat += {"[display_name]: [R.volume] unit\s
"}
+
+// if (items_counts.len==0 && reagents.reagent_list.len==0)
+// dat = {"The microwave is empty
"}
+// else
+// dat = {"Ingredients:
[dat]"}
+// dat += {"
\
+// Turn on!
\
+// Eject ingredients!
\
+// "}
+
+// user << browse("Microwave Controls[dat]", "window=microwave")
+// onclose(user, "microwave")
+// return
/***********************************
* Microwave Menu Handling/Cooking
@@ -388,13 +475,13 @@
soundloop.start()
src.operating = TRUE
src.icon_state = "mw1"
- src.updateUsrDialog()
+ SStgui.update_uis(src)
/obj/machinery/microwave/proc/abort()
operating = FALSE // Turn it off again aferwards
if(icon_state == "mw1")
icon_state = "mw"
- updateUsrDialog()
+ SStgui.update_uis(src)
soundloop.stop()
/obj/machinery/microwave/proc/stop()
@@ -402,7 +489,7 @@
operating = FALSE // Turn it off again aferwards
if(icon_state == "mw1")
icon_state = "mw"
- updateUsrDialog()
+ SStgui.update_uis(src)
soundloop.stop()
/obj/machinery/microwave/proc/dispose(var/message = 1)
@@ -413,7 +500,7 @@
src.reagents.clear_reagents()
if(message)
to_chat(usr, "You dispose of the microwave contents.")
- src.updateUsrDialog()
+ SStgui.update_uis(src)
/obj/machinery/microwave/proc/muck_start()
playsound(src, 'sound/effects/splat.ogg', 50, 1) // Play a splat sound
@@ -425,7 +512,7 @@
src.flags = null //So you can't add condiments
src.icon_state = "mwbloody" // Make it look dirty too
src.operating = 0 // Turn it off again aferwards
- src.updateUsrDialog()
+ SStgui.update_uis(src)
soundloop.stop()
@@ -438,7 +525,7 @@
src.broken = 2 // Make it broken so it can't be used util fixed
src.flags = null //So you can't add condiments
src.operating = 0 // Turn it off again aferwards
- src.updateUsrDialog()
+ SStgui.update_uis(src)
soundloop.stop()
/obj/machinery/microwave/proc/fail()
@@ -460,23 +547,6 @@
ffuu.reagents.add_reagent("toxin", amount/10)
return ffuu
-/obj/machinery/microwave/Topic(href, href_list)
- if(..())
- return
-
- usr.set_machine(src)
- if(src.operating)
- src.updateUsrDialog()
- return
-
- switch(href_list["action"])
- if ("cook")
- cook()
-
- if ("dispose")
- dispose()
- return
-
/obj/machinery/microwave/verb/Eject()
set src in oview(1)
set category = "Object"
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/holodeck/HolodeckControl.dm b/code/modules/holodeck/HolodeckControl.dm
index 5ba939fd8d..bfa684f4e6 100644
--- a/code/modules/holodeck/HolodeckControl.dm
+++ b/code/modules/holodeck/HolodeckControl.dm
@@ -79,60 +79,59 @@
return
user.set_machine(src)
- ui_interact(user)
+ tgui_interact(user)
/**
- * Display the NanoUI window for the Holodeck Computer.
- *
- * See NanoUI documentation for details.
+ * Open the UI!
*/
-/obj/machinery/computer/HolodeckControl/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- user.set_machine(src)
+/obj/machinery/computer/HolodeckControl/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, "Holodeck", name)
+ ui.open()
- var/list/data = list()
- var/program_list[0]
- var/restricted_program_list[0]
+/**
+ * Data for the TGUI UI
+ */
+/obj/machinery/computer/HolodeckControl/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+ var/list/program_list = list()
+ var/list/restricted_program_list = list()
for(var/P in supported_programs)
- program_list[++program_list.len] = P
+ program_list.Add(P)
for(var/P in restricted_programs)
- restricted_program_list[++restricted_program_list.len] = P
+ restricted_program_list.Add(P)
data["supportedPrograms"] = program_list
data["restrictedPrograms"] = restricted_program_list
data["currentProgram"] = current_program
+ data["isSilicon"] = FALSE
if(issilicon(user))
- data["isSilicon"] = 1
- else
- data["isSilicon"] = null
+ data["isSilicon"] = TRUE
+
data["safetyDisabled"] = safety_disabled
data["emagged"] = emagged
+ data["gravity"] = FALSE
if(linkedholodeck.has_gravity)
- data["gravity"] = 1
- else
- data["gravity"] = null
+ data["gravity"] = TRUE
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "holodeck.tmpl", src.name, 400, 550)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(20)
+ return data
-/obj/machinery/computer/HolodeckControl/Topic(href, href_list)
+/obj/machinery/computer/HolodeckControl/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
- if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
- usr.set_machine(src)
+ return TRUE
- if(href_list["program"])
- var/prog = href_list["program"]
+ switch(action)
+ if("program")
+ var/prog = params["program"]
if(prog in (supported_programs + restricted_programs))
if(loadProgram(prog))
current_program = prog
+ return TRUE
- else if(href_list["AIoverride"])
+ if("AIoverride")
if(!issilicon(usr))
return
@@ -147,13 +146,13 @@
else
message_admins("[key_name_admin(usr)] restored the holodeck's safeties")
log_game("[key_name(usr)] restored the holodeck's safeties")
+ return TRUE
- else if(href_list["gravity"])
+ if("gravity")
toggleGravity(linkedholodeck)
+ return TRUE
- src.add_fingerprint(usr)
-
- SSnanoui.update_uis(src)
+ add_fingerprint(usr)
/obj/machinery/computer/HolodeckControl/emag_act(var/remaining_charges, var/mob/user as mob)
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
diff --git a/code/modules/hydroponics/beekeeping/beehive.dm b/code/modules/hydroponics/beekeeping/beehive.dm
index 4172d3dead..e91624724f 100644
--- a/code/modules/hydroponics/beekeeping/beehive.dm
+++ b/code/modules/hydroponics/beekeeping/beehive.dm
@@ -248,7 +248,7 @@
..()
recipes = wax_recipes
-/material/wax
+/datum/material/wax
name = "wax"
stack_type = /obj/item/stack/material/wax
icon_colour = "#fff343"
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/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index 1caf83608b..17eee1149c 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -338,11 +338,11 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
if(!bibledelay)
var/obj/item/weapon/storage/bible/B = new /obj/item/weapon/storage/bible(src.loc)
- if(ticker && ( ticker.Bible_icon_state && ticker.Bible_item_state) )
- B.icon_state = ticker.Bible_icon_state
- B.item_state = ticker.Bible_item_state
- B.name = ticker.Bible_name
- B.deity_name = ticker.Bible_deity_name
+ if(GLOB.religion)
+ B.icon_state = GLOB.bible_icon_state
+ B.item_state = GLOB.bible_item_state
+ B.name = GLOB.bible_name
+ B.deity_name = GLOB.deity
bibledelay = 1
spawn(60)
diff --git a/code/modules/looking_glass/lg_console.dm b/code/modules/looking_glass/lg_console.dm
index 60b51a325a..b46ea9c5fb 100644
--- a/code/modules/looking_glass/lg_console.dm
+++ b/code/modules/looking_glass/lg_console.dm
@@ -50,27 +50,30 @@
return ..()
/obj/machinery/computer/looking_glass/attack_ai(var/mob/user as mob)
- return src.attack_hand(user)
+ return attack_hand(user)
/obj/machinery/computer/looking_glass/attack_hand(var/mob/user as mob)
if(..())
return
- user.set_machine(src)
- ui_interact(user)
+ tgui_interact(user)
-/obj/machinery/computer/looking_glass/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- user.set_machine(src)
-
- var/list/data = list()
- var/program_list[0]
+/obj/machinery/computer/looking_glass/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "LookingGlass", name)
+ ui.open()
+/obj/machinery/computer/looking_glass/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
+ var/list/data = ..()
+
+ var/list/program_list = list()
for(var/P in supported_programs)
- program_list[++program_list.len] = P
+ program_list.Add(P)
if(emagged)
for(var/P in secret_programs)
- program_list[++program_list.len] = P
+ program_list.Add(P)
data["supportedPrograms"] = program_list
data["currentProgram"] = current_program
@@ -78,24 +81,18 @@
if(my_area?.has_gravity)
data["gravity"] = 1
else
- data["gravity"] = null
+ data["gravity"] = 0
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- ui = new(user, src, ui_key, "lookingglass.tmpl", src.name, 400, 550)
- ui.set_initial_data(data)
- ui.open()
- ui.set_auto_update(20)
+ return data
-/obj/machinery/computer/looking_glass/Topic(href, href_list)
+/obj/machinery/computer/looking_glass/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
- return 1
- if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
- usr.set_machine(src)
-
- if(href_list["program"])
+ return TRUE
+
+ switch(action)
+ if("program")
if(ready)
- var/prog = href_list["program"]
+ var/prog = params["program"]
if(prog == "Off")
current_program = "Off"
unload_program()
@@ -104,17 +101,18 @@
load_program(prog)
else
visible_message("ERROR. Recalibrating displays.")
+ return TRUE
- else if(href_list["gravity"])
+ if("gravity")
toggle_gravity(my_area)
+ return TRUE
- else if(href_list["immersion"])
+ if("immersion")
immersion = !immersion
my_area.toggle_optional(immersion)
+ return TRUE
- src.add_fingerprint(usr)
-
- SSnanoui.update_uis(src)
+ add_fingerprint(usr)
/obj/machinery/computer/looking_glass/emag_act(var/remaining_charges, var/mob/user as mob)
if (!emagged)
diff --git a/code/modules/materials/material_recipes.dm b/code/modules/materials/material_recipes.dm
index b852e10383..ff567c55f4 100644
--- a/code/modules/materials/material_recipes.dm
+++ b/code/modules/materials/material_recipes.dm
@@ -1,9 +1,9 @@
-/material/proc/get_recipes()
+/datum/material/proc/get_recipes()
if(!recipes)
generate_recipes()
return recipes
-/material/proc/generate_recipes()
+/datum/material/proc/generate_recipes()
recipes = list()
// If is_brittle() returns true, these are only good for a single strike.
@@ -29,7 +29,7 @@
recipes += new/datum/stack_recipe("[display_name] knife", /obj/item/weapon/material/knife/plastic, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] blade", /obj/item/weapon/material/butterflyblade, 6, time = 20, one_per_turf = 0, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
-/material/steel/generate_recipes()
+/datum/material/steel/generate_recipes()
..()
recipes += new/datum/stack_recipe_list("office chairs",list( \
new/datum/stack_recipe("dark office chair", /obj/structure/bed/chair/office/dark, 5, one_per_turf = 1, on_floor = 1), \
@@ -105,7 +105,7 @@
))
recipes += new/datum/stack_recipe("desk bell", /obj/item/weapon/deskbell, 1, on_floor = 1, supplied_material = "[name]")
-/material/plasteel/generate_recipes()
+/datum/material/plasteel/generate_recipes()
..()
recipes += new/datum/stack_recipe("AI core", /obj/structure/AIcore, 4, time = 50, one_per_turf = 1)
recipes += new/datum/stack_recipe("Metal crate", /obj/structure/closet/crate, 10, time = 50, one_per_turf = 1)
@@ -114,16 +114,16 @@
recipes += new/datum/stack_recipe("roller bed", /obj/item/roller, 5, time = 30, on_floor = 1)
recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 10)
-/material/stone/generate_recipes()
+/datum/material/stone/generate_recipes()
..()
recipes += new/datum/stack_recipe("planting bed", /obj/machinery/portable_atmospherics/hydroponics/soil, 3, time = 10, one_per_turf = 1, on_floor = 1)
-/material/stone/marble/generate_recipes()
+/datum/material/stone/marble/generate_recipes()
..()
recipes += new/datum/stack_recipe("light marble floor tile", /obj/item/stack/tile/wmarble, 1, 4, 20)
recipes += new/datum/stack_recipe("dark marble floor tile", /obj/item/stack/tile/bmarble, 1, 4, 20)
-/material/plastic/generate_recipes()
+/datum/material/plastic/generate_recipes()
..()
recipes += new/datum/stack_recipe("plastic crate", /obj/structure/closet/crate/plastic, 10, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("plastic bag", /obj/item/weapon/storage/bag/plasticbag, 3, on_floor = 1, pass_stack_color = TRUE)
@@ -141,7 +141,7 @@
recipes += new/datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS)
recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE)
-/material/wood/generate_recipes()
+/datum/material/wood/generate_recipes()
..()
recipes += new/datum/stack_recipe("oar", /obj/item/weapon/oar, 2, time = 30, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("boat", /obj/vehicle/boat, 20, time = 10 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
@@ -163,11 +163,11 @@
recipes += new/datum/stack_recipe("wooden standup figure", /obj/structure/barricade/cutout, 5, time = 10 SECONDS, pass_stack_color = TRUE) //VOREStation Add
recipes += new/datum/stack_recipe("noticeboard", /obj/structure/noticeboard, 1)
-/material/wood/log/generate_recipes()
+/datum/material/wood/log/generate_recipes()
recipes = list()
recipes += new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 5, time = 50, supplied_material = "[name]", pass_stack_color = TRUE)
-/material/cardboard/generate_recipes()
+/datum/material/cardboard/generate_recipes()
..()
recipes += new/datum/stack_recipe("box", /obj/item/weapon/storage/box, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("donut box", /obj/item/weapon/storage/box/donut/empty, pass_stack_color = TRUE)
@@ -186,7 +186,7 @@
new/datum/stack_recipe("yellow folder", /obj/item/weapon/folder/yellow), \
))
-/material/snow/generate_recipes()
+/datum/material/snow/generate_recipes()
recipes = list()
recipes += new/datum/stack_recipe("snowball", /obj/item/weapon/material/snow/snowball, 1, time = 10)
recipes += new/datum/stack_recipe("snow brick", /obj/item/stack/material/snowbrick, 2, time = 10)
@@ -194,7 +194,7 @@
recipes += new/datum/stack_recipe("snow robot", /obj/structure/snowman/borg, 2, time = 10)
recipes += new/datum/stack_recipe("snow spider", /obj/structure/snowman/spider, 3, time = 20)
-/material/snowbrick/generate_recipes()
+/datum/material/snowbrick/generate_recipes()
recipes = list()
recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
recipes += new/datum/stack_recipe("[display_name] barricade", /obj/structure/barricade, 5, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
@@ -205,7 +205,7 @@
recipes += new/datum/stack_recipe("[display_name] wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
recipes += new/datum/stack_recipe("[display_name] ashtray", /obj/item/weapon/material/ashtray, 2, one_per_turf = 1, on_floor = 1, supplied_material = "[name]")
-/material/wood/sif/generate_recipes()
+/datum/material/wood/sif/generate_recipes()
..()
recipes += new/datum/stack_recipe("alien wood floor tile", /obj/item/stack/tile/wood/sif, 1, 4, 20, pass_stack_color = TRUE)
for(var/datum/stack_recipe/r_recipe in recipes)
@@ -216,11 +216,11 @@
recipes -= r_recipe
continue
-/material/supermatter/generate_recipes()
+/datum/material/supermatter/generate_recipes()
recipes = list()
recipes += new/datum/stack_recipe("supermatter shard", /obj/machinery/power/supermatter/shard, 30 , one_per_turf = 1, time = 600, on_floor = 1)
-/material/cloth/generate_recipes()
+/datum/material/cloth/generate_recipes()
recipes = list()
recipes += new/datum/stack_recipe("woven net", /obj/item/weapon/material/fishing_net, 10, time = 30 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE)
@@ -238,7 +238,7 @@
recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("crude bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE)
-/material/resin/generate_recipes()
+/datum/material/resin/generate_recipes()
recipes = list()
recipes += new/datum/stack_recipe("[display_name] door", /obj/structure/simple_door/resin, 10, one_per_turf = 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] barricade", /obj/effect/alien/resin/wall, 5, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE)
diff --git a/code/modules/materials/material_recipes_vr.dm b/code/modules/materials/material_recipes_vr.dm
index ba2a95250a..3dc6975a04 100644
--- a/code/modules/materials/material_recipes_vr.dm
+++ b/code/modules/materials/material_recipes_vr.dm
@@ -1,5 +1,5 @@
-/material/steel/generate_recipes()
+/datum/material/steel/generate_recipes()
. = ..()
recipes += new/datum/stack_recipe_list("mounted chairs", list(
new/datum/stack_recipe("mounted chair", /obj/structure/bed/chair/bay/chair, 2, one_per_turf = 1, on_floor = 1, time = 10),
@@ -80,11 +80,11 @@
new/datum/stack_recipe("orange sofa corner", /obj/structure/bed/chair/sofa/orange/corner, 1, one_per_turf = 1, on_floor = 1), \
))
-/material/durasteel/generate_recipes()
+/datum/material/durasteel/generate_recipes()
. = ..()
recipes += new/datum/stack_recipe("durasteel fishing rod", /obj/item/weapon/material/fishing_rod/modern/strong, 2)
recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 30)
-/material/plastitanium/generate_recipes()
+/datum/material/plastitanium/generate_recipes()
. = ..()
recipes += new/datum/stack_recipe("whetstone", /obj/item/weapon/whetstone, 2, time = 20)
diff --git a/code/modules/materials/material_sheets.dm b/code/modules/materials/material_sheets.dm
index 153e023ad0..6eb7b990e8 100644
--- a/code/modules/materials/material_sheets.dm
+++ b/code/modules/materials/material_sheets.dm
@@ -14,7 +14,7 @@
)
var/default_type = DEFAULT_WALL_MATERIAL
- var/material/material
+ var/datum/material/material
var/perunit = SHEET_MATERIAL_AMOUNT
var/apply_colour //temp pending icon rewrite
drop_sound = 'sound/items/drop/axe.ogg'
@@ -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/materials/material_sheets_vr.dm b/code/modules/materials/material_sheets_vr.dm
index fa8676d92d..e198d6d3c0 100644
--- a/code/modules/materials/material_sheets_vr.dm
+++ b/code/modules/materials/material_sheets_vr.dm
@@ -21,7 +21,7 @@
type_to_spawn = /obj/item/stack/material/glass/titanium
/obj/item/stack/material/plastitanium
- name = "plas-tanium sheets"
+ name = "plastitanium sheets"
icon = 'icons/obj/stacks_vr.dmi'
icon_state = "sheet-plastitanium"
item_state = "sheet-silver"
@@ -32,8 +32,20 @@
name = "stack of plastitanium"
type_to_spawn = /obj/item/stack/material/plastitanium
+/obj/item/stack/material/plastitanium/hull
+ name = "plastitanium hull sheets"
+ icon = 'icons/obj/stacks_vr.dmi'
+ icon_state = "sheet-plastitanium"
+ item_state = "sheet-silver"
+ no_variants = FALSE
+ default_type = MAT_PLASTITANIUMHULL
+
+/obj/fiftyspawner/plastitanium_hull
+ name = "stack of plastitanium"
+ type_to_spawn = /obj/item/stack/material/plastitanium/hull
+
/obj/item/stack/material/glass/plastitanium
- name = "plas-tanium glass sheets"
+ name = "plastitanium glass sheets"
icon = 'icons/obj/stacks_vr.dmi'
icon_state = "sheet-plastitaniumglass"
item_state = "sheet-silver"
diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm
index 0fa5d0814c..8171f24579 100644
--- a/code/modules/materials/materials.dm
+++ b/code/modules/materials/materials.dm
@@ -45,7 +45,7 @@ var/list/name_to_material
//mostly for convenience
/obj/proc/get_material_name()
- var/material/material = get_material()
+ var/datum/material/material = get_material()
if(material)
return material.name
@@ -53,8 +53,8 @@ var/list/name_to_material
/proc/populate_material_list(force_remake=0)
if(name_to_material && !force_remake) return // Already set up!
name_to_material = list()
- for(var/type in typesof(/material) - /material)
- var/material/new_mineral = new type
+ for(var/type in typesof(/datum/material) - /datum/material)
+ var/datum/material/new_mineral = new type
if(!new_mineral.name)
continue
name_to_material[lowertext(new_mineral.name)] = new_mineral
@@ -67,13 +67,13 @@ var/list/name_to_material
return name_to_material[name]
/proc/material_display_name(name)
- var/material/material = get_material_by_name(name)
+ var/datum/material/material = get_material_by_name(name)
if(material)
return material.display_name
return null
// Material definition and procs follow.
-/material
+/datum/material
var/name // Unique name for use in indexing the list.
var/display_name // Prettier name for display.
var/use_name
@@ -137,7 +137,7 @@ var/list/name_to_material
var/rotting_touch_message = "crumbles under your touch"
// Placeholders for light tiles and rglass.
-/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
+/datum/material/proc/build_rod_product(var/mob/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
if(!rod_product)
to_chat(user, "You cannot make anything out of \the [target_stack]")
return
@@ -150,7 +150,7 @@ var/list/name_to_material
S.add_fingerprint(user)
S.add_to_stacks(user)
-/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
+/datum/material/proc/build_wired_product(var/mob/living/user, var/obj/item/stack/used_stack, var/obj/item/stack/target_stack)
if(!wire_product)
to_chat(user, "You cannot make anything out of \the [target_stack]")
return
@@ -165,7 +165,7 @@ var/list/name_to_material
user.put_in_hands(product)
// Make sure we have a display name and shard icon even if they aren't explicitly set.
-/material/New()
+/datum/material/New()
..()
if(!display_name)
display_name = name
@@ -175,15 +175,15 @@ var/list/name_to_material
shard_icon = shard_type
// This is a placeholder for proper integration of windows/windoors into the system.
-/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
+/datum/material/proc/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
return 0
// Weapons handle applying a divisor for this value locally.
-/material/proc/get_blunt_damage()
+/datum/material/proc/get_blunt_damage()
return weight //todo
// Return the matter comprising this material.
-/material/proc/get_matter()
+/datum/material/proc/get_matter()
var/list/temp_matter = list()
if(islist(composite_material))
for(var/material_string in composite_material)
@@ -193,61 +193,61 @@ var/list/name_to_material
return temp_matter
// As above.
-/material/proc/get_edge_damage()
+/datum/material/proc/get_edge_damage()
return hardness //todo
// Snowflakey, only checked for alien doors at the moment.
-/material/proc/can_open_material_door(var/mob/living/user)
+/datum/material/proc/can_open_material_door(var/mob/living/user)
return 1
// Currently used for weapons and objects made of uranium to irradiate things.
-/material/proc/products_need_process()
+/datum/material/proc/products_need_process()
return (radioactivity>0) //todo
// Used by walls when qdel()ing to avoid neighbor merging.
-/material/placeholder
+/datum/material/placeholder
name = "placeholder"
// Places a girder object when a wall is dismantled, also applies reinforced material.
-/material/proc/place_dismantled_girder(var/turf/target, var/material/reinf_material, var/material/girder_material)
+/datum/material/proc/place_dismantled_girder(var/turf/target, var/datum/material/reinf_material, var/datum/material/girder_material)
var/obj/structure/girder/G = new(target)
if(reinf_material)
G.reinf_material = reinf_material
G.reinforce_girder()
if(girder_material)
- if(istype(girder_material, /material))
+ if(istype(girder_material, /datum/material))
girder_material = girder_material.name
G.set_material(girder_material)
// General wall debris product placement.
// Not particularly necessary aside from snowflakey cult girders.
-/material/proc/place_dismantled_product(var/turf/target)
+/datum/material/proc/place_dismantled_product(var/turf/target)
place_sheet(target)
// Debris product. Used ALL THE TIME.
-/material/proc/place_sheet(var/turf/target)
+/datum/material/proc/place_sheet(var/turf/target)
if(stack_type)
return new stack_type(target)
// As above.
-/material/proc/place_shard(var/turf/target)
+/datum/material/proc/place_shard(var/turf/target)
if(shard_type)
return new /obj/item/weapon/material/shard(target, src.name)
// Used by walls and weapons to determine if they break or not.
-/material/proc/is_brittle()
+/datum/material/proc/is_brittle()
return !!(flags & MATERIAL_BRITTLE)
-/material/proc/combustion_effect(var/turf/T, var/temperature)
+/datum/material/proc/combustion_effect(var/turf/T, var/temperature)
return
// Used by walls to do on-touch things, after checking for crumbling and open-ability.
-/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
+/datum/material/proc/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
return
// Datum definitions follow.
-/material/uranium
+/datum/material/uranium
name = "uranium"
stack_type = /obj/item/stack/material/uranium
radioactivity = 12
@@ -259,7 +259,7 @@ var/list/name_to_material
door_icon_base = "stone"
supply_conversion_value = 2
-/material/diamond
+/datum/material/diamond
name = "diamond"
stack_type = /obj/item/stack/material/diamond
flags = MATERIAL_UNMELTABLE
@@ -275,7 +275,7 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 6)
supply_conversion_value = 8
-/material/gold
+/datum/material/gold
name = "gold"
stack_type = /obj/item/stack/material/gold
icon_colour = "#EDD12F"
@@ -287,11 +287,11 @@ var/list/name_to_material
sheet_plural_name = "ingots"
supply_conversion_value = 2
-/material/gold/bronze //placeholder for ashtrays
+/datum/material/gold/bronze //placeholder for ashtrays
name = "bronze"
icon_colour = "#EDD12F"
-/material/silver
+/datum/material/silver
name = "silver"
stack_type = /obj/item/stack/material/silver
icon_colour = "#D1E6E3"
@@ -304,7 +304,7 @@ var/list/name_to_material
supply_conversion_value = 2
//R-UST port
-/material/supermatter
+/datum/material/supermatter
name = "supermatter"
icon_colour = "#FFFF00"
stack_type = /obj/item/stack/material/supermatter
@@ -322,7 +322,7 @@ var/list/name_to_material
is_fusion_fuel = 1
stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 5, TECH_BLUESPACE = 4)
-/material/phoron
+/datum/material/phoron
name = "phoron"
stack_type = /obj/item/stack/material/phoron
ignition_point = PHORON_MINIMUM_BURN_TEMPERATURE
@@ -338,7 +338,7 @@ var/list/name_to_material
/*
// Commenting this out while fires are so spectacularly lethal, as I can't seem to get this balanced appropriately.
-/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier)
+/datum/material/phoron/combustion_effect(var/turf/T, var/temperature, var/effect_multiplier)
if(isnull(ignition_point))
return 0
if(temperature < ignition_point)
@@ -353,7 +353,7 @@ var/list/name_to_material
return round(totalPhoron/100)
*/
-/material/stone
+/datum/material/stone
name = "sandstone"
stack_type = /obj/item/stack/material/sandstone
icon_base = "stone"
@@ -369,7 +369,7 @@ var/list/name_to_material
sheet_singular_name = "brick"
sheet_plural_name = "bricks"
-/material/stone/marble
+/datum/material/stone/marble
name = "marble"
icon_colour = "#AAAAAA"
weight = 26
@@ -378,7 +378,7 @@ var/list/name_to_material
stack_type = /obj/item/stack/material/marble
supply_conversion_value = 2
-/material/steel
+/datum/material/steel
name = DEFAULT_WALL_MATERIAL
stack_type = /obj/item/stack/material/steel
integrity = 150
@@ -388,7 +388,7 @@ var/list/name_to_material
icon_reinf = "reinf_over"
icon_colour = "#666666"
-/material/steel/hull
+/datum/material/steel/hull
name = MAT_STEELHULL
stack_type = /obj/item/stack/material/steel/hull
integrity = 250
@@ -397,10 +397,10 @@ var/list/name_to_material
icon_reinf = "reinf_mesh"
icon_colour = "#666677"
-/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets.
+/datum/material/steel/hull/place_sheet(var/turf/target) //Deconstructed into normal steel sheets.
new /obj/item/stack/material/steel(target)
-/material/diona
+/datum/material/diona
name = "biomass"
icon_colour = null
stack_type = null
@@ -408,19 +408,19 @@ var/list/name_to_material
icon_base = "diona"
icon_reinf = "noreinf"
-/material/diona/place_dismantled_product()
+/datum/material/diona/place_dismantled_product()
return
-/material/diona/place_dismantled_girder(var/turf/target)
+/datum/material/diona/place_dismantled_girder(var/turf/target)
spawn_diona_nymph(target)
-/material/steel/holographic
+/datum/material/steel/holographic
name = "holo" + DEFAULT_WALL_MATERIAL
display_name = DEFAULT_WALL_MATERIAL
stack_type = null
shard_type = SHARD_NONE
-/material/plasteel
+/datum/material/plasteel
name = "plasteel"
stack_type = /obj/item/stack/material/plasteel
integrity = 400
@@ -437,7 +437,7 @@ var/list/name_to_material
composite_material = list(DEFAULT_WALL_MATERIAL = SHEET_MATERIAL_AMOUNT, "platinum" = SHEET_MATERIAL_AMOUNT) //todo
supply_conversion_value = 6
-/material/plasteel/hull
+/datum/material/plasteel/hull
name = MAT_PLASTEELHULL
stack_type = /obj/item/stack/material/plasteel/hull
integrity = 600
@@ -446,11 +446,11 @@ var/list/name_to_material
icon_colour = "#777788"
explosion_resistance = 40
-/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
+/datum/material/plasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
new /obj/item/stack/material/plasteel(target)
// Very rare alloy that is reflective, should be used sparingly.
-/material/durasteel
+/datum/material/durasteel
name = "durasteel"
stack_type = /obj/item/stack/material/durasteel/hull
integrity = 600
@@ -467,7 +467,7 @@ var/list/name_to_material
composite_material = list("plasteel" = SHEET_MATERIAL_AMOUNT, "diamond" = SHEET_MATERIAL_AMOUNT) //shrug
supply_conversion_value = 9
-/material/durasteel/hull //The 'Hardball' of starship hulls.
+/datum/material/durasteel/hull //The 'Hardball' of starship hulls.
name = MAT_DURASTEELHULL
icon_base = "hull"
icon_reinf = "reinf_mesh"
@@ -475,10 +475,10 @@ var/list/name_to_material
explosion_resistance = 90
reflectivity = 0.9
-/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets.
+/datum/material/durasteel/hull/place_sheet(var/turf/target) //Deconstructed into normal durasteel sheets.
new /obj/item/stack/material/durasteel(target)
-/material/plasteel/titanium
+/datum/material/plasteel/titanium
name = MAT_TITANIUM
stack_type = /obj/item/stack/material/titanium
conductivity = 2.38
@@ -487,16 +487,16 @@ var/list/name_to_material
icon_colour = "#D1E6E3"
icon_reinf = "reinf_metal"
-/material/plasteel/titanium/hull
+/datum/material/plasteel/titanium/hull
name = MAT_TITANIUMHULL
stack_type = /obj/item/stack/material/titanium/hull
icon_base = "hull"
icon_reinf = "reinf_mesh"
-/material/plasteel/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets.
+/datum/material/plasteel/titanium/hull/place_sheet(var/turf/target) //Deconstructed into normal titanium sheets.
new /obj/item/stack/material/titanium(target)
-/material/glass
+/datum/material/glass
name = "glass"
stack_type = /obj/item/stack/material/glass
flags = MATERIAL_BRITTLE
@@ -517,7 +517,7 @@ var/list/name_to_material
created_fulltile_window = /obj/structure/window/basic/full
rod_product = /obj/item/stack/material/glass/reinforced
-/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
+/datum/material/glass/build_windows(var/mob/living/user, var/obj/item/stack/used_stack)
if(!user || !used_stack || !created_window || !created_fulltile_window || !window_options.len)
return 0
@@ -588,10 +588,10 @@ var/list/name_to_material
new build_path(T, build_dir, 1)
return 1
-/material/glass/proc/is_reinforced()
+/datum/material/glass/proc/is_reinforced()
return (hardness > 35) //todo
-/material/glass/reinforced
+/datum/material/glass/reinforced
name = "rglass"
display_name = "reinforced glass"
stack_type = /obj/item/stack/material/glass/reinforced
@@ -611,7 +611,7 @@ var/list/name_to_material
wire_product = null
rod_product = null
-/material/glass/phoron
+/datum/material/glass/phoron
name = "borosilicate glass"
display_name = "borosilicate glass"
stack_type = /obj/item/stack/material/glass/phoronglass
@@ -625,7 +625,7 @@ var/list/name_to_material
wire_product = null
rod_product = /obj/item/stack/material/glass/phoronrglass
-/material/glass/phoron/reinforced
+/datum/material/glass/phoron/reinforced
name = "reinforced borosilicate glass"
display_name = "reinforced borosilicate glass"
stack_type = /obj/item/stack/material/glass/phoronrglass
@@ -640,7 +640,7 @@ var/list/name_to_material
composite_material = list() //todo
rod_product = null
-/material/plastic
+/datum/material/plastic
name = "plastic"
stack_type = /obj/item/stack/material/plastic
flags = MATERIAL_BRITTLE
@@ -655,13 +655,13 @@ var/list/name_to_material
melting_point = T0C+371 //assuming heat resistant plastic
stack_origin_tech = list(TECH_MATERIAL = 3)
-/material/plastic/holographic
+/datum/material/plastic/holographic
name = "holoplastic"
display_name = "plastic"
stack_type = null
shard_type = SHARD_NONE
-/material/graphite
+/datum/material/graphite
name = MAT_GRAPHITE
stack_type = /obj/item/stack/material/graphite
flags = MATERIAL_BRITTLE
@@ -677,7 +677,7 @@ var/list/name_to_material
radiation_resistance = 15
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 2)
-/material/osmium
+/datum/material/osmium
name = "osmium"
stack_type = /obj/item/stack/material/osmium
icon_colour = "#9999FF"
@@ -687,7 +687,7 @@ var/list/name_to_material
conductivity = 100
supply_conversion_value = 6
-/material/tritium
+/datum/material/tritium
name = "tritium"
stack_type = /obj/item/stack/material/tritium
icon_colour = "#777777"
@@ -697,7 +697,7 @@ var/list/name_to_material
is_fusion_fuel = 1
conductive = 0
-/material/deuterium
+/datum/material/deuterium
name = "deuterium"
stack_type = /obj/item/stack/material/deuterium
icon_colour = "#999999"
@@ -707,7 +707,7 @@ var/list/name_to_material
is_fusion_fuel = 1
conductive = 0
-/material/mhydrogen
+/datum/material/mhydrogen
name = "mhydrogen"
stack_type = /obj/item/stack/material/mhydrogen
icon_colour = "#E6C5DE"
@@ -716,7 +716,7 @@ var/list/name_to_material
is_fusion_fuel = 1
supply_conversion_value = 6
-/material/platinum
+/datum/material/platinum
name = "platinum"
stack_type = /obj/item/stack/material/platinum
icon_colour = "#9999FF"
@@ -727,7 +727,7 @@ var/list/name_to_material
sheet_plural_name = "ingots"
supply_conversion_value = 5
-/material/iron
+/datum/material/iron
name = "iron"
stack_type = /obj/item/stack/material/iron
icon_colour = "#5C5454"
@@ -736,7 +736,7 @@ var/list/name_to_material
sheet_singular_name = "ingot"
sheet_plural_name = "ingots"
-/material/lead
+/datum/material/lead
name = MAT_LEAD
stack_type = /obj/item/stack/material/lead
icon_colour = "#273956"
@@ -749,7 +749,7 @@ var/list/name_to_material
// Particle Smasher and other exotic materials.
-/material/verdantium
+/datum/material/verdantium
name = MAT_VERDANTIUM
stack_type = /obj/item/stack/material/verdantium
icon_base = "metal"
@@ -770,7 +770,7 @@ var/list/name_to_material
sheet_plural_name = "sheets"
supply_conversion_value = 8
-/material/morphium
+/datum/material/morphium
name = MAT_MORPHIUM
stack_type = /obj/item/stack/material/morphium
icon_base = "metal"
@@ -791,13 +791,13 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 8, TECH_ILLEGAL = 1, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_ARCANE = 1)
supply_conversion_value = 13
-/material/morphium/hull
+/datum/material/morphium/hull
name = MAT_MORPHIUMHULL
stack_type = /obj/item/stack/material/morphium/hull
icon_base = "hull"
icon_reinf = "reinf_mesh"
-/material/valhollide
+/datum/material/valhollide
name = MAT_VALHOLLIDE
stack_type = /obj/item/stack/material/valhollide
icon_base = "stone"
@@ -820,7 +820,7 @@ var/list/name_to_material
// Adminspawn only, do not let anyone get this.
-/material/alienalloy
+/datum/material/alienalloy
name = "alienalloy"
display_name = "durable alloy"
stack_type = null
@@ -834,31 +834,31 @@ var/list/name_to_material
protectiveness = 80 // 80%
// Likewise.
-/material/alienalloy/elevatorium
+/datum/material/alienalloy/elevatorium
name = "elevatorium"
display_name = "elevator panelling"
icon_colour = "#666666"
// Ditto.
-/material/alienalloy/dungeonium
+/datum/material/alienalloy/dungeonium
name = "dungeonium"
display_name = "ultra-durable"
icon_base = "dungeon"
icon_colour = "#FFFFFF"
-/material/alienalloy/bedrock
+/datum/material/alienalloy/bedrock
name = "bedrock"
display_name = "impassable rock"
icon_base = "rock"
icon_colour = "#FFFFFF"
-/material/alienalloy/alium
+/datum/material/alienalloy/alium
name = "alium"
display_name = "alien"
icon_base = "alien"
icon_colour = "#FFFFFF"
-/material/resin
+/datum/material/resin
name = "resin"
icon_colour = "#35343a"
icon_base = "resin"
@@ -874,13 +874,13 @@ var/list/name_to_material
stack_origin_tech = list(TECH_MATERIAL = 8, TECH_PHORON = 4, TECH_BLUESPACE = 4, TECH_BIO = 7)
stack_type = /obj/item/stack/material/resin
-/material/resin/can_open_material_door(var/mob/living/user)
+/datum/material/resin/can_open_material_door(var/mob/living/user)
var/mob/living/carbon/M = user
if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)
return 1
return 0
-/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
+/datum/material/resin/wall_touch_special(var/turf/simulated/wall/W, var/mob/living/L)
var/mob/living/carbon/M = L
if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)
to_chat(M, "\The [W] shudders under your touch, starting to become porous.")
@@ -892,7 +892,7 @@ var/list/name_to_material
return 1
return 0
-/material/wood
+/datum/material/wood
name = MAT_WOOD
stack_type = /obj/item/stack/material/wood
icon_colour = "#9c5930"
@@ -915,7 +915,7 @@ var/list/name_to_material
sheet_singular_name = "plank"
sheet_plural_name = "planks"
-/material/wood/log
+/datum/material/wood/log
name = MAT_LOG
icon_base = "log"
stack_type = /obj/item/stack/material/log
@@ -924,25 +924,25 @@ var/list/name_to_material
pass_stack_colors = TRUE
supply_conversion_value = 3 //YW Adds: logs worth points
-/material/wood/log/sif
+/datum/material/wood/log/sif
name = MAT_SIFLOG
icon_colour = "#0099cc" // Cyan-ish
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
stack_type = /obj/item/stack/material/log/sif
-/material/wood/holographic
+/datum/material/wood/holographic
name = "holowood"
display_name = "wood"
stack_type = null
shard_type = SHARD_NONE
-/material/wood/sif
+/datum/material/wood/sif
name = MAT_SIFWOOD
stack_type = /obj/item/stack/material/wood/sif
icon_colour = "#0099cc" // Cyan-ish
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2) // Alien wood would presumably be more interesting to the analyzer.
-/material/cardboard
+/datum/material/cardboard
name = "cardboard"
stack_type = /obj/item/stack/material/cardboard
flags = MATERIAL_BRITTLE
@@ -962,7 +962,7 @@ var/list/name_to_material
radiation_resistance = 1
pass_stack_colors = TRUE
-/material/snow
+/datum/material/snow
name = MAT_SNOW
stack_type = /obj/item/stack/material/snow
flags = MATERIAL_BRITTLE
@@ -980,7 +980,7 @@ var/list/name_to_material
sheet_plural_name = "pile" //Just a bigger pile
radiation_resistance = 1
-/material/snowbrick //only slightly stronger than snow, used to make igloos mostly
+/datum/material/snowbrick //only slightly stronger than snow, used to make igloos mostly
name = "packed snow"
flags = MATERIAL_BRITTLE
stack_type = /obj/item/stack/material/snowbrick
@@ -998,7 +998,7 @@ var/list/name_to_material
sheet_plural_name = "bricks"
radiation_resistance = 1
-/material/cloth //todo
+/datum/material/cloth //todo
name = "cloth"
stack_origin_tech = list(TECH_MATERIAL = 2)
door_icon_base = "wood"
@@ -1009,7 +1009,7 @@ var/list/name_to_material
conductive = 0
pass_stack_colors = TRUE
-/material/cult
+/datum/material/cult
name = "cult"
display_name = "disturbing stone"
icon_base = "cult"
@@ -1020,21 +1020,21 @@ var/list/name_to_material
sheet_plural_name = "bricks"
conductive = 0
-/material/cult/place_dismantled_girder(var/turf/target)
+/datum/material/cult/place_dismantled_girder(var/turf/target)
new /obj/structure/girder/cult(target, "cult")
-/material/cult/place_dismantled_product(var/turf/target)
+/datum/material/cult/place_dismantled_product(var/turf/target)
new /obj/effect/decal/cleanable/blood(target)
-/material/cult/reinf
+/datum/material/cult/reinf
name = "cult2"
display_name = "human remains"
-/material/cult/reinf/place_dismantled_product(var/turf/target)
+/datum/material/cult/reinf/place_dismantled_product(var/turf/target)
new /obj/effect/decal/remains/human(target)
//TODO PLACEHOLDERS:
-/material/leather
+/datum/material/leather
name = "leather"
icon_colour = "#5C4831"
stack_origin_tech = list(TECH_MATERIAL = 2)
@@ -1044,7 +1044,7 @@ var/list/name_to_material
protectiveness = 3 // 13%
conductive = 0
-/material/carpet
+/datum/material/carpet
name = "carpet"
display_name = "comfy"
use_name = "red upholstery"
@@ -1057,7 +1057,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cotton
+/datum/material/cotton
name = "cotton"
display_name ="cotton"
icon_colour = "#FFFFFF"
@@ -1068,7 +1068,7 @@ var/list/name_to_material
conductive = 0
// This all needs to be OOP'd and use inheritence if its ever used in the future.
-/material/cloth_teal
+/datum/material/cloth_teal
name = "teal"
display_name ="teal"
use_name = "teal cloth"
@@ -1079,7 +1079,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cloth_black
+/datum/material/cloth_black
name = "black"
display_name = "black"
use_name = "black cloth"
@@ -1090,7 +1090,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cloth_green
+/datum/material/cloth_green
name = "green"
display_name = "green"
use_name = "green cloth"
@@ -1101,7 +1101,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cloth_puple
+/datum/material/cloth_puple
name = "purple"
display_name = "purple"
use_name = "purple cloth"
@@ -1112,7 +1112,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cloth_blue
+/datum/material/cloth_blue
name = "blue"
display_name = "blue"
use_name = "blue cloth"
@@ -1123,7 +1123,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cloth_beige
+/datum/material/cloth_beige
name = "beige"
display_name = "beige"
use_name = "beige cloth"
@@ -1134,7 +1134,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cloth_lime
+/datum/material/cloth_lime
name = "lime"
display_name = "lime"
use_name = "lime cloth"
@@ -1145,7 +1145,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cloth_yellow
+/datum/material/cloth_yellow
name = "yellow"
display_name = "yellow"
use_name = "yellow cloth"
@@ -1156,7 +1156,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/cloth_orange
+/datum/material/cloth_orange
name = "orange"
display_name = "orange"
use_name = "orange cloth"
@@ -1167,7 +1167,7 @@ var/list/name_to_material
protectiveness = 1 // 4%
conductive = 0
-/material/toy_foam
+/datum/material/toy_foam
name = "foam"
display_name = "foam"
use_name = "foam"
diff --git a/code/modules/materials/materials_vr.dm b/code/modules/materials/materials_vr.dm
index c341a15496..460869d32f 100644
--- a/code/modules/materials/materials_vr.dm
+++ b/code/modules/materials/materials_vr.dm
@@ -1,4 +1,4 @@
-/material/flesh
+/datum/material/flesh
name = "flesh"
display_name = "chunk of flesh"
icon_colour = "#dd90aa"
@@ -10,7 +10,7 @@
hardness = 500
weight = 500
-/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix.
+/datum/material/fluff //This is to allow for 2 handed weapons that don't want to have a prefix.
name = " "
display_name = ""
icon_colour = "#000000"
@@ -19,19 +19,19 @@
hardness = 60
weight = 20 //Strong as iron.
-/material/darkglass
+/datum/material/darkglass
name = "darkglass"
display_name = "darkglass"
icon_base = "darkglass"
icon_colour = "#FFFFFF"
-/material/fancyblack
+/datum/material/fancyblack
name = "fancyblack"
display_name = "fancyblack"
icon_base = "fancyblack"
icon_colour = "#FFFFFF"
-/material/glass/titaniumglass
+/datum/material/glass/titaniumglass
name = MAT_TITANIUMGLASS
display_name = "titanium glass"
stack_type = /obj/item/stack/material/glass/titanium
@@ -48,7 +48,7 @@
rod_product = /obj/item/stack/material/glass/titanium
composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, "glass" = SHEET_MATERIAL_AMOUNT)
-/material/plastitanium
+/datum/material/plastitanium
name = MAT_PLASTITANIUM
stack_type = /obj/item/stack/material/plastitanium
integrity = 600
@@ -65,7 +65,18 @@
composite_material = list(MAT_TITANIUM = SHEET_MATERIAL_AMOUNT, MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT)
supply_conversion_value = 8
-/material/glass/plastaniumglass
+/datum/material/plastitanium/hull
+ name = MAT_PLASTITANIUMHULL
+ stack_type = /obj/item/stack/material/plastitanium/hull
+ icon_base = "hull"
+ icon_reinf = "reinf_mesh"
+ icon_colour = "#585658"
+ explosion_resistance = 50
+
+/datum/material/plastitanium/hull/place_sheet(var/turf/target) //Deconstructed into normal plasteel sheets.
+ new /obj/item/stack/material/plastitanium(target)
+
+/datum/material/glass/plastaniumglass
name = MAT_PLASTITANIUMGLASS
display_name = "plas-titanium glass"
stack_type = /obj/item/stack/material/glass/plastitanium
diff --git a/code/modules/media/media_tracks.dm b/code/modules/media/media_tracks.dm
index 42ad9809fb..840f857f96 100644
--- a/code/modules/media/media_tracks.dm
+++ b/code/modules/media/media_tracks.dm
@@ -25,7 +25,7 @@
str += " by [artist]"
return str
-/datum/track/proc/toNanoList()
+/datum/track/proc/toTguiList()
return list("ref" = "\ref[src]", "title" = title, "artist" = artist, "duration" = duration)
diff --git a/code/modules/mining/drilling/scanner.dm b/code/modules/mining/drilling/scanner.dm
index 31da4a9753..50bf8bdd35 100644
--- a/code/modules/mining/drilling/scanner.dm
+++ b/code/modules/mining/drilling/scanner.dm
@@ -6,7 +6,7 @@
item_state = "electronic"
origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1)
matter = list(DEFAULT_WALL_MATERIAL = 150)
- var/scan_time = 5 SECONDS
+ var/scan_time = 2 SECONDS
/obj/item/weapon/mining_scanner/attack_self(mob/user as mob)
to_chat(user, "You begin sweeping \the [src] about, scanning for metal deposits.")
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index 93c711b6be..32d47681c3 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -275,7 +275,7 @@
var/can_make = CLAMP(ores_stored[metal],0,sheets_per_tick-sheets)
if(can_make%2>0) can_make--
- var/material/M = get_material_by_name(O.compresses_to)
+ var/datum/material/M = get_material_by_name(O.compresses_to)
if(!istype(M) || !can_make || ores_stored[metal] < 1)
continue
@@ -289,7 +289,7 @@
var/can_make = CLAMP(ores_stored[metal],0,sheets_per_tick-sheets)
- var/material/M = get_material_by_name(O.smelts_to)
+ var/datum/material/M = get_material_by_name(O.smelts_to)
if(!istype(M) || !can_make || ores_stored[metal] < 1)
continue
diff --git a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
index 2f388e2ba5..0ab8381002 100644
--- a/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
+++ b/code/modules/mining/ore_redemption_machine/equipment_vendor.dm
@@ -91,8 +91,9 @@
EQUIPMENT("Fine Excavation Kit - Measuring Tape", /obj/item/device/measuring_tape, 125),
EQUIPMENT("Fine Excavation Kit - Hand Pick", /obj/item/weapon/pickaxe/hand, 375),
EQUIPMENT("Explosive Excavation Kit - Plastic Charge",/obj/item/weapon/plastique/seismic/locked, 1500),
- EQUIPMENT("Industrial Equipment - Phoron Bore", /obj/item/weapon/gun/magnetic/matfed, 3000),
- EQUIPMENT("Industrial Equipment - Sheet-Snatcher",/obj/item/weapon/storage/bag/sheetsnatcher, 500),
+ EQUIPMENT("Industrial Equipment - Phoron Bore", /obj/item/weapon/gun/magnetic/matfed, 3000),
+ EQUIPMENT("Industrial Equipment - Inducer", /obj/item/weapon/inducer, 900),
+ EQUIPMENT("Industrial Equipment - Sheet-Snatcher", /obj/item/weapon/storage/bag/sheetsnatcher, 500),
)
prize_list["Hardsuit"] = list(
EQUIPMENT("Hardsuit - Control Module", /obj/item/weapon/rig/industrial/vendor, 2000),
diff --git a/code/modules/mining/ore_redemption_machine/survey_vendor.dm b/code/modules/mining/ore_redemption_machine/survey_vendor.dm
index 1eb8672ef6..eaf5667094 100644
--- a/code/modules/mining/ore_redemption_machine/survey_vendor.dm
+++ b/code/modules/mining/ore_redemption_machine/survey_vendor.dm
@@ -55,6 +55,7 @@
EQUIPMENT("Digital Tablet - Standard", /obj/item/modular_computer/tablet/preset/custom_loadout/standard, 50),
EQUIPMENT("Digital Tablet - Advanced", /obj/item/modular_computer/tablet/preset/custom_loadout/advanced, 100),
EQUIPMENT("Industrial Equipment - Phoron Bore", /obj/item/weapon/gun/magnetic/matfed, 300),
+ EQUIPMENT("Industrial Equipment - Inducer", /obj/item/weapon/inducer, 90),
EQUIPMENT("Laser Pointer", /obj/item/device/laser_pointer, 90),
EQUIPMENT("Luxury Shelter Capsule", /obj/item/device/survivalcapsule/luxury, 310),
EQUIPMENT("Bar Shelter Capsule", /obj/item/device/survivalcapsule/luxurybar, 1000),
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 a736c8f976..5febeeba30 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/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 3f633c262d..a6326263da 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -183,31 +183,32 @@
// VOREstation Edit End.
#undef HUMAN_LOWEST_SLOWDOWN
+/mob/living/carbon/human/get_jetpack()
+ if(back)
+ var/obj/item/weapon/rig/rig = get_rig()
+ if(istype(back, /obj/item/weapon/tank/jetpack))
+ return back
+ else if(istype(rig))
+ for(var/obj/item/rig_module/maneuvering_jets.module in rig.installed_modules)
+ return module.jets
+
/mob/living/carbon/human/Process_Spacemove(var/check_drift = 0)
//Can we act?
if(restrained()) return 0
+ if(..()) //Can move due to other reasons, don't use jetpack fuel
+ return 1
+
//Do we have a working jetpack?
- var/obj/item/weapon/tank/jetpack/thrust
- if(back)
- if(istype(back,/obj/item/weapon/tank/jetpack))
- thrust = back
- else if(istype(get_rig(),/obj/item/weapon/rig))
- var/obj/item/weapon/rig/rig = get_rig()
- for(var/obj/item/rig_module/maneuvering_jets/module in rig.installed_modules)
- thrust = module.jets
- break
+ var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
if(thrust)
- if(((!check_drift) || (check_drift && thrust.stabilization_on)) && (!lying) && (thrust.allow_thrust(0.01, src)))
+ if(((!check_drift) || (check_drift && thrust.stabilization_on)) && (!lying) && (thrust.do_thrust(0.01, src)))
inertia_dir = 0
return 1
if(flying) //VOREStation Edit. If you're flying, you glide around!
return 0 //VOREStation Edit.
- //If no working jetpack then use the other checks
- if(..())
- return 1
return 0
@@ -215,7 +216,11 @@
//If knocked out we might just hit it and stop. This makes it possible to get dead bodies and such.
if(species.flags & NO_SLIP)
- return
+ return 0
+
+ var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
+ if(thrust?.can_thrust(0.01))
+ return 0
if(stat)
prob_slip = 0 // Changing this to zero to make it line up with the comment, and also, make more sense.
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/alraune.dm b/code/modules/mob/living/carbon/human/species/station/alraune.dm
index fe7410c774..8353d36cba 100644
--- a/code/modules/mob/living/carbon/human/species/station/alraune.dm
+++ b/code/modules/mob/living/carbon/human/species/station/alraune.dm
@@ -111,19 +111,19 @@
//This is mostly normal breath code with some tweaks that apply to their particular biology.
var/datum/gas_mixture/breath = null
- var/fullysealed = FALSE //if they're wearing a fully sealed suit, their internals take priority.
- var/environmentalair = FALSE //if no sealed suit, internals take priority in low pressure environements
+ var/fullysealed = FALSE //are they covered in a sealed suit or not
- if(H.wear_suit && (H.wear_suit.min_pressure_protection = 0) && H.head && (H.head.min_pressure_protection = 0))
+ if(H.wear_suit && (H.wear_suit.min_pressure_protection < hazard_low_pressure) && H.head && (H.head.min_pressure_protection < hazard_low_pressure))
+ //if they're wearing a fully sealed suit, their internals take priority.
+ breath = H.get_breath_from_internal()
fullysealed = TRUE
- else // find out if local gas mixture is enough to override use of internals
+ else
+ // find out if local gas mixture is enough to override use of internals
+ // if pressure is low enough, they can still breathe from internals without a suit
var/datum/gas_mixture/environment = H.loc.return_air()
var/envpressure = environment.return_pressure()
- if(envpressure >= hazard_low_pressure)
- environmentalair = TRUE
-
- if(fullysealed || !environmentalair)
- breath = H.get_breath_from_internal()
+ if(envpressure < hazard_low_pressure)
+ breath = H.get_breath_from_internal()
if(!breath) //No breath from internals so let's try to get air from our location
// cut-down version of get_breath_from_environment - notably, gas masks provide no benefit
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/species/station/traits_vr/positive.dm b/code/modules/mob/living/carbon/human/species/station/traits_vr/positive.dm
index a7c3da8a40..87ee6b048b 100644
--- a/code/modules/mob/living/carbon/human/species/station/traits_vr/positive.dm
+++ b/code/modules/mob/living/carbon/human/species/station/traits_vr/positive.dm
@@ -74,13 +74,13 @@
name = "Darksight"
desc = "Allows you to see a short distance in the dark."
cost = 1
- var_changes = list("darksight" = 3)
+ var_changes = list("darksight" = 5, "flash_mod" = 2.0)
/datum/trait/darksight_plus
name = "Darksight (Major)"
desc = "Allows you to see in the dark for almost the whole screen."
cost = 2
- var_changes = list("darksight" = 6)
+ var_changes = list("darksight" = 8, "flash_mod" = 3.0)
/datum/trait/melee_attack
name = "Sharp Melee"
diff --git a/code/modules/mob/living/carbon/human/stripping.dm b/code/modules/mob/living/carbon/human/stripping.dm
index 736109794a..7aa08accbb 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))
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/living.dm b/code/modules/mob/living/living.dm
index f72ec0d488..68f993412a 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -132,16 +132,25 @@ default behaviour is:
if((tmob.mob_always_swap || (tmob.a_intent == I_HELP || tmob.restrained()) && (a_intent == I_HELP || src.restrained())) && tmob.canmove && canmove && !tmob.buckled && !buckled && can_swap && can_move_mob(tmob, 1, 0)) // mutual brohugs all around!
var/turf/oldloc = loc
+ //VOREstation Edit - Begin
+
+ //check bumpnom chance, if it's a simplemob that's doing the bumping
+ var/mob/living/simple_mob/srcsimp = src
+ if(istype(srcsimp))
+ if(srcsimp.tryBumpNom(tmob))
+ now_pushing = 0
+ return
+
+ //if it's a simplemob being bumped, and the above didn't make them start getting bumpnommed, they get a chance to bumpnom
+ var/mob/living/simple_mob/tmobsimp = tmob
+ if(istype(tmobsimp))
+ if(tmobsimp.tryBumpNom(src))
+ now_pushing = 0
+ return
+
+ //VOREstation Edit - End
forceMove(tmob.loc)
//VOREstation Edit - Begin
- if (istype(tmob, /mob/living/simple_mob)) //check bumpnom chance, if it's a simplemob that's bumped
- tmob.Bumped(src)
- else if(istype(src, /mob/living/simple_mob)) //otherwise, if it's a simplemob doing the bumping. Simplemob on simplemob doesn't seem to trigger but that's fine.
- Bumped(tmob)
- if (tmob.loc == src) //check if they got ate, and if so skip the forcemove
- now_pushing = 0
- return
-
// In case of micros, we don't swap positions; instead occupying the same square!
if (handle_micro_bump_helping(tmob))
now_pushing = 0
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 a701a2588d..4101362f84 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
@@ -151,7 +151,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_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm
index fe05775c51..bc9b7367f2 100644
--- a/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -1,16 +1,28 @@
+/mob/living/silicon/robot/get_jetpack()
+ if(module)
+ for(var/obj/item/weapon/tank/jetpack/J in module.modules)
+ return J
+
+/mob/living/silicon/robot/Check_Shoegrip()
+ return module && module.no_slip
+
/mob/living/silicon/robot/Process_Spaceslipping(var/prob_slip)
+ var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
+ if(thrust?.can_thrust(0.01))
+ return 0
if(module && module.no_slip)
return 0
..(prob_slip)
-/mob/living/silicon/robot/Process_Spacemove()
- if(module)
- for(var/obj/item/weapon/tank/jetpack/J in module.modules)
- if(istype(J, /obj/item/weapon/tank/jetpack))
- if(J.allow_thrust(0.01))
- return 1
- if(..())
+/mob/living/silicon/robot/Process_Spacemove(var/check_drift = 0)
+ if(..())//Can move due to other reasons, don't use jetpack fuel
return 1
+
+ var/obj/item/weapon/tank/jetpack/thrust = get_jetpack()
+ if(thrust && (!check_drift || (check_drift && thrust.stabilization_on)) && thrust.do_thrust(0.01))
+ inertia_dir = 0
+ return 1
+
return 0
//No longer needed, but I'll leave it here incase we plan to re-use it.
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/simple_mob_vr.dm b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
index 6b2d4bb6fe..ef631fa897 100644
--- a/code/modules/mob/living/simple_mob/simple_mob_vr.dm
+++ b/code/modules/mob/living/simple_mob/simple_mob_vr.dm
@@ -244,17 +244,23 @@
"The stomach glorps and gurgles as it tries to work you into slop.")
/mob/living/simple_mob/Bumped(var/atom/movable/AM, yes)
- if(ismob(AM))
- var/mob/tmob = AM
- if(will_eat(tmob) && !istype(tmob, type) && prob(vore_bump_chance) && !ckey) //check if they decide to eat. Includes sanity check to prevent cannibalism.
- if(tmob.canmove && prob(vore_pounce_chance)) //if they'd pounce for other noms, pounce for these too, otherwise still try and eat them if they hold still
- tmob.Weaken(5)
- tmob.visible_message("\the [src] [vore_bump_emote] \the [tmob]!!")
- set_AI_busy(TRUE)
+ if(tryBumpNom(AM))
+ return
+ ..()
+
+/mob/living/simple_mob/proc/tryBumpNom(var/mob/tmob)
+ //returns TRUE if we actually start an attempt to bumpnom, FALSE if checks fail or the random bump nom chance fails
+ if(istype(tmob) && will_eat(tmob) && !istype(tmob, type) && prob(vore_bump_chance) && !ckey) //check if they decide to eat. Includes sanity check to prevent cannibalism.
+ if(tmob.canmove && prob(vore_pounce_chance)) //if they'd pounce for other noms, pounce for these too, otherwise still try and eat them if they hold still
+ tmob.Weaken(5)
+ tmob.visible_message("\the [src] [vore_bump_emote] \the [tmob]!!")
+ set_AI_busy(TRUE)
+ spawn()
animal_nom(tmob)
update_icon()
set_AI_busy(FALSE)
- ..()
+ return TRUE
+ return FALSE
// Checks to see if mob doesn't like this kind of turf
/mob/living/simple_mob/IMove(newloc)
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 dbedc27aa0..d713ade614 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/giant_spider/thermic.dm b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/thermic.dm
index 7abb7156d5..d51f6422fe 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/thermic.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/giant_spider/thermic.dm
@@ -28,6 +28,7 @@
melee_damage_lower = 10
melee_damage_upper = 25
+ attack_armor_pen = 15
heat_resist = 0.75
cold_resist = -0.50
diff --git a/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm b/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm
index 8d09b18fea..848fb7fafa 100644
--- a/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/animal/pets/parrot.dm
@@ -1,252 +1,253 @@
-// Parrots can talk, and may repeat things it hears.
-/mob/living/simple_mob/animal/passive/bird/parrot
- name = "parrot"
- description_info = "You can give it a headset by clicking on it with a headset. \
- To remove it, click the bird while on grab intent."
- has_langs = list("Galactic Common", "Bird")
-
- ai_holder_type = /datum/ai_holder/simple_mob/passive/parrot
-
- // A headset, so that talking parrots can yell at the crew over comms.
- // If set to a type, on initialize it will be instantiated into that type.
- var/obj/item/device/radio/headset/my_headset = null
-
-// Say list
-/datum/say_list/bird/poly
- speak = list(
- "Poly wanna cracker!",
- "Check the singulo, you chucklefucks!",
- "Wire the solars, you lazy bums!",
- "WHO TOOK THE DAMN HARDSUITS?",
- "OH GOD ITS FREE CALL THE SHUTTLE",
- "Danger! Crystal hyperstructure instability!",
- "CRYSTAL DELAMINATION IMMINENT.",
- "Tweet tweet, I'm a Teshari.",
- "Chitters.",
- "Meteors have been detected on a collision course with the station!"
- )
-
-// Lets the AI use headsets.
-// Player-controlled parrots will need to do it manually.
-/mob/living/simple_mob/animal/passive/bird/parrot/ISay(message)
- if(my_headset && prob(50))
- var/list/keys = list()
- for(var/channel in my_headset.channels)
- var/key = get_radio_key_from_channel(channel)
- if(key)
- keys += key
- if(keys.len)
- var/key_used = pick(keys)
- return say("[key_used] [message]")
- return say(message)
-
-// Ugly saycode so parrots can use their headsets.
-/mob/living/simple_mob/animal/passive/bird/parrot/handle_message_mode(message_mode, message, verb, speaking, used_radios)
- ..()
- if(message_mode)
- if(my_headset && istype(my_headset, /obj/item/device/radio))
- my_headset.talk_into(src, message, message_mode, verb, speaking)
- used_radios += my_headset
-
-// Clicked on while holding an object.
-/mob/living/simple_mob/animal/passive/bird/parrot/attackby(obj/item/I, mob/user)
- if(istype(I, /obj/item/device/radio/headset))
- give_headset(I, user)
- return
- return ..()
-
-// Clicked on by empty hand.
-/mob/living/simple_mob/animal/passive/bird/parrot/attack_hand(mob/living/L)
- if(L.a_intent == I_GRAB && my_headset)
- remove_headset(L)
- else
- ..()
-
-
-/mob/living/simple_mob/animal/passive/bird/parrot/proc/give_headset(obj/item/device/radio/headset/new_headset, mob/living/user)
- if(!istype(new_headset))
- to_chat(user, span("warning", "\The [new_headset] isn't a headset."))
- return
- if(my_headset)
- to_chat(user, span("warning", "\The [src] is already wearing \a [my_headset]."))
- return
- else
- user.drop_item(new_headset)
- my_headset = new_headset
- new_headset.forceMove(src)
- to_chat(user, span("warning", "You place \a [new_headset] on \the [src]. You monster."))
- to_chat(src, span("notice", "\The [user] gives you \a [new_headset]. You should put it to good use immediately."))
- return
-
-/mob/living/simple_mob/animal/passive/bird/parrot/proc/remove_headset(mob/living/user)
- if(!my_headset)
- to_chat(user, "\The [src] doesn't have a headset to remove, thankfully.")
- else
- ISay("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!")
- my_headset.forceMove(get_turf(src))
- user.put_in_hands(my_headset)
- to_chat(user, span("notice", "You take away \the [src]'s [my_headset.name]. Finally."))
- to_chat(src, span("warning", "\The [user] takes your [my_headset.name] away! How cruel!"))
- my_headset = null
-
-/mob/living/simple_mob/animal/passive/bird/parrot/examine(mob/user)
- . = ..()
- if(my_headset)
- . += "It is wearing \a [my_headset]."
-
-/mob/living/simple_mob/animal/passive/bird/parrot/Initialize()
- if(my_headset)
- my_headset = new my_headset(src)
- return ..()
-
-// Subtypes.
-
-// Best Bird
-/mob/living/simple_mob/animal/passive/bird/parrot/poly
- name = "Poly"
- desc = "It's a parrot. An expert on quantum cracker theory."
- icon_state = "poly"
- icon_rest = "poly-held"
- icon_dead = "poly-dead"
- tt_desc = "E Ara macao"
- //my_headset = /obj/item/device/radio/headset/headset_eng //VOREStation Removal
- say_list_type = /datum/say_list/bird/poly
-
-// Best Bird with best headset.
-/mob/living/simple_mob/animal/passive/bird/parrot/poly/ultimate
- my_headset = /obj/item/device/radio/headset/omni
-
-/mob/living/simple_mob/animal/passive/bird/parrot/kea
- name = "kea"
- desc = "A species of parrot. On Earth, they are unique among other parrots for residing in alpine climates. \
- They are known to be intelligent and curious, which has made some consider them a pest."
- icon_state = "kea"
- icon_rest = "kea-held"
- icon_dead = "kea-dead"
- tt_desc = "E Nestor notabilis"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/eclectus
- name = "eclectus"
- desc = "A species of parrot, this species features extreme sexual dimorphism in their plumage's colors. \
- A male eclectus has emerald green plumage, where as a female eclectus has red and purple plumage."
- icon_state = "eclectus"
- icon_rest = "eclectus-held"
- icon_dead = "eclectus-dead"
- tt_desc = "E Eclectus roratus"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/eclectus/Initialize()
- gender = pick(MALE, FEMALE)
- if(gender == FEMALE)
- icon_state = "eclectusf"
- icon_rest = "eclectusf-held"
- icon_dead = "eclectusf-dead"
- return ..()
-
-/mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot
- name = "grey parrot"
- desc = "A species of parrot. This one is predominantly grey, but has red tail feathers."
- icon_state = "agrey"
- icon_rest = "agrey-held"
- icon_dead = "agrey-dead"
- tt_desc = "E Psittacus erithacus"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique
- name = "black-headed caique"
- desc = "A species of parrot, these birds have a distinct black color on their heads, distinguishing them from their relative Caiques."
- icon_state = "bcaique"
- icon_rest = "bcaique-held"
- icon_dead = "bcaique-dead"
- tt_desc = "E Pionites melanocephalus"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/white_caique
- name = "white-bellied caique"
- desc = "A species of parrot, they are also known as the Green-Thighed Parrot."
- icon_state = "wcaique"
- icon_rest = "wcaique-held"
- icon_dead = "wcaique-dead"
- tt_desc = "E Pionites leucogaster"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar
- name = "budgerigar"
- desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
- This one is has its natural colors of green and yellow."
- icon_state = "gbudge"
- icon_rest = "gbudge-held"
- icon_dead = "gbudge-dead"
- tt_desc = "E Melopsittacus undulatus"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue
- icon_state = "bbudge"
- icon_rest = "bbudge-held"
- icon_dead = "bbudge-dead"
- desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
- This one has a mutation which altered its color to be blue instead of green and yellow."
-
-/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen
- icon_state = "bgbudge"
- icon_rest = "bgbudge-held"
- icon_dead = "bgbudge-dead"
- desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
- This one has a mutation which altered its color to be a mix of blue and green."
-
-/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel
- name = "cockatiel"
- desc = "A species of parrot. This one has a highly visible crest."
- icon_state = "tiel"
- icon_rest = "tiel-held"
- icon_dead = "tiel-dead"
- tt_desc = "E Nymphicus hollandicus"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white
- icon_state = "wtiel"
- icon_rest = "wtiel-held"
- icon_dead = "wtiel-dead"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish
- icon_state = "luttiel"
- icon_rest = "luttiel-held"
- icon_dead = "luttiel-dead"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey
- icon_state = "blutiel" // idk why this is blu.
- icon_rest = "blutiel-held"
- icon_dead = "blutiel-dead"
-
-// This actually might be the yellow-crested cockatoo but idk.
-/mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo
- name = "sulphur-crested cockatoo"
- desc = "A species of parrot. This one has an expressive yellow crest. Their underwing and tail feathers are also yellow."
- icon_state = "too"
- icon_rest = "too-held"
- icon_dead = "too-dead"
- tt_desc = "E Cacatua galerita"
-
-// This was originally called 'hooded_too', which might not mean the unbrella cockatoo but idk.
-/mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo
- name = "white cockatoo"
- desc = "A species of parrot. This one is also known as the Umbrella Cockatoo, due to the semicircular shape of its crest."
- icon_state = "utoo"
- icon_rest = "utoo-held"
- icon_dead = "utoo-dead"
- tt_desc = "E Cacatua alba"
-
-/mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo
- name = "pink cockatoo"
- desc = "A species of parrot. This one is also known as Major Mitchell's cockatoo, \
- in honor of a human surveyor and explorer who existed before humans fully explored their home planet."
- icon_state = "mtoo"
- icon_rest = "mtoo-held"
- icon_dead = "mtoo-dead"
- tt_desc = "E Lophochroa leadbeateri"
-
-
-// AI
-/datum/ai_holder/simple_mob/passive/parrot
- speak_chance = 2
- base_wander_delay = 8
-
-/datum/ai_holder/simple_mob/passive/parrot/on_hear_say(mob/living/speaker, message)
- if(holder.stat || !holder.say_list || !message || speaker == holder)
- return
- var/datum/say_list/S = holder.say_list
- S.speak |= message
\ No newline at end of file
+// Parrots can talk, and may repeat things it hears.
+/mob/living/simple_mob/animal/passive/bird/parrot
+ name = "parrot"
+ description_info = "You can give it a headset by clicking on it with a headset. \
+ To remove it, click the bird while on grab intent."
+ has_langs = list("Galactic Common", "Bird")
+
+ ai_holder_type = /datum/ai_holder/simple_mob/passive/parrot
+
+ // A headset, so that talking parrots can yell at the crew over comms.
+ // If set to a type, on initialize it will be instantiated into that type.
+ var/obj/item/device/radio/headset/my_headset = null
+
+// Say list
+/datum/say_list/bird/poly
+ speak = list(
+ "Poly wanna cracker!",
+ "Check the singulo, you chucklefucks!",
+ "Wire the solars, you lazy bums!",
+ "WHO TOOK THE DAMN HARDSUITS?",
+ "OH GOD ITS FREE CALL THE SHUTTLE",
+ "Danger! Crystal hyperstructure instability!",
+ "CRYSTAL DELAMINATION IMMINENT.",
+ "Tweet tweet, I'm a Teshari.",
+ "Chitters.",
+ "Meteors have been detected on a collision course with the station!"
+ )
+
+// Lets the AI use headsets.
+// Player-controlled parrots will need to do it manually.
+/mob/living/simple_mob/animal/passive/bird/parrot/ISay(message)
+ if(my_headset && prob(50))
+ var/list/keys = list()
+ for(var/channel in my_headset.channels)
+ var/key = get_radio_key_from_channel(channel)
+ if(key)
+ keys += key
+ if(keys.len)
+ var/key_used = pick(keys)
+ return say("[key_used] [message]")
+ return say(message)
+
+// Ugly saycode so parrots can use their headsets.
+/mob/living/simple_mob/animal/passive/bird/parrot/handle_message_mode(message_mode, message, verb, speaking, used_radios)
+ ..()
+ if(message_mode)
+ if(my_headset && istype(my_headset, /obj/item/device/radio))
+ my_headset.talk_into(src, message, message_mode, verb, speaking)
+ used_radios += my_headset
+
+// Clicked on while holding an object.
+/mob/living/simple_mob/animal/passive/bird/parrot/attackby(obj/item/I, mob/user)
+ if(istype(I, /obj/item/device/radio/headset))
+ give_headset(I, user)
+ return
+ return ..()
+
+// Clicked on by empty hand.
+/mob/living/simple_mob/animal/passive/bird/parrot/attack_hand(mob/living/L)
+ if(L.a_intent == I_GRAB && my_headset)
+ remove_headset(L)
+ else
+ ..()
+
+
+/mob/living/simple_mob/animal/passive/bird/parrot/proc/give_headset(obj/item/device/radio/headset/new_headset, mob/living/user)
+ if(!istype(new_headset))
+ to_chat(user, span("warning", "\The [new_headset] isn't a headset."))
+ return
+ if(my_headset)
+ to_chat(user, span("warning", "\The [src] is already wearing \a [my_headset]."))
+ return
+ else
+ user.drop_item(new_headset)
+ my_headset = new_headset
+ new_headset.forceMove(src)
+ to_chat(user, span("warning", "You place \a [new_headset] on \the [src]. You monster."))
+ to_chat(src, span("notice", "\The [user] gives you \a [new_headset]. You should put it to good use immediately."))
+ return
+
+/mob/living/simple_mob/animal/passive/bird/parrot/proc/remove_headset(mob/living/user)
+ if(!my_headset)
+ to_chat(user, "\The [src] doesn't have a headset to remove, thankfully.")
+ else
+ ISay("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!")
+ my_headset.forceMove(get_turf(src))
+ user.put_in_hands(my_headset)
+ to_chat(user, span("notice", "You take away \the [src]'s [my_headset.name]. Finally."))
+ to_chat(src, span("warning", "\The [user] takes your [my_headset.name] away! How cruel!"))
+ my_headset = null
+
+/mob/living/simple_mob/animal/passive/bird/parrot/examine(mob/user)
+ . = ..()
+ if(my_headset)
+ . += "It is wearing \a [my_headset]."
+
+/mob/living/simple_mob/animal/passive/bird/parrot/Initialize()
+ if(my_headset)
+ my_headset = new my_headset(src)
+ return ..()
+
+// Subtypes.
+
+// Best Bird
+/mob/living/simple_mob/animal/passive/bird/parrot/poly
+ name = "Poly"
+ desc = "It's a parrot. An expert on quantum cracker theory."
+ icon_state = "poly"
+ icon_rest = "poly-held"
+ icon_dead = "poly-dead"
+ tt_desc = "E Ara macao"
+ attack_armor_pen = 20 //HE HAS THE B E A K
+ my_headset = /obj/item/device/radio/headset/headset_eng
+ say_list_type = /datum/say_list/bird/poly
+
+// Best Bird with best headset.
+/mob/living/simple_mob/animal/passive/bird/parrot/poly/ultimate
+ my_headset = /obj/item/device/radio/headset/omni
+
+/mob/living/simple_mob/animal/passive/bird/parrot/kea
+ name = "kea"
+ desc = "A species of parrot. On Earth, they are unique among other parrots for residing in alpine climates. \
+ They are known to be intelligent and curious, which has made some consider them a pest."
+ icon_state = "kea"
+ icon_rest = "kea-held"
+ icon_dead = "kea-dead"
+ tt_desc = "E Nestor notabilis"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/eclectus
+ name = "eclectus"
+ desc = "A species of parrot, this species features extreme sexual dimorphism in their plumage's colors. \
+ A male eclectus has emerald green plumage, where as a female eclectus has red and purple plumage."
+ icon_state = "eclectus"
+ icon_rest = "eclectus-held"
+ icon_dead = "eclectus-dead"
+ tt_desc = "E Eclectus roratus"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/eclectus/Initialize()
+ gender = pick(MALE, FEMALE)
+ if(gender == FEMALE)
+ icon_state = "eclectusf"
+ icon_rest = "eclectusf-held"
+ icon_dead = "eclectusf-dead"
+ return ..()
+
+/mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot
+ name = "grey parrot"
+ desc = "A species of parrot. This one is predominantly grey, but has red tail feathers."
+ icon_state = "agrey"
+ icon_rest = "agrey-held"
+ icon_dead = "agrey-dead"
+ tt_desc = "E Psittacus erithacus"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique
+ name = "black-headed caique"
+ desc = "A species of parrot, these birds have a distinct black color on their heads, distinguishing them from their relative Caiques."
+ icon_state = "bcaique"
+ icon_rest = "bcaique-held"
+ icon_dead = "bcaique-dead"
+ tt_desc = "E Pionites melanocephalus"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/white_caique
+ name = "white-bellied caique"
+ desc = "A species of parrot, they are also known as the Green-Thighed Parrot."
+ icon_state = "wcaique"
+ icon_rest = "wcaique-held"
+ icon_dead = "wcaique-dead"
+ tt_desc = "E Pionites leucogaster"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar
+ name = "budgerigar"
+ desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
+ This one is has its natural colors of green and yellow."
+ icon_state = "gbudge"
+ icon_rest = "gbudge-held"
+ icon_dead = "gbudge-dead"
+ tt_desc = "E Melopsittacus undulatus"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue
+ icon_state = "bbudge"
+ icon_rest = "bbudge-held"
+ icon_dead = "bbudge-dead"
+ desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
+ This one has a mutation which altered its color to be blue instead of green and yellow."
+
+/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen
+ icon_state = "bgbudge"
+ icon_rest = "bgbudge-held"
+ icon_dead = "bgbudge-dead"
+ desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
+ This one has a mutation which altered its color to be a mix of blue and green."
+
+/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel
+ name = "cockatiel"
+ desc = "A species of parrot. This one has a highly visible crest."
+ icon_state = "tiel"
+ icon_rest = "tiel-held"
+ icon_dead = "tiel-dead"
+ tt_desc = "E Nymphicus hollandicus"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white
+ icon_state = "wtiel"
+ icon_rest = "wtiel-held"
+ icon_dead = "wtiel-dead"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish
+ icon_state = "luttiel"
+ icon_rest = "luttiel-held"
+ icon_dead = "luttiel-dead"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey
+ icon_state = "blutiel" // idk why this is blu.
+ icon_rest = "blutiel-held"
+ icon_dead = "blutiel-dead"
+
+// This actually might be the yellow-crested cockatoo but idk.
+/mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo
+ name = "sulphur-crested cockatoo"
+ desc = "A species of parrot. This one has an expressive yellow crest. Their underwing and tail feathers are also yellow."
+ icon_state = "too"
+ icon_rest = "too-held"
+ icon_dead = "too-dead"
+ tt_desc = "E Cacatua galerita"
+
+// This was originally called 'hooded_too', which might not mean the unbrella cockatoo but idk.
+/mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo
+ name = "white cockatoo"
+ desc = "A species of parrot. This one is also known as the Umbrella Cockatoo, due to the semicircular shape of its crest."
+ icon_state = "utoo"
+ icon_rest = "utoo-held"
+ icon_dead = "utoo-dead"
+ tt_desc = "E Cacatua alba"
+
+/mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo
+ name = "pink cockatoo"
+ desc = "A species of parrot. This one is also known as Major Mitchell's cockatoo, \
+ in honor of a human surveyor and explorer who existed before humans fully explored their home planet."
+ icon_state = "mtoo"
+ icon_rest = "mtoo-held"
+ icon_dead = "mtoo-dead"
+ tt_desc = "E Lophochroa leadbeateri"
+
+
+// AI
+/datum/ai_holder/simple_mob/passive/parrot
+ speak_chance = 2
+ base_wander_delay = 8
+
+/datum/ai_holder/simple_mob/passive/parrot/on_hear_say(mob/living/speaker, message)
+ if(holder.stat || !holder.say_list || !message || speaker == holder)
+ return
+ var/datum/say_list/S = holder.say_list
+ S.speak |= message
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 9502940343..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,10 +18,12 @@
maxHealth = 100
health = 100
+ see_in_dark = 7
harm_intent_damage = 5
melee_damage_lower = 25
melee_damage_upper = 25
+ attack_armor_pen = 15 //It's a freaking alien.
attack_sharp = TRUE
attack_edge = TRUE
@@ -121,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/humanoid/mercs/mercs.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm
index c24d932a72..60532385ad 100644
--- a/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/mercs/mercs.dm
@@ -24,6 +24,7 @@
harm_intent_damage = 5
melee_damage_lower = 15 //Tac Knife damage
melee_damage_upper = 15
+ attack_armor_pen = 20
attack_sharp = 1
attack_edge = 1
attacktext = list("slashed", "stabbed")
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm
index cc16cebedc..3927b1dcf1 100644
--- a/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/pirates.dm
@@ -15,7 +15,7 @@
harm_intent_damage = 5
melee_damage_lower = 30
melee_damage_upper = 30
- attack_armor_pen = 50
+ attack_armor_pen = 30
attack_sharp = 1
attack_edge = 1
diff --git a/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm b/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm
index ce679f90de..121e112a7a 100644
--- a/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/humanoid/russian.dm
@@ -14,6 +14,7 @@
response_harm = "hits"
harm_intent_damage = 5
+ attack_armor_pen = 15
melee_damage_lower = 15
melee_damage_upper = 15
attacktext = list("punched")
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone.dm
index 7c35258a7f..6766cd67d3 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone.dm
@@ -34,9 +34,6 @@
desc = "An automated combat drone armed with state of the art weaponry and shielding."
catalogue_data = list(/datum/category_item/catalogue/technology/drone/combat_drone)
- icon = 'icons/mob/animal_vr64x64.dmi' //VOREStation Add
- pixel_x = -16 //VOREStation Add
- pixel_y = -16 //VOREStation Add
icon_state = "drone"
icon_living = "drone"
icon_dead = "drone_dead"
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone_vr.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone_vr.dm
new file mode 100644
index 0000000000..09956c1579
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/drones/combat_drone_vr.dm
@@ -0,0 +1,8 @@
+/mob/living/simple_mob/mechanical/combat_drone
+ icon = 'icons/mob/animal_vr64x64.dmi'
+
+ pixel_x = -16
+ default_pixel_x = -16
+ pixel_y = -16
+ default_pixel_y = -16
+
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/golem.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/golem.dm
index 808e5c6c38..5071f10b34 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/golem.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/golem.dm
@@ -1,152 +1,153 @@
-// The GOLEM is a spell-flinging synthetic.
-
-/mob/living/simple_mob/mechanical/technomancer_golem
- name = "unknown synthetic"
- desc = "A rather unusual looking synthetic."
- icon = 'icons/mob/mob.dmi'
- icon_state = "golem"
- health = 300
- maxHealth = 300
-
- faction = "golem"
-
- response_help = "pets"
- response_disarm = "pushes away"
- response_harm = "punches"
- harm_intent_damage = 3
- friendly = "hugs"
-
- melee_damage_lower = 30 // It has a built in esword.
- melee_damage_upper = 30
- attack_sound = 'sound/weapons/blade1.ogg'
- attacktext = list("slashed")
- melee_attack_delay = 0.5 SECONDS // Even has custom attack animations.
- ranged_attack_delay = 0.5 SECONDS
- special_attack_delay = 1 SECOND
-
- special_attack_min_range = 0
- special_attack_max_range = 7
-
- ai_holder_type = /datum/ai_holder/simple_mob/melee
-
- var/obj/item/weapon/technomancer_core/golem/core = null
- var/obj/item/weapon/spell/active_spell = null // Shield and ranged spells
- var/mob/living/master = null
- var/casting = FALSE // Used to ensure the correct animation is played. Testing if a spell exists won't always work as some spells delete themselves upon use.
-
- var/list/known_spells = list(
- "beam" = /obj/item/weapon/spell/projectile/beam,
- "chain lightning" = /obj/item/weapon/spell/projectile/chain_lightning,
- "force missile" = /obj/item/weapon/spell/projectile/force_missile,
- "ionic bolt" = /obj/item/weapon/spell/projectile/ionic_bolt,
- "lightning" = /obj/item/weapon/spell/projectile/lightning,
- "blink" = /obj/item/weapon/spell/blink,
- "dispel" = /obj/item/weapon/spell/dispel,
- "oxygenate" = /obj/item/weapon/spell/oxygenate,
- "mend life" = /obj/item/weapon/spell/modifier/mend_life,
- "mend synthetic" = /obj/item/weapon/spell/modifier/mend_synthetic,
- "mend organs" = /obj/item/weapon/spell/mend_organs,
- "purify" = /obj/item/weapon/spell/modifier/purify,
- "resurrect" = /obj/item/weapon/spell/resurrect,
- "passwall" = /obj/item/weapon/spell/passwall,
- "repel missiles" = /obj/item/weapon/spell/modifier/repel_missiles,
- "corona" = /obj/item/weapon/spell/modifier/corona,
- "haste" = /obj/item/weapon/spell/modifier/haste
- )
-
-/mob/living/simple_mob/mechanical/technomancer_golem/Initialize()
- core = new(src)
- return ..()
-
-/mob/living/simple_mob/mechanical/technomancer_golem/Destroy()
- qdel(core)
- return ..()
-
-/mob/living/simple_mob/mechanical/technomancer_golem/unref_spell()
- active_spell = null
- return ..()
-
-/mob/living/simple_mob/mechanical/technomancer_golem/death()
- ..()
- visible_message("\The [src] disintegrates!")
- new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc)
- var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- qdel(src)
-
-/mob/living/simple_mob/mechanical/technomancer_golem/place_spell_in_hand(var/path)
- if(!path || !ispath(path))
- return FALSE
- if(active_spell)
- qdel(active_spell)
-
- active_spell = new path(src)
-
-/mob/living/simple_mob/mechanical/technomancer_golem/verb/test_giving_spells()
- var/choice = input(usr, "What spell?", "Give spell") as null|anything in known_spells
- if(choice)
- place_spell_in_hand(known_spells[choice])
- else
- qdel(active_spell)
-
-/mob/living/simple_mob/mechanical/technomancer_golem/get_technomancer_core()
- return core
-
-/mob/living/simple_mob/mechanical/technomancer_golem/can_special_attack(atom/A)
- if(active_spell) // Don't bother checking everything else if no spell is ready.
- return ..()
- return FALSE
-
-/mob/living/simple_mob/mechanical/technomancer_golem/should_special_attack(atom/A)
- return instability < 50 // Don't kill ourselves by casting everything.
-
-
-/mob/living/simple_mob/mechanical/technomancer_golem/do_special_attack(atom/A)
- var/proximity = Adjacent(A)
- if(active_spell)
- if(proximity && active_spell.cast_methods & CAST_MELEE) // Use melee method if available and close enough.
- return active_spell.on_melee_cast(A, src)
- else if(active_spell.cast_methods & CAST_RANGED) // Otherwise use ranged if possible. Will also work for point-blank range.
- return active_spell.on_ranged_cast(A, src)
- return ..()
-
-/mob/living/simple_mob/mechanical/technomancer_golem/melee_pre_animation(atom/A)
- if(active_spell && active_spell.cast_methods & CAST_MELEE|CAST_RANGED) // If they're trying to melee-cast a spell, use the special animation instead.
- special_pre_animation(A)
- return
-
- flick("golem_pre_melee", src) // To force the animation to restart.
- icon_living = "golem_pre_melee" // The animation will hold after this point until melee_post_animation() gets called.
- icon_state = "golem_pre_melee"
- setClickCooldown(2)
-
-/mob/living/simple_mob/mechanical/technomancer_golem/melee_post_animation(atom/A)
- if(casting) // Some spells delete themselves when used, so we use a different variable set earlier instead.
- special_post_animation(A)
- return
-
- flick("golem_post_melee", src)
- icon_living = "golem"
- icon_state = "golem"
- setClickCooldown(6)
-
-/mob/living/simple_mob/mechanical/technomancer_golem/ranged_pre_animation(atom/A)
- flick("golem_pre_ranged", src)
- icon_living = "golem_pre_ranged"
- icon_state = "golem_pre_ranged"
- setClickCooldown(5)
-
-/mob/living/simple_mob/mechanical/technomancer_golem/ranged_post_animation(atom/A)
- flick("golem_post_ranged", src)
- icon_living = "golem"
- icon_state = "golem"
- setClickCooldown(5)
-
-/mob/living/simple_mob/mechanical/technomancer_golem/special_pre_animation(atom/A)
- casting = TRUE
- ranged_pre_animation(A) // Both have the same animation.
-
-/mob/living/simple_mob/mechanical/technomancer_golem/special_post_animation(atom/A)
- casting = FALSE
- ranged_post_animation(A)
+// The GOLEM is a spell-flinging synthetic.
+
+/mob/living/simple_mob/mechanical/technomancer_golem
+ name = "unknown synthetic"
+ desc = "A rather unusual looking synthetic."
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "golem"
+ health = 300
+ maxHealth = 300
+
+ faction = "golem"
+
+ response_help = "pets"
+ response_disarm = "pushes away"
+ response_harm = "punches"
+ harm_intent_damage = 3
+ friendly = "hugs"
+
+ melee_damage_lower = 30 // It has a built in esword.
+ melee_damage_upper = 30
+ attack_armor_pen = 20
+ attack_sound = 'sound/weapons/blade1.ogg'
+ attacktext = list("slashed")
+ melee_attack_delay = 0.5 SECONDS // Even has custom attack animations.
+ ranged_attack_delay = 0.5 SECONDS
+ special_attack_delay = 1 SECOND
+
+ special_attack_min_range = 0
+ special_attack_max_range = 7
+
+ ai_holder_type = /datum/ai_holder/simple_mob/melee
+
+ var/obj/item/weapon/technomancer_core/golem/core = null
+ var/obj/item/weapon/spell/active_spell = null // Shield and ranged spells
+ var/mob/living/master = null
+ var/casting = FALSE // Used to ensure the correct animation is played. Testing if a spell exists won't always work as some spells delete themselves upon use.
+
+ var/list/known_spells = list(
+ "beam" = /obj/item/weapon/spell/projectile/beam,
+ "chain lightning" = /obj/item/weapon/spell/projectile/chain_lightning,
+ "force missile" = /obj/item/weapon/spell/projectile/force_missile,
+ "ionic bolt" = /obj/item/weapon/spell/projectile/ionic_bolt,
+ "lightning" = /obj/item/weapon/spell/projectile/lightning,
+ "blink" = /obj/item/weapon/spell/blink,
+ "dispel" = /obj/item/weapon/spell/dispel,
+ "oxygenate" = /obj/item/weapon/spell/oxygenate,
+ "mend life" = /obj/item/weapon/spell/modifier/mend_life,
+ "mend synthetic" = /obj/item/weapon/spell/modifier/mend_synthetic,
+ "mend organs" = /obj/item/weapon/spell/mend_organs,
+ "purify" = /obj/item/weapon/spell/modifier/purify,
+ "resurrect" = /obj/item/weapon/spell/resurrect,
+ "passwall" = /obj/item/weapon/spell/passwall,
+ "repel missiles" = /obj/item/weapon/spell/modifier/repel_missiles,
+ "corona" = /obj/item/weapon/spell/modifier/corona,
+ "haste" = /obj/item/weapon/spell/modifier/haste
+ )
+
+/mob/living/simple_mob/mechanical/technomancer_golem/Initialize()
+ core = new(src)
+ return ..()
+
+/mob/living/simple_mob/mechanical/technomancer_golem/Destroy()
+ qdel(core)
+ return ..()
+
+/mob/living/simple_mob/mechanical/technomancer_golem/unref_spell()
+ active_spell = null
+ return ..()
+
+/mob/living/simple_mob/mechanical/technomancer_golem/death()
+ ..()
+ visible_message("\The [src] disintegrates!")
+ new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ qdel(src)
+
+/mob/living/simple_mob/mechanical/technomancer_golem/place_spell_in_hand(var/path)
+ if(!path || !ispath(path))
+ return FALSE
+ if(active_spell)
+ qdel(active_spell)
+
+ active_spell = new path(src)
+
+/mob/living/simple_mob/mechanical/technomancer_golem/verb/test_giving_spells()
+ var/choice = input(usr, "What spell?", "Give spell") as null|anything in known_spells
+ if(choice)
+ place_spell_in_hand(known_spells[choice])
+ else
+ qdel(active_spell)
+
+/mob/living/simple_mob/mechanical/technomancer_golem/get_technomancer_core()
+ return core
+
+/mob/living/simple_mob/mechanical/technomancer_golem/can_special_attack(atom/A)
+ if(active_spell) // Don't bother checking everything else if no spell is ready.
+ return ..()
+ return FALSE
+
+/mob/living/simple_mob/mechanical/technomancer_golem/should_special_attack(atom/A)
+ return instability < 50 // Don't kill ourselves by casting everything.
+
+
+/mob/living/simple_mob/mechanical/technomancer_golem/do_special_attack(atom/A)
+ var/proximity = Adjacent(A)
+ if(active_spell)
+ if(proximity && active_spell.cast_methods & CAST_MELEE) // Use melee method if available and close enough.
+ return active_spell.on_melee_cast(A, src)
+ else if(active_spell.cast_methods & CAST_RANGED) // Otherwise use ranged if possible. Will also work for point-blank range.
+ return active_spell.on_ranged_cast(A, src)
+ return ..()
+
+/mob/living/simple_mob/mechanical/technomancer_golem/melee_pre_animation(atom/A)
+ if(active_spell && active_spell.cast_methods & CAST_MELEE|CAST_RANGED) // If they're trying to melee-cast a spell, use the special animation instead.
+ special_pre_animation(A)
+ return
+
+ flick("golem_pre_melee", src) // To force the animation to restart.
+ icon_living = "golem_pre_melee" // The animation will hold after this point until melee_post_animation() gets called.
+ icon_state = "golem_pre_melee"
+ setClickCooldown(2)
+
+/mob/living/simple_mob/mechanical/technomancer_golem/melee_post_animation(atom/A)
+ if(casting) // Some spells delete themselves when used, so we use a different variable set earlier instead.
+ special_post_animation(A)
+ return
+
+ flick("golem_post_melee", src)
+ icon_living = "golem"
+ icon_state = "golem"
+ setClickCooldown(6)
+
+/mob/living/simple_mob/mechanical/technomancer_golem/ranged_pre_animation(atom/A)
+ flick("golem_pre_ranged", src)
+ icon_living = "golem_pre_ranged"
+ icon_state = "golem_pre_ranged"
+ setClickCooldown(5)
+
+/mob/living/simple_mob/mechanical/technomancer_golem/ranged_post_animation(atom/A)
+ flick("golem_post_ranged", src)
+ icon_living = "golem"
+ icon_state = "golem"
+ setClickCooldown(5)
+
+/mob/living/simple_mob/mechanical/technomancer_golem/special_pre_animation(atom/A)
+ casting = TRUE
+ ranged_pre_animation(A) // Both have the same animation.
+
+/mob/living/simple_mob/mechanical/technomancer_golem/special_post_animation(atom/A)
+ casting = FALSE
+ ranged_post_animation(A)
diff --git a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/hivebot.dm b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/hivebot.dm
index c90d0413be..667c514f0b 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/hivebot.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/hivebot/hivebot.dm
@@ -46,6 +46,7 @@
health = 1 LASERS_TO_KILL
melee_damage_lower = 8
melee_damage_upper = 8
+ attack_armor_pen = 5
/datum/ai_holder/simple_mob/hivebot
pointblank = TRUE
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 89281bf4fc..4545057bc6 100644
--- a/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm
+++ b/code/modules/mob/living/simple_mob/subtypes/mechanical/viscerator.dm
@@ -87,3 +87,9 @@
if(istype(L, /mob/living/simple_mob/mechanical/ward/monitor/crew)) // Also ignore friendly monitor wards
return TRUE
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
+ 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/oregrub.dm b/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm
new file mode 100644
index 0000000000..c4163733bd
--- /dev/null
+++ b/code/modules/mob/living/simple_mob/subtypes/vore/oregrub.dm
@@ -0,0 +1,173 @@
+/datum/category_item/catalogue/fauna/oregrub
+ name = "Oregrub"
+ desc = "Some form of mutated space larva, they seem to feed on minerals. This makes them the natural enemy of miners. \
+ To make matters worse, these creatures will flee when threatened. More than a few foolhardy miners have met their end chasing down oregrubs after some other hostile creature attacked them. \
+ Their guts tend to contain undigested minerals, so miners who are quick (and not afraid to get their hands dirty) can reap some rewards from these leathery lithovores."
+ value = CATALOGUER_REWARD_EASY
+
+/datum/category_item/catalogue/fauna/lavagrub
+ name = "Lavagrub"
+ desc = "Some form of mutated space larva, they seem to feed on minerals. This makes them the natural enemy of miners. \
+ To make matters worse, these creatures will flee when threatened. More than a few foolhardy miners have met their end chasing down oregrubs after some other hostile creature attacked them. \
+ This particular variant seems to be even tougher and faster than its common brown kin, and its hide is laced with silicates that make it more durable. \
+ On the plus side, it's sure to contain even more valuable minerals within its bowels, if you can catch up with it to crack it open..."
+ value = CATALOGUER_REWARD_MEDIUM
+
+/datum/ai_holder/simple_mob/oregrub
+ hostile = FALSE //docile, unless you hit them
+ retaliate = TRUE //they *may* bite you...
+ can_flee = TRUE //but they'd rather run away
+ dying_threshold = 1 //and ideally, we flee as soon as possible
+ flee_when_outmatched = TRUE //especially when outmatched
+ outmatched_threshold = 25 //and we're outmatched by... basically everything!
+
+/datum/ai_holder/simple_mob/oregrub/lava
+ outmatched_threshold = 15
+
+/mob/living/simple_mob/vore/oregrub
+ name = "juvenile oregrub"
+ desc = "A young, leathery oregrub."
+ catalogue_data = list(/datum/category_item/catalogue/fauna/oregrub)
+ icon = 'icons/mob/vore.dmi' //all of these are placeholders
+ icon_state = "oregrub"
+ icon_living = "oregrub"
+ icon_dead = "oregrub-dead"
+
+ faction = "grubs"
+ maxHealth = 50 //oregrubs are quite hardy
+ health = 50
+
+ melee_damage_lower = 1
+ melee_damage_upper = 3 //low damage, they prefer to flee
+
+ movement_cooldown = 8
+
+ meat_type = /obj/item/weapon/ore/coal
+
+ response_help = "pokes"
+ response_disarm = "pushes"
+ response_harm = "roughly pushes"
+
+ ai_holder_type = /datum/ai_holder/simple_mob/oregrub
+ say_list_type = /datum/say_list/oregrub
+
+ var/poison_per_bite = 2.5
+ var/poison_type = "thermite_v" //burn baby burn
+ var/poison_chance = 50
+
+ var/min_ore = 4
+ var/max_ore = 7
+
+ vore_bump_chance = 0 //disabled for now
+ vore_bump_emote = "applies minimal effort to try and slurp up"
+ vore_active = 0 //disabled for now
+ vore_capacity = 1
+ vore_pounce_chance = 0 //grubs only eat incapacitated targets
+ vore_default_mode = DM_DIGEST
+
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ minbodytemp = 0
+ maxbodytemp = 1000
+ poison_resist = 1.0
+
+ //these things are resilient, on account of being infused with all the minerals they eat
+ armor = list(
+ "melee" = 25,
+ "bullet" = 15,
+ "laser" = 15,
+ "energy" = 0,
+ "bomb" = 25,
+ "bio" = 100,
+ "rad" = 100
+ )
+
+/mob/living/simple_mob/vore/oregrub/lava
+ name = "mature lavagrub"
+ desc = "A mature, rocky lavagrub"
+ catalogue_data = list(/datum/category_item/catalogue/fauna/lavagrub)
+ icon_state = "lavagrub"
+ icon_living = "lavagrub"
+ icon_dead = "lavagrub-dead"
+
+ movement_cooldown = 5
+ maxHealth = 75 //lavagrubs are really hardy
+ health = 75
+ ai_holder_type = /datum/ai_holder/simple_mob/oregrub/lava
+ //lavagrubs have even more armor than oregrubs
+ armor = list(
+ "melee" = 50,
+ "bullet" = 25,
+ "laser" = 25,
+ "energy" = 0,
+ "bomb" = 50,
+ "bio" = 100,
+ "rad" = 100
+ )
+
+ var/lava_min_ore = 6
+ var/lava_max_ore = 10
+
+ poison_per_bite = 5
+ poison_chance = 66
+
+/datum/say_list/oregrub
+ emote_see = list("burbles", "chitters", "snuffles around for fresh ore")
+
+/mob/living/simple_mob/vore/oregrub/apply_melee_effects(var/atom/A)
+ if(isliving(A))
+ var/mob/living/L = A
+ var/target_zone = pick(BP_TORSO,BP_TORSO,BP_TORSO,BP_L_LEG,BP_R_LEG,BP_L_ARM,BP_R_ARM,BP_HEAD)
+ if(L.can_inject(src, null, target_zone))
+ inject_poison(L, target_zone)
+
+/mob/living/simple_mob/vore/oregrub/death()
+ visible_message("\The [src] shudders and collapses, expelling the ores it had devoured!")
+ var/i = rand(min_ore,max_ore)
+ while(i>1)
+ var/ore = pick(/obj/item/weapon/ore/glass,/obj/item/weapon/ore/coal,/obj/item/weapon/ore/iron,/obj/item/weapon/ore/lead,/obj/item/weapon/ore/marble,/obj/item/weapon/ore/phoron,/obj/item/weapon/ore/silver,/obj/item/weapon/ore/gold)
+ new ore(src.loc)
+ i--
+ ..()
+
+/mob/living/simple_mob/vore/oregrub/lava/handle_light()
+ . = ..()
+ if(. == 0 && !is_dead())
+ set_light(2.5, 1, COLOR_ORANGE)
+ return 1
+
+/mob/living/simple_mob/vore/oregrub/lava/death()
+ set_light(0)
+ var/p = rand(lava_min_ore,lava_max_ore)
+ while(p>1)
+ var/ore = pick(/obj/item/weapon/ore/osmium,/obj/item/weapon/ore/uranium,/obj/item/weapon/ore/hydrogen,/obj/item/weapon/ore/diamond,/obj/item/weapon/ore/verdantium)
+ new ore(src.loc)
+ p--
+ ..()
+
+// Does actual poison injection, after all checks passed.
+/mob/living/simple_mob/vore/oregrub/proc/inject_poison(mob/living/L, target_zone)
+ if(prob(poison_chance))
+ to_chat(L, "You feel fire running through your veins!")
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+//I'm no good at writing this stuff, so I've just left it as placeholders and disabled the chances of them eating you.
+/*
+/mob/living/simple_mob/vore/oregrub/init_vore()
+ ..()
+ var/obj/belly/B = vore_selected
+ B.name = "stomach"
+ B.desc = "PLACEHOLDER!"
+
+ B.emote_lists[DM_HOLD] = list(
+ "PLACEHOLDER!")
+
+ B.emote_lists[DM_DIGEST] = list(
+ "PLACEHOLDER!")
+*/
\ No newline at end of file
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 680021de9f..4d9a2e774a 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/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 92856d72c8..75b2ccd07f 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -390,6 +390,9 @@
/mob/proc/Post_Incorpmove()
return
+/mob/proc/get_jetpack()
+ return
+
///Process_Spacemove
///Called by /client/Move()
///For moving in space
diff --git a/code/modules/mob/new_player/sprite_accessories_vr.dm b/code/modules/mob/new_player/sprite_accessories_vr.dm
index 9e0681d490..720b72fa18 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 4768cacbae..a52f66c834 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)]