Merge pull request #12229 from Arturlang/TGUI-3.0

[READY]TGUI 3.0
This commit is contained in:
silicons
2020-07-16 17:28:42 -07:00
committed by GitHub
921 changed files with 33028 additions and 40339 deletions
+1 -1
View File
@@ -69,7 +69,7 @@
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ntnet_relay", "NTNet Quantum Relay", ui_x, ui_y, master_ui, state)
ui = new(user, src, ui_key, "NtnetRelay", "NTNet Quantum Relay", ui_x, ui_y, master_ui, state)
ui.open()
+12 -10
View File
@@ -71,22 +71,17 @@
/obj/machinery/vr_sleeper/update_icon_state()
icon_state = "[initial(icon_state)][state_open ? "-open" : ""]"
/obj/machinery/vr_sleeper/open_machine()
if(state_open)
return
if(occupant)
SStgui.close_user_uis(occupant, src)
return ..()
/obj/machinery/vr_sleeper/MouseDrop_T(mob/target, mob/user)
if(user.lying || !iscarbon(target) || !Adjacent(target) || !user.canUseTopic(src, BE_CLOSE, TRUE, NO_TK))
return
close_machine(target)
ui_interact(user)
/obj/machinery/vr_sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
/obj/machinery/vr_sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_contained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "vr_sleeper", "VR Sleeper", 475, 340, master_ui, state)
ui = new(user, src, ui_key, "VrSleeper", "VR Sleeper", 475, 340, master_ui, state)
ui.open()
/obj/machinery/vr_sleeper/ui_act(action, params)
@@ -130,11 +125,13 @@
/obj/machinery/vr_sleeper/ui_data(mob/user)
var/list/data = list()
var/is_living
if(vr_mob && !QDELETED(vr_mob))
is_living = isliving(vr_mob)
data["can_delete_avatar"] = TRUE
data["vr_avatar"] = list("name" = vr_mob.name)
data["isliving"] = istype(vr_mob)
if(data["isliving"])
data["isliving"] = is_living
if(is_living)
var/status
switch(vr_mob.stat)
if(CONSCIOUS)
@@ -146,6 +143,11 @@
if(SOFT_CRIT)
status = "Barely Conscious"
data["vr_avatar"] += list("status" = status, "health" = vr_mob.health, "maxhealth" = vr_mob.maxHealth)
else
data["can_delete_avatar"] = FALSE
data["vr_avatar"] = FALSE
data["isliving"] = FALSE
data["toggle_open"] = state_open
data["emagged"] = you_die_in_the_game_you_die_for_real
data["isoccupant"] = (user == occupant)
+1 -1
View File
@@ -62,7 +62,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/cmd_admin_check_player_exp, /* shows players by playtime */
/client/proc/toggle_combo_hud, // toggle display of the combination pizza antag and taco sci/med/eng hud
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
/client/proc/open_shuttle_manipulator, /* Opens shuttle manipulator UI */
/datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */
/client/proc/respawn_character,
/client/proc/secrets,
/client/proc/toggle_hear_radio, /*allows admins to hide all radio output*/
+1 -1
View File
@@ -36,7 +36,7 @@
/datum/borgpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.admin_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "borgopanel", "Borg Panel", 700, 700, master_ui, state)
ui = new(user, src, ui_key, "BorgPanel", "Borg Panel", 700, 700, master_ui, state)
ui.open()
/datum/borgpanel/ui_data(mob/user)
+1 -8
View File
@@ -421,7 +421,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
new_character.real_name = record_found.fields["name"]
new_character.gender = record_found.fields["gender"]
new_character.age = record_found.fields["age"]
new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"])
new_character.hardset_dna(record_found.fields["identity"], record_found.fields["enzymes"], null, record_found.fields["name"], record_found.fields["blood_type"], new record_found.fields["species"], record_found.fields["features"])
else
var/datum/preferences/A = new()
A.copy_to(new_character)
@@ -1058,13 +1058,6 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
var/datum/atom_hud/A = GLOB.huds[ANTAG_HUD_TRAITOR]
return A.hudusers[mob]
/client/proc/open_shuttle_manipulator()
set category = "Admin"
set name = "Shuttle Manipulator"
set desc = "Opens the shuttle manipulator UI."
for(var/obj/machinery/shuttle_manipulator/M in GLOB.machines)
M.ui_interact(usr)
/client/proc/run_weather()
set category = "Fun"
+76
View File
@@ -0,0 +1,76 @@
/datum/admins/proc/open_shuttlepanel()
set category = "Admin"
set name = "Shuttle Manipulator"
set desc = "Opens the shuttle manipulator UI."
if(!check_rights(R_ADMIN))
return
SSshuttle.ui_interact(usr)
/obj/docking_port/mobile/proc/admin_fly_shuttle(mob/user)
var/list/options = list()
for(var/port in SSshuttle.stationary)
if (istype(port, /obj/docking_port/stationary/transit))
continue // please don't do this
var/obj/docking_port/stationary/S = port
if (canDock(S) == SHUTTLE_CAN_DOCK)
options[S.name || S.id] = S
options += "--------"
options += "Infinite Transit"
options += "Delete Shuttle"
options += "Into The Sunset (delete & greentext 'escape')"
var/selection = input(user, "Select where to fly [name || id]:", "Fly Shuttle") as null|anything in options
if(!selection)
return
switch(selection)
if("Infinite Transit")
destination = null
mode = SHUTTLE_IGNITING
setTimer(ignitionTime)
if("Delete Shuttle")
if(alert(user, "Really delete [name || id]?", "Delete Shuttle", "Cancel", "Really!") != "Really!")
return
jumpToNullSpace()
if("Into The Sunset (delete & greentext 'escape')")
if(alert(user, "Really delete [name || id] and greentext escape objectives?", "Delete Shuttle", "Cancel", "Really!") != "Really!")
return
intoTheSunset()
else
if(options[selection])
request(options[selection])
/obj/docking_port/mobile/emergency/admin_fly_shuttle(mob/user)
return // use the existing verbs for this
/obj/docking_port/mobile/arrivals/admin_fly_shuttle(mob/user)
switch(alert(user, "Would you like to fly the arrivals shuttle once or change its destination?", "Fly Shuttle", "Fly", "Retarget", "Cancel"))
if("Cancel")
return
if("Fly")
return ..()
var/list/options = list()
for(var/port in SSshuttle.stationary)
if (istype(port, /obj/docking_port/stationary/transit))
continue // please don't do this
var/obj/docking_port/stationary/S = port
if (canDock(S) == SHUTTLE_CAN_DOCK)
options[S.name || S.id] = S
var/selection = input(user, "Select the new arrivals destination:", "Fly Shuttle") as null|anything in options
if(!selection)
return
target_dock = options[selection]
if(!QDELETED(target_dock))
destination = target_dock
@@ -23,6 +23,7 @@ GLOBAL_LIST_EMPTY(antagonists)
var/show_name_in_check_antagonists = FALSE //Will append antagonist name in admin listings - use for categories that share more than one antag type
var/list/blacklisted_quirks = list(/datum/quirk/nonviolent,/datum/quirk/mute) // Quirks that will be removed upon gaining this antag. Pacifist and mute are default.
var/threat = 0 // Amount of threat this antag poses, for dynamic mode
var/show_to_ghosts = FALSE // Should this antagonist be shown as antag to ghosts? Shouldn't be used for stealthy antagonists like traitors
var/list/skill_modifiers
@@ -7,6 +7,7 @@
job_rank = ROLE_ABDUCTOR
show_in_antagpanel = FALSE //should only show subtypes
threat = 5
show_to_ghosts = TRUE
var/datum/team/abductor_team/team
var/sub_role
var/outfit
+1
View File
@@ -2,6 +2,7 @@
name = "Blob"
roundend_category = "blobs"
antagpanel_category = "Blob"
show_to_ghosts = TRUE
job_rank = ROLE_BLOB
threat = 20
var/datum/action/innate/blobpop/pop_action
@@ -16,7 +16,7 @@
/datum/cellular_emporium/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "cellular_emporium", name, 900, 480, master_ui, state)
ui = new(user, src, ui_key, "CellularEmporium", name, 900, 480, master_ui, state)
ui.open()
/datum/cellular_emporium/ui_data(mob/user)
@@ -38,10 +38,11 @@
set_slab.update_quickbind()
/proc/generate_all_scripture()
if(!GLOB.all_scripture.len)
for(var/V in sortList(subtypesof(/datum/clockwork_scripture), /proc/cmp_clockscripture_priority))
var/datum/clockwork_scripture/S = new V
GLOB.all_scripture[S.type] = S
if(GLOB.all_scripture.len)
return
for(var/V in sortList(subtypesof(/datum/clockwork_scripture) - list(/datum/clockwork_scripture/channeled, /datum/clockwork_scripture/create_object, /datum/clockwork_scripture/create_object/construct), /proc/cmp_clockscripture_priority))
var/datum/clockwork_scripture/S = new V
GLOB.all_scripture[S.type] = S
//changes construction value
/proc/change_construction_value(amount)
@@ -1,7 +1,7 @@
/obj/item/clockwork/slab //Clockwork slab: The most important tool in Ratvar's arsenal. Allows scripture recital, tutorials, and generates components.
name = "clockwork slab"
desc = "A strange metal tablet. A clock in the center turns around and around."
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.<br>\
clockwork_desc = "A link between you and the Celestial Derelict. It contains information, recites scripture, and is your most vital tool as a Servant.\
It can be used to link traps and triggers by attacking them with the slab. Keep in mind that traps linked with one another will activate in tandem!"
icon_state = "dread_ipad"
@@ -15,16 +15,19 @@
var/busy //If the slab is currently being used by something
var/no_cost = FALSE //If the slab is admin-only and needs no components and has no scripture locks
var/speed_multiplier = 1 //multiples how fast this slab recites scripture
var/selected_scripture = SCRIPTURE_DRIVER
// var/selected_scripture = SCRIPTURE_DRIVER //handled UI side
var/obj/effect/proc_holder/slab/slab_ability //the slab's current bound ability, for certain scripture
var/recollecting = FALSE //if we're looking at fancy recollection
var/recollecting = TRUE //if we're looking at fancy recollection. tutorial enabled by default
var/recollection_category = "Default"
var/list/quickbound = list(/datum/clockwork_scripture/abscond, \
/datum/clockwork_scripture/ranged_ability/kindle, /datum/clockwork_scripture/ranged_ability/hateful_manacles) //quickbound scripture, accessed by index
var/maximum_quickbound = 5 //how many quickbound scriptures we can have
var/ui_x = 800
var/ui_z = 420
var/obj/structure/destructible/clockwork/trap/linking //If we're linking traps together, which ones we're doing
/obj/item/clockwork/slab/internal //an internal motor for mobs running scripture
@@ -146,8 +149,8 @@
if(!quickbound[i])
continue
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
. += "<b>Quickbind</b> button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>."
. += "<b>Available power:</b> <span class='bold brass'>[DisplayPower(get_clockwork_power())].</span>"
. += "Quickbind button: <span class='[get_component_span(initial(quickbind_slot.primary_component))]'>[initial(quickbind_slot.name)]</span>."
. += "Available power: <span class='bold brass'>[DisplayPower(get_clockwork_power())].</span>"
//Slab actions; Hierophant, Quickbind
/obj/item/clockwork/slab/ui_action_click(mob/user, action)
@@ -165,18 +168,19 @@
user.emote("scream")
user.apply_damage(5, BURN, BODY_ZONE_L_ARM)
user.apply_damage(5, BURN, BODY_ZONE_R_ARM)
return 0
return FALSE
if(!is_servant_of_ratvar(user))
to_chat(user, "<span class='warning'>The information on [src]'s display shifts rapidly. After a moment, your head begins to pound, and you tear your eyes away.</span>")
user.confused += 5
user.dizziness += 5
return 0
if(user.confused || user.dizziness)
user.confused += 5
user.dizziness += 5
return FALSE
if(busy)
to_chat(user, "<span class='warning'>[src] refuses to work, displaying the message: \"[busy]!\"</span>")
return 0
return FALSE
if(!no_cost && !can_recite_scripture(user))
to_chat(user, "<span class='nezbere'>[src] hums fitfully in your hands, but doesn't seem to do anything...</span>")
return 0
return FALSE
access_display(user)
/obj/item/clockwork/slab/AltClick(mob/living/user)
@@ -195,9 +199,7 @@
/obj/item/clockwork/slab/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "clockwork_slab", name, 800, 420, master_ui, state)
ui.set_autoupdate(FALSE) //we'll update this occasionally, but not as often as possible
ui.set_style("clockwork")
ui = new(user, src, ui_key, "ClockworkSlab", name, ui_x, ui_z, master_ui, state)
ui.open()
/obj/item/clockwork/slab/proc/recite_scripture(datum/clockwork_scripture/scripture, mob/living/user)
@@ -207,10 +209,12 @@
to_chat(user, "<span class='warning'>You need to hold the slab in your active hand to recite scripture!</span>")
return FALSE
var/initial_tier = initial(scripture.tier)
if(initial_tier != SCRIPTURE_PERIPHERAL)
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier])
to_chat(user, "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>")
return FALSE
if(initial_tier == SCRIPTURE_PERIPHERAL)
to_chat(user, "<span class='warning'>Nice try using href exploits</span>")
return
if(!GLOB.ratvar_awakens && !no_cost && !SSticker.scripture_states[initial_tier])
to_chat(user, "<span class='warning'>That scripture is not unlocked, and cannot be recited!</span>")
return FALSE
var/datum/clockwork_scripture/scripture_to_recite = new scripture
scripture_to_recite.slab = src
scripture_to_recite.invoker = user
@@ -218,26 +222,6 @@
return TRUE
//Guide to Serving Ratvar
/obj/item/clockwork/slab/proc/recollection()
var/list/textlist = list("If you're seeing this, file a bug report.")
if(GLOB.ratvar_awakens)
textlist = list("<font color=#BE8700 size=3><b>")
for(var/i in 1 to 100)
textlist += "HONOR RATVAR "
textlist += "</b></font>"
else
textlist = list("<font color=#BE8700 size=3><b><center>[text2ratvar("Purge all untruths and honor Engine.")]</center></b></font><br>\
\
<b><i>NOTICE:</b> This information is out of date. Read the Ark & You primer in your backpack or read the wiki page for current info.</i><br>\
<hr><br>\
These pages serve as the archives of Ratvar, the Clockwork Justiciar. This section of your slab has information on being as a Servant, advice for what to do next, and \
pointers for serving the master well. You should recommended that you check this area for help if you get stuck or need guidance on what to do next.<br><br>\
\
<i>Disclaimer: Many objects, terms, and phrases, such as Servant, Cache, and Slab, are capitalized like proper nouns. This is a quirk of the Ratvarian language; \
do not let it confuse you! You are free to use the names in pronoun form when speaking in normal languages.<br>")
return textlist.Join()
//Gets text for a certain section. "Default" is used for when you first open Recollection.
//Current sections (make sure to update this if you add one:
//- Basics
@@ -246,255 +230,93 @@
//- Scripture
//- Power
//- Conversion
/obj/item/clockwork/slab/proc/get_recollection_text(section)
var/list/dat = list()
switch(section)
if("Default")
dat += "You can browse the above sections as you please. They're designed to be read in order, but feel free to pick and choose between them."
if("Getting Started")
dat += "<font color=#BE8700 size=3>Getting Started</font><br><br>"
dat += "Welcome, Servant! This section houses the utmost basics of being a Servant of Ratvar, and is much more informal than the other sections. Being a Servant of \
Ratvar is a very complex role, with many systems, objects, and resources to use effectively and creatively.<br><br>"
dat += "This section of your clockwork slab covers everything that Servants have to be aware of, but is a long read because of how in-depth the systems are. Knowing \
how to use the tools at your disposal makes all the difference between a clueless Servant and a great one.<br><br>"
dat += "If this is your first time being a Servant, relax. It's very much possible that you'll fail, but it's impossible to learn without making mistakes. For the time \
being, use the Hierophant Network button in the top left-hand corner of your screen to try and get in touch with your fellow Servants; ignore the others for now. This button \
will let you send messages across space and time to all other Servants. This makes it great for coordinating, and you should use it often! <i>Note:</i> Using \
this will cause you to whisper your message aloud, so doing so in a public place is very suspicious and you should try to restrict it to private use.<br><br>"
dat += "If you aren't willing or don't have the time to read through every section, you can still help your teammates! Ask if they've set up a base. If they have, head there \
and ask however you can help; chances are there's always something. If not, it's your job as a Servant to get one up and running! Try to find a secluded, low-traffic area, \
like the auxiliary base or somewhere deep in maintenance. You'll want to go into the Drivers section of the slab and look for <i>Tinkerer's Cache.</i> Find a nice spot and \
create one. This serves as a storage for <i>components,</i> the cult's primary resource. (Your slab's probably produced a few by now.) By attacking that cache with this \
slab, you'll offload all your components into it, and all Servants will be able to use those components from any distance - all Tinkerer's Caches are linked!<br><br>"
dat += "Once you have a base up and running, contact your fellows and let them know. You should come back here often to drop off the slab's components, and your fellows \
should do the same, either in this cache or in ones of their own.<br><br>"
dat += "If you think you're confident in taking further steps to help the cult, feel free to move onto the other sections. If not, let your allies know that you're new and \
would appreciate the help they might offer you. Most experienced Servants would be happy to help; if everyone is inexperienced, then you'll have to step out of your comfort \
zone and read onto the other sections. It's very likely that you might fail, but don't worry too much about it; you can't learn effectively without making mistakes.<br><br>"
dat += "For now, welcome! If you're looking to learn, you should start with the <b>Basics</b> section, then move onto <b>Components</b> and <b>Scripture</b>. At the very \
least, you should read the <b><i>Conversion</i></b> section, as it outlines the most important aspects of being a Servant. Good luck!<br><br>"
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
if("Basics")
dat += "<font color=#BE8700 size=3>Servant Basics</font><br><br>"
dat += "The first thing any Servant should know is their slab, inside and out. The clockwork slab is by far your most important tool. It allows you to speak with your \
fellow Servants, create components that fuel many of your abilities, use those abilities, and should be kept safe and hidden on your person at all times. If you have not \
done so already, it's a good idea to check for any fellow Servants using the Hierophant Network button in the top-left corner of your screen; due to the cult's nature, \
teamwork is an instrumental component of your success.<br><br>" //get it? component? ha!
dat += "As a Servant of Ratvar, the tools you are given focus around building and maintaining bases and outposts. A great deal of your power comes from stationary \
structures, and without constructing a base somewhere, it's essentially impossible to succeed. Finding a good spot to build a base can be difficult, and it's recommended \
that you choose an area in low-traffic part of the station (such as the auxiliary base). Make sure to disconnect any cameras in the area beforehand.<br><br>"
dat += "Because of how complex being a Servant is, it isn't possible to fit much information into this section. It's highly recommended that you read the <b>Components</b> \
and <b>Scripture</b> sections next. Not knowing how these two systems work will cripple both you and your fellows, and lead to a frustrating experience for everyone.<br><br>"
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
if("Terminology")
dat += "<font color=#BE8700 size=3>Common Servant Terminology</font><br>"
dat += "<i>This isn't intended to be read all at once; you are advised to treat it moreso as a glossary.</i><br><br>"
dat += "<font color=#BE8700 size=3>General</font><br>"
dat += "<font color=#BE8700><b>Servant:</b></font> A person or robot who serves Ratvar. You are one of these.<br>"
dat += "<font color=#BE8700><b>Cache:</b></font> A <i>Tinkerer's Cache</i>, which is a structure that stores and creates components.<br>"
dat += "<font color=#BE8700><b>CV:</b></font> Construction Value. All clockwork structures, floors, and walls increase this number.<br>"
dat += "<font color=#BE8700><b>Vitality:</b></font> Used for healing effects, produced by Ratvarian spear attacks and Vitality Matrices.<br>"
dat += "<font color=#BE8700><b>Geis:</b></font> An important scripture used to make normal crew and robots into Servants of Ratvar.<br>"
dat += "<font color=#BE8700><b>Ark:</b></font> The cult's win condition, a huge structure that needs to be defended.<br><br>"
dat += "<font color=#BE8700 size=3>Items</font><br>"
dat += "<font color=#BE8700><b>Slab:</b></font> A clockwork slab, a Servant's most important tool. You're holding one! Keep it safe and hidden.<br>"
dat += "<font color=#BE8700><b>Visor:</b></font> A judicial visor, which is a pair of glasses that can smite an area for a brief stun and delayed explosion.<br>"
dat += "<font color=#BE8700><b>Wraith Specs:</b></font> Wraith spectacles, which provide true sight (X-ray, night vision) but damage the wearer's eyes.<br>"
dat += "<font color=#BE8700><b>Spear:</b></font> A Ratvarian spear, which is a very powerful melee weapon that produces Vitality.<br>"
dat += "<font color=#BE8700><b>Fabricator:</b></font> A replica fabricator, which converts objects into clockwork versions.<br><br>"
dat += "<font color=#BE8700 size=3>Constructs</font><br>"
dat += "<font color=#BE8700><b>Marauder:</b></font> A clockwork marauder, which is a powerful bodyguard that hides in its owner.<br><br>"
dat += "<font color=#BE8700 size=3>Structures (* = requires power)</font><br>"
dat += "<font color=#BE8700><b>Warden:</b></font> An ocular warden, which is a ranged turret that damages non-Servants that see it.<br>"
dat += "<font color=#BE8700><b>Prism*:</b></font> A prolonging prism, which delays the shuttle for two minutes at a huge power cost.<br><br>"
dat += "<font color=#BE8700><b>Motor*:</b></font> A mania motor, which serves as area-denial through negative effects and eventual conversion.<br>"
dat += "<font color=#BE8700><b>Daemon*:</b></font> A tinkerer's daemon, which quickly creates components.<br>"
dat += "<font color=#BE8700><b>Obelisk*:</b></font> A clockwork obelisk, which can broadcast large messages and allows limited teleportation.<br>"
dat += "<font color=#BE8700 size=3>Sigils</font><br>"
dat += "<i>Note: Sigils can be stacked on top of one another, making certain sigils very effective when paired!</i><br>"
dat += "<font color=#BE8700><b>Transgression:</b></font> Stuns the first non-Servant to cross it for ten seconds and blinds others nearby. Disappears on use.<br>"
dat += "<font color=#BE8700><b>Submission:</b></font> Converts the first non-Servant to stand on the sigil for seven seconds. Disappears on use.<br>"
dat += "<font color=#BE8700><b>Matrix:</b></font> Drains health from non-Servants, producing Vitality. Can heal and revive Servants.<br>"
dat += "<font color=#BE8700><b>Accession:</b></font> Identical to the Sigil of Submission, but doesn't disappear on use. It can also convert a single mindshielded target, but will disappear after doing this.<br>"
dat += "<font color=#BE8700><b>Transmission:</b></font> Drains and stores power for clockwork structures. Feeding it brass sheets will create additional power.<br><br>"
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
if("Components")
dat += "<font color=#BE8700 size=3>Components & Their Uses</font><br><br>"
dat += "<b>Components</b> are your primary resource as a Servant. There are five types of component, with each one being used in different roles:<br><br>"
dat += "Although this is a good rule of thumb, their effects become much more nuanced when used together. For instance, a turret might have both belligerent eyes and \
vanguard cogwheels as construction requirements, because it defends its allies by harming its enemies.<br><br>"
dat += "Components' primary use is fueling <b>scripture</b> (covered in its own section), and they can be created through various ways. This clockwork slab, for instance, \
will make a random component of every type - or a specific one, if you choose a target component from the interface - every <b>remove me already</b>. This number will increase \
as the amount of Servants in the covenant increase; additionally, slabs can only produce components when held by a Servant, and holding more than one slab will cause both \
of them to halt progress until one of them is removed from their person.<br><br>"
dat += "Your slab has an internal storage of components, but it isn't meant to be the main one. Instead, there's a <b>global storage</b> of components that can be \
added to through various ways. Anything that needs components will first draw them from the global storage before attempting to draw them from the slab. Most methods of \
component production add to the global storage. You can also offload components from your slab into the global storage by using it on a Tinkerer's Cache, a structure whose \
primary purpose is to do just that (although it will also slowly produce components when placed near a brass wall.)<br><br>"
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
if("Scripture")
dat += "<font color=#BE8700 size=3>The Ancient Scripture</font><br><br>"
dat += "If you have experience with the Nar'Sian cult (or the \"blood cult\") then you will know of runes. They are the manifestations of the Geometer's power, and where most \
of the cult's supernatural ability comes from. The Servant equivalent of runes is called <b>scripture</b>, and unlike runes, scripture is loaded into your clockwork slab.<br><br>"
dat += "Each piece of scripture has widely-varying effects. Your most important scripture, <i>Geis</i>, is obvious and suspicious, but charges your slab with energy and allows \
you to attack a non-Servant in melee range to restrain them and begin converting them into a Servant. This is just one example; each piece of scripture can be simple or \
complex, be obvious or have hidden mechanics that can only be found through trial and error.<br><br>"
dat += "Any given piece of scripture has a component cost listed in its \"Recite\" button. The acronyms for the components should be obvious if you've read about components \
already; reciting this piece of scripture will consume the listed components, first from the global storage and then from your slab. Note that failing to recite a piece of \
scripture will <i>not</i> consume the components required to recite it.<br><br>"
dat += "It should also be noted that some scripture cannot be recited alone. Especially with more powerful scripture, you may need multiple Servants to recite a piece of \
scripture; both of you will need to stand still until the recital completes. <i>Only human and silicon Servants are valid for scripture recital!</i> Constructs cannot help \
in reciting scripture.<br><br>"
dat += "Finally, scripture is separated into three \"tiers\" based on power: Drivers, Scripts, and Applications.[prob(1) ? " (The Revenant tier was removed a long time ago. \
Get with the times.)" : ""] You can view the requirements to unlock each tier in its scripture list. Once a tier is unlocked, it's unlocked permanently; the cult only needs to fill the \
requirement for unlocking a tier once!<br><br>"
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
if("Power")
dat += "<font color=#BE8700 size=3>Power! Unlimited Power!</font><br><br>"
dat += "In the early stages of the cult, the only resource that must be actively worried about is components. However, as new scripture is unlocked, a new resource \
becomes necessary: <b>power</b>. Almost all clockwork structures require power to function in some way. There is nothing special about this power; it's mere electricity, \
and can be harnessed in several ways.<br><br>"
dat += "To begin with, if there is no other source of power nearby, structures will draw from the area's APC, assuming it has one. This is inefficient and ill-advised as \
anything but a last resort. Instead, it is recommended that a <b>Sigil of Transmission</b> is created. This sigil serves as both battery and power generator for nearby clockwork \
structures, and those structures will happily draw power from the sigil before they resort to APCs.<br><br>"
dat += "Generating power is less easy. The most reliable and efficient way is using brass sheets; attacking a sigil of transmission with brass sheets will convert them \
to power, at a rate of <b>[DisplayPower(POWER_FLOOR)]</b> per sheet. (Brass sheets are created from replica fabricators, which are explained more in detail in the <b>Conversion</b> section.) \
Activating a sigil of transmission will also cause it to drain power from the nearby area, which, while effective, serves as an obvious tell that there is something wrong.<br><br>"
dat += "Without power, many structures will not function, making a base vulnerable to attack. For this reason, it is critical that you keep an eye on your power reserves and \
ensure that they remain comfortably high.<br><br>"
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
if("Conversion")
dat += "<font color=#BE8700 size=3>Growing the Ranks</font><br><br>"
dat += "Because the Servants of Ratvar are a cult, the main method to gain more power is to \"enlighten\" normal crew into new Servants. When a crewmember is converted, \
they become a full-fledged Servant, ready and willing to serve the cause of Ratvar. It should also be noted that <i>silicon crew, such as cyborgs and the AI, can be \
converted just like normal crew</i> and will gain special abilities; this is covered later. This section will also cover converting the station's structure itself; walls, \
floors, windows, tables, and other objects can all be converted into clockwork versions, and serve an important purpose.<br><br>"
dat += "<font color=#BE8700><b>A Note on Geis:</b></font> There are several ways to convert humans and silicons. However, the most important tool to making them work is \
<b>Geis</b>, a Driver-tier scripture. Using it whispers an invocation very quickly and charges your slab with power. In addition to <i>making the slab visible in your hand,</i> \
you can now use it on a target within melee range to bind and mute them. It is by far your most reliable tool for capturing potential converts and targets, though it is incredibly \
obvious. In addition, you are unable to take any actions other than moving while your target is bound. The binding will last for 25 seconds and mute for about 13 seconds, though \
allies can use Geis to refresh these effects.<br><br>"
dat += "<font color=#BE8700><b>Converting:</b></font> The two methods of conversion are the <b>sigil of submission</b>, whose purpose is to do so, and the <b>mania motor.</b> \
The sigil of submission is a sigil that, when stood on by a non-Servant for eight seconds, will convert that non-Servant. This is the only practical way to convert targets. \
Sigils of submission are cheap, early, and permanent! Make sure sigils of submission are placed only in bases or otherwise hidden spots, or with a sigil of transgression on them. \
The mania motor, however, is generally unreliable and unlocked later, only converting those who stand near it for an extended period.<br><br>"
dat += "<font color=#BE8700><b>Converting Humans:</b></font> For obvious reasons, humans are the most common conversion target. Because every crew member is different, and \
may be armed with different equipment, you should take precautions to ensure that they aren't able to resist. If able, removing a headset is essential, as is restraining \
them through handcuffs, cable ties, or other restraints. Some crew, like security, are also implanted with mindshield implants; these will prevent conversion and must be \
surgically removed before they are an eligible convert. <i>Note:</i> The captain is <i>never</i> an eligible convert and should instead be killed or imprisoned. If security \
begins administering mindshield implants, this will greatly inhibit conversion. Also note that mindshield implants can be broken by a sigil of accession automatically, but \
the sigil will disappear.<br><br>"
dat += "<font color=#BE8700><b>Converting Silicons:</b></font> Due to their robotic nature, silicons are generally more predictable than humans in terms of conversion. \
However, they are also much, much harder to subdue, especially cyborgs. The easiest way to convert a cyborg is by using Geis to restrain them, then dragging them to a sigil \
of submission. If you stack a sigil of transgression and a sigil of submission, a crossing cyborg will be stunned and helpless to escape before they are converted.<br><br>"
dat += "Converting AIs is very often the hardest task of the cult, and has been the downfall of countless successful Servants. Their omnipresence across the station, \
coupled with their secure location and ability to lock themselves securely, makes them a powerful target. However, once the AI itself is reached, it is usually completely \
helpless to resist its own conversion. A very common tactic is to take advantage of a converted cyborg to rush the AI before it is able to react.<br><br>"
dat += "Even once an AI is converted, care must be taken to ensure that it remains hidden. Not only does the AI's core become brassy and thus obvious to an outside \
observer, but <i>the AI loses the ability to speak in anything but Ratvarian.</i> For this reason, it has to remain completely silent over common radio channels if stealth \
is at all a priority. This is suspicious and will rapidly lead to the crew checking on it, which usually results in the cult's outing. It is, however, necessary to convert \
all AIs present on the station before the Ark becomes invokable, so this must be done at some point.<br><br>"
dat += "<font color=#BE8700><b>Converting the Station:</b></font> Converted objects all serve a purpose and are important to the cult's success. To convert objects, \
a Servant needs to use a <b>replica fabricator,</b> a handheld tool that uses power to replace objects with clockwork versions. Different clockwork objects have different \
effects and are often crucial. The most noteworthy are <b>clockwork walls,</b> which automatically \"link\" to any nearby Tinkerer's Caches, causing them to <b>slowly \
generate components.</b> This is incredibly useful for obvious reasons, and creating a clockwork wall near every Tinkerer's Cache should be prioritized. Clockwork floors \
will slowly heal any toxin damage suffered by Servants standing on them, and clockwork airlocks can only be opened by Servants.<br><br>"
dat += "The replica fabricator itself is also worth noting. In addition to replacing objects, it can also create brass sheets at the cost of power by using the \
fabricator in-hand. It can also be used to repair any damaged clockwork structures.<br><br>"
dat += "Replacing objects is almost as, if not as important as, converting new Servants. A base is impossible to manage without clockwork walls at the very least, and \
once the cult has been outed and the crew are actively searching, there is little reason not to use as many as possible.<br><br>"
dat += "<font color=#BE8700 size=3>-=-=-=-=-=-</font>"
else
dat += "<font color=#BE8700 size=3>404: [section ? section : "Section"] Not Found!</font><br><br>\
One of the cogscarabs must've misplaced this section, because the game wasn't able to find any info regarding it. Report this to the coders!"
return "<br><br>[dat.Join()]<br><br>"
//Gets the quickbound scripture as a text block.
/obj/item/clockwork/slab/proc/get_recollection_quickbinds()
var/list/dat = list()
dat += "<font color=#BE8700 size=3>Quickbound Scripture</font><br>\
<i>You can have up to five scriptures bound to action buttons for easy use.</i><br><br>"
if(LAZYLEN(quickbound))
for(var/i in 1 to maximum_quickbound)
if(LAZYLEN(quickbound) < i || !quickbound[i])
dat += "A <b>Quickbind</b> slot, currently set to <b><font color=#BE8700>Nothing</font></b>.<br>"
else
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
dat += "A <b>Quickbind</b> slot, currently set to <b><font color=[get_component_color_bright(initial(quickbind_slot.primary_component))]>[initial(quickbind_slot.name)]</font></b>.<br>"
return dat.Join()
/obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI
var/list/data = list()
data["power"] = "<b><font color=#B18B25>[DisplayPower(get_clockwork_power())]</b> power is available for scripture and other consumers.</font>"
switch(selected_scripture) //display info based on selected scripture tier
if(SCRIPTURE_DRIVER)
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
if(SCRIPTURE_SCRIPT)
if(SSticker.scripture_states[SCRIPTURE_SCRIPT])
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
else
data["tier_info"] = "<font color=#B18B25><i>These scriptures will automatically unlock when the Ark is halfway ready or if [DisplayPower(SCRIPT_UNLOCK_THRESHOLD)] of power is reached.</i></font>"
if(SCRIPTURE_APPLICATION)
if(SSticker.scripture_states[SCRIPTURE_APPLICATION])
data["tier_info"] = "<font color=#B18B25><b>These scriptures are permanently unlocked.</b></font>"
else
data["tier_info"] = "<font color=#B18B25><i>Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached..</i></font>"
data["selected"] = selected_scripture
data["scripturecolors"] = "<font color=#DAAA18>Scriptures in <b>yellow</b> are related to construction and building.</font><br>\
<font color=#6E001A>Scriptures in <b>red</b> are related to attacking and offense.</font><br>\
<font color=#1E8CE1>Scriptures in <b>blue</b> are related to healing and defense.</font><br>\
<font color=#AF0AAF>Scriptures in <b>purple</b> are niche but still important!</font><br>\
<font color=#DAAA18><i>Scriptures with italicized names are important to success.</i></font>"
generate_all_scripture()
data["scripture"] = list()
. = list()
.["recollection"] = recollecting
.["power"] = DisplayPower(get_clockwork_power())
.["power_unformatted"] = get_clockwork_power()
// .["rec_text"] = recollection() handled TGUI side
.["HONOR_RATVAR"] = GLOB.ratvar_awakens
.["scripture"] = list()
for(var/s in GLOB.all_scripture)
var/datum/clockwork_scripture/S = GLOB.all_scripture[s]
if(S.tier == selected_scripture) //display only scriptures of the selected tier
var/scripture_color = get_component_color_bright(S.primary_component)
var/list/temp_info = list("name" = "<font color=[scripture_color]><b>[S.name]</b></font>",
"descname" = "<font color=[scripture_color]>([S.descname])</font>",
"tip" = "[S.desc]\n[S.usage_tip]",
"required" = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])",
"type" = "[S.type]",
"quickbind" = S.quickbind)
if(S.important)
temp_info["name"] = "<i>[temp_info["name"]]</i>"
var/found = quickbound.Find(S.type)
if(found)
temp_info["bound"] = "<b>[found]</b>"
if(S.invokers_required > 1)
temp_info["invokers"] = "<font color=#B18B25>Invokers: <b>[S.invokers_required]</b></font>"
data["scripture"] += list(temp_info)
data["recollection"] = recollecting
if(recollecting)
data["recollection_categories"] = GLOB.ratvar_awakens ? list() : list(\
list("name" = "Getting Started", "desc" = "First-time servant? Read this first."), \
list("name" = "Basics", "desc" = "A primer on how to play as a servant."), \
list("name" = "Terminology", "desc" = "Common acronyms, words, and terms."), \
list("name" = "Components", "desc" = "Information on components, your primary resource."), \
list("name" = "Scripture", "desc" = "Information on scripture, ancient tools used by the cult."), \
list("name" = "Power", "desc" = "The power system that certain objects use to function."), \
list("name" = "Conversion", "desc" = "Converting the crew, cyborgs, and very walls to your cause."), \
)
data["rec_text"] = recollection()
data["rec_section"] = GLOB.ratvar_awakens ? "" : get_recollection_text(recollection_category)
data["rec_binds"] = GLOB.ratvar_awakens ? "" : get_recollection_quickbinds()
return data
if(S.tier == SCRIPTURE_PERIPHERAL) //yes, tiers are the tabs.
continue
var/list/data = list()
data["name"] = S.name
data["descname"] = S.descname
data["tip"] = "[S.desc]\n[S.usage_tip]"
data["required"] = "([DisplayPower(S.power_cost)][S.special_power_text ? "+ [replacetext(S.special_power_text, "POWERCOST", "[DisplayPower(S.special_power_cost)]")]" : ""])"
data["required_unformatted"] = S.power_cost
data["type"] = "[S.type]"
data["quickbind"] = S.quickbind //this is if it cant quickbind
data["fontcolor"] = get_component_color_bright(S.primary_component)
data["important"] = S.important //italic!
var/found = quickbound.Find(S.type)
if(found)
data["bound"] = found //number (pos) on where is it on the list
if(S.invokers_required > 1)
data["invokers"] = "Invokers: [S.invokers_required]"
.["rec_binds"] = list()
for(var/i in 1 to maximum_quickbound)
if(GLOB.ratvar_awakens)
return
if(LAZYLEN(quickbound) < i || !quickbound[i])
.["rec_binds"] += list(list())
else
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
.["rec_binds"] += list(list(
"name" = initial(quickbind_slot.name),
"color" = get_component_color_bright(initial(quickbind_slot.primary_component))
))
.["scripture"][S.tier] += list(data)
/obj/item/clockwork/slab/ui_static_data(mob/user)
. = list()
.["tier_infos"] = list()
.["tier_infos"][SCRIPTURE_DRIVER] = list(
"requirement" = "None, this is already unlocked",
"ready" = TRUE //to bold it on JS side, and to say "These scriptures are permanently unlocked."
)
.["tier_infos"][SCRIPTURE_SCRIPT] = list(
"requirement" = "These scriptures will automatically unlock when the Ark is halfway ready or if [DisplayPower(SCRIPT_UNLOCK_THRESHOLD)] of power is reached.",
"ready" = SSticker.scripture_states[SCRIPTURE_SCRIPT] //huh, on the gamemode ticker? okay...
)
.["tier_infos"][SCRIPTURE_APPLICATION] = list(
"requirement" = "Unlock these optional scriptures by converting another servant or if [DisplayPower(APPLICATION_UNLOCK_THRESHOLD)] of power is reached..",
"ready" = SSticker.scripture_states[SCRIPTURE_APPLICATION]
)
// .["selected"] = selected_scripture
generate_all_scripture()
.["recollection_categories"] = GLOB.ratvar_awakens ? list() : list(
list("name" = "Getting Started", "desc" = "First-time servant? Read this first."),
list("name" = "Basics", "desc" = "A primer on how to play as a servant."),
list("name" = "Terminology", "desc" = "Common acronyms, words, and terms."),
list("name" = "Components", "desc" = "Information on components, your primary resource."),
list("name" = "Scripture", "desc" = "Information on scripture, ancient tools used by the cult."),
list("name" = "Power", "desc" = "The power system that certain objects use to function."),
list("name" = "Conversion", "desc" = "Converting the crew, cyborgs, and very walls to your cause.")
)
// .["rec_section"]["title"] //this is here if ever we decided to return these back.
// .["rec_section"]["info"]// wall of info for the thing
/obj/item/clockwork/slab/ui_act(action, params)
switch(action)
if("toggle")
recollecting = !recollecting
if("recite")
INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["category"]), usr, FALSE)
if("select")
selected_scripture = params["category"]
INVOKE_ASYNC(src, .proc/recite_scripture, text2path(params["script"]), usr, FALSE)
if("bind")
var/datum/clockwork_scripture/path = text2path(params["category"]) //we need a path and not a string
var/datum/clockwork_scripture/path = text2path(params["script"]) //we need a path and not a string
if(!ispath(path, /datum/clockwork_scripture) || !initial(path.quickbind) || initial(path.tier) == SCRIPTURE_PERIPHERAL) //fuck you href bus
to_chat(usr, "<span class='warning'>Nice try using href exploits</span>")
return
var/found_index = quickbound.Find(path)
if(found_index) //hey, we already HAVE this bound
if(LAZYLEN(quickbound) == found_index) //if it's the last scripture, remove it instead of leaving a null
@@ -512,8 +334,8 @@
quickbind_to_slot(path, target_index)
if("rec_category")
recollection_category = params["category"]
ui_interact(usr)
return 1
update_static_data()
return TRUE
/obj/item/clockwork/slab/proc/quickbind_to_slot(datum/clockwork_scripture/scripture, index) //takes a typepath(typecast for initial()) and binds it to a slot
if(!ispath(scripture) || !scripture || (scripture in quickbound))
+1
View File
@@ -92,6 +92,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
threat = 5
show_to_ghosts = TRUE
var/obligation
var/ban
var/bane
@@ -2,6 +2,7 @@
name = "Sentient Disease"
roundend_category = "diseases"
antagpanel_category = "Disease"
show_to_ghosts = TRUE
var/disease_name = ""
/datum/antagonist/disease/on_gain()
+1
View File
@@ -12,6 +12,7 @@
var/list/name_source
threat = -5
show_in_antagpanel = FALSE
show_to_ghosts = TRUE
antag_moodlet = /datum/mood_event/focused
/datum/antagonist/ert/on_gain()
@@ -9,6 +9,7 @@
roundend_category = "monkeys"
antagpanel_category = "Monkey"
threat = 3
show_to_ghosts = TRUE
var/datum/team/monkey/monkey_team
var/monkey_only = TRUE
@@ -3,3 +3,4 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
threat = 5
show_to_ghosts = TRUE
+1
View File
@@ -3,6 +3,7 @@
antagpanel_category = "Ninja"
job_rank = ROLE_NINJA
show_name_in_check_antagonists = TRUE
show_to_ghosts = TRUE
antag_moodlet = /datum/mood_event/focused
threat = 8
var/helping_station = FALSE
@@ -7,6 +7,9 @@
density = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
ui_x = 350
ui_y = 442
var/timer_set = 90
var/default_timer_set = 90
var/minimum_timer_set = 90
@@ -262,8 +265,7 @@
/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key="main", datum/tgui/ui=null, force_open=0, datum/tgui/master_ui=null, datum/ui_state/state=GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "nuclear_bomb", name, 350, 442, master_ui, state)
ui.set_style(ui_style)
ui = new(user, src, ui_key, "NuclearBomb", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/nuclearbomb/ui_data(mob/user)
@@ -6,6 +6,7 @@
antag_moodlet = /datum/mood_event/focused
threat = 10
skill_modifiers = list(/datum/skill_modifier/job/level/wiring)
show_to_ghosts = TRUE
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
@@ -4,6 +4,7 @@
show_in_antagpanel = FALSE
var/datum/objective/mission
var/datum/team/ert/ert_team
show_to_ghosts = TRUE
/datum/antagonist/official/greet()
to_chat(owner, "<B><font size=3 color=red>You are a CentCom Official.</font></B>")
@@ -4,6 +4,7 @@
roundend_category = "space pirates"
antagpanel_category = "Pirate"
threat = 5
show_to_ghosts = TRUE
var/datum/team/pirate/crew
/datum/antagonist/pirate/greet()
@@ -3,6 +3,7 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
threat = 5
show_to_ghosts = TRUE
/datum/antagonist/revenant/greet()
owner.announce_objectives()
+2
View File
@@ -1,6 +1,8 @@
/datum/antagonist/santa
name = "Santa"
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
show_to_ghosts = TRUE
/datum/antagonist/santa/on_gain()
. = ..()
@@ -6,6 +6,7 @@
threat = 10
job_rank = ROLE_ALIEN
show_in_antagpanel = FALSE
show_to_ghosts = TRUE
/datum/antagonist/slaughter/on_gain()
forge_objectives()
@@ -1,4 +1,4 @@
// Support unit gets it's own very basic antag datum for admin logging.
/// Support unit gets it's own very basic antag datum for admin logging.
/datum/antagonist/traitor/contractor_support
name = "Contractor Support Unit"
antag_moodlet = /datum/mood_event/focused
@@ -8,11 +8,13 @@
should_equip = FALSE /// Don't give them an uplink.
var/datum/team/contractor_team/contractor_team
/datum/team/contractor_team // Team for storing both the contractor and their support unit - only really for the HUD and admin logging.
/// Team for storing both the contractor and their support unit - only really for the HUD and admin logging.
/datum/team/contractor_team
show_roundend_report = FALSE
/datum/antagonist/traitor/contractor_support/forge_traitor_objectives()
var/datum/objective/generic_objective = new
generic_objective.name = "Follow Contractor's Orders"
generic_objective.explanation_text = "Follow your orders. Assist agents in this mission area."
generic_objective.completed = TRUE
@@ -25,7 +27,9 @@
var/static/list/contractor_items = typecacheof(/datum/contractor_item/, TRUE)
var/datum/syndicate_contract/current_contract
var/list/datum/syndicate_contract/assigned_contracts = list()
var/list/assigned_targets = list() // used as a blacklist to make sure we're not assigning targets already assigned
var/contracts_completed = 0
var/contract_TC_payed_out = 0 // Keeping track for roundend reporting
var/contract_TC_to_redeem = 0 // Used internally and roundend reporting - what TC we have available to cashout.
@@ -34,7 +38,8 @@
var/datum/contractor_item/contractor_item = new path
hub_items.Add(contractor_item)
/datum/contractor_hub/proc/create_contracts(datum/mind/owner) // 6 initial contracts
/datum/contractor_hub/proc/create_contracts(datum/mind/owner)
// 6 initial contracts
var/list/to_generate = list(
CONTRACT_PAYOUT_LARGE,
CONTRACT_PAYOUT_MEDIUM,
@@ -44,61 +49,74 @@
CONTRACT_PAYOUT_SMALL
)
var/lowest_TC_threshold = 30 // We don't want the sum of all the payouts to be under this amount
//What the fuck
if(length(to_generate) > length(GLOB.data_core.locked))
to_generate.Cut(1, length(GLOB.data_core.locked))
// We don't want the sum of all the payouts to be under this amount
var/lowest_TC_threshold = 30
var/total = 0
var/lowest_paying_sum = 0
var/datum/syndicate_contract/lowest_paying_contract
to_generate = shuffle(to_generate) // Randomise order, so we don't have contracts always in payout order.
var/start_index = 1 // Support contract generation happening multiple times
if(assigned_contracts.len != 0)
// Randomise order, so we don't have contracts always in payout order.
to_generate = shuffle(to_generate)
// Support contract generation happening multiple times
var/start_index = 1
if (assigned_contracts.len != 0)
start_index = assigned_contracts.len + 1
for(var/i = 1; i <= to_generate.len; i++) // Generate contracts, and find the lowest paying.
// Generate contracts, and find the lowest paying.
for (var/i = 1; i <= to_generate.len; i++)
var/datum/syndicate_contract/contract_to_add = new(owner, assigned_targets, to_generate[i])
var/contract_payout_total = contract_to_add.contract.payout + contract_to_add.contract.payout_bonus
assigned_targets.Add(contract_to_add.contract.target)
if(!lowest_paying_contract || (contract_payout_total < lowest_paying_sum))
if (!lowest_paying_contract || (contract_payout_total < lowest_paying_sum))
lowest_paying_sum = contract_payout_total
lowest_paying_contract = contract_to_add
total += contract_payout_total
contract_to_add.id = start_index
assigned_contracts.Add(contract_to_add)
start_index++
if(total < lowest_TC_threshold) // If the threshold for TC payouts isn't reached, boost the lowest paying contract
// If the threshold for TC payouts isn't reached, boost the lowest paying contract
if (total < lowest_TC_threshold)
lowest_paying_contract.contract.payout_bonus += (lowest_TC_threshold - total)
/datum/contractor_item
var/name // Name of item
var/desc // description of item
var/item // item path, no item path means the purchase needs it's own handle_purchase()
var/item_icon = "fa-broadcast-tower" // fontawesome icon to use inside the hub - https://fontawesome.com/icons/
var/item_icon = "broadcast-tower" // fontawesome icon to use inside the hub - https://fontawesome.com/icons/
var/limited = -1 // Any number above 0 for how many times it can be bought in a round for a single traitor. -1 is unlimited.
var/cost // Cost of the item in contract rep.
/datum/contractor_item/contract_reroll
name = "Contract Reroll"
desc = "Request a reroll of your current contract list. Will generate a new target, payment, and dropoff for the contracts you currently have available."
item_icon = "fa-dice"
item_icon = "dice"
limited = 2
cost = 0
/datum/contractor_item/contract_reroll/handle_purchase(var/datum/contractor_hub/hub)
. = ..()
if (.)
var/list/new_target_list = list() // We're not regenerating already completed/aborted/extracting contracts, but we don't want to repeat their targets.
/// We're not regenerating already completed/aborted/extracting contracts, but we don't want to repeat their targets.
var/list/new_target_list = list()
for(var/datum/syndicate_contract/contract_check in hub.assigned_contracts)
if (contract_check.status != CONTRACT_STATUS_ACTIVE && contract_check.status != CONTRACT_STATUS_INACTIVE)
if (contract_check.contract.target)
new_target_list.Add(contract_check.contract.target)
continue
for(var/datum/syndicate_contract/rerolling_contract in hub.assigned_contracts) // Reroll contracts without duplicates
/// Reroll contracts without duplicates
for(var/datum/syndicate_contract/rerolling_contract in hub.assigned_contracts)
if (rerolling_contract.status != CONTRACT_STATUS_ACTIVE && rerolling_contract.status != CONTRACT_STATUS_INACTIVE)
continue
rerolling_contract.generate(new_target_list)
new_target_list.Add(rerolling_contract.contract.target)
hub.assigned_targets = new_target_list // Set our target list with the new set we've generated.
/// Set our target list with the new set we've generated.
hub.assigned_targets = new_target_list
/datum/contractor_item/contractor_pinpointer
name = "Contractor Pinpointer"
desc = "A pinpointer that finds targets even without active suit sensors. Due to taking advantage of an exploit within the system, it can't pinpoint to the same accuracy as the traditional models. Becomes permanently locked to the user that first activates it."
@@ -125,20 +143,25 @@
/datum/contractor_item/contractor_partner/handle_purchase(var/datum/contractor_hub/hub, mob/living/user)
. = ..()
if (.)
to_chat(user, "<span class='notice'>The uplink vibrates quietly, connecting to nearby agents...</span>")
var/list/mob/candidates = pollGhostCandidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_CONTRACTOR_SUPPORT)
var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_CONTRACTOR_SUPPORT)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
spawn_contractor_partner(user, C.key)
else
to_chat(user, "<span class='notice'>No available agents at this time, please try again later.</span>")
limited += 1 // refund and add the limit back.
// refund and add the limit back.
limited += 1
hub.contract_rep += cost
hub.purchased_items -= src
/datum/outfit/contractor_partner
name = "Contractor Support Unit"
uniform = /obj/item/clothing/under/chameleon
suit = /obj/item/clothing/suit/chameleon
back = /obj/item/storage/backpack
@@ -148,28 +171,35 @@
ears = /obj/item/radio/headset/chameleon
id = /obj/item/card/id/syndicate
r_hand = /obj/item/storage/toolbox/syndicate
backpack_contents = list(/obj/item/storage/box/survival, /obj/item/implanter/uplink, /obj/item/clothing/mask/chameleon,
/obj/item/storage/fancy/cigarettes/cigpack_syndicate, /obj/item/lighter)
/datum/outfit/contractor_partner/post_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
var/obj/item/clothing/mask/cigarette/syndicate/cig = H.get_item_by_slot(SLOT_WEAR_MASK)
cig.light() // pre-light their cig for extra badass
var/obj/item/clothing/mask/cigarette/syndicate/cig = H.get_item_by_slot(ITEM_SLOT_MASK)
// pre-light their cig
cig.light()
/datum/contractor_item/contractor_partner/proc/spawn_contractor_partner(mob/living/user, key)
var/mob/living/carbon/human/partner = new()
var/datum/outfit/contractor_partner/partner_outfit = new()
partner_outfit.equip(partner)
var/obj/structure/closet/supplypod/arrival_pod = new()
arrival_pod.style = STYLE_SYNDICATE
arrival_pod.explosionSize = list(0,0,0,1)
arrival_pod.bluespace = TRUE
var/turf/free_location = find_obstruction_free_location(2, user)
if (!free_location) // We really want to send them - if we can't find a nice location just land it on top of them.
// We really want to send them - if we can't find a nice location just land it on top of them.
if (!free_location)
free_location = get_turf(user)
partner.forceMove(arrival_pod)
partner.ckey = key
partner_mind = partner.mind // We give a reference to the mind that'll be the support unit
/// We give a reference to the mind that'll be the support unit
partner_mind = partner.mind
partner_mind.make_Contractor_Support()
to_chat(partner_mind.current, "\n<span class='alertwarning'>[user.real_name] is your superior. Follow any, and all orders given by them. You're here to support their mission only.</span>")
to_chat(partner_mind.current, "<span class='alertwarning'>Should they perish, or be otherwise unavailable, you're to assist other active agents in this mission area to the best of your ability.</span>\n\n")
@@ -186,7 +216,7 @@
. = ..()
if (.)
power_fail(35, 50)
priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", "poweroff")
priority_announce("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure", "poweroff.ogg")
// Subtract cost, and spawn if it's an item.
/datum/contractor_item/proc/handle_purchase(var/datum/contractor_hub/hub, mob/living/user)
@@ -199,6 +229,7 @@
else if (limited == 0)
return FALSE
hub.purchased_items.Add(src)
user.playsound_local(user, 'sound/machines/uplinkpurchase.ogg', 100)
if (item && ispath(item))
var/atom/item_to_create = new item(get_turf(user))
@@ -4,47 +4,70 @@
var/datum/objective/contract/contract = new()
var/target_rank
var/ransom = 0
var/payout_type = null
var/payout_type
var/wanted_message
var/list/victim_belongings = list()
/datum/syndicate_contract/New(contract_owner, blacklist, type=CONTRACT_PAYOUT_SMALL)
contract.owner = contract_owner
payout_type = type
generate(blacklist)
/datum/syndicate_contract/proc/generate(blacklist)
contract.find_target(null, blacklist)
var/datum/data/record/record = find_record("name", contract.target.name, GLOB.data_core.general)
if(record)
var/datum/data/record/record
if (contract.target)
record = find_record("name", contract.target.name, GLOB.data_core.general)
if (record)
target_rank = record.fields["rank"]
else
target_rank = "Unknown"
if (payout_type == CONTRACT_PAYOUT_LARGE)
contract.payout_bonus = rand(9,13)
else if(payout_type == CONTRACT_PAYOUT_MEDIUM)
else if (payout_type == CONTRACT_PAYOUT_MEDIUM)
contract.payout_bonus = rand(6,8)
else
contract.payout_bonus = rand(2,4)
contract.payout = rand(0, 2)
contract.generate_dropoff()
ransom = 100 * rand(18, 45)
var/base = pick_list(WANTED_FILE, "basemessage")
var/verb_string = pick_list(WANTED_FILE, "verb")
var/noun = pick_list_weighted(WANTED_FILE, "noun")
var/location = pick_list_weighted(WANTED_FILE, "location")
wanted_message = "[base] [verb_string] [noun] [location]."
/datum/syndicate_contract/proc/handle_extraction(var/mob/living/user)
if (contract.target && contract.dropoff_check(user, contract.target.current))
var/turf/free_location = find_obstruction_free_location(3, user, contract.dropoff)
if(free_location) // We've got a valid location, launch.
if (free_location)
// We've got a valid location, launch.
launch_extraction_pod(free_location)
return TRUE
return FALSE
// Launch the pod to collect our victim.
/datum/syndicate_contract/proc/launch_extraction_pod(turf/empty_pod_turf)
var/obj/structure/closet/supplypod/extractionpod/empty_pod = new()
RegisterSignal(empty_pod, COMSIG_ATOM_ENTERED, .proc/enter_check)
empty_pod.stay_after_drop = TRUE
empty_pod.reversing = TRUE
empty_pod.explosionSize = list(0,0,0,1)
empty_pod.leavingSound = 'sound/effects/podwoosh.ogg'
new /obj/effect/abstract/DPtarget(empty_pod_turf, empty_pod)
/datum/syndicate_contract/proc/enter_check(datum/source, sent_mob)
@@ -52,37 +75,55 @@
if(isliving(sent_mob))
var/mob/living/M = sent_mob
var/datum/antagonist/traitor/traitor_data = contract.owner.has_antag_datum(/datum/antagonist/traitor)
if(M == contract.target.current)
traitor_data.contractor_hub.contract_TC_to_redeem += contract.payout
traitor_data.contractor_hub.contracts_completed += 1
if(M.stat != DEAD)
traitor_data.contractor_hub.contract_TC_to_redeem += contract.payout_bonus
status = CONTRACT_STATUS_COMPLETE
if(traitor_data.contractor_hub.current_contract == src)
traitor_data.contractor_hub.current_contract = null
traitor_data.contractor_hub.contract_rep += 2
else
status = CONTRACT_STATUS_ABORTED // Sending a target that wasn't even yours is as good as just aborting it
if(traitor_data.contractor_hub.current_contract == src)
traitor_data.contractor_hub.current_contract = null
if(iscarbon(M))
for(var/obj/item/W in M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(W == H.w_uniform || W == H.shoes)
continue //So all they're left with are shoes and uniform.
if(W == H.w_uniform)
continue //So all they're left with are shoes and uniform.
if(W == H.shoes)
continue
M.transferItemToLoc(W)
victim_belongings.Add(W)
var/obj/structure/closet/supplypod/extractionpod/pod = source
pod.send_up(pod) // Handle the pod returning
// Handle the pod returning
pod.send_up(pod)
if(ishuman(M))
var/mob/living/carbon/human/target = M // After we remove items, at least give them what they need to live.
var/mob/living/carbon/human/target = M
// After we remove items, at least give them what they need to live.
target.dna.species.give_important_for_life(target)
handleVictimExperience(M) // After pod is sent we start the victim narrative/heal.
var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR)
var/points_to_check = min(D.account_balance, ransom)
D.adjust_money(min(points_to_check, ransom))
priority_announce("One of your crew was captured by a rival organisation - we've needed to pay their ransom to bring them back. \
As is policy we've taken a portion of the station's funds to offset the overall cost.", null, "attention", null, "Nanotrasen Asset Protection")
As is policy we've taken a portion of the station's funds to offset the overall cost.", null, "attention", null, "Nanotrasen Asset Protection")
sleep(30)
@@ -128,13 +169,18 @@
M.Dizzy(15)
M.confused += 20
/datum/syndicate_contract/proc/returnVictim(var/mob/living/M) // We're returning the victim
// We're returning the victim
/datum/syndicate_contract/proc/returnVictim(var/mob/living/M)
var/list/possible_drop_loc = list()
for(var/turf/possible_drop in contract.dropoff.contents)
if(!is_blocked_turf(possible_drop))
possible_drop_loc.Add(possible_drop)
if(!isspaceturf(possible_drop) && !isclosedturf(possible_drop))
if(!is_blocked_turf(possible_drop))
possible_drop_loc.Add(possible_drop)
if(possible_drop_loc.len > 0)
var/pod_rand_loc = rand(1, possible_drop_loc.len)
var/obj/structure/closet/supplypod/return_pod = new()
return_pod.bluespace = TRUE
return_pod.explosionSize = list(0,0,0,0)
@@ -144,8 +190,10 @@
for(var/obj/item/W in M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(W == H.w_uniform || W == H.shoes)
if(W == H.w_uniform)
continue //So all they're left with are shoes and uniform.
if(W == H.shoes)
continue
M.dropItemToGround(W)
for(var/obj/item/W in victim_belongings)
W.forceMove(return_pod)
@@ -13,6 +13,7 @@
var/move_to_lair = TRUE
var/outfit_type = /datum/outfit/wizard
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
show_to_ghosts = TRUE
/datum/antagonist/wizard/on_gain()
register()
+1
View File
@@ -12,6 +12,7 @@
name = "Xenomorph"
job_rank = ROLE_ALIEN
show_in_antagpanel = FALSE
show_to_ghosts = TRUE
var/datum/team/xeno/xeno_team
threat = 3
+6 -37
View File
@@ -4,7 +4,6 @@
icon_state = "health"
custom_materials = list(/datum/material/iron=800, /datum/material/glass=200)
attachable = TRUE
secured = FALSE
var/scanning = FALSE
var/health_scan
@@ -12,7 +11,8 @@
/obj/item/assembly/health/examine(mob/user)
. = ..()
. += "<span class='notice'>Use a multitool to swap between \"detect death\" mode and \"detect critical state\" mode.</span>"
. += "Use it in hand to turn it off/on and Alt-click to swap between \"detect death\" mode and \"detect critical state\" mode."
. += "[src.scanning ? "The sensor is on and you can see [health_scan] displayed on the screen" : "The sensor is off"]."
/obj/item/assembly/health/activate()
if(!..())
@@ -30,14 +30,13 @@
update_icon()
return secured
/obj/item/assembly/health/multitool_act(mob/living/user, obj/item/I)
/obj/item/assembly/health/AltClick(mob/living/user)
if(alarm_health == HEALTH_THRESHOLD_CRIT)
alarm_health = HEALTH_THRESHOLD_DEAD
to_chat(user, "<span class='notice'>You toggle [src] to \"detect death\" mode.</span>")
else
alarm_health = HEALTH_THRESHOLD_CRIT
to_chat(user, "<span class='notice'>You toggle [src] to \"detect critical state\" mode.</span>")
return TRUE
/obj/item/assembly/health/process()
if(!scanning || !secured)
@@ -46,7 +45,6 @@
var/atom/A = src
if(connected && connected.holder)
A = connected.holder
for(A, A && !ismob(A), A=A.loc);
// like get_turf(), but for mobs.
var/mob/living/M = A
@@ -71,36 +69,7 @@
STOP_PROCESSING(SSobj, src)
return
/obj/item/assembly/health/ui_interact(mob/user as mob)//TODO: Change this to the wires thingy
/obj/item/assembly/health/attack_self(mob/user)
. = ..()
if(!secured)
user.show_message("<span class='warning'>The [name] is unsecured!</span>")
return FALSE
var/dat = "<TT><B>Health Sensor</B></TT>"
dat += "<BR><A href='?src=[REF(src)];scanning=1'>[scanning?"On":"Off"]</A>"
if(scanning && health_scan)
dat += "<BR>Health: [health_scan]"
user << browse(dat, "window=hscan")
onclose(user, "hscan")
/obj/item/assembly/health/Topic(href, href_list)
..()
if(!ismob(usr))
return
var/mob/user = usr
if(!user.canUseTopic(src))
usr << browse(null, "window=hscan")
onclose(usr, "hscan")
return
if(href_list["scanning"])
toggle_scan()
if(href_list["close"])
usr << browse(null, "window=hscan")
return
attack_self(user)
return
to_chat(user, "<span class='notice'>You toggle [src] [src.scanning ? "off" : "on"].</span>")
toggle_scan()
+40 -38
View File
@@ -4,7 +4,8 @@
icon_state = "infrared"
custom_materials = list(/datum/material/iron=1000, /datum/material/glass=500)
is_position_sensitive = TRUE
var/ui_x = 225
var/ui_y = 110
var/on = FALSE
var/visible = FALSE
var/maxlength = 8
@@ -38,7 +39,7 @@
/obj/item/assembly/infra/activate()
if(!..())
return FALSE//Cooldown check
return FALSE //Cooldown check
on = !on
refreshBeam()
update_icon()
@@ -69,7 +70,7 @@
holder.update_icon()
return
/obj/item/assembly/infra/dropped(mob/user)
/obj/item/assembly/infra/dropped()
. = ..()
if(holder)
holder_movement() //sync the dir of the device as well if it's contained in a TTV or an assembly holder
@@ -133,7 +134,7 @@
. = ..()
setDir(t)
/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
/obj/item/assembly/infra/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE)
. = ..()
olddir = dir
@@ -176,55 +177,56 @@
return
return refreshBeam()
/obj/item/assembly/infra/ui_interact(mob/user)//TODO: change this this to the wire control panel
. = ..()
if(is_secured(user))
user.set_machine(src)
var/dat = "<TT><B>Infrared Laser</B></TT>"
dat += "<BR><B>Status</B>: [on ? "<A href='?src=[REF(src)];state=0'>On</A>" : "<A href='?src=[REF(src)];state=1'>Off</A>"]"
dat += "<BR><B>Visibility</B>: [visible ? "<A href='?src=[REF(src)];visible=0'>Visible</A>" : "<A href='?src=[REF(src)];visible=1'>Invisible</A>"]"
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
user << browse(dat, "window=infra")
onclose(user, "infra")
return
/obj/item/assembly/infra/Topic(href, href_list)
..()
if(usr.incapacitated() || !in_range(loc, usr))
usr << browse(null, "window=infra")
onclose(usr, "infra")
return
if(href_list["state"])
on = !(on)
update_icon()
refreshBeam()
if(href_list["visible"])
visible = !(visible)
update_icon()
refreshBeam()
if(href_list["close"])
usr << browse(null, "window=infra")
return
if(usr)
attack_self(usr)
/obj/item/assembly/infra/setDir()
. = ..()
refreshBeam()
/obj/item/assembly/infra/ui_status(mob/user)
if(is_secured(user))
return ..()
return UI_CLOSE
/obj/item/assembly/infra/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "InfraredEmitter", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/item/assembly/infra/ui_data(mob/user)
var/list/data = list()
data["on"] = on
data["visible"] = visible
return data
/obj/item/assembly/infra/ui_act(action, params)
if(..())
return
switch(action)
if("power")
on = !on
. = TRUE
if("visibility")
visible = !visible
. = TRUE
update_icon()
refreshBeam()
/***************************IBeam*********************************/
/obj/effect/beam/i_beam
name = "infrared beam"
icon = 'icons/obj/projectiles.dmi'
icon_state = "ibeam"
var/obj/item/assembly/infra/master
anchored = TRUE
density = FALSE
pass_flags = PASSTABLE|PASSGLASS|PASSGRILLE|LETPASSTHROW
var/obj/item/assembly/infra/master
/obj/effect/beam/i_beam/Crossed(atom/movable/AM as mob|obj)
. = ..()
if(istype(AM, /obj/effect/beam))
return
if (isitem(AM))
+44 -50
View File
@@ -4,7 +4,8 @@
icon_state = "prox"
custom_materials = list(/datum/material/iron=800, /datum/material/glass=200)
attachable = TRUE
var/ui_x = 250
var/ui_y = 185
var/scanning = FALSE
var/timing = FALSE
var/time = 10
@@ -26,7 +27,7 @@
/obj/item/assembly/prox_sensor/activate()
if(!..())
return FALSE//Cooldown check
return FALSE //Cooldown check
if(!scanning)
timing = !timing
else
@@ -41,7 +42,6 @@
else
proximity_monitor.SetHost(src,src)
/obj/item/assembly/prox_sensor/toggle_secure()
secured = !secured
if(!secured)
@@ -56,8 +56,6 @@
update_icon()
return secured
/obj/item/assembly/prox_sensor/HasProximity(atom/movable/AM as mob|obj)
if (istype(AM, /obj/effect/beam))
return
@@ -75,7 +73,6 @@
next_activate = world.time + 30
return TRUE
/obj/item/assembly/prox_sensor/process()
if(!timing)
return
@@ -111,50 +108,47 @@
holder.update_icon()
return
/obj/item/assembly/prox_sensor/ui_interact(mob/user)//TODO: Change this to the wires thingy
. = ..()
/obj/item/assembly/prox_sensor/ui_status(mob/user)
if(is_secured(user))
var/second = time % 60
var/minute = (time - second) / 60
var/dat = "<TT><B>Proximity Sensor</B></TT>"
if(!scanning)
dat += "<BR>[(timing ? "<A href='?src=[REF(src)];time=0'>Arming</A>" : "<A href='?src=[REF(src)];time=1'>Not Arming</A>")] [minute]:[second]"
dat += "<BR><A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>"
dat += "<BR><A href='?src=[REF(src)];scanning=[scanning?"0'>Armed":"1'>Unarmed (Movement sensor active when armed!)"]</A>"
dat += "<BR>Detection range: <A href='?src=[REF(src)];sense=down'>-</A> [sensitivity] <A href='?src=[REF(src)];sense=up'>+</A>"
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
user << browse(dat, "window=prox")
onclose(user, "prox")
return ..()
return UI_CLOSE
/obj/item/assembly/prox_sensor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ProximitySensor", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/item/assembly/prox_sensor/ui_data(mob/user)
var/list/data = list()
data["seconds"] = round(time % 60)
data["minutes"] = round((time - data["seconds"]) / 60)
data["timing"] = timing
data["scanning"] = scanning
data["sensitivity"] = sensitivity
return data
/obj/item/assembly/prox_sensor/ui_act(action, params)
if(..())
return
/obj/item/assembly/prox_sensor/Topic(href, href_list)
..()
if(usr.incapacitated() || !in_range(loc, usr))
usr << browse(null, "window=prox")
onclose(usr, "prox")
return
if(href_list["sense"])
sensitivity_change(((href_list["sense"] == "up") ? 1 : -1))
if(href_list["scanning"])
toggle_scan(text2num(href_list["scanning"]))
if(href_list["time"])
timing = text2num(href_list["time"])
update_icon()
if(href_list["tp"])
var/tp = text2num(href_list["tp"])
time += tp
time = min(max(round(time), 0), 600)
if(href_list["close"])
usr << browse(null, "window=prox")
return
if(usr)
attack_self(usr)
switch(action)
if("scanning")
toggle_scan(!scanning)
. = TRUE
if("sense")
var/value = text2num(params["range"])
if(value)
sensitivity_change(value)
. = TRUE
if("time")
timing = !timing
update_icon()
. = TRUE
if("input")
var/value = text2num(params["adjust"])
if(value)
value = round(time + value)
time = clamp(value, 0, 600)
. = TRUE
+11 -8
View File
@@ -8,7 +8,8 @@
custom_materials = list(/datum/material/iron=400, /datum/material/glass=120)
wires = WIRE_RECEIVE | WIRE_PULSE | WIRE_RADIO_PULSE | WIRE_RADIO_RECEIVE
attachable = TRUE
var/ui_x = 280
var/ui_y = 132
var/code = DEFAULT_SIGNALER_CODE
var/frequency = FREQ_SIGNALER
var/datum/radio_frequency/radio_connection
@@ -47,14 +48,16 @@
holder.update_icon()
return
/obj/item/assembly/signaler/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
if(!is_secured(user))
return
/obj/item/assembly/signaler/ui_status(mob/user)
if(is_secured(user))
return ..()
return UI_CLOSE
/obj/item/assembly/signaler/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/ui_width = 280
var/ui_height = 132
ui = new(user, src, ui_key, "signaler", name, ui_width, ui_height, master_ui, state)
ui = new(user, src, ui_key, "Signaler", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/item/assembly/signaler/ui_data(mob/user)
@@ -231,4 +234,4 @@
/obj/item/assembly/signaler/cyborg/attackby(obj/item/W, mob/user, params)
return
/obj/item/assembly/signaler/cyborg/screwdriver_act(mob/living/user, obj/item/I)
return
return
+38 -47
View File
@@ -4,7 +4,8 @@
icon_state = "timer"
custom_materials = list(/datum/material/iron=500, /datum/material/glass=50)
attachable = TRUE
var/ui_x = 275
var/ui_y = 115
var/timing = FALSE
var/time = 5
var/saved_time = 5
@@ -41,7 +42,6 @@
update_icon()
return TRUE
/obj/item/assembly/timer/toggle_secure()
secured = !secured
if(secured)
@@ -52,7 +52,6 @@
update_icon()
return secured
/obj/item/assembly/timer/proc/timer_end()
if(!secured || next_activate > world.time)
return FALSE
@@ -66,7 +65,6 @@
timing = TRUE
update_icon()
/obj/item/assembly/timer/process()
if(!timing)
return
@@ -76,7 +74,6 @@
timer_end()
time = saved_time
/obj/item/assembly/timer/update_icon()
cut_overlays()
attached_overlays = list()
@@ -86,50 +83,44 @@
if(holder)
holder.update_icon()
/obj/item/assembly/timer/ui_interact(mob/user)//TODO: Have this use the wires
. = ..()
/obj/item/assembly/timer/ui_status(mob/user)
if(is_secured(user))
var/second = time % 60
var/minute = (time - second) / 60
var/dat = "<TT><B>Timing Unit</B></TT>"
dat += "<BR>[(timing ? "<A href='?src=[REF(src)];time=0'>Timing</A>" : "<A href='?src=[REF(src)];time=1'>Not Timing</A>")] [minute]:[second]"
dat += "<BR><A href='?src=[REF(src)];tp=-30'>-</A> <A href='?src=[REF(src)];tp=-1'>-</A> <A href='?src=[REF(src)];tp=1'>+</A> <A href='?src=[REF(src)];tp=30'>+</A>"
dat += "<BR><BR><A href='?src=[REF(src)];repeat=[(loop ? "0'>Stop repeating" : "1'>Set to repeat")]</A>"
dat += "<BR><BR><A href='?src=[REF(src)];refresh=1'>Refresh</A>"
dat += "<BR><BR><A href='?src=[REF(src)];close=1'>Close</A>"
var/datum/browser/popup = new(user, "timer", name)
popup.set_content(dat)
popup.open()
return ..()
return UI_CLOSE
/obj/item/assembly/timer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "Timer", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/item/assembly/timer/Topic(href, href_list)
..()
if(!usr.canUseTopic(src, BE_CLOSE))
usr << browse(null, "window=timer")
onclose(usr, "timer")
/obj/item/assembly/timer/ui_data(mob/user)
var/list/data = list()
data["seconds"] = round(time % 60)
data["minutes"] = round((time - data["seconds"]) / 60)
data["timing"] = timing
data["loop"] = loop
return data
/obj/item/assembly/timer/ui_act(action, params)
if(..())
return
if(href_list["time"])
timing = text2num(href_list["time"])
if(timing && istype(holder, /obj/item/transfer_valve))
var/timer_message = "[ADMIN_LOOKUPFLW(usr)] activated [src] attachment on [holder]."
message_admins(timer_message)
GLOB.bombers += timer_message
log_game("[key_name(usr)] activated [src] attachment on [holder]")
update_icon()
if(href_list["repeat"])
loop = text2num(href_list["repeat"])
if(href_list["tp"])
var/tp = text2num(href_list["tp"])
time += tp
time = min(max(round(time), 1), 600)
saved_time = time
if(href_list["close"])
usr << browse(null, "window=timer")
return
if(usr)
attack_self(usr)
switch(action)
if("time")
timing = !timing
if(timing && istype(holder, /obj/item/transfer_valve))
log_game(usr, "activated a", src, "attachment on [holder]")
update_icon()
. = TRUE
if("repeat")
loop = !loop
. = TRUE
if("input")
var/value = text2num(params["adjust"])
if(value)
value = round(time + value)
time = clamp(value, 1, 600)
saved_time = time
. = TRUE
+3
View File
@@ -1,10 +1,12 @@
/*
Asset cache quick users guide:
Make a datum in asset_list_items.dm with your assets for your thing.
Checkout asset_list.dm for the helper subclasses
The simple subclass will most like be of use for most cases.
Then call get_asset_datum() with the type of the datum you created and store the return
Then call .send(client) on that stored return value.
Note: If your code uses output() with assets you will need to call asset_flush on the client and wait for it to return before calling output(). You only need do this if .send(client) returned TRUE
*/
@@ -98,3 +100,4 @@ Note: If your code uses output() with assets you will need to call asset_flush o
//The same asset will always lead to the same asset name
/proc/generate_asset_name(file)
return "asset.[md5(fcopy_rsc(file))]"
+2
View File
@@ -226,3 +226,5 @@ GLOBAL_LIST_EMPTY(asset_datums)
/datum/asset/simple/icon_states/multiple_icons/register()
for(var/i in icons)
..(i)
+34 -77
View File
@@ -1,27 +1,10 @@
//DEFINITIONS FOR ASSET DATUMS START HERE.
/* uncomment this and delete the tgui def bellow this for the new tgui
/datum/asset/simple/tgui
assets = list(
"tgui.bundle.js" = 'tgui/packages/tgui/public/tgui.bundle.js',
"tgui.bundle.css" = 'tgui/packages/tgui/public/tgui.bundle.css',
)
*/
/datum/asset/simple/tgui
assets = list(
// Old TGUI
"tgui.css" = 'tgui/assets/tgui.css',
"tgui.js" = 'tgui/assets/tgui.js',
// tgui-next
"tgui-main.html" = 'tgui-next/packages/tgui/public/tgui-main.html',
"tgui.bundle.js" = 'tgui-next/packages/tgui/public/tgui.bundle.js',
"tgui.bundle.css" = 'tgui-next/packages/tgui/public/tgui.bundle.css',
// Old TGUI compatability
"tgui-fallback.html" = 'tgui-next/packages/tgui/public/tgui-fallback.html',
"shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js',
"shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js',
"shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js',
"shim-css-om.js" = 'tgui-next/packages/tgui/public/shim-css-om.js',
)
/datum/asset/group/tgui
children = list(
@@ -56,17 +39,17 @@
"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'
"smmon_6.gif" = 'icons/program_icons/smmon_6.gif',
"borg_mon.gif" = 'icons/program_icons/borg_mon.gif'
)
/* uncomment if you're porting the new ntnet app
/datum/asset/simple/radar_assets
assets = list(
"ntosradarbackground.png" = 'icons/UI_Icons/tgui/ntosradar_background.png',
"ntosradarpointer.png" = 'icons/UI_Icons/tgui/ntosradar_pointer.png',
"ntosradarpointerS.png" = 'icons/UI_Icons/tgui/ntosradar_pointer_S.png'
)
*/
/datum/asset/spritesheet/simple/pda
name = "pda"
assets = list(
@@ -95,7 +78,6 @@
"refresh" = 'icons/pda_icons/pda_refresh.png',
"scanner" = 'icons/pda_icons/pda_scanner.png',
"signaler" = 'icons/pda_icons/pda_signaler.png',
//"skills" = 'icons/pda_icons/pda_skills.png',
"status" = 'icons/pda_icons/pda_status.png',
"dronephone" = 'icons/pda_icons/pda_dronephone.png',
"emoji" = 'icons/pda_icons/pda_emoji.png'
@@ -115,12 +97,9 @@
"stamp-cap" = 'icons/stamp_icons/large_stamp-cap.png',
"stamp-qm" = 'icons/stamp_icons/large_stamp-qm.png',
"stamp-law" = 'icons/stamp_icons/large_stamp-law.png'
//"stamp-chap" = 'icons/stamp_icons/large_stamp-chap.png',
//"stamp-mime" = 'icons/stamp_icons/large_stamp-mime.png',
//"stamp-centcom" = 'icons/stamp_icons/large_stamp-centcom.png',
//"stamp-syndicate" = 'icons/stamp_icons/large_stamp-syndicate.png'
)
/datum/asset/simple/IRV
assets = list(
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
@@ -168,12 +147,13 @@
"jquery.min.js" = 'code/modules/goonchat/browserassets/js/jquery.min.js',
)
/datum/asset/simple/goonchat
assets = list(
"json2.min.js" = 'code/modules/goonchat/browserassets/js/json2.min.js',
"browserOutput.js" = 'code/modules/goonchat/browserassets/js/browserOutput.js',
"browserOutput.css" = 'code/modules/goonchat/browserassets/css/browserOutput.css',
"browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css', //dark theme, cit specific
"browserOutput_dark.css" = 'code/modules/goonchat/browserassets/css/browserOutput_dark.css',
"browserOutput_light.css" = 'code/modules/goonchat/browserassets/css/browserOutput_light.css'
)
@@ -219,6 +199,16 @@
"none_button.png" = 'html/none_button.png',
)
/datum/asset/simple/arcade
assets = list(
"boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
"boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
"boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
"boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
"boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
"boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
)
/datum/asset/spritesheet/simple/minesweeper
name = "minesweeper"
assets = list(
@@ -237,45 +227,7 @@
"minehit" = 'icons/UI_Icons/minesweeper_tiles/minehit.png'
)
/* Port the app game thing
/datum/asset/simple/arcade
assets = list(
"boss1.gif" = 'icons/UI_Icons/Arcade/boss1.gif',
"boss2.gif" = 'icons/UI_Icons/Arcade/boss2.gif',
"boss3.gif" = 'icons/UI_Icons/Arcade/boss3.gif',
"boss4.gif" = 'icons/UI_Icons/Arcade/boss4.gif',
"boss5.gif" = 'icons/UI_Icons/Arcade/boss5.gif',
"boss6.gif" = 'icons/UI_Icons/Arcade/boss6.gif',
)
*/
/*
/datum/asset/spritesheet/simple/achievements
name ="achievements"
assets = list(
"default" = 'icons/UI_Icons/Achievements/default.png',
"basemisc" = 'icons/UI_Icons/Achievements/basemisc.png',
"baseboss" = 'icons/UI_Icons/Achievements/baseboss.png',
"baseskill" = 'icons/UI_Icons/Achievements/baseskill.png',
"bbgum" = 'icons/UI_Icons/Achievements/Boss/bbgum.png',
"colossus" = 'icons/UI_Icons/Achievements/Boss/colossus.png',
"hierophant" = 'icons/UI_Icons/Achievements/Boss/hierophant.png',
"legion" = 'icons/UI_Icons/Achievements/Boss/legion.png',
"miner" = 'icons/UI_Icons/Achievements/Boss/miner.png',
"swarmer" = 'icons/UI_Icons/Achievements/Boss/swarmer.png',
"tendril" = 'icons/UI_Icons/Achievements/Boss/tendril.png',
"featofstrength" = 'icons/UI_Icons/Achievements/Misc/featofstrength.png',
"helbital" = 'icons/UI_Icons/Achievements/Misc/helbital.png',
"jackpot" = 'icons/UI_Icons/Achievements/Misc/jackpot.png',
"meteors" = 'icons/UI_Icons/Achievements/Misc/meteors.png',
"timewaste" = 'icons/UI_Icons/Achievements/Misc/timewaste.png',
"upgrade" = 'icons/UI_Icons/Achievements/Misc/upgrade.png',
"clownking" = 'icons/UI_Icons/Achievements/Misc/clownking.png',
"clownthanks" = 'icons/UI_Icons/Achievements/Misc/clownthanks.png',
"rule8" = 'icons/UI_Icons/Achievements/Misc/rule8.png',
"snail" = 'icons/UI_Icons/Achievements/Misc/snail.png',
"mining" = 'icons/UI_Icons/Achievements/Skills/mining.png',
)
*/
/datum/asset/spritesheet/simple/pills
name ="pills"
assets = list(
@@ -313,8 +265,8 @@
/datum/asset/spritesheet/pipes
name = "pipes"
/datum/asset/spritesheet/pipes/register() //we do not have chempipes
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi', 'icons/obj/atmospherics/pipes/transit_tube.dmi'))
/datum/asset/spritesheet/pipes/register()
for (var/each in list('icons/obj/atmospherics/pipes/pipe_item.dmi', 'icons/obj/atmospherics/pipes/disposal.dmi'))
InsertAll("", each, GLOB.alldirs)
..()
@@ -323,7 +275,7 @@
name = "design"
/datum/asset/spritesheet/research_designs/register()
for(var/path in subtypesof(/datum/design))
for (var/path in subtypesof(/datum/design))
var/datum/design/D = path
var/icon_file
@@ -381,9 +333,9 @@
name = "vending"
/datum/asset/spritesheet/vending/register()
for(var/k in GLOB.vending_products)
for (var/k in GLOB.vending_products)
var/atom/item = k
if(!ispath(item, /atom))
if (!ispath(item, /atom))
continue
var/icon_file = initial(item.icon)
@@ -394,12 +346,12 @@
if(icon_state in icon_states_list)
I = icon(icon_file, icon_state, SOUTH)
var/c = initial(item.color)
if(!isnull(c) && c != "#FFFFFF")
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)
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])"
@@ -418,7 +370,12 @@
"dna_extra.gif" = 'html/dna_extra.gif'
)
/datum/asset/simple/vv
/datum/asset/simple/orbit
assets = list(
"view_variables.css" = 'html/admin/view_variables.css'
"ghost.png" = 'html/ghost.png'
)
assets = list(
"ghost.png" = 'html/ghost.png'
)
@@ -23,6 +23,7 @@
}
};
xhr.send(null);
</script>
</body>
</html>
</script>
</body>
</html>
@@ -241,7 +241,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "airalarm", name, 440, 650, master_ui, state)
ui = new(user, src, ui_key, "AirAlarm", name, 440, 650, master_ui, state)
ui.open()
/obj/machinery/airalarm/ui_data(mob/user)
@@ -26,6 +26,21 @@ Passive gate is similar to the regular pump except:
construction_type = /obj/item/pipe/directional
pipe_state = "passivegate"
ui_x = 335
ui_y = 115
/obj/machinery/atmospherics/components/binary/passive_gate/CtrlClick(mob/user)
if(can_interact(user))
on = !on
update_icon()
return ..()
/obj/machinery/atmospherics/components/binary/passive_gate/AltClick(mob/user)
if(can_interact(user))
target_pressure = MAX_OUTPUT_PRESSURE
update_icon()
return ..()
/obj/machinery/atmospherics/components/binary/passive_gate/Destroy()
SSradio.remove_object(src,frequency)
return ..()
@@ -91,7 +106,7 @@ Passive gate is similar to the regular pump except:
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_pump", name, 335, 115, master_ui, state)
ui = new(user, src, ui_key, "AtmosPump", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/atmospherics/components/binary/passive_gate/ui_data()
@@ -111,7 +111,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_pump", name, 335, 115, master_ui, state)
ui = new(user, src, ui_key, "AtmosPump", name, 335, 115, master_ui, state)
ui.open()
/obj/machinery/atmospherics/components/binary/pump/ui_data()
@@ -96,7 +96,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_pump", name, 310, 115, master_ui, state)
ui = new(user, src, ui_key, "AtmosPump", name, 310, 115, master_ui, state)
ui.open()
/obj/machinery/atmospherics/components/binary/volume_pump/ui_data()
@@ -137,7 +137,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_filter", name, 475, 185, master_ui, state)
ui = new(user, src, ui_key, "AtmosFilter", name, 475, 185, master_ui, state)
ui.open()
/obj/machinery/atmospherics/components/trinary/filter/ui_data()
@@ -131,7 +131,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_mixer", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, ui_key, "AtmosMixer", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/atmospherics/components/trinary/mixer/ui_data()
@@ -324,7 +324,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "cryo", name, 400, 550, master_ui, state)
ui = new(user, src, ui_key, "Cryo", name, 400, 550, master_ui, state)
ui.open()
/obj/machinery/atmospherics/components/unary/cryo_cell/ui_data()
@@ -20,6 +20,21 @@
pipe_state = "injector"
ui_x = 310
ui_y = 115
/obj/machinery/atmospherics/components/unary/outlet_injector/CtrlClick(mob/user)
if(can_interact(user))
on = !on
update_icon()
return ..()
/obj/machinery/atmospherics/components/unary/outlet_injector/AltClick(mob/user)
if(can_interact(user))
volume_rate = MAX_TRANSFER_RATE
update_icon()
return ..()
/obj/machinery/atmospherics/components/unary/outlet_injector/Destroy()
SSradio.remove_object(src,frequency)
return ..()
@@ -140,7 +155,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atmos_pump", name, 310, 115, master_ui, state)
ui = new(user, src, ui_key, "AtmosPump", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/atmospherics/components/unary/outlet_injector/ui_data()
@@ -129,7 +129,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "thermomachine", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, ui_key, "ThermoMachine", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/atmospherics/components/unary/thermomachine/ui_data(mob/user)
@@ -5,6 +5,8 @@
desc = "A canister for the storage of gas."
icon_state = "yellow"
density = TRUE
ui_x = 300
ui_y = 232
var/valve_open = FALSE
var/obj/machinery/atmospherics/components/binary/passive_gate/pump
@@ -34,6 +36,7 @@
var/restricted = FALSE
req_access = list()
var/update = 0
var/static/list/label2types = list(
"n2" = /obj/machinery/portable_atmospherics/canister/nitrogen,
"o2" = /obj/machinery/portable_atmospherics/canister/oxygen,
@@ -159,11 +162,11 @@
/obj/machinery/portable_atmospherics/canister/proto
name = "prototype canister"
/obj/machinery/portable_atmospherics/canister/proto/default
name = "prototype canister"
desc = "The best way to fix an atmospheric emergency... or the best way to introduce one."
icon_state = "proto"
icon_state = "proto"
volume = 5000
max_integrity = 300
temperature_resistance = 2000 + T0C
@@ -171,6 +174,7 @@
can_min_release_pressure = (ONE_ATMOSPHERE / 30)
prototype = TRUE
/obj/machinery/portable_atmospherics/canister/proto/default/oxygen
name = "prototype canister"
desc = "A prototype canister for a prototype bike, what could go wrong?"
@@ -192,6 +196,7 @@
update_icon()
/obj/machinery/portable_atmospherics/canister/Destroy()
qdel(pump)
pump = null
@@ -215,7 +220,6 @@
/obj/machinery/portable_atmospherics/canister/update_overlays()
. = ..()
if(holding)
. += "can-open"
if(connected_port)
@@ -245,7 +249,8 @@
new /obj/item/stack/sheet/metal (loc, 5)
qdel(src)
/obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I)
obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I)
..()
if(user.a_intent == INTENT_HARM)
return FALSE
@@ -273,10 +278,9 @@
T.assume_air(expelled_gas)
air_update_turf()
stat |= BROKEN
obj_break()
density = FALSE
playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3)
update_icon()
playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
investigate_log("was destroyed.", INVESTIGATE_ATMOS)
if(holding)
@@ -319,7 +323,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "canister", name, 420, 405, master_ui, state)
ui = new(user, src, ui_key, "Canister", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/portable_atmospherics/canister/ui_data()
@@ -354,7 +358,7 @@
return
switch(action)
if("relabel")
var/label = input("New canister label:", name) as null|anything in label2types
var/label = input("New canister label:", name) as null|anything in sortList(label2types)
if(label && !..())
var/newtype = label2types[label]
if(newtype)
@@ -8,6 +8,8 @@
name = "portable air pump"
icon_state = "psiphon:0"
density = TRUE
ui_x = 300
ui_y = 315
var/on = FALSE
var/direction = PUMP_OUT
@@ -32,7 +34,6 @@
/obj/machinery/portable_atmospherics/pump/update_icon_state()
icon_state = "psiphon:[on]"
/obj/machinery/portable_atmospherics/pump/update_overlays()
. = ..()
if(holding)
@@ -79,14 +80,14 @@
on = FALSE
update_icon()
else if(on && holding && direction == PUMP_OUT)
investigate_log("[key_name(user)] started a transfer into [holding].<br>", INVESTIGATE_ATMOS)
investigate_log("[key_name(user)] started a transfer into [holding].", INVESTIGATE_ATMOS)
/obj/machinery/portable_atmospherics/pump/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "portable_pump", name, 300, 315, master_ui, state)
ui = new(user, src, ui_key, "PortablePump", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/portable_atmospherics/pump/ui_data()
@@ -121,14 +122,14 @@
message_admins("[ADMIN_LOOKUPFLW(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [ADMIN_VERBOSEJMP(src)]")
log_admin("[key_name(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [AREACOORD(src)]")
else if(on && direction == PUMP_OUT)
investigate_log("[key_name(usr)] started a transfer into [holding].<br>", INVESTIGATE_ATMOS)
investigate_log("[key_name(usr)] started a transfer into [holding].", INVESTIGATE_ATMOS)
. = TRUE
if("direction")
if(direction == PUMP_OUT)
direction = PUMP_IN
else
if(on && holding)
investigate_log("[key_name(usr)] started a transfer into [holding].<br>", INVESTIGATE_ATMOS)
investigate_log("[key_name(usr)] started a transfer into [holding].", INVESTIGATE_ATMOS)
direction = PUMP_OUT
. = TRUE
if("pressure")
@@ -142,10 +143,6 @@
else if(pressure == "max")
pressure = PUMP_MAX_PRESSURE
. = TRUE
else if(pressure == "input")
pressure = input("New release pressure ([PUMP_MIN_PRESSURE]-[PUMP_MAX_PRESSURE] kPa):", name, pump.target_pressure) as num|null
if(!isnull(pressure) && !..())
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
@@ -154,7 +151,6 @@
investigate_log("was set to [pump.target_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS)
if("eject")
if(holding)
holding.forceMove(drop_location())
holding = null
replace_tank(usr, FALSE)
. = TRUE
update_icon()
@@ -2,6 +2,8 @@
name = "portable air scrubber"
icon_state = "pscrubber:0"
density = TRUE
ui_x = 320
ui_y = 350
var/on = FALSE
var/volume_rate = 1000
@@ -64,7 +66,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.physical_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "portable_scrubber", name, 320, 335, master_ui, state)
ui = new(user, src, ui_key, "PortableScrubber", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/portable_atmospherics/scrubber/ui_data()
+290 -209
View File
@@ -1,246 +1,327 @@
/// Station home gateway
GLOBAL_DATUM(the_gateway, /obj/machinery/gateway/centerstation)
/// List of possible gateway destinations.
GLOBAL_LIST_EMPTY(gateway_destinations)
/**
* Corresponds to single entry in gateway control.
*
* Will NOT be added automatically to GLOB.gateway_destinations list.
*/
/datum/gateway_destination
var/name = "Unknown Destination"
var/wait = 0 /// How long after roundstart this destination becomes active
var/enabled = TRUE /// If disabled, the destination won't be availible
var/hidden = FALSE /// Will not show on gateway controls at all.
/* Can a gateway link to this destination right now. */
/datum/gateway_destination/proc/is_availible()
return enabled && (world.time - SSticker.round_start_time >= wait)
/* Returns user-friendly description why you can't connect to this destination, displayed in UI */
/datum/gateway_destination/proc/get_availible_reason()
. = "Unreachable"
if(world.time - SSticker.round_start_time < wait)
. = "Connection desynchronized. Recalibration in progress."
/* Check if the movable is allowed to arrive at this destination (exile implants mostly) */
/datum/gateway_destination/proc/incoming_pass_check(atom/movable/AM)
return TRUE
/* Get the actual turf we'll arrive at */
/datum/gateway_destination/proc/get_target_turf()
CRASH("get target turf not implemented for this destination type")
/* Called after moving the movable to target turf */
/datum/gateway_destination/proc/post_transfer(atom/movable/AM)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
/* Called when gateway activates with this destination. */
/datum/gateway_destination/proc/activate(obj/machinery/gateway/activated)
return
/* Called when gateway targeting this destination deactivates. */
/datum/gateway_destination/proc/deactivate(obj/machinery/gateway/deactivated)
return
/* Returns data used by gateway controller ui */
/datum/gateway_destination/proc/get_ui_data()
. = list()
.["ref"] = REF(src)
.["name"] = name
.["availible"] = is_availible()
.["reason"] = get_availible_reason()
if(wait)
.["timeout"] = max(1 - (wait - (world.time - SSticker.round_start_time)) / wait, 0)
/* Destination is another gateway */
/datum/gateway_destination/gateway
/// The gateway this destination points at
var/obj/machinery/gateway/target_gateway
/* We set the target gateway target to activator gateway */
/datum/gateway_destination/gateway/activate(obj/machinery/gateway/activated)
if(!target_gateway.target)
target_gateway.activate(activated)
/* We turn off the target gateway if it's linked with us */
/datum/gateway_destination/gateway/deactivate(obj/machinery/gateway/deactivated)
if(target_gateway.target == deactivated.destination)
target_gateway.deactivate()
/datum/gateway_destination/gateway/is_availible()
return ..() && target_gateway.calibrated && !target_gateway.target && target_gateway.powered()
/datum/gateway_destination/gateway/get_availible_reason()
. = ..()
if(!target_gateway.calibrated)
. = "Exit gateway malfunction. Manual recalibration required."
if(target_gateway.target)
. = "Exit gateway in use."
if(!target_gateway.powered())
. = "Exit gateway unpowered."
/datum/gateway_destination/gateway/get_target_turf()
return get_step(target_gateway.portal,SOUTH)
/datum/gateway_destination/gateway/post_transfer(atom/movable/AM)
. = ..()
addtimer(CALLBACK(AM,/atom/movable.proc/setDir,SOUTH),0)
/* Special home destination, so we can check exile implants */
/datum/gateway_destination/gateway/home
/datum/gateway_destination/gateway/home/incoming_pass_check(atom/movable/AM)
if(isliving(AM))
if(check_exile_implant(AM))
return FALSE
else
for(var/mob/living/L in AM.contents)
if(check_exile_implant(L))
target_gateway.say("Rejecting [AM]: Exile implant detected in contained lifeform.")
return FALSE
if(AM.has_buckled_mobs())
for(var/mob/living/L in AM.buckled_mobs)
if(check_exile_implant(L))
target_gateway.say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
return FALSE
return TRUE
/datum/gateway_destination/gateway/home/proc/check_exile_implant(mob/living/L)
for(var/obj/item/implant/exile/E in L.implants)//Checking that there is an exile implant
to_chat(L, "<span class='userdanger'>The station gate has detected your exile implant and is blocking your entry.</span>")
return TRUE
return FALSE
/* Destination is one ore more turfs - created by landmarks */
/datum/gateway_destination/point
var/list/target_turfs = list()
/// Used by away landmarks
var/id
/datum/gateway_destination/point/get_target_turf()
return pick(target_turfs)
/* Dense invisible object starting the teleportation. Created by gateways on activation. */
/obj/effect/gateway_portal_bumper
var/obj/machinery/gateway/gateway
density = TRUE
invisibility = INVISIBILITY_ABSTRACT
/obj/effect/gateway_portal_bumper/Bumped(atom/movable/AM)
if(get_dir(src,AM) == SOUTH)
gateway.Transfer(AM)
/obj/effect/gateway_portal_bumper/Destroy(force)
. = ..()
gateway = null
/obj/machinery/gateway
name = "gateway"
desc = "A mysterious gateway built by unknown hands, it allows for faster than light travel to far-flung locations."
icon = 'icons/obj/machines/gateway.dmi'
icon_state = "off"
density = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/active = 0
var/checkparts = TRUE
var/list/obj/effect/landmark/randomspawns = list()
// 3x2 offset by one row
pixel_x = -32
pixel_y = -32
bound_height = 64
bound_width = 96
bound_x = -32
bound_y = 0
density = TRUE
use_power = IDLE_POWER_USE
idle_power_usage = 100
active_power_usage = 5000
var/calibrated = TRUE
var/list/linked = list()
var/can_link = FALSE //Is this the centerpiece?
/// Type of instanced gateway destination, needs to be subtype of /datum/gateway_destination/gateway
var/destination_type = /datum/gateway_destination/gateway
/// Name of the generated destination
var/destination_name = "Unknown Gateway"
/// This is our own destination, pointing at this gateway
var/datum/gateway_destination/gateway/destination
/// This is current active destination
var/datum/gateway_destination/target
/// bumper object, the thing that starts actual teleport
var/obj/effect/gateway_portal_bumper/portal
/obj/machinery/gateway/Initialize()
randomspawns = GLOB.awaydestinations
generate_destination()
update_icon()
if(!istype(src, /obj/machinery/gateway/centerstation) && !istype(src, /obj/machinery/gateway/centeraway))
switch(dir)
if(SOUTH,SOUTHEAST,SOUTHWEST)
density = FALSE
return ..()
/obj/machinery/gateway/proc/toggleoff()
for(var/obj/machinery/gateway/G in linked)
G.active = 0
G.update_icon()
active = 0
/obj/machinery/gateway/proc/generate_destination()
destination = new destination_type
destination.name = destination_name
destination.target_gateway = src
GLOB.gateway_destinations += destination
/obj/machinery/gateway/proc/deactivate()
var/datum/gateway_destination/dest = target
target = null
dest.deactivate(src)
QDEL_NULL(portal)
use_power = IDLE_POWER_USE
update_icon()
/obj/machinery/gateway/proc/detect()
if(!can_link)
return FALSE
linked = list() //clear the list
var/turf/T = loc
var/ready = FALSE
for(var/i in GLOB.alldirs)
T = get_step(loc, i)
var/obj/machinery/gateway/G = locate(/obj/machinery/gateway) in T
if(G)
linked.Add(G)
continue
//this is only done if we fail to find a part
ready = FALSE
toggleoff()
break
if((linked.len == 8) || !checkparts)
ready = TRUE
return ready
/obj/machinery/gateway/process()
if((stat & (NOPOWER)) && use_power)
if(target)
deactivate()
return
/obj/machinery/gateway/update_icon_state()
icon_state = active ? "on" : "off"
if(target)
icon_state = "on"
else
icon_state = "off"
/obj/machinery/gateway/attack_hand(mob/user)
. = ..()
if(.)
return
if(!detect())
return
if(!active)
toggleon(user)
return
toggleoff()
/obj/machinery/gateway/proc/toggleon(mob/user)
return FALSE
/obj/machinery/gateway/safe_throw_at()
/obj/machinery/gateway/safe_throw_at(atom/target, range, speed, mob/thrower, spin = TRUE, diagonals_first = FALSE, datum/callback/callback, force = MOVE_FORCE_STRONG, gentle = FALSE)
return
/obj/machinery/gateway/proc/generate_bumper()
portal = new(get_turf(src))
portal.gateway = src
/obj/machinery/gateway/proc/activate(datum/gateway_destination/D)
if(!powered() || target)
return
target = D
target.activate(destination)
generate_bumper()
use_power = ACTIVE_POWER_USE
update_icon()
/obj/machinery/gateway/proc/Transfer(atom/movable/AM)
if(!target || !target.incoming_pass_check(AM))
return
AM.forceMove(target.get_target_turf())
target.post_transfer(AM)
/* Station's primary gateway */
/obj/machinery/gateway/centerstation
destination_type = /datum/gateway_destination/gateway/home
destination_name = "Home Gateway"
/obj/machinery/gateway/centerstation/Initialize()
. = ..()
if(!GLOB.the_gateway)
GLOB.the_gateway = src
update_icon()
wait = world.time + CONFIG_GET(number/gateway_delay) //+ thirty minutes default
awaygate = locate(/obj/machinery/gateway/centeraway)
/obj/machinery/gateway/centerstation/Destroy()
if(GLOB.the_gateway == src)
GLOB.the_gateway = null
return ..()
//this is da important part wot makes things go
/obj/machinery/gateway/centerstation
density = TRUE
icon_state = "offcenter"
use_power = IDLE_POWER_USE
//warping vars
var/wait = 0 //this just grabs world.time at world start
var/obj/machinery/gateway/centeraway/awaygate = null
can_link = TRUE
/obj/machinery/gateway/centerstation/update_icon_state()
icon_state = active ? "oncenter" : "offcenter"
/obj/machinery/gateway/centerstation/process()
if((stat & (NOPOWER)) && use_power)
if(active)
toggleoff()
return
if(active)
use_power(5000)
/obj/machinery/gateway/centerstation/toggleon(mob/user)
if(!detect())
return
if(!powered())
return
if(!awaygate)
to_chat(user, "<span class='notice'>Error: No destination found.</span>")
return
if(world.time < wait)
to_chat(user, "<span class='notice'>Error: Warpspace triangulation in progress. Estimated time to completion: [DisplayTimeText(wait - world.time)].</span>")
return
for(var/obj/machinery/gateway/G in linked)
G.active = 1
G.update_icon()
active = 1
update_icon()
//okay, here's the good teleporting stuff
/obj/machinery/gateway/centerstation/Bumped(atom/movable/AM)
if(!active)
return
if(!detect())
return
if(!awaygate || QDELETED(awaygate))
return
if(awaygate.calibrated)
AM.forceMove(get_step(awaygate.loc, SOUTH))
AM.setDir(SOUTH)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
return
/obj/machinery/gateway/multitool_act(mob/living/user, obj/item/I)
if(calibrated)
to_chat(user, "<span class='alert'>The gate is already calibrated, there is no work for you to do here.</span>")
else
var/obj/effect/landmark/dest = pick(randomspawns)
if(dest)
AM.forceMove(get_turf(dest))
AM.setDir(SOUTH)
use_power(5000)
return
/obj/machinery/gateway/centeraway/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/multitool))
if(calibrated)
to_chat(user, "\black The gate is already calibrated, there is no work for you to do here.")
return
else
to_chat(user, "<span class='boldnotice'>Recalibration successful!</span>: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.")
calibrated = TRUE
return
/////////////////////////////////////Away////////////////////////
/obj/machinery/gateway/centeraway
density = TRUE
icon_state = "offcenter"
use_power = NO_POWER_USE
var/obj/machinery/gateway/centerstation/stationgate = null
can_link = TRUE
/obj/machinery/gateway/centeraway/Initialize()
. = ..()
update_icon()
stationgate = locate(/obj/machinery/gateway/centerstation)
/obj/machinery/gateway/centeraway/update_icon_state()
icon_state = active ? "oncenter" : "offcenter"
/obj/machinery/gateway/centeraway/toggleon(mob/user)
if(!detect())
return
if(!stationgate)
to_chat(user, "<span class='notice'>Error: No destination found.</span>")
return
for(var/obj/machinery/gateway/G in linked)
G.active = 1
G.update_icon()
active = 1
update_icon()
/obj/machinery/gateway/centeraway/proc/check_exile_implant(mob/living/L)
for(var/obj/item/implant/exile/E in L.implants)//Checking that there is an exile implant
to_chat(L, "\black The station gate has detected your exile implant and is blocking your entry.")
return TRUE
return FALSE
/obj/machinery/gateway/centeraway/Bumped(atom/movable/AM)
if(!detect())
return
if(!active)
return
if(!stationgate || QDELETED(stationgate))
return
if(isliving(AM))
if(check_exile_implant(AM))
return
else
for(var/mob/living/L in AM.contents)
if(check_exile_implant(L))
say("Rejecting [AM]: Exile implant detected in contained lifeform.")
return
if(AM.has_buckled_mobs())
for(var/mob/living/L in AM.buckled_mobs)
if(check_exile_implant(L))
say("Rejecting [AM]: Exile implant detected in close proximity lifeform.")
return
AM.forceMove(get_step(stationgate.loc, SOUTH))
AM.setDir(SOUTH)
if (ismob(AM))
var/mob/M = AM
if (M.client)
M.client.move_delay = max(world.time + 5, M.client.move_delay)
/obj/machinery/gateway/centeraway/admin
desc = "A mysterious gateway built by unknown hands, this one seems more compact."
/obj/machinery/gateway/centeraway/admin/Initialize()
. = ..()
if(stationgate && !stationgate.awaygate)
stationgate.awaygate = src
/obj/machinery/gateway/centeraway/admin/detect()
to_chat(user, "<span class='boldnotice'>Recalibration successful!</span>: \black This gate's systems have been fine tuned. Travel to this gate will now be on target.")
calibrated = TRUE
return TRUE
/* Doesn't need control console or power, always links to home when interacting. */
/obj/machinery/gateway/away
density = TRUE
use_power = NO_POWER_USE
/obj/machinery/gateway/away/interact(mob/user, special_state)
. = ..()
if(!target)
if(!GLOB.the_gateway)
to_chat(user,"<span class='warning'>Home gateway is not responding!</span>")
if(GLOB.the_gateway.target)
to_chat(user,"<span class='warning'>Home gateway already in use!</span>")
return
activate(GLOB.the_gateway.destination)
else
deactivate()
/* Gateway control computer */
/obj/machinery/computer/gateway_control
name = "Gateway Control"
desc = "Human friendly interface to the mysterious gate next to it."
var/obj/machinery/gateway/G
/obj/machinery/computer/gateway_control/Initialize(mapload, obj/item/circuitboard/C)
. = ..()
try_to_linkup()
/obj/machinery/computer/gateway_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui, force_open, datum/tgui/master_ui, datum/ui_state/state = GLOB.default_state)
. = ..()
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "Gateway", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/computer/gateway_control/ui_data(mob/user)
. = ..()
.["gateway_present"] = G
.["gateway_status"] = G ? G.powered() : FALSE
.["current_target"] = G?.target?.get_ui_data()
var/list/destinations = list()
if(G)
for(var/datum/gateway_destination/D in GLOB.gateway_destinations)
if(D == G.destination)
continue
destinations += list(D.get_ui_data())
.["destinations"] = destinations
/obj/machinery/computer/gateway_control/ui_act(action, list/params)
. = ..()
if(.)
return
switch(action)
if("linkup")
try_to_linkup()
return TRUE
if("activate")
var/datum/gateway_destination/D = locate(params["destination"]) in GLOB.gateway_destinations
try_to_connect(D)
return TRUE
if("deactivate")
if(G && G.target)
G.deactivate()
return TRUE
/obj/machinery/computer/gateway_control/proc/try_to_linkup()
G = locate(/obj/machinery/gateway) in view(7,get_turf(src))
/obj/machinery/computer/gateway_control/proc/try_to_connect(datum/gateway_destination/D)
if(!D || !G)
return
if(!D.is_availible() || G.target)
return
G.activate(D)
/obj/item/paper/fluff/gateway
info = "Congratulations,<br><br>Your station has been selected to carry out the Gateway Project.<br><br>The equipment will be shipped to you at the start of the next quarter.<br> You are to prepare a secure location to house the equipment as outlined in the attached documents.<br><br>--Nanotrasen Blue Space Research"
info = "Congratulations,<br><br>Your station has been selected to carry out the Gateway Project.<br><br>The equipment will be shipped to you at the start of the next quarter.<br> You are to prepare a secure location to house the equipment as outlined in the attached documents.<br><br>--Nanotrasen Bluespace Research"
name = "Confidential Correspondence, Pg 1"
+17 -13
View File
@@ -15,24 +15,28 @@
INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!")
GLOB.random_zlevels_generated[name] = TRUE
/proc/reset_gateway_spawns(reset = FALSE)
for(var/obj/machinery/gateway/G in world)
if(reset)
G.randomspawns = GLOB.awaydestinations
else
G.randomspawns.Add(GLOB.awaydestinations)
/obj/effect/landmark/awaystart
name = "away mission spawn"
desc = "Randomly picked away mission spawn points."
var/id
var/delay = TRUE // If the generated destination should be delayed by configured gateway delay
/obj/effect/landmark/awaystart/New()
GLOB.awaydestinations += src
..()
/obj/effect/landmark/awaystart/Initialize()
. = ..()
var/datum/gateway_destination/point/current
for(var/datum/gateway_destination/point/D in GLOB.gateway_destinations)
if(D.id == id)
current = D
if(!current)
current = new
current.id = id
if(delay)
current.wait = CONFIG_GET(number/gateway_delay)
GLOB.gateway_destinations += current
current.target_turfs += get_turf(src)
/obj/effect/landmark/awaystart/Destroy()
GLOB.awaydestinations -= src
return ..()
/obj/effect/landmark/awaystart/nodelay
delay = FALSE
/proc/generateMapList(filename)
. = list()
+1 -1
View File
@@ -55,7 +55,7 @@ force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.adm
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "centcom_podlauncher", "Config/Launch Supplypod", 700, 700, master_ui, state)
ui = new(user, src, ui_key, "CentcomPodLauncher", "Config/Launch Supplypod", 700, 700, master_ui, state)
ui.open()
/datum/centcom_podlauncher/ui_data(mob/user) //Sends info about the pod to the UI.
+1 -1
View File
@@ -74,7 +74,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "cargo", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, ui_key, "Cargo", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/computer/cargo/ui_data()
+3 -1
View File
@@ -13,6 +13,8 @@
All sales are near instantaneous - please choose carefully"
icon_screen = "supply_express"
circuit = /obj/item/circuitboard/computer/cargo/express
ui_x = 600
ui_y = 700
blockade_warning = "Bluespace instability detected. Delivery impossible."
req_access = list(ACCESS_QM)
var/message
@@ -90,7 +92,7 @@
/obj/machinery/computer/cargo/express/ui_interact(mob/living/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "cargo_express", name, 600, 700, master_ui, state)
ui = new(user, src, ui_key, "CargoExpress", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/computer/cargo/express/ui_data(mob/user)
+2 -3
View File
@@ -20,9 +20,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
When somebody clicks a link in game, this Topic is called first.
It does the stuff in this proc and then is redirected to the Topic() proc for the src=[0xWhatever]
(if specified in the link). ie locate(hsrc).Topic()
Such links can be spoofed.
Because of this certain things MUST be considered whenever adding a Topic() for something:
- Can it be fed harmful values which could cause runtimes?
- Is the Topic call an admin-only thing?
@@ -36,10 +34,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null
return
// asset_cache
var/asset_cache_job
if(href_list["asset_cache_confirm_arrival"])
asset_cache_job = asset_cache_confirm_arrival(href_list["asset_cache_confirm_arrival"])
if (!asset_cache_job)
if(!asset_cache_job)
return
var/mtl = CONFIG_GET(number/minute_topic_limit)
+9 -5
View File
@@ -18,6 +18,7 @@
var/list/log = list()
var/range = 8
var/view_check = TRUE
var/forensicPrintCount = 0
actions_types = list(/datum/action/item_action/displayDetectiveScanResults)
/datum/action/item_action/displayDetectiveScanResults
@@ -42,12 +43,15 @@
/obj/item/detective_scanner/proc/PrintReport()
// Create our paper
var/obj/item/paper/P = new(get_turf(src))
P.name = "paper- 'Scanner Report'"
P.info = "<center><font size='6'><B>Scanner Report</B></font></center><HR><BR>"
//This could be a global count like sec and med record printouts. See GLOB.data_core.medicalPrintCount AKA datacore.dm
var frNum = ++forensicPrintCount
P.name = text("FR-[] 'Forensic Record'", frNum)
P.info = text("<center><B>Forensic Record - (FR-[])</B></center><HR><BR>", frNum)
P.info += jointext(log, "<BR>")
P.info += "<HR><B>Notes:</B><BR>"
P.info_links = P.info
P.updateinfolinks()
P.update_icon()
if(ismob(loc))
var/mob/M = loc
@@ -216,4 +220,4 @@
return
to_chat(user, "<span class='notice'><B>Scanner Report</B></span>")
for(var/iterLog in log)
to_chat(user, iterLog)
to_chat(user, iterLog)
+50 -40
View File
@@ -225,7 +225,8 @@
suit_type = /obj/item/clothing/suit/space
helmet_type = /obj/item/clothing/head/helmet/space
mask_type = /obj/item/clothing/mask/breath
storage_type = /obj/item/tank/jetpack/void
storage_type = /obj/item/tank/internals/oxygen
/obj/machinery/loot_locator
name = "Booty Locator"
@@ -280,8 +281,9 @@
/obj/machinery/computer/piratepad_control
name = "cargo hold control terminal"
resistance_flags = INDESTRUCTIBLE
var/status_report = "Idle"
ui_x = 600
ui_y = 230
var/status_report = "Ready for delivery."
var/obj/machinery/piratepad/pad
var/warmup_time = 100
var/sending = FALSE
@@ -298,7 +300,6 @@
if (istype(I) && istype(I.buffer,/obj/machinery/piratepad))
to_chat(user, "<span class='notice'>You link [src] with [I.buffer] in [I] buffer.</span>")
pad = I.buffer
updateDialog()
return TRUE
/obj/machinery/computer/piratepad_control/LateInitialize()
@@ -311,29 +312,43 @@
else
pad = locate() in range(4,src)
/obj/machinery/computer/piratepad_control/ui_interact(mob/user)
. = ..()
var/list/t = list()
t += "<div class='statusDisplay'>Cargo Hold Control<br>"
t += "Current cargo value : [points]"
t += "</div>"
if(!pad)
t += "<div class='statusDisplay'>No pad located.</div><BR>"
else
t += "<br>[status_report]<br>"
if(!sending)
t += "<a href='?src=[REF(src)];recalc=1;'>Recalculate Value</a><a href='?src=[REF(src)];send=1'>Send</a>"
else
t += "<a href='?src=[REF(src)];stop=1'>Stop sending</a>"
/obj/machinery/computer/piratepad_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "CargoHoldTerminal", name, ui_x, ui_y, master_ui, state)
ui.open()
var/datum/browser/popup = new(user, "piratepad", name, 300, 500)
popup.set_content(t.Join())
popup.open()
/obj/machinery/computer/piratepad_control/ui_data(mob/user)
var/list/data = list()
data["points"] = points
data["pad"] = pad ? TRUE : FALSE
data["sending"] = sending
data["status_report"] = status_report
return data
/obj/machinery/computer/piratepad_control/ui_act(action, params)
if(..())
return
if(!pad)
return
switch(action)
if("recalc")
recalc()
. = TRUE
if("send")
start_sending()
. = TRUE
if("stop")
stop_sending()
. = TRUE
/obj/machinery/computer/piratepad_control/proc/recalc()
if(sending)
return
status_report = "Predicted value:<br>"
status_report = "Predicted value: "
var/value = 0
var/datum/export_report/ex = new
for(var/atom/movable/AM in get_turf(pad))
if(AM == pad)
@@ -341,7 +356,12 @@
export_item_and_contents(AM, EXPORT_PIRATE | EXPORT_CARGO | EXPORT_CONTRABAND | EXPORT_EMAG, apply_elastic = FALSE, dry_run = TRUE, external_report = ex)
for(var/datum/export/E in ex.total_amount)
status_report += E.total_printout(ex,notes = FALSE) + "<br>"
status_report += E.total_printout(ex,notes = FALSE)
status_report += " "
value += ex.total_value[E]
if(!value)
status_report += "0"
/obj/machinery/computer/piratepad_control/proc/send()
if(!sending)
@@ -354,14 +374,15 @@
continue
export_item_and_contents(AM, EXPORT_PIRATE | EXPORT_CARGO | EXPORT_CONTRABAND | EXPORT_EMAG, apply_elastic = FALSE, delete_unsold = FALSE, external_report = ex)
status_report = "Sold:<br>"
status_report = "Sold: "
var/value = 0
for(var/datum/export/E in ex.total_amount)
var/export_text = E.total_printout(ex,notes = FALSE) //Don't want nanotrasen messages, makes no sense here.
if(!export_text)
continue
status_report += export_text + "<br>"
status_report += export_text
status_report += " "
value += ex.total_value[E]
if(!total_report)
@@ -374,11 +395,12 @@
points += value
if(!value)
status_report += "Nothing"
pad.visible_message("<span class='notice'>[pad] activates!</span>")
flick(pad.sending_state,pad)
pad.icon_state = pad.idle_state
sending = FALSE
updateDialog()
/obj/machinery/computer/piratepad_control/proc/start_sending()
if(sending)
@@ -397,20 +419,6 @@
pad.icon_state = pad.idle_state
deltimer(sending_timer)
/obj/machinery/computer/piratepad_control/Topic(href, href_list)
if(..())
return
if(pad)
if(href_list["recalc"])
recalc()
if(href_list["send"])
start_sending()
if(href_list["stop"])
stop_sending()
updateDialog()
else
updateDialog()
/datum/export/pirate
export_category = EXPORT_PIRATE
@@ -435,6 +443,8 @@
var/mob/living/carbon/human/H = AM
if(H.stat != CONSCIOUS || !H.mind || !H.mind.assigned_role) //mint condition only
return 0
else if("pirate" in H.faction) //can't ransom your fellow pirates to CentCom!
return 0
else
if(H.mind.assigned_role in GLOB.command_positions)
return 3000
@@ -160,7 +160,7 @@
/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "smartvend", name, 440, 550, master_ui, state)
ui = new(user, src, ui_key, "SmartVend", name, 440, 550, master_ui, state)
ui.set_autoupdate(FALSE)
ui.open()
+1 -1
View File
@@ -83,7 +83,7 @@
/obj/machinery/computer/holodeck/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "holodeck", name, 400, 500, master_ui, state)
ui = new(user, src, ui_key, "Holodeck", name, 400, 500, master_ui, state)
ui.open()
/obj/machinery/computer/holodeck/ui_data(mob/user)
+1 -1
View File
@@ -219,7 +219,7 @@
/obj/item/paper/fluff/holodeck/trek_diploma
name = "paper - Starfleet Academy Diploma"
info = {"<h2>Starfleet Academy</h2></br><p>Official Diploma</p></br>"}
info = {"__Starfleet Academy__\nOfficial Diploma"}
/obj/item/paper/fluff/holodeck/disclaimer
name = "Holodeck Disclaimer"
+1 -1
View File
@@ -115,7 +115,7 @@
features["mcolor"] = "#59CE00"
for(var/V in quirks)
new V(podman)
podman.hardset_dna(null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
podman.hardset_dna(null,null,null,podman.real_name,blood_type, new /datum/species/pod,features)//Discard SE's and UI's, podman cloning is inaccurate, and always make them a podman
podman.set_cloned_appearance()
else //else, one packet of seeds. maybe two
+1 -1
View File
@@ -11,7 +11,7 @@
/datum/language_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.language_menu_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "language_menu", "Language Menu", 700, 600, master_ui, state)
ui = new(user, src, ui_key, "LanguageMenu", "Language Menu", 700, 600, master_ui, state)
ui.open()
/datum/language_menu/ui_data(mob/user)
+1 -1
View File
@@ -99,7 +99,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "codex_gigas", name, 450, 450, master_ui, state)
ui = new(user, src, ui_key, "CodexGigas", name, 450, 450, master_ui, state)
ui.open()
/obj/item/book/codex_gigas/ui_data(mob/user)
+1 -1
View File
@@ -209,7 +209,7 @@
/obj/structure/chisel_message/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "engraved_message", name, 600, 300, master_ui, state)
ui = new(user, src, ui_key, "EngravedMessage", name, 600, 300, master_ui, state)
ui.open()
/obj/structure/chisel_message/ui_data(mob/user)
+1
View File
@@ -92,6 +92,7 @@ interface with the mining shuttle at the landing site if a mobile beacon is also
say("<span class='danger'>Launch sequence activated! Prepare for drop!!</span>")
playsound(loc, 'sound/machines/warning-buzzer.ogg', 70, 0)
launch_warning = FALSE
log_shuttle("[key_name(usr)] has launched the auxillary base.")
else if(!shuttle_error)
say("Shuttle request uploaded. Please stand away from the doors.")
else
@@ -19,7 +19,7 @@ GLOBAL_LIST_INIT(marker_beacon_colors, list(
singular_name = "marker beacon"
desc = "Prism-brand path illumination devices. Used by miners to mark paths and warn of danger."
icon = 'icons/obj/lighting.dmi'
icon_state = "marker"
icon_state = "markerbronze"
merge_type = /obj/item/stack/marker_beacon
max_amount = 100
novariants = TRUE
@@ -8,6 +8,9 @@ GLOBAL_LIST(labor_sheet_values)
icon = 'icons/obj/machines/mining_machines.dmi'
icon_state = "console"
density = FALSE
ui_x = 315
ui_y = 430
var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine = null
var/machinedir = SOUTH
var/obj/machinery/door/airlock/release_door
@@ -36,7 +39,7 @@ GLOBAL_LIST(labor_sheet_values)
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "labor_claim_console", name, 315, 430, master_ui, state)
ui = new(user, src, ui_key, "LaborClaimConsole", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/mineral/labor_claim_console/ui_data(mob/user)
@@ -100,7 +103,6 @@ GLOBAL_LIST(labor_sheet_values)
Radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
to_chat(usr, "<span class='notice'>Shuttle received message and will be sent shortly.</span>")
. = TRUE
/obj/machinery/mineral/labor_claim_console/proc/locate_stacking_machine()
stacking_machine = locate(/obj/machinery/mineral/stacking_machine, get_step(src, machinedir))
@@ -110,12 +112,9 @@ GLOBAL_LIST(labor_sheet_values)
qdel(src)
/obj/machinery/mineral/labor_claim_console/emag_act(mob/user)
. = ..()
if(obj_flags & EMAGGED)
return
obj_flags |= EMAGGED
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
return TRUE
if(!(obj_flags & EMAGGED))
obj_flags |= EMAGGED
to_chat(user, "<span class='warning'>PZZTTPFFFT</span>")
/**********************Prisoner Collection Unit**************************/
+56 -5
View File
@@ -3,9 +3,54 @@
/**********************Mineral processing unit console**************************/
/obj/machinery/mineral
speed_process = TRUE
init_process = FALSE
/// The current direction of `input_turf`, in relation to the machine.
var/input_dir = NORTH
/// The current direction, in relation to the machine, that items will be output to.
var/output_dir = SOUTH
/// The turf the machines listens to for items to pick up. Calls the `pickup_item()` proc.
var/turf/input_turf = null
/// Determines if this machine needs to pick up items. Used to avoid registering signals to `/mineral` machines that don't pickup items.
var/needs_item_input = FALSE
/obj/machinery/mineral/Initialize(mapload)
. = ..()
if(needs_item_input && anchored)
register_input_turf()
/// Gets the turf in the `input_dir` direction adjacent to the machine, and registers signals for ATOM_ENTERED and ATOM_CREATED. Calls the `pickup_item()` proc when it receives these signals.
/obj/machinery/mineral/proc/register_input_turf()
input_turf = get_step(src, input_dir)
if(input_turf) // make sure there is actually a turf
RegisterSignal(input_turf, list(COMSIG_ATOM_CREATED, COMSIG_ATOM_ENTERED), .proc/pickup_item)
/// Unregisters signals that are registered the machine's input turf, if it has one.
/obj/machinery/mineral/proc/unregister_input_turf()
if(input_turf)
UnregisterSignal(input_turf, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_CREATED))
/obj/machinery/mineral/Moved()
. = ..()
if(!needs_item_input || !anchored)
return
unregister_input_turf()
register_input_turf()
/**
Base proc for all `/mineral` subtype machines to use. Place your item pickup behavior in this proc when you override it for your specific machine.
Called when the COMSIG_ATOM_ENTERED and COMSIG_ATOM_CREATED signals are sent.
Arguments:
* source - the turf that is listening for the signals.
* target - the atom that just moved onto the `source` turf.
* oldLoc - the old location that `target` was at before moving onto `source`.
*/
/obj/machinery/mineral/proc/pickup_item(datum/source, atom/movable/target, atom/oldLoc)
return
/// Generic unloading proc. Takes an atom as an argument and forceMove's it to the turf adjacent to this machine in the `output_dir` direction.
/obj/machinery/mineral/proc/unload_mineral(atom/movable/S)
S.forceMove(drop_location())
var/turf/T = get_step(src,output_dir)
@@ -19,7 +64,6 @@
density = TRUE
var/obj/machinery/mineral/processing_unit/machine = null
var/machinedir = EAST
speed_process = TRUE
/obj/machinery/mineral/processing_unit_console/Initialize()
. = ..()
@@ -58,6 +102,7 @@
if(href_list["set_on"])
machine.on = (href_list["set_on"] == "on")
START_PROCESSING(SSmachines, machine)
updateUsrDialog()
return
@@ -75,6 +120,7 @@
icon = 'icons/obj/machines/mining_machines.dmi'
icon_state = "furnace"
density = TRUE
needs_item_input = TRUE
var/obj/machinery/mineral/CONSOLE = null
var/on = FALSE
var/datum/material/selected_material = null
@@ -93,9 +139,6 @@
QDEL_NULL(stored_research)
return ..()
/obj/machinery/mineral/processing_unit/HasProximity(atom/movable/AM)
if(istype(AM, /obj/item/stack/ore) && AM.loc == get_step(src, input_dir))
process_ore(AM)
/obj/machinery/mineral/processing_unit/proc/process_ore(obj/item/stack/ore/O)
if(QDELETED(O))
@@ -144,8 +187,14 @@
return dat
/obj/machinery/mineral/processing_unit/pickup_item(datum/source, atom/movable/target, atom/oldLoc)
if(QDELETED(target))
return
if(istype(target, /obj/item/stack/ore))
process_ore(target)
/obj/machinery/mineral/processing_unit/process()
if (on)
if(on)
if(selected_material)
smelt_ore()
@@ -155,6 +204,8 @@
if(CONSOLE)
CONSOLE.updateUsrDialog()
else
STOP_PROCESSING(SSmachines, src)
/obj/machinery/mineral/processing_unit/proc/smelt_ore()
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
+1 -1
View File
@@ -198,7 +198,7 @@
/obj/machinery/mineral/ore_redemption/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ore_redemption_machine", "Ore Redemption Machine", 440, 550, master_ui, state)
ui = new(user, src, ui_key, "OreRedemptionMachine", "Ore Redemption Machine", 440, 550, master_ui, state)
ui.open()
/obj/machinery/mineral/ore_redemption/ui_data(mob/user)
+77 -32
View File
@@ -7,6 +7,8 @@
icon_state = "mining"
density = TRUE
circuit = /obj/item/circuitboard/machine/mining_equipment_vendor
ui_x = 425
ui_y = 600
var/icon_deny = "mining-deny"
var/obj/item/card/id/inserted_id
var/list/prize_list = list( //if you add something to this, please, for the love of god, sort it by price/type. use tabs and not spaces.
@@ -84,9 +86,14 @@
src.equipment_path = path
src.cost = cost
/obj/machinery/mineral/equipment_vendor/power_change()
..()
update_icon()
/obj/machinery/mineral/equipment_vendor/Initialize()
. = ..()
build_inventory()
/obj/machinery/mineral/equipment_vendor/proc/build_inventory()
for(var/p in prize_list)
var/datum/data/mining_equipment/M = p
GLOB.vending_products[M.equipment_path] = 1
/obj/machinery/mineral/equipment_vendor/update_icon_state()
if(powered())
@@ -94,44 +101,82 @@
else
icon_state = "[initial(icon_state)]-off"
/obj/machinery/mineral/equipment_vendor/ui_interact(mob/user)
. = ..()
var/list/dat = list()
dat += "<br><b>Equipment point cost list:</b><BR><table border='0' width='300'>"
/obj/machinery/mineral/equipment_vendor/ui_base_html(html)
var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/vending)
. = replacetext(html, "<!--customheadhtml-->", assets.css_tag())
/obj/machinery/mineral/equipment_vendor/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/vending)
assets.send(user)
ui = new(user, src, ui_key, "MiningVendor", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/mineral/equipment_vendor/ui_static_data(mob/user)
. = list()
.["product_records"] = list()
for(var/datum/data/mining_equipment/prize in prize_list)
dat += "<tr><td>[prize.equipment_name]</td><td>[prize.cost]</td><td><A href='?src=[REF(src)];purchase=[REF(prize)]'>Purchase</A></td></tr>"
dat += "</table>"
var/list/product_data = list(
path = replacetext(replacetext("[prize.equipment_path]", "/obj/item/", ""), "/", "-"),
name = prize.equipment_name,
price = prize.cost,
ref = REF(prize)
)
.["product_records"] += list(product_data)
var/datum/browser/popup = new(user, "miningvendor", "Mining Equipment Vendor", 400, 350)
popup.set_content(dat.Join())
popup.open()
return
/obj/machinery/mineral/equipment_vendor/ui_data(mob/user)
. = list()
var/mob/living/carbon/human/H
var/obj/item/card/id/C
if(ishuman(user))
H = user
C = H.get_idcard(TRUE)
if(C)
.["user"] = list()
.["user"]["points"] = C.mining_points
if(C.assignment)
.["user"]["job"] = C.assignment
else
.["user"]["job"] = "No Job"
/obj/machinery/mineral/equipment_vendor/Topic(href, href_list)
/obj/machinery/mineral/equipment_vendor/ui_act(action, params)
if(..())
return
if(href_list["purchase"])
var/mob/M = usr
var/obj/item/card/id/I = M.get_idcard(TRUE)
if(istype(I))
var/datum/data/mining_equipment/prize = locate(href_list["purchase"]) in prize_list
if (!prize || !(prize in prize_list))
to_chat(usr, "<span class='warning'>Error: Invalid choice!</span>")
switch(action)
if("purchase")
var/mob/M = usr
var/obj/item/card/id/I = M.get_idcard(TRUE)
if(!istype(I))
to_chat(usr, "<span class='alert'>Error: An ID is required!</span>")
flick(icon_deny, src)
return
var/datum/data/mining_equipment/prize = locate(params["ref"]) in prize_list
if(!prize || !(prize in prize_list))
to_chat(usr, "<span class='alert'>Error: Invalid choice!</span>")
flick(icon_deny, src)
return
if(prize.cost > I.mining_points)
to_chat(usr, "<span class='warning'>Error: Insufficient credits for [prize.equipment_name] on [I]!</span>")
to_chat(usr, "<span class='alert'>Error: Insufficient points for [prize.equipment_name] on [I]!</span>")
flick(icon_deny, src)
else
I.mining_points -= prize.cost
to_chat(usr, "<span class='notice'>[src] clanks to life briefly before vending [prize.equipment_name]!</span>")
new prize.equipment_path(src.loc)
SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]"))
else
to_chat(usr, "<span class='warning'>Error: An ID with a registered account is required!</span>")
flick(icon_deny, src)
updateUsrDialog()
return
return
I.mining_points -= prize.cost
to_chat(usr, "<span class='notice'>[src] clanks to life briefly before vending [prize.equipment_name]!</span>")
new prize.equipment_path(loc)
SSblackbox.record_feedback("nested tally", "mining_equipment_bought", 1, list("[type]", "[prize.equipment_path]"))
. = TRUE
/obj/machinery/mineral/equipment_vendor/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/mining_voucher))
RedeemVoucher(I, user)
return
if(default_deconstruction_screwdriver(user, "mining-open", "mining", I))
return
if(default_deconstruction_crowbar(I))
return
return ..()
/obj/machinery/mineral/equipment_vendor/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/mining_voucher))
+96 -77
View File
@@ -6,12 +6,15 @@
icon = 'icons/obj/economy.dmi'
icon_state = "coinpress0"
density = TRUE
var/newCoins = 0 //how many coins the machine made in it's last load
input_dir = EAST
ui_x = 300
ui_y = 250
needs_item_input = TRUE
var/obj/item/storage/bag/money/bag_to_use
var/produced_coins = 0 // how many coins the machine has made in it's last cycle
var/processing = FALSE
var/chosen = /datum/material/iron //which material will be used to make coins
var/coinsToProduce = 10
speed_process = TRUE
var/obj/item/storage/bag/money/bag_to_use
/obj/machinery/mineral/mint/Initialize()
. = ..()
@@ -28,89 +31,105 @@
/datum/material/mythril,
/datum/material/plastic,
/datum/material/runite
), MINERAL_MATERIAL_AMOUNT * 50, FALSE, /obj/item/stack)
chosen = SSmaterials.GetMaterialRef(chosen)
), MINERAL_MATERIAL_AMOUNT * 75, FALSE, /obj/item/stack)
chosen = SSmaterials.GetMaterialRef(chosen)
/obj/machinery/mineral/mint/process()
var/turf/T = get_step(src, input_dir)
if(!T)
/obj/machinery/mineral/mint/pickup_item(datum/source, atom/movable/target, atom/oldLoc)
if(QDELETED(target))
return
if(!istype(target, /obj/item/stack))
return
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/obj/item/stack/sheet/O in T)
var/inserted = materials.insert_item(O)
if(inserted)
qdel(O)
var/obj/item/stack/S = target
/obj/machinery/mineral/mint/attack_hand(mob/user)
if(materials.insert_item(S))
qdel(S)
/obj/machinery/mineral/mint/process()
if(processing)
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
var/datum/material/M = chosen
if(!M)
processing = FALSE
icon_state = "coinpress0"
return
icon_state = "coinpress1"
var/coin_mat = MINERAL_MATERIAL_AMOUNT
for(var/sheets in 1 to 2)
if(materials.use_amount_mat(coin_mat, chosen))
for(var/coin_to_make in 1 to 5)
create_coins()
produced_coins++
CHECK_TICK
else
var/found_new = FALSE
for(var/datum/material/inserted_material in materials.materials)
var/amount = materials.get_material_amount(inserted_material)
if(amount)
chosen = inserted_material
found_new = TRUE
if(!found_new)
processing = FALSE
else
STOP_PROCESSING(SSmachines, src)
icon_state = "coinpress0"
/obj/machinery/mineral/mint/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "Mint", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/machinery/mineral/mint/ui_data()
var/list/data = list()
data["inserted_materials"] = list()
data["chosen_material"] = null
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/datum/material/inserted_material in materials.materials)
var/amount = materials.get_material_amount(inserted_material)
if(!amount)
continue
data["inserted_materials"] += list(list(
"material" = inserted_material.name,
"amount" = amount,
))
if(chosen == inserted_material)
data["chosen_material"] = inserted_material.name
data["produced_coins"] = produced_coins
data["processing"] = processing
return data;
/obj/machinery/mineral/mint/ui_act(action, params, datum/tgui/ui)
. = ..()
if(.)
return
var/dat = "<b>Coin Press</b><br>"
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/datum/material/M in materials.materials)
var/amount = materials.get_material_amount(M)
if(!amount && chosen != M)
continue
dat += "<br><b>[M.name] amount:</b> [amount] cm<sup>3</sup> "
if (chosen == M)
dat += "<b>Chosen</b>"
else
dat += "<A href='?src=[REF(src)];choose=[REF(M)]'>Choose</A>"
var/datum/material/M = chosen
dat += "<br><br>Will produce [coinsToProduce] [lowertext(M.name)] coins if enough materials are available.<br>"
dat += "<A href='?src=[REF(src)];chooseAmt=-10'>-10</A> "
dat += "<A href='?src=[REF(src)];chooseAmt=-5'>-5</A> "
dat += "<A href='?src=[REF(src)];chooseAmt=-1'>-1</A> "
dat += "<A href='?src=[REF(src)];chooseAmt=1'>+1</A> "
dat += "<A href='?src=[REF(src)];chooseAmt=5'>+5</A> "
dat += "<A href='?src=[REF(src)];chooseAmt=10'>+10</A> "
dat += "<br><br>In total this machine produced <font color='green'><b>[newCoins]</b></font> coins."
dat += "<br><A href='?src=[REF(src)];makeCoins=[1]'>Make coins</A>"
user << browse(dat, "window=mint")
/obj/machinery/mineral/mint/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
src.add_fingerprint(usr)
if(processing==1)
to_chat(usr, "<span class='notice'>The machine is processing.</span>")
return
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
if(href_list["choose"])
var/datum/material/new_material = locate(href_list["choose"])
if(istype(new_material))
chosen = new_material
if(href_list["chooseAmt"])
coinsToProduce = clamp(coinsToProduce + text2num(href_list["chooseAmt"]), 0, 1000)
updateUsrDialog()
if(href_list["makeCoins"])
var/temp_coins = coinsToProduce
if(action == "startpress")
if (!processing)
produced_coins = 0
processing = TRUE
icon_state = "coinpress1"
var/coin_mat = MINERAL_MATERIAL_AMOUNT * 0.2
var/datum/material/M = chosen
if(!M)
updateUsrDialog()
return
while(coinsToProduce > 0 && materials.use_amount_mat(coin_mat, chosen))
create_coins()
coinsToProduce--
newCoins++
src.updateUsrDialog()
sleep(5)
icon_state = "coinpress0"
START_PROCESSING(SSmachines, src)
return TRUE
if (action == "stoppress")
processing = FALSE
coinsToProduce = temp_coins
src.updateUsrDialog()
return
STOP_PROCESSING(SSmachines, src)
return TRUE
if (action == "changematerial")
var/datum/component/material_container/materials = GetComponent(/datum/component/material_container)
for(var/datum/material/mat in materials.materials)
if (params["material_name"] == mat.name)
chosen = mat
return TRUE
/obj/machinery/mineral/mint/proc/create_coins()
var/turf/T = get_step(src,output_dir)
+7 -4
View File
@@ -9,6 +9,9 @@
density = TRUE
pressure_resistance = 5*ONE_ATMOSPHERE
var/ui_x = 335
var/ui_y = 415
/obj/structure/ore_box/attackby(obj/item/W, mob/user, params)
if (istype(W, /obj/item/stack/ore))
user.transferItemToLoc(W, src)
@@ -24,16 +27,16 @@
/obj/structure/ore_box/crowbar_act(mob/living/user, obj/item/I)
if(I.use_tool(src, user, 50, volume=50))
user.visible_message("[user] pries \the [src] apart.",
user.visible_message("<span class='notice'>[user] pries \the [src] apart.</span>",
"<span class='notice'>You pry apart \the [src].</span>",
"<span class='italics'>You hear splitting wood.</span>")
"<span class='hear'>You hear splitting wood.</span>")
deconstruct(TRUE, user)
return TRUE
/obj/structure/ore_box/examine(mob/living/user)
if(Adjacent(user) && istype(user))
ui_interact(user)
return ..()
. = ..()
/obj/structure/ore_box/attack_hand(mob/user)
. = ..()
@@ -62,7 +65,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "ore_box", name, 335, 415, master_ui, state)
ui = new(user, src, ui_key, "OreBox", name, ui_x, ui_y, master_ui, state)
ui.open()
/obj/structure/ore_box/ui_data()
@@ -24,7 +24,7 @@
/datum/notificationpanel/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "notificationpanel", "Notification Preferences", 270, 360, master_ui, state)
ui = new(user, src, ui_key, "NotificationPreferences", "Notification Preferences", 270, 360, master_ui, state)
ui.open()
/datum/notificationpanel/ui_data(mob/user)
+6 -4
View File
@@ -54,6 +54,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
// Used for displaying in ghost chat, without changing the actual name
// of the mob
var/deadchat_name
var/datum/orbit_menu/orbit_menu
var/datum/spawners_menu/spawners_menu
/mob/dead/observer/Initialize(mapload, mob/body)
@@ -161,6 +162,7 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
updateallghostimages()
QDEL_NULL(orbit_menu)
QDEL_NULL(spawners_menu)
return ..()
@@ -490,10 +492,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Orbit" // "Haunt"
set desc = "Follow and orbit a mob."
var/list/mobs = getpois(skip_mindless=1)
var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs
var/mob/target = mobs[input]
ManualFollow(target)
if(!orbit_menu)
orbit_menu = new(src)
orbit_menu.ui_interact(src)
// This is the ghost's follow verb with an argument
/mob/dead/observer/proc/ManualFollow(atom/movable/target)
+78
View File
@@ -0,0 +1,78 @@
/datum/orbit_menu
var/mob/dead/observer/owner
/datum/orbit_menu/New(mob/dead/observer/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/orbit_menu/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.observer_state)
if (!ui)
ui = new(user, src, ui_key, "Orbit", "Orbit", 350, 700, master_ui, state)
ui.open()
/datum/orbit_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if (..())
return
if (action == "orbit")
var/list/pois = getpois(skip_mindless = 1)
var/atom/movable/poi = pois[params["name"]]
if (poi != null)
owner.ManualFollow(poi)
ui.close()
/datum/orbit_menu/ui_data(mob/user)
var/list/data = list()
var/list/alive = list()
var/list/antagonists = list()
var/list/dead = list()
var/list/ghosts = list()
var/list/misc = list()
var/list/npcs = list()
var/list/pois = getpois(skip_mindless = 1)
for (var/name in pois)
var/list/serialized = list()
serialized["name"] = name
var/poi = pois[name]
var/mob/M = poi
if (istype(M))
if (isobserver(M))
ghosts += list(serialized)
else if (M.stat == DEAD)
dead += list(serialized)
else if (M.mind == null)
npcs += list(serialized)
else
var/number_of_orbiters = M.orbiters?.orbiters?.len
if (number_of_orbiters)
serialized["orbiters"] = number_of_orbiters
var/datum/mind/mind = M.mind
var/was_antagonist = FALSE
for (var/_A in mind.antag_datums)
var/datum/antagonist/A = _A
if (A.show_to_ghosts)
was_antagonist = TRUE
serialized["antag"] = A.name
antagonists += list(serialized)
break
if (!was_antagonist)
alive += list(serialized)
else
misc += list(serialized)
data["alive"] = alive
data["antagonists"] = antagonists
data["dead"] = dead
data["ghosts"] = ghosts
data["misc"] = misc
data["npcs"] = npcs
return data
@@ -25,7 +25,7 @@
status_flags = CANUNCONSCIOUS|CANPUSH
var/heat_protection = 0.5
heat_protection = 0.5
var/leaping = 0
gib_type = /obj/effect/decal/cleanable/blood/gibs/xeno
unique_name = 1
@@ -64,3 +64,11 @@
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
var/tackling = FALSE //Whether or not we are tackling, this will prevent the knock into effects for carbons
/// Protection (insulation) from the heat, Value 0-1 corresponding to the percentage of protection
var/heat_protection = 0 // No heat protection
/// Protection (insulation) from the cold, Value 0-1 corresponding to the percentage of protection
var/cold_protection = 0 // No cold protection
/// Timer id of any transformation
var/transformation_timer
@@ -33,6 +33,7 @@
enable_intentional_sprint_mode()
RegisterSignal(src, COMSIG_COMPONENT_CLEAN_ACT, /atom.proc/clean_blood)
GLOB.human_list += src
/mob/living/carbon/human/ComponentInitialize()
@@ -47,6 +48,7 @@
/mob/living/carbon/human/Destroy()
QDEL_NULL(physiology)
QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff
GLOB.human_list -= src
return ..()
/mob/living/carbon/human/prepare_data_huds()
@@ -382,7 +382,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
//keep it at the right spot, so we can't have people taking shortcuts
var/location = C.dna.mutation_index.Find(inert_mutation)
C.dna.mutation_index[location] = new_species.inert_mutation
C.dna.default_mutation_genes[location] = C.dna.mutation_index[location]
C.dna.mutation_index[new_species.inert_mutation] = create_sequence(new_species.inert_mutation)
C.dna.default_mutation_genes[new_species.inert_mutation] = C.dna.mutation_index[new_species.inert_mutation]
if(!new_species.has_field_of_vision && has_field_of_vision && ishuman(C) && CONFIG_GET(flag/use_field_of_vision))
var/datum/component/field_of_vision/F = C.GetComponent(/datum/component/field_of_vision)
@@ -314,7 +314,7 @@
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "slime_swap_body", name, 400, 400, master_ui, state)
ui = new(user, src, ui_key, "SlimeBodySwapper", name, 400, 400, master_ui, state)
ui.open()
/datum/action/innate/swap_body/ui_data(mob/user)
@@ -0,0 +1,74 @@
/datum/robot_control
var/mob/living/silicon/ai/owner
/datum/robot_control/New(mob/living/silicon/ai/new_owner)
if(!istype(new_owner))
qdel(src)
owner = new_owner
/datum/robot_control/proc/is_interactable(mob/user)
if(user != owner || owner.incapacitated())
return FALSE
if(owner.control_disabled)
to_chat(user, "<span class='warning'>Wireless control is disabled.</span>")
return FALSE
return TRUE
/datum/robot_control/ui_status(mob/user)
if(is_interactable(user))
return ..()
return UI_CLOSE
/datum/robot_control/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "RemoteRobotControl", "Remote Robot Control", 500, 500, master_ui, state)
ui.open()
/datum/robot_control/ui_data(mob/user)
if(!owner || user != owner)
return
var/list/data = list()
var/turf/ai_current_turf = get_turf(owner)
var/ai_zlevel = ai_current_turf.z
data["robots"] = list()
for(var/mob/living/simple_animal/bot/B in GLOB.bots_list)
if(B.z != ai_zlevel || B.remote_disabled) //Only non-emagged bots on the same Z-level are detected!
continue
var/list/robot_data = list(
name = B.name,
model = B.model,
mode = B.get_mode(),
hacked = B.hacked,
location = get_area_name(B, TRUE),
ref = REF(B)
)
data["robots"] += list(robot_data)
return data
/datum/robot_control/ui_act(action, params)
if(..())
return
if(!is_interactable(usr))
return
switch(action)
if("callbot") //Command a bot to move to a selected location.
if(owner.call_bot_cooldown > world.time)
to_chat(usr, "<span class='danger'>Error: Your last call bot command is still processing, please wait for the bot to finish calculating a route.</span>")
return
owner.Bot = locate(params["ref"]) in GLOB.bots_list
if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled)
return
owner.waypoint_mode = TRUE
to_chat(usr, "<span class='notice'>Set your waypoint by clicking on a valid location free of obstructions.</span>")
. = TRUE
if("interface") //Remotely connect to a bot!
owner.Bot = locate(params["ref"]) in GLOB.bots_list
if(!owner.Bot || owner.Bot.remote_disabled || owner.control_disabled)
return
owner.Bot.attack_ai(usr)
. = TRUE
@@ -115,6 +115,19 @@
else
return "<span class='average'>[mode_name[mode]]</span>"
/**
* Returns a status string about the bot's current status, if it's moving, manually controlled, or idle.
*/
/mob/living/simple_animal/bot/proc/get_mode_ui()
if(client) //Player bots do not have modes, thus the override. Also an easy way for PDA users/AI to know when a bot is a player.
return paicard ? "pAI Controlled" : "Autonomous"
else if(!on)
return "Inactive"
else if(!mode)
return "Idle"
else
return "[mode_name[mode]]"
/mob/living/simple_animal/bot/proc/turn_on()
if(stat)
return FALSE
@@ -174,7 +174,7 @@
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "mulebot", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, ui_key, "Mule", name, ui_x, ui_y, master_ui, state)
ui.open()
/mob/living/simple_animal/bot/mulebot/ui_data(mob/user)
+14
View File
@@ -558,3 +558,17 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
//Can the mob see reagents inside of containers?
/mob/proc/can_see_reagents()
return stat == DEAD || silicon_privileges //Dead guys and silicons can always see reagents
/mob/proc/is_blind()
SHOULD_BE_PURE(TRUE)
return eye_blind ? TRUE : HAS_TRAIT(src, TRAIT_BLIND)
/mob/proc/can_read(obj/O)
if(is_blind())
to_chat(src, "<span class='warning'>As you are trying to read [O], you suddenly feel very stupid!</span>")
return
if(!is_literate())
to_chat(src, "<span class='notice'>You try to read [O], but can't comprehend any of it.</span>")
return
return TRUE
+99 -48
View File
@@ -1,26 +1,8 @@
/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG))
if (mob_transforming)
#define TRANSFORMATION_DURATION 22
/mob/living/carbon/proc/monkeyize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_DEFAULTMSG))
if(mob_transforming || transformation_timer)
return
//Handle items on mob
//first implants & organs
var/list/stored_implants = list()
var/list/int_organs = list()
if (tr_flags & TR_KEEPIMPLANTS)
for(var/X in implants)
var/obj/item/implant/IMP = X
stored_implants += IMP
IMP.removed(src, 1, 1)
var/list/missing_bodyparts_zones = get_missing_limbs()
var/obj/item/cavity_object
var/obj/item/bodypart/chest/CH = get_bodypart(BODY_ZONE_CHEST)
if(CH.cavity_item)
cavity_object = CH.cavity_item
CH.cavity_item = null
if(tr_flags & TR_KEEPITEMS)
var/Itemlist = get_equipped_items(TRUE)
@@ -30,13 +12,36 @@
//Make mob invisible and spawn animation
mob_transforming = TRUE
Stun(INFINITY, ignore_canstun = TRUE)
Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE)
icon = null
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
new /obj/effect/temp_visual/monkeyify(loc)
sleep(22)
transformation_timer = addtimer(CALLBACK(src, .proc/finish_monkeyize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE)
/mob/living/carbon/proc/finish_monkeyize(tr_flags)
transformation_timer = null
var/list/missing_bodyparts_zones = get_missing_limbs()
var/list/stored_implants = list()
if (tr_flags & TR_KEEPIMPLANTS)
for(var/X in implants)
var/obj/item/implant/IMP = X
stored_implants += IMP
IMP.removed(src, 1, 1)
var/list/int_organs = list()
var/obj/item/cavity_object
var/obj/item/bodypart/chest/CH = get_bodypart(BODY_ZONE_CHEST)
if(CH.cavity_item)
cavity_object = CH.cavity_item
CH.cavity_item = null
var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey( loc )
// hash the original name?
@@ -50,6 +55,7 @@
if(tr_flags & TR_KEEPSE)
O.dna.mutation_index = dna.mutation_index
O.dna.default_mutation_genes = dna.default_mutation_genes
O.dna.set_se(1, GET_INITIALIZED_MUTATION(RACEMUT))
if(suiciding)
@@ -149,12 +155,33 @@
////////////////////////// Humanize //////////////////////////////
//Could probably be merged with monkeyize but other transformations got their own procs, too
/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_DEFAULTMSG))
if (mob_transforming)
/mob/living/carbon/proc/humanize(tr_flags = (TR_KEEPITEMS | TR_KEEPVIRUS | TR_KEEPSTUNS | TR_KEEPREAGENTS | TR_DEFAULTMSG))
if (mob_transforming || transformation_timer)
return
//Handle items on mob
//first implants & organs
//now the rest
if (tr_flags & TR_KEEPITEMS)
var/Itemlist = get_equipped_items(TRUE)
Itemlist += held_items
for(var/obj/item/W in Itemlist)
dropItemToGround(W, TRUE)
if (client)
client.screen -= W
//Make mob invisible and spawn animation
mob_transforming = TRUE
Paralyze(TRANSFORMATION_DURATION, ignore_canstun = TRUE)
icon = null
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
new /obj/effect/temp_visual/monkeyify/humanify(loc)
transformation_timer = addtimer(CALLBACK(src, .proc/finish_humanize, tr_flags), TRANSFORMATION_DURATION, TIMER_UNIQUE)
/mob/living/carbon/proc/finish_humanize(tr_flags)
transformation_timer = null
var/list/stored_implants = list()
var/list/int_organs = list()
@@ -173,25 +200,6 @@
cavity_object = CH.cavity_item
CH.cavity_item = null
//now the rest
if (tr_flags & TR_KEEPITEMS)
var/Itemlist = get_equipped_items(TRUE)
Itemlist += held_items
for(var/obj/item/W in Itemlist)
dropItemToGround(W, TRUE)
if (client)
client.screen -= W
//Make mob invisible and spawn animation
mob_transforming = TRUE
Stun(22, ignore_canstun = TRUE)
icon = null
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
new /obj/effect/temp_visual/monkeyify/humanify(loc)
sleep(22)
var/mob/living/carbon/human/O = new( loc )
for(var/obj/item/C in O.loc)
O.equip_to_appropriate_slot(C)
@@ -208,6 +216,7 @@
if(tr_flags & TR_KEEPSE)
O.dna.mutation_index = dna.mutation_index
O.dna.default_mutation_genes = dna.default_mutation_genes
O.dna.set_se(0, GET_INITIALIZED_MUTATION(RACEMUT))
O.domutcheck()
@@ -353,7 +362,7 @@
qdel(src)
/mob/living/carbon/human/proc/Robotize(delete_items = 0, transfer_after = TRUE)
if (mob_transforming)
if(mob_transforming)
return
for(var/obj/item/W in src)
if(delete_items)
@@ -582,6 +591,48 @@
. = new_mob
qdel(src)
/* Certain mob types have problems and should not be allowed to be controlled by players.
*
* This proc is here to force coders to manually place their mob in this list, hopefully tested.
* This also gives a place to explain -why- players shouldnt be turn into certain mobs and hopefully someone can fix them.
*/
/mob/proc/safe_animal(MP)
//Bad mobs! - Remember to add a comment explaining what's wrong with the mob
if(!MP)
return 0 //Sanity, this should never happen.
if(ispath(MP, /mob/living/simple_animal/hostile/construct))
return 0 //Verbs do not appear for players.
//Good mobs!
if(ispath(MP, /mob/living/simple_animal/pet/cat))
return 1
if(ispath(MP, /mob/living/simple_animal/pet/dog/corgi))
return 1
if(ispath(MP, /mob/living/simple_animal/crab))
return 1
if(ispath(MP, /mob/living/simple_animal/hostile/carp))
return 1
if(ispath(MP, /mob/living/simple_animal/hostile/mushroom))
return 1
if(ispath(MP, /mob/living/simple_animal/shade))
return 1
if(ispath(MP, /mob/living/simple_animal/hostile/killertomato))
return 1
if(ispath(MP, /mob/living/simple_animal/mouse))
return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak)
if(ispath(MP, /mob/living/simple_animal/hostile/bear))
return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak)
if(ispath(MP, /mob/living/simple_animal/parrot))
return 1 //Parrots are no longer unfinished! -Nodrak
//Not in here? Must be untested!
return 0
#undef TRANSFORMATION_DURATION
/mob/living/proc/turn_into_pickle()
//if they're already a pickle, turn them back instead
if(istype(src, /mob/living/simple_animal/pickle))
@@ -37,9 +37,9 @@
if (!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntos_main", "NtOS Main menu", 400, 500, master_ui, state)
ui.set_style("ntos")
assets = get_asset_datum(/datum/asset/simple/arcade)
assets.send(user)
ui = new(user, src, ui_key, "NtosMain", "NtOS Main menu", 400, 500, master_ui, state)
ui.open()
ui.set_autoupdate(state = 1)
@@ -85,3 +85,4 @@
var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
hard_drive.store_file(new/datum/computer_file/program/chatclient())
hard_drive.store_file(new/datum/computer_file/program/nttransfer())
hard_drive.store_file(new/datum/computer_file/program/arcade())
@@ -1,26 +1,45 @@
// /program/ files are executable programs that do things.
/datum/computer_file/program
filetype = "PRG"
filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET!
var/required_access = null // List of required accesses to *run* the program.
var/transfer_access = null // List of required access to download or file host the program
var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running.
var/obj/item/modular_computer/computer // Device that runs this program.
var/filedesc = "Unknown Program" // User-friendly name of this program.
var/extended_desc = "N/A" // Short description of this program's function.
var/program_icon_state = null // Program-specific screen icon state
var/requires_ntnet = 0 // Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes.
var/requires_ntnet_feature = 0 // Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION)
var/ntnet_status = 1 // NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc.
var/usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL
var/network_destination = null // Optional string that describes what NTNet server/system this program connects to. Used in default logging.
var/available_on_ntnet = 1 // Whether the program can be downloaded from NTNet. Set to 0 to disable.
var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
var/tgui_id // ID of TGUI interface
var/ui_style // ID of custom TGUI style (optional)
var/ui_x = 575 // Default size of TGUI window, in pixels
/// File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET!
filename = "UnknownProgram"
/// List of required accesses to *run* the program.
var/required_access = null
/// List of required access to download or file host the program
var/transfer_access = null
/// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running.
var/program_state = PROGRAM_STATE_KILLED
/// Device that runs this program.
var/obj/item/modular_computer/computer
/// User-friendly name of this program.
var/filedesc = "Unknown Program"
/// Short description of this program's function.
var/extended_desc = "N/A"
/// Program-specific screen icon state
var/program_icon_state = null
/// Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes.
var/requires_ntnet = FALSE
/// Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION)
var/requires_ntnet_feature = 0
/// NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc.
var/ntnet_status = 1
/// Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL
var/usage_flags = PROGRAM_ALL
/// Optional string that describes what NTNet server/system this program connects to. Used in default logging.
var/network_destination = null
/// Whether the program can be downloaded from NTNet. Set to 0 to disable.
var/available_on_ntnet = 1
/// Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable.
var/available_on_syndinet = 0
/// ID of TGUI interface
var/tgui_id
/// Default size of TGUI window, in pixels
var/ui_x = 575
var/ui_y = 700
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 /icons/program_icons. Be careful not to use too large images!
/// 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 /icons/program_icons. Be careful not to use too large images!
var/ui_header = null
///Assets specific to programs
var/list/special_assets = list()
/datum/computer_file/program/New(obj/item/modular_computer/comp = null)
..()
@@ -50,23 +69,23 @@
/datum/computer_file/program/proc/generate_network_log(text)
if(computer)
return computer.add_log(text)
return 0
return FALSE
/datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = 0, mob/user = null)
if(!(hardware_flag & usage_flags))
if(loud && computer && user)
to_chat(user, "<span class='danger'>\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.</span>")
return 0
return 1
return FALSE
return TRUE
/datum/computer_file/program/proc/get_signal(specific_action = 0)
if(computer)
return computer.get_ntnet_status(specific_action)
return 0
return FALSE
// Called by Process() on device that runs us, once every tick.
/datum/computer_file/program/proc/process_tick()
return 1
return TRUE
// Check if the user can run program. Only humans can operate computer. Automatically called in run_program()
// User has to wear their ID for ID Scan to work.
@@ -87,7 +106,7 @@
if(IsAdminGhost(user))
return TRUE
if(computer && computer.hasSiliconAccessInArea(user))
if(issilicon(user))
return TRUE
if(ishuman(user))
@@ -98,6 +117,7 @@
D = card_slot.GetID()
var/mob/living/carbon/human/h = user
var/obj/item/card/id/I = h.get_idcard(TRUE)
if(!I && !D)
if(loud)
to_chat(user, "<span class='danger'>\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.</span>")
@@ -123,7 +143,7 @@
// This is performed on program startup. May be overridden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure.
// When implementing new program based device, use this to run the program.
/datum/computer_file/program/proc/run_program(mob/living/user)
if(can_run(user, 1))
if(can_run(user, TRUE))
if(requires_ntnet && network_destination)
generate_network_log("Connection opened to [network_destination].")
program_state = PROGRAM_STATE_ACTIVE
@@ -143,12 +163,11 @@
if(!ui && tgui_id)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
for(var/i in special_assets)
assets = get_asset_datum(i)
assets.send(user)
ui = new(user, src, ui_key, tgui_id, filedesc, ui_x, ui_y, state = state)
if(ui_style)
ui.set_style(ui_style)
ui.set_autoupdate(state = 1)
ui.open()
// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC:
@@ -156,7 +175,7 @@
// 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/ui_act(action,params,datum/tgui/ui)
/datum/computer_file/program/ui_act(action,list/params,datum/tgui/ui)
if(..())
return TRUE
if(computer)
@@ -4,14 +4,14 @@
program_icon_state = "generic"
extended_desc = "This program is capable of reconstructing damaged AI systems. Requires direct AI connection via intellicard slot."
size = 12
requires_ntnet = 0
usage_flags = PROGRAM_CONSOLE
requires_ntnet = FALSE
usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP
transfer_access = ACCESS_HEADS
available_on_ntnet = 1
tgui_id = "ntos_ai_restorer"
ui_x = 600
available_on_ntnet = TRUE
tgui_id = "NtosAiRestorer"
ui_x = 370
ui_y = 400
/// Variable dictating if we are in the process of restoring the AI in the inserted intellicard
var/restoring = FALSE
/datum/computer_file/program/aidiag/proc/get_ai(cardcheck)
@@ -30,11 +30,11 @@
if(ai_slot.stored_card.AI)
return ai_slot.stored_card.AI
return null
return
/datum/computer_file/program/aidiag/ui_act(action, params)
if(..())
return TRUE
return
var/mob/living/silicon/ai/A = get_ai()
if(!A)
@@ -44,6 +44,7 @@
if("PRG_beginReconstruction")
if(A && A.health < 100)
restoring = TRUE
A.notify_ghost_cloning("Your core files are being restored!", source = computer)
return TRUE
if("PRG_eject")
if(computer.all_components[MC_AI])
@@ -53,7 +54,7 @@
return TRUE
/datum/computer_file/program/aidiag/process_tick()
..()
. = ..()
if(!restoring) //Put the check here so we don't check for an ai all the time
return
var/obj/item/aicard/cardhold = get_ai(2)
@@ -73,13 +74,13 @@
restoring = FALSE
return
ai_slot.locked =TRUE
A.adjustOxyLoss(-1, 0)
A.adjustFireLoss(-1, 0)
A.adjustToxLoss(-1, 0)
A.adjustBruteLoss(-1, 0)
A.adjustOxyLoss(-5, 0)
A.adjustFireLoss(-5, 0)
A.adjustToxLoss(-5, 0)
A.adjustBruteLoss(-5, 0)
A.updatehealth()
if(A.health >= 0 && A.stat == DEAD)
A.revive()
A.revive(full_heal = FALSE, admin_revive = FALSE)
// Finished restoring
if(A.health >= 100)
ai_slot.locked = FALSE
@@ -90,14 +91,14 @@
/datum/computer_file/program/aidiag/ui_data(mob/user)
var/list/data = get_header_data()
var/mob/living/silicon/ai/AI
// A shortcut for getting the AI stored inside the computer. The program already does necessary checks.
AI = get_ai()
var/mob/living/silicon/ai/AI = get_ai()
var/obj/item/aicard/aicard = get_ai(2)
data["ejectable"] = TRUE
data["AI_present"] = FALSE
data["error"] = null
if(!aicard)
data["nocard"] = TRUE
data["error"] = "Please insert an intelliCard."
else
if(!AI)
@@ -107,15 +108,15 @@
if(cardhold.flush)
data["error"] = "Flush in progress"
else
data["AI_present"] = TRUE
data["name"] = AI.name
data["restoring"] = restoring
data["laws"] = AI.laws.get_law_list(include_zeroth = 1)
data["health"] = (AI.health + 100) / 2
data["isDead"] = AI.stat == DEAD
data["ai_laws"] = AI.laws.get_law_list(include_zeroth = 1)
data["laws"] = AI.laws.get_law_list(include_zeroth = 1)
return data
/datum/computer_file/program/aidiag/kill_program(forced)
restoring = FALSE
return ..(forced)
return ..()
@@ -7,7 +7,7 @@
requires_ntnet = 1
network_destination = "alarm monitoring network"
size = 5
tgui_id = "ntos_station_alert"
tgui_id = "NtosStationAlertConsole"
ui_x = 315
ui_y = 500
@@ -72,15 +72,23 @@
/datum/computer_file/program/alarm_monitor/proc/cancelAlarm(class, area/A, obj/origin)
var/list/L = alarms[class]
var/cleared = 0
var/arealevelalarm = FALSE // set to TRUE for alarms that set/clear whole areas
if (class=="Fire")
arealevelalarm = TRUE
for (var/I in L)
if (I == A.name)
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
if (!arealevelalarm) // the traditional behaviour
var/list/alarm = L[I]
var/list/srcs = alarm[3]
if (origin in srcs)
srcs -= origin
if (srcs.len == 0)
cleared = 1
L -= I
else
L -= I // wipe the instances entirely
cleared = 1
L -= I
update_alarm_display()
return !cleared
@@ -8,20 +8,20 @@
available_on_ntnet = 0
unsendable = 1
undeletable = 1
tgui_id = "synd_contract"
ui_style = "syndicate"
ui_x = 600
tgui_id = "SyndContractor"
ui_x = 500
ui_y = 600
var/error = ""
var/page = CONTRACT_UPLINK_PAGE_CONTRACTS
var/info_screen = TRUE
var/assigned = FALSE
var/first_load = TRUE
/datum/computer_file/program/contract_uplink/run_program(var/mob/living/user)
. = ..(user)
/datum/computer_file/program/contract_uplink/ui_act(action, params)
if(..())
return 1
return TRUE
var/mob/living/user = usr
var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD]
switch(action)
@@ -31,27 +31,32 @@
hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ACTIVE
hard_drive.traitor_data.contractor_hub.current_contract = hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id]
program_icon_state = "single_contract"
return 1
return TRUE
if("PRG_login")
var/datum/antagonist/traitor/traitor_data = user.mind.has_antag_datum(/datum/antagonist/traitor)
if(traitor_data) // Bake their data right into the hard drive, or we don't allow non-antags gaining access to unused contract system. We also create their contracts at this point.
if(!traitor_data.contractor_hub) // Only play greet sound, and handle contractor hub when assigning for the first time.
// Bake their data right into the hard drive, or we don't allow non-antags gaining access to an unused
// contract system.
// We also create their contracts at this point.
if(traitor_data)
// Only play greet sound, and handle contractor hub when assigning for the first time.
if(!traitor_data.contractor_hub)
user.playsound_local(user, 'sound/effects/contractstartup.ogg', 100, FALSE)
traitor_data.contractor_hub = new
traitor_data.contractor_hub.create_hub_items()
user.playsound_local(user, 'sound/effects/contractstartup.ogg', 100, 0)
// Stops any topic exploits such as logging in multiple times on a single system.
// Stops any topic exploits such as logging in multiple times on a single system.
if(!assigned)
traitor_data.contractor_hub.create_contracts(traitor_data.owner)
hard_drive.traitor_data = traitor_data
program_icon_state = "contracts"
assigned = TRUE
else
error = "Incorrect login details."
return 1
error = "UNAUTHORIZED USER"
return TRUE
if("PRG_call_extraction")
if(hard_drive.traitor_data.contractor_hub.current_contract.status != CONTRACT_STATUS_EXTRACTING)
if(hard_drive.traitor_data.contractor_hub.current_contract.handle_extraction(user))
user.playsound_local(user, 'sound/effects/confirmdropoff.ogg', 100, 1)
user.playsound_local(user, 'sound/effects/confirmdropoff.ogg', 100, TRUE)
hard_drive.traitor_data.contractor_hub.current_contract.status = CONTRACT_STATUS_EXTRACTING
program_icon_state = "extracted"
else
@@ -59,17 +64,18 @@
error = "Either both you or your target aren't at the dropoff location, or the pod hasn't got a valid place to land. Clear space, or make sure you're both inside."
else
user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50)
error = "Already extracting... Place the target into the pod. If the pod was destroyed, you will need to cancel this contract."
return 1
error = "Already extracting... Place the target into the pod. If the pod was destroyed, this contract is no longer possible."
return TRUE
if("PRG_contract_abort")
var/contract_id = hard_drive.traitor_data.contractor_hub.current_contract.id
hard_drive.traitor_data.contractor_hub.current_contract = null
hard_drive.traitor_data.contractor_hub.assigned_contracts[contract_id].status = CONTRACT_STATUS_ABORTED
program_icon_state = "contracts"
return 1
return TRUE
if("PRG_redeem_TC")
if(hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem)
var/obj/item/stack/telecrystal/crystals = new /obj/item/stack/telecrystal(get_turf(user), hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem)
var/obj/item/stack/telecrystal/crystals = new /obj/item/stack/telecrystal(get_turf(user),
hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.put_in_hands(crystals))
@@ -78,22 +84,23 @@
to_chat(user, "<span class='notice'>Your payment materializes onto the floor.</span>")
hard_drive.traitor_data.contractor_hub.contract_TC_payed_out += hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem
hard_drive.traitor_data.contractor_hub.contract_TC_to_redeem = 0
return 1
return TRUE
else
user.playsound_local(user, 'sound/machines/uplinkerror.ogg', 50)
return 1
return TRUE
if("PRG_clear_error")
error = ""
if("PRG_contractor_hub")
page = CONTRACT_UPLINK_PAGE_HUB
program_icon_state = "store"
if("PRG_hub_back")
page = CONTRACT_UPLINK_PAGE_CONTRACTS
program_icon_state = "contracts"
return TRUE
if("PRG_set_first_load_finished")
first_load = FALSE
return TRUE
if("PRG_toggle_info")
info_screen = !info_screen
return TRUE
if("buy_hub")
if(hard_drive.traitor_data.owner.current == user)
var/item = params["item"]
for (var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items)
for(var/datum/contractor_item/hub_item in hard_drive.traitor_data.contractor_hub.hub_items)
if (hub_item.name == item)
hub_item.handle_purchase(hard_drive.traitor_data.contractor_hub, user)
else
@@ -104,21 +111,28 @@
var/obj/item/computer_hardware/hard_drive/small/syndicate/hard_drive = computer.all_components[MC_HDD]
var/screen_to_be = null
data["first_load"] = first_load
if(hard_drive && hard_drive.traitor_data != null)
var/datum/antagonist/traitor/traitor_data = hard_drive.traitor_data
error = ""
data = get_header_data()
data += get_header_data()
if(traitor_data.contractor_hub.current_contract)
data["ongoing_contract"] = TRUE
screen_to_be = "single_contract"
if(traitor_data.contractor_hub.current_contract.status == CONTRACT_STATUS_EXTRACTING)
data["extraction_enroute"] = TRUE
screen_to_be = "extracted"
else
data["extraction_enroute"] = FALSE
else
data["ongoing_contract"] = FALSE
data["extraction_enroute"] = FALSE
data["logged_in"] = TRUE
data["station_name"] = GLOB.station_name
data["redeemable_tc"] = traitor_data.contractor_hub.contract_TC_to_redeem
data["earned_tc"] = traitor_data.contractor_hub.contract_TC_payed_out
data["contracts_completed"] = traitor_data.contractor_hub.contracts_completed
data["contract_rep"] = traitor_data.contractor_hub.contract_rep
data["page"] = page
data["info_screen"] = info_screen
data["error"] = error
for(var/datum/contractor_item/hub_item in traitor_data.contractor_hub.hub_items)
data["contractor_hub_items"] += list(list(
@@ -136,7 +150,8 @@
"payout_bonus" = contract.contract.payout_bonus,
"dropoff" = contract.contract.dropoff,
"id" = contract.id,
"status" = contract.status
"status" = contract.status,
"message" = contract.wanted_message
))
var/direction
@@ -155,14 +170,8 @@
else
direction = "???"
data["dropoff_direction"] = direction
if (page == CONTRACT_UPLINK_PAGE_HUB)
screen_to_be = "store"
if (!screen_to_be)
screen_to_be = "contracts"
else
data["logged_in"] = FALSE
if (!screen_to_be)
screen_to_be = "assign"
program_icon_state = screen_to_be
update_computer_icon()
return data
return data
@@ -4,11 +4,10 @@
program_icon_state = "hostile"
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
tgui_id = "ntos_net_dos"
ui_style = "syndicate"
requires_ntnet = TRUE
available_on_ntnet = FALSE
available_on_syndinet = TRUE
tgui_id = "NtosNetDos"
ui_x = 400
ui_y = 250
@@ -37,64 +36,55 @@
if(target)
target.dos_sources.Remove(src)
target = null
executed = 0
executed = FALSE
..()
/datum/computer_file/program/ntnet_dos/ui_act(action, params)
if(..())
return 1
return
switch(action)
if("PRG_target_relay")
for(var/obj/machinery/ntnet_relay/R in SSnetworks.station_network.relays)
if("[R.uid]" == params["targid"])
target = R
return 1
break
return TRUE
if("PRG_reset")
if(target)
target.dos_sources.Remove(src)
target = null
executed = 0
executed = FALSE
error = ""
return 1
return TRUE
if("PRG_execute")
if(target)
executed = 1
executed = TRUE
target.dos_sources.Add(src)
if(SSnetworks.station_network.intrusion_detection_enabled)
var/obj/item/computer_hardware/network_card/network_card = computer.all_components[MC_NET]
SSnetworks.station_network.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]")
SSnetworks.station_network.intrusion_detection_alarm = 1
return 1
SSnetworks.station_network.intrusion_detection_alarm = TRUE
return TRUE
/datum/computer_file/program/ntnet_dos/ui_data(mob/user)
if(!SSnetworks.station_network)
return
var/list/data = list()
var/list/data = get_header_data()
data = get_header_data()
if(error)
data["error"] = error
else if(target && executed)
data["target"] = 1
data["error"] = error
if(target && executed)
data["target"] = TRUE
data["speed"] = dos_speed
// 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 = target.dos_overload * 100 / target.dos_capacity
data["dos_strings"] = list()
for(var/j, j<10, j++)
var/string = ""
for(var/i, i<20, i++)
string = "[string][prob(percentage)]"
data["dos_strings"] += list(list("nums" = string))
data["overload"] = target.dos_overload
data["capacity"] = target.dos_capacity
else
data["target"] = FALSE
data["relays"] = list()
for(var/obj/machinery/ntnet_relay/R in SSnetworks.station_network.relays)
data["relays"] += list(list("id" = R.uid))
data["focus"] = target ? target.uid : null
return data
return data
@@ -4,11 +4,10 @@
program_icon_state = "hostile"
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
tgui_id = "ntos_revelation"
ui_style = "syndicate"
requires_ntnet = FALSE
available_on_ntnet = FALSE
available_on_syndinet = TRUE
tgui_id = "NtosRevelation"
ui_x = 400
ui_y = 250
@@ -22,7 +21,7 @@
/datum/computer_file/program/revelation/proc/activate()
if(computer)
computer.visible_message("<span class='notice'>\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.</span>")
computer.enabled = 0
computer.enabled = FALSE
computer.update_icon()
var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
var/obj/item/computer_hardware/battery/battery_module = computer.all_components[MC_CELL]
@@ -44,18 +43,20 @@
/datum/computer_file/program/revelation/ui_act(action, params)
if(..())
return 1
return
switch(action)
if("PRG_arm")
armed = !armed
return TRUE
if("PRG_activate")
activate()
return TRUE
if("PRG_obfuscate")
var/mob/living/user = usr
var/newname = sanitize(input(user, "Enter new program name: "))
var/newname = params["new_name"]
if(!newname)
return
filedesc = newname
return TRUE
/datum/computer_file/program/revelation/clone()
@@ -68,4 +69,4 @@
data["armed"] = armed
return data
return data
@@ -0,0 +1,169 @@
/datum/computer_file/program/arcade
filename = "arcade"
filedesc = "Nanotrasen Micro Arcade"
program_icon_state = "arcade"
extended_desc = "This port of the classic game 'Outbomb Cuban Pete', redesigned to run on tablets, with thrilling graphics and chilling storytelling."
requires_ntnet = FALSE
network_destination = "arcade network"
size = 6
tgui_id = "NtosArcade"
ui_x = 450
ui_y = 350
///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
/datum/computer_file/program/arcade/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
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()
sleep(10)
/datum/computer_file/program/arcade/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
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
pause_state = FALSE
game_check()
/datum/computer_file/program/arcade/ui_interact(mob/user, ui_key, datum/tgui/ui, force_open, datum/tgui/master_ui, datum/ui_state/state)
. = ..()
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/arcade)
assets.send(user)
/datum/computer_file/program/arcade/ui_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
/datum/computer_file/program/arcade/ui_act(action, list/params)
if(..())
return TRUE
var/obj/item/computer_hardware/printer/printer
if(computer)
printer = computer.all_components[MC_PRINT]
switch(action)
if("Attack")
var/attackamt = 0 //Spam prevention.
if(pause_state == FALSE)
attackamt = rand(2,6)
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)
var/maxPointCost = 3
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)
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, "<span class='notice'>Hardware error: A printer is required to redeem tickets.</span>")
return
if(printer.stored_paper <= 0)
to_chat(usr, "<span class='notice'>Hardware error: Printer is out of paper.</span>")
return
else
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
if(ticket_count >= 1)
new /obj/item/stack/arcadeticket((get_turf(computer)), 1)
to_chat(usr, "<span class='notice'>[src] dispenses a ticket!</span>")
ticket_count -= 1
printer.stored_paper -= 1
else
to_chat(usr, "<span class='notice'>You don't have any stored tickets!</span>")
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()
@@ -0,0 +1,33 @@
/datum/computer_file/program/atmosscan
filename = "atmosscan"
filedesc = "Atmospheric Scanner"
program_icon_state = "air"
extended_desc = "A small built-in sensor reads out the atmospheric conditions around the device."
network_destination = "atmos scan"
size = 4
tgui_id = "NtosAtmos"
ui_x = 300
ui_y = 350
/datum/computer_file/program/atmosscan/ui_data(mob/user)
var/list/data = get_header_data()
var/list/airlist = list()
var/turf/T = get_turf(ui_host())
if(T)
var/datum/gas_mixture/environment = T.return_air()
var/list/env_gases = environment.gases
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
data["AirPressure"] = round(pressure,0.1)
data["AirTemp"] = round(environment.temperature-T0C)
if (total_moles)
for(var/id in env_gases)
var/gas_level = env_gases[id][MOLES]/total_moles
if(gas_level > 0)
airlist += list(list("name" = "[env_gases[id][GAS_META][META_GAS_NAME]]", "percentage" = round(gas_level*100, 0.01)))
data["AirData"] = airlist
return data
/datum/computer_file/program/atmosscan/ui_act(action, list/params)
if(..())
return TRUE
@@ -0,0 +1,69 @@
/datum/computer_file/program/borg_monitor
filename = "cyborgmonitor"
filedesc = "Cyborg Remote Monitoring"
ui_header = "borg_mon.gif"
program_icon_state = "generic"
extended_desc = "This program allows for remote monitoring of station cyborgs."
requires_ntnet = TRUE
transfer_access = ACCESS_ROBOTICS
network_destination = "cyborg remote monitoring"
size = 5
tgui_id = "NtosCyborgRemoteMonitor"
ui_x = 600
ui_y = 800
/datum/computer_file/program/borg_monitor/ui_data(mob/user)
var/list/data = get_header_data()
data["card"] = FALSE
if(computer.GetID())
data["card"] = TRUE
data["cyborgs"] = list()
for(var/mob/living/silicon/robot/R in GLOB.silicon_mobs)
if((get_turf(computer)).z != (get_turf(R)).z)
continue
if(R.scrambledcodes)
continue
var/list/upgrade
for(var/obj/item/borg/upgrade/I in R.upgrades)
upgrade += "\[[I.name]\] "
var/shell = FALSE
if(R.shell && !R.ckey)
shell = TRUE
var/list/cyborg_data = list(
name = R.name,
locked_down = R.locked_down,
status = R.stat,
shell_discon = shell,
charge = R.cell ? round(R.cell.percent()) : null,
module = R.module ? "[R.module.name] Module" : "No Module Detected",
upgrades = upgrade,
ref = REF(R)
)
data["cyborgs"] += list(cyborg_data)
return data
/datum/computer_file/program/borg_monitor/ui_act(action, params)
if(..())
return
switch(action)
if("messagebot")
var/mob/living/silicon/robot/R = locate(params["ref"]) in GLOB.silicon_mobs
if(!istype(R))
return
var/obj/item/card/id/ID = computer.GetID()
if(!ID)
return
var/message = stripped_input(usr, message = "Enter message to be sent to remote cyborg.", title = "Send Message")
if(!message)
return
to_chat(R, "<br><br><span class='notice'>Message from [ID.registered_name] -- \"[message]\"</span><br>")
SEND_SOUND(R, 'sound/machines/twobeep_high.ogg')
if(R.connected_ai)
to_chat(R.connected_ai, "<br><br><span class='notice'>Message from [ID.registered_name] to [R] -- \"[message]\"</span><br>")
SEND_SOUND(R.connected_ai, 'sound/machines/twobeep_high.ogg')
@@ -1,3 +1,11 @@
#define CARDCON_DEPARTMENT_SERVICE "Service"
#define CARDCON_DEPARTMENT_SECURITY "Security"
#define CARDCON_DEPARTMENT_MEDICAL "Medical"
#define CARDCON_DEPARTMENT_SUPPLY "Supply"
#define CARDCON_DEPARTMENT_SCIENCE "Science"
#define CARDCON_DEPARTMENT_ENGINEERING "Engineering"
#define CARDCON_DEPARTMENT_COMMAND "Command"
/datum/computer_file/program/card_mod
filename = "cardmod"
filedesc = "ID Card Modification"
@@ -6,97 +14,90 @@
transfer_access = ACCESS_HEADS
requires_ntnet = 0
size = 8
tgui_id = "ntos_card"
ui_x = 600
ui_y = 700
tgui_id = "NtosCard"
ui_x = 450
ui_y = 520
var/mod_mode = 1
var/is_centcom = 0
var/show_assignments = 0
var/minor = 0
var/authenticated = 0
var/list/reg_ids = list()
var/list/region_access = null
var/list/head_subordinates = null
var/target_dept = 0 //Which department this computer has access to. 0=all departments
var/change_position_cooldown = 30
//Jobs you cannot open new positions for
var/list/blacklisted = list(
"AI",
"Assistant",
"Cyborg",
"Captain",
"Head of Personnel",
"Head of Security",
"Chief Engineer",
"Research Director",
"Chief Medical Officer")
var/is_centcom = FALSE
var/minor = FALSE
var/authenticated = FALSE
var/list/region_access
var/list/head_subordinates
///Which departments this computer has access to. Defined as access regions. null = all departments
var/target_dept
//The scaling factor of max total positions in relation to the total amount of people on board the station in %
var/max_relative_positions = 30 //30%: Seems reasonable, limit of 6 @ 20 players
//For some reason everything was exploding if this was static.
var/list/sub_managers
//This is used to keep track of opened positions for jobs to allow instant closing
//Assoc array: "JobName" = (int)<Opened Positions>
var/list/opened_positions = list();
/datum/computer_file/program/card_mod/New(obj/item/modular_computer/comp)
. = ..()
sub_managers = list(
"[ACCESS_HOP]" = list(
"department" = list(CARDCON_DEPARTMENT_SERVICE, CARDCON_DEPARTMENT_COMMAND),
"region" = 1,
"head" = "Head of Personnel"
),
"[ACCESS_HOS]" = list(
"department" = CARDCON_DEPARTMENT_SECURITY,
"region" = 2,
"head" = "Head of Security"
),
"[ACCESS_CMO]" = list(
"department" = CARDCON_DEPARTMENT_MEDICAL,
"region" = 3,
"head" = "Chief Medical Officer"
),
"[ACCESS_RD]" = list(
"department" = CARDCON_DEPARTMENT_SCIENCE,
"region" = 4,
"head" = "Research Director"
),
"[ACCESS_CE]" = list(
"department" = CARDCON_DEPARTMENT_ENGINEERING,
"region" = 5,
"head" = "Chief Engineer"
)
)
/datum/computer_file/program/card_mod/New()
..()
addtimer(CALLBACK(src, .proc/SetConfigCooldown), 0)
/datum/computer_file/program/card_mod/proc/authenticate(mob/user, obj/item/card/id/id_card)
if(!id_card)
return
/datum/computer_file/program/card_mod/proc/SetConfigCooldown()
change_position_cooldown = CONFIG_GET(number/id_console_jobslot_delay)
region_access = list()
if(!target_dept && (ACCESS_CHANGE_IDS in id_card.access))
minor = FALSE
authenticated = TRUE
update_static_data(user)
return TRUE
/datum/computer_file/program/card_mod/event_idremoved(background, slot)
if(!slot || slot == 2)// slot being false means both are removed
minor = 0
authenticated = 0
head_subordinates = null
region_access = null
var/list/head_types = list()
for(var/access_text in sub_managers)
var/list/info = sub_managers[access_text]
var/access = text2num(access_text)
if((access in id_card.access) && ((info["region"] in target_dept) || !length(target_dept)))
region_access += info["region"]
//I don't even know what I'm doing anymore
head_types += info["head"]
head_subordinates = list()
if(length(head_types))
for(var/j in SSjob.occupations)
var/datum/job/job = j
for(var/head in head_types)//god why
if(head in job.department_head)
head_subordinates += job.title
/datum/computer_file/program/card_mod/proc/job_blacklisted(jobtitle)
return (jobtitle in blacklisted)
if(length(region_access))
minor = TRUE
authenticated = TRUE
update_static_data(user)
return TRUE
//Logic check for if you can open the job
/datum/computer_file/program/card_mod/proc/can_open_job(datum/job/job)
if(job)
if(!job_blacklisted(job.title))
if((job.total_positions <= GLOB.player_list.len * (max_relative_positions / 100)))
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] < 0))
return 1
return -2
return 0
return 0
//Logic check for if you can close the job
/datum/computer_file/program/card_mod/proc/can_close_job(datum/job/job)
if(job)
if(!job_blacklisted(job.title))
if(job.total_positions > job.current_positions)
var/delta = (world.time / 10) - GLOB.time_last_changed_position
if((change_position_cooldown < delta) || (opened_positions[job.title] > 0))
return 1
return -2
return 0
return 0
/datum/computer_file/program/card_mod/proc/format_jobs(list/jobs)
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
var/obj/item/card/id/id_card = card_slot.stored_card
var/list/formatted = list()
for(var/job in jobs)
formatted.Add(list(list(
"display_name" = replacetext(job, "&nbsp", " "),
"target_rank" = id_card && id_card.assignment ? id_card.assignment : "Unassigned",
"job" = job)))
return formatted
return FALSE
/datum/computer_file/program/card_mod/ui_act(action, params)
if(..())
return 1
return TRUE
var/obj/item/computer_hardware/card_slot/card_slot
var/obj/item/computer_hardware/printer/printer
@@ -106,192 +107,220 @@
if(!card_slot)
return
var/obj/item/card/id/user_id_card = null
var/mob/user = usr
var/obj/item/card/id/user_id_card = user.get_idcard(FALSE)
var/obj/item/card/id/id_card = card_slot.stored_card
var/obj/item/card/id/auth_card = card_slot.stored_card2
if(auth_card)
user_id_card = auth_card
else
if(ishuman(user))
var/mob/living/carbon/human/h = user
user_id_card = h.get_idcard(TRUE)
switch(action)
if("PRG_switchm")
if(params["target"] == "mod")
mod_mode = 1
else if (params["target"] == "manifest")
mod_mode = 0
else if (params["target"] == "manage")
mod_mode = 2
if("PRG_togglea")
if(show_assignments)
show_assignments = 0
else
show_assignments = 1
if("PRG_authenticate")
if(!computer || !user_id_card)
playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return
if(authenticate(user, user_id_card))
playsound(computer, 'sound/machines/terminal_on.ogg', 50, FALSE)
return TRUE
if("PRG_logout")
authenticated = FALSE
playsound(computer, 'sound/machines/terminal_off.ogg', 50, FALSE)
return TRUE
if("PRG_print")
if(computer && printer) //This option should never be called if there is no printer
if(mod_mode)
if(authorized())
var/contents = {"<h4>Access Report</h4>
<u>Prepared By:</u> [user_id_card && user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]<br>
<u>For:</u> [id_card.registered_name ? id_card.registered_name : "Unregistered"]<br>
<hr>
<u>Assignment:</u> [id_card.assignment]<br>
<u>Access:</u><br>
"}
if(!computer || !printer)
return
if(!authenticated)
return
var/contents = {"<h4>Access Report</h4>
<u>Prepared By:</u> [user_id_card && user_id_card.registered_name ? user_id_card.registered_name : "Unknown"]<br>
<u>For:</u> [id_card.registered_name ? id_card.registered_name : "Unregistered"]<br>
<hr>
<u>Assignment:</u> [id_card.assignment]<br>
<u>Access:</u><br>
"}
var/known_access_rights = get_all_accesses()
for(var/A in id_card.access)
if(A in known_access_rights)
contents += " [get_access_desc(A)]"
var/known_access_rights = get_all_accesses()
for(var/A in id_card.access)
if(A in known_access_rights)
contents += " [get_access_desc(A)]"
if(!printer.print_text(contents,"access report"))
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
return
else
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
else
var/contents = {"<h4>Crew Manifest</h4>
<br>
[GLOB.data_core ? GLOB.data_core.get_manifest(0) : ""]
"}
if(!printer.print_text(contents,text("crew manifest ([])", STATION_TIME_TIMESTAMP("hh:mm:ss", world.time))))
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
return
else
computer.visible_message("<span class='notice'>\The [computer] prints out paper.</span>")
if("PRG_eject")
if(computer && card_slot)
var/select = params["target"]
switch(select)
if("id")
if(id_card)
GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment)
card_slot.try_eject(1, user)
else
var/obj/item/I = usr.get_active_held_item()
if (istype(I, /obj/item/card/id))
if(!usr.transferItemToLoc(I, computer))
return
card_slot.stored_card = I
if("auth")
if(auth_card)
if(id_card)
GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment)
head_subordinates = null
region_access = null
authenticated = 0
minor = 0
card_slot.try_eject(2, user)
else
var/obj/item/I = usr.get_active_held_item()
if (istype(I, /obj/item/card/id))
if(!usr.transferItemToLoc(I, computer))
return
card_slot.stored_card2 = I
if("PRG_terminate")
if(computer && ((id_card.assignment in head_subordinates) || id_card.assignment == "Assistant"))
id_card.assignment = "Unassigned"
remove_nt_access(id_card)
if("PRG_edit")
if(computer && authorized())
if(params["name"])
var/temp_name = reject_bad_name(input("Enter name.", "Name", id_card.registered_name))
if(temp_name)
id_card.registered_name = temp_name
else
computer.visible_message("<span class='notice'>[computer] buzzes rudely.</span>")
//else if(params["account"])
// var/account_num = text2num(input("Enter account number.", "Account", id_card.associated_account_number))
// id_card.associated_account_number = account_num
if("PRG_assign")
if(computer && authorized() && id_card)
var/t1 = params["assign_target"]
if(t1 == "Custom")
var/temp_t = reject_bad_text(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(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, "<span class='warning'>No log exists for this job: [t1]</span>")
return
access = jobdatum.get_access()
remove_nt_access(id_card)
apply_access(id_card, access)
id_card.assignment = t1
if("PRG_access")
if(params["allowed"] && computer && authorized())
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_accesses()))
id_card.access -= access_type
if(!access_allowed)
id_card.access += access_type
if("PRG_open_job")
var/edit_job_target = params["target"]
var/datum/job/j = SSjob.GetJob(edit_job_target)
if(!j)
return 0
if(can_open_job(j) != 1)
return 0
if(opened_positions[edit_job_target] >= 0)
GLOB.time_last_changed_position = world.time / 10
j.total_positions++
opened_positions[edit_job_target]++
if("PRG_close_job")
var/edit_job_target = params["target"]
var/datum/job/j = SSjob.GetJob(edit_job_target)
if(!j)
return 0
if(can_close_job(j) != 1)
return 0
//Allow instant closing without cooldown if a position has been opened before
if(opened_positions[edit_job_target] <= 0)
GLOB.time_last_changed_position = world.time / 10
j.total_positions--
opened_positions[edit_job_target]--
if("PRG_regsel")
if(!reg_ids)
reg_ids = list()
var/regsel = text2num(params["region"])
if(regsel in reg_ids)
reg_ids -= regsel
if(!printer.print_text(contents,"access report"))
to_chat(usr, "<span class='notice'>Hardware error: Printer was unable to print the file. It may be out of paper.</span>")
return
else
reg_ids += regsel
playsound(computer, 'sound/machines/terminal_on.ogg', 50, FALSE)
computer.visible_message("<span class='notice'>\The [computer] prints out a paper.</span>")
return TRUE
if("PRG_eject")
if(!computer || !card_slot)
return
if(id_card)
GLOB.data_core.manifest_modify(id_card.registered_name, id_card.assignment)
card_slot.try_eject(TRUE, user)
else
var/obj/item/I = user.get_active_held_item()
if(istype(I, /obj/item/card/id))
if(!user.transferItemToLoc(I, computer))
return
card_slot.stored_card = I
playsound(computer, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
return TRUE
if("PRG_terminate")
if(!computer || !authenticated)
return
if(minor)
if(!(id_card.assignment in head_subordinates) && id_card.assignment != "Assistant")
return
if(id_card)
id_card.name = text("[id_card.registered_name]'s ID Card ([id_card.assignment])")
id_card.access -= get_all_centcom_access() + get_all_accesses()
id_card.assignment = "Unassigned"
id_card.update_label()
playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return TRUE
if("PRG_edit")
if(!computer || !authenticated || !id_card)
return
var/new_name = params["name"]
if(!new_name)
return
id_card.registered_name = new_name
id_card.update_label()
playsound(computer, "terminal_type", 50, FALSE)
return TRUE
if("PRG_assign")
if(!computer || !authenticated || !id_card)
return
var/target = params["assign_target"]
if(!target)
return
return 1
if(target == "Custom")
var/custom_name = params["custom_name"]
if(custom_name)
id_card.assignment = custom_name
id_card.update_label()
else
if(minor && !(target in head_subordinates))
return
var/list/new_access = list()
if(is_centcom)
new_access = get_centcom_access(target)
else
var/datum/job/job
for(var/jobtype in subtypesof(/datum/job))
var/datum/job/J = new jobtype
if(J.title == target)
job = J
break
if(!job)
to_chat(user, "<span class='warning'>No class exists for this job: [target]</span>")
return
new_access = job.get_access()
id_card.access -= get_all_centcom_access() + get_all_accesses()
id_card.access |= new_access
id_card.assignment = target
id_card.update_label()
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
return TRUE
if("PRG_access")
if(!computer || !authenticated)
return
var/access_type = text2num(params["access_target"])
if(access_type in (is_centcom ? get_all_centcom_access() : get_all_accesses()))
if(access_type in id_card.access)
id_card.access -= access_type
else
id_card.access |= access_type
playsound(computer, "terminal_type", 50, FALSE)
return TRUE
if("PRG_grantall")
if(!computer || !authenticated || minor)
return
id_card.access |= (is_centcom ? get_all_centcom_access() : get_all_accesses())
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
return TRUE
if("PRG_denyall")
if(!computer || !authenticated || minor)
return
id_card.access.Cut()
playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return TRUE
if("PRG_grantregion")
if(!computer || !authenticated)
return
var/region = text2num(params["region"])
if(isnull(region))
return
id_card.access |= get_region_accesses(region)
playsound(computer, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE)
return TRUE
if("PRG_denyregion")
if(!computer || !authenticated)
return
var/region = text2num(params["region"])
if(isnull(region))
return
id_card.access -= get_region_accesses(region)
playsound(computer, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE)
return TRUE
/datum/computer_file/program/card_mod/proc/remove_nt_access(obj/item/card/id/id_card)
id_card.access -= get_all_accesses()
id_card.access -= get_all_centcom_access()
/datum/computer_file/program/card_mod/proc/apply_access(obj/item/card/id/id_card, list/accesses)
id_card.access |= accesses
/datum/computer_file/program/card_mod/ui_static_data(mob/user)
var/list/data = list()
data["station_name"] = station_name()
data["centcom_access"] = is_centcom
data["minor"] = target_dept || minor ? TRUE : FALSE
var/list/departments = target_dept
if(is_centcom)
departments = list("CentCom" = get_all_centcom_jobs())
else if(isnull(departments))
departments = list(
CARDCON_DEPARTMENT_COMMAND = list("Captain"),
CARDCON_DEPARTMENT_ENGINEERING = GLOB.engineering_positions,
CARDCON_DEPARTMENT_MEDICAL = GLOB.medical_positions,
CARDCON_DEPARTMENT_SCIENCE = GLOB.science_positions,
CARDCON_DEPARTMENT_SECURITY = GLOB.security_positions,
CARDCON_DEPARTMENT_SUPPLY = GLOB.supply_positions,
CARDCON_DEPARTMENT_SERVICE = GLOB.civilian_positions
)
data["jobs"] = list()
for(var/department in departments)
var/list/job_list = departments[department]
var/list/department_jobs = list()
for(var/job in job_list)
if(minor && !(job in head_subordinates))
continue
department_jobs += list(list(
"display_name" = replacetext(job, "&nbsp", " "),
"job" = job
))
if(length(department_jobs))
data["jobs"][department] = department_jobs
var/list/regions = list()
for(var/i in 1 to 7)
if((minor || target_dept) && !(i in region_access))
continue
var/list/accesses = list()
for(var/access in get_region_accesses(i))
if (get_access_desc(access))
accesses += list(list(
"desc" = replacetext(get_access_desc(access), "&nbsp", " "),
"ref" = access,
))
regions += list(list(
"name" = get_region_accesses_name(i),
"regid" = i,
"accesses" = accesses
))
data["regions"] = regions
return data
/datum/computer_file/program/card_mod/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/card_slot/card_slot
@@ -301,181 +330,34 @@
card_slot = computer.all_components[MC_CARD]
printer = computer.all_components[MC_PRINT]
data["mmode"] = mod_mode
var/authed = 0
if(computer)
if(card_slot)
var/obj/item/card/id/auth_card = card_slot.stored_card2
data["auth_name"] = auth_card ? strip_html_simple(auth_card.name) : "-----"
authed = authorized()
if(mod_mode == 2)
data["slots"] = list()
var/list/pos = list()
for(var/datum/job/job in SSjob.occupations)
if(job.title in blacklisted)
continue
var/list/status_open = build_manage(job,1)
var/list/status_close = build_manage(job,0)
pos.Add(list(list(
"title" = job.title,
"current" = job.current_positions,
"total" = job.total_positions,
"status_open" = (authed && !minor) ? status_open["enable"]: 0,
"status_close" = (authed && !minor) ? status_close["enable"] : 0,
"desc_open" = status_open["desc"],
"desc_close" = status_close["desc"])))
data["slots"] = pos
data["src"] = "[REF(src)]"
data["station_name"] = station_name()
if(!mod_mode)
data["manifest"] = list()
var/list/crew = list()
for(var/datum/data/record/t in sortRecord(GLOB.data_core.general))
crew.Add(list(list(
"name" = t.fields["name"],
"rank" = t.fields["rank"])))
data["manifest"] = crew
data["assignments"] = show_assignments
if(computer)
data["have_id_slot"] = !!card_slot
data["have_printer"] = !!printer
if(!card_slot && mod_mode == 1)
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["have_id_slot"] = FALSE
data["have_printer"] = FALSE
data["centcom_access"] = is_centcom
data["authenticated"] = authed
if(mod_mode == 1 && computer)
if(card_slot)
var/obj/item/card/id/id_card = card_slot.stored_card
data["has_id"] = !!id_card
data["id_rank"] = id_card && id_card.assignment ? html_encode(id_card.assignment) : "Unassigned"
data["id_owner"] = id_card && id_card.registered_name ? html_encode(id_card.registered_name) : "-----"
data["id_name"] = id_card ? strip_html_simple(id_card.name) : "-----"
if(show_assignments)
data["engineering_jobs"] = format_jobs(GLOB.engineering_positions)
data["medical_jobs"] = format_jobs(GLOB.medical_positions)
data["science_jobs"] = format_jobs(GLOB.science_positions)
data["security_jobs"] = format_jobs(GLOB.security_positions)
data["cargo_jobs"] = format_jobs(GLOB.supply_positions)
data["civilian_jobs"] = format_jobs(GLOB.civilian_positions)
data["centcom_jobs"] = format_jobs(get_all_centcom_jobs())
if(card_slot.stored_card)
var/obj/item/card/id/id_card = 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), "&nbsp", " "),
"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++)
if((minor || target_dept) && !(i in region_access))
continue
var/list/accesses = list()
if(i in reg_ids)
for(var/access in get_region_accesses(i))
if (get_access_desc(access))
accesses.Add(list(list(
"desc" = replacetext(get_access_desc(access), "&nbsp", " "),
"ref" = access,
"allowed" = (access in id_card.access) ? 1 : 0)))
regions.Add(list(list(
"name" = get_region_accesses_name(i),
"regid" = i,
"selected" = (i in reg_ids) ? 1 : null,
"accesses" = accesses)))
data["regions"] = regions
data["minor"] = target_dept || minor ? 1 : 0
data["authenticated"] = authenticated
if(computer)
var/obj/item/card/id/id_card = card_slot.stored_card
data["has_id"] = !!id_card
data["id_name"] = id_card ? id_card.name : "-----"
if(id_card)
data["id_rank"] = id_card.assignment ? id_card.assignment : "Unassigned"
data["id_owner"] = id_card.registered_name ? id_card.registered_name : "-----"
data["access_on_card"] = id_card.access
return data
/datum/computer_file/program/card_mod/proc/build_manage(datum/job,open = FALSE)
var/out = "Denied"
var/can_change= 0
if(open)
can_change = can_open_job(job)
else
can_change = can_close_job(job)
var/enable = 0
if(can_change == 1)
out = "[open ? "Open Position" : "Close Position"]"
enable = 1
else if(can_change == -2)
var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1)
var/mins = round(time_to_wait / 60)
var/seconds = time_to_wait - (60*mins)
out = "Cooldown ongoing: [mins]:[(seconds < 10) ? "0[seconds]" : "[seconds]"]"
else
out = "Denied"
return list("enable" = enable, "desc" = out)
/datum/computer_file/program/card_mod/proc/authorized()
if(!authenticated && computer)
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
if(card_slot)
var/obj/item/card/id/auth_card = card_slot.stored_card2
if(auth_card)
region_access = list()
if(ACCESS_CHANGE_IDS in auth_card.GetAccess())
minor = 0
authenticated = 1
return 1
else
if((ACCESS_HOP in auth_card.access) && ((target_dept==1) || !target_dept))
region_access |= 1
region_access |= 6
get_subordinates("Head of Personnel")
if((ACCESS_HOS in auth_card.access) && ((target_dept==2) || !target_dept))
region_access |= 2
get_subordinates("Head of Security")
if((ACCESS_CMO in auth_card.access) && ((target_dept==3) || !target_dept))
region_access |= 3
get_subordinates("Chief Medical Officer")
if((ACCESS_RD in auth_card.access) && ((target_dept==4) || !target_dept))
region_access |= 4
get_subordinates("Research Director")
if((ACCESS_CE in auth_card.access) && ((target_dept==5) || !target_dept))
region_access |= 5
get_subordinates("Chief Engineer")
if(region_access.len)
minor = 1
authenticated = 1
return 1
else
return authenticated
/datum/computer_file/program/card_mod/proc/get_subordinates(rank)
head_subordinates = list()
for(var/datum/job/job in SSjob.occupations)
if(rank in job.department_head)
head_subordinates += job.title
#undef CARDCON_DEPARTMENT_SERVICE
#undef CARDCON_DEPARTMENT_SECURITY
#undef CARDCON_DEPARTMENT_MEDICAL
#undef CARDCON_DEPARTMENT_SCIENCE
#undef CARDCON_DEPARTMENT_SUPPLY
#undef CARDCON_DEPARTMENT_ENGINEERING
#undef CARDCON_DEPARTMENT_COMMAND
@@ -0,0 +1,74 @@
/datum/computer_file/program/shipping
filename = "shipping"
filedesc = "Nanotrasen Shipping Scanner"
program_icon_state = "shipping"
extended_desc = "A combination printer/scanner app that enables modular computers to print barcodes for easy scanning and shipping."
network_destination = "ship scanner"
size = 6
tgui_id = "NtosShipping"
ui_x = 450
ui_y = 350
///Account used for creating barcodes.
var/datum/bank_account/payments_acc
///The amount which the tagger will recieve for the sale.
var/percent_cut = 20
/datum/computer_file/program/shipping/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
var/obj/item/computer_hardware/printer/printer = computer.all_components[MC_PRINT]
var/obj/item/card/id/id_card = card_slot ? card_slot.stored_card : null
data["has_id_slot"] = !!card_slot
data["has_printer"] = !!printer
data["paperamt"] = printer ? "[printer.stored_paper] / [printer.max_paper]" : null
data["card_owner"] = card_slot && card_slot.stored_card ? id_card.registered_name : "No Card Inserted."
data["current_user"] = payments_acc ? payments_acc.account_holder : null
data["barcode_split"] = percent_cut
return data
/datum/computer_file/program/shipping/ui_act(action, list/params)
if(..())
return TRUE
if(!computer)
return
// Get components
var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
var/obj/item/computer_hardware/printer/printer = computer.all_components[MC_PRINT]
var/obj/item/card/id/id_card = card_slot ? card_slot.stored_card : null
if(!card_slot || !printer) //We need both to successfully use this app.
return
switch(action)
if("ejectid")
if(id_card)
card_slot.try_eject(TRUE, usr)
if("selectid")
if(!id_card)
return
if(!id_card.registered_account)
playsound(get_turf(ui_host()), 'sound/machines/buzz-sigh.ogg', 50, TRUE, -1)
return
payments_acc = id_card.registered_account
playsound(get_turf(ui_host()), 'sound/machines/ping.ogg', 50, TRUE, -1)
if("resetid")
payments_acc = null
if("setsplit")
var/potential_cut = input("How much would you like to payout to the registered card?","Percentage Profit") as num|null
percent_cut = potential_cut ? clamp(round(potential_cut, 1), 1, 50) : 20
if("print")
if(!printer)
to_chat(usr, "<span class='notice'>Hardware error: A printer is required to print barcodes.</span>")
return
if(printer.stored_paper <= 0)
to_chat(usr, "<span class='notice'>Hardware error: Printer is out of paper.</span>")
return
if(!payments_acc)
to_chat(usr, "<span class='notice'>Software error: Please set a current user first.</span>")
return
var/obj/item/barcode/barcode = new /obj/item/barcode(get_turf(ui_host()))
barcode.payments_acc = payments_acc
barcode.percent_cut = percent_cut
printer.stored_paper--
to_chat(usr, "<span class='notice'>The computer prints out a barcode.</span>")
@@ -14,7 +14,7 @@
ui_y = 630
available_on_ntnet = 0
requires_ntnet = 0
tgui_id = "ntos_configuration"
tgui_id = "NtosConfiguration"
var/obj/item/modular_computer/movable = null

Some files were not shown because too many files have changed in this diff Show More