mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-09 16:12:17 +00:00
TGUI Civilian
UI's Converted: - Aurora Cooking - Chaplain Book Selection - ColorMate - Cryo Storage - Holodeck - Jukebox - Looking Glass - Microwave - Newscasters - Timeclock - Vending Machine Improvements
This commit is contained in:
8
code/_global_vars/religion.dm
Normal file
8
code/_global_vars/religion.dm
Normal file
@@ -0,0 +1,8 @@
|
||||
// All religion stuff
|
||||
GLOBAL_VAR(religion)
|
||||
GLOBAL_VAR(deity)
|
||||
|
||||
//bible
|
||||
GLOBAL_VAR(bible_name)
|
||||
GLOBAL_VAR(bible_icon_state)
|
||||
GLOBAL_VAR(bible_item_state)
|
||||
@@ -32,12 +32,6 @@ SUBSYSTEM_DEF(ticker)
|
||||
|
||||
var/list/datum/mind/minds = list() // The people in the game. Used for objective tracking.
|
||||
|
||||
// TODO - I am sure there is a better place these can go.
|
||||
var/Bible_icon_state // icon_state the chaplain has chosen for his bible
|
||||
var/Bible_item_state // item_state the chaplain has chosen for his bible
|
||||
var/Bible_name // name of the bible
|
||||
var/Bible_deity_name
|
||||
|
||||
var/random_players = FALSE // If set to nonzero, ALL players who latejoin or declare-ready join will have random appearances/genders
|
||||
|
||||
// TODO - Should this go here or in the job subsystem?
|
||||
@@ -567,8 +561,4 @@ var/global/datum/controller/subsystem/ticker/ticker
|
||||
|
||||
minds = SSticker.minds
|
||||
|
||||
Bible_icon_state = SSticker.Bible_icon_state
|
||||
Bible_item_state = SSticker.Bible_item_state
|
||||
Bible_name = SSticker.Bible_name
|
||||
Bible_deity_name = SSticker.Bible_deity_name
|
||||
random_players = SSticker.random_players
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* Datum that holds the instances and information about the items stored. Currently used in SmartFridges and Vending Machines.
|
||||
*/
|
||||
/datum/stored_item
|
||||
var/item_name = "name" //Name of the item(s) displayed
|
||||
var/item_path = null
|
||||
var/amount = 0
|
||||
var/list/instances //What items are actually stored
|
||||
var/stored //The thing holding it is
|
||||
var/item_name = "name" //Name of the item(s) displayed
|
||||
var/item_path = null
|
||||
var/amount = 0
|
||||
var/list/instances //What items are actually stored
|
||||
var/stored //The thing holding it is
|
||||
|
||||
/datum/stored_item/New(var/stored, var/path, var/name = null, var/amount = 0)
|
||||
src.item_path = path
|
||||
|
||||
@@ -32,136 +32,69 @@
|
||||
if(!B)
|
||||
return
|
||||
|
||||
spawn(0)
|
||||
var/religion_name = "Unitarianism"
|
||||
var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Unitarianism", "Name change", religion_name), MAX_NAME_LEN)
|
||||
if(GLOB.religion)
|
||||
B.deity_name = GLOB.deity
|
||||
B.name = GLOB.bible_name
|
||||
B.icon_state = GLOB.bible_icon_state
|
||||
B.item_state = GLOB.bible_item_state
|
||||
to_chat(H, "<span class='boldnotice'>There is already an established religion onboard the station. You are an acolyte of [GLOB.deity]. Defer to the [title].</span>")
|
||||
return
|
||||
|
||||
INVOKE_ASYNC(src, .proc/religion_prompts, H, B)
|
||||
|
||||
if (!new_religion)
|
||||
new_religion = religion_name
|
||||
switch(lowertext(new_religion))
|
||||
if("unitarianism")
|
||||
B.name = "The Great Canon"
|
||||
if("christianity")
|
||||
B.name = "The Holy Bible"
|
||||
if("judaism")
|
||||
B.name = "The Torah"
|
||||
if("islam")
|
||||
B.name = "Quran"
|
||||
if("buddhism")
|
||||
B.name = "Tripitakas"
|
||||
if("hinduism")
|
||||
B.name = pick("The Srimad Bhagvatam", "The Four Vedas", "The Shiv Mahapuran", "Devi Mahatmya")
|
||||
if("neopaganism")
|
||||
B.name = "Neopagan Hymnbook"
|
||||
if("phact shintoism")
|
||||
B.name = "The Kojiki"
|
||||
if("kishari national faith")
|
||||
B.name = "The Scriptures of Kishar"
|
||||
if("pleromanism")
|
||||
B.name = "The Revised Great Canon"
|
||||
if("spectralism")
|
||||
B.name = "The Book of the Spark"
|
||||
if("hauler")
|
||||
B.name = "Histories of Captaincy"
|
||||
if("nock")
|
||||
B.name = "The Book of the First"
|
||||
if("singulitarian worship")
|
||||
B.name = "The Book of the Precursors"
|
||||
if("starlit path of angessa martei")
|
||||
B.name = "Quotations of Exalted Martei"
|
||||
if("sikhism")
|
||||
B.name = "Guru Granth Sahib"
|
||||
else
|
||||
B.name = "The Holy Book of [new_religion]"
|
||||
feedback_set_details("religion_name","[new_religion]")
|
||||
/datum/job/chaplain/proc/religion_prompts(mob/living/carbon/human/H, obj/item/weapon/storage/bible/B)
|
||||
var/religion_name = "Unitarianism"
|
||||
var/new_religion = sanitize(input(H, "You are the crew services officer. Would you like to change your religion? Default is Unitarianism", "Name change", religion_name), MAX_NAME_LEN)
|
||||
if(!new_religion)
|
||||
new_religion = religion_name
|
||||
|
||||
spawn(1)
|
||||
var/deity_name = "Hashem"
|
||||
var/new_deity = sanitize(input(H, "Would you like to change your deity? Default is Hashem", "Name change", deity_name), MAX_NAME_LEN)
|
||||
switch(lowertext(new_religion))
|
||||
if("unitarianism")
|
||||
B.name = "The Great Canon"
|
||||
if("christianity")
|
||||
B.name = "The Holy Bible"
|
||||
if("judaism")
|
||||
B.name = "The Torah"
|
||||
if("islam")
|
||||
B.name = "Quran"
|
||||
if("buddhism")
|
||||
B.name = "Tripitakas"
|
||||
if("hinduism")
|
||||
B.name = pick("The Srimad Bhagvatam", "The Four Vedas", "The Shiv Mahapuran", "Devi Mahatmya")
|
||||
if("neopaganism")
|
||||
B.name = "Neopagan Hymnbook"
|
||||
if("phact shintoism")
|
||||
B.name = "The Kojiki"
|
||||
if("kishari national faith")
|
||||
B.name = "The Scriptures of Kishar"
|
||||
if("pleromanism")
|
||||
B.name = "The Revised Great Canon"
|
||||
if("spectralism")
|
||||
B.name = "The Book of the Spark"
|
||||
if("hauler")
|
||||
B.name = "Histories of Captaincy"
|
||||
if("nock")
|
||||
B.name = "The Book of the First"
|
||||
if("singulitarian worship")
|
||||
B.name = "The Book of the Precursors"
|
||||
if("starlit path of angessa martei")
|
||||
B.name = "Quotations of Exalted Martei"
|
||||
if("sikhism")
|
||||
B.name = "Guru Granth Sahib"
|
||||
else
|
||||
B.name = "The Holy Book of [new_religion]"
|
||||
feedback_set_details("religion_name","[new_religion]")
|
||||
|
||||
if ((length(new_deity) == 0) || (new_deity == "Hashem") )
|
||||
new_deity = deity_name
|
||||
B.deity_name = new_deity
|
||||
var/deity_name = "Hashem"
|
||||
var/new_deity = sanitize(input(H, "Would you like to change your deity? Default is Hashem", "Name change", deity_name), MAX_NAME_LEN)
|
||||
|
||||
var/accepted = 0
|
||||
var/outoftime = 0
|
||||
spawn(200) // 20 seconds to choose
|
||||
outoftime = 1
|
||||
var/new_book_style = "Bible"
|
||||
if((length(new_deity) == 0) || (new_deity == "Hashem"))
|
||||
new_deity = deity_name
|
||||
B.deity_name = new_deity
|
||||
|
||||
while(!accepted)
|
||||
if(!B) break // prevents possible runtime errors
|
||||
new_book_style = input(H,"Which bible style would you like?") in list("Bible", "Koran", "Scrapbook", "Pagan", "White Bible", "Holy Light", "Athiest", "Tome", "The King in Yellow", "Ithaqua", "Scientology", "the bible melts", "Necronomicon","Orthodox","Torah")
|
||||
switch(new_book_style)
|
||||
if("Koran")
|
||||
B.icon_state = "koran"
|
||||
B.item_state = "koran"
|
||||
if("Scrapbook")
|
||||
B.icon_state = "scrapbook"
|
||||
B.item_state = "scrapbook"
|
||||
if("White Bible")
|
||||
B.icon_state = "white"
|
||||
B.item_state = "syringe_kit"
|
||||
if("Holy Light")
|
||||
B.icon_state = "holylight"
|
||||
B.item_state = "syringe_kit"
|
||||
if("Athiest")
|
||||
B.icon_state = "athiest"
|
||||
B.item_state = "syringe_kit"
|
||||
if("Tome")
|
||||
B.icon_state = "tome"
|
||||
B.item_state = "syringe_kit"
|
||||
if("The King in Yellow")
|
||||
B.icon_state = "kingyellow"
|
||||
B.item_state = "kingyellow"
|
||||
if("Ithaqua")
|
||||
B.icon_state = "ithaqua"
|
||||
B.item_state = "ithaqua"
|
||||
if("Scientology")
|
||||
B.icon_state = "scientology"
|
||||
B.item_state = "scientology"
|
||||
if("the bible melts")
|
||||
B.icon_state = "melted"
|
||||
B.item_state = "melted"
|
||||
if("Necronomicon")
|
||||
B.icon_state = "necronomicon"
|
||||
B.item_state = "necronomicon"
|
||||
if("Pagan")
|
||||
B.icon_state = "shadows"
|
||||
B.item_state = "syringe_kit"
|
||||
if("Orthodox")
|
||||
B.icon_state = "orthodoxy"
|
||||
B.item_state = "bible"
|
||||
if("Torah")
|
||||
B.icon_state = "torah"
|
||||
B.item_state = "clipboard"
|
||||
if("Guru")
|
||||
B.icon_state = "guru"
|
||||
B.item_state = "clipboard"
|
||||
else
|
||||
B.icon_state = "bible"
|
||||
B.item_state = "bible"
|
||||
GLOB.religion = new_religion
|
||||
GLOB.bible_name = B.name
|
||||
GLOB.deity = B.deity_name
|
||||
feedback_set_details("religion_deity","[new_deity]")
|
||||
|
||||
|
||||
H.update_inv_l_hand() // so that it updates the bible's item_state in his hand
|
||||
|
||||
switch(input(H,"Look at your bible - is this what you want?") in list("Yes","No"))
|
||||
if("Yes")
|
||||
accepted = 1
|
||||
if("No")
|
||||
if(outoftime)
|
||||
to_chat(H, "Welp, out of time, buddy. You're stuck. Next time choose faster.")
|
||||
accepted = 1
|
||||
|
||||
if(ticker)
|
||||
ticker.Bible_icon_state = B.icon_state
|
||||
ticker.Bible_item_state = B.item_state
|
||||
ticker.Bible_name = B.name
|
||||
ticker.Bible_deity_name = B.deity_name
|
||||
feedback_set_details("religion_deity","[new_deity]")
|
||||
feedback_set_details("religion_book","[new_book_style]")
|
||||
return 1
|
||||
|
||||
/* If you uncomment this, every time the mob preview updates it makes a new PDA. It seems to work just fine and display without it, so why this exists, haven't a clue. -Hawk
|
||||
/datum/job/chaplain/equip_preview(var/mob/living/carbon/human/H, var/alt_title)
|
||||
return equip(H, alt_title, FALSE)
|
||||
*/
|
||||
|
||||
@@ -66,23 +66,33 @@
|
||||
if(..())
|
||||
return
|
||||
user.set_machine(src)
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/timeclock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
user.set_machine(src)
|
||||
/obj/machinery/computer/timeclock/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "TimeClock", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/timeclock/tgui_data(mob/user)
|
||||
var/list/data = ..()
|
||||
|
||||
var/list/data = list()
|
||||
// Okay, data for showing the user's OWN PTO stuff
|
||||
if(user.client)
|
||||
data["department_hours"] = SANITIZE_LIST(user.client.department_hours)
|
||||
data["user_name"] = "[user]"
|
||||
|
||||
// Data about the card that we put into it.
|
||||
data["card"] = null
|
||||
data["assignment"] = null
|
||||
data["job_datum"] = null
|
||||
data["allow_change_job"] = null
|
||||
data["job_choices"] = null
|
||||
if(card)
|
||||
data["card"] = "[card]"
|
||||
data["assignment"] = card.assignment
|
||||
var/datum/job/job = job_master.GetJob(card.rank)
|
||||
if (job)
|
||||
if(job)
|
||||
data["job_datum"] = list(
|
||||
"title" = job.title,
|
||||
"departments" = english_list(job.departments),
|
||||
@@ -96,46 +106,42 @@
|
||||
if(job && job.timeoff_factor < 0) // Currently are Off Duty, so gotta lookup what on-duty jobs are open
|
||||
data["job_choices"] = getOpenOnDutyJobs(user, job.pto_type)
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "timeclock_vr.tmpl", capitalize(src.name), 500, 520)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/timeclock/Topic(href, href_list)
|
||||
/obj/machinery/computer/timeclock/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return 1
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
return TRUE
|
||||
|
||||
if (href_list["id"])
|
||||
if(card)
|
||||
usr.put_in_hands(card)
|
||||
card = null
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
|
||||
I.forceMove(src)
|
||||
card = I
|
||||
update_icon()
|
||||
return 1
|
||||
if(href_list["switch-to-onduty-rank"])
|
||||
if(checkFace())
|
||||
if(checkCardCooldown())
|
||||
makeOnDuty(href_list["switch-to-onduty-rank"], href_list["switch-to-onduty-assignment"])
|
||||
add_fingerprint(usr)
|
||||
|
||||
switch(action)
|
||||
if("id")
|
||||
if(card)
|
||||
usr.put_in_hands(card)
|
||||
card = null
|
||||
update_icon()
|
||||
return 1
|
||||
if(href_list["switch-to-offduty"])
|
||||
if(checkFace())
|
||||
if(checkCardCooldown())
|
||||
makeOffDuty()
|
||||
usr.put_in_hands(card)
|
||||
card = null
|
||||
update_icon()
|
||||
return 1
|
||||
return 1 // Return 1 to update UI
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id) && usr.unEquip(I))
|
||||
I.forceMove(src)
|
||||
card = I
|
||||
update_icon()
|
||||
return TRUE
|
||||
if("switch-to-onduty-rank")
|
||||
if(checkFace())
|
||||
if(checkCardCooldown())
|
||||
makeOnDuty(params["switch-to-onduty-rank"], params["switch-to-onduty-assignment"])
|
||||
usr.put_in_hands(card)
|
||||
card = null
|
||||
update_icon()
|
||||
return TRUE
|
||||
if("switch-to-offduty")
|
||||
if(checkFace())
|
||||
if(checkCardCooldown())
|
||||
makeOffDuty()
|
||||
usr.put_in_hands(card)
|
||||
card = null
|
||||
update_icon()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/timeclock/proc/getOpenOnDutyJobs(var/mob/user, var/department)
|
||||
var/list/available_jobs = list()
|
||||
|
||||
@@ -74,97 +74,81 @@
|
||||
storage_name = "Travel Oversight Control"
|
||||
allow_items = 1
|
||||
|
||||
/obj/machinery/computer/cryopod/attack_ai()
|
||||
attack_hand()
|
||||
/obj/machinery/computer/cryopod/attack_ai(mob/user)
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/computer/cryopod/attack_hand(mob/user = usr)
|
||||
/obj/machinery/computer/cryopod/attack_hand(mob/user)
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
|
||||
user.set_machine(src)
|
||||
add_fingerprint(usr)
|
||||
tgui_interact(user)
|
||||
|
||||
var/dat
|
||||
/obj/machinery/computer/cryopod/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "CryoStorageVr", storage_name) // VOREStation Edit - Use our own template for our custom data
|
||||
ui.open()
|
||||
|
||||
if(!(ticker))
|
||||
return
|
||||
/obj/machinery/computer/cryopod/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
dat += "<hr/><br/><b>[storage_name]</b><br/>"
|
||||
dat += "<i>Welcome, [user.real_name].</i><br/><br/><hr/>"
|
||||
dat += "<a href='?src=\ref[src];log=1'>View storage log</a>.<br>"
|
||||
data["real_name"] = user.real_name
|
||||
data["allow_items"] = allow_items
|
||||
data["crew"] = frozen_crew
|
||||
|
||||
data["items"] = list()
|
||||
if(allow_items)
|
||||
dat += "<a href='?src=\ref[src];view=1'>View objects</a>.<br>"
|
||||
//dat += "<a href='?src=\ref[src];item=1'>Recover object</a>.<br>" //VOREStation Removal - Just log them.
|
||||
//dat += "<a href='?src=\ref[src];allitems=1'>Recover all objects</a>.<br>" //VOREStation Removal
|
||||
for(var/F in frozen_items)
|
||||
data["items"].Add(F) // VOREStation Edit
|
||||
/* VOREStation Removal
|
||||
data["items"].Add(list(list(
|
||||
"name" = "[F]",
|
||||
"ref" = REF(F),
|
||||
)))
|
||||
VOREStation Removal End */
|
||||
|
||||
user << browse(dat, "window=cryopod_console")
|
||||
onclose(user, "cryopod_console")
|
||||
|
||||
/obj/machinery/computer/cryopod/Topic(href, href_list)
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/cryopod/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return
|
||||
|
||||
var/mob/user = usr
|
||||
add_fingerprint(usr)
|
||||
|
||||
add_fingerprint(user)
|
||||
return FALSE // VOREStation Edit - prevent topic exploits
|
||||
|
||||
if(href_list["log"])
|
||||
switch(action)
|
||||
if("item")
|
||||
if(!allow_items)
|
||||
return
|
||||
|
||||
var/dat = "<b>Recently stored [storage_type]</b><br/><hr/><br/>"
|
||||
for(var/person in frozen_crew)
|
||||
dat += "[person]<br/>"
|
||||
dat += "<hr/>"
|
||||
if(!LAZYLEN(frozen_items))
|
||||
to_chat(usr, "<span class='notice'>There is nothing to recover from storage.</span>")
|
||||
return
|
||||
|
||||
user << browse(dat, "window=cryolog")
|
||||
var/obj/item/I = locate(params["ref"]) in frozen_items
|
||||
if(!I)
|
||||
to_chat(usr, "<span class='notice'>\The [I] is no longer in storage.</span>")
|
||||
return
|
||||
|
||||
if(href_list["view"])
|
||||
if(!allow_items) return
|
||||
visible_message("<span class='notice'>The console beeps happily as it disgorges [I].</span>")
|
||||
|
||||
var/dat = "<b>Recently stored objects</b><br/><hr/><br/>"
|
||||
//VOREStation Edit Start
|
||||
for(var/I in frozen_items)
|
||||
dat += "[I]<br/>"
|
||||
//VOREStation Edit End
|
||||
dat += "<hr/>"
|
||||
|
||||
user << browse(dat, "window=cryoitems")
|
||||
|
||||
else if(href_list["item"])
|
||||
if(!allow_items) return
|
||||
|
||||
if(frozen_items.len == 0)
|
||||
to_chat(user, "<span class='notice'>There is nothing to recover from storage.</span>")
|
||||
return
|
||||
|
||||
var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items
|
||||
if(!I)
|
||||
return
|
||||
|
||||
if(!(I in frozen_items))
|
||||
to_chat(user, "<span class='notice'>\The [I] is no longer in storage.</span>")
|
||||
return
|
||||
|
||||
visible_message("<span class='notice'>The console beeps happily as it disgorges \the [I].</span>", 3)
|
||||
|
||||
I.forceMove(get_turf(src))
|
||||
frozen_items -= I
|
||||
|
||||
else if(href_list["allitems"])
|
||||
if(!allow_items) return
|
||||
|
||||
if(frozen_items.len == 0)
|
||||
to_chat(user, "<span class='notice'>There is nothing to recover from storage.</span>")
|
||||
return
|
||||
|
||||
visible_message("<span class='notice'>The console beeps happily as it disgorges the desired objects.</span>", 3)
|
||||
|
||||
for(var/obj/item/I in frozen_items)
|
||||
I.forceMove(get_turf(src))
|
||||
frozen_items -= I
|
||||
if("allitems")
|
||||
if(!allow_items)
|
||||
return
|
||||
|
||||
if(!LAZYLEN(frozen_items))
|
||||
to_chat(usr, "<span class='notice'>There is nothing to recover from storage.</span>")
|
||||
return
|
||||
|
||||
visible_message("<span class='notice'>The console beeps happily as it disgorges the desired objects.</span>")
|
||||
|
||||
for(var/obj/item/I in frozen_items)
|
||||
I.forceMove(get_turf(src))
|
||||
frozen_items -= I
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
/obj/item/weapon/circuitboard/cryopodcontrol
|
||||
name = "Circuit board (Cryogenic Oversight Console)"
|
||||
|
||||
@@ -188,91 +188,92 @@
|
||||
if (panel_open)
|
||||
overlays += "panel_open"
|
||||
|
||||
/obj/machinery/media/jukebox/Topic(href, href_list)
|
||||
if(..() || !(Adjacent(usr) || istype(usr, /mob/living/silicon)))
|
||||
return
|
||||
|
||||
if(!anchored)
|
||||
to_chat(usr, "<span class='warning'>You must secure \the [src] first.</span>")
|
||||
return
|
||||
|
||||
if(inoperable())
|
||||
to_chat(usr, "\The [src] doesn't appear to function.")
|
||||
return
|
||||
|
||||
if(href_list["change_track"])
|
||||
var/datum/track/T = locate(href_list["change_track"]) in tracks
|
||||
if(istype(T))
|
||||
current_track = T
|
||||
StartPlaying()
|
||||
else if(href_list["loopmode"])
|
||||
var/newval = text2num(href_list["loopmode"])
|
||||
loop_mode = sanitize_inlist(newval, list(JUKEMODE_NEXT, JUKEMODE_RANDOM, JUKEMODE_REPEAT_SONG, JUKEMODE_PLAY_ONCE), loop_mode)
|
||||
else if(href_list["volume"])
|
||||
var/newval = input("Choose Jukebox volume (0-100%)", "Jukebox volume", round(volume * 100.0))
|
||||
newval = sanitize_integer(text2num(newval), min = 0, max = 100, default = volume * 100.0)
|
||||
volume = newval / 100.0
|
||||
update_music() // To broadcast volume change without restarting song
|
||||
else if(href_list["stop"])
|
||||
StopPlaying()
|
||||
else if(href_list["play"])
|
||||
if(emagged)
|
||||
playsound(src, 'sound/items/AirHorn.ogg', 100, 1)
|
||||
for(var/mob/living/carbon/M in ohearers(6, src))
|
||||
if(M.get_ear_protection() >= 2)
|
||||
continue
|
||||
M.SetSleeping(0)
|
||||
M.stuttering += 20
|
||||
M.ear_deaf += 30
|
||||
M.Weaken(3)
|
||||
if(prob(30))
|
||||
M.Stun(10)
|
||||
M.Paralyse(4)
|
||||
else
|
||||
M.make_jittery(500)
|
||||
spawn(15)
|
||||
explode()
|
||||
else if(current_track == null)
|
||||
to_chat(usr, "No track selected.")
|
||||
else
|
||||
StartPlaying()
|
||||
|
||||
return 1
|
||||
|
||||
/obj/machinery/media/jukebox/interact(mob/user)
|
||||
if(inoperable())
|
||||
to_chat(usr, "\The [src] doesn't appear to function.")
|
||||
return
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/media/jukebox/ui_interact(mob/user, ui_key = "jukebox", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
var/title = "RetroBox - Space Style"
|
||||
var/data[0]
|
||||
/obj/machinery/media/jukebox/tgui_status(mob/user)
|
||||
if(inoperable())
|
||||
to_chat(user, "<span class='warning'>[src] doesn't appear to function.</span>")
|
||||
return STATUS_CLOSE
|
||||
if(!anchored)
|
||||
to_chat(user, "<span class='warning'>You must secure [src] first.</span>")
|
||||
return STATUS_CLOSE
|
||||
. = ..()
|
||||
|
||||
if(operable())
|
||||
data["playing"] = playing
|
||||
data["hacked"] = hacked
|
||||
data["max_queue_len"] = max_queue_len
|
||||
data["media_start_time"] = media_start_time
|
||||
data["loop_mode"] = loop_mode
|
||||
data["volume"] = volume
|
||||
if(current_track)
|
||||
data["current_track_ref"] = "\ref[current_track]" // Convenient shortcut
|
||||
data["current_track"] = current_track.toNanoList()
|
||||
data["percent"] = playing ? min(100, round(world.time - media_start_time) / current_track.duration) : 0;
|
||||
|
||||
var/list/nano_tracks = new
|
||||
for(var/datum/track/T in tracks)
|
||||
nano_tracks[++nano_tracks.len] = T.toNanoList()
|
||||
data["tracks"] = nano_tracks
|
||||
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "jukebox.tmpl", title, 450, 600)
|
||||
ui.set_initial_data(data)
|
||||
/obj/machinery/media/jukebox/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Jukebox", "RetroBox - Space Style")
|
||||
ui.open()
|
||||
ui.set_auto_update(playing)
|
||||
|
||||
/obj/machinery/media/jukebox/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
data["playing"] = playing
|
||||
data["loop_mode"] = loop_mode
|
||||
data["volume"] = volume
|
||||
data["current_track_ref"] = null
|
||||
data["current_track"] = null
|
||||
if(current_track)
|
||||
data["current_track_ref"] = "\ref[current_track]" // Convenient shortcut
|
||||
data["current_track"] = current_track.toTguiList()
|
||||
data["percent"] = playing ? min(100, round(world.time - media_start_time) / current_track.duration) : 0;
|
||||
|
||||
var/list/tgui_tracks = list()
|
||||
for(var/datum/track/T in tracks)
|
||||
tgui_tracks.Add(list(T.toTguiList()))
|
||||
data["tracks"] = tgui_tracks
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/media/jukebox/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("change_track")
|
||||
var/datum/track/T = locate(params["change_track"]) in tracks
|
||||
if(istype(T))
|
||||
current_track = T
|
||||
StartPlaying()
|
||||
return TRUE
|
||||
if("loopmode")
|
||||
var/newval = text2num(params["loopmode"])
|
||||
loop_mode = sanitize_inlist(newval, list(JUKEMODE_NEXT, JUKEMODE_RANDOM, JUKEMODE_REPEAT_SONG, JUKEMODE_PLAY_ONCE), loop_mode)
|
||||
return TRUE
|
||||
if("volume")
|
||||
volume = clamp(params["val"], 0, 1)
|
||||
update_music() // To broadcast volume change without restarting song
|
||||
return TRUE
|
||||
if("stop")
|
||||
StopPlaying()
|
||||
return TRUE
|
||||
if("play")
|
||||
if(emagged)
|
||||
playsound(src, 'sound/items/AirHorn.ogg', 100, 1)
|
||||
for(var/mob/living/carbon/M in ohearers(6, src))
|
||||
if(M.get_ear_protection() >= 2)
|
||||
continue
|
||||
M.SetSleeping(0)
|
||||
M.stuttering += 20
|
||||
M.ear_deaf += 30
|
||||
M.Weaken(3)
|
||||
if(prob(30))
|
||||
M.Stun(10)
|
||||
M.Paralyse(4)
|
||||
else
|
||||
M.make_jittery(500)
|
||||
spawn(15)
|
||||
explode()
|
||||
else if(current_track == null)
|
||||
to_chat(usr, "No track selected.")
|
||||
else
|
||||
StartPlaying()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/media/jukebox/attack_ai(mob/user as mob)
|
||||
return src.attack_hand(user)
|
||||
|
||||
@@ -132,20 +132,6 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
var/ispowered = 1 //starts powered, changes with power_change()
|
||||
//var/list/datum/feed_channel/channel_list = list() //This list will contain the names of the feed channels. Each name will refer to a data region where the messages of the feed channels are stored.
|
||||
//OBSOLETE: We're now using a global news network
|
||||
var/screen = 0 //Or maybe I'll make it into a list within a list afterwards... whichever I prefer, go fuck yourselves :3
|
||||
// 0 = welcome screen - main menu
|
||||
// 1 = view feed channels
|
||||
// 2 = create feed channel
|
||||
// 3 = create feed story
|
||||
// 4 = feed story submited sucessfully
|
||||
// 5 = feed channel created successfully
|
||||
// 6 = ERROR: Cannot create feed story
|
||||
// 7 = ERROR: Cannot create feed channel
|
||||
// 8 = print newspaper
|
||||
// 9 = viewing channel feeds
|
||||
// 10 = censor feed story
|
||||
// 11 = censor feed channel
|
||||
//Holy shit this is outdated, made this when I was still starting newscasters :3
|
||||
var/paper_remaining = 0
|
||||
var/securityCaster = 0
|
||||
// 0 = Caster cannot be used to issue wanted posters
|
||||
@@ -171,6 +157,8 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
anchored = 1
|
||||
var/obj/machinery/exonet_node/node = null
|
||||
circuit = /obj/item/weapon/circuitboard/newscaster
|
||||
// TGUI
|
||||
var/list/temp = null
|
||||
|
||||
/obj/machinery/newscaster/security_unit //Security unit
|
||||
name = "Security Newscaster"
|
||||
@@ -246,10 +234,16 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
return
|
||||
return
|
||||
|
||||
/obj/machinery/newscaster/attack_ai(mob/user as mob)
|
||||
/obj/machinery/newscaster/attack_ai(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/newscaster/attack_hand(mob/user as mob) //########### THE MAIN BEEF IS HERE! And in the proc below this...############
|
||||
/obj/machinery/newscaster/tgui_status(mob/user)
|
||||
if(!ispowered || isbroken)
|
||||
return STATUS_CLOSE
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/machinery/newscaster/attack_hand(mob/user)
|
||||
if(!ispowered || isbroken)
|
||||
return
|
||||
|
||||
@@ -263,263 +257,136 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
|
||||
if(!user.IsAdvancedToolUser())
|
||||
return 0
|
||||
|
||||
tgui_interact(user)
|
||||
|
||||
if(istype(user, /mob/living/carbon/human) || istype(user,/mob/living/silicon))
|
||||
var/mob/living/human_or_robot_user = user
|
||||
var/dat
|
||||
dat = text("<HEAD><TITLE>Newscaster</TITLE></HEAD><H3>Newscaster Unit #[unit_no]</H3>")
|
||||
/**
|
||||
* Sets a temporary message to display to the user
|
||||
*
|
||||
* Arguments:
|
||||
* * text - Text to display, null/empty to clear the message from the UI
|
||||
* * style - The style of the message: (color name), info, success, warning, danger, virus
|
||||
*/
|
||||
/obj/machinery/newscaster/proc/set_temp(text = "", style = "info", update_now = FALSE)
|
||||
temp = list(text = text, style = style)
|
||||
if(update_now)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/newscaster/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Newscaster", "Newscaster Unit #[unit_no]")
|
||||
ui.open()
|
||||
|
||||
scan_user(human_or_robot_user) //Newscaster scans you
|
||||
/obj/machinery/newscaster/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
switch(screen)
|
||||
if(0)
|
||||
dat += "Welcome to Newscasting Unit #[unit_no].<BR> Interface & News networks Operational."
|
||||
dat += "<BR><FONT SIZE=1>Property of NanoTrasen Inc</FONT>"
|
||||
if(news_network.wanted_issue)
|
||||
dat+= "<HR><A href='?src=\ref[src];view_wanted=1'>Read Wanted Issue</A>"
|
||||
dat+= "<HR><BR><A href='?src=\ref[src];create_channel=1'>Create Feed Channel</A>"
|
||||
dat+= "<BR><A href='?src=\ref[src];view=1'>View Feed Channels</A>"
|
||||
dat+= "<BR><A href='?src=\ref[src];create_feed_story=1'>Submit new Feed story</A>"
|
||||
dat+= "<BR><A href='?src=\ref[src];menu_paper=1'>Print newspaper</A>"
|
||||
dat+= "<BR><A href='?src=\ref[src];refresh=1'>Re-scan User</A>"
|
||||
dat+= "<BR><BR><A href='?src=\ref[human_or_robot_user];mach_close=newscaster_main'>Exit</A>"
|
||||
if(securityCaster)
|
||||
var/wanted_already = 0
|
||||
if(news_network.wanted_issue)
|
||||
wanted_already = 1
|
||||
// Main menu
|
||||
data["temp"] = temp
|
||||
|
||||
dat+="<HR><B>Feed Security functions:</B><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];menu_wanted=1'>[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue</A>"
|
||||
dat+="<BR><A href='?src=\ref[src];menu_censor_story=1'>Censor Feed Stories</A>"
|
||||
dat+="<BR><A href='?src=\ref[src];menu_censor_channel=1'>Mark Feed Channel with [using_map.company_name] D-Notice</A>"
|
||||
dat+="<BR><HR>The newscaster recognises you as: <FONT COLOR='green'>[scanned_user]</FONT>"
|
||||
if(1)
|
||||
dat+= "Station Feed Channels<HR>"
|
||||
if(isemptylist(news_network.network_channels))
|
||||
dat+="<I>No active channels found...</I>"
|
||||
else
|
||||
for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
|
||||
if(CHANNEL.is_admin_channel)
|
||||
dat+="<B><FONT style='BACKGROUND-COLOR: LightGreen '><A href='?src=\ref[src];show_channel=\ref[CHANNEL]'>[CHANNEL.channel_name]</A></FONT></B><BR>"
|
||||
else
|
||||
dat+="<B><A href='?src=\ref[src];show_channel=\ref[CHANNEL]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : null]<BR></B>"
|
||||
dat+="<BR><HR><A href='?src=\ref[src];refresh=1'>Refresh</A>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Back</A>"
|
||||
if(2)
|
||||
dat+="Creating new Feed Channel..."
|
||||
dat+="<HR><B><A href='?src=\ref[src];set_channel_name=1'>Channel Name</A>:</B> [channel_name]<BR>"
|
||||
dat+="<B>Channel Author:</B> <FONT COLOR='green'>[scanned_user]</FONT><BR>"
|
||||
dat+="<B><A href='?src=\ref[src];set_channel_lock=1'>Will Accept Public Feeds</A>:</B> [(c_locked) ? ("NO") : ("YES")]<BR><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];submit_new_channel=1'>Submit</A><BR><BR><A href='?src=\ref[src];setScreen=[0]'>Cancel</A><BR>"
|
||||
if(3)
|
||||
dat+="Creating new Feed Message..."
|
||||
dat+="<HR><B><A href='?src=\ref[src];set_channel_receiving=1'>Receiving Channel</A>:</B> [channel_name]<BR>" //MARK
|
||||
dat+="<B>Message Author:</B> <FONT COLOR='green'>[scanned_user]</FONT><BR>"
|
||||
dat+="<B><A href='?src=\ref[src];set_new_message=1'>Message Body</A>:</B> [msg] <BR>"
|
||||
dat+="<B><A href='?src=\ref[src];set_attachment=1'>Attach Photo</A>:</B> [(photo_data ? "Photo Attached" : "No Photo")]</BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];submit_new_message=1'>Submit</A><BR><BR><A href='?src=\ref[src];setScreen=[0]'>Cancel</A><BR>"
|
||||
if(4)
|
||||
dat+="Feed story successfully submitted to [channel_name].<BR><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Return</A><BR>"
|
||||
if(5)
|
||||
dat+="Feed Channel [channel_name] created successfully.<BR><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Return</A><BR>"
|
||||
if(6)
|
||||
dat+="<B><FONT COLOR='maroon'>ERROR: Could not submit Feed story to Network.</B></FONT><HR><BR>"
|
||||
if(channel_name=="")
|
||||
dat+="<FONT COLOR='maroon'>Invalid receiving channel name.</FONT><BR>"
|
||||
if(scanned_user=="Unknown")
|
||||
dat+="<FONT COLOR='maroon'>Channel author unverified.</FONT><BR>"
|
||||
if(msg == "" || msg == "\[REDACTED\]")
|
||||
dat+="<FONT COLOR='maroon'>Invalid message body.</FONT><BR>"
|
||||
data["user"] = tgui_user_name(user)
|
||||
data["unit_no"] = unit_no
|
||||
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[3]'>Return</A><BR>"
|
||||
if(7)
|
||||
dat+="<B><FONT COLOR='maroon'>ERROR: Could not submit Feed Channel to Network.</B></FONT><HR><BR>"
|
||||
var/list/existing_authors = list()
|
||||
for(var/datum/feed_channel/FC in news_network.network_channels)
|
||||
if(FC.author == "\[REDACTED\]")
|
||||
existing_authors += FC.backup_author
|
||||
else
|
||||
existing_authors += FC.author
|
||||
if(scanned_user in existing_authors)
|
||||
dat+="<FONT COLOR='maroon'>There already exists a Feed channel under your name.</FONT><BR>"
|
||||
if(channel_name=="" || channel_name == "\[REDACTED\]")
|
||||
dat+="<FONT COLOR='maroon'>Invalid channel name.</FONT><BR>"
|
||||
var/check = 0
|
||||
for(var/datum/feed_channel/FC in news_network.network_channels)
|
||||
if(FC.channel_name == channel_name)
|
||||
check = 1
|
||||
break
|
||||
if(check)
|
||||
dat+="<FONT COLOR='maroon'>Channel name already in use.</FONT><BR>"
|
||||
if(scanned_user=="Unknown")
|
||||
dat+="<FONT COLOR='maroon'>Channel author unverified.</FONT><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[2]'>Return</A><BR>"
|
||||
if(8)
|
||||
var/total_num=length(news_network.network_channels)
|
||||
var/active_num=total_num
|
||||
var/message_num=0
|
||||
for(var/datum/feed_channel/FC in news_network.network_channels)
|
||||
if(!FC.censored)
|
||||
message_num += length(FC.messages) //Dont forget, datum/feed_channel's var messages is a list of datum/feed_message
|
||||
else
|
||||
active_num--
|
||||
dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories." //TODO: CONTINUE
|
||||
dat+="<BR><BR><B>Liquid Paper remaining:</B> [(paper_remaining) *100 ] cm^3"
|
||||
dat+="<BR><BR><A href='?src=\ref[src];print_paper=[0]'>Print Paper</A>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Cancel</A>"
|
||||
if(9)
|
||||
dat+="<B>[viewing_channel.channel_name]: </B><FONT SIZE=1>\[created by: <FONT COLOR='maroon'>[viewing_channel.author]</FONT>\]</FONT><HR>"
|
||||
if(viewing_channel.censored)
|
||||
dat+="<FONT COLOR='red'><B>ATTENTION: </B></FONT>This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.<BR>"
|
||||
dat+="No further feed story additions are allowed while the D-Notice is in effect.</FONT><BR><BR>"
|
||||
else
|
||||
if(isemptylist(viewing_channel.messages))
|
||||
dat+="<I>No feed messages found in channel...</I><BR>"
|
||||
else
|
||||
var/i = 0
|
||||
for(var/datum/feed_message/MESSAGE in viewing_channel.messages)
|
||||
i++
|
||||
dat+="-[MESSAGE.body] <BR>"
|
||||
if(MESSAGE.img)
|
||||
usr << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
|
||||
dat+="<img src='tmp_photo[i].png' width = '180'><BR>"
|
||||
if(MESSAGE.caption)
|
||||
dat+="<FONT SIZE=1><B>[MESSAGE.caption]</B></FONT><BR>"
|
||||
dat+="<BR>"
|
||||
dat+="<FONT SIZE=1>\[Story by <FONT COLOR='maroon'>[MESSAGE.author] - [MESSAGE.time_stamp]</FONT>\]</FONT><BR>"
|
||||
dat+="<BR><HR><A href='?src=\ref[src];refresh=1'>Refresh</A>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[1]'>Back</A>"
|
||||
if(10)
|
||||
dat+="<B>[using_map.company_name] Feed Censorship Tool</B><BR>"
|
||||
dat+="<FONT SIZE=1>NOTE: Due to the nature of news Feeds, total deletion of a Feed Story is not possible.<BR>"
|
||||
dat+="Keep in mind that users attempting to view a censored feed will instead see the \[REDACTED\] tag above it.</FONT>"
|
||||
dat+="<HR>Select Feed channel to get Stories from:<BR>"
|
||||
if(isemptylist(news_network.network_channels))
|
||||
dat+="<I>No feed channels found active...</I><BR>"
|
||||
else
|
||||
for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
|
||||
dat+="<A href='?src=\ref[src];pick_censor_channel=\ref[CHANNEL]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : null]<BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Cancel</A>"
|
||||
if(11)
|
||||
dat+="<B>[using_map.company_name] D-Notice Handler</B><HR>"
|
||||
dat+="<FONT SIZE=1>A D-Notice is to be bestowed upon the channel if the handling Authority deems it as harmful for the station's"
|
||||
dat+="morale, integrity or disciplinary behaviour. A D-Notice will render a channel unable to be updated by anyone, without deleting any feed"
|
||||
dat+="stories it might contain at the time. You can lift a D-Notice if you have the required access at any time.</FONT><HR>"
|
||||
if(isemptylist(news_network.network_channels))
|
||||
dat+="<I>No feed channels found active...</I><BR>"
|
||||
else
|
||||
for(var/datum/feed_channel/CHANNEL in news_network.network_channels)
|
||||
dat+="<A href='?src=\ref[src];pick_d_notice=\ref[CHANNEL]'>[CHANNEL.channel_name]</A> [(CHANNEL.censored) ? ("<FONT COLOR='red'>***</FONT>") : null]<BR>"
|
||||
var/list/wanted_issue = null
|
||||
if(news_network.wanted_issue)
|
||||
wanted_issue = list(
|
||||
"author" = news_network.wanted_issue.backup_author,
|
||||
"criminal" = news_network.wanted_issue.author,
|
||||
"desc" = news_network.wanted_issue.body,
|
||||
"img" = null
|
||||
)
|
||||
if(news_network.wanted_issue.img)
|
||||
wanted_issue["img"] = icon2base64(news_network.wanted_issue.img)
|
||||
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Back</A>"
|
||||
if(12)
|
||||
dat+="<B>[viewing_channel.channel_name]: </B><FONT SIZE=1>\[ created by: <FONT COLOR='maroon'>[viewing_channel.author]</FONT> \]</FONT><BR>"
|
||||
dat+="<FONT SIZE=2><A href='?src=\ref[src];censor_channel_author=\ref[viewing_channel]'>[(viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]</A></FONT><HR>"
|
||||
data["wanted_issue"] = wanted_issue
|
||||
|
||||
data["securityCaster"] = !!securityCaster
|
||||
|
||||
var/list/network_channels = list()
|
||||
for(var/datum/feed_channel/FC in news_network.network_channels)
|
||||
network_channels.Add(list(list(
|
||||
"admin" = FC.is_admin_channel,
|
||||
"ref" = REF(FC),
|
||||
"name" = FC.channel_name,
|
||||
"censored" = FC.censored,
|
||||
)))
|
||||
data["channels"] = network_channels
|
||||
|
||||
if(isemptylist(viewing_channel.messages))
|
||||
dat+="<I>No feed messages found in channel...</I><BR>"
|
||||
else
|
||||
for(var/datum/feed_message/MESSAGE in viewing_channel.messages)
|
||||
dat+="-[MESSAGE.body] <BR><FONT SIZE=1>\[[MESSAGE.message_type] by <FONT COLOR='maroon'>[MESSAGE.author]</FONT>\]</FONT><BR>"
|
||||
dat+="<FONT SIZE=2><A href='?src=\ref[src];censor_channel_story_body=\ref[MESSAGE]'>[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")]</A> - <A href='?src=\ref[src];censor_channel_story_author=\ref[MESSAGE]'>[(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]</A></FONT><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[10]'>Back</A>"
|
||||
if(13)
|
||||
dat+="<B>[viewing_channel.channel_name]: </B><FONT SIZE=1>\[ created by: <FONT COLOR='maroon'>[viewing_channel.author]</FONT> \]</FONT><BR>"
|
||||
dat+="Channel messages listed below. If you deem them dangerous to the station, you can <A href='?src=\ref[src];toggle_d_notice=\ref[viewing_channel]'>Bestow a D-Notice upon the channel</A>.<HR>"
|
||||
if(viewing_channel.censored)
|
||||
dat+="<FONT COLOR='red'><B>ATTENTION: </B></FONT>This channel has been deemed as threatening to the welfare of the station, and marked with a [using_map.company_name] D-Notice.<BR>"
|
||||
dat+="No further feed story additions are allowed while the D-Notice is in effect.<BR><BR>"
|
||||
else
|
||||
if(isemptylist(viewing_channel.messages))
|
||||
dat+="<I>No feed messages found in channel...</I><BR>"
|
||||
else
|
||||
for(var/datum/feed_message/MESSAGE in viewing_channel.messages)
|
||||
dat+="-[MESSAGE.body] <BR><FONT SIZE=1>\[[MESSAGE.message_type] by <FONT COLOR='maroon'>[MESSAGE.author]</FONT>\]</FONT><BR>"
|
||||
// Creating Channels
|
||||
data["channel_name"] = channel_name
|
||||
data["c_locked"] = c_locked
|
||||
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[11]'>Back</A>"
|
||||
if(14)
|
||||
dat+="<B>Wanted Issue Handler:</B>"
|
||||
var/wanted_already = 0
|
||||
var/end_param = 1
|
||||
if(news_network.wanted_issue)
|
||||
wanted_already = 1
|
||||
end_param = 2
|
||||
// Creating Messages
|
||||
// data["channel_name"] = channel_name
|
||||
data["msg"] = msg
|
||||
data["photo_data"] = !!photo_data
|
||||
|
||||
if(wanted_already)
|
||||
dat+="<FONT SIZE=2><BR><I>A wanted issue is already in Feed Circulation. You can edit or cancel it below.</FONT></I>"
|
||||
dat+="<HR>"
|
||||
dat+="<A href='?src=\ref[src];set_wanted_name=1'>Criminal Name</A>: [channel_name] <BR>"
|
||||
dat+="<A href='?src=\ref[src];set_wanted_desc=1'>Description</A>: [msg] <BR>"
|
||||
dat+="<A href='?src=\ref[src];set_attachment=1'>Attach Photo</A>: [(photo_data ? "Photo Attached" : "No Photo")]</BR>"
|
||||
if(wanted_already)
|
||||
dat+="<B>Wanted Issue created by:</B><FONT COLOR='green'> [news_network.wanted_issue.backup_author]</FONT><BR>"
|
||||
else
|
||||
dat+="<B>Wanted Issue will be created under prosecutor:</B><FONT COLOR='green'> [scanned_user]</FONT><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];submit_wanted=[end_param]'>[(wanted_already) ? ("Edit Issue") : ("Submit")]</A>"
|
||||
if(wanted_already)
|
||||
dat+="<BR><A href='?src=\ref[src];cancel_wanted=1'>Take down Issue</A>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Cancel</A>"
|
||||
if(15)
|
||||
dat+="<FONT COLOR='green'>Wanted issue for [channel_name] is now in Network Circulation.</FONT><BR><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Return</A><BR>"
|
||||
if(16)
|
||||
dat+="<B><FONT COLOR='maroon'>ERROR: Wanted Issue rejected by Network.</B></FONT><HR><BR>"
|
||||
if(channel_name=="" || channel_name == "\[REDACTED\]")
|
||||
dat+="<FONT COLOR='maroon'>Invalid name for person wanted.</FONT><BR>"
|
||||
if(scanned_user=="Unknown")
|
||||
dat+="<FONT COLOR='maroon'>Issue author unverified.</FONT><BR>"
|
||||
if(msg == "" || msg == "\[REDACTED\]")
|
||||
dat+="<FONT COLOR='maroon'>Invalid description.</FONT><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Return</A><BR>"
|
||||
if(17)
|
||||
dat+="<B>Wanted Issue successfully deleted from Circulation</B><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Return</A><BR>"
|
||||
if(18)
|
||||
dat+="<B><FONT COLOR ='maroon'>-- STATIONWIDE WANTED ISSUE --</B></FONT><BR><FONT SIZE=2>\[Submitted by: <FONT COLOR='green'>[news_network.wanted_issue.backup_author]</FONT>\]</FONT><HR>"
|
||||
dat+="<B>Criminal</B>: [news_network.wanted_issue.author]<BR>"
|
||||
dat+="<B>Description</B>: [news_network.wanted_issue.body]<BR>"
|
||||
dat+="<B>Photo:</B>: "
|
||||
if(news_network.wanted_issue.img)
|
||||
usr << browse_rsc(news_network.wanted_issue.img, "tmp_photow.png")
|
||||
dat+="<BR><img src='tmp_photow.png' width = '180'>"
|
||||
else
|
||||
dat+="None"
|
||||
dat+="<BR><BR><A href='?src=\ref[src];setScreen=[0]'>Back</A><BR>"
|
||||
if(19)
|
||||
dat+="<FONT COLOR='green'>Wanted issue for [channel_name] successfully edited.</FONT><BR><BR>"
|
||||
dat+="<BR><A href='?src=\ref[src];setScreen=[0]'>Return</A><BR>"
|
||||
if(20)
|
||||
dat+="<FONT COLOR='green'>Printing successful. Please receive your newspaper from the bottom of the machine.</FONT><BR><BR>"
|
||||
dat+="<A href='?src=\ref[src];setScreen=[0]'>Return</A>"
|
||||
if(21)
|
||||
dat+="<FONT COLOR='maroon'>Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.</FONT><BR><BR>"
|
||||
dat+="<A href='?src=\ref[src];setScreen=[0]'>Return</A>"
|
||||
else
|
||||
dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com"
|
||||
// Printing menu
|
||||
var/total_num = LAZYLEN(news_network.network_channels)
|
||||
var/active_num = total_num
|
||||
var/message_num = 0
|
||||
for(var/datum/feed_channel/FC in news_network.network_channels)
|
||||
if(!FC.censored)
|
||||
message_num += length(FC.messages) //Dont forget, datum/feed_channel's var messages is a list of datum/feed_message
|
||||
else
|
||||
active_num--
|
||||
data["total_num"] = total_num
|
||||
data["active_num"] = active_num
|
||||
data["message_num"] = message_num
|
||||
data["paper_remaining"] = paper_remaining
|
||||
|
||||
// Viewing a specific channel
|
||||
var/list/viewing = null
|
||||
if(viewing_channel)
|
||||
var/list/messages = list()
|
||||
viewing = list(
|
||||
"name" = viewing_channel.channel_name,
|
||||
"author" = viewing_channel.author,
|
||||
"censored" = viewing_channel.censored,
|
||||
"messages" = messages,
|
||||
"ref" = REF(viewing_channel),
|
||||
)
|
||||
if(!viewing_channel.censored)
|
||||
for(var/datum/feed_message/M in viewing_channel.messages)
|
||||
var/list/msgdata = list(
|
||||
"body" = M.body,
|
||||
"img" = null,
|
||||
"type" = M.message_type,
|
||||
"caption" = null,
|
||||
"author" = M.author,
|
||||
"timestamp" = M.time_stamp,
|
||||
"ref" = REF(M),
|
||||
)
|
||||
if(M.img)
|
||||
msgdata["img"] = icon2base64(M.img)
|
||||
msgdata["caption"] = M.caption
|
||||
|
||||
human_or_robot_user << browse(dat, "window=newscaster_main;size=400x600")
|
||||
onclose(human_or_robot_user, "newscaster_main")
|
||||
messages.Add(list(msgdata))
|
||||
data["viewing_channel"] = viewing
|
||||
|
||||
/obj/machinery/newscaster/Topic(href, href_list)
|
||||
// Censorship
|
||||
data["company"] = using_map.company_name
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/newscaster/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return
|
||||
if((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.set_machine(src)
|
||||
if(href_list["set_channel_name"])
|
||||
channel_name = sanitizeSafe(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""), MAX_LNAME_LEN)
|
||||
updateUsrDialog()
|
||||
//update_icon()
|
||||
return TRUE
|
||||
|
||||
else if(href_list["set_channel_lock"])
|
||||
switch(action)
|
||||
if("cleartemp")
|
||||
temp = null
|
||||
return TRUE
|
||||
|
||||
if("set_channel_name")
|
||||
channel_name = sanitizeSafe(params["val"], MAX_LNAME_LEN)
|
||||
return TRUE
|
||||
|
||||
if("set_channel_lock")
|
||||
c_locked = !c_locked
|
||||
updateUsrDialog()
|
||||
//update_icon()
|
||||
return TRUE
|
||||
|
||||
else if(href_list["submit_new_channel"])
|
||||
if("submit_new_channel")
|
||||
//var/list/existing_channels = list() //OBSOLETE
|
||||
var/list/existing_authors = list()
|
||||
for(var/datum/feed_channel/FC in news_network.network_channels)
|
||||
@@ -533,121 +400,118 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
if(FC.channel_name == channel_name)
|
||||
check = 1
|
||||
break
|
||||
if(channel_name == "" || channel_name == "\[REDACTED\]" || scanned_user == "Unknown" || check || (scanned_user in existing_authors))
|
||||
screen=7
|
||||
else
|
||||
var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel")
|
||||
if(choice=="Confirm")
|
||||
news_network.CreateFeedChannel(channel_name, scanned_user, c_locked)
|
||||
screen=5
|
||||
updateUsrDialog()
|
||||
//update_icon()
|
||||
var/our_user = tgui_user_name(usr)
|
||||
if(channel_name == "" || channel_name == "\[REDACTED\]")
|
||||
set_temp("Error: Could not submit feed channel to network: Invalid Channel Name.", "danger", FALSE)
|
||||
return TRUE
|
||||
if(our_user == "Unknown")
|
||||
set_temp("Error: Could not submit feed channel to network: Channel author unverified.", "danger", FALSE)
|
||||
return TRUE
|
||||
if(check)
|
||||
set_temp("Error: Could not submit feed channel to network: Channel name already in use.", "danger", FALSE)
|
||||
return TRUE
|
||||
if(our_user in existing_authors)
|
||||
set_temp("Error: Could not submit feed channel to network: A feed channel already exists under your name.", "danger", FALSE)
|
||||
return TRUE
|
||||
|
||||
else if(href_list["set_channel_receiving"])
|
||||
var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel")
|
||||
if(choice == "Confirm")
|
||||
news_network.CreateFeedChannel(channel_name, our_user, c_locked)
|
||||
set_temp("Feed channel [channel_name] created successfully.", "success", FALSE)
|
||||
return TRUE
|
||||
|
||||
if("set_channel_receiving")
|
||||
//var/list/datum/feed_channel/available_channels = list()
|
||||
var/list/available_channels = list()
|
||||
for(var/datum/feed_channel/F in news_network.network_channels)
|
||||
if((!F.locked || F.author == scanned_user) && !F.censored)
|
||||
available_channels += F.channel_name
|
||||
channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels
|
||||
updateUsrDialog()
|
||||
var/new_channel_name = input(usr, "Choose receiving Feed Channel", "Network Channel Handler") as null|anything in available_channels
|
||||
if(new_channel_name)
|
||||
channel_name = new_channel_name
|
||||
return TRUE
|
||||
|
||||
else if(href_list["set_new_message"])
|
||||
msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", ""))
|
||||
updateUsrDialog()
|
||||
if("set_new_message")
|
||||
msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", "") as message|null)
|
||||
return TRUE
|
||||
|
||||
else if(href_list["set_attachment"])
|
||||
if("set_attachment")
|
||||
AttachPhoto(usr)
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
else if(href_list["submit_new_message"])
|
||||
if(msg =="" || msg=="\[REDACTED\]" || scanned_user == "Unknown" || channel_name == "")
|
||||
screen=6
|
||||
else
|
||||
var/image = photo_data ? photo_data.photo : null
|
||||
feedback_inc("newscaster_stories",1)
|
||||
news_network.SubmitArticle(msg, scanned_user, channel_name, image, 0)
|
||||
screen=4
|
||||
if("submit_new_message")
|
||||
var/our_user = tgui_user_name(usr)
|
||||
if(msg == "" || msg == "\[REDACTED\]")
|
||||
set_temp("Error: Could not submit feed message to network: Invalid Message.", "danger", FALSE)
|
||||
return TRUE
|
||||
if(our_user == "Unknown")
|
||||
set_temp("Error: Could not submit feed message to network: Channel author unverified.", "danger", FALSE)
|
||||
return TRUE
|
||||
if(channel_name == "")
|
||||
set_temp("Error: Could not submit feed message to network: No feed channel selected.", "danger", FALSE)
|
||||
return TRUE
|
||||
|
||||
updateUsrDialog()
|
||||
var/image = photo_data ? photo_data.photo : null
|
||||
feedback_inc("newscaster_stories",1)
|
||||
news_network.SubmitArticle(msg, our_user, channel_name, image, 0)
|
||||
set_temp("Feed message created successfully.", "success", FALSE)
|
||||
return TRUE
|
||||
|
||||
else if(href_list["create_channel"])
|
||||
screen=2
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["create_feed_story"])
|
||||
screen=3
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["menu_paper"])
|
||||
screen=8
|
||||
updateUsrDialog()
|
||||
else if(href_list["print_paper"])
|
||||
if("print_paper")
|
||||
if(!paper_remaining)
|
||||
screen=21
|
||||
else
|
||||
print_paper()
|
||||
screen = 20
|
||||
updateUsrDialog()
|
||||
set_temp("Unable to print newspaper. Insufficient paper. Please notify maintenance personnel to refill machine storage.", "danger", FALSE)
|
||||
return TRUE
|
||||
|
||||
print_paper()
|
||||
set_temp("Printing successful. Please receive your newspaper from the bottom of the machine.", "success", FALSE)
|
||||
return TRUE
|
||||
|
||||
else if(href_list["menu_censor_story"])
|
||||
screen=10
|
||||
updateUsrDialog()
|
||||
if("set_wanted_desc")
|
||||
msg = sanitize(params["val"])
|
||||
return TRUE
|
||||
|
||||
else if(href_list["menu_censor_channel"])
|
||||
screen=11
|
||||
updateUsrDialog()
|
||||
if("submit_wanted")
|
||||
if(!securityCaster)
|
||||
return FALSE
|
||||
var/our_user = tgui_user_name(usr)
|
||||
if(channel_name == "")
|
||||
set_temp("Error: Could not submit wanted issue to network: Invalid Criminal Name.", "danger", FALSE)
|
||||
return TRUE
|
||||
if(msg == "")
|
||||
set_temp("Error: Could not submit wanted issue to network: Invalid Description.", "danger", FALSE)
|
||||
return TRUE
|
||||
if(our_user == "Unknown")
|
||||
set_temp("Error: Could not submit wanted issue to network: Author unverified.", "danger", FALSE)
|
||||
return TRUE
|
||||
|
||||
else if(href_list["menu_wanted"])
|
||||
var/already_wanted = 0
|
||||
if(news_network.wanted_issue)
|
||||
already_wanted = 1
|
||||
var/choice = alert("Please confirm Wanted Issue change.", "Network Security Handler", "Confirm", "Cancel")
|
||||
if(choice == "Confirm")
|
||||
if(news_network.wanted_issue)
|
||||
if(news_network.wanted_issue.is_admin_message)
|
||||
alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot edit it.", "Ok")
|
||||
return
|
||||
news_network.wanted_issue.author = channel_name
|
||||
news_network.wanted_issue.body = msg
|
||||
news_network.wanted_issue.backup_author = scanned_user
|
||||
if(photo_data)
|
||||
news_network.wanted_issue.img = photo_data.photo.img
|
||||
set_temp("Wanted issue for [channel_name] successfully edited.", "success", FALSE)
|
||||
return TRUE
|
||||
|
||||
if(already_wanted)
|
||||
channel_name = news_network.wanted_issue.author
|
||||
msg = news_network.wanted_issue.body
|
||||
screen = 14
|
||||
updateUsrDialog()
|
||||
var/datum/feed_message/WANTED = new /datum/feed_message
|
||||
WANTED.author = channel_name
|
||||
WANTED.body = msg
|
||||
WANTED.backup_author = scanned_user //I know, a bit wacky
|
||||
if(photo_data)
|
||||
WANTED.img = photo_data.photo.img
|
||||
news_network.wanted_issue = WANTED
|
||||
news_network.alert_readers()
|
||||
set_temp("Wanted issue for [channel_name] is now in Network Circulation.", "success", FALSE)
|
||||
return TRUE
|
||||
|
||||
else if(href_list["set_wanted_name"])
|
||||
channel_name = sanitizeSafe(input(usr, "Provide the name of the Wanted person", "Network Security Handler", ""), MAX_LNAME_LEN)
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["set_wanted_desc"])
|
||||
msg = sanitize(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", ""))
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["submit_wanted"])
|
||||
var/input_param = text2num(href_list["submit_wanted"])
|
||||
if(msg == "" || channel_name == "" || scanned_user == "Unknown")
|
||||
screen = 16
|
||||
else
|
||||
var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel")
|
||||
if(choice=="Confirm")
|
||||
if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below
|
||||
var/datum/feed_message/WANTED = new /datum/feed_message
|
||||
WANTED.author = channel_name
|
||||
WANTED.body = msg
|
||||
WANTED.backup_author = scanned_user //I know, a bit wacky
|
||||
if(photo_data)
|
||||
WANTED.img = photo_data.photo.img
|
||||
news_network.wanted_issue = WANTED
|
||||
news_network.alert_readers()
|
||||
screen = 15
|
||||
else
|
||||
if(news_network.wanted_issue.is_admin_message)
|
||||
alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot edit it.","Ok")
|
||||
return
|
||||
news_network.wanted_issue.author = channel_name
|
||||
news_network.wanted_issue.body = msg
|
||||
news_network.wanted_issue.backup_author = scanned_user
|
||||
if(photo_data)
|
||||
news_network.wanted_issue.img = photo_data.photo.img
|
||||
screen = 19
|
||||
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["cancel_wanted"])
|
||||
if("cancel_wanted")
|
||||
if(!securityCaster)
|
||||
return FALSE
|
||||
if(news_network.wanted_issue.is_admin_message)
|
||||
alert("The wanted issue has been distributed by a [using_map.company_name] higherup. You cannot take it down.","Ok")
|
||||
return
|
||||
@@ -656,49 +520,52 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
news_network.wanted_issue = null
|
||||
for(var/obj/machinery/newscaster/NEWSCASTER in allCasters)
|
||||
NEWSCASTER.update_icon()
|
||||
screen=17
|
||||
updateUsrDialog()
|
||||
set_temp("Wanted issue taken down.", "success", FALSE)
|
||||
return TRUE
|
||||
|
||||
else if(href_list["view_wanted"])
|
||||
screen=18
|
||||
updateUsrDialog()
|
||||
else if(href_list["censor_channel_author"])
|
||||
var/datum/feed_channel/FC = locate(href_list["censor_channel_author"])
|
||||
if("censor_channel_author")
|
||||
if(!securityCaster)
|
||||
return FALSE
|
||||
var/datum/feed_channel/FC = locate(params["ref"])
|
||||
if(FC.is_admin_channel)
|
||||
alert("This channel was created by a [using_map.company_name] Officer. You cannot censor it.","Ok")
|
||||
return
|
||||
if(FC.author != "<B>\[REDACTED\]</B>")
|
||||
if(FC.author != "\[REDACTED\]")
|
||||
FC.backup_author = FC.author
|
||||
FC.author = "<B>\[REDACTED\]</B>"
|
||||
FC.author = "\[REDACTED\]"
|
||||
else
|
||||
FC.author = FC.backup_author
|
||||
FC.update()
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
else if(href_list["censor_channel_story_author"])
|
||||
var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"])
|
||||
if("censor_channel_story_author")
|
||||
if(!securityCaster)
|
||||
return FALSE
|
||||
var/datum/feed_message/MSG = locate(params["ref"])
|
||||
if(MSG.is_admin_message)
|
||||
alert("This message was created by a [using_map.company_name] Officer. You cannot censor its author.","Ok")
|
||||
return
|
||||
if(MSG.author != "<B>\[REDACTED\]</B>")
|
||||
if(MSG.author != "\[REDACTED\]")
|
||||
MSG.backup_author = MSG.author
|
||||
MSG.author = "<B>\[REDACTED\]</B>"
|
||||
MSG.author = "\[REDACTED\]"
|
||||
else
|
||||
MSG.author = MSG.backup_author
|
||||
MSG.parent_channel.update()
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
else if(href_list["censor_channel_story_body"])
|
||||
var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"])
|
||||
if("censor_channel_story_body")
|
||||
if(!securityCaster)
|
||||
return FALSE
|
||||
var/datum/feed_message/MSG = locate(params["ref"])
|
||||
if(MSG.is_admin_message)
|
||||
alert("This channel was created by a [using_map.company_name] Officer. You cannot censor it.","Ok")
|
||||
return
|
||||
if(MSG.body != "<B>\[REDACTED\]</B>")
|
||||
if(MSG.body != "\[REDACTED\]")
|
||||
MSG.backup_body = MSG.body
|
||||
MSG.backup_caption = MSG.caption
|
||||
MSG.backup_img = MSG.img
|
||||
MSG.body = "<B>\[REDACTED\]</B>"
|
||||
MSG.caption = "<B>\[REDACTED\]</B>"
|
||||
MSG.body = "\[REDACTED\]"
|
||||
MSG.caption = "\[REDACTED\]"
|
||||
MSG.img = null
|
||||
else
|
||||
MSG.body = MSG.backup_body
|
||||
@@ -706,60 +573,32 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
MSG.img = MSG.backup_img
|
||||
|
||||
MSG.parent_channel.update()
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
else if(href_list["pick_d_notice"])
|
||||
var/datum/feed_channel/FC = locate(href_list["pick_d_notice"])
|
||||
viewing_channel = FC
|
||||
screen=13
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["toggle_d_notice"])
|
||||
var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"])
|
||||
if("toggle_d_notice")
|
||||
if(!securityCaster)
|
||||
return FALSE
|
||||
var/datum/feed_channel/FC = locate(params["ref"])
|
||||
if(FC.is_admin_channel)
|
||||
alert("This channel was created by a [using_map.company_name] Officer. You cannot place a D-Notice upon it.","Ok")
|
||||
return
|
||||
FC.censored = !FC.censored
|
||||
FC.update()
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
else if(href_list["view"])
|
||||
screen=1
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["setScreen"]) //Brings us to the main menu and resets all fields~
|
||||
screen = text2num(href_list["setScreen"])
|
||||
if(screen == 0)
|
||||
scanned_user = "Unknown";
|
||||
msg = "";
|
||||
c_locked=0;
|
||||
channel_name="";
|
||||
viewing_channel = null
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["show_channel"])
|
||||
var/datum/feed_channel/FC = locate(href_list["show_channel"])
|
||||
if("show_channel")
|
||||
var/datum/feed_channel/FC = locate(params["show_channel"])
|
||||
viewing_channel = FC
|
||||
screen = 9
|
||||
updateUsrDialog()
|
||||
return TRUE
|
||||
|
||||
else if(href_list["pick_censor_channel"])
|
||||
var/datum/feed_channel/FC = locate(href_list["pick_censor_channel"])
|
||||
viewing_channel = FC
|
||||
screen = 12
|
||||
updateUsrDialog()
|
||||
|
||||
else if(href_list["refresh"])
|
||||
updateUsrDialog()
|
||||
|
||||
/obj/machinery/newscaster/attackby(I as obj, user as mob)
|
||||
/obj/machinery/newscaster/attackby(I as obj, user)
|
||||
if(computer_deconstruction_screwdriver(user, I))
|
||||
return
|
||||
else
|
||||
attack_hand(user)
|
||||
return
|
||||
|
||||
/obj/machinery/newscaster/attack_ai(mob/user as mob)
|
||||
/obj/machinery/newscaster/attack_ai(mob/user)
|
||||
return attack_hand(user) //or maybe it'll have some special functions? No idea.
|
||||
|
||||
/datum/news_photo
|
||||
@@ -770,7 +609,7 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
is_synth = synth
|
||||
photo = p
|
||||
|
||||
/obj/machinery/newscaster/proc/AttachPhoto(mob/user as mob)
|
||||
/obj/machinery/newscaster/proc/AttachPhoto(mob/user)
|
||||
if(photo_data)
|
||||
if(!photo_data.is_synth)
|
||||
photo_data.photo.loc = src.loc
|
||||
@@ -812,7 +651,7 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
|
||||
drop_sound = 'sound/items/drop/wrapper.ogg'
|
||||
pickup_sound = 'sound/items/pickup/wrapper.ogg'
|
||||
|
||||
obj/item/weapon/newspaper/attack_self(mob/user as mob)
|
||||
obj/item/weapon/newspaper/attack_self(mob/user)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
var/dat
|
||||
@@ -922,7 +761,7 @@ obj/item/weapon/newspaper/Topic(href, href_list)
|
||||
if(istype(src.loc, /mob))
|
||||
attack_self(src.loc)
|
||||
|
||||
obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user)
|
||||
if(istype(W, /obj/item/weapon/pen))
|
||||
if(scribble_page == curr_page)
|
||||
to_chat(user, "<FONT COLOR='blue'>There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?</FONT>")
|
||||
@@ -939,8 +778,20 @@ obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
return
|
||||
|
||||
////////////////////////////////////helper procs
|
||||
/obj/machinery/newscaster/proc/tgui_user_name(mob/user)
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
var/obj/item/weapon/card/id/I = H.GetIdCard()
|
||||
if(I)
|
||||
return GetNameAndAssignmentFromId(I)
|
||||
|
||||
/obj/machinery/newscaster/proc/scan_user(mob/living/user as mob)
|
||||
if(issilicon(user))
|
||||
var/mob/living/silicon/S = user
|
||||
return "[S.name] ([S.job])"
|
||||
|
||||
return "Unknown"
|
||||
|
||||
/obj/machinery/newscaster/proc/scan_user(mob/living/user)
|
||||
if(istype(user,/mob/living/carbon/human)) //User is a human
|
||||
var/mob/living/carbon/human/human_user = user
|
||||
var/obj/item/weapon/card/id/I = human_user.GetIdCard()
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
// I'm honestly pretty sure that short of stuffing five million things into this
|
||||
// there's absolutely no way it could ever have any performance impact
|
||||
// Given that all it does is set the color var
|
||||
// But just in case it's cursed in some arcane horrible way
|
||||
// I'm going to leave this limit here
|
||||
#define MAX_PROCESSING 10 // Arbitrary performance insurance
|
||||
|
||||
/obj/machinery/gear_painter
|
||||
name = "Color Mate"
|
||||
desc = "A machine to give your apparel a fresh new color! Recommended to use with white items for best results."
|
||||
@@ -29,9 +36,9 @@
|
||||
processing.Cut()
|
||||
return ..()
|
||||
|
||||
/obj/machinery/gear_painter/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(processing.len)
|
||||
to_chat(user, "<span class='warning'>The machine is already loaded.</span>")
|
||||
/obj/machinery/gear_painter/attackby(obj/item/W, mob/user)
|
||||
if(LAZYLEN(processing) >= MAX_PROCESSING)
|
||||
to_chat(user, "<span class='warning'>The machine is full.</span>")
|
||||
return
|
||||
if(default_deconstruction_screwdriver(user, W))
|
||||
return
|
||||
@@ -45,65 +52,65 @@
|
||||
user.drop_from_inventory(W)
|
||||
W.forceMove(src)
|
||||
processing |= W
|
||||
SStgui.update_uis(src)
|
||||
else
|
||||
..()
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/gear_painter/attack_hand(mob/user as mob)
|
||||
/obj/machinery/gear_painter/attack_hand(mob/user)
|
||||
if(..())
|
||||
return
|
||||
interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/gear_painter/interact(mob/user as mob)
|
||||
if(inoperable())
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = "<TITLE>Color Mate Control Panel</TITLE><BR>"
|
||||
if(!processing.len)
|
||||
dat += "No item inserted."
|
||||
else
|
||||
for(var/atom/movable/O in processing)
|
||||
dat += "Item inserted: [O]<HR>"
|
||||
dat += "<A href='?src=\ref[src];select=1'>Select new color.</A><BR>"
|
||||
dat += "Color: <font color='[activecolor]'>⚫</font>"
|
||||
dat += "<A href='?src=\ref[src];paint=1'>Apply new color.</A><BR><BR>"
|
||||
dat += "<A href='?src=\ref[src];clear=1'>Remove paintjob.</A><BR><BR>"
|
||||
dat += "<A href='?src=\ref[src];eject=1'>Eject item.</A><BR><BR>"
|
||||
/obj/machinery/gear_painter/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "ColorMate", name)
|
||||
ui.open()
|
||||
|
||||
var/datum/browser/menu = new(user, "colormate","Color Mate Control Panel", 400, 600, src)
|
||||
menu.set_content(dat)
|
||||
menu.open()
|
||||
return
|
||||
/obj/machinery/gear_painter/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
/obj/machinery/gear_painter/Topic(href, href_list)
|
||||
var/list/items = list()
|
||||
for(var/atom/movable/O in processing)
|
||||
items.Add("[O]")
|
||||
data["items"] = items
|
||||
|
||||
data["activecolor"] = activecolor
|
||||
return data
|
||||
|
||||
/obj/machinery/gear_painter/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return
|
||||
return TRUE
|
||||
|
||||
usr.set_machine(src)
|
||||
add_fingerprint(usr)
|
||||
|
||||
if(href_list["close"])
|
||||
return
|
||||
switch(action)
|
||||
if("select")
|
||||
var/newcolor = input(usr, "Choose a color.", "", activecolor) as color|null
|
||||
if(newcolor)
|
||||
activecolor = newcolor
|
||||
. = TRUE
|
||||
|
||||
if(href_list["select"])
|
||||
var/newcolor = input(usr, "Choose a color.", "", activecolor) as color|null
|
||||
if(newcolor)
|
||||
activecolor = newcolor
|
||||
if("paint")
|
||||
for(var/atom/movable/O in processing)
|
||||
O.color = activecolor
|
||||
CHECK_TICK
|
||||
playsound(src, 'sound/effects/spray3.ogg', 50, 1)
|
||||
. = TRUE
|
||||
|
||||
if(href_list["paint"])
|
||||
for(var/atom/movable/O in processing)
|
||||
O.color = activecolor
|
||||
playsound(src, 'sound/effects/spray3.ogg', 50, 1)
|
||||
if("clear")
|
||||
for(var/atom/movable/O in processing)
|
||||
O.color = initial(O.color)
|
||||
CHECK_TICK
|
||||
playsound(src, 'sound/effects/spray3.ogg', 50, 1)
|
||||
. = TRUE
|
||||
|
||||
if(href_list["clear"])
|
||||
for(var/atom/movable/O in processing)
|
||||
O.color = initial(O.color)
|
||||
playsound(src, 'sound/effects/spray3.ogg', 50, 1)
|
||||
|
||||
if(href_list["eject"])
|
||||
for(var/atom/movable/O in processing)
|
||||
O.forceMove(drop_location())
|
||||
processing.Cut()
|
||||
if("eject")
|
||||
for(var/atom/movable/O in processing)
|
||||
O.forceMove(drop_location())
|
||||
CHECK_TICK
|
||||
processing.Cut()
|
||||
. = TRUE
|
||||
|
||||
update_icon()
|
||||
updateUsrDialog()
|
||||
|
||||
@@ -26,9 +26,6 @@
|
||||
var/vend_delay = 10 //How long does it take to vend?
|
||||
var/categories = CAT_NORMAL // Bitmask of cats we're currently showing
|
||||
var/datum/stored_item/vending_product/currently_vending = null // What we're requesting payment for right now
|
||||
var/tmp/actively_vending = null // Used to allow TGUI to display normal items in-progress being vended
|
||||
var/status_message = "" // Status screen messages like "insufficient funds", displayed in NanoUI
|
||||
var/status_error = 0 // Set to 1 if status_message is an error
|
||||
var/vending_sound = "machines/vending/vending_drop.ogg"
|
||||
|
||||
/*
|
||||
@@ -91,6 +88,7 @@
|
||||
build_inventory()
|
||||
power_change()
|
||||
|
||||
GLOBAL_LIST_EMPTY(vending_products)
|
||||
/**
|
||||
* Build produdct_records from the products lists
|
||||
*
|
||||
@@ -115,6 +113,7 @@
|
||||
product.category = category
|
||||
|
||||
product_records.Add(product)
|
||||
GLOB.vending_products[entry] = 1
|
||||
|
||||
/obj/machinery/vending/Destroy()
|
||||
qdel(wires)
|
||||
@@ -151,32 +150,8 @@
|
||||
return 1
|
||||
|
||||
/obj/machinery/vending/attackby(obj/item/weapon/W as obj, mob/user as mob)
|
||||
|
||||
var/obj/item/weapon/card/id/I = W.GetID()
|
||||
|
||||
if(currently_vending && vendor_account && !vendor_account.suspended)
|
||||
var/paid = 0
|
||||
var/handled = 0
|
||||
|
||||
if(I) //for IDs and PDAs and wallets with IDs
|
||||
paid = pay_with_card(I,W)
|
||||
handled = 1
|
||||
else if(istype(W, /obj/item/weapon/spacecash/ewallet))
|
||||
var/obj/item/weapon/spacecash/ewallet/C = W
|
||||
paid = pay_with_ewallet(C)
|
||||
handled = 1
|
||||
else if(istype(W, /obj/item/weapon/spacecash))
|
||||
var/obj/item/weapon/spacecash/C = W
|
||||
paid = pay_with_cash(C, user)
|
||||
handled = 1
|
||||
|
||||
if(paid)
|
||||
vend(currently_vending, usr)
|
||||
return
|
||||
else if(handled)
|
||||
SStgui.update_uis(src)
|
||||
return // don't smack that machine with your 2 thalers
|
||||
|
||||
if(I || istype(W, /obj/item/weapon/spacecash))
|
||||
attack_hand(user)
|
||||
return
|
||||
@@ -262,8 +237,7 @@
|
||||
visible_message("<span class='info'>\The [usr] swipes \the [wallet] through \the [src].</span>")
|
||||
playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
|
||||
if(currently_vending.price > wallet.worth)
|
||||
status_message = "Insufficient funds on chargecard."
|
||||
status_error = 1
|
||||
to_chat(usr, "<span class='warning'>Insufficient funds on chargecard.</span>")
|
||||
return 0
|
||||
else
|
||||
wallet.worth -= currently_vending.price
|
||||
@@ -276,22 +250,18 @@
|
||||
* Takes payment for whatever is the currently_vending item. Returns 1 if
|
||||
* successful, 0 if failed
|
||||
*/
|
||||
/obj/machinery/vending/proc/pay_with_card(var/obj/item/weapon/card/id/I, var/obj/item/ID_container)
|
||||
if(I==ID_container || ID_container == null)
|
||||
visible_message("<span class='info'>\The [usr] swipes \the [I] through \the [src].</span>")
|
||||
else
|
||||
visible_message("<span class='info'>\The [usr] swipes \the [ID_container] through \the [src].</span>")
|
||||
/obj/machinery/vending/proc/pay_with_card(obj/item/weapon/card/id/I, mob/M)
|
||||
visible_message("<span class='info'>[M] swipes a card through [src].</span>")
|
||||
playsound(src, 'sound/machines/id_swipe.ogg', 50, 1)
|
||||
|
||||
var/datum/money_account/customer_account = get_account(I.associated_account_number)
|
||||
if(!customer_account)
|
||||
status_message = "Error: Unable to access account. Please contact technical support if problem persists."
|
||||
status_error = 1
|
||||
return 0
|
||||
to_chat(M, "<span class='warning'>Error: Unable to access account. Please contact technical support if problem persists.</span>")
|
||||
return FALSE
|
||||
|
||||
if(customer_account.suspended)
|
||||
status_message = "Unable to access account: account suspended."
|
||||
status_error = 1
|
||||
return 0
|
||||
to_chat(M, "<span class='warning'>Unable to access account: account suspended.</span>")
|
||||
return FALSE
|
||||
|
||||
// Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is
|
||||
// empty at high security levels
|
||||
@@ -300,38 +270,36 @@
|
||||
customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2)
|
||||
|
||||
if(!customer_account)
|
||||
status_message = "Unable to access account: incorrect credentials."
|
||||
status_error = 1
|
||||
return 0
|
||||
to_chat(M, "<span class='warning'>Unable to access account: incorrect credentials.</span>")
|
||||
return FALSE
|
||||
|
||||
if(currently_vending.price > customer_account.money)
|
||||
status_message = "Insufficient funds in account."
|
||||
status_error = 1
|
||||
return 0
|
||||
to_chat(M, "<span class='warning'>Insufficient funds in account.</span>")
|
||||
return FALSE
|
||||
|
||||
// Okay to move the money at this point
|
||||
|
||||
// debit money from the purchaser's account
|
||||
customer_account.money -= currently_vending.price
|
||||
|
||||
// create entry in the purchaser's account log
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = "[vendor_account.owner_name] (via [name])"
|
||||
T.purpose = "Purchase of [currently_vending.item_name]"
|
||||
if(currently_vending.price > 0)
|
||||
T.amount = "([currently_vending.price])"
|
||||
else
|
||||
// Okay to move the money at this point
|
||||
T.amount = "[currently_vending.price]"
|
||||
T.source_terminal = name
|
||||
T.date = current_date_string
|
||||
T.time = stationtime2text()
|
||||
customer_account.transaction_log.Add(T)
|
||||
|
||||
// debit money from the purchaser's account
|
||||
customer_account.money -= currently_vending.price
|
||||
|
||||
// create entry in the purchaser's account log
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = "[vendor_account.owner_name] (via [name])"
|
||||
T.purpose = "Purchase of [currently_vending.item_name]"
|
||||
if(currently_vending.price > 0)
|
||||
T.amount = "([currently_vending.price])"
|
||||
else
|
||||
T.amount = "[currently_vending.price]"
|
||||
T.source_terminal = name
|
||||
T.date = current_date_string
|
||||
T.time = stationtime2text()
|
||||
customer_account.transaction_log.Add(T)
|
||||
|
||||
// Give the vendor the money. We use the account owner name, which means
|
||||
// that purchases made with stolen/borrowed card will look like the card
|
||||
// owner made them
|
||||
credit_purchase(customer_account.owner_name)
|
||||
return 1
|
||||
// Give the vendor the money. We use the account owner name, which means
|
||||
// that purchases made with stolen/borrowed card will look like the card
|
||||
// owner made them
|
||||
credit_purchase(customer_account.owner_name)
|
||||
return 1
|
||||
|
||||
/**
|
||||
* Add money for current purchase to the vendor account.
|
||||
@@ -367,6 +335,11 @@
|
||||
wires.Interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/vending/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/spritesheet/vending),
|
||||
)
|
||||
|
||||
/obj/machinery/vending/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
@@ -375,39 +348,34 @@
|
||||
|
||||
/obj/machinery/vending/tgui_data(mob/user)
|
||||
var/list/data = list()
|
||||
if(currently_vending)
|
||||
data["mode"] = 1
|
||||
data["product"] = currently_vending.item_name
|
||||
data["price"] = currently_vending.price
|
||||
data["message"] = status_message
|
||||
data["message_err"] = status_error
|
||||
data["products"] = null
|
||||
else
|
||||
data["mode"] = 0
|
||||
var/list/listed_products = list()
|
||||
var/list/listed_products = list()
|
||||
|
||||
for(var/key = 1 to product_records.len)
|
||||
var/datum/stored_item/vending_product/I = product_records[key]
|
||||
data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE
|
||||
for(var/key = 1 to product_records.len)
|
||||
var/datum/stored_item/vending_product/I = product_records[key]
|
||||
|
||||
if(!(I.category & categories))
|
||||
continue
|
||||
if(!(I.category & categories))
|
||||
continue
|
||||
|
||||
listed_products.Add(list(list(
|
||||
"key" = key,
|
||||
"name" = I.item_name,
|
||||
"price" = I.price,
|
||||
"color" = I.display_color,
|
||||
"amount" = I.get_amount())))
|
||||
listed_products.Add(list(list(
|
||||
"key" = key,
|
||||
"name" = I.item_name,
|
||||
"price" = I.price,
|
||||
"color" = I.display_color,
|
||||
"isatom" = ispath(I.item_path, /atom),
|
||||
"path" = replacetext(replacetext("[I.item_path]", "/obj/item/", ""), "/", "-"),
|
||||
"amount" = I.get_amount()
|
||||
)))
|
||||
|
||||
data["products"] = listed_products
|
||||
data["products"] = listed_products
|
||||
|
||||
if(coin)
|
||||
data["coin"] = coin.name
|
||||
else
|
||||
data["coin"] = FALSE
|
||||
|
||||
if(actively_vending)
|
||||
data["actively_vending"] = actively_vending
|
||||
if(currently_vending)
|
||||
data["actively_vending"] = currently_vending.item_name
|
||||
else
|
||||
data["actively_vending"] = null
|
||||
|
||||
@@ -417,6 +385,29 @@
|
||||
else
|
||||
data["panel"] = 0
|
||||
|
||||
var/mob/living/carbon/human/H
|
||||
var/obj/item/weapon/card/id/C
|
||||
|
||||
data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash.";
|
||||
data["userMoney"] = 0
|
||||
data["user"] = null
|
||||
if(ishuman(user))
|
||||
H = user
|
||||
C = H.GetIdCard()
|
||||
var/obj/item/weapon/spacecash/S = H.get_active_hand()
|
||||
if(istype(S))
|
||||
data["userMoney"] = S.worth
|
||||
data["guestNotice"] = "Accepting [S.initial_name]. You have: [S.worth]₮."
|
||||
else if(istype(C))
|
||||
var/datum/money_account/A = get_account(C.associated_account_number)
|
||||
if(istype(A))
|
||||
data["user"] = list()
|
||||
data["user"]["name"] = A.owner_name
|
||||
data["userMoney"] = A.money
|
||||
data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job"
|
||||
else
|
||||
data["guestNotice"] = "Unlinked ID detected. Present cash to pay.";
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/vending/tgui_act(action, params)
|
||||
@@ -427,36 +418,36 @@
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if(action == "remove_coin")
|
||||
if(issilicon(usr))
|
||||
return FALSE
|
||||
|
||||
if(!coin)
|
||||
to_chat(usr, "There is no coin in this machine.")
|
||||
return
|
||||
|
||||
coin.forceMove(src.loc)
|
||||
if(!usr.get_active_hand())
|
||||
usr.put_in_hands(coin)
|
||||
|
||||
to_chat(usr, "<span class='notice'>You remove \the [coin] from \the [src].</span>")
|
||||
coin = null
|
||||
categories &= ~CAT_COIN
|
||||
return TRUE
|
||||
|
||||
if(!usr.contents.Find(src) && (!in_range(src, usr) && isturf(loc)))
|
||||
return FALSE
|
||||
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("remove_coin")
|
||||
if(issilicon(usr))
|
||||
return FALSE
|
||||
|
||||
if(!coin)
|
||||
to_chat(usr, "There is no coin in this machine.")
|
||||
return
|
||||
|
||||
coin.forceMove(src.loc)
|
||||
if(!usr.get_active_hand())
|
||||
usr.put_in_hands(coin)
|
||||
|
||||
to_chat(usr, "<span class='notice'>You remove \the [coin] from \the [src].</span>")
|
||||
coin = null
|
||||
categories &= ~CAT_COIN
|
||||
return TRUE
|
||||
if("vend")
|
||||
if(!vend_ready || currently_vending)
|
||||
if(!vend_ready)
|
||||
to_chat(usr, "<span class='warning'>[src] is busy!</span>")
|
||||
return
|
||||
if(!allowed(usr) && !emagged && scan_id)
|
||||
to_chat(usr, "<span class='warning'>Access denied.</span>") //Unless emagged of course
|
||||
flick("[icon_state]-deny",src)
|
||||
playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
|
||||
return
|
||||
if(panel_open)
|
||||
to_chat(usr, "<span class='warning'>[src] cannot dispense products while its service panel is open!</span>")
|
||||
return
|
||||
|
||||
var/key = text2num(params["vend"])
|
||||
var/datum/stored_item/vending_product/R = product_records[key]
|
||||
@@ -464,39 +455,83 @@
|
||||
// This should not happen unless the request from NanoUI was bad
|
||||
if(!(R.category & categories))
|
||||
return
|
||||
|
||||
if(!can_buy(R, usr))
|
||||
return
|
||||
|
||||
vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved.
|
||||
|
||||
if(R.price <= 0)
|
||||
vend(R, usr)
|
||||
else if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something.
|
||||
add_fingerprint(usr)
|
||||
vend_ready = TRUE
|
||||
return TRUE
|
||||
|
||||
if(issilicon(usr)) //If the item is not free, provide feedback if a synth is trying to buy something.
|
||||
to_chat(usr, "<span class='danger'>Lawed unit recognized. Lawed units cannot complete this transaction. Purchase canceled.</span>")
|
||||
return
|
||||
else
|
||||
currently_vending = R
|
||||
if(!vendor_account || vendor_account.suspended)
|
||||
status_message = "This machine is currently unable to process payments due to issues with the associated account."
|
||||
status_error = 1
|
||||
else
|
||||
status_message = "Please swipe a card or insert cash to pay for the item."
|
||||
status_error = 0
|
||||
if(!ishuman(usr))
|
||||
return
|
||||
|
||||
if("cancelpurchase")
|
||||
currently_vending = null
|
||||
var/mob/living/carbon/human/H = usr
|
||||
var/obj/item/weapon/card/id/C = H.GetIdCard()
|
||||
|
||||
if(!vendor_account || vendor_account.suspended)
|
||||
to_chat(usr, "Vendor account offline. Unable to process transaction.")
|
||||
flick("[icon_state]-deny",src)
|
||||
vend_ready = TRUE
|
||||
return
|
||||
|
||||
currently_vending = R
|
||||
|
||||
var/paid = FALSE
|
||||
|
||||
if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash))
|
||||
var/obj/item/weapon/spacecash/cash = usr.get_active_hand()
|
||||
paid = pay_with_cash(cash, usr)
|
||||
else if(istype(usr.get_active_hand(), /obj/item/weapon/spacecash/ewallet))
|
||||
var/obj/item/weapon/spacecash/ewallet/wallet = usr.get_active_hand()
|
||||
paid = pay_with_ewallet(wallet)
|
||||
else if(istype(C, /obj/item/weapon/card))
|
||||
paid = pay_with_card(C, usr)
|
||||
/*else if(usr.can_advanced_admin_interact())
|
||||
to_chat(usr, "<span class='notice'>Vending object due to admin interaction.</span>")
|
||||
paid = TRUE*/
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Payment failure: you have no ID or other method of payment.")
|
||||
vend_ready = TRUE
|
||||
flick("[icon_state]-deny",src)
|
||||
return TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update.
|
||||
if(paid)
|
||||
vend(currently_vending, usr) // vend will handle vend_ready
|
||||
. = TRUE
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Payment failure: unable to process payment.")
|
||||
vend_ready = TRUE
|
||||
|
||||
if("togglevoice")
|
||||
if(!panel_open)
|
||||
return FALSE
|
||||
shut_up = !shut_up
|
||||
|
||||
/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user)
|
||||
if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
|
||||
to_chat(usr, "<span class='warning'>Access denied.</span>") //Unless emagged of course
|
||||
/obj/machinery/vending/proc/can_buy(datum/stored_item/vending_product/R, mob/user)
|
||||
if(!allowed(user) && !emagged && scan_id)
|
||||
to_chat(user, "<span class='warning'>Access denied.</span>") //Unless emagged of course
|
||||
flick("[icon_state]-deny",src)
|
||||
playsound(src, 'sound/machines/deniedbeep.ogg', 50, 0)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/vending/proc/vend(datum/stored_item/vending_product/R, mob/user)
|
||||
if(!can_buy(R, user))
|
||||
return
|
||||
vend_ready = 0 //One thing at a time!!
|
||||
actively_vending = R.item_name
|
||||
status_message = "Vending..."
|
||||
status_error = 0
|
||||
|
||||
if(!R.amount)
|
||||
to_chat(user, "<span class='warning'>[src] has ran out of that product.</span>")
|
||||
vend_ready = TRUE
|
||||
return
|
||||
|
||||
vend_ready = FALSE //One thing at a time!!
|
||||
SStgui.update_uis(src)
|
||||
|
||||
if(R.category & CAT_COIN)
|
||||
@@ -523,24 +558,22 @@
|
||||
|
||||
use_power(vend_power_usage) //actuators and stuff
|
||||
flick("[icon_state]-vend",src)
|
||||
spawn(vend_delay)
|
||||
R.get_product(get_turf(src))
|
||||
if(has_logs)
|
||||
do_logging(R, user, 1)
|
||||
if(prob(1))
|
||||
sleep(3)
|
||||
if(R.get_product(get_turf(src)))
|
||||
visible_message("<span class='notice'>\The [src] clunks as it vends an additional item.</span>")
|
||||
playsound(src, "sound/[vending_sound]", 100, 1, 1)
|
||||
addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay)
|
||||
|
||||
status_message = ""
|
||||
status_error = 0
|
||||
vend_ready = 1
|
||||
actively_vending = null
|
||||
currently_vending = null
|
||||
SStgui.update_uis(src)
|
||||
/obj/machinery/vending/proc/delayed_vend(datum/stored_item/vending_product/R, mob/user)
|
||||
R.get_product(get_turf(src))
|
||||
if(has_logs)
|
||||
do_logging(R, user, 1)
|
||||
if(prob(1))
|
||||
sleep(3)
|
||||
if(R.get_product(get_turf(src)))
|
||||
visible_message("<span class='notice'>\The [src] clunks as it vends an additional item.</span>")
|
||||
playsound(src, "sound/[vending_sound]", 100, 1, 1)
|
||||
|
||||
vend_ready = 1
|
||||
currently_vending = null
|
||||
SStgui.update_uis(src)
|
||||
|
||||
return 1
|
||||
|
||||
/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0)
|
||||
if(user.GetIdCard())
|
||||
|
||||
@@ -535,6 +535,7 @@
|
||||
product.category = category
|
||||
|
||||
product_records.Add(product)
|
||||
GLOB.vending_products[entry] = 1
|
||||
|
||||
/obj/machinery/vending/magivend
|
||||
name = "MagiVend"
|
||||
|
||||
@@ -1,3 +1,24 @@
|
||||
GLOBAL_LIST_INIT(biblenames, list(
|
||||
"Bible", "Koran", "Scrapbook",
|
||||
"Pagan", "White Bible", "Holy Light",
|
||||
"Athiest", "Tome", "The King in Yellow",
|
||||
"Ithaqua", "Scientology", "the bible melts",
|
||||
"Necronomicon", "Orthodox", "Torah"))
|
||||
//If you get these two lists not matching in size, there will be runtimes and I will hurt you in ways you couldn't even begin to imagine
|
||||
// if your bible has no custom itemstate, use one of the existing ones
|
||||
GLOBAL_LIST_INIT(biblestates, list(
|
||||
"bible", "koran", "scrapbook",
|
||||
"shadows", "white", "holylight",
|
||||
"athiest", "tome", "kingyellow",
|
||||
"ithaqua", "scientology", "melted",
|
||||
"necronomicon", "orthodoxy", "torah"))
|
||||
GLOBAL_LIST_INIT(bibleitemstates, list(
|
||||
"bible", "koran", "scrapbook",
|
||||
"syringe_kit", "syringe_kit", "syringe_kit",
|
||||
"syringe_kit", "syringe_kit", "kingyellow",
|
||||
"ithaqua", "scientology", "melted",
|
||||
"necronomicon", "bible", "clipboard"))
|
||||
|
||||
/obj/item/weapon/storage/bible
|
||||
name = "bible"
|
||||
desc = "Apply to head repeatedly."
|
||||
@@ -15,6 +36,51 @@
|
||||
use_sound = 'sound/bureaucracy/bookopen.ogg'
|
||||
drop_sound = 'sound/bureaucracy/bookclose.ogg'
|
||||
|
||||
/obj/item/weapon/storage/bible/attack_self(mob/living/carbon/human/user)
|
||||
if(GLOB.bible_icon_state)
|
||||
icon_state = GLOB.bible_icon_state
|
||||
item_state = GLOB.bible_item_state
|
||||
return FALSE
|
||||
if(user?.mind?.assigned_role != "Chaplain")
|
||||
return FALSE
|
||||
|
||||
var/list/skins = list()
|
||||
for(var/i in 1 to GLOB.biblestates.len)
|
||||
var/image/bible_image = image(icon = 'icons/obj/storage.dmi', icon_state = GLOB.biblestates[i])
|
||||
skins += list("[GLOB.biblenames[i]]" = bible_image)
|
||||
|
||||
var/choice = show_radial_menu(user, src, skins, custom_check = CALLBACK(src, .proc/check_menu, user), radius = 40, require_near = TRUE)
|
||||
if(!choice)
|
||||
return FALSE
|
||||
var/bible_index = GLOB.biblenames.Find(choice)
|
||||
if(!bible_index)
|
||||
return FALSE
|
||||
icon_state = GLOB.biblestates[bible_index]
|
||||
item_state = GLOB.bibleitemstates[bible_index]
|
||||
|
||||
GLOB.bible_icon_state = icon_state
|
||||
GLOB.bible_item_state = item_state
|
||||
feedback_set_details("religion_book", "[choice]")
|
||||
|
||||
/**
|
||||
* Checks if we are allowed to interact with a radial menu
|
||||
*
|
||||
* Arguments:
|
||||
* * user The mob interacting with the menu
|
||||
*/
|
||||
/obj/item/weapon/storage/bible/proc/check_menu(mob/living/carbon/human/user)
|
||||
if(GLOB.bible_icon_state)
|
||||
return FALSE
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.get_active_hand() != src)
|
||||
return FALSE
|
||||
if(user.incapacitated())
|
||||
return FALSE
|
||||
if(user.mind.assigned_role != "Chaplain")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/weapon/storage/bible/booze
|
||||
name = "bible"
|
||||
desc = "To be applied to the head repeatedly."
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
/obj/item/weapon/storage/briefcase/clutch
|
||||
name = "clutch purse"
|
||||
desc = "A fashionable handheld bag typically used by women."
|
||||
icon = 'icons/obj/clothing/backpack.dmi' //VOREStation Edit - Wrong sprite location
|
||||
icon_state = "clutch"
|
||||
item_state_slots = list(slot_r_hand_str = "smpurse", slot_l_hand_str = "smpurse")
|
||||
force = 0
|
||||
|
||||
@@ -355,39 +355,56 @@
|
||||
// Insert(initial(D.id), I)
|
||||
// return ..()
|
||||
|
||||
// /datum/asset/spritesheet/vending
|
||||
// name = "vending"
|
||||
/datum/asset/spritesheet/vending
|
||||
name = "vending"
|
||||
|
||||
// /datum/asset/spritesheet/vending/register()
|
||||
// for (var/k in GLOB.vending_products)
|
||||
// var/atom/item = k
|
||||
// if (!ispath(item, /atom))
|
||||
// continue
|
||||
/datum/asset/spritesheet/vending/register()
|
||||
for(var/k in GLOB.vending_products)
|
||||
var/atom/item = k
|
||||
if(!ispath(item, /atom))
|
||||
continue
|
||||
|
||||
// var/icon_file = initial(item.icon)
|
||||
// var/icon_state = initial(item.icon_state)
|
||||
// var/icon/I
|
||||
var/icon_file = initial(item.icon)
|
||||
var/icon_state = initial(item.icon_state)
|
||||
|
||||
// var/icon_states_list = icon_states(icon_file)
|
||||
// if(icon_state in icon_states_list)
|
||||
// I = icon(icon_file, icon_state, SOUTH)
|
||||
// var/c = initial(item.color)
|
||||
// if (!isnull(c) && c != "#FFFFFF")
|
||||
// I.Blend(c, ICON_MULTIPLY)
|
||||
// else
|
||||
// var/icon_states_string
|
||||
// for (var/an_icon_state in icon_states_list)
|
||||
// if (!icon_states_string)
|
||||
// icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
// else
|
||||
// icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
// stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
|
||||
// I = icon('icons/turf/floors.dmi', "", SOUTH)
|
||||
// I really don't like the fact that I have to do this, but what the hell else *can* I do to make all of these
|
||||
// random special items work?
|
||||
if(ispath(item, /obj/item/weapon/reagent_containers/food/drinks/glass2) && !ispath(item, /obj/item/weapon/reagent_containers/food/drinks/glass2/fitnessflask))
|
||||
var/obj/item/weapon/reagent_containers/food/drinks/glass2/G = item
|
||||
icon_state = initial(G.base_icon)
|
||||
if(ispath(item, /obj/item/clothing/suit))
|
||||
var/obj/item/clothing/suit/U = item
|
||||
if(initial(U.index))
|
||||
icon_file = "icons/obj/clothing/suits_[initial(U.index)].dmi"
|
||||
if(ispath(item, /obj/item/clothing/under))
|
||||
var/obj/item/clothing/under/U = item
|
||||
if(initial(U.index))
|
||||
icon_file = "icons/obj/clothing/uniforms_[initial(U.index)].dmi"
|
||||
if(ispath(item, /obj/item/weapon/reagent_containers/hypospray/autoinjector))
|
||||
icon_state += "0"
|
||||
|
||||
// var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
|
||||
var/icon/I
|
||||
|
||||
// Insert(imgid, I)
|
||||
// return ..()
|
||||
var/icon_states_list = icon_states(icon_file)
|
||||
if(icon_state in icon_states_list)
|
||||
I = icon(icon_file, icon_state, SOUTH)
|
||||
var/c = initial(item.color)
|
||||
if(!isnull(c) && c != "#FFFFFF")
|
||||
I.Blend(c, ICON_MULTIPLY)
|
||||
else
|
||||
var/icon_states_string
|
||||
for(var/an_icon_state in icon_states_list)
|
||||
if(!icon_states_string)
|
||||
icon_states_string = "[json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
else
|
||||
icon_states_string += ", [json_encode(an_icon_state)](\ref[an_icon_state])"
|
||||
stack_trace("[item] does not have a valid icon state, icon=[icon_file], icon_state=[json_encode(icon_state)](\ref[icon_state]), icon_states=[icon_states_string]")
|
||||
I = icon('icons/turf/floors.dmi', "", SOUTH)
|
||||
|
||||
var/imgid = replacetext(replacetext("[item]", "/obj/item/", ""), "/", "-")
|
||||
|
||||
Insert(imgid, I)
|
||||
return ..()
|
||||
|
||||
// /datum/asset/simple/genetics
|
||||
// assets = list(
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
slot_flags = SLOT_TIE | SLOT_OCLOTHING
|
||||
icon = 'icons/obj/clothing/ties_vr.dmi'
|
||||
icon_override = 'icons/mob/ties_vr.dmi'
|
||||
icon_state = "collar_blk"
|
||||
var/writtenon = 0
|
||||
|
||||
/obj/item/clothing/accessory/collar/silver
|
||||
|
||||
@@ -1027,7 +1027,7 @@ Uniforms and such
|
||||
desc = "Made from a space-proof fibre and tight fitting, this uniform usually gives the agile Rangers all kinds of protection while not inhibiting their movement. \
|
||||
This costume is instead made from genuine cotton fibre and is based on the season three uniform."
|
||||
icon = 'icons/obj/clothing/ranger.dmi'
|
||||
icon_state = "ranger_uniform"
|
||||
icon_state = "white_ranger_uniform"
|
||||
rolled_down = 0
|
||||
rolled_sleeves = 0
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
|
||||
/obj/item/clothing/under/shorts/jeans/grey
|
||||
name = "grey jeans shorts"
|
||||
icon_state = "greypants_shorts"
|
||||
icon_state = "greyshorts"
|
||||
|
||||
/obj/item/clothing/under/shorts/jeans/grey/female
|
||||
name = "grey jeans short shorts"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/obj/item/weapon/spacecash
|
||||
name = "0 Thaler"
|
||||
var/initial_name = "Thaler"
|
||||
desc = "It's worth 0 Thalers."
|
||||
gender = PLURAL
|
||||
icon = 'icons/obj/items.dmi'
|
||||
@@ -31,15 +32,15 @@
|
||||
h_user.drop_from_inventory(src)
|
||||
h_user.drop_from_inventory(SC)
|
||||
h_user.put_in_hands(SC)
|
||||
to_chat(user, "<span class='notice'>You combine the Thalers to a bundle of [SC.worth] Thalers.</span>")
|
||||
to_chat(user, "<span class='notice'>You combine the [initial_name]s to a bundle of [SC.worth] [initial_name]s.</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/weapon/spacecash/update_icon()
|
||||
overlays.Cut()
|
||||
name = "[worth] Thaler\s"
|
||||
name = "[worth] [initial_name]\s"
|
||||
if(worth in list(1000,500,200,100,50,20,10,1))
|
||||
icon_state = "spacecash[worth]"
|
||||
desc = "It's worth [worth] Thalers."
|
||||
desc = "It's worth [worth] [initial_name]s."
|
||||
return
|
||||
var/sum = src.worth
|
||||
var/num = 0
|
||||
@@ -60,7 +61,7 @@
|
||||
M.Turn(pick(-45, -27.5, 0, 0, 0, 0, 0, 0, 0, 27.5, 45))
|
||||
banknote.transform = M
|
||||
src.overlays += banknote
|
||||
src.desc = "They are worth [worth] Thalers."
|
||||
src.desc = "They are worth [worth] [initial_name]s."
|
||||
|
||||
/obj/item/weapon/spacecash/proc/adjust_worth(var/adjust_worth = 0, var/update = 1)
|
||||
worth += adjust_worth
|
||||
@@ -79,7 +80,7 @@
|
||||
return worth
|
||||
|
||||
/obj/item/weapon/spacecash/attack_self()
|
||||
var/amount = input(usr, "How many Thalers do you want to take? (0 to [src.worth])", "Take Money", 20) as num
|
||||
var/amount = input(usr, "How many [initial_name]s do you want to take? (0 to [src.worth])", "Take Money", 20) as num
|
||||
if(!src || QDELETED(src))
|
||||
return
|
||||
amount = round(CLAMP(amount, 0, src.worth))
|
||||
@@ -150,6 +151,7 @@ proc/spawn_money(var/sum, spawnloc, mob/living/carbon/human/human_user as mob)
|
||||
|
||||
/obj/item/weapon/spacecash/ewallet
|
||||
name = "charge card"
|
||||
initial_name = "charge card"
|
||||
icon_state = "efundcard"
|
||||
desc = "A card that holds an amount of money."
|
||||
drop_sound = 'sound/items/drop/card.ogg'
|
||||
|
||||
@@ -81,6 +81,30 @@
|
||||
else
|
||||
to_chat(user, "<span class='notice>'It is empty.</span>")
|
||||
|
||||
/obj/machinery/appliance/proc/report_progress_tgui(datum/cooking_item/CI)
|
||||
if(!CI || !CI.max_cookwork)
|
||||
return list("average", "Not Cooking.")
|
||||
|
||||
if(!CI.cookwork)
|
||||
return list("blue", "Cold.")
|
||||
|
||||
var/progress = CI.cookwork / CI.max_cookwork
|
||||
|
||||
if (progress < 0.25)
|
||||
return list("blue", "It's barely started cooking.")
|
||||
if (progress < 0.75)
|
||||
return list("average", "It's cooking away nicely.")
|
||||
if (progress < 1)
|
||||
return list("good", "It's almost ready!")
|
||||
|
||||
var/half_overcook = (CI.overcook_mult - 1)*0.5
|
||||
if (progress < 1+half_overcook)
|
||||
return list("good", "It's done!")
|
||||
if (progress < CI.overcook_mult)
|
||||
return list("bad", "It looks overcooked, get it out!")
|
||||
else
|
||||
return list("bad", "It is burning!")
|
||||
|
||||
/obj/machinery/appliance/proc/report_progress(var/datum/cooking_item/CI)
|
||||
if (!CI || !CI.max_cookwork)
|
||||
return null
|
||||
@@ -240,28 +264,28 @@
|
||||
/obj/machinery/appliance/attackby(var/obj/item/I, var/mob/user)
|
||||
if(!cook_type || (stat & (BROKEN)))
|
||||
to_chat(user, "<span class='warning'>\The [src] is not working.</span>")
|
||||
return
|
||||
return FALSE
|
||||
|
||||
var/result = can_insert(I, user)
|
||||
if(!result)
|
||||
if(!(default_deconstruction_screwdriver(user, I)))
|
||||
default_part_replacement(user, I)
|
||||
return
|
||||
return FALSE
|
||||
|
||||
if(result == 2)
|
||||
var/obj/item/weapon/grab/G = I
|
||||
if (G && istype(G) && G.affecting)
|
||||
cook_mob(G.affecting, user)
|
||||
return
|
||||
return FALSE
|
||||
|
||||
//From here we can start cooking food
|
||||
add_content(I, user)
|
||||
. = add_content(I, user)
|
||||
update_icon()
|
||||
|
||||
//Override for container mechanics
|
||||
/obj/machinery/appliance/proc/add_content(var/obj/item/I, var/mob/user)
|
||||
if(!user.unEquip(I))
|
||||
return
|
||||
return FALSE
|
||||
|
||||
var/datum/cooking_item/CI = has_space(I)
|
||||
if (istype(I, /obj/item/weapon/reagent_containers/cooking_container) && CI == 1)
|
||||
@@ -271,13 +295,13 @@
|
||||
cooking_objs.Add(CI)
|
||||
user.visible_message("<span class='notice'>\The [user] puts \the [I] into \the [src].</span>")
|
||||
if (CC.check_contents() == 0)//If we're just putting an empty container in, then dont start any processing.
|
||||
return
|
||||
return TRUE
|
||||
else
|
||||
if (CI && istype(CI))
|
||||
I.forceMove(CI.container)
|
||||
|
||||
else //Something went wrong
|
||||
return
|
||||
return FALSE
|
||||
|
||||
if (selected_option)
|
||||
CI.combine_target = selected_option
|
||||
@@ -549,11 +573,11 @@
|
||||
FA.alarm()
|
||||
|
||||
/obj/machinery/appliance/attack_hand(var/mob/user)
|
||||
if (cooking_objs.len)
|
||||
if (removal_menu(user))
|
||||
return
|
||||
else
|
||||
..()
|
||||
if(..())
|
||||
return
|
||||
|
||||
if(cooking_objs.len)
|
||||
removal_menu(user)
|
||||
|
||||
/obj/machinery/appliance/proc/removal_menu(var/mob/user)
|
||||
if (can_remove_items(user))
|
||||
@@ -571,7 +595,7 @@
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/appliance/proc/can_remove_items(var/mob/user)
|
||||
/obj/machinery/appliance/proc/can_remove_items(var/mob/user, show_warning = TRUE)
|
||||
if (!Adjacent(user))
|
||||
return FALSE
|
||||
|
||||
|
||||
@@ -14,6 +14,63 @@
|
||||
mobdamagetype = BURN
|
||||
can_burn_food = TRUE
|
||||
|
||||
/obj/machinery/appliance/cooker/attack_hand(mob/user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/appliance/cooker/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "CookingAppliance", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/appliance/cooker/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
data["temperature"] = round(temperature - T0C, 0.1)
|
||||
data["optimalTemp"] = round(optimal_temp - T0C, 0.1)
|
||||
data["temperatureEnough"] = temperature >= min_temp
|
||||
data["efficiency"] = round(get_efficiency(), 0.1)
|
||||
data["containersRemovable"] = can_remove_items(user, show_warning = FALSE)
|
||||
|
||||
var/list/our_contents = list()
|
||||
for(var/i in 1 to max_contents)
|
||||
our_contents += list(list("empty" = TRUE))
|
||||
if(i <= LAZYLEN(cooking_objs))
|
||||
var/datum/cooking_item/CI = cooking_objs[i]
|
||||
if(istype(CI))
|
||||
our_contents[i] = list()
|
||||
our_contents[i]["progress"] = 0
|
||||
our_contents[i]["progressText"] = report_progress_tgui(CI)
|
||||
if(CI.max_cookwork)
|
||||
our_contents[i]["progress"] = CI.cookwork / CI.max_cookwork
|
||||
if(CI.container)
|
||||
our_contents[i]["container"] = CI.container.label(i)
|
||||
else
|
||||
our_contents[i]["container"] = null
|
||||
data["our_contents"] = our_contents
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/appliance/cooker/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("slot")
|
||||
var/slot = params["slot"]
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if(slot <= LAZYLEN(cooking_objs)) // Inserting
|
||||
var/datum/cooking_item/CI = cooking_objs[slot]
|
||||
|
||||
if(istype(I) && can_insert(I)) // Why do hard work when we can just make them smack us?
|
||||
attackby(I, usr)
|
||||
else if(istype(CI))
|
||||
eject(CI, usr)
|
||||
return TRUE
|
||||
if(istype(I)) // Why do hard work when we can just make them smack us?
|
||||
attackby(I, usr)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/appliance/cooker/examine(var/mob/user)
|
||||
. = ..()
|
||||
if(.) //no need to duplicate adjacency check
|
||||
@@ -141,6 +198,6 @@
|
||||
|
||||
/obj/machinery/appliance/cooker/add_content(var/obj/item/I, var/mob/user)
|
||||
var/datum/cooking_item/CI = ..()
|
||||
if (CI && CI.combine_target)
|
||||
if(istype(CI) && CI.combine_target)
|
||||
to_chat(user, "\The [I] will be used to make a [selected_option]. Output selection is returned to default for future items.")
|
||||
selected_option = null
|
||||
@@ -68,11 +68,13 @@ fundamental differences
|
||||
return 0
|
||||
|
||||
|
||||
/obj/machinery/appliance/mixer/can_remove_items(var/mob/user)
|
||||
if (stat)
|
||||
/obj/machinery/appliance/mixer/can_remove_items(var/mob/user, show_warning = TRUE)
|
||||
if(stat)
|
||||
return 1
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't remove ingredients while it's turned on! Turn it off first or wait for it to finish.</span>")
|
||||
if(show_warning)
|
||||
to_chat(user, "<span class='warning'>You can't remove ingredients while it's turned on! Turn it off first or wait for it to finish.</span>")
|
||||
return 0
|
||||
|
||||
//Container is not removable
|
||||
/obj/machinery/appliance/mixer/removal_menu(var/mob/user)
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
cooking = FALSE
|
||||
|
||||
playsound(src, 'sound/machines/hatch_open.ogg', 20, 1)
|
||||
to_chat(user, "<span class='notice'>You [open? "close":"open"] the oven door</span>")
|
||||
to_chat(user, "<span class='notice'>You [open ? "open" : "close"] the oven door.</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/appliance/cooker/oven/proc/manip(var/obj/item/I)
|
||||
@@ -133,9 +133,10 @@
|
||||
if(temperature > T.temperature)
|
||||
equalize_temperature()
|
||||
|
||||
/obj/machinery/appliance/cooker/oven/can_remove_items(var/mob/user)
|
||||
/obj/machinery/appliance/cooker/oven/can_remove_items(var/mob/user, show_warning = TRUE)
|
||||
if(!open)
|
||||
to_chat(user, "<span class='warning'>You can't take anything out while the door is closed!</span>")
|
||||
if(show_warning)
|
||||
to_chat(user, "<span class='warning'>You can't take anything out while the door is closed!</span>")
|
||||
return 0
|
||||
|
||||
else
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
src.broken = 0 // just to be sure
|
||||
src.icon_state = "mw"
|
||||
src.flags = OPENCONTAINER | NOREACT
|
||||
SStgui.update_uis(src)
|
||||
else //Otherwise bad luck!!
|
||||
to_chat(user, "<span class='warning'>It's dirty!</span>")
|
||||
return 1
|
||||
@@ -141,10 +142,11 @@
|
||||
user.visible_message( \
|
||||
"<span class='notice'>\The [user] has added \the [O] to \the [src].</span>", \
|
||||
"<span class='notice'>You add \the [O] to \the [src].</span>")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
else if(istype(O,/obj/item/weapon/reagent_containers/glass) || \
|
||||
istype(O,/obj/item/weapon/reagent_containers/food/drinks) || \
|
||||
istype(O,/obj/item/weapon/reagent_containers/food/condiment) \
|
||||
istype(O,/obj/item/weapon/reagent_containers/food/drinks) || \
|
||||
istype(O,/obj/item/weapon/reagent_containers/food/condiment) \
|
||||
)
|
||||
if (!O.reagents)
|
||||
return 1
|
||||
@@ -181,83 +183,168 @@
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You have no idea what you can cook with this [O].</span>")
|
||||
..()
|
||||
src.updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/microwave/tgui_state(mob/user)
|
||||
return GLOB.tgui_physical_state
|
||||
|
||||
/obj/machinery/microwave/attack_ai(mob/user as mob)
|
||||
if(istype(user, /mob/living/silicon/robot) && Adjacent(user))
|
||||
attack_hand(user)
|
||||
attack_hand(user)
|
||||
|
||||
/obj/machinery/microwave/attack_hand(mob/user as mob)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/*******************
|
||||
* Microwave Menu
|
||||
********************/
|
||||
/obj/machinery/microwave/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Microwave", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/microwave/interact(mob/user as mob) // The microwave Menu
|
||||
var/dat = ""
|
||||
if(src.broken > 0)
|
||||
dat = {"<TT>Bzzzzttttt</TT>"}
|
||||
else if(src.operating)
|
||||
dat = {"<TT>Microwaving in progress!<BR>Please wait...!</TT>"}
|
||||
else if(src.dirty==100)
|
||||
dat = {"<TT>This microwave is dirty!<BR>Please clean it before use!</TT>"}
|
||||
else
|
||||
var/list/items_counts = new
|
||||
var/list/items_measures = new
|
||||
var/list/items_measures_p = new
|
||||
for (var/obj/O in ((contents - component_parts) - circuit))
|
||||
var/display_name = O.name
|
||||
if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg))
|
||||
items_measures[display_name] = "egg"
|
||||
items_measures_p[display_name] = "eggs"
|
||||
if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu))
|
||||
items_measures[display_name] = "tofu chunk"
|
||||
items_measures_p[display_name] = "tofu chunks"
|
||||
if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat
|
||||
items_measures[display_name] = "slab of meat"
|
||||
items_measures_p[display_name] = "slabs of meat"
|
||||
if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket))
|
||||
display_name = "Turnovers"
|
||||
items_measures[display_name] = "turnover"
|
||||
items_measures_p[display_name] = "turnovers"
|
||||
if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat))
|
||||
items_measures[display_name] = "fillet of meat"
|
||||
items_measures_p[display_name] = "fillets of meat"
|
||||
items_counts[display_name]++
|
||||
for (var/O in items_counts)
|
||||
var/N = items_counts[O]
|
||||
if (!(O in items_measures))
|
||||
dat += {"<B>[capitalize(O)]:</B> [N] [lowertext(O)]\s<BR>"}
|
||||
else
|
||||
if (N==1)
|
||||
dat += {"<B>[capitalize(O)]:</B> [N] [items_measures[O]]<BR>"}
|
||||
else
|
||||
dat += {"<B>[capitalize(O)]:</B> [N] [items_measures_p[O]]<BR>"}
|
||||
/obj/machinery/microwave/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
for (var/datum/reagent/R in reagents.reagent_list)
|
||||
var/display_name = R.name
|
||||
if (R.id == "capsaicin")
|
||||
display_name = "Hotsauce"
|
||||
if (R.id == "frostoil")
|
||||
display_name = "Coldsauce"
|
||||
dat += {"<B>[display_name]:</B> [R.volume] unit\s<BR>"}
|
||||
data["broken"] = broken
|
||||
data["operating"] = operating
|
||||
data["dirty"] = dirty == 100
|
||||
data["items"] = get_items_list()
|
||||
|
||||
return data
|
||||
|
||||
if (items_counts.len==0 && reagents.reagent_list.len==0)
|
||||
dat = {"<B>The microwave is empty</B><BR>"}
|
||||
/obj/machinery/microwave/proc/get_items_list()
|
||||
var/list/data = list()
|
||||
|
||||
var/list/items_counts = list()
|
||||
var/list/items_measures = list()
|
||||
var/list/items_measures_p = list()
|
||||
for(var/obj/O in ((contents - component_parts) - circuit))
|
||||
var/display_name = O.name
|
||||
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg))
|
||||
items_measures[display_name] = "egg"
|
||||
items_measures_p[display_name] = "eggs"
|
||||
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu))
|
||||
items_measures[display_name] = "tofu chunk"
|
||||
items_measures_p[display_name] = "tofu chunks"
|
||||
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat
|
||||
items_measures[display_name] = "slab of meat"
|
||||
items_measures_p[display_name] = "slabs of meat"
|
||||
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket))
|
||||
display_name = "Turnovers"
|
||||
items_measures[display_name] = "turnover"
|
||||
items_measures_p[display_name] = "turnovers"
|
||||
if(istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat))
|
||||
items_measures[display_name] = "fillet of meat"
|
||||
items_measures_p[display_name] = "fillets of meat"
|
||||
items_counts[display_name]++
|
||||
for(var/O in items_counts)
|
||||
var/N = items_counts[O]
|
||||
if(!(O in items_measures))
|
||||
data.Add(list(list(
|
||||
"name" = capitalize(O),
|
||||
"amt" = N,
|
||||
"extra" = "[lowertext(O)][N > 1 ? "s" : ""]",
|
||||
)))
|
||||
else
|
||||
dat = {"<b>Ingredients:</b><br>[dat]"}
|
||||
dat += {"<HR><BR>\
|
||||
<A href='?src=\ref[src];action=cook'>Turn on!<BR>\
|
||||
<A href='?src=\ref[src];action=dispose'>Eject ingredients!<BR>\
|
||||
"}
|
||||
data.Add(list(list(
|
||||
"name" = capitalize(O),
|
||||
"amt" = N,
|
||||
"extra" = N == 1 ? items_measures[O] : items_measures_p[O],
|
||||
)))
|
||||
|
||||
user << browse("<HEAD><TITLE>Microwave Controls</TITLE></HEAD><TT>[dat]</TT>", "window=microwave")
|
||||
onclose(user, "microwave")
|
||||
return
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
var/display_name = R.name
|
||||
if(R.id == "capsaicin")
|
||||
display_name = "Hotsauce"
|
||||
if(R.id == "frostoil")
|
||||
display_name = "Coldsauce"
|
||||
data.Add(list(list(
|
||||
"name" = display_name,
|
||||
"amt" = R.volume,
|
||||
"extra" = "unit[R.volume > 1 ? "s" : ""]"
|
||||
)))
|
||||
|
||||
return data
|
||||
|
||||
/obj/machinery/microwave/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return TRUE
|
||||
|
||||
if(operating)
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("cook")
|
||||
cook()
|
||||
return TRUE
|
||||
|
||||
if("dispose")
|
||||
dispose()
|
||||
return TRUE
|
||||
|
||||
// /obj/machinery/microwave/interact(mob/user as mob) // The microwave Menu
|
||||
// var/dat = ""
|
||||
// if(src.broken > 0)
|
||||
// dat = {"<TT>Bzzzzttttt</TT>"}
|
||||
// else if(src.operating)
|
||||
// dat = {"<TT>Microwaving in progress!<BR>Please wait...!</TT>"}
|
||||
// else if(src.dirty==100)
|
||||
// dat = {"<TT>This microwave is dirty!<BR>Please clean it before use!</TT>"}
|
||||
// else
|
||||
// var/list/items_counts = new
|
||||
// var/list/items_measures = new
|
||||
// var/list/items_measures_p = new
|
||||
// for (var/obj/O in ((contents - component_parts) - circuit))
|
||||
// var/display_name = O.name
|
||||
// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/egg))
|
||||
// items_measures[display_name] = "egg"
|
||||
// items_measures_p[display_name] = "eggs"
|
||||
// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/tofu))
|
||||
// items_measures[display_name] = "tofu chunk"
|
||||
// items_measures_p[display_name] = "tofu chunks"
|
||||
// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/meat)) //any meat
|
||||
// items_measures[display_name] = "slab of meat"
|
||||
// items_measures_p[display_name] = "slabs of meat"
|
||||
// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/donkpocket))
|
||||
// display_name = "Turnovers"
|
||||
// items_measures[display_name] = "turnover"
|
||||
// items_measures_p[display_name] = "turnovers"
|
||||
// if (istype(O,/obj/item/weapon/reagent_containers/food/snacks/carpmeat))
|
||||
// items_measures[display_name] = "fillet of meat"
|
||||
// items_measures_p[display_name] = "fillets of meat"
|
||||
// items_counts[display_name]++
|
||||
// for (var/O in items_counts)
|
||||
// var/N = items_counts[O]
|
||||
// if (!(O in items_measures))
|
||||
// dat += {"<B>[capitalize(O)]:</B> [N] [lowertext(O)]\s<BR>"}
|
||||
// else
|
||||
// if (N==1)
|
||||
// dat += {"<B>[capitalize(O)]:</B> [N] [items_measures[O]]<BR>"}
|
||||
// else
|
||||
// dat += {"<B>[capitalize(O)]:</B> [N] [items_measures_p[O]]<BR>"}
|
||||
|
||||
// for (var/datum/reagent/R in reagents.reagent_list)
|
||||
// var/display_name = R.name
|
||||
// if (R.id == "capsaicin")
|
||||
// display_name = "Hotsauce"
|
||||
// if (R.id == "frostoil")
|
||||
// display_name = "Coldsauce"
|
||||
// dat += {"<B>[display_name]:</B> [R.volume] unit\s<BR>"}
|
||||
|
||||
// if (items_counts.len==0 && reagents.reagent_list.len==0)
|
||||
// dat = {"<B>The microwave is empty</B><BR>"}
|
||||
// else
|
||||
// dat = {"<b>Ingredients:</b><br>[dat]"}
|
||||
// dat += {"<HR><BR>\
|
||||
// <A href='?src=\ref[src];action=cook'>Turn on!<BR>\
|
||||
// <A href='?src=\ref[src];action=dispose'>Eject ingredients!<BR>\
|
||||
// "}
|
||||
|
||||
// user << browse("<HEAD><TITLE>Microwave Controls</TITLE></HEAD><TT>[dat]</TT>", "window=microwave")
|
||||
// onclose(user, "microwave")
|
||||
// return
|
||||
|
||||
/***********************************
|
||||
* Microwave Menu Handling/Cooking
|
||||
@@ -388,13 +475,13 @@
|
||||
soundloop.start()
|
||||
src.operating = TRUE
|
||||
src.icon_state = "mw1"
|
||||
src.updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/microwave/proc/abort()
|
||||
operating = FALSE // Turn it off again aferwards
|
||||
if(icon_state == "mw1")
|
||||
icon_state = "mw"
|
||||
updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
soundloop.stop()
|
||||
|
||||
/obj/machinery/microwave/proc/stop()
|
||||
@@ -402,7 +489,7 @@
|
||||
operating = FALSE // Turn it off again aferwards
|
||||
if(icon_state == "mw1")
|
||||
icon_state = "mw"
|
||||
updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
soundloop.stop()
|
||||
|
||||
/obj/machinery/microwave/proc/dispose(var/message = 1)
|
||||
@@ -413,7 +500,7 @@
|
||||
src.reagents.clear_reagents()
|
||||
if(message)
|
||||
to_chat(usr, "<span class='notice'>You dispose of the microwave contents.</span>")
|
||||
src.updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/microwave/proc/muck_start()
|
||||
playsound(src, 'sound/effects/splat.ogg', 50, 1) // Play a splat sound
|
||||
@@ -425,7 +512,7 @@
|
||||
src.flags = null //So you can't add condiments
|
||||
src.icon_state = "mwbloody" // Make it look dirty too
|
||||
src.operating = 0 // Turn it off again aferwards
|
||||
src.updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
soundloop.stop()
|
||||
|
||||
|
||||
@@ -438,7 +525,7 @@
|
||||
src.broken = 2 // Make it broken so it can't be used util fixed
|
||||
src.flags = null //So you can't add condiments
|
||||
src.operating = 0 // Turn it off again aferwards
|
||||
src.updateUsrDialog()
|
||||
SStgui.update_uis(src)
|
||||
soundloop.stop()
|
||||
|
||||
/obj/machinery/microwave/proc/fail()
|
||||
@@ -460,23 +547,6 @@
|
||||
ffuu.reagents.add_reagent("toxin", amount/10)
|
||||
return ffuu
|
||||
|
||||
/obj/machinery/microwave/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
|
||||
usr.set_machine(src)
|
||||
if(src.operating)
|
||||
src.updateUsrDialog()
|
||||
return
|
||||
|
||||
switch(href_list["action"])
|
||||
if ("cook")
|
||||
cook()
|
||||
|
||||
if ("dispose")
|
||||
dispose()
|
||||
return
|
||||
|
||||
/obj/machinery/microwave/verb/Eject()
|
||||
set src in oview(1)
|
||||
set category = "Object"
|
||||
|
||||
@@ -79,60 +79,59 @@
|
||||
return
|
||||
user.set_machine(src)
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/**
|
||||
* Display the NanoUI window for the Holodeck Computer.
|
||||
*
|
||||
* See NanoUI documentation for details.
|
||||
* Open the UI!
|
||||
*/
|
||||
/obj/machinery/computer/HolodeckControl/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
user.set_machine(src)
|
||||
/obj/machinery/computer/HolodeckControl/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "Holodeck", name)
|
||||
ui.open()
|
||||
|
||||
var/list/data = list()
|
||||
var/program_list[0]
|
||||
var/restricted_program_list[0]
|
||||
/**
|
||||
* Data for the TGUI UI
|
||||
*/
|
||||
/obj/machinery/computer/HolodeckControl/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
var/list/program_list = list()
|
||||
var/list/restricted_program_list = list()
|
||||
|
||||
for(var/P in supported_programs)
|
||||
program_list[++program_list.len] = P
|
||||
program_list.Add(P)
|
||||
|
||||
for(var/P in restricted_programs)
|
||||
restricted_program_list[++restricted_program_list.len] = P
|
||||
restricted_program_list.Add(P)
|
||||
|
||||
data["supportedPrograms"] = program_list
|
||||
data["restrictedPrograms"] = restricted_program_list
|
||||
data["currentProgram"] = current_program
|
||||
data["isSilicon"] = FALSE
|
||||
if(issilicon(user))
|
||||
data["isSilicon"] = 1
|
||||
else
|
||||
data["isSilicon"] = null
|
||||
data["isSilicon"] = TRUE
|
||||
|
||||
data["safetyDisabled"] = safety_disabled
|
||||
data["emagged"] = emagged
|
||||
data["gravity"] = FALSE
|
||||
if(linkedholodeck.has_gravity)
|
||||
data["gravity"] = 1
|
||||
else
|
||||
data["gravity"] = null
|
||||
data["gravity"] = TRUE
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "holodeck.tmpl", src.name, 400, 550)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(20)
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/HolodeckControl/Topic(href, href_list)
|
||||
/obj/machinery/computer/HolodeckControl/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return 1
|
||||
if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.set_machine(src)
|
||||
return TRUE
|
||||
|
||||
if(href_list["program"])
|
||||
var/prog = href_list["program"]
|
||||
switch(action)
|
||||
if("program")
|
||||
var/prog = params["program"]
|
||||
if(prog in (supported_programs + restricted_programs))
|
||||
if(loadProgram(prog))
|
||||
current_program = prog
|
||||
return TRUE
|
||||
|
||||
else if(href_list["AIoverride"])
|
||||
if("AIoverride")
|
||||
if(!issilicon(usr))
|
||||
return
|
||||
|
||||
@@ -147,13 +146,13 @@
|
||||
else
|
||||
message_admins("[key_name_admin(usr)] restored the holodeck's safeties")
|
||||
log_game("[key_name(usr)] restored the holodeck's safeties")
|
||||
return TRUE
|
||||
|
||||
else if(href_list["gravity"])
|
||||
if("gravity")
|
||||
toggleGravity(linkedholodeck)
|
||||
return TRUE
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
SSnanoui.update_uis(src)
|
||||
add_fingerprint(usr)
|
||||
|
||||
/obj/machinery/computer/HolodeckControl/emag_act(var/remaining_charges, var/mob/user as mob)
|
||||
playsound(src, 'sound/effects/sparks4.ogg', 75, 1)
|
||||
|
||||
@@ -338,11 +338,11 @@ datum/borrowbook // Datum used to keep track of who has borrowed what when and f
|
||||
if(!bibledelay)
|
||||
|
||||
var/obj/item/weapon/storage/bible/B = new /obj/item/weapon/storage/bible(src.loc)
|
||||
if(ticker && ( ticker.Bible_icon_state && ticker.Bible_item_state) )
|
||||
B.icon_state = ticker.Bible_icon_state
|
||||
B.item_state = ticker.Bible_item_state
|
||||
B.name = ticker.Bible_name
|
||||
B.deity_name = ticker.Bible_deity_name
|
||||
if(GLOB.religion)
|
||||
B.icon_state = GLOB.bible_icon_state
|
||||
B.item_state = GLOB.bible_item_state
|
||||
B.name = GLOB.bible_name
|
||||
B.deity_name = GLOB.deity
|
||||
|
||||
bibledelay = 1
|
||||
spawn(60)
|
||||
|
||||
@@ -50,27 +50,30 @@
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/looking_glass/attack_ai(var/mob/user as mob)
|
||||
return src.attack_hand(user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/machinery/computer/looking_glass/attack_hand(var/mob/user as mob)
|
||||
if(..())
|
||||
return
|
||||
user.set_machine(src)
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/computer/looking_glass/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
user.set_machine(src)
|
||||
|
||||
var/list/data = list()
|
||||
var/program_list[0]
|
||||
/obj/machinery/computer/looking_glass/tgui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if(!ui)
|
||||
ui = new(user, src, "LookingGlass", name)
|
||||
ui.open()
|
||||
|
||||
/obj/machinery/computer/looking_glass/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
|
||||
var/list/data = ..()
|
||||
|
||||
var/list/program_list = list()
|
||||
for(var/P in supported_programs)
|
||||
program_list[++program_list.len] = P
|
||||
program_list.Add(P)
|
||||
|
||||
if(emagged)
|
||||
for(var/P in secret_programs)
|
||||
program_list[++program_list.len] = P
|
||||
program_list.Add(P)
|
||||
|
||||
data["supportedPrograms"] = program_list
|
||||
data["currentProgram"] = current_program
|
||||
@@ -78,24 +81,18 @@
|
||||
if(my_area?.has_gravity)
|
||||
data["gravity"] = 1
|
||||
else
|
||||
data["gravity"] = null
|
||||
data["gravity"] = 0
|
||||
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
ui = new(user, src, ui_key, "lookingglass.tmpl", src.name, 400, 550)
|
||||
ui.set_initial_data(data)
|
||||
ui.open()
|
||||
ui.set_auto_update(20)
|
||||
return data
|
||||
|
||||
/obj/machinery/computer/looking_glass/Topic(href, href_list)
|
||||
/obj/machinery/computer/looking_glass/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
|
||||
if(..())
|
||||
return 1
|
||||
if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon)))
|
||||
usr.set_machine(src)
|
||||
|
||||
if(href_list["program"])
|
||||
return TRUE
|
||||
|
||||
switch(action)
|
||||
if("program")
|
||||
if(ready)
|
||||
var/prog = href_list["program"]
|
||||
var/prog = params["program"]
|
||||
if(prog == "Off")
|
||||
current_program = "Off"
|
||||
unload_program()
|
||||
@@ -104,17 +101,18 @@
|
||||
load_program(prog)
|
||||
else
|
||||
visible_message("<span class='warning'>ERROR. Recalibrating displays.</span>")
|
||||
return TRUE
|
||||
|
||||
else if(href_list["gravity"])
|
||||
if("gravity")
|
||||
toggle_gravity(my_area)
|
||||
return TRUE
|
||||
|
||||
else if(href_list["immersion"])
|
||||
if("immersion")
|
||||
immersion = !immersion
|
||||
my_area.toggle_optional(immersion)
|
||||
return TRUE
|
||||
|
||||
src.add_fingerprint(usr)
|
||||
|
||||
SSnanoui.update_uis(src)
|
||||
add_fingerprint(usr)
|
||||
|
||||
/obj/machinery/computer/looking_glass/emag_act(var/remaining_charges, var/mob/user as mob)
|
||||
if (!emagged)
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
str += " by [artist]"
|
||||
return str
|
||||
|
||||
/datum/track/proc/toNanoList()
|
||||
/datum/track/proc/toTguiList()
|
||||
return list("ref" = "\ref[src]", "title" = title, "artist" = artist, "duration" = duration)
|
||||
|
||||
|
||||
|
||||
@@ -379,6 +379,29 @@ You can also set the stat of a NIF to NIF_TEMPFAIL without any issues to disable
|
||||
human.adjust_nutrition(-use_charge)
|
||||
return TRUE
|
||||
|
||||
// This operates on a nifsoft *path*, not an instantiation.
|
||||
// It tells the nifsoft shop if it's installation will succeed, to prevent it
|
||||
// from charging the user for incompatible software.
|
||||
/obj/item/device/nif/proc/can_install(var/datum/nifsoft/path)
|
||||
if(stat == NIF_TEMPFAIL)
|
||||
return FALSE
|
||||
|
||||
if(nifsofts[initial(path.list_pos)])
|
||||
notify("The software \"[initial(path.name)]\" is already installed.", TRUE)
|
||||
return FALSE
|
||||
|
||||
if(human)
|
||||
var/applies_to = initial(path.applies_to)
|
||||
var/synth = human.isSynthetic()
|
||||
if(synth && !(applies_to & NIF_SYNTHETIC))
|
||||
notify("The software \"[initial(path.name)]\" is not supported on your chassis type.",TRUE)
|
||||
return FALSE
|
||||
if(!synth && !(applies_to & NIF_ORGANIC))
|
||||
notify("The software \"[initial(path.name)]\" is not supported in organic life.",TRUE)
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
//Install a piece of software
|
||||
/obj/item/device/nif/proc/install(var/datum/nifsoft/new_soft)
|
||||
if(stat == NIF_TEMPFAIL) return FALSE
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
wires = new /datum/wires/vending/no_contraband(src) //These wires can't be hacked for contraband.
|
||||
entopic = new(aholder = src, aicon = icon, aicon_state = "beacon")
|
||||
|
||||
/obj/machinery/vending/nifsoft_shop/tgui_data(mob/user)
|
||||
. = ..()
|
||||
.["chargesMoney"] = TRUE
|
||||
|
||||
/obj/machinery/vending/nifsoft_shop/Destroy()
|
||||
QDEL_NULL(entopic)
|
||||
return ..()
|
||||
@@ -93,95 +97,39 @@
|
||||
|
||||
product_records.Add(product)
|
||||
|
||||
/obj/machinery/vending/nifsoft_shop/allowed(mob/user)
|
||||
if(!ishuman(user))
|
||||
return FALSE
|
||||
/obj/machinery/vending/nifsoft_shop/can_buy(datum/stored_item/vending_product/R, mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
var/datum/nifsoft/path = R.item_path
|
||||
if(!ishuman(user))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!H.nif || !H.nif.stat == NIF_WORKING)
|
||||
to_chat(H, "<span class='warning'>[src] seems unable to connect to your NIF...</span>")
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!H.nif || !H.nif.stat == NIF_WORKING)
|
||||
to_chat(H, "<span class='warning'>[src] seems unable to connect to your NIF...</span>")
|
||||
flick("[icon_state]-deny",entopic.my_image)
|
||||
return FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
//Had to override this too
|
||||
/obj/machinery/vending/nifsoft_shop/Topic(href, href_list)
|
||||
if(stat & (BROKEN|NOPOWER))
|
||||
return
|
||||
if(usr.stat || usr.restrained())
|
||||
return
|
||||
|
||||
if(href_list["remove_coin"] && !istype(usr,/mob/living/silicon))
|
||||
if(!coin)
|
||||
to_chat(usr, "There is no coin in this machine.")
|
||||
return
|
||||
|
||||
coin.forceMove(src.loc)
|
||||
if(!usr.get_active_hand())
|
||||
usr.put_in_hands(coin)
|
||||
to_chat(usr, "<span class='notice'>You remove \the [coin] from \the [src]</span>")
|
||||
coin = null
|
||||
categories &= ~CAT_COIN
|
||||
|
||||
if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))))
|
||||
if((href_list["vend"]) && (vend_ready) && (!currently_vending))
|
||||
if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH
|
||||
to_chat(usr, "<span class='warning'>Access denied.</span>") //Unless emagged of course
|
||||
flick("[icon_state]-deny",entopic.my_image)
|
||||
return
|
||||
|
||||
var/key = text2num(href_list["vend"])
|
||||
var/datum/stored_item/vending_product/R = product_records[key]
|
||||
|
||||
// This should not happen unless the request from NanoUI was bad
|
||||
if(!(R.category & categories))
|
||||
return
|
||||
|
||||
//Specific soft access checking
|
||||
var/datum/nifsoft/path = R.item_path
|
||||
if(initial(path.access))
|
||||
var/list/soft_access = list(initial(path.access))
|
||||
var/list/usr_access = usr.GetAccess()
|
||||
if(scan_id && !has_access(soft_access, list(), usr_access) && !emagged)
|
||||
to_chat(usr, "<span class='warning'>You aren't authorized to buy [initial(path.name)].</span>")
|
||||
flick("[icon_state]-deny",entopic.my_image)
|
||||
return
|
||||
|
||||
if(R.price <= 0)
|
||||
vend(R, usr)
|
||||
else if(istype(usr,/mob/living/silicon)) //If the item is not free, provide feedback if a synth is trying to buy something.
|
||||
to_chat(usr, "<span class='danger'>Artificial unit recognized. Artificial units cannot complete this transaction. Purchase canceled.</span>")
|
||||
return
|
||||
else
|
||||
currently_vending = R
|
||||
if(!vendor_account || vendor_account.suspended)
|
||||
status_message = "This machine is currently unable to process payments due to problems with the associated account."
|
||||
status_error = 1
|
||||
else
|
||||
status_message = "[initial(path.desc)]<br><br><b>Please swipe a card or insert cash to pay for the item.</b>"
|
||||
status_error = 0
|
||||
|
||||
else if(href_list["cancelpurchase"])
|
||||
currently_vending = null
|
||||
|
||||
else if((href_list["togglevoice"]) && (panel_open))
|
||||
shut_up = !shut_up
|
||||
|
||||
add_fingerprint(usr)
|
||||
SSnanoui.update_uis(src)
|
||||
if(!H.nif.can_install(path))
|
||||
flick("[icon_state]-deny", entopic.my_image)
|
||||
return FALSE
|
||||
|
||||
if(initial(path.access))
|
||||
var/list/soft_access = list(initial(path.access))
|
||||
var/list/usr_access = user.GetAccess()
|
||||
if(scan_id && !has_access(soft_access, list(), usr_access) && !emagged)
|
||||
to_chat(user, "<span class='warning'>You aren't authorized to buy [initial(path.name)].</span>")
|
||||
flick("[icon_state]-deny", entopic.my_image)
|
||||
return FALSE
|
||||
|
||||
// Also special treatment!
|
||||
/obj/machinery/vending/nifsoft_shop/vend(datum/stored_item/vending_product/R, mob/user)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if((!allowed(usr)) && !emagged && scan_id && istype(H)) //For SECURE VENDING MACHINES YEAH
|
||||
to_chat(usr, "<span class='warning'>Purchase not allowed.</span>") //Unless emagged of course
|
||||
if(!can_buy(R, user)) //For SECURE VENDING MACHINES YEAH
|
||||
to_chat(user, "<span class='warning'>Purchase not allowed.</span>") //Unless emagged of course
|
||||
flick("[icon_state]-deny",entopic.my_image)
|
||||
return
|
||||
vend_ready = 0 //One thing at a time!!
|
||||
status_message = "Installing..."
|
||||
status_error = 0
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
if(R.category & CAT_COIN)
|
||||
if(!coin)
|
||||
@@ -209,15 +157,14 @@
|
||||
spawn(vend_delay)
|
||||
R.amount--
|
||||
new R.item_path(H.nif)
|
||||
H.nif.notify("New software installed: [R.item_name]")
|
||||
flick("[icon_state]-vend",entopic.my_image)
|
||||
if(has_logs)
|
||||
do_logging(R, user, 1)
|
||||
|
||||
status_message = ""
|
||||
status_error = 0
|
||||
vend_ready = 1
|
||||
currently_vending = null
|
||||
SSnanoui.update_uis(src)
|
||||
SStgui.update_uis(src)
|
||||
return 1
|
||||
|
||||
//Can't throw intangible software at people.
|
||||
|
||||
@@ -195,7 +195,7 @@ var/global/photo_count = 0
|
||||
for(var/i; i <= sorted.len; i++)
|
||||
var/atom/A = sorted[i]
|
||||
if(A)
|
||||
var/icon/img = getFlatIcon(A)//, picture_planes = picture_planes)//build_composite_icon(A) //VOREStation Edit
|
||||
var/icon/img = getFlatIcon(A, no_anim = TRUE)//, picture_planes = picture_planes)//build_composite_icon(A) //VOREStation Edit
|
||||
|
||||
// If what we got back is actually a picture, draw it.
|
||||
if(istype(img, /icon))
|
||||
@@ -216,7 +216,7 @@ var/global/photo_count = 0
|
||||
// Calculate where we are relative to the center of the photo
|
||||
var/xoff = (the_turf.x - center.x) * 32 + center_offset
|
||||
var/yoff = (the_turf.y - center.y) * 32 + center_offset
|
||||
res.Blend(getFlatIcon(the_turf.loc), blendMode2iconMode(the_turf.blend_mode),xoff,yoff)
|
||||
res.Blend(getFlatIcon(the_turf.loc, no_anim = TRUE), blendMode2iconMode(the_turf.blend_mode),xoff,yoff)
|
||||
return res
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@@ -1,36 +0,0 @@
|
||||
<!--
|
||||
Interface for holodeck computers
|
||||
See: code/modules/holodeck/HolodeckControl.dm
|
||||
-->
|
||||
|
||||
<h3>Current Loaded Programs:</h3>
|
||||
{{for data.supportedPrograms}}
|
||||
<div class='item'>{{:helper.link(value, data.currentProgram == value ? 'check' : 'close', {'program' : value}, null, data.currentProgram == value ? 'linkOn' : null)}}</div>
|
||||
{{/for}}
|
||||
<div class='item'>Please ensure that only holographic weapons are used in the holodeck if a combat simulation has been loaded.</div>
|
||||
{{if data.isSilicon}}
|
||||
{{if data.safetyDisabled}}
|
||||
{{if data.emagged}}
|
||||
<div class='item'><span class='bad'><b>ERROR</b></span>: Cannot re-enable Safety Protocols.</div>
|
||||
{{else}}
|
||||
<div class='item'>{{:helper.link('Re-Enable Safety Protocols?', 'help', {'AIoverride' : 1}, null, 'linkOn')}}</div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<div class='item'>{{:helper.link('Re-Enable Safety Protocols?', 'help', {'AIoverride' : 1}, null, 'redButton')}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
{{if data.safetyDisabled}}
|
||||
{{for data.restrictedPrograms}}
|
||||
<div class='item'>{{:helper.link('Begin ' + value, data.currentProgram == value ? 'check' : 'close', {'program' : value.program}, null, data.currentProgram == value ? 'linkOn' : null)}}</div>
|
||||
{{/for}}
|
||||
<div class='item average'>Ensure the holodeck is empty before testing.</div>
|
||||
<div class='item'>Safety Protocols are <span class='bad'>DISABLED</span></div>
|
||||
{{else}}
|
||||
<div class='item'>Safety Protocols are <span class='good'>ENABLED</span></div>
|
||||
{{/if}}
|
||||
|
||||
<div class='item'>
|
||||
<div class='itemLabelNarrow'>Gravity:</div>
|
||||
{{:helper.link(data.gravity ? 'On ' : 'Off', data.gravity ? 'check' : 'close', {'gravity' : 1}, null, data.gravity ? 'linkOn' : 'redButton')}}
|
||||
</div>
|
||||
@@ -1,49 +0,0 @@
|
||||
<!--
|
||||
Title: Jukebox UI
|
||||
Used In File(s): \code\game\machinery\jukebox.dm
|
||||
-->
|
||||
|
||||
<div class='statusDisplay'>
|
||||
<div class="item">
|
||||
<div class="itemLabel">Currently Playing:</div>
|
||||
{{if data.playing && data.current_track }}
|
||||
<div class="itemContent"><b>{{:data.current_track.title}}</b> by <i>{{:data.current_track.artist ? data.current_track.artist : "Unknown"}}</i></div>
|
||||
{{else}}
|
||||
<div class="itemContent">Stopped</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemContent">
|
||||
{{:helper.displayBar(data.percent, 0, 1, 'good')}}
|
||||
</div>
|
||||
<div class="itemLabel">
|
||||
{{:helper.link('Play' , 'play', {'play' : 1}, data.playing == 1 ? 'disabled' : null, null)}}
|
||||
{{:helper.link('Stop' , 'stop', {'stop' : 1}, data.playing == 0 ? 'disabled' : null, null)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">{{:helper.link('Volume', 'volume-on', {'volume' : 1})}}</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.displayBar(data.volume, 0, 1, (data.volume < .25) ? 'bad' : (data.volume < .75) ? 'average' : 'good')}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">Loop Mode:</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.link('Next', 'triangle-1-e', {'loopmode' : 1}, data.loop_mode == 1 ? 'disabled' : null, null)}}
|
||||
{{:helper.link('Random', 'shuffle', {'loopmode' : 2}, data.loop_mode == 2 ? 'disabled' : null, null)}}
|
||||
{{:helper.link('Repeat', 'arrowrefresh-1-w', {'loopmode' : 3}, data.loop_mode == 3 ? 'disabled' : null, null)}}
|
||||
{{:helper.link('Once', 'arrowstop-1-e', {'loopmode' : 4}, data.loop_mode == 4 ? 'disabled' : null, null)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<H3><span class="white">Available tracks:</span></H3>
|
||||
<div class="itemContent">
|
||||
{{for data.tracks}}
|
||||
<div class="item">
|
||||
{{:helper.link(value.title, 'gear', {'change_track' : value.ref}, data.current_track_ref == value.ref ? 'disabled' : null, null)}}
|
||||
</div>
|
||||
{{/for}}
|
||||
</div>
|
||||
@@ -1,14 +0,0 @@
|
||||
<h3>Current Loaded Programs:</h3>
|
||||
{{for data.supportedPrograms}}
|
||||
<div class='item'>{{:helper.link(value, data.currentProgram == value ? 'check' : 'close', {'program' : value}, null, data.currentProgram == value ? 'linkOn' : null)}}</div>
|
||||
{{/for}}
|
||||
|
||||
<div class='item'>
|
||||
<div class='itemLabel'>Area Gravity:</div>
|
||||
{{:helper.link(data.gravity ? 'On ' : 'Off', data.gravity ? 'check' : 'close', {'gravity' : 1}, null, data.gravity ? 'linkOn' : 'redButton')}}
|
||||
</div>
|
||||
|
||||
<div class='item'>
|
||||
<div class='itemLabel'>Full Immersion:</div>
|
||||
{{:helper.link(data.immersion ? 'On ' : 'Off', data.immersion ? 'check' : 'close', {'immersion' : 1}, null, data.immersion ? 'linkOn' : 'redButton')}}
|
||||
</div>
|
||||
@@ -1,83 +0,0 @@
|
||||
<!--
|
||||
Timeclock UI
|
||||
See: code/game/machinery/computer/timeclock_vr.dm
|
||||
-->
|
||||
|
||||
<!-- Always show person's status display -->
|
||||
<div class="statusDisplay">
|
||||
<h3><div class='notice'>OOC Note: PTO acquired is account-wide and shared across all characters. Info listed below is not IC information.</div></h3>
|
||||
<h3>Time Off Balance for {{:config.user.name}}</h3>
|
||||
{{props data.department_hours}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">{{:key}}</div>
|
||||
<div class="statusValue {{:value > 6 ? 'good' : value < 1 ? 'bad' : 'average'}}">{{:helper.fixed(value)}} {{:helper.fixed(value) == 1.0 ? 'hour' : 'hours'}}</div>
|
||||
</div>
|
||||
{{empty}}
|
||||
<div class='notice'>No Hours Accrued</div>
|
||||
{{/props}}
|
||||
</div>
|
||||
|
||||
<h3>Employment Information</h3>
|
||||
<div class='itemGroup'>
|
||||
<div class='item'>
|
||||
<div class='itemLabel'>Employee ID:</div>
|
||||
{{:helper.link(data.card ? data.card : 'Insert ID', 'person', {'id' : 1})}}
|
||||
</div>
|
||||
{{if data.job_datum }}
|
||||
<div class='item'>
|
||||
<div class='itemLabel'>Rank:</div>
|
||||
<div class='itemContent'>
|
||||
<span style='padding: 2px 8px; border-radius: 4px; background-color: {{:data.job_datum.selection_color}};'>{{:data.job_datum.title}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class='item'>
|
||||
<div class='itemLabel'>Departments:</div>
|
||||
<div class='itemContent'>{{:data.job_datum.departments}}</div>
|
||||
</div>
|
||||
<div class='item'>
|
||||
<div class='itemLabel'>Pay Scale:</div>
|
||||
<div class='itemContent'>{{:data.job_datum.economic_modifier}}</div>
|
||||
</div>
|
||||
<div class='item'>
|
||||
<div class='itemLabel'>PTO Eligibility:</div>
|
||||
{{if data.job_datum.timeoff_factor > 0 }}
|
||||
<div class='itemContent' title='Hours working this position will earn time off for its department.' style='cursor: help;'>
|
||||
Earns PTO - {{:data.job_datum.pto_department}}
|
||||
</div>
|
||||
{{else data.job_datum.timeoff_factor < 0}}
|
||||
<div class='itemContent' title='Hours spent in this position are deducted from your time off for its department.' style='cursor: help;'>
|
||||
Requires PTO - {{:data.job_datum.pto_department}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class='itemContent' title='This job neither requires nor earns time off hours.' style='cursor: help;'>
|
||||
Neutral
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{if data.allow_change_job && data.job_datum && data.job_datum.timeoff_factor != 0 && !(data.assignment == "Dismissed")}}
|
||||
<h3>Employment Actions</h3>
|
||||
<div class='itemGroup'>
|
||||
<div class='item'>
|
||||
{{if (data.job_datum.timeoff_factor > 0) }}
|
||||
{{if helper.round(data.department_hours[data.job_datum.pto_department]) > 0}}
|
||||
{{:helper.link('Go Off-Duty', 'alert', {'switch-to-offduty': 1})}}
|
||||
{{else}}
|
||||
<i class='uiIcon16 icon-alert-red'></i>
|
||||
<span class='bad'>Insufficent Time Off Accrued</span>
|
||||
{{/if}}
|
||||
{{else (data.job_datum.timeoff_factor < 0) }}
|
||||
{{props data.job_choices :alt_titles:job }}
|
||||
{{props alt_titles :alt_title:alt_title_index }}
|
||||
<div class='itemLabelWide'>{{:alt_title}}</div>
|
||||
<div class='itemContentMedium'>{{:helper.link("Go On-Duty", 'suitcase', {'switch-to-onduty-rank' : job,'switch-to-onduty-assignment' : alt_title})}}</div>
|
||||
{{/props}}
|
||||
{{empty}}
|
||||
<div class='notice'>No Open Positions - See Head of Personnel</div>
|
||||
{{/props}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
66
tgui/packages/tgui/interfaces/ColorMate.js
Normal file
66
tgui/packages/tgui/interfaces/ColorMate.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
export const ColorMate = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
items,
|
||||
activecolor,
|
||||
} = data;
|
||||
|
||||
let height = Math.min(270 + (items.length * 15), 600);
|
||||
|
||||
return (
|
||||
<Window width={300} height={height} resizable>
|
||||
<Window.Content>
|
||||
{items.length && (
|
||||
<Fragment>
|
||||
<Section title="Paint">
|
||||
<Flex justify="center" align="center">
|
||||
<Flex.Item basis="50%">
|
||||
<Box backgroundColor={activecolor} width="120px" height="120px" />
|
||||
</Flex.Item>
|
||||
<Flex.Item basis="50% ">
|
||||
<Button
|
||||
fluid
|
||||
icon="eye-dropper"
|
||||
onClick={() => act("select")}>
|
||||
Select Color
|
||||
</Button>
|
||||
<Button
|
||||
fluid
|
||||
icon="fill-drip"
|
||||
onClick={() => act("paint")}>
|
||||
Paint Items
|
||||
</Button>
|
||||
<Button
|
||||
fluid
|
||||
icon="tint-slash"
|
||||
onClick={() => act("clear")}>
|
||||
Remove Paintjob
|
||||
</Button>
|
||||
<Button
|
||||
fluid
|
||||
icon="eject"
|
||||
onClick={() => act("eject")}>
|
||||
Eject Items
|
||||
</Button>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
<Section title="Items">
|
||||
{items.map((item, i) => <Box key={i}>#{i+1}: {item}</Box>)}
|
||||
</Section>
|
||||
</Fragment>
|
||||
) || (
|
||||
<Section>
|
||||
<Box color="bad">No items inserted.</Box>
|
||||
</Section>
|
||||
)}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
78
tgui/packages/tgui/interfaces/CookingAppliance.js
Normal file
78
tgui/packages/tgui/interfaces/CookingAppliance.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import { round } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, AnimatedNumber } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
export const CookingAppliance = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
temperature,
|
||||
optimalTemp,
|
||||
temperatureEnough,
|
||||
efficiency,
|
||||
containersRemovable,
|
||||
our_contents,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Window width={600} height={600} resizable>
|
||||
<Window.Content scrollable>
|
||||
<Section title="Status">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Temperature">
|
||||
<ProgressBar
|
||||
color={temperatureEnough ? "good" : "blue"}
|
||||
value={temperature}
|
||||
maxValue={optimalTemp + 100}>
|
||||
<AnimatedNumber value={temperature} />°C / {optimalTemp}°C
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Efficiency">
|
||||
<AnimatedNumber value={efficiency} />%
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section title="Containers">
|
||||
<LabeledList>
|
||||
{our_contents.map((content, i) => {
|
||||
if (content.empty) {
|
||||
return (
|
||||
<LabeledList.Item label={"Slot #" + (i + 1)} >
|
||||
<Button
|
||||
onClick={() => act("slot", { slot: i + 1 })}>
|
||||
Empty
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LabeledList.Item label={"Slot #" + (i + 1)} verticalAlign="middle" key={i}>
|
||||
<Flex spacing={1}>
|
||||
<Flex.Item>
|
||||
<Button
|
||||
disabled={!containersRemovable}
|
||||
onClick={() => act("slot", { slot: i + 1 })}>
|
||||
{content.container || "No Container"}
|
||||
</Button>
|
||||
</Flex.Item>
|
||||
<Flex.Item grow={1}>
|
||||
<ProgressBar
|
||||
color={content.progressText[0]}
|
||||
value={content.progress}
|
||||
maxValue={1}>
|
||||
{content.progressText[1]}
|
||||
</ProgressBar>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</LabeledList.Item>
|
||||
);
|
||||
})}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
87
tgui/packages/tgui/interfaces/CryoStorage.js
Normal file
87
tgui/packages/tgui/interfaces/CryoStorage.js
Normal file
@@ -0,0 +1,87 @@
|
||||
import { useBackend, useLocalState } from "../backend";
|
||||
import { Box, Button, Section, Tabs, NoticeBox } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
export const CryoStorage = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
real_name,
|
||||
allow_items,
|
||||
} = data;
|
||||
|
||||
const [tab, setTab] = useLocalState(context, "tab", 0);
|
||||
|
||||
return (
|
||||
<Window width={400} height={600} resizable>
|
||||
<Window.Content scrollable>
|
||||
<Tabs>
|
||||
<Tabs.Tab
|
||||
selected={tab === 0}
|
||||
onClick={() => setTab(0)}>
|
||||
Crew
|
||||
</Tabs.Tab>
|
||||
{!!allow_items && (
|
||||
<Tabs.Tab
|
||||
selected={tab === 1}
|
||||
onClick={() => setTab(1)}>
|
||||
Items
|
||||
</Tabs.Tab>
|
||||
)}
|
||||
</Tabs>
|
||||
<NoticeBox info>Welcome, {real_name}.</NoticeBox>
|
||||
{tab === 0 && <CryoStorageCrew />}
|
||||
{!!allow_items && tab === 1 && <CryoStorageItems />}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
export const CryoStorageCrew = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
crew,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Section title="Stored Crew">
|
||||
{crew.length && crew.map(c => <Box key={c} color="label">{c}</Box>) || (
|
||||
<Box color="good">
|
||||
No crew currently stored.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export const CryoStorageItems = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
items,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Section title="Stored Items" buttons={
|
||||
<Button
|
||||
icon="hand-rock"
|
||||
onClick={() => act("allitems")}>
|
||||
Claim All
|
||||
</Button>
|
||||
}>
|
||||
{items.length && items.map(item => (
|
||||
<Button
|
||||
key={item.ref}
|
||||
icon="hand-rock"
|
||||
onClick={() => act("item", { ref: item.ref })}>
|
||||
{item.name}
|
||||
</Button>
|
||||
)) || (
|
||||
<Box color="average">
|
||||
No items stored.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
57
tgui/packages/tgui/interfaces/CryoStorageVr.js
Normal file
57
tgui/packages/tgui/interfaces/CryoStorageVr.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { useBackend, useLocalState } from "../backend";
|
||||
import { Box, Button, Section, Tabs, NoticeBox } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
import { CryoStorageCrew } from "./CryoStorage";
|
||||
|
||||
export const CryoStorageVr = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
real_name,
|
||||
allow_items,
|
||||
} = data;
|
||||
|
||||
const [tab, setTab] = useLocalState(context, "tab", 0);
|
||||
|
||||
return (
|
||||
<Window width={400} height={600} resizable>
|
||||
<Window.Content scrollable>
|
||||
<Tabs>
|
||||
<Tabs.Tab
|
||||
selected={tab === 0}
|
||||
onClick={() => setTab(0)}>
|
||||
Crew
|
||||
</Tabs.Tab>
|
||||
{!!allow_items && (
|
||||
<Tabs.Tab
|
||||
selected={tab === 1}
|
||||
onClick={() => setTab(1)}>
|
||||
Items
|
||||
</Tabs.Tab>
|
||||
)}
|
||||
</Tabs>
|
||||
<NoticeBox info>Welcome, {real_name}.</NoticeBox>
|
||||
{tab === 0 && <CryoStorageCrew />}
|
||||
{!!allow_items && tab === 1 && <CryoStorageItemsVr />}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
export const CryoStorageItemsVr = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
items,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Section title="Stored Items">
|
||||
{items.length && items.map(item => <Box color="label" key={item}>{item}</Box>) || (
|
||||
<Box color="average">
|
||||
No items stored.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
72
tgui/packages/tgui/interfaces/Holodeck.js
Normal file
72
tgui/packages/tgui/interfaces/Holodeck.js
Normal file
@@ -0,0 +1,72 @@
|
||||
import { round } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
export const Holodeck = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
supportedPrograms,
|
||||
restrictedPrograms,
|
||||
currentProgram,
|
||||
isSilicon,
|
||||
safetyDisabled,
|
||||
emagged,
|
||||
gravity,
|
||||
} = data;
|
||||
|
||||
let programsToShow = supportedPrograms;
|
||||
|
||||
if (safetyDisabled) {
|
||||
programsToShow = programsToShow.concat(restrictedPrograms);
|
||||
}
|
||||
|
||||
return (
|
||||
<Window width={400} height={610} resizable>
|
||||
<Window.Content scrollable>
|
||||
<Section title="Programs">
|
||||
{programsToShow.map(prog => (
|
||||
<Button
|
||||
key={prog}
|
||||
color={restrictedPrograms.indexOf(prog) !== -1 ? "bad" : null}
|
||||
icon="eye"
|
||||
content={prog}
|
||||
selected={currentProgram === prog}
|
||||
fluid
|
||||
onClick={() => act("program", { program: prog })} />
|
||||
))}
|
||||
</Section>
|
||||
{!!isSilicon && (
|
||||
<Section title="Override">
|
||||
<Button
|
||||
icon="exclamation-triangle"
|
||||
fluid
|
||||
disabled={emagged}
|
||||
color={safetyDisabled ? "good" : "bad"}
|
||||
onClick={() => act("AIoverride")}>
|
||||
{!!emagged && "Error, unable to control. "}
|
||||
{safetyDisabled ? "Enable Safeties" : "Disable Safeties"}
|
||||
</Button>
|
||||
</Section>
|
||||
)}
|
||||
<Section title="Controls">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Safeties">
|
||||
{safetyDisabled ? <Box color="bad">DISABLED</Box> : <Box color="good">ENABLED</Box>}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Gravity">
|
||||
<Button
|
||||
icon="user-astronaut"
|
||||
selected={gravity}
|
||||
onClick={() => act("gravity")}>
|
||||
{gravity ? "Enabled" : "Disabled"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
@@ -2,122 +2,7 @@ import { Box, Flex, LabeledList, Section, Icon } from "../components";
|
||||
import { useBackend } from "../backend";
|
||||
import { Window } from "../layouts";
|
||||
import { Fragment } from "inferno";
|
||||
|
||||
const rank2icon = {
|
||||
// Command
|
||||
'Colony Director': 'user-tie',
|
||||
'Site Manager': 'user-tie',
|
||||
'Overseer': 'user-tie',
|
||||
'Head of Personnel': 'briefcase',
|
||||
'Crew Resources Officer': 'briefcase',
|
||||
'Deputy Director': 'briefcase',
|
||||
'Command Secretary': 'user-tie',
|
||||
// Security
|
||||
'Head of Security': 'user-shield',
|
||||
'Security Commander': 'user-shield',
|
||||
'Chief of Security': 'user-shield',
|
||||
'Warden': ['city', 'shield-alt'],
|
||||
'Detective': 'search',
|
||||
'Forensic Technician': 'search',
|
||||
'Security Officer': 'user-shield',
|
||||
'Junior Officer': 'user-shield',
|
||||
// Engineering
|
||||
'Chief Engineer': 'toolbox',
|
||||
'Atmospheric Technician': 'wind',
|
||||
'Station Engineer': 'toolbox',
|
||||
'Maintenance Technician': 'wrench',
|
||||
'Engine Technician': 'toolbox',
|
||||
'Electrician': 'toolbox',
|
||||
// Medical
|
||||
'Chief Medical Officer': 'user-md',
|
||||
'Chemist': 'mortar-pestle',
|
||||
'Pharmacist': 'mortar-pestle',
|
||||
'Medical Doctor': 'user-md',
|
||||
'Surgeon': 'user-md',
|
||||
'Emergency Physician': 'user-md',
|
||||
'Nurse': 'user-md',
|
||||
'Virologist': 'disease',
|
||||
'Paramedic': 'ambulance',
|
||||
'Emergency Medical Technician': 'ambulance',
|
||||
'Psychiatrist': 'couch',
|
||||
'Psychologist': 'couch',
|
||||
// Science
|
||||
'Research Director': 'user-graduate',
|
||||
'Research Supervisor': 'user-graduate',
|
||||
'Roboticist': 'robot',
|
||||
'Biomechanical Engineer': ['wrench', 'heartbeat'],
|
||||
'Mechatronic Engineer': 'wrench',
|
||||
'Scientist': 'flask',
|
||||
'Xenoarchaeologist': 'flask',
|
||||
'Anomalist': 'flask',
|
||||
'Phoron Researcher': 'flask',
|
||||
'Circuit Designer': 'car-battery',
|
||||
'Xenobiologist': 'meteor',
|
||||
'Xenobotanist': ['biohazard', 'seedling'],
|
||||
// Cargo
|
||||
'Quartermaster': 'box-open',
|
||||
'Supply Chief': 'warehouse',
|
||||
'Cargo Technician': 'box-open',
|
||||
'Shaft Miner': 'hard-hat',
|
||||
'Drill Technician': 'hard-hat',
|
||||
// Exploration
|
||||
'Pathfinder': 'binoculars',
|
||||
'Explorer': 'user-astronaut',
|
||||
'Field Medic': ['user-md', 'user-astronaut'],
|
||||
'Pilot': 'space-shuttle',
|
||||
// Civvies
|
||||
'Bartender': 'glass-martini',
|
||||
'Barista': 'coffee',
|
||||
'Botanist': 'leaf',
|
||||
'Gardener': 'leaf',
|
||||
'Chaplain': 'place-of-worship',
|
||||
'Counselor': 'couch',
|
||||
'Chef': 'utensils',
|
||||
'Cook': 'utensils',
|
||||
'Entertainer': 'smile-beam',
|
||||
'Performer': 'smile-beam',
|
||||
'Musician': 'guitar',
|
||||
'Stagehand': 'smile-beam',
|
||||
// All of the interns
|
||||
'Intern': 'school',
|
||||
'Apprentice Engineer': ['school', 'wrench'],
|
||||
'Medical Intern': ['school', 'user-md'],
|
||||
'Lab Assistant': ['school', 'flask'],
|
||||
'Security Cadet': ['school', 'shield-alt'],
|
||||
'Jr. Cargo Tech': ['school', 'box'],
|
||||
'Jr. Explorer': ['school', 'user-astronaut'],
|
||||
'Server': ['school', 'utensils'],
|
||||
// Back to civvies
|
||||
'Internal Affairs Agent': 'balance-scale',
|
||||
'Janitor': 'broom',
|
||||
'Custodian': 'broom',
|
||||
'Sanitation Technician': 'hand-sparkles',
|
||||
'Maid': 'broom',
|
||||
'Librarian': 'book',
|
||||
'Journalist': 'newspaper',
|
||||
'Writer': 'book',
|
||||
'Historian': 'chalkboard-teacher',
|
||||
'Professor': 'chalkboard-teacher',
|
||||
'Visitor': 'user',
|
||||
// Special roles
|
||||
'Emergency Responder': 'fighter-jet',
|
||||
};
|
||||
const RankIcon = (props, context) => {
|
||||
const {
|
||||
rank,
|
||||
} = props;
|
||||
|
||||
let rankObj = rank2icon[rank];
|
||||
if (typeof rankObj === "string") {
|
||||
return <Icon inline color="label" name={rankObj} size={2} />;
|
||||
} else if (Array.isArray(rankObj)) {
|
||||
return rankObj.map(icon => (
|
||||
<Icon inline key={icon} color="label" name={icon} size={2} />
|
||||
));
|
||||
} else {
|
||||
return <Icon inline color="label" name="user" size={2} />;
|
||||
}
|
||||
};
|
||||
import { RankIcon } from "./common/RankIcon";
|
||||
|
||||
export const IDCard = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
|
||||
117
tgui/packages/tgui/interfaces/Jukebox.js
Normal file
117
tgui/packages/tgui/interfaces/Jukebox.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import { round } from 'common/math';
|
||||
import { sortBy } from 'common/collections';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, LabeledList, ProgressBar, Section, Slider } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
export const Jukebox = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
playing,
|
||||
loop_mode,
|
||||
volume,
|
||||
current_track_ref,
|
||||
current_track,
|
||||
percent,
|
||||
tracks,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Window width={450} height={600} resizable>
|
||||
<Window.Content scrollable>
|
||||
<Section title="Currently Playing">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Title">
|
||||
{playing && current_track && (
|
||||
<Box>
|
||||
{current_track.title} by {current_track.artist || "Unkown"}
|
||||
</Box>
|
||||
) || (
|
||||
<Box>
|
||||
Stopped
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Controls">
|
||||
<Button
|
||||
icon="play"
|
||||
disabled={playing}
|
||||
onClick={() => act("play")}>
|
||||
Play
|
||||
</Button>
|
||||
<Button
|
||||
icon="stop"
|
||||
disabled={!playing}
|
||||
onClick={() => act("stop")}>
|
||||
Stop
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Loop Mode">
|
||||
<Button
|
||||
icon="play"
|
||||
onClick={() => act("loopmode", { loopmode: 1 })}
|
||||
selected={loop_mode === 1}>
|
||||
Next
|
||||
</Button>
|
||||
<Button
|
||||
icon="random"
|
||||
onClick={() => act("loopmode", { loopmode: 2 })}
|
||||
selected={loop_mode === 2}>
|
||||
Shuffle
|
||||
</Button>
|
||||
<Button
|
||||
icon="redo"
|
||||
onClick={() => act("loopmode", { loopmode: 3 })}
|
||||
selected={loop_mode === 3}>
|
||||
Repeat
|
||||
</Button>
|
||||
<Button
|
||||
icon="step-forward"
|
||||
onClick={() => act("loopmode", { loopmode: 4 })}
|
||||
selected={loop_mode === 4}>
|
||||
Once
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Progress">
|
||||
<ProgressBar
|
||||
value={percent}
|
||||
maxValue={1}
|
||||
color="good" />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Volume">
|
||||
<Slider
|
||||
minValue={0}
|
||||
step={0.01}
|
||||
value={volume}
|
||||
maxValue={1}
|
||||
ranges={{
|
||||
good: [.75, Infinity],
|
||||
average: [.25, .75],
|
||||
bad: [0, .25],
|
||||
}}
|
||||
format={val => round(val * 100, 1) + "%"}
|
||||
onChange={(e, val) => act("volume", { val: round(val, 2) })} />
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section title="Available Tracks">
|
||||
{tracks.length && sortBy(a => a.title)(tracks).map(track => (
|
||||
<Button
|
||||
fluid
|
||||
icon="play"
|
||||
key={track.ref}
|
||||
selected={current_track_ref === track.ref}
|
||||
onClick={() => act("change_track", { change_track: track.ref })}>
|
||||
{track.title}
|
||||
</Button>
|
||||
)) || (
|
||||
<Box color="bad">
|
||||
Error: No songs loaded.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
60
tgui/packages/tgui/interfaces/LookingGlass.js
Normal file
60
tgui/packages/tgui/interfaces/LookingGlass.js
Normal file
@@ -0,0 +1,60 @@
|
||||
import { round } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
export const LookingGlass = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
supportedPrograms,
|
||||
currentProgram,
|
||||
immersion,
|
||||
gravity,
|
||||
} = data;
|
||||
|
||||
let height = Math.min(180 + (supportedPrograms.length * 23), 600);
|
||||
|
||||
return (
|
||||
<Window width={300} height={height} resizable>
|
||||
<Window.Content scrollable>
|
||||
<Section title="Programs">
|
||||
{supportedPrograms.map(program => (
|
||||
<Button
|
||||
key={program}
|
||||
fluid
|
||||
icon="eye"
|
||||
selected={program === currentProgram}
|
||||
onClick={() => act("program", { program: program })}>
|
||||
{program}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
<Section title="Controls">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Gravity">
|
||||
<Button
|
||||
fluid
|
||||
icon="user-astronaut"
|
||||
selected={gravity}
|
||||
onClick={() => act("gravity")}>
|
||||
{gravity ? "Enabled" : "Disabled"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Full Immersion">
|
||||
<Button
|
||||
mt={-1}
|
||||
fluid
|
||||
icon="eye"
|
||||
selected={immersion}
|
||||
onClick={() => act("immersion")}>
|
||||
{immersion ? "Enabled" : "Disabled"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
73
tgui/packages/tgui/interfaces/Microwave.js
Normal file
73
tgui/packages/tgui/interfaces/Microwave.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import { round } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
|
||||
export const Microwave = (props, context) => {
|
||||
const { act, config, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
broken,
|
||||
operating,
|
||||
dirty,
|
||||
items,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Window width={400} height={500} resizable>
|
||||
<Window.Content scrollable>
|
||||
{broken && (
|
||||
<Section>
|
||||
<Box color="bad">
|
||||
Bzzzzttttt!!
|
||||
</Box>
|
||||
</Section>
|
||||
) || operating && (
|
||||
<Section>
|
||||
<Box color="good">
|
||||
Microwaving in progress!<br />
|
||||
Please wait...!
|
||||
</Box>
|
||||
</Section>
|
||||
) || dirty && (
|
||||
<Section>
|
||||
<Box color="bad">
|
||||
This microwave is dirty!<br />
|
||||
Please clean it before use!
|
||||
</Box>
|
||||
</Section>
|
||||
) || items.length && (
|
||||
<Section level={1} title="Ingredients" buttons={
|
||||
<Fragment>
|
||||
<Button
|
||||
icon="radiation"
|
||||
onClick={() => act("cook")}>
|
||||
Microwave
|
||||
</Button>
|
||||
<Button
|
||||
icon="eject"
|
||||
onClick={() => act("dispose")}>
|
||||
Eject
|
||||
</Button>
|
||||
</Fragment>
|
||||
}>
|
||||
<LabeledList>
|
||||
{items.map(item => (
|
||||
<LabeledList.Item key={item.name} label={item.name}>
|
||||
{item.amt} {item.extra}
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
) || (
|
||||
<Section>
|
||||
<Box color="bad">
|
||||
{config.title} is empty.
|
||||
</Box>
|
||||
</Section>
|
||||
)}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
570
tgui/packages/tgui/interfaces/Newscaster.js
Normal file
570
tgui/packages/tgui/interfaces/Newscaster.js
Normal file
@@ -0,0 +1,570 @@
|
||||
import { decodeHtmlEntities } from 'common/string';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend, useSharedState } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, Input, ProgressBar, Section, NoticeBox } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
import { TemporaryNotice } from './common/TemporaryNotice';
|
||||
|
||||
const NEWSCASTER_SCREEN_MAIN = "Main Menu";
|
||||
const NEWSCASTER_SCREEN_NEWCHANNEL = "New Channel";
|
||||
const NEWSCASTER_SCREEN_VIEWLIST = "View List";
|
||||
const NEWSCASTER_SCREEN_NEWSTORY = "New Story";
|
||||
const NEWSCASTER_SCREEN_PRINT = "Print";
|
||||
const NEWSCASTER_SCREEN_NEWWANTED = "New Wanted";
|
||||
const NEWSCASTER_SCREEN_VIEWWANTED = "View Wanted";
|
||||
const NEWSCASTER_SCREEN_SELECTEDCHANNEL = "View Selected Channel";
|
||||
|
||||
export const Newscaster = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
screen,
|
||||
user,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Window width={600} height={600} resizable>
|
||||
<Window.Content scrollable>
|
||||
<TemporaryNotice decode />
|
||||
<NewscasterContent />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterContent = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
user,
|
||||
} = data;
|
||||
|
||||
const [screen, setScreen] = useSharedState(context, "screen", NEWSCASTER_SCREEN_MAIN);
|
||||
let Template = screenToTemplate[screen];
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Template setScreen={setScreen} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterMainMenu = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
securityCaster,
|
||||
wanted_issue,
|
||||
} = data;
|
||||
|
||||
const {
|
||||
setScreen,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Section title="Main Menu">
|
||||
{wanted_issue && (
|
||||
<Button fluid icon="eye" onClick={() => setScreen(NEWSCASTER_SCREEN_VIEWWANTED)} color="bad">
|
||||
Read WANTED Issue
|
||||
</Button>
|
||||
)}
|
||||
<Button fluid icon="eye" onClick={() => setScreen(NEWSCASTER_SCREEN_VIEWLIST)}>
|
||||
View Feed Channels
|
||||
</Button>
|
||||
<Button fluid icon="plus" onClick={() => setScreen(NEWSCASTER_SCREEN_NEWCHANNEL)}>
|
||||
Create Feed Channel
|
||||
</Button>
|
||||
<Button fluid icon="plus" onClick={() => setScreen(NEWSCASTER_SCREEN_NEWSTORY)}>
|
||||
Create Feed Message
|
||||
</Button>
|
||||
<Button fluid icon="print" onClick={() => setScreen(NEWSCASTER_SCREEN_PRINT)}>
|
||||
Print Newspaper
|
||||
</Button>
|
||||
</Section>
|
||||
{!!securityCaster && (
|
||||
<Section title="Feed Security Functions">
|
||||
<Button fluid icon="plus" onClick={() => setScreen(NEWSCASTER_SCREEN_NEWWANTED)}>
|
||||
Manage "Wanted" Issue
|
||||
</Button>
|
||||
</Section>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterNewChannel = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
channel_name,
|
||||
c_locked,
|
||||
user,
|
||||
} = data;
|
||||
|
||||
const {
|
||||
setScreen,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Section title="Creating new Feed Channel" buttons={
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Back
|
||||
</Button>
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Channel Name">
|
||||
<Input
|
||||
fluid
|
||||
value={decodeHtmlEntities(channel_name)}
|
||||
onInput={(e, val) => act("set_channel_name", { val: val })} />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Channel Author" color="good">
|
||||
{user}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Accept Public Feeds">
|
||||
<Button
|
||||
icon={c_locked ? "lock" : "lock-open"}
|
||||
selected={!c_locked}
|
||||
onClick={() => act("set_channel_lock")}>
|
||||
{c_locked ? "No" : "Yes"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Button
|
||||
fluid
|
||||
color="good"
|
||||
icon="plus"
|
||||
onClick={() => act("submit_new_channel")}>
|
||||
Submit Channel
|
||||
</Button>
|
||||
<Button
|
||||
fluid
|
||||
color="bad"
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterViewList = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
channels,
|
||||
} = data;
|
||||
|
||||
const {
|
||||
setScreen,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Section title="Station Feed Channels" buttons={
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Back
|
||||
</Button>
|
||||
}>
|
||||
{channels.map(channel => (
|
||||
<Button
|
||||
fluid
|
||||
key={channel.name}
|
||||
icon="eye"
|
||||
color={channel.admin ? "good" : channel.censored ? "bad" : ""}
|
||||
onClick={() => {
|
||||
act("show_channel", { show_channel: channel.ref });
|
||||
setScreen(NEWSCASTER_SCREEN_SELECTEDCHANNEL);
|
||||
}}>
|
||||
{decodeHtmlEntities(channel.name)}
|
||||
</Button>
|
||||
))}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterNewStory = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
channel_name,
|
||||
user,
|
||||
msg,
|
||||
photo_data,
|
||||
} = data;
|
||||
|
||||
const {
|
||||
setScreen,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Section title="Creating new Feed Message..." buttons={
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Back
|
||||
</Button>
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Receiving Channel">
|
||||
<Button
|
||||
fluid
|
||||
onClick={() => act("set_channel_receiving")}>
|
||||
{channel_name || "Unset"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Message Author" color="good">
|
||||
{user}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Message Body" verticalAlign="top">
|
||||
<Flex>
|
||||
<Flex.Item grow={1}>
|
||||
<Section width="99%" inline>
|
||||
{msg || "(no message yet)"}
|
||||
</Section>
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Button
|
||||
verticalAlign="top"
|
||||
onClick={() => act("set_new_message")}
|
||||
icon="pen"
|
||||
tooltip="Edit Message"
|
||||
tooltipPosition="left" />
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Attach Photo">
|
||||
<Button
|
||||
fluid
|
||||
icon="image"
|
||||
onClick={() => act("set_attachment")}>
|
||||
{photo_data ? "Photo Attached" : "No Photo"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Button
|
||||
fluid
|
||||
color="good"
|
||||
icon="plus"
|
||||
onClick={() => act("submit_new_message")}>
|
||||
Submit Message
|
||||
</Button>
|
||||
<Button
|
||||
fluid
|
||||
color="bad"
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterPrint = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
total_num,
|
||||
active_num,
|
||||
message_num,
|
||||
paper_remaining,
|
||||
} = data;
|
||||
|
||||
const {
|
||||
setScreen,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Section title="Printing" buttons={
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Back
|
||||
</Button>
|
||||
}>
|
||||
<Box color="label" mb={1}>
|
||||
Newscaster currently serves a total of {total_num} Feed channels, {active_num} of which are active,
|
||||
and a total of {message_num} Feed stories.
|
||||
</Box>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Liquid Paper remaining">
|
||||
{paper_remaining * 100} cm³
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Button
|
||||
mt={1}
|
||||
fluid
|
||||
color="good"
|
||||
icon="plus"
|
||||
onClick={() => act("print_paper")}>
|
||||
Print Paper
|
||||
</Button>
|
||||
<Button
|
||||
fluid
|
||||
color="bad"
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterNewWanted = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
channel_name,
|
||||
msg,
|
||||
photo_data,
|
||||
user,
|
||||
wanted_issue,
|
||||
} = data;
|
||||
|
||||
const {
|
||||
setScreen,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Section title="Wanted Issue Handler" buttons={
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Back
|
||||
</Button>
|
||||
}>
|
||||
<LabeledList>
|
||||
{!!wanted_issue && (
|
||||
<LabeledList.Item label="Already In Circulation">
|
||||
A wanted issue is already in circulation. You can edit or cancel it below.
|
||||
</LabeledList.Item>
|
||||
)}
|
||||
<LabeledList.Item label="Criminal Name">
|
||||
<Input
|
||||
fluid
|
||||
value={decodeHtmlEntities(channel_name)}
|
||||
onInput={(e, val) => act("set_channel_name", { val: val })} />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Description">
|
||||
<Input
|
||||
fluid
|
||||
value={decodeHtmlEntities(msg)}
|
||||
onInput={(e, val) => act("set_wanted_desc", { val: val })} />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Attach Photo">
|
||||
<Button
|
||||
fluid
|
||||
icon="image"
|
||||
onClick={() => act("set_attachment")}>
|
||||
{photo_data ? "Photo Attached" : "No Photo"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Prosecutor" color="good">
|
||||
{user}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Button
|
||||
mt={1}
|
||||
fluid
|
||||
color="good"
|
||||
icon="plus"
|
||||
onClick={() => act("submit_wanted")}>
|
||||
Submit Wanted Issue
|
||||
</Button>
|
||||
{!!wanted_issue && (
|
||||
<Button
|
||||
fluid
|
||||
color="average"
|
||||
icon="minus"
|
||||
onClick={() => act("cancel_wanted")}>
|
||||
Take Down Issue
|
||||
</Button>
|
||||
)}
|
||||
<Button
|
||||
fluid
|
||||
color="bad"
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Cancel
|
||||
</Button>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterViewWanted = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
wanted_issue,
|
||||
} = data;
|
||||
|
||||
const {
|
||||
setScreen,
|
||||
} = props;
|
||||
|
||||
if (!wanted_issue) {
|
||||
return (
|
||||
<Section title="No Outstanding Wanted Issues" buttons={
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Back
|
||||
</Button>
|
||||
}>
|
||||
There are no wanted issues currently outstanding.
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="--STATIONWIDE WANTED ISSUE--" color="bad" buttons={
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_MAIN)}>
|
||||
Back
|
||||
</Button>
|
||||
}>
|
||||
<Box color="white">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Submitted by" color="good">
|
||||
{decodeHtmlEntities(wanted_issue.author)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Divider />
|
||||
<LabeledList.Item label="Criminal">
|
||||
{decodeHtmlEntities(wanted_issue.criminal)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Description">
|
||||
{decodeHtmlEntities(wanted_issue.desc)}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Photo">
|
||||
{wanted_issue.img && <img src={wanted_issue.img} /> || "None"}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const NewscasterViewSelected = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
viewing_channel,
|
||||
securityCaster,
|
||||
company,
|
||||
} = data;
|
||||
|
||||
const {
|
||||
setScreen,
|
||||
} = props;
|
||||
|
||||
if (!viewing_channel) {
|
||||
return (
|
||||
<Section title="Channel Not Found" buttons={
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_VIEWLIST)}>
|
||||
Back
|
||||
</Button>
|
||||
}>
|
||||
The channel you were looking for no longer exists.
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title={decodeHtmlEntities(viewing_channel.name)} buttons={
|
||||
<Fragment>
|
||||
{!!securityCaster && (
|
||||
<Button.Confirm
|
||||
color="bad"
|
||||
icon="ban"
|
||||
confirmIcon="ban"
|
||||
content="Issue D-Notice"
|
||||
onClick={() => act("toggle_d_notice", { ref: viewing_channel.ref })} />
|
||||
)}
|
||||
<Button
|
||||
icon="undo"
|
||||
onClick={() => setScreen(NEWSCASTER_SCREEN_VIEWLIST)}>
|
||||
Back
|
||||
</Button>
|
||||
</Fragment>
|
||||
}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Channel Created By">
|
||||
{securityCaster && (
|
||||
<Button.Confirm
|
||||
color="bad"
|
||||
icon="strikethrough"
|
||||
confirmIcon="strikethrough"
|
||||
content={decodeHtmlEntities(viewing_channel.author)}
|
||||
tooltip="Censor?"
|
||||
confirmContent="Censor Author"
|
||||
onClick={() => act("censor_channel_author", { ref: viewing_channel.ref })} />
|
||||
) || (
|
||||
<Box>
|
||||
{decodeHtmlEntities(viewing_channel.author)}
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
{!!viewing_channel.censored && (
|
||||
<Box color="bad">
|
||||
ATTENTION: This channel has been deemed as threatening to the welfare of the station,
|
||||
and marked with a {company} D-Notice. No further feed story additions are allowed
|
||||
while the D-Notice is in effect.
|
||||
</Box>
|
||||
)}
|
||||
{!!viewing_channel.messages.length && viewing_channel.messages.map(message => (
|
||||
<Section key={message.ref}>
|
||||
- {decodeHtmlEntities(message.body)}
|
||||
{!!message.img && (
|
||||
<Box>
|
||||
<img src={"data:image/png;base64," + message.img} />
|
||||
{decodeHtmlEntities(message.caption) || null}
|
||||
</Box>
|
||||
)}
|
||||
<Box color="grey">
|
||||
[Story by {decodeHtmlEntities(message.author)} - {message.timestamp}]
|
||||
</Box>
|
||||
{!!securityCaster && (
|
||||
<Fragment>
|
||||
<Button.Confirm
|
||||
mt={1}
|
||||
color="bad"
|
||||
icon="strikethrough"
|
||||
confirmIcon="strikethrough"
|
||||
content="Censor Story"
|
||||
onClick={() => act("censor_channel_story_body", { ref: message.ref })} />
|
||||
<Button.Confirm
|
||||
color="bad"
|
||||
icon="strikethrough"
|
||||
confirmIcon="strikethrough"
|
||||
content="Censor Author"
|
||||
onClick={() => act("censor_channel_story_author", { ref: message.ref })} />
|
||||
</Fragment>
|
||||
)}
|
||||
</Section>
|
||||
)) || !viewing_channel.censored && (
|
||||
<Box color="average">
|
||||
No feed messages found in channel.
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
/* Must be at the bottom because of how the const lifting rules work */
|
||||
let screenToTemplate = {};
|
||||
screenToTemplate[NEWSCASTER_SCREEN_MAIN] = NewscasterMainMenu;
|
||||
screenToTemplate[NEWSCASTER_SCREEN_NEWCHANNEL] = NewscasterNewChannel;
|
||||
screenToTemplate[NEWSCASTER_SCREEN_VIEWLIST] = NewscasterViewList;
|
||||
screenToTemplate[NEWSCASTER_SCREEN_NEWSTORY] = NewscasterNewStory;
|
||||
screenToTemplate[NEWSCASTER_SCREEN_PRINT] = NewscasterPrint;
|
||||
screenToTemplate[NEWSCASTER_SCREEN_NEWWANTED] = NewscasterNewWanted;
|
||||
screenToTemplate[NEWSCASTER_SCREEN_VIEWWANTED] = NewscasterViewWanted;
|
||||
screenToTemplate[NEWSCASTER_SCREEN_SELECTEDCHANNEL] = NewscasterViewSelected;
|
||||
144
tgui/packages/tgui/interfaces/TimeClock.js
Normal file
144
tgui/packages/tgui/interfaces/TimeClock.js
Normal file
@@ -0,0 +1,144 @@
|
||||
import { toFixed } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, NoticeBox } from "../components";
|
||||
import { Window } from "../layouts";
|
||||
import { RankIcon } from "./common/RankIcon";
|
||||
|
||||
export const TimeClock = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
|
||||
const {
|
||||
department_hours,
|
||||
user_name,
|
||||
card,
|
||||
assignment,
|
||||
job_datum,
|
||||
allow_change_job,
|
||||
job_choices,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Window width={500} height={520} resizable>
|
||||
<Window.Content scrollable>
|
||||
<Section title="OOC">
|
||||
<NoticeBox>
|
||||
OOC Note: PTO acquired is account-wide and shared across all characters.
|
||||
Info listed below is not IC information.
|
||||
</NoticeBox>
|
||||
<Section level={2} title={"Time Off Balance for " + user_name}>
|
||||
<LabeledList>
|
||||
{Object.keys(department_hours).map(key => (
|
||||
<LabeledList.Item
|
||||
key={key}
|
||||
label={key}
|
||||
color={
|
||||
department_hours[key] > 6
|
||||
? "good"
|
||||
: department_hours[key] > 1
|
||||
? "average"
|
||||
: "bad"
|
||||
}>
|
||||
{toFixed(department_hours[key], 1)} {department_hours[key] === 1 ? "hour" : "hours"}
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Section>
|
||||
<Section title="Employee Info">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Employee ID">
|
||||
<Button
|
||||
fluid
|
||||
icon="user"
|
||||
onClick={() => act("id")}>
|
||||
{card || "Insert ID"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
{!!job_datum && (
|
||||
<Fragment>
|
||||
<LabeledList.Item label="Rank">
|
||||
<Box
|
||||
backgroundColor={job_datum.selection_color}
|
||||
p={0.8}>
|
||||
<Flex justify="space-between" align="center">
|
||||
<Flex.Item>
|
||||
<Box ml={1}>
|
||||
<RankIcon color="white" rank={job_datum.title} />
|
||||
</Box>
|
||||
</Flex.Item>
|
||||
<Flex.Item>
|
||||
<Box fontSize={1.5} inline mr={1}>
|
||||
{job_datum.title}
|
||||
</Box>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Box>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Departments">
|
||||
{job_datum.departments}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Pay Scale">
|
||||
{job_datum.economic_modifier}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="PTO Elegibility">
|
||||
{job_datum.timeoff_factor > 0 && (
|
||||
<Box>
|
||||
Earns PTO - {job_datum.pto_department}
|
||||
</Box>
|
||||
) || job_datum.timeoff_factor < 0 && (
|
||||
<Box>
|
||||
Requires PTO - {job_datum.pto_department}
|
||||
</Box>
|
||||
) || (
|
||||
<Box>
|
||||
Neutral
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</Fragment>
|
||||
)}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
{!!(allow_change_job && job_datum && job_datum.timeoff_factor !== 0 && assignment !== "Dismissed") && (
|
||||
<Section title="Employment Actions">
|
||||
{job_datum.timeoff_factor > 0 && (
|
||||
department_hours[job_datum.pto_department] > 0 && (
|
||||
<Button
|
||||
fluid
|
||||
icon="exclamation-triangle"
|
||||
onClick={() => act("switch-to-offduty")}>
|
||||
Go Off-Duty
|
||||
</Button>
|
||||
) || (
|
||||
<Box color="bad">
|
||||
Warning: You do not have enough accrued time off to go off-duty.
|
||||
</Box>
|
||||
)
|
||||
) || (
|
||||
Object.keys(job_choices).length && Object.keys(job_choices).map(job => {
|
||||
let alt_titles = job_choices[job];
|
||||
|
||||
return alt_titles.map(title => (
|
||||
<Button
|
||||
key={title}
|
||||
icon="suitcase"
|
||||
onClick={() => act("switch-to-onduty-rank", {
|
||||
"switch-to-onduty-rank": job,
|
||||
"switch-to-onduty-assignment": title,
|
||||
})}>
|
||||
{title}
|
||||
</Button>
|
||||
));
|
||||
}) || (
|
||||
<Box color="bad">
|
||||
No Open Positions - See Head Of Personnel
|
||||
</Box>
|
||||
)
|
||||
)}
|
||||
</Section>
|
||||
)}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
@@ -4,9 +4,6 @@ import { useBackend } from '../backend';
|
||||
import { Box, Button, Section, Table, LabeledList } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
const VENDING_MODE_PRODUCTS = 0;
|
||||
const VENDING_MODE_PURCHASESCREEN = 1;
|
||||
|
||||
const VendingRow = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
@@ -15,11 +12,21 @@ const VendingRow = (props, context) => {
|
||||
const {
|
||||
product,
|
||||
} = props;
|
||||
const free = (
|
||||
product.price === 0
|
||||
);
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell collapsing>
|
||||
{product.isatom && (
|
||||
<span
|
||||
className={classes([
|
||||
'vending32x32',
|
||||
product.path,
|
||||
])}
|
||||
style={{
|
||||
'vertical-align': 'middle',
|
||||
'horizontal-align': 'middle',
|
||||
}} />
|
||||
) || null}
|
||||
</Table.Cell>
|
||||
<Table.Cell bold color={product.color}>
|
||||
{product.name}
|
||||
</Table.Cell>
|
||||
@@ -51,25 +58,16 @@ const VendingRow = (props, context) => {
|
||||
export const Vending = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
mode,
|
||||
panel,
|
||||
} = data;
|
||||
|
||||
let body = null;
|
||||
|
||||
if (mode === VENDING_MODE_PRODUCTS) {
|
||||
body = <VendingProducts />;
|
||||
} else if (mode === VENDING_MODE_PURCHASESCREEN) {
|
||||
body = <VendingPurchaseScreen />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Window
|
||||
width={450}
|
||||
height={600}
|
||||
resizable>
|
||||
<Window.Content scrollable>
|
||||
{body}
|
||||
<VendingProducts />
|
||||
{panel ? (
|
||||
<VendingMaintenance />
|
||||
) : null}
|
||||
@@ -82,6 +80,10 @@ export const VendingProducts = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
coin,
|
||||
chargesMoney,
|
||||
user,
|
||||
userMoney,
|
||||
guestNotice,
|
||||
products,
|
||||
} = data;
|
||||
|
||||
@@ -89,6 +91,23 @@ export const VendingProducts = (props, context) => {
|
||||
let myproducts = products.filter(item => !!item);
|
||||
return (
|
||||
<Fragment>
|
||||
{!!chargesMoney && (
|
||||
<Section title="User">
|
||||
{user && (
|
||||
<Box>
|
||||
Welcome, <b>{user.name}</b>,
|
||||
{' '}
|
||||
<b>{user.job || 'Unemployed'}</b>!
|
||||
<br />
|
||||
Your balance is <b>{userMoney}₮ Thalers</b>.
|
||||
</Box>
|
||||
) || (
|
||||
<Box color="light-grey">
|
||||
{guestNotice}
|
||||
</Box>
|
||||
)}
|
||||
</Section>
|
||||
)}
|
||||
<Section title="Products">
|
||||
<Table>
|
||||
{myproducts.map(product => (
|
||||
@@ -112,37 +131,6 @@ export const VendingProducts = (props, context) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const VendingPurchaseScreen = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
product,
|
||||
price,
|
||||
message,
|
||||
message_err,
|
||||
} = data;
|
||||
|
||||
return (
|
||||
<Section title="Payment Confirmation" buttons={(
|
||||
<Button
|
||||
icon="undo"
|
||||
content="Cancel"
|
||||
onClick={() => act('cancelpurchase')} />
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Item selected">
|
||||
{product}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Charge">
|
||||
{price}₮
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Section mt={1} label="Message" color={message_err ? 'bad' : ''}>
|
||||
{message}
|
||||
</Section>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
export const VendingMaintenance = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
|
||||
119
tgui/packages/tgui/interfaces/common/RankIcon.js
Normal file
119
tgui/packages/tgui/interfaces/common/RankIcon.js
Normal file
@@ -0,0 +1,119 @@
|
||||
import { Icon } from "../../components";
|
||||
|
||||
const rank2icon = {
|
||||
// Command
|
||||
'Colony Director': 'user-tie',
|
||||
'Site Manager': 'user-tie',
|
||||
'Overseer': 'user-tie',
|
||||
'Head of Personnel': 'briefcase',
|
||||
'Crew Resources Officer': 'briefcase',
|
||||
'Deputy Director': 'briefcase',
|
||||
'Command Secretary': 'user-tie',
|
||||
// Security
|
||||
'Head of Security': 'user-shield',
|
||||
'Security Commander': 'user-shield',
|
||||
'Chief of Security': 'user-shield',
|
||||
'Warden': ['city', 'shield-alt'],
|
||||
'Detective': 'search',
|
||||
'Forensic Technician': 'search',
|
||||
'Security Officer': 'user-shield',
|
||||
'Junior Officer': 'user-shield',
|
||||
// Engineering
|
||||
'Chief Engineer': 'toolbox',
|
||||
'Atmospheric Technician': 'wind',
|
||||
'Station Engineer': 'toolbox',
|
||||
'Maintenance Technician': 'wrench',
|
||||
'Engine Technician': 'toolbox',
|
||||
'Electrician': 'toolbox',
|
||||
// Medical
|
||||
'Chief Medical Officer': 'user-md',
|
||||
'Chemist': 'mortar-pestle',
|
||||
'Pharmacist': 'mortar-pestle',
|
||||
'Medical Doctor': 'user-md',
|
||||
'Surgeon': 'user-md',
|
||||
'Emergency Physician': 'user-md',
|
||||
'Nurse': 'user-md',
|
||||
'Virologist': 'disease',
|
||||
'Paramedic': 'ambulance',
|
||||
'Emergency Medical Technician': 'ambulance',
|
||||
'Psychiatrist': 'couch',
|
||||
'Psychologist': 'couch',
|
||||
// Science
|
||||
'Research Director': 'user-graduate',
|
||||
'Research Supervisor': 'user-graduate',
|
||||
'Roboticist': 'robot',
|
||||
'Biomechanical Engineer': ['wrench', 'heartbeat'],
|
||||
'Mechatronic Engineer': 'wrench',
|
||||
'Scientist': 'flask',
|
||||
'Xenoarchaeologist': 'flask',
|
||||
'Anomalist': 'flask',
|
||||
'Phoron Researcher': 'flask',
|
||||
'Circuit Designer': 'car-battery',
|
||||
'Xenobiologist': 'meteor',
|
||||
'Xenobotanist': ['biohazard', 'seedling'],
|
||||
// Cargo
|
||||
'Quartermaster': 'box-open',
|
||||
'Supply Chief': 'warehouse',
|
||||
'Cargo Technician': 'box-open',
|
||||
'Shaft Miner': 'hard-hat',
|
||||
'Drill Technician': 'hard-hat',
|
||||
// Exploration
|
||||
'Pathfinder': 'binoculars',
|
||||
'Explorer': 'user-astronaut',
|
||||
'Field Medic': ['user-md', 'user-astronaut'],
|
||||
'Pilot': 'space-shuttle',
|
||||
// Civvies
|
||||
'Bartender': 'glass-martini',
|
||||
'Barista': 'coffee',
|
||||
'Botanist': 'leaf',
|
||||
'Gardener': 'leaf',
|
||||
'Chaplain': 'place-of-worship',
|
||||
'Counselor': 'couch',
|
||||
'Chef': 'utensils',
|
||||
'Cook': 'utensils',
|
||||
'Entertainer': 'smile-beam',
|
||||
'Performer': 'smile-beam',
|
||||
'Musician': 'guitar',
|
||||
'Stagehand': 'smile-beam',
|
||||
// All of the interns
|
||||
'Intern': 'school',
|
||||
'Apprentice Engineer': ['school', 'wrench'],
|
||||
'Medical Intern': ['school', 'user-md'],
|
||||
'Lab Assistant': ['school', 'flask'],
|
||||
'Security Cadet': ['school', 'shield-alt'],
|
||||
'Jr. Cargo Tech': ['school', 'box'],
|
||||
'Jr. Explorer': ['school', 'user-astronaut'],
|
||||
'Server': ['school', 'utensils'],
|
||||
// Back to civvies
|
||||
'Internal Affairs Agent': 'balance-scale',
|
||||
'Janitor': 'broom',
|
||||
'Custodian': 'broom',
|
||||
'Sanitation Technician': 'hand-sparkles',
|
||||
'Maid': 'broom',
|
||||
'Librarian': 'book',
|
||||
'Journalist': 'newspaper',
|
||||
'Writer': 'book',
|
||||
'Historian': 'chalkboard-teacher',
|
||||
'Professor': 'chalkboard-teacher',
|
||||
'Visitor': 'user',
|
||||
// Special roles
|
||||
'Emergency Responder': 'fighter-jet',
|
||||
};
|
||||
|
||||
export const RankIcon = (props, context) => {
|
||||
const {
|
||||
rank,
|
||||
color = 'label',
|
||||
} = props;
|
||||
|
||||
let rankObj = rank2icon[rank];
|
||||
if (typeof rankObj === "string") {
|
||||
return <Icon inline color={color} name={rankObj} size={2} />;
|
||||
} else if (Array.isArray(rankObj)) {
|
||||
return rankObj.map(icon => (
|
||||
<Icon inline key={icon} color={color} name={icon} size={2} />
|
||||
));
|
||||
} else {
|
||||
return <Icon inline color={color} name="user" size={2} />;
|
||||
}
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
import { decodeHtmlEntities } from 'common/string';
|
||||
import { useBackend } from "../../backend";
|
||||
import { Box, Button, NoticeBox } from "../../components";
|
||||
|
||||
@@ -15,6 +16,9 @@ import { Box, Button, NoticeBox } from "../../components";
|
||||
* @param {object} context
|
||||
*/
|
||||
export const TemporaryNotice = (_properties, context) => {
|
||||
const {
|
||||
decode,
|
||||
} = _properties;
|
||||
const { act, data } = useBackend(context);
|
||||
const { temp } = data;
|
||||
if (!temp) {
|
||||
@@ -24,7 +28,7 @@ export const TemporaryNotice = (_properties, context) => {
|
||||
return (
|
||||
<NoticeBox {...temporaryProperty}>
|
||||
<Box display="inline-block" verticalAlign="middle">
|
||||
{temp.text}
|
||||
{decode ? decodeHtmlEntities(temp.text) : temp.text}
|
||||
</Box>
|
||||
<Button
|
||||
icon="times-circle"
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
#include "code\_global_vars\bitfields.dm"
|
||||
#include "code\_global_vars\misc.dm"
|
||||
#include "code\_global_vars\mobs.dm"
|
||||
#include "code\_global_vars\religion.dm"
|
||||
#include "code\_global_vars\sensitive.dm"
|
||||
#include "code\_global_vars\lists\mapping.dm"
|
||||
#include "code\_global_vars\lists\misc.dm"
|
||||
|
||||
Reference in New Issue
Block a user