Merge pull request #12853 from LetterN/TGUI-4

TGUI4 port
This commit is contained in:
silicons
2020-08-09 05:46:21 -07:00
committed by GitHub
539 changed files with 15719 additions and 8963 deletions
@@ -0,0 +1,79 @@
GLOBAL_LIST_INIT(abductor_gear, subtypesof(/datum/abductor_gear))
/datum/abductor_gear
/// Name of the gear
var/name = "Generic Abductor Gear"
/// Description of the gear
var/description = "Generic description."
/// Unique ID of the gear
var/id = "abductor_generic"
/// Credit cost of the gear
var/cost = 1
/// Build path of the gear itself
var/build_path = null
/// Category of the gear
var/category = "Basic Gear"
/datum/abductor_gear/agent_helmet
name = "Agent Helmet"
description = "Abduct with style - spiky style. Prevents digital tracking."
id = "agent_helmet"
build_path = /obj/item/clothing/head/helmet/abductor
/datum/abductor_gear/agent_vest
name = "Agent Vest"
description = "A vest outfitted with advanced stealth technology. It has two modes - combat and stealth."
id = "agent_vest"
build_path = /obj/item/clothing/suit/armor/abductor/vest
/datum/abductor_gear/radio_silencer
name = "Radio Silencer"
description = "A compact device used to shut down communications equipment."
id = "radio_silencer"
build_path = /obj/item/abductor/silencer
/datum/abductor_gear/science_tool
name = "Science Tool"
description = "A dual-mode tool for retrieving specimens and scanning appearances. Scanning can be done through cameras."
id = "science_tool"
build_path = /obj/item/abductor/gizmo
/*
/datum/abductor_gear/advanced_baton
name = "Advanced Baton"
description = "A quad-mode baton used for incapacitation and restraining of specimens."
id = "advanced_baton"
cost = 2
build_path = /obj/item/melee/baton/abductor //does not exist?
*/
/datum/abductor_gear/superlingual_matrix
name = "Superlingual Matrix"
description = "A mysterious structure that allows for instant communication between users. Pretty impressive until you need to eat something."
id = "superlingual_matrix"
build_path = /obj/item/organ/tongue/abductor
category = "Advanced Gear"
/datum/abductor_gear/mental_interface
name = "Mental Interface Device"
description = "A dual-mode tool for directly communicating with sentient brains. It can be used to send a direct message to a target, \
or to send a command to a test subject with a charged gland."
id = "mental_interface"
cost = 2
build_path = /obj/item/abductor/mind_device
category = "Advanced Gear"
/datum/abductor_gear/reagent_synthesizer
name = "Reagent Synthesizer"
description = "Synthesizes a variety of reagents using proto-matter."
id = "reagent_synthesizer"
cost = 2
build_path = /obj/item/abductor_machine_beacon/chem_dispenser
category = "Advanced Gear"
/datum/abductor_gear/shrink_ray
name = "Shrink Ray Blaster"
description = "This is a piece of frightening alien tech that enhances the magnetic pull of atoms in a localized space to temporarily make an object shrink. \
That or it's just space magic. Either way, it shrinks stuff."
id = "shrink_ray"
cost = 2
build_path = /obj/item/gun/energy/shrink_ray
category = "Advanced Gear"
@@ -23,99 +23,105 @@
var/obj/machinery/abductor/pad/pad
var/obj/machinery/computer/camera_advanced/abductor/camera
var/list/datum/icon_snapshot/disguises = list()
/// Currently selected gear category
var/selected_cat
/// Dictates if the compact mode of the interface is on or off
var/compact_mode = FALSE
/// Possible gear to be dispensed
var/list/possible_gear
/obj/machinery/abductor/console/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!HAS_TRAIT(user, TRAIT_ABDUCTOR_TRAINING) && !HAS_TRAIT(user.mind, TRAIT_ABDUCTOR_TRAINING))
to_chat(user, "<span class='warning'>You start mashing alien buttons at random!</span>")
if(do_after(user,100, target = src))
TeleporterSend()
return
user.set_machine(src)
var/dat = ""
dat += "<H3> Abductsoft 3000 </H3>"
/obj/machinery/abductor/console/ui_status(mob/user)
if(!isabductor(user) && !isobserver(user))
return UI_CLOSE
return ..()
/obj/machinery/abductor/console/ui_state(mob/user)
return GLOB.physical_state
/obj/machinery/abductor/console/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "AbductorConsole", name)
ui.open()
/obj/machinery/abductor/console/ui_static_data(mob/user)
var/list/data = list()
data["categories"] = list()
for(var/category in possible_gear)
var/list/cat = list(
"name" = category,
"items" = (category == selected_cat ? list() : null))
for(var/gear in possible_gear[category])
var/datum/abductor_gear/AG = possible_gear[category][gear]
cat["items"] += list(list(
"name" = AG.name,
"cost" = AG.cost,
"desc" = AG.description,
))
data["categories"] += list(cat)
return data
/obj/machinery/abductor/console/ui_data(mob/user)
var/list/data = list()
data["compactMode"] = compact_mode
data["experiment"] = experiment ? TRUE : FALSE
if(experiment)
var/points = experiment.points
var/credits = experiment.credits
dat += "Collected Samples : [points] <br>"
dat += "Gear Credits: [credits] <br>"
dat += "<b>Transfer data in exchange for supplies:</b><br>"
dat += "<a href='?src=[REF(src)];dispense=baton'>Advanced Baton (2 Credits)</A><br>"
dat += "<a href='?src=[REF(src)];dispense=mind_device'>Mental Interface Device (2 Credits)</A><br>"
dat += "<a href='?src=[REF(src)];dispense=chem_dispenser'>Reagent Synthesizer (2 Credits)</A><br>"
dat += "<a href='?src=[REF(src)];dispense=helmet'>Agent Helmet (1 Credit)</A><br>"
dat += "<a href='?src=[REF(src)];dispense=vest'>Agent Vest (1 Credit)</A><br>"
dat += "<a href='?src=[REF(src)];dispense=silencer'>Radio Silencer (1 Credit)</A><br>"
dat += "<a href='?src=[REF(src)];dispense=tool'>Science Tool (1 Credit)</A><br>"
dat += "<a href='?src=[REF(src)];dispense=tongue'>Superlingual Matrix (1 Credit)</a><br>"
else
dat += "<span class='bad'>NO EXPERIMENT MACHINE DETECTED</span> <br>"
data["points"] = experiment.points
data["credits"] = experiment.credits
data["pad"] = pad ? TRUE : FALSE
if(pad)
dat += "<span class='bad'>Emergency Teleporter System.</span>"
dat += "<span class='bad'>Consider using primary observation console first.</span>"
dat += "<a href='?src=[REF(src)];teleporter_send=1'>Activate Teleporter</A><br>"
if(gizmo && gizmo.marked)
dat += "<a href='?src=[REF(src)];teleporter_retrieve=1'>Retrieve Mark</A><br>"
else
dat += "<span class='linkOff'>Retrieve Mark</span><br>"
else
dat += "<span class='bad'>NO TELEPAD DETECTED</span></br>"
data["gizmo"] = gizmo && gizmo.marked ? TRUE : FALSE
data["vest"] = vest ? TRUE : FALSE
if(vest)
dat += "<h4> Agent Vest Mode </h4><br>"
var/mode = vest.mode
if(mode == VEST_STEALTH)
dat += "<a href='?src=[REF(src)];flip_vest=1'>Combat</A>"
dat += "<span class='linkOff'>Stealth</span>"
else
dat += "<span class='linkOff'>Combat</span>"
dat += "<a href='?src=[REF(src)];flip_vest=1'>Stealth</A>"
data["vest_mode"] = vest.mode
data["vest_lock"] = HAS_TRAIT_FROM(vest, TRAIT_NODROP, ABDUCTOR_VEST_TRAIT)
return data
dat+="<br>"
dat += "<a href='?src=[REF(src)];select_disguise=1'>Select Agent Vest Disguise</a><br>"
dat += "<a href='?src=[REF(src)];toggle_vest=1'>[HAS_TRAIT_FROM(vest, TRAIT_NODROP, ABDUCTOR_VEST_TRAIT) ? "Unlock" : "Lock"] Vest</a><br>"
else
dat += "<span class='bad'>NO AGENT VEST DETECTED</span>"
var/datum/browser/popup = new(user, "computer", "Abductor Console", 400, 500)
popup.set_content(dat)
popup.open()
/obj/machinery/abductor/console/Topic(href, href_list)
if(..())
/obj/machinery/abductor/console/ui_act(action, list/params)
. = ..()
if(.)
return
usr.set_machine(src)
if(href_list["teleporter_send"])
TeleporterSend()
else if(href_list["teleporter_retrieve"])
TeleporterRetrieve()
else if(href_list["flip_vest"])
FlipVest()
else if(href_list["toggle_vest"])
if(vest)
switch(action)
if("buy")
var/item_name = params["name"]
var/list/buyable_items = list()
for(var/category in possible_gear)
buyable_items += possible_gear[category]
for(var/key in buyable_items)
var/datum/abductor_gear/AG = buyable_items[key]
if(AG.name == item_name)
Dispense(AG.build_path, AG.cost)
return TRUE
if("teleporter_send")
TeleporterSend()
return TRUE
if("teleporter_retrieve")
TeleporterRetrieve()
return TRUE
if("flip_vest")
FlipVest()
return TRUE
if("toggle_vest")
if(!vest)
return
vest.toggle_nodrop()
else if(href_list["select_disguise"])
SelectDisguise()
else if(href_list["dispense"])
switch(href_list["dispense"])
if("baton")
Dispense(/obj/item/abductor/baton,cost=2)
if("helmet")
Dispense(/obj/item/clothing/head/helmet/abductor)
if("silencer")
Dispense(/obj/item/abductor/silencer)
if("tool")
Dispense(/obj/item/abductor/gizmo)
if("vest")
Dispense(/obj/item/clothing/suit/armor/abductor/vest)
if("mind_device")
Dispense(/obj/item/abductor/mind_device,cost=2)
if("chem_dispenser")
Dispense(/obj/item/abductor_machine_beacon/chem_dispenser,cost=2)
if("tongue")
Dispense(/obj/item/organ/tongue/abductor)
updateUsrDialog()
return TRUE
if("select_disguise")
SelectDisguise()
return TRUE
if("select")
selected_cat = params["category"]
return TRUE
if("compact_toggle")
compact_mode = !compact_mode
return TRUE
/obj/machinery/abductor/console/proc/TeleporterRetrieve()
if(pad && gizmo && gizmo.marked)
@@ -156,7 +162,6 @@
pad.teleport_target = location
to_chat(user, "<span class='notice'>Location marked as test subject release point.</span>")
/obj/machinery/abductor/console/Initialize(mapload)
..()
return INITIALIZE_HINT_LATELOAD
@@ -22,38 +22,44 @@
gland_colors[i] = random_color()
amounts[i] = rand(1,5)
/obj/machinery/abductor/gland_dispenser/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!isabductor(user))
/obj/machinery/abductor/gland_dispenser/ui_status(mob/user)
if(!isabductor(user) && !isobserver(user))
return UI_CLOSE
return ..()
/obj/machinery/abductor/gland_dispenser/ui_state(mob/user)
return GLOB.physical_state
/obj/machinery/abductor/gland_dispenser/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "GlandDispenser", name)
ui.open()
/obj/machinery/abductor/gland_dispenser/ui_data(mob/user)
var/list/data = list()
data["glands"] = list()
for(var/gland_number=1,gland_number<=gland_colors.len,gland_number++)
var/list/gland_information = list(
"color" = gland_colors[gland_number],
"amount" = amounts[gland_number],
"id" = gland_number,
)
data["glands"] += list(gland_information)
return data
/obj/machinery/abductor/gland_dispenser/ui_act(action, list/params)
. = ..()
if(.)
return
user.set_machine(src)
var/box_css = {"
<style>
a.box.gland {
float: left;
width: 20px;
height: 20px;
margin: 5px;
border-width: 1px;
border-style: solid;
border-color: rgba(0,0,0,.2);
text-align: center;
}
</style>"}
var/dat = ""
var/item_count = 0
for(var/i=1,i<=gland_colors.len,i++)
item_count++
var/g_color = gland_colors[i]
var/amount = amounts[i]
dat += "<a class='box gland' style='background-color:[g_color]' href='?src=[REF(src)];dispense=[i]'>[amount]</a>"
if(item_count == 4) // Four boxes per line
dat +="</br></br>"
item_count = 0
var/datum/browser/popup = new(user, "glands", "Gland Dispenser", 200, 200)
popup.add_head_content(box_css)
popup.set_content(dat)
popup.open()
return
switch(action)
if("dispense")
var/gland_id = text2num(params["gland_id"])
if(!gland_id)
return
Dispense(gland_id)
return TRUE
/obj/machinery/abductor/gland_dispenser/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/organ/heart/gland))
@@ -65,15 +71,6 @@
else
return ..()
/obj/machinery/abductor/gland_dispenser/Topic(href, href_list)
if(..())
return
usr.set_machine(src)
if(href_list["dispense"])
Dispense(text2num(href_list["dispense"]))
updateUsrDialog()
/obj/machinery/abductor/gland_dispenser/proc/Dispense(count)
if(amounts[count]>0)
amounts[count]--
@@ -15,16 +15,13 @@
var/breakout_time = 450
/obj/machinery/abductor/experiment/MouseDrop_T(mob/target, mob/user)
if(user.stat || user.lying || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
var/mob/living/L = user
if(user.stat || (isliving(user) && (!(L.mobility_flags & MOBILITY_STAND) || !(L.mobility_flags & MOBILITY_UI))) || !Adjacent(user) || !target.Adjacent(user) || !ishuman(target))
return
if(isabductor(target))
return
close_machine(target)
/obj/machinery/abductor/experiment/on_attack_hand(mob/user, act_intent = user.a_intent, unarmed_attack_flags)
experimentUI(user)
/obj/machinery/abductor/experiment/open_machine()
if(!state_open && !panel_open)
..()
@@ -46,7 +43,7 @@
/obj/machinery/abductor/experiment/container_resist(mob/living/user)
user.visible_message("<span class='notice'>You see [user] kicking against the door of [src]!</span>", \
"<span class='notice'>You lean on the back of [src] and start pushing the door open... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
"<span class='italics'>You hear a metallic creaking from [src].</span>")
"<span class='hear'>You hear a metallic creaking from [src].</span>")
if(do_after(user,(breakout_time), target = src))
if(!user || user.stat != CONSCIOUS || user.loc != src || state_open)
return
@@ -54,122 +51,84 @@
"<span class='notice'>You successfully break out of [src]!</span>")
open_machine()
/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H)
var/icon/photo = null
var/g = (H.dna.features["body_model"] == FEMALE) ? "f" : "m"
if(H.dna.species.use_skintones)
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.skin_tone]_[g]")
else
photo = icon("icon" = 'icons/mob/human.dmi', "icon_state" = "[H.dna.species.id]_[g]")
photo.Blend("#[H.dna.features["mcolor"]]", ICON_MULTIPLY)
/obj/machinery/abductor/experiment/ui_status(mob/user)
if(user == occupant)
return UI_CLOSE
return ..()
var/icon/eyes
if(EYECOLOR in H.dna.species.species_traits)
eyes = icon("icon" = 'icons/mob/human_face.dmi', "icon_state" = "eyes")
eyes.Blend("#[H.eye_color]", ICON_MULTIPLY)
/obj/machinery/abductor/experiment/ui_state(mob/user)
return GLOB.physical_state
var/datum/sprite_accessory/S
S = GLOB.hair_styles_list[H.hair_style]
if(S && (HAIR in H.dna.species.species_traits))
var/icon/hair = icon("icon" = S.icon, "icon_state" = "[S.icon_state]")
hair.Blend("#[H.hair_color]", ICON_MULTIPLY)
eyes.Blend(hair, ICON_OVERLAY)
/obj/machinery/abductor/experiment/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ProbingConsole", name)
ui.open()
S = GLOB.facial_hair_styles_list[H.facial_hair_style]
if(S && (FACEHAIR in H.dna.species.species_traits))
var/icon/facial = icon("icon" = S.icon, "icon_state" = "[S.icon_state]")
facial.Blend("#[H.facial_hair_color]", ICON_MULTIPLY)
eyes.Blend(facial, ICON_OVERLAY)
if(eyes)
photo.Blend(eyes, ICON_OVERLAY)
var/icon/splat = icon("icon" = 'icons/mob/dam_mob.dmi',"icon_state" = "chest30")
photo.Blend(splat,ICON_OVERLAY)
return photo
/obj/machinery/abductor/experiment/proc/experimentUI(mob/user)
var/dat
dat += "<h3> Experiment </h3>"
if(occupant)
var/obj/item/photo/P = new
P.picture = new
P.picture.picture_image = icon(dissection_icon(occupant), dir = SOUTH)
user << browse_rsc(P.picture.picture_image, "dissection_img")
dat += "<table><tr><td>"
dat += "<img src=dissection_img height=80 width=80>" //Avert your eyes
dat += "</td><td>"
dat += "<a href='?src=[REF(src)];experiment=1'>Probe</a><br>"
dat += "<a href='?src=[REF(src)];experiment=2'>Dissect</a><br>"
dat += "<a href='?src=[REF(src)];experiment=3'>Analyze</a><br>"
dat += "</td></tr></table>"
else
dat += "<span class='linkOff'>Experiment </span>"
if(!occupant)
dat += "<h3>Machine Unoccupied</h3>"
else
dat += "<h3>Subject Status : </h3>"
dat += "[occupant.name] => "
var/mob/living/mob_occupant = occupant
switch(mob_occupant.stat)
if(CONSCIOUS)
dat += "<span class='good'>Conscious</span>"
if(UNCONSCIOUS)
dat += "<span class='average'>Unconscious</span>"
else // DEAD
dat += "<span class='bad'>Deceased</span>"
dat += "<br>"
dat += "[flash]"
dat += "<br>"
dat += "<a href='?src=[REF(src)];refresh=1'>Scan</a>"
dat += "<a href='?src=[REF(src)];[state_open ? "close=1'>Close</a>" : "open=1'>Open</a>"]"
var/datum/browser/popup = new(user, "experiment", "Probing Console", 300, 300)
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
popup.set_content(dat)
popup.open()
/obj/machinery/abductor/experiment/Topic(href, href_list)
if(..() || usr == occupant)
return
usr.set_machine(src)
if(href_list["refresh"])
updateUsrDialog()
return
if(href_list["open"])
open_machine()
return
if(href_list["close"])
close_machine()
return
/obj/machinery/abductor/experiment/ui_data(mob/user)
var/list/data = list()
data["open"] = state_open
data["feedback"] = flash
data["occupant"] = occupant ? TRUE : FALSE
data["occupant_name"] = null
data["occupant_status"] = null
if(occupant)
var/mob/living/mob_occupant = occupant
if(mob_occupant.stat != DEAD)
if(href_list["experiment"])
flash = Experiment(occupant,href_list["experiment"],usr)
updateUsrDialog()
add_fingerprint(usr)
data["occupant_name"] = mob_occupant.name
data["occupant_status"] = mob_occupant.stat
return data
/obj/machinery/abductor/experiment/proc/Experiment(mob/occupant,type,mob/user)
/obj/machinery/abductor/experiment/ui_act(action, list/params)
. = ..()
if(.)
return
switch(action)
if("door")
if(state_open)
close_machine()
return TRUE
else
open_machine()
return TRUE
if("experiment")
if(!occupant)
return
var/mob/living/mob_occupant = occupant
if(mob_occupant.stat == DEAD)
return
flash = experiment(occupant, params["experiment_type"], usr)
return TRUE
/**
* experiment: Performs selected experiment on occupant mob, resulting in a point reward on success
*
* Arguments:
* * occupant The mob inside the machine
* * type The type of experiment to be performed
* * user The mob starting the experiment
*/
/obj/machinery/abductor/experiment/proc/experiment(mob/occupant, type, mob/user)
LAZYINITLIST(history)
var/mob/living/carbon/human/H = occupant
var/datum/antagonist/abductor/user_abductor = user.mind.has_antag_datum(/datum/antagonist/abductor)
if(!user_abductor)
return "<span class='bad'>Authorization failure. Contact mothership immidiately.</span>"
return "Authorization failure. Contact mothership immediately."
var/point_reward = 0
if(!H)
return "Invalid or missing specimen."
if(H in history)
return "<span class='bad'>Specimen already in database.</span>"
return "Specimen already in database."
if(H.stat == DEAD)
say("Specimen deceased - please provide fresh sample.")
return "<span class='bad'>Specimen deceased.</span>"
return "Specimen deceased."
var/obj/item/organ/heart/gland/GlandTest = locate() in H.internal_organs
if(!GlandTest)
say("Experimental dissection not detected!")
return "<span class='bad'>No glands detected!</span>"
if(H.mind != null && (H.voluntary_ghosted || (H.ckey != null)))
return "No glands detected!"
if(H.mind != null && H.ckey != null)
LAZYINITLIST(abductee_minds)
LAZYADD(history, H)
LAZYADD(abductee_minds, H.mind)
@@ -191,22 +150,27 @@
point_reward++
if(point_reward > 0)
open_machine()
SendBack(H)
playsound(src.loc, 'sound/machines/ding.ogg', 50, 1)
send_back(H)
playsound(src.loc, 'sound/machines/ding.ogg', 50, TRUE)
points += point_reward
credits += point_reward
return "<span class='good'>Experiment successful! [point_reward] new data-points collected.</span>"
return "Experiment successful! [point_reward] new data-points collected."
else
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1)
return "<span class='bad'>Experiment failed! No replacement organ detected.</span>"
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, TRUE)
return "Experiment failed! No replacement organ detected."
else
say("Brain activity nonexistent - disposing sample...")
open_machine()
SendBack(H)
return "<span class='bad'>Specimen braindead - disposed.</span>"
send_back(H)
return "Specimen braindead - disposed."
/obj/machinery/abductor/experiment/proc/SendBack(mob/living/carbon/human/H)
/**
* send_back: Sends a mob back to a selected teleport location if safe
*
* Arguments:
* * H The human mob to be sent back
*/
/obj/machinery/abductor/experiment/proc/send_back(mob/living/carbon/human/H)
H.Sleeping(160)
H.uncuff()
if(console && console.pad && console.pad.teleport_target)
@@ -216,7 +180,6 @@
SSjob.SendToLateJoin(H, FALSE)
return
/obj/machinery/abductor/experiment/update_icon_state()
if(state_open)
icon_state = "experiment-open"
@@ -13,10 +13,13 @@
changeling = null
. = ..()
/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)
/datum/cellular_emporium/ui_state(mob/user)
return GLOB.always_state
/datum/cellular_emporium/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "CellularEmporium", name, 900, 480, master_ui, state)
ui = new(user, src, "CellularEmporium", name)
ui.open()
/datum/cellular_emporium/ui_data(mob/user)
@@ -25,9 +25,6 @@
/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
@@ -39,6 +36,11 @@
speed_multiplier = 0
no_cost = TRUE
/obj/item/clockwork/slab/debug/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!is_servant_of_ratvar(user))
add_servant_of_ratvar(user)
return ..()
/obj/item/clockwork/slab/traitor
var/spent = FALSE
@@ -57,11 +59,6 @@
to_chat(user, "<span class='userdanger'>[src] falls dark. It appears you weren't worthy.</span>")
return ..()
/obj/item/clockwork/slab/debug/on_attack_hand(mob/living/user, act_intent = user.a_intent, unarmed_attack_flags)
if(!is_servant_of_ratvar(user))
add_servant_of_ratvar(user)
return ..()
/obj/item/clockwork/slab/cyborg //three scriptures, plus a spear and fabricator
clockwork_desc = "A divine link to the Celestial Derelict, allowing for limited recital of scripture."
quickbound = list(/datum/clockwork_scripture/ranged_ability/judicial_marker, /datum/clockwork_scripture/ranged_ability/linked_vanguard, \
@@ -145,14 +142,15 @@
/obj/item/clockwork/slab/examine(mob/user)
. = ..()
if(is_servant_of_ratvar(user) || isobserver(user))
if(LAZYLEN(quickbound))
for(var/i in 1 to quickbound.len)
if(!quickbound[i])
continue
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
. += "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>"
if(!is_servant_of_ratvar(user) || !isobserver(user))
return
if(LAZYLEN(quickbound))
for(var/i in 1 to quickbound.len)
if(!quickbound[i])
continue
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
. += "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)
@@ -198,12 +196,6 @@
ui_interact(user)
return TRUE
/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, "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)
if(!scripture || !user || !user.canUseTopic(src) || (!no_cost && !can_recite_scripture(user)))
return FALSE
@@ -223,27 +215,62 @@
scripture_to_recite.run_scripture()
return TRUE
/*
* 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
* Terminology
* Components
* Scripture
* Power
* Conversion
* * what - What section?
*/
/obj/item/clockwork/slab/proc/get_recollection(what) //Now DMDOC compliant!*
. = list()
switch(what) //need someone to rewrite info for this.
if("Default")
.["title"] = "Default"
.["info"] = "Hello servant! Currently these categories dosen't work!"
/*
if("Basics")
.["title"] = "Basics"
.["info"] = "# MARKDOWN WITH HTML?"
if("Terminology")
.["title"] = "Terminology"
.["info"] = "# MARKDOWN WITH HTML?"
if("Components")
.["title"] = "Default"
.["info"] = "# MARKDOWN WITH HTML?"
if("Scripture")
.["title"] = "Default"
.["info"] = "# MARKDOWN WITH HTML?"
if("Power")
.["title"] = "Power"
.["info"] = "# MARKDOWN WITH HTML?"
if("Conversion")
.["title"] = "Conversion"
.["info"] = "# MARKDOWN WITH HTML?"
*/
else
return null //error text handled tgui side. should not cause BSOD
//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
//- Terminology
//- Components
//- Scripture
//- Power
//- Conversion
/obj/item/clockwork/slab/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "ClockworkSlab", name)
ui.open()
/obj/item/clockwork/slab/ui_data(mob/user) //we display a lot of data via TGUI
. = 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)
for(var/s in GLOB.all_scripture) //don't block this, even when ratvar spawns for roundend griff.
var/datum/clockwork_scripture/S = GLOB.all_scripture[s]
if(S.tier == SCRIPTURE_PERIPHERAL) //yes, tiers are the tabs.
if(S.tier == SCRIPTURE_PERIPHERAL) // This tier is skiped because this contains basetype stuff
continue
var/list/data = list()
@@ -253,7 +280,7 @@
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["quickbind"] = S.quickbind //this is if it cant quickbind (bool)
data["fontcolor"] = get_component_color_bright(S.primary_component)
data["important"] = S.important //italic!
@@ -265,10 +292,8 @@
.["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())
.["rec_binds"] += list(list()) //a blank json.
else
var/datum/clockwork_scripture/quickbind_slot = quickbound[i]
.["rec_binds"] += list(list(
@@ -280,7 +305,11 @@
/obj/item/clockwork/slab/ui_static_data(mob/user)
. = list()
.["tier_infos"] = list()
.["tier_infos"] = list() //HEY!! WHEN ADDING NEW TIER, ADD IT HERE
.["tier_infos"][SCRIPTURE_PERIPHERAL] = list(
"requirement" = "Breaking the code DM side. Report to coggerbus if this appears!!",
"ready" = FALSE //just in case. Should NOT exist at all
)
.["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."
@@ -297,10 +326,10 @@
"requirement" = "Unlock powerful equipment and structures by converting five servants or if [DisplayPower(JUDGEMENT_UNLOCK_THRESHOLD)] of power is reached..",
"ready" = SSticker.scripture_states[SCRIPTURE_JUDGEMENT]
)
// .["selected"] = selected_scripture
generate_all_scripture()
.["recollection_categories"] = GLOB.ratvar_awakens ? list() : list(
.["recollection_categories"] = list()
if(GLOB.ratvar_awakens)
return
.["recollection_categories"] = 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."),
@@ -309,8 +338,9 @@
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
.["rec_section"] = get_recollection(recollection_category)
generate_all_scripture()
//needs a new place to live, preferably when clockcult unlocks/downgrades a tier. Smart enough to earlyreturn.
/obj/item/clockwork/slab/ui_act(action, params)
switch(action)
@@ -369,4 +399,4 @@
Q.button_icon_state = quickbind_slot.name
Q.UpdateButtonIcon()
if(isliving(loc))
Q.Grant(loc)
Q.Grant(loc)
@@ -7,17 +7,13 @@
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
var/maximum_timer_set = 3600
ui_style = "nanotrasen"
var/numeric_input = ""
var/ui_mode = NUKEUI_AWAIT_DISK
var/timing = FALSE
var/exploding = FALSE
var/exploded = FALSE
@@ -34,7 +30,6 @@
var/interior = ""
var/proper_bomb = TRUE //Please
var/obj/effect/countdown/nuclearbomb/countdown
var/nuclear_cooldown //used to stop global spam.
/obj/machinery/nuclearbomb/Initialize()
. = ..()
@@ -77,15 +72,16 @@
/obj/machinery/nuclearbomb/syndicate/get_cinematic_type(off_station)
var/datum/game_mode/nuclear/NM = SSticker.mode
switch(off_station)
if(FALSE)
if(0)
if(istype(NM) && !NM.nuke_team.syndies_escaped())
return CINEMATIC_ANNIHILATION
else
return CINEMATIC_NUKE_WIN
if(NUKE_MISS_STATION)
if(1)
return CINEMATIC_NUKE_MISS
else
if(2)
return CINEMATIC_NUKE_FAR
return CINEMATIC_NUKE_FAR
/obj/machinery/nuclearbomb/proc/disk_check(obj/item/disk/nuclear/D)
if(D.fake)
@@ -194,7 +190,7 @@
icon_state = "nuclearbomb_exploding"
/obj/machinery/nuclearbomb/update_overlays()
. = ..()
. += ..()
update_icon_interior()
update_icon_lights()
@@ -236,7 +232,7 @@
explode()
else
var/volume = (get_time_left() <= 20 ? 30 : 5)
playsound(loc, 'sound/items/timer.ogg', volume, 0)
playsound(loc, 'sound/items/timer.ogg', volume, FALSE)
/obj/machinery/nuclearbomb/proc/update_ui_mode()
if(exploded)
@@ -261,17 +257,18 @@
ui_mode = NUKEUI_AWAIT_TIMER
/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)
/obj/machinery/nuclearbomb/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "NuclearBomb", name, ui_x, ui_y, master_ui, state)
ui = new(user, src, "NuclearBomb", name)
ui.open()
/obj/machinery/nuclearbomb/ui_data(mob/user)
var/list/data = list()
data["disk_present"] = auth
var/hidden_code = (ui_mode == NUKEUI_AWAIT_CODE && numeric_input != "ERROR")
var/current_code = ""
if(hidden_code)
while(length(current_code) < length(numeric_input))
@@ -388,14 +385,13 @@
if("anchor")
if(auth && yes_code)
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
set_anchor(usr)
set_anchor()
else
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
/obj/machinery/nuclearbomb/proc/set_anchor(mob/user)
if((istype(get_area(src), /area/space) || isinspace()) && !anchored)
to_chat(user, "<span class='warning'>This is not a suitable platform for anchoring [src]!</span>")
/obj/machinery/nuclearbomb/proc/set_anchor()
if(isinspace() && !anchored)
to_chat(usr, "<span class='warning'>There is nothing to anchor to!</span>")
else
anchored = !anchored
@@ -416,9 +412,6 @@
if(safety)
to_chat(usr, "<span class='danger'>The safety is still on.</span>")
return
if(!timing && nuclear_cooldown > world.time)
to_chat(usr, "<span class='danger'>[src]'s timer protocols are currently on cooldown, please stand by.</span>")
return
timing = !timing
if(timing)
previous_level = NUM2SECLEVEL(GLOB.security_level)
@@ -427,12 +420,6 @@
S.switch_mode_to(TRACK_INFILTRATOR)
countdown.start()
set_security_level("delta")
nuclear_cooldown = world.time + 15 SECONDS
if(GLOB.war_declared)
var/area/A = get_area(src)
priority_announce("Alert: Unexpected increase in radiation levels near [A.name] ([src.x],[src.y],[src.z]). Please send an authorized radiation specialist to investigate.", "Sensory Nuclear Indexer Telemetry Calculation Helper")
else
detonation_timer = null
set_security_level(previous_level)
@@ -483,12 +470,19 @@
var/off_station = FALSE
var/turf/bomb_location = get_turf(src)
if(!bomb_location || !is_station_level(bomb_location.z))
off_station = NUKE_MISS_STATION
var/area/A = get_area(bomb_location)
if(bomb_location && is_station_level(bomb_location.z))
if(istype(A, /area/space))
off_station = NUKE_NEAR_MISS
if((bomb_location.x < (128-NUKERANGE)) || (bomb_location.x > (128+NUKERANGE)) || (bomb_location.y < (128-NUKERANGE)) || (bomb_location.y > (128+NUKERANGE)))
off_station = NUKE_NEAR_MISS
else if(bomb_location.onSyndieBase())
off_station = NUKE_SYNDICATE_BASE
else
off_station = NUKE_MISS_STATION
if(!off_station)
if(off_station < 2) //can only launch when nuke is on syndie base or space
SSshuttle.registerHostileEnvironment(src)
SSshuttle.lockdown = TRUE
@@ -502,13 +496,13 @@
INVOKE_ASYNC(GLOBAL_PROC,.proc/KillEveryoneOnZLevel, z)
/obj/machinery/nuclearbomb/proc/get_cinematic_type(off_station)
if(!off_station)
if(off_station < 2)
return CINEMATIC_SELFDESTRUCT
else
return CINEMATIC_SELFDESTRUCT_MISS
/obj/machinery/nuclearbomb/beer
name = "Nanotrasen-brand nuclear fission explosive"
name = "\improper Nanotrasen-brand nuclear fission explosive"
desc = "One of the more successful achievements of the Nanotrasen Corporate Warfare Division, their nuclear fission explosives are renowned for being cheap to produce and devastatingly effective. Signs explain that though this particular device has been decommissioned, every Nanotrasen station is equipped with an equivalent one, just in case. All Captains carefully guard the disk needed to detonate them - at least, the sign says they do. There seems to be a tap on the back."
proper_bomb = FALSE
var/obj/structure/reagent_dispensers/beerkeg/keg
@@ -521,9 +515,9 @@
/obj/machinery/nuclearbomb/beer/examine(mob/user)
. = ..()
if(keg.reagents.total_volume)
. += "<span class='notice'>It has [keg.reagents.total_volume] unit\s left.</span>"
to_chat(user, "<span class='notice'>It has [keg.reagents.total_volume] unit\s left.</span>")
else
. += "<span class='danger'>It's empty.</span>"
to_chat(user, "<span class='danger'>It's empty.</span>")
/obj/machinery/nuclearbomb/beer/attackby(obj/item/W, mob/user, params)
if(W.is_refillable())
@@ -535,6 +529,8 @@
return ..()
/obj/machinery/nuclearbomb/beer/actually_explode()
//Unblock roundend, we're not actually exploding.
SSticker.roundend_check_paused = FALSE
var/turf/bomb_location = get_turf(src)
if(!bomb_location)
disarm()
@@ -583,7 +579,7 @@
This is here to make the tiles around the station mininuke change when it's armed.
*/
/obj/machinery/nuclearbomb/selfdestruct/set_anchor(mob/user)
/obj/machinery/nuclearbomb/selfdestruct/set_anchor()
return
/obj/machinery/nuclearbomb/selfdestruct/set_active()
@@ -641,18 +637,19 @@ This is here to make the tiles around the station mininuke change when it's arme
if(newturf && lastlocation == newturf)
if(last_disk_move < world.time - 5000 && prob((world.time - 5000 - last_disk_move)*0.0001))
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
if(istype(loneop))
if(istype(loneop) && loneop.occurrences < loneop.max_occurrences)
loneop.weight += 1
if(loneop.weight % 5 == 0)
if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1) //players count now
message_admins("[src] is stationary in [ADMIN_VERBOSEJMP(newturf)]. The weight of Lone Operative is now [loneop.weight].")
log_game("[src] is stationary for too long in [loc_name(newturf)], and has increased the weight of the Lone Operative event to [loneop.weight].")
else
lastlocation = newturf
last_disk_move = world.time
var/datum/round_event_control/operative/loneop = locate(/datum/round_event_control/operative) in SSevents.control
if(istype(loneop) && prob(loneop.weight))
if(istype(loneop) && loneop.occurrences < loneop.max_occurrences && prob(loneop.weight))
loneop.weight = max(loneop.weight - 1, 0)
if(loneop.weight % 5 == 0)
if(loneop.weight % 5 == 0 && SSticker.totalPlayers > 1)
message_admins("[src] is on the move (currently in [ADMIN_VERBOSEJMP(newturf)]). The weight of Lone Operative is now [loneop.weight].")
log_game("[src] being on the move has reduced the weight of the Lone Operative event to [loneop.weight].")
@@ -661,9 +658,19 @@ This is here to make the tiles around the station mininuke change when it's arme
if(!fake)
return
if(isobserver(user) || HAS_TRAIT(user, TRAIT_DISK_VERIFIER) || (user.mind && HAS_TRAIT(user.mind, TRAIT_DISK_VERIFIER)))
if(isobserver(user) || HAS_TRAIT(user.mind, TRAIT_DISK_VERIFIER))
. += "<span class='warning'>The serial numbers on [src] are incorrect.</span>"
/*
* You can't accidentally eat the nuke disk, bro
*/
/*
/obj/item/disk/nuclear/on_accidental_consumption(mob/living/carbon/M, mob/living/carbon/user, obj/item/source_item, discover_after = TRUE)
M.visible_message("<span class='warning'>[M] looks like [M.p_theyve()] just bitten into something important.</span>", \
"<span class='warning'>Wait, is this the nuke disk?</span>")
return discover_after
*/
/obj/item/disk/nuclear/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/claymore/highlander) && !fake)
var/obj/item/claymore/highlander/H = I
@@ -686,7 +693,7 @@ This is here to make the tiles around the station mininuke change when it's arme
/obj/item/disk/nuclear/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] is going delta! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(src, 'sound/machines/alarm.ogg', 50, -1, 1)
playsound(src, 'sound/machines/alarm.ogg', 50, -1, TRUE)
for(var/i in 1 to 100)
addtimer(CALLBACK(user, /atom/proc/add_atom_colour, (i % 2)? "#00FF00" : "#FF0000", ADMIN_COLOUR_PRIORITY), i)
addtimer(CALLBACK(src, .proc/manual_suicide, user), 101)
@@ -694,7 +701,7 @@ This is here to make the tiles around the station mininuke change when it's arme
/obj/item/disk/nuclear/proc/manual_suicide(mob/living/user)
user.remove_atom_colour(ADMIN_COLOUR_PRIORITY)
user.visible_message("<span class='suicide'>[user] was destroyed by the nuclear blast!</span>")
user.visible_message("<span class='suicide'>[user] is destroyed by the nuclear blast!</span>")
user.adjustOxyLoss(200)
user.death(0)