Revert "Merge branch 'master' of https://github.com/PolarisSS13/Polaris into NanoGrade"

This reverts commit 6bb5409349, reversing
changes made to f6a83d5ee0.
This commit is contained in:
SinTwo
2016-08-15 12:58:00 -04:00
parent 6bb5409349
commit eabefc538a
325 changed files with 3375 additions and 41824 deletions
-7
View File
@@ -6,11 +6,9 @@ env:
BYOND_MAJOR="510"
BYOND_MINOR="1346"
MACRO_COUNT=986
NODE_VERSION="4"
cache:
directories:
- tgui/node_modules
- $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}
addons:
@@ -21,13 +19,10 @@ addons:
- libstdc++6:i386
before_script:
- cd tgui && npm install && cd ..
- chmod +x ./install-byond.sh
- ./install-byond.sh
install:
- rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $NODE_VERSION
- npm install -g gulp-cli
- pip install --user PyYaml -q
- pip install --user beautifulsoup4 -q
@@ -39,8 +34,6 @@ script:
- awk -f tools/indentation.awk **/*.dm
- md5sum -c - <<< "88490b460c26947f5ec1ab1bb9fa9f17 *html/changelogs/example.yml"
- (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; echo "$num escapes (expecting ${MACRO_COUNT} or less)"; [ $num -le ${MACRO_COUNT} ])
- cd tgui && gulp
- cd ..
- source $HOME/BYOND-${BYOND_MAJOR}.${BYOND_MINOR}/byond/bin/byondsetup
- python tools/TagMatcher/tag-matcher.py ../..
- echo "#define UNIT_TEST 1" > code/_unit_tests.dm
-4
View File
@@ -1,4 +0,0 @@
#define UI_INTERACTIVE 2 // Green/Interactive
#define UI_UPDATE 1 // Orange/Updates Only
#define UI_DISABLED 0 // Red/Disabled
#define UI_CLOSE -1 // Closed
-5
View File
@@ -1,5 +0,0 @@
#define TICK_LIMIT_RUNNING 90
#define TICK_LIMIT_TO_RUN 85
#define TICK_CHECK ( world.tick_usage > TICK_LIMIT_RUNNING ? stoplag() : 0 )
#define CHECK_TICK if(world.tick_usage > TICK_LIMIT_RUNNING) stoplag()
-16
View File
@@ -1,22 +1,6 @@
#if DM_VERSION < 510
//Case Sensitive!
/proc/text2listEx(text, delimiter="\n")
var/delim_len = length(delimiter)
if(delim_len < 1) return list(text)
. = list()
var/last_found = 1
var/found
do
found = findtextEx(text, delimiter, last_found, 0)
. += copytext(text, last_found, found)
last_found = found + delim_len
while(found)
/proc/replacetext(text, find, replacement)
return jointext(splittext(text, find), replacement)
/proc/replacetextEx(text, find, replacement)
return jointext(text2listEx(text, find), replacement)
#endif
-28
View File
@@ -1,28 +0,0 @@
/proc/get_turf_pixel(atom/movable/AM)
if(!istype(AM))
return
//Find AM's matrix so we can use it's X/Y pixel shifts
var/matrix/M = matrix(AM.transform)
var/pixel_x_offset = AM.pixel_x + M.get_x_shift()
var/pixel_y_offset = AM.pixel_y + M.get_y_shift()
//Irregular objects
if(AM.bound_height != world.icon_size || AM.bound_width != world.icon_size)
var/icon/AMicon = icon(AM.icon, AM.icon_state)
pixel_x_offset += ((AMicon.Width()/world.icon_size)-1)*(world.icon_size*0.5)
pixel_y_offset += ((AMicon.Height()/world.icon_size)-1)*(world.icon_size*0.5)
qdel(AMicon)
//DY and DX
var/rough_x = round(round(pixel_x_offset,world.icon_size)/world.icon_size)
var/rough_y = round(round(pixel_y_offset,world.icon_size)/world.icon_size)
//Find coordinates
var/turf/T = get_turf(AM) //use AM's turfs, as it's coords are the same as AM's AND AM's coords are lost if it is inside another atom
var/final_x = T.x + rough_x
var/final_y = T.y + rough_y
if(final_x || final_y)
return locate(final_x, final_y, T.z)
-24
View File
@@ -323,30 +323,6 @@ proc/listclearnulls(list/list)
return (result + L.Copy(Li, 0))
return (result + R.Copy(Ri, 0))
/proc/sortByVar(var/list/L, var/key)
if(L.len < 2)
return L
var/middle = L.len / 2 + 1
return mergeVaredLists(sortByVar(L.Copy(0, middle), key), sortByVar(L.Copy(middle), key), key)
/proc/mergeVaredLists(var/list/L, var/list/R, var/key)
var/Li=1
var/Ri=1
var/list/result = new()
while(Li <= L.len && Ri <= R.len)
var/datum/LO = L[Li]
var/datum/RO = R[Ri]
if(LO.vars[key] > RO.vars[key])
// Works around list += list2 merging lists; it's not pretty but it works
result += "temp item"
result[result.len] = R[Ri++]
else
result += "temp item"
result[result.len] = L[Li++]
if(Li <= L.len)
return (result + L.Copy(Li, 0))
return (result + R.Copy(Ri, 0))
//Mergesort: any value in a list, preserves key=value structure
/proc/sortAssoc(var/list/L)
-7
View File
@@ -82,13 +82,6 @@
if(config.log_world_output)
diary << "\[[time_stamp()]]DD_OUTPUT: [text][log_end]"
/*
Standardized method for tracking startup times.
*/
/proc/log_startup_progress(var/message)
admin_notice("<span class='danger'>[message]</span>", R_DEBUG)
log_to_dd(message)
/proc/log_misc(text)
diary << "\[[time_stamp()]]MISC: [text][log_end]"
-8
View File
@@ -15,11 +15,3 @@
animate(src, transform = m120, time = speed, loops)
animate(transform = m240, time = speed)
animate(transform = m360, time = speed)
//The X pixel offset of this matrix
/matrix/proc/get_x_shift()
. = c
//The Y pixel offset of this matrix
/matrix/proc/get_y_shift()
. = f
+1 -13
View File
@@ -100,16 +100,4 @@ var/round_start_time = 0
/hook/startup/proc/set_roundstart_hour()
roundstart_hour = pick(2,7,12,17)
return 1
/*
Returns "watch handle" (really just a timestamp)
*/
/proc/start_watch()
return world.timeofday
/*
Returns number of seconds elapsed.
@param wh number The "Watch Handle" from start_watch(). (timestamp)
*/
/proc/stop_watch(wh)
return round(0.1*(world.timeofday-wh),0.1)
return 1
-12
View File
@@ -1315,15 +1315,3 @@ var/mob/dview/dview_mob = new
tY = max(1, min(world.maxy, origin.y + (text2num(tY) - (world.view + 1))))
return locate(tX, tY, tZ)
//Key thing that stops lag. Cornerstone of performance in ss13, Just sitting here, in unsorted.dm.
/proc/stoplag()
. = 1
sleep(world.tick_lag)
if(world.tick_usage > TICK_LIMIT_TO_RUN) //woke up, still not enough tick, sleep for more.
. += 2
sleep(world.tick_lag*2)
if(world.tick_usage > TICK_LIMIT_TO_RUN) //woke up, STILL not enough tick, sleep for more.
. += 4
sleep(world.tick_lag*4)
//you might be thinking of adding more steps to this, or making it use a loop and a counter var
// not worth it.
+12 -33
View File
@@ -66,9 +66,6 @@ world/loop_checks = 0
testing("GC: [refID] old enough to test: GCd_at_time: [GCd_at_time] time_to_kill: [time_to_kill] current: [world.time]")
#endif
if(A && A.gcDestroyed == GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake
#ifdef GC_FINDREF
LocateReferences(A)
#endif
// Something's still referring to the qdel'd object. Kill it.
testing("GC: -- \ref[A] | [A.type] was unable to be GC'd and was deleted --")
logging["[A.type]"]++
@@ -91,47 +88,29 @@ world/loop_checks = 0
#undef GC_COLLECTIONS_PER_TICK
#ifdef GC_FINDREF
/datum/controller/process/garbage_collector/proc/LocateReferences(var/atom/A)
testing("GC: Attempting to locate references to [A] | [A.type]. This is a potentially long-running operation.")
if(istype(A))
if(A.loc != null)
testing("GC: [A] | [A.type] is located in [A.loc] instead of null")
if(A.contents.len)
testing("GC: [A] | [A.type] has contents: [jointext(A.contents)]")
var/ref_count = 0
for(var/atom/atom)
ref_count += LookForRefs(atom, A)
for(var/datum/datum) // This is strictly /datum, not subtypes.
ref_count += LookForRefs(datum, A)
for(var/client/client)
ref_count += LookForRefs(client, A)
var/message = "GC: References found to [A] | [A.type]: [ref_count]."
if(!ref_count)
message += " Has likely been supplied as an 'in list' argment to a proc."
testing(message)
/datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/datum/A)
/datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/list/targ)
. = 0
for(var/V in D.vars)
if(V == "contents")
continue
if(!islist(D.vars[V]))
if(D.vars[V] == A)
if(istype(D.vars[V], /atom))
var/atom/A = D.vars[V]
if(A in targ)
testing("GC: [A] | [A.type] referenced by [D] | [D.type], var [V]")
. += 1
else
. += LookForListRefs(D.vars[V], A, D, V)
else if(islist(D.vars[V]))
. += LookForListRefs(D.vars[V], targ, D, V)
/datum/controller/process/garbage_collector/proc/LookForListRefs(var/list/L, var/datum/A, var/datum/D, var/V)
/datum/controller/process/garbage_collector/proc/LookForListRefs(var/list/L, var/list/targ, var/datum/D, var/V)
. = 0
for(var/F in L)
if(!islist(F))
if(F == A || L[F] == A)
if(istype(F, /atom))
var/atom/A = F
if(A in targ)
testing("GC: [A] | [A.type] referenced by [D] | [D.type], list [V]")
. += 1
else
. += LookForListRefs(F, A, D, "[F] in list [V]")
if(islist(F))
. += LookForListRefs(F, targ, D, "[F] in list [V]")
#endif
/datum/controller/process/garbage_collector/proc/AddTrash(datum/A)
-28
View File
@@ -1,28 +0,0 @@
var/global/datum/controller/process/tgui/tgui_process
/datum/controller/process/tgui
var/list/tg_open_uis = list() // A list of open UIs, grouped by src_object and ui_key.
var/list/processing_uis = list() // A list of processing UIs, ungrouped.
var/basehtml // The HTML base used for all UIs.
/datum/controller/process/tgui/setup()
name = "tgui"
schedule_interval = 10 // every 2 seconds
start_delay = 23
basehtml = file2text('tgui/tgui.html') // Read the HTML from disk.
tgui_process = src
/datum/controller/process/tgui/doWork()
for(var/gui in processing_uis)
var/datum/tgui/ui = gui
if(ui && ui.user && ui.src_object)
ui.process()
SCHECK
continue
processing_uis.Remove(ui)
SCHECK
/datum/controller/process/tgui/statProcess()
..()
stat(null, "[tgui_process.processing_uis.len] UI\s")
+11 -38
View File
@@ -21,13 +21,11 @@ datum/controller/game_controller/New()
qdel(master_controller)
master_controller = src
var/watch = 0
if(!job_master)
watch = start_watch()
job_master = new /datum/controller/occupations()
job_master.SetupOccupations()
job_master.LoadJobs("config/jobs.txt")
log_startup_progress("Job setup complete in [stop_watch(watch)]s.")
admin_notice("<span class='danger'>Job setup complete</span>", R_DEBUG)
if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase()
if(!syndicate_code_response) syndicate_code_response = generate_code_phrase()
@@ -46,56 +44,31 @@ datum/controller/game_controller/proc/setup()
datum/controller/game_controller/proc/setup_objects()
var/watch = start_watch()
var/count = 0
var/overwatch = start_watch() //Overall.
log_startup_progress("Populating asset cache...")
populate_asset_cache()
log_startup_progress(" Populated [asset_cache.len] assets in [stop_watch(watch)]s.")
watch = start_watch()
log_startup_progress("Initializing objects")
// sleep(-1)
admin_notice("<span class='danger'>Initializing objects</span>", R_DEBUG)
sleep(-1)
for(var/atom/movable/object in world)
if(isnull(object.gcDestroyed))
object.initialize()
count++
log_startup_progress(" Initialized [count] objects in [stop_watch(watch)]s.")
watch = start_watch()
count = 0
log_startup_progress("Initializing areas")
// sleep(-1)
admin_notice("<span class='danger'>Initializing areas</span>", R_DEBUG)
sleep(-1)
for(var/area/area in all_areas)
area.initialize()
count++
log_startup_progress(" Initialized [count] areas in [stop_watch(watch)]s.")
watch = start_watch()
count = 0
log_startup_progress("Initializing pipe networks")
// sleep(-1)
admin_notice("<span class='danger'>Initializing pipe networks</span>", R_DEBUG)
sleep(-1)
for(var/obj/machinery/atmospherics/machine in machines)
machine.build_network()
count++
log_startup_progress(" Initialized [count] pipe networks in [stop_watch(watch)]s.")
watch = start_watch()
count = 0
log_startup_progress("Initializing atmos machinery.")
// sleep(-1)
admin_notice("<span class='danger'>Initializing atmos machinery.</span>", R_DEBUG)
sleep(-1)
for(var/obj/machinery/atmospherics/unary/U in machines)
if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
var/obj/machinery/atmospherics/unary/vent_pump/T = U
T.broadcast_status()
count++
else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
T.broadcast_status()
count++
log_startup_progress(" Initialized [count] atmospherics devices in [stop_watch(watch)]s.")
log_startup_progress("Finished object initializations in [stop_watch(overwatch)]s.")
// Set up antagonists.
populate_antag_type_list()
@@ -103,5 +76,5 @@ datum/controller/game_controller/proc/setup_objects()
//Set up spawn points.
populate_spawn_points()
log_startup_progress("Initializations complete.")
// sleep(-1)
admin_notice("<span class='danger'>Initializations complete.</span>", R_DEBUG)
sleep(-1)
-31
View File
@@ -1,31 +0,0 @@
/datum
var/weakref
/datum/Destroy()
weakref = null // Clear this reference to ensure it's kept for as brief duration as possible.
. = ..()
//obtain a weak reference to a datum
/proc/weakref(datum/D)
if(D.gcDestroyed)
return
if(!D.weakref)
D.weakref = new /datum/weakref(D)
return D.weakref
/datum/weakref
var/ref
/datum/weakref/New(datum/D)
ref = "\ref[D]"
/datum/weakref/Destroy()
// A weakref datum should not be manually destroyed as it is a shared resource,
// rather it should be automatically collected by the BYOND GC when all references are gone.
return 0
/datum/weakref/proc/resolve()
var/datum/D = locate(ref)
if(D && D.weakref == src)
return D
return null
+3 -15
View File
@@ -286,7 +286,6 @@
occupantData["name"] = H.name
occupantData["stat"] = H.stat
occupantData["health"] = H.health
occupantData["maxHealth"] = H.maxHealth
occupantData["hasVirus"] = H.virus2.len
@@ -310,7 +309,6 @@
var/blood_volume = round(H.vessel.get_reagent_amount("blood"))
bloodData["volume"] = blood_volume
bloodData["percent"] = round(((blood_volume / 560)*100))
bloodData["bloodLevel"] = round(H.vessel.get_reagent_amount("blood"))
occupantData["blood"] = bloodData
@@ -331,10 +329,6 @@
organData["germ_level"] = E.germ_level
organData["bruteLoss"] = E.brute_dam
organData["fireLoss"] = E.burn_dam
organData["totalLoss"] = E.brute_dam + E.burn_dam
organData["maxHealth"] = E.max_damage
organData["bruised"] = E.min_bruised_damage
organData["broken"] = E.min_broken_damage
var/implantData[0]
for(var/obj/I in E.implants)
@@ -379,16 +373,13 @@
var/organData[0]
organData["name"] = I.name
if(I.status & ORGAN_ASSISTED)
organData["robotic"] = 1
organData["desc"] = "Assisted"
else if(I.robotic >= ORGAN_ROBOT)
organData["robotic"] = 2
organData["desc"] = "Mechanical"
else
organData["robotic"] = null
organData["desc"] = null
organData["germ_level"] = I.germ_level
organData["damage"] = I.damage
organData["maxHealth"] = I.max_damage
organData["bruised"] = I.min_broken_damage
organData["broken"] = I.min_bruised_damage
intOrganData.Add(list(organData))
@@ -426,9 +417,6 @@
printing = null
printing_text = null
if (href_list["ejectify"])
src.connected.eject()
/obj/machinery/body_scanconsole/proc/generate_printing_text()
var/dat = ""
+77 -61
View File
@@ -265,17 +265,20 @@ update_flag
return src.attack_hand(user)
/obj/machinery/portable_atmospherics/canister/attack_hand(var/mob/user as mob)
return src.tg_ui_interact(user)
return src.ui_interact(user)
/obj/machinery/portable_atmospherics/canister/ui_data(mob/user)
var/list/data = list()
/obj/machinery/portable_atmospherics/canister/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if (src.destroyed)
return
// this is the data which will be sent to the ui
var/data[0]
data["name"] = name
data["canLabel"] = can_label ? 1 : 0
data["portConnected"] = connected_port ? 1 : 0
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
data["releasePressure"] = round(release_pressure ? release_pressure : 0)
data["minReleasePressure"] = round(ONE_ATMOSPHERE/10)
data["defaultReleasePressure"] = ONE_ATMOSPHERE
data["maxReleasePressure"] = round(10*ONE_ATMOSPHERE)
data["valveOpen"] = valve_open ? 1 : 0
@@ -283,70 +286,83 @@ update_flag
if (holding)
data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure()))
return data
/obj/machinery/portable_atmospherics/canister/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_physical_state)
if (src.destroyed)
return
ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "canister", name, 400, 400, master_ui, state)
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "canister.tmpl", "Canister", 480, 400)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/portable_atmospherics/canister/ui_status(mob/user, datum/ui_state/state)
if(!istype(src.loc, /turf))
return UI_CLOSE
return ..()
/obj/machinery/portable_atmospherics/canister/Topic(href, href_list)
/obj/machinery/portable_atmospherics/canister/ui_act(action, params)
switch(action)
if("relabel")
if (can_label)
var/list/colors = list(\
"\[N2O\]" = "redws", \
"\[N2\]" = "red", \
"\[O2\]" = "blue", \
"\[Phoron\]" = "orange", \
"\[CO2\]" = "black", \
"\[Air\]" = "grey", \
"\[CAUTION\]" = "yellow", \
)
var/label = input("Choose canister label", "Gas canister") as null|anything in colors
if (label)
src.canister_color = colors[label]
src.icon_state = colors[label]
src.name = "\improper Canister: [label]"
if("pressure")
var/diff = text2num(params["adjust"])
if(diff > 0)
release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff)
//Do not use "if(..()) return" here, canisters will stop working in unpowered areas like space or on the derelict. // yeah but without SOME sort of Topic check any dick can mess with them via exploits as he pleases -walter0o
//First comment might be outdated.
if (!istype(src.loc, /turf))
return 0
if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) // exploit protection -walter0o
usr << browse(null, "window=canister")
onclose(usr, "canister")
return
if(href_list["toggle"])
if (valve_open)
if (holding)
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the [holding]<br>"
else
release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff)
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the <font color='red'><b>air</b></font><br>"
else
if (holding)
release_log += "Valve was <b>opened</b> by [usr] ([usr.ckey]), starting the transfer into the [holding]<br>"
else
release_log += "Valve was <b>opened</b> by [usr] ([usr.ckey]), starting the transfer into the <font color='red'><b>air</b></font><br>"
log_open()
valve_open = !valve_open
if("valve")
if (href_list["remove_tank"])
if(holding)
if (valve_open)
if (holding)
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the [holding]<br>"
else
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the <font color='red'><b>air</b></font><br>"
else
if (holding)
release_log += "Valve was <b>opened</b> by [usr] ([usr.ckey]), starting the transfer into the [holding]<br>"
else
release_log += "Valve was <b>opened</b> by [usr] ([usr.ckey]), starting the transfer into the <font color='red'><b>air</b></font><br>"
log_open()
valve_open = !valve_open
valve_open = 0
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the [holding]<br>"
if(istype(holding, /obj/item/weapon/tank))
holding.manipulated_by = usr.real_name
holding.loc = loc
holding = null
if("eject")
if(holding)
if (valve_open)
valve_open = 0
release_log += "Valve was <b>closed</b> by [usr] ([usr.ckey]), stopping the transfer into the [holding]<br>"
if(istype(holding, /obj/item/weapon/tank))
holding.manipulated_by = usr.real_name
holding.loc = loc
holding = null
return TRUE
if (href_list["pressure_adj"])
var/diff = text2num(href_list["pressure_adj"])
if(diff > 0)
release_pressure = min(10*ONE_ATMOSPHERE, release_pressure+diff)
else
release_pressure = max(ONE_ATMOSPHERE/10, release_pressure+diff)
if (href_list["relabel"])
if (can_label)
var/list/colors = list(\
"\[N2O\]" = "redws", \
"\[N2\]" = "red", \
"\[O2\]" = "blue", \
"\[Phoron\]" = "orange", \
"\[CO2\]" = "black", \
"\[Air\]" = "grey", \
"\[CAUTION\]" = "yellow", \
)
var/label = input("Choose canister label", "Gas canister") as null|anything in colors
if (label)
src.canister_color = colors[label]
src.icon_state = colors[label]
src.name = "Canister: [label]"
src.add_fingerprint(usr)
update_icon()
return 1
/obj/machinery/portable_atmospherics/canister/phoron/New()
..()
@@ -11,91 +11,103 @@
req_access = list(access_engine)
var/secure = 0 //if set, then wires will be randomized and bolts will drop if the door is broken
var/list/conf_access = list()
var/list/conf_access = null
var/one_access = 0 //if set to 1, door would receive req_one_access instead of req_access
var/last_configurator = null
var/locked = 1
/obj/item/weapon/airlock_electronics/attack_self(mob/user as mob)
if (!ishuman(user) && !istype(user,/mob/living/silicon/robot))
return ..(user)
attack_self(mob/user as mob)
if (!ishuman(user) && !istype(user,/mob/living/silicon/robot))
return ..(user)
tg_ui_interact(user)
var/t1 = text("<B>Access control</B><br>\n")
//tgui interact code generously lifted from tgstation.
/obj/item/weapon/airlock_electronics/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, \
datum/tgui/master_ui = null, datum/ui_state/state = hands_state)
if (last_configurator)
t1 += "Operator: [last_configurator]<br>"
tgui_process.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "airlock_electronics", src.name, 1000, 500, master_ui, state)
ui.open()
if (locked)
t1 += "<a href='?src=\ref[src];login=1'>Swipe ID</a><hr>"
else
t1 += "<a href='?src=\ref[src];logout=1'>Block</a><hr>"
/obj/item/weapon/airlock_electronics/ui_data(mob/user)
var/list/data = list()
var/list/regions = list()
t1 += "Access requirement is set to "
t1 += one_access ? "<a style='color: green' href='?src=\ref[src];one_access=1'>ONE</a><hr>" : "<a style='color: red' href='?src=\ref[src];one_access=1'>ALL</a><hr>"
for(var/i in ACCESS_REGION_SECURITY to ACCESS_REGION_SUPPLY) //code/game/jobs/_access_defs.dm
var/list/region = list()
var/list/accesses = list()
for(var/j in get_region_accesses(i))
var/list/access = list()
access["name"] = get_access_desc(j)
access["id"] = j
access["req"] = (j in src.conf_access)
accesses[++accesses.len] = access
region["name"] = get_region_accesses_name(i)
region["accesses"] = accesses
regions[++regions.len] = region
data["regions"] = regions
data["oneAccess"] = one_access
data["locked"] = locked
t1 += conf_access == null ? "<font color=red>All</font><br>" : "<a href='?src=\ref[src];access=all'>All</a><br>"
return data
t1 += "<br>"
/obj/item/weapon/airlock_electronics/ui_act(action, params)
if(..())
return TRUE
switch(action)
if("clear")
conf_access = list()
one_access = 0
return TRUE
if("one_access")
one_access = !one_access
return TRUE
if("set")
var/access = text2num(params["access"])
if (!(access in conf_access))
conf_access += access
else
conf_access -= access
return TRUE
if("unlock")
var/list/accesses = get_all_station_access()
for (var/acc in accesses)
var/aname = get_access_desc(acc)
if (!conf_access || !conf_access.len || !(acc in conf_access))
t1 += "<a href='?src=\ref[src];access=[acc]'>[aname]</a><br>"
else if(one_access)
t1 += "<a style='color: green' href='?src=\ref[src];access=[acc]'>[aname]</a><br>"
else
t1 += "<a style='color: red' href='?src=\ref[src];access=[acc]'>[aname]</a><br>"
t1 += text("<p><a href='?src=\ref[];close=1'>Close</a></p>\n", src)
user << browse(t1, "window=airlock_electronics")
onclose(user, "airlock")
Topic(href, href_list)
..()
if (usr.stat || usr.restrained() || (!ishuman(usr) && !istype(usr,/mob/living/silicon)))
return
if (href_list["close"])
usr << browse(null, "window=airlock")
return
if (href_list["login"])
if(istype(usr,/mob/living/silicon))
locked = 0
last_configurator = usr.name
return TRUE
src.locked = 0
src.last_configurator = usr.name
else
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/device/pda))
var/obj/item/device/pda/pda = I
I = pda.id
if(!istype(I, /obj/item/weapon/card/id))
usr << "<span class='warning'>[\src] flashes a yellow LED near the ID scanner. Did you remember to scan your ID or PDA?</span>"
return TRUE
if (I && src.check_access(I))
locked = 0
last_configurator = I:registered_name
else
usr << "<span class='warning'>[\src] flashes a red LED near the ID scanner, indicating your access has been denied.</span>"
return TRUE
if("lock")
src.locked = 0
src.last_configurator = I:registered_name
if (locked)
return
if (href_list["logout"])
locked = 1
. = TRUE
if (href_list["one_access"])
one_access = !one_access
if (href_list["access"])
toggle_access(href_list["access"])
attack_self(usr)
proc
toggle_access(var/acc)
if (acc == "all")
conf_access = null
else
var/req = text2num(acc)
if (conf_access == null)
conf_access = list()
if (!(req in conf_access))
conf_access += req
else
conf_access -= req
if (!conf_access.len)
conf_access = null
/obj/item/weapon/airlock_electronics/secure
name = "secure airlock electronics"
desc = "designed to be somewhat more resistant to hacking than standard electronics."
origin_tech = list(TECH_DATA = 2)
secure = 1
secure = 1
+107 -54
View File
@@ -53,6 +53,7 @@
return
return
//Main door timer loop, if it's timing and time is >0 reduce time by 1.
// if it's less than 0, open door, reset timer
// update the door_timer window and the icon
@@ -67,10 +68,12 @@
if(timeleft > 1e5)
src.releasetime = 0
if(world.timeofday > src.releasetime)
src.timer_end() // open doors, reset timer, clear status screen
src.timing = 0
src.updateUsrDialog()
src.update_icon()
else
@@ -78,12 +81,14 @@
return
// has the door power situation changed, if so update icon.
/obj/machinery/door_timer/power_change()
..()
update_icon()
return
// open/closedoor checks if door_timer has power, if so it checks if the
// linked door is open/closed (by density) then opens it/closes it.
@@ -94,9 +99,6 @@
// Set releasetime
releasetime = world.timeofday + timetoset
//set timing
timing = 1
for(var/obj/machinery/door/window/brigdoor/door in targets)
if(door.density) continue
spawn(0)
@@ -109,6 +111,7 @@
C.icon_state = C.icon_locked
return 1
// Opens and unlocks doors, power check
/obj/machinery/door_timer/proc/timer_end()
if(stat & (NOPOWER|BROKEN)) return 0
@@ -116,9 +119,6 @@
// Reset releasetime
releasetime = 0
//reset timing
timing = 0
for(var/obj/machinery/door/window/brigdoor/door in targets)
if(!door.density) continue
spawn(0)
@@ -132,6 +132,7 @@
return 1
// Check for releasetime timeleft
/obj/machinery/door_timer/proc/timeleft()
. = (releasetime - world.timeofday)/10
@@ -151,62 +152,116 @@
/obj/machinery/door_timer/attack_ai(var/mob/user as mob)
return src.attack_hand(user)
//Allows humans to use door_timer
//Opens dialog window when someone clicks on door timer
// Allows altering timer and the timing boolean.
// Flasher activation limited to 150 seconds
/obj/machinery/door_timer/attack_hand(var/mob/user as mob)
tg_ui_interact(user)
/obj/machinery/door_timer/ui_data(mob/user)
var/list/data = list()
data["timing"] = timing
data["releasetime"] = releasetime
data["timetoset"] = timetoset
data["timeleft"] = timeleft()
var/list/flashes = list()
for(var/obj/machinery/flasher/flash in targets)
var/list/flashdata = list()
if(flash.last_flash && (flash.last_flash + 150) > world.time)
flashdata["status"] = 0
else
flashdata["status"] = 1
flashes[++flashes.len] = flashdata
data["flashes"] = flashes
return data
/obj/machinery/door_timer/ui_act(action, params)
if(..())
return TRUE
return
src.add_fingerprint(usr)
// Used for the 'time left' display
var/second = round(timeleft() % 60)
var/minute = round((timeleft() - second) / 60)
// Used for 'set timer'
var/setsecond = round((timetoset / 10) % 60)
var/setminute = round(((timetoset / 10) - setsecond) / 60)
user.set_machine(src)
// dat
var/dat = "<HTML><BODY><TT>"
dat += "<HR>Timer System:</hr>"
dat += " <b>Door [src.id] controls</b><br/>"
// Start/Stop timer
if (src.timing)
dat += "<a href='?src=\ref[src];timing=0'>Stop Timer and open door</a><br/>"
else
dat += "<a href='?src=\ref[src];timing=1'>Activate Timer and close door</a><br/>"
// Time Left display (uses releasetime)
dat += "Time Left: [(minute ? text("[minute]:") : null)][second] <br/>"
dat += "<br/>"
// Set Timer display (uses timetoset)
if(src.timing)
dat += "Set Timer: [(setminute ? text("[setminute]:") : null)][setsecond] <a href='?src=\ref[src];change=1'>Set</a><br/>"
else
dat += "Set Timer: [(setminute ? text("[setminute]:") : null)][setsecond]<br/>"
// Controls
dat += "<a href='?src=\ref[src];tp=-60'>-</a> <a href='?src=\ref[src];tp=-1'>-</a> <a href='?src=\ref[src];tp=1'>+</a> <A href='?src=\ref[src];tp=60'>+</a><br/>"
// Mounted flash controls
for(var/obj/machinery/flasher/F in targets)
if(F.last_flash && (F.last_flash + 150) > world.time)
dat += "<br/><A href='?src=\ref[src];fc=1'>Flash Charging</A>"
else
dat += "<br/><A href='?src=\ref[src];fc=1'>Activate Flash</A>"
dat += "<br/><br/><a href='?src=\ref[user];mach_close=computer'>Close</a>"
dat += "</TT></BODY></HTML>"
user << browse(dat, "window=computer;size=400x500")
onclose(user, "computer")
return
//Function for using door_timer dialog input, checks if user has permission
// href_list to
// "timing" turns on timer
// "tp" value to modify timer
// "fc" activates flasher
// "change" resets the timer to the timetoset amount while the timer is counting down
// Also updates dialog window and timer icon
/obj/machinery/door_timer/Topic(href, href_list)
if(..())
return
if(!src.allowed(usr))
return TRUE
return
switch (action)
if("start")
if(timetoset > 18000)
log_admin("[key_name(usr)] has started a brig timer over 30 minutes in length!")
message_admins("[key_name_admin(usr)] has started a brig timer over 30 minutes in length!")
timer_start()
if("stop")
timer_end()
if("flash")
usr.set_machine(src)
if(href_list["timing"])
src.timing = text2num(href_list["timing"])
if(src.timing)
src.timer_start()
else
src.timer_end()
else
if(href_list["tp"]) //adjust timer, close door if not already closed
var/tp = text2num(href_list["tp"])
var/addtime = (timetoset / 10)
addtime += tp
addtime = min(max(round(addtime), 0), 3600)
timeset(addtime)
if(href_list["fc"])
for(var/obj/machinery/flasher/F in targets)
F.flash()
if("time")
timetoset += text2num(params["adjust"])
timetoset = Clamp(timetoset, 0, 36000)
if(href_list["change"])
src.timer_start()
src.add_fingerprint(usr)
src.updateUsrDialog()
src.update_icon()
return TRUE
/obj/machinery/door_timer/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "brig_timer", name , 300, 150, master_ui, state)
ui.open()
/* if(src.timing)
src.timer_start()
else
src.timer_end() */
return
//icon update function
// if NOPOWER, display blank
@@ -227,9 +282,7 @@
disp2 = "Error"
update_display(disp1, disp2)
else
if(maptext)
maptext = ""
update_display("Set","Time") // would be nice to have some default printed text
if(maptext) maptext = ""
return
+1
View File
@@ -31,6 +31,7 @@
var/close_door_at = 0 //When to automatically close the door, if possible
//Multi-tile doors
dir = EAST
var/width = 1
// turf animation
-1
View File
@@ -1,7 +1,6 @@
//Terribly sorry for the code doubling, but things go derpy otherwise.
/obj/machinery/door/airlock/multi_tile
width = 2
dir = EAST
/obj/machinery/door/airlock/multi_tile/New()
..()
+73 -70
View File
@@ -8,7 +8,7 @@ datum/track/New(var/title_name, var/audio)
title = title_name
sound = audio
/obj/machinery/media/jukebox
/obj/machinery/media/jukebox/
name = "space jukebox"
icon = 'icons/obj/jukebox.dmi'
icon_state = "jukebox2-nopower"
@@ -44,11 +44,10 @@ datum/track/New(var/title_name, var/audio)
component_parts += new /obj/item/weapon/stock_parts/console_screen(src)
component_parts += new /obj/item/stack/cable_coil(src, 5)
RefreshParts()
update_icon()
/obj/machinery/media/jukebox/Destroy()
StopPlaying()
. = ..()
..()
/obj/machinery/media/jukebox/power_change()
if(!powered(power_channel) || !anchored)
@@ -75,7 +74,10 @@ datum/track/New(var/title_name, var/audio)
else
overlays += "[state_base]-running"
/obj/machinery/media/jukebox/interact(mob/user)
/obj/machinery/media/jukebox/Topic(href, href_list)
if(..() || !(Adjacent(usr) || istype(usr, /mob/living/silicon)))
return
if(!anchored)
usr << "<span class='warning'>You must secure \the [src] first.</span>"
return
@@ -84,73 +86,69 @@ datum/track/New(var/title_name, var/audio)
usr << "\The [src] doesn't appear to function."
return
tg_ui_interact(user)
/obj/machinery/media/jukebox/ui_status(mob/user, datum/ui_state/state)
if(!anchored || inoperable())
return UI_CLOSE
return ..()
/obj/machinery/media/jukebox/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_default_state)
ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "jukebox", "RetroBox - Space Style", 340, 440, master_ui, state)
ui.open()
/obj/machinery/media/jukebox/ui_data()
var/list/juke_tracks = new
for(var/datum/track/T in tracks)
juke_tracks.Add(T.title)
var/list/data = list(
"current_track" = current_track != null ? current_track.title : "No track selected",
"playing" = playing,
"tracks" = juke_tracks
)
return data
/obj/machinery/media/jukebox/ui_act(action, params)
if(..())
return TRUE
switch(action)
if("change_track")
for(var/datum/track/T in tracks)
if(T.title == params["title"])
current_track = T
StartPlaying()
break
. = TRUE
if("stop")
StopPlaying()
. = TRUE
if("play")
if(emagged)
emag_play()
else if(!current_track)
usr << "No track selected."
else
if(href_list["change_track"])
for(var/datum/track/T in tracks)
if(T.title == href_list["title"])
current_track = T
StartPlaying()
. = TRUE
/obj/machinery/media/jukebox/proc/emag_play()
playsound(loc, 'sound/items/AirHorn.ogg', 100, 1)
for(var/mob/living/carbon/M in ohearers(6, src))
if(istype(M, /mob/living/carbon/human))
var/mob/living/carbon/human/H = M
if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs))
continue
M.sleeping = 0
M.stuttering += 20
M.ear_deaf += 30
M.Weaken(3)
if(prob(30))
M.Stun(10)
M.Paralyse(4)
break
else if(href_list["stop"])
StopPlaying()
else if(href_list["play"])
if(emagged)
playsound(src.loc, 'sound/items/AirHorn.ogg', 100, 1)
for(var/mob/living/carbon/M in ohearers(6, src))
if(M.get_ear_protection() >= 2)
continue
M.sleeping = 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)
usr << "No track selected."
else
M.make_jittery(500)
spawn(15)
explode()
StartPlaying()
return 1
/obj/machinery/media/jukebox/interact(mob/user)
if(stat & (NOPOWER|BROKEN))
usr << "\The [src] doesn't appear to function."
return
ui_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]
if(!(stat & (NOPOWER|BROKEN)))
data["current_track"] = current_track != null ? current_track.title : ""
data["playing"] = playing
var/list/nano_tracks = new
for(var/datum/track/T in tracks)
nano_tracks[++nano_tracks.len] = list("track" = T.title)
data["tracks"] = nano_tracks
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "jukebox.tmpl", title, 450, 600)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
ui.open()
/obj/machinery/media/jukebox/attack_ai(mob/user as mob)
return src.attack_hand(user)
@@ -174,6 +172,10 @@ datum/track/New(var/title_name, var/audio)
/obj/machinery/media/jukebox/attackby(obj/item/W as obj, mob/user as mob)
src.add_fingerprint(user)
if(default_deconstruction_screwdriver(user, W))
return
if(default_deconstruction_crowbar(user, W))
return
if(istype(W, /obj/item/weapon/wrench))
if(playing)
StopPlaying()
@@ -198,6 +200,7 @@ datum/track/New(var/title_name, var/audio)
// Always kill the current sound
for(var/mob/living/M in mobs_in_area(main_area))
M << sound(null, channel = 1)
main_area.forced_ambience = null
playing = 0
update_use_power(1)
@@ -217,4 +220,4 @@ datum/track/New(var/title_name, var/audio)
playing = 1
update_use_power(2)
update_icon()
update_icon()
+6 -10
View File
@@ -90,8 +90,6 @@
/datum/feed_network/proc/insert_message_in_channel(var/datum/feed_channel/FC, var/datum/feed_message/newMsg)
FC.messages += newMsg
if(newMsg.img)
register_asset("newscaster_photo_[sanitize(FC.channel_name)]_[FC.messages.len].png", newMsg.img)
newMsg.parent_channel = FC
FC.update()
alert_readers(FC.announcement)
@@ -379,12 +377,11 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
else
var/i = 0
for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages)
++i
i++
dat+="-[MESSAGE.body] <BR>"
if(MESSAGE.img)
var/resourc_name = "newscaster_photo_[sanitize(viewing_channel.channel_name)]_[i].png"
send_asset(usr.client, resourc_name)
dat+="<img src='[resourc_name]' width = '180'><BR>"
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>"
@@ -877,12 +874,11 @@ obj/item/weapon/newspaper/attack_self(mob/user as mob)
dat+="<ul>"
var/i = 0
for(var/datum/feed_message/MESSAGE in C.messages)
++i
i++
dat+="-[MESSAGE.body] <BR>"
if(MESSAGE.img)
var/resourc_name = "newscaster_photo_[sanitize(C.channel_name)]_[i].png"
send_asset(user.client, resourc_name)
dat+="<img src='[resourc_name]' width = '180'><BR>"
user << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
dat+="<img src='tmp_photo[i].png' width = '180'><BR>"
dat+="<FONT SIZE=1>\[[MESSAGE.message_type] by <FONT COLOR='maroon'>[MESSAGE.author]</FONT>\]</FONT><BR><BR>"
dat+="</ul>"
if(scribble_page==curr_page)
+8 -3
View File
@@ -11,10 +11,11 @@
var/set_temperature = T0C + 20 //K
var/heating_power = 40000
/obj/machinery/space_heater/New()
..()
if (cell_type)
cell = new cell_type(src)
src.cell = new cell_type(src)
update_icon()
/obj/machinery/space_heater/update_icon()
@@ -78,7 +79,7 @@
return
/obj/machinery/space_heater/attack_hand(mob/user as mob)
add_fingerprint(user)
src.add_fingerprint(user)
interact(user)
/obj/machinery/space_heater/interact(mob/user as mob)
@@ -110,6 +111,7 @@
update_icon()
return
/obj/machinery/space_heater/Topic(href, href_list)
if (usr.stat)
return
@@ -133,6 +135,7 @@
cell = null
power_change()
if("cellinstall")
if(panel_open && !cell)
var/obj/item/weapon/cell/C = usr.get_active_hand()
@@ -150,6 +153,8 @@
usr.unset_machine()
return
/obj/machinery/space_heater/process()
if(on)
if(cell && cell.charge)
@@ -181,4 +186,4 @@
else
on = 0
power_change()
update_icon()
update_icon()
+2 -4
View File
@@ -620,9 +620,9 @@ var/global/list/obj/item/device/pda/PDAs = list()
if(!FC.censored)
var/index = 0
for(var/datum/feed_message/FM in FC.messages)
++index
index++
if(FM.img)
send_asset(usr.client, "newscaster_photo_[sanitize(FC.channel_name)]_[index].png")
usr << browse_rsc(FM.img, "pda_news_tmp_photo_[feed["channel"]]_[index].png")
// News stories are HTML-stripped but require newline replacement to be properly displayed in NanoUI
var/body = replacetext(FM.body, "\n", "<br>")
messages[++messages.len] = list("author" = FM.author, "body" = body, "message_type" = FM.message_type, "time_stamp" = FM.time_stamp, "has_image" = (FM.img != null), "caption" = FM.caption, "index" = index)
@@ -651,8 +651,6 @@ var/global/list/obj/item/device/pda/PDAs = list()
//NOTE: graphic resources are loaded on client login
/obj/item/device/pda/attack_self(mob/user as mob)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/pda)
assets.send(user)
user.set_machine(src)
@@ -33,12 +33,12 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
var/obj/item/weapon/cartridge/cartridge = null //current cartridge
var/list/modules = list(
list("module" = "Phone", "icon" = "mobile", "number" = 2),
list("module" = "Contacts", "icon" = "users", "number" = 3),
list("module" = "Messaging", "icon" = "envelope", "number" = 4),
list("module" = "Note", "icon" = "file-text", "number" = 5),
list("module" = "Settings", "icon" = "gear", "number" = 6)
) //list("module" = "Name of Module", "icon" = "icon name", "number" = "what tab is the module")
list("module" = "Phone", "icon" = "phone64", "number" = 2),
list("module" = "Contacts", "icon" = "person64", "number" = 3),
list("module" = "Messaging", "icon" = "comment64", "number" = 4),
list("module" = "Note", "icon" = "note64", "number" = 5),
list("module" = "Settings", "icon" = "gear64", "number" = 6)
) //list("module" = "Name of Module", "icon" = "icon name64", "number" = "what tab is the module")
var/selected_tab = 1
var/owner = ""
+1 -1
View File
@@ -198,7 +198,7 @@
dat += {"
<b><font size='3px'>pAI Request Module</font></b><br><br>
<p>Requesting AI personalities from central database... If there are no entries, or if a suitable entry is not listed, check again later as more personalities may be added.</p>
Searching for personalities, please wait...<br><br>
<img src='loading.gif' /> Searching for personalities<br><br>
<table>
<tr>
+1 -4
View File
@@ -143,9 +143,6 @@
return 0
/obj/item/weapon/card/id/proc/show(mob/user as mob)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper)
assets.send(user)
if(front && side)
user << browse_rsc(front, "front.png")
user << browse_rsc(side, "side.png")
@@ -365,4 +362,4 @@
desc = "An identification card of some sort. It does not look like it is issued by NT."
icon_state = "permit"
primary_color = rgb(142,94,0)
secondary_color = rgb(191,159,95)
secondary_color = rgb(191,159,95)
-1
View File
@@ -115,7 +115,6 @@
/obj/attack_ghost(mob/user)
ui_interact(user)
tg_ui_interact(user)
..()
/obj/proc/interact(mob/user)
+1 -1
View File
@@ -125,7 +125,7 @@
return
if("marked datum")
current = holder.marked_datum()
current = holder.marked_datum
if(!current)
switch(alert("You do not currently have a marked datum; do you want to pass null instead?",, "Yes", "Cancel"))
if("Yes")
+1 -4
View File
@@ -6,16 +6,13 @@ var/list/admin_datums = list()
var/rights = 0
var/fakekey = null
var/datum/weakref/marked_datum_weak
var/datum/marked_datum
var/admincaster_screen = 0 //See newscaster.dm under machinery for a full description
var/datum/feed_message/admincaster_feed_message = new /datum/feed_message //These two will act as holders.
var/datum/feed_channel/admincaster_feed_channel = new /datum/feed_channel
var/admincaster_signature //What you'll sign the newsfeeds as
/datum/admins/proc/marked_datum()
if(marked_datum_weak)
return marked_datum_weak.resolve()
/datum/admins/New(initial_rank = "Temporary Admin", initial_rights = 0, ckey)
if(!ckey)
+1 -2
View File
@@ -1538,7 +1538,6 @@
where = "onfloor"
if ( where == "inmarked" )
var/marked_datum = marked_datum()
if ( !marked_datum )
usr << "You don't have any object marked. Abandoning spawn."
return
@@ -1556,7 +1555,7 @@
if ("relative")
target = locate(loc.x + X,loc.y + Y,loc.z + Z)
if ( "inmarked" )
target = marked_datum()
target = marked_datum
if(target)
for (var/path in paths)
-15
View File
@@ -959,18 +959,3 @@
log_admin("[key_name(src)] has toggled [M.key]'s [blockname] block [state]!")
else
alert("Invalid mob")
/client/proc/reload_nanoui_resources()
set category = "Debug"
set name = "Reload NanoUI Resources"
set desc = "Force the client to redownload NanoUI Resources"
// Close open NanoUIs.
nanomanager.close_user_uis(usr)
// Re-load the assets.
var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui)
assets.register()
// Clear the user's cache so they get resent.
usr.client.cache = list()
-1
View File
@@ -162,7 +162,6 @@ var/list/debug_verbs = list (
,/client/proc/setup_supermatter_engine
,/client/proc/atmos_toggle_debug
,/client/proc/spawn_tanktransferbomb
,/client/proc/reload_nanoui_resources
)
+35 -43
View File
@@ -27,20 +27,20 @@ var/list/VVckey_edit = list("key", "ckey")
src.modify_variables(ticker)
feedback_add_details("admin_verb","ETV") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/mod_list_add_ass()
var/class = "text"
var/list/class_input = list("text","num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
if(src.holder)
var/datum/marked_datum = holder.marked_datum()
if(marked_datum)
class_input += "marked datum ([marked_datum.type])"
/client/proc/mod_list_add_ass() //haha
var/class = "text"
if(src.holder && src.holder.marked_datum)
class = input("What kind of variable?","Variable Type") as null|anything in list("text",
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default","marked datum ([holder.marked_datum.type])")
else
class = input("What kind of variable?","Variable Type") as null|anything in list("text",
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
class = input("What kind of variable?","Variable Type") as null|anything in class_input
if(!class)
return
var/datum/marked_datum = holder.marked_datum()
if(marked_datum && class == "marked datum ([marked_datum.type])")
if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])")
class = "marked datum"
var/var_value = null
@@ -69,7 +69,7 @@ var/list/VVckey_edit = list("key", "ckey")
var_value = input("Pick icon:","Icon") as null|icon
if("marked datum")
var_value = holder.marked_datum()
var_value = holder.marked_datum
if(!var_value) return
@@ -79,18 +79,17 @@ var/list/VVckey_edit = list("key", "ckey")
/client/proc/mod_list_add(var/list/L, atom/O, original_name, objectvar)
var/class = "text"
var/list/class_input = list("text","num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
if(src.holder)
var/datum/marked_datum = holder.marked_datum()
if(marked_datum)
class_input += "marked datum ([marked_datum.type])"
if(src.holder && src.holder.marked_datum)
class = input("What kind of variable?","Variable Type") as null|anything in list("text",
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default","marked datum ([holder.marked_datum.type])")
else
class = input("What kind of variable?","Variable Type") as null|anything in list("text",
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
class = input("What kind of variable?","Variable Type") as null|anything in class_input
if(!class)
return
var/datum/marked_datum = holder.marked_datum()
if(marked_datum && class == "marked datum ([marked_datum.type])")
if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])")
class = "marked datum"
var/var_value = null
@@ -119,7 +118,7 @@ var/list/VVckey_edit = list("key", "ckey")
var_value = input("Pick icon:","Icon") as icon
if("marked datum")
var_value = holder.marked_datum()
var_value = holder.marked_datum
if(!var_value) return
@@ -245,21 +244,17 @@ var/list/VVckey_edit = list("key", "ckey")
usr << "If a direction, direction is: [dir]"
var/class = "text"
var/list/class_input = list("text","num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
if(src.holder)
var/datum/marked_datum = holder.marked_datum()
if(marked_datum)
class_input += "marked datum ([marked_datum.type])"
class_input += "DELETE FROM LIST"
class = input("What kind of variable?","Variable Type",default) as null|anything in class_input
if(src.holder && src.holder.marked_datum)
class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default","marked datum ([holder.marked_datum.type])", "DELETE FROM LIST")
else
class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default", "DELETE FROM LIST")
if(!class)
return
var/datum/marked_datum = holder.marked_datum()
if(marked_datum && class == "marked datum ([marked_datum.type])")
if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])")
class = "marked datum"
var/original_var
@@ -341,9 +336,7 @@ var/list/VVckey_edit = list("key", "ckey")
L[L.Find(variable)] = new_var
if("marked datum")
new_var = holder.marked_datum()
if(!new_var)
return
new_var = holder.marked_datum
if(assoc)
L[assoc_key] = new_var
else
@@ -508,12 +501,12 @@ var/list/VVckey_edit = list("key", "ckey")
if(dir)
usr << "If a direction, direction is: [dir]"
var/list/class_input = list("text","num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
if(src.holder)
var/datum/marked_datum = holder.marked_datum()
if(marked_datum)
class_input += "marked datum ([marked_datum.type])"
class = input("What kind of variable?","Variable Type",default) as null|anything in class_input
if(src.holder && src.holder.marked_datum)
class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default","marked datum ([holder.marked_datum.type])")
else
class = input("What kind of variable?","Variable Type",default) as null|anything in list("text",
"num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default")
if(!class)
return
@@ -525,8 +518,7 @@ var/list/VVckey_edit = list("key", "ckey")
else
original_name = O:name
var/datum/marked_datum = holder.marked_datum()
if(marked_datum && class == "marked datum ([marked_datum.type])")
if(holder.marked_datum && class == "marked datum ([holder.marked_datum.type])")
class = "marked datum"
switch(class)
@@ -592,7 +584,7 @@ var/list/VVckey_edit = list("key", "ckey")
O.vars[variable] = var_new
if("marked datum")
O.vars[variable] = holder.marked_datum()
O.vars[variable] = holder.marked_datum
world.log << "### VarEdit by [src]: [O.type] [variable]=[html_encode("[O.vars[variable]]")]"
log_admin("[key_name(src)] modified [original_name]'s [variable] to [O.vars[variable]]")
+2 -5
View File
@@ -223,7 +223,7 @@
usr << "This can only be done to instances of type /datum"
return
src.holder.marked_datum_weak = weakref(D)
src.holder.marked_datum = D
href_list["datumrefresh"] = href_list["mark_object"]
else if(href_list["rotatedatum"])
@@ -476,10 +476,7 @@
usr << "This can only be done on mobs with clients"
return
nanomanager.close_uis(H)
H.client.cache.Cut()
var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui)
assets.send(H)
nanomanager.send_resources(H.client)
usr << "Resource files sent"
H << "Your NanoUI Resource files have been refreshed"
@@ -45,7 +45,7 @@
</tr></table>
<div align='center'>
<b><font size='1'>[replacetext("[D.type]", "/", "/<wbr>")]</font></b>
[holder.marked_datum() == D ? "<br/><font size='1' color='red'><b>Marked Object</b></font>" : ""]
[holder.marked_datum == D ? "<br/><font size='1' color='red'><b>Marked Object</b></font>" : ""]
</div>
</td>
<td width='50%'>
+4 -4
View File
@@ -3,7 +3,7 @@ proc/createRandomZlevel()
return
var/list/potentialRandomZlevels = list()
log_startup_progress("Searching for away missions...")
admin_notice("\red \b Searching for away missions...", R_DEBUG)
var/list/Lines = file2list("maps/RandomZLevels/fileList.txt")
if(!Lines.len) return
for (var/t in Lines)
@@ -35,7 +35,7 @@ proc/createRandomZlevel()
if(potentialRandomZlevels.len)
log_startup_progress("Loading away mission...")
admin_notice("\red \b Loading away mission...", R_DEBUG)
var/map = pick(potentialRandomZlevels)
var/file = file(map)
@@ -48,8 +48,8 @@ proc/createRandomZlevel()
continue
awaydestinations.Add(L)
log_startup_progress("Away mission loaded.")
admin_notice("\red \b Away mission loaded.", R_DEBUG)
else
log_startup_progress("No away missions found.")
admin_notice("\red \b No away missions found.", R_DEBUG)
return
-277
View File
@@ -1,277 +0,0 @@
/*
Asset cache quick users guide:
Make a datum at the bottom of this file with your assets for your thing.
The simple subsystem will most like be of use for most cases.
Then call get_asset_datum() with the type of the datum you created and store the return
Then call .send(client) on that stored return value.
You can set verify to TRUE if you want send() to sleep until the client has the assets.
*/
// Amount of time(ds) MAX to send per asset, if this get exceeded we cancel the sleeping.
// This is doubled for the first asset, then added per asset after
#define ASSET_CACHE_SEND_TIMEOUT 7
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
//List of ALL assets for the above, format is list(filename = asset).
/var/global/list/asset_cache = list()
/client
var/list/cache = list() // List of all assets sent to this client by the asset cache.
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
var/list/sending = list()
var/last_asset_job = 0 // Last job done.
//This proc sends the asset to the client, but only if it needs it.
//This proc blocks(sleeps) unless verify is set to false
/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE)
if(!istype(client))
if(ismob(client))
var/mob/M = client
if(M.client)
client = M.client
else
return 0
else
return 0
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
return 0
client << browse_rsc(asset_cache[asset_name], asset_name)
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
if (client)
client.cache += asset_name
return 1
if (!client)
return 0
client.sending |= asset_name
var/job = ++client.last_asset_job
client << browse({"
<script>
window.location.href="?asset_cache_confirm_arrival=[job]"
</script>
"}, "window=asset_cache_browser")
var/t = 0
var/timeout_time = (ASSET_CACHE_SEND_TIMEOUT * client.sending.len) + ASSET_CACHE_SEND_TIMEOUT
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(client)
client.sending -= asset_name
client.cache |= asset_name
client.completed_asset_jobs -= job
return 1
//This proc blocks(sleeps) unless verify is set to false
/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE)
if(!istype(client))
if(ismob(client))
var/mob/M = client
if(M.client)
client = M.client
else
return 0
else
return 0
var/list/unreceived = asset_list - (client.cache + client.sending)
if(!unreceived || !unreceived.len)
return 0
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
client << "Sending Resources..."
for(var/asset in unreceived)
if (asset in asset_cache)
client << browse_rsc(asset_cache[asset], asset)
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
if (client)
client.cache += unreceived
return 1
if (!client)
return 0
client.sending |= unreceived
var/job = ++client.last_asset_job
client << browse({"
<script>
window.location.href="?asset_cache_confirm_arrival=[job]"
</script>
"}, "window=asset_cache_browser")
var/t = 0
var/timeout_time = ASSET_CACHE_SEND_TIMEOUT * client.sending.len
while(client && !client.completed_asset_jobs.Find(job) && t < timeout_time) // Reception is handled in Topic()
sleep(1) // Lock up the caller until this is received.
t++
if(client)
client.sending -= unreceived
client.cache |= unreceived
client.completed_asset_jobs -= job
return 1
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
//The proc calls procs that sleep for long times.
proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
for(var/file in files)
if (!client)
break
if (register_asset)
register_asset(file,files[file])
send_asset(client,file)
sleep(-1) //queuing calls like this too quickly can cause issues in some client versions
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
//if it's an icon or something be careful, you'll have to copy it before further use.
/proc/register_asset(var/asset_name, var/asset)
asset_cache[asset_name] = asset
//From here on out it's populating the asset cache.
/proc/populate_asset_cache()
for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple))
var/datum/asset/A = new type()
A.register()
for(var/client/C in clients)
//doing this to a client too soon after they've connected can cause issues, also the proc we call sleeps
spawn(10)
getFilesSlow(C, asset_cache, FALSE)
//These datums are used to populate the asset cache, the proc "register()" does this.
//all of our asset datums, used for referring to these later
/var/global/list/asset_datums = list()
//get a assetdatum or make a new one
/proc/get_asset_datum(var/type)
if (!(type in asset_datums))
return new type()
return asset_datums[type]
/datum/asset/New()
asset_datums[type] = src
/datum/asset/proc/register()
return
/datum/asset/proc/send(client)
return
//If you don't need anything complicated.
/datum/asset/simple
var/assets = list()
var/verify = FALSE
/datum/asset/simple/register()
for(var/asset_name in assets)
register_asset(asset_name, assets[asset_name])
/datum/asset/simple/send(client)
send_asset_list(client,assets,verify)
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/paper
assets = list(
"large_stamp-clown.png" = 'icons/paper_icons/large_stamp-clown.png',
"large_stamp-deny.png" = 'icons/paper_icons/large_stamp-deny.png',
"large_stamp-ok.png" = 'icons/paper_icons/large_stamp-ok.png',
"large_stamp-hop.png" = 'icons/paper_icons/large_stamp-hop.png',
"large_stamp-cmo.png" = 'icons/paper_icons/large_stamp-cmo.png',
"large_stamp-ce.png" = 'icons/paper_icons/large_stamp-ce.png',
"large_stamp-hos.png" = 'icons/paper_icons/large_stamp-hos.png',
"large_stamp-rd.png" = 'icons/paper_icons/large_stamp-rd.png',
"large_stamp-cap.png" = 'icons/paper_icons/large_stamp-cap.png',
"large_stamp-qm.png" = 'icons/paper_icons/large_stamp-qm.png',
"large_stamp-law.png" = 'icons/paper_icons/large_stamp-law.png',
"large_stamp-cent.png" = 'icons/paper_icons/large_stamp-cent.png',
"talisman.png" = 'icons/paper_icons/talisman.png',
"ntlogo.png" = 'icons/paper_icons/ntlogo.png',
"sglogo.png" = 'icons/paper_icons/sglogo.png'
)
/datum/asset/simple/tgui
assets = list(
"tgui.css" = 'tgui/assets/tgui.css',
"tgui.js" = 'tgui/assets/tgui.js'
)
/datum/asset/simple/pda
assets = list(
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
"pda_back.png" = 'icons/pda_icons/pda_back.png',
"pda_bell.png" = 'icons/pda_icons/pda_bell.png',
"pda_blank.png" = 'icons/pda_icons/pda_blank.png',
"pda_boom.png" = 'icons/pda_icons/pda_boom.png',
"pda_bucket.png" = 'icons/pda_icons/pda_bucket.png',
"pda_chatroom.png" = 'icons/pda_icons/pda_chatroom.png',
"pda_crate.png" = 'icons/pda_icons/pda_crate.png',
"pda_cuffs.png" = 'icons/pda_icons/pda_cuffs.png',
"pda_eject.png" = 'icons/pda_icons/pda_eject.png',
"pda_exit.png" = 'icons/pda_icons/pda_exit.png',
"pda_honk.png" = 'icons/pda_icons/pda_honk.png',
"pda_locked.png" = 'icons/pda_icons/pda_locked.png',
"pda_mail.png" = 'icons/pda_icons/pda_mail.png',
"pda_medical.png" = 'icons/pda_icons/pda_medical.png',
"pda_menu.png" = 'icons/pda_icons/pda_menu.png',
"pda_mule.png" = 'icons/pda_icons/pda_mule.png',
"pda_notes.png" = 'icons/pda_icons/pda_notes.png',
"pda_power.png" = 'icons/pda_icons/pda_power.png',
"pda_rdoor.png" = 'icons/pda_icons/pda_rdoor.png',
"pda_reagent.png" = 'icons/pda_icons/pda_reagent.png',
"pda_refresh.png" = 'icons/pda_icons/pda_refresh.png',
"pda_scanner.png" = 'icons/pda_icons/pda_scanner.png',
"pda_signaler.png" = 'icons/pda_icons/pda_signaler.png',
"pda_status.png" = 'icons/pda_icons/pda_status.png'
)
/datum/asset/nanoui
var/list/common = list()
var/list/common_dirs = list(
"nano/assets/",
"nano/css/",
"nano/js/",
"nano/images/",
"nano/layouts/"
)
var/list/uncommon_dirs = list(
"nano/templates/"
)
/datum/asset/nanoui/register()
// Crawl the directories to find files.
for (var/path in common_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
common[filename] = fcopy_rsc(path + filename)
register_asset(filename, common[filename])
for (var/path in uncommon_dirs)
var/list/filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // Ignore directories.
if(fexists(path + filename))
register_asset(filename, fcopy_rsc(path + filename))
/datum/asset/nanoui/send(client, uncommon)
if(!islist(uncommon))
uncommon = list(uncommon)
send_asset_list(client, uncommon)
send_asset_list(client, common)
+1 -3
View File
@@ -47,6 +47,4 @@
preload_rsc = 0 // This is 0 so we can set it to an URL once the player logs in and have them download the resources from a different server.
var/global/obj/screen/click_catcher/void
//NanoUI//
var/topic_debugging = 0 //if set to true, allows client to see nanoUI errors -- yes i realize this is messy but it'll make live testing infinitely easier
+48 -18
View File
@@ -28,17 +28,11 @@
#if defined(TOPIC_DEBUGGING)
world << "[src]'s Topic: [href] destined for [hsrc]."
#endif
if(href_list["nano_err"]) //nano throwing errors
if(topic_debugging)
src << "## NanoUI: " + html_decode(href_list["nano_err"]) //NANO DEBUG HOOK
world << "## NanoUI, Subject [src]: " + html_decode(href_list["nano_err"]) //NANO DEBUG HOOK
if(href_list["asset_cache_confirm_arrival"])
//src << "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED."
var/job = text2num(href_list["asset_cache_confirm_arrival"])
completed_asset_jobs += job
return
#endif
//search the href for script injection
if( findtext(href,"<script",1,0) )
@@ -161,15 +155,13 @@
log_client_to_db()
send_resources()
nanomanager.send_resources(src)
if(!void)
void = new()
void.MakeGreed()
screen += void
if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
src << "<span class='warning'>Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.</span>"
if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates.
src << "<span class='info'>You have unread updates in the changelog.</span>"
winset(src, "rpane.changelog", "background-color=#eaeaea;font-style=bold")
@@ -288,18 +280,56 @@
/client/proc/last_activity_seconds()
return inactivity / 10
//Send resources to the client.
//send resources to the client. It's here in its own proc so we can move it around easiliy if need be
/client/proc/send_resources()
// Most assets are now handled through global_cache.dm
getFiles(
'html/search.js', // Used in various non-NanoUI HTML windows for search functionality
'html/panels.css' // Used for styling certain panels, such as in the new player panel
'html/search.js',
'html/panels.css',
'html/images/loading.gif',
'html/images/ntlogo.png',
'html/images/sglogo.png',
'html/images/talisman.png',
'icons/pda_icons/pda_atmos.png',
'icons/pda_icons/pda_back.png',
'icons/pda_icons/pda_bell.png',
'icons/pda_icons/pda_blank.png',
'icons/pda_icons/pda_boom.png',
'icons/pda_icons/pda_bucket.png',
'icons/pda_icons/pda_crate.png',
'icons/pda_icons/pda_cuffs.png',
'icons/pda_icons/pda_eject.png',
'icons/pda_icons/pda_exit.png',
'icons/pda_icons/pda_flashlight.png',
'icons/pda_icons/pda_honk.png',
'icons/pda_icons/pda_mail.png',
'icons/pda_icons/pda_medical.png',
'icons/pda_icons/pda_menu.png',
'icons/pda_icons/pda_mule.png',
'icons/pda_icons/pda_notes.png',
'icons/pda_icons/pda_power.png',
'icons/pda_icons/pda_rdoor.png',
'icons/pda_icons/pda_reagent.png',
'icons/pda_icons/pda_refresh.png',
'icons/pda_icons/pda_scanner.png',
'icons/pda_icons/pda_signaler.png',
'icons/pda_icons/pda_status.png',
'icons/spideros_icons/sos_1.png',
'icons/spideros_icons/sos_2.png',
'icons/spideros_icons/sos_3.png',
'icons/spideros_icons/sos_4.png',
'icons/spideros_icons/sos_5.png',
'icons/spideros_icons/sos_6.png',
'icons/spideros_icons/sos_7.png',
'icons/spideros_icons/sos_8.png',
'icons/spideros_icons/sos_9.png',
'icons/spideros_icons/sos_10.png',
'icons/spideros_icons/sos_11.png',
'icons/spideros_icons/sos_12.png',
'icons/spideros_icons/sos_13.png',
'icons/spideros_icons/sos_14.png'
)
spawn (10)
//Precache the client with all other assets slowly, so as to not block other browse() calls
getFilesSlow(src, asset_cache, register_asset = FALSE)
mob/proc/MayRespawn()
return 0
@@ -144,24 +144,6 @@ var/list/_client_preferences_by_type
enabled_description = "Fancy"
disabled_description = "Plain"
/datum/client_preference/nanoui_style
description = "Fancy NanoUI style"
key = "NANO_STYLED"
enabled_description = "Fancy"
disabled_description = "Plain"
/datum/client_preference/tgui_style
description ="tgui Style"
key = "TGUI_FANCY"
enabled_description = "Fancy"
disabled_description = "Plain"
/datum/client_preference/tgui_monitor
description ="tgui Monitor"
key = "TGUI_MONITOR"
enabled_description = "Primary"
disabled_description = "All"
/********************
* Staff Preferences *
********************/
+1 -1
View File
@@ -262,7 +262,7 @@ datum/preferences
if(be_random_name)
real_name = random_name(identifying_gender,species)
// Ask the preferences datums to apply their own settings to the new mob
// Ask the preferences datums to apply their own settings to the new mob
player_setup.copy_to_mob(character)
if(icon_updates)
@@ -798,9 +798,6 @@
return 0
return 1
/obj/item/weapon/rig/check_access(obj/item/I)
return TRUE
/obj/item/weapon/rig/proc/force_rest(var/mob/user)
if(!ai_can_move_suit(user, check_user_module = 1))
return
+284 -276
View File
@@ -6,6 +6,12 @@ send money to people (might be worth attaching money to custom database thing fo
log transactions
*/
#define NO_SCREEN 0
#define CHANGE_SECURITY_LEVEL 1
#define TRANSFER_FUNDS 2
#define VIEW_TRANSACTION_LOGS 3
/obj/item/weapon/card/id/var/money = 2000
/obj/machinery/atm
@@ -20,20 +26,13 @@ log transactions
var/datum/money_account/authenticated_account
var/number_incorrect_tries = 0
var/previous_account_number = 0
var/account_num = 0
var/pin_num = 0
var/max_pin_attempts = 3
var/ticks_left_locked_down = 0
var/ticks_left_timeout = 0
var/machine_id = ""
var/obj/item/weapon/card/held_card
var/editing_security_level = 0
var/withdrawal_type = 1
var/withdrawal = 0
var/target_account_num = 0
var/transaction_amount = 0
var/transaction_purpose = 0
var/view_screen = 0
var/view_screen = NO_SCREEN
var/datum/effect/effect/system/spark_spread/spark_system
/obj/machinery/atm/New()
@@ -103,7 +102,7 @@ log transactions
if(istype(I, /obj/item/weapon/card))
if(emagged > 0)
//prevent inserting id into an emagged ATM
user << "\icon[src]<span class='warning'>CARD READER ERROR. This system has been compromised!</span>"
user << "\red \icon[src] CARD READER ERROR. This system has been compromised!"
return
else if(istype(I,/obj/item/weapon/card/emag))
I.resolve_attackby(src, user)
@@ -143,67 +142,268 @@ log transactions
/obj/machinery/atm/attack_hand(mob/user as mob)
if(istype(user, /mob/living/silicon))
user << "\icon[src]<span class='warning'>Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per system banking regulation #1005.</span>"
user << "\red \icon[src] Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per system banking regulation #1005."
return
tg_ui_interact(user)
if(get_dist(src,user) <= 1)
/obj/machinery/atm/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "atm", "[name] [machine_id]", 550, 650, master_ui, state)
ui.open()
//js replicated from obj/machinery/computer/card
var/dat = "<h1>Automatic Teller Machine</h1>"
dat += "For all your monetary needs!<br>"
dat += "<i>This terminal is</i> [machine_id]. <i>Report this code when contacting IT Support</i><br/>"
/obj/machinery/atm/ui_data(mob/user)
var/list/data = list()
if(authenticated_account)
var/list/authAccount = list()
var/list/transactions = list()
authAccount["suspended"] = authenticated_account.suspended
authAccount["securityLevel"] = authenticated_account.security_level
for(var/datum/transaction/T in authenticated_account.transaction_log)
var/list/log_list = list()
log_list["date"] = T.date
log_list["time"] = T.time
log_list["target_name"] = T.target_name
log_list["purpose"] = T.purpose
log_list["amount"] = T.amount
log_list["source_terminal"] = T.source_terminal
transactions[++transactions.len] = log_list
authAccount["transactionLog"] = transactions
authAccount["money"] = authenticated_account.money
authAccount["name"] = authenticated_account.owner_name
data["authAccount"] = authAccount
if(emagged > 0)
dat += "Card: <span style='color: red;'>LOCKED</span><br><br><span style='color: red;'>Unauthorized terminal access detected! This ATM has been locked. Please contact IT Support.</span>"
else
dat += "Card: <a href='?src=\ref[src];choice=insert_card'>[held_card ? held_card.name : "------"]</a><br><br>"
if(ticks_left_locked_down > 0)
dat += "<span class='alert'>Maximum number of pin attempts exceeded! Access to this ATM has been temporarily disabled.</span>"
else if(authenticated_account)
if(authenticated_account.suspended)
dat += "\red<b>Access to this account has been suspended, and the funds within frozen.</b>"
else
switch(view_screen)
if(CHANGE_SECURITY_LEVEL)
dat += "Select a new security level for this account:<br><hr>"
var/text = "Zero - Either the account number or card is required to access this account. EFTPOS transactions will require a card and ask for a pin, but not verify the pin is correct."
if(authenticated_account.security_level != 0)
text = "<A href='?src=\ref[src];choice=change_security_level;new_security_level=0'>[text]</a>"
dat += "[text]<hr>"
text = "One - An account number and pin must be manually entered to access this account and process transactions."
if(authenticated_account.security_level != 1)
text = "<A href='?src=\ref[src];choice=change_security_level;new_security_level=1'>[text]</a>"
dat += "[text]<hr>"
text = "Two - In addition to account number and pin, a card is required to access this account and process transactions."
if(authenticated_account.security_level != 2)
text = "<A href='?src=\ref[src];choice=change_security_level;new_security_level=2'>[text]</a>"
dat += "[text]<hr><br>"
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=0'>Back</a>"
if(VIEW_TRANSACTION_LOGS)
dat += "<b>Transaction logs</b><br>"
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=0'>Back</a>"
dat += "<table border=1 style='width:100%'>"
dat += "<tr>"
dat += "<td><b>Date</b></td>"
dat += "<td><b>Time</b></td>"
dat += "<td><b>Target</b></td>"
dat += "<td><b>Purpose</b></td>"
dat += "<td><b>Value</b></td>"
dat += "<td><b>Source terminal ID</b></td>"
dat += "</tr>"
for(var/datum/transaction/T in authenticated_account.transaction_log)
dat += "<tr>"
dat += "<td>[T.date]</td>"
dat += "<td>[T.time]</td>"
dat += "<td>[T.target_name]</td>"
dat += "<td>[T.purpose]</td>"
dat += "<td>$[T.amount]</td>"
dat += "<td>[T.source_terminal]</td>"
dat += "</tr>"
dat += "</table>"
dat += "<A href='?src=\ref[src];choice=print_transaction'>Print</a><br>"
if(TRANSFER_FUNDS)
dat += "<b>Account balance:</b> $[authenticated_account.money]<br>"
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=0'>Back</a><br><br>"
dat += "<form name='transfer' action='?src=\ref[src]' method='get'>"
dat += "<input type='hidden' name='src' value='\ref[src]'>"
dat += "<input type='hidden' name='choice' value='transfer'>"
dat += "Target account number: <input type='text' name='target_acc_number' value='' style='width:200px; background-color:white;'><br>"
dat += "Funds to transfer: <input type='text' name='funds_amount' value='' style='width:200px; background-color:white;'><br>"
dat += "Transaction purpose: <input type='text' name='purpose' value='Funds transfer' style='width:200px; background-color:white;'><br>"
dat += "<input type='submit' value='Transfer funds'><br>"
dat += "</form>"
else
dat += "Welcome, <b>[authenticated_account.owner_name].</b><br/>"
dat += "<b>Account balance:</b> $[authenticated_account.money]"
dat += "<form name='withdrawal' action='?src=\ref[src]' method='get'>"
dat += "<input type='hidden' name='src' value='\ref[src]'>"
dat += "<input type='radio' name='choice' value='withdrawal' checked> Cash <input type='radio' name='choice' value='e_withdrawal'> Chargecard<br>"
dat += "<input type='text' name='funds_amount' value='' style='width:200px; background-color:white;'><input type='submit' value='Withdraw'>"
dat += "</form>"
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=1'>Change account security level</a><br>"
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=2'>Make transfer</a><br>"
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=3'>View transaction log</a><br>"
dat += "<A href='?src=\ref[src];choice=balance_statement'>Print balance statement</a><br>"
dat += "<A href='?src=\ref[src];choice=logout'>Logout</a><br>"
else
dat += "<form name='atm_auth' action='?src=\ref[src]' method='get'>"
dat += "<input type='hidden' name='src' value='\ref[src]'>"
dat += "<input type='hidden' name='choice' value='attempt_auth'>"
dat += "<b>Account:</b> <input type='text' id='account_num' name='account_num' style='width:250px; background-color:white;'><br>"
dat += "<b>PIN:</b> <input type='text' id='account_pin' name='account_pin' style='width:250px; background-color:white;'><br>"
dat += "<input type='submit' value='Submit'><br>"
dat += "</form>"
user << browse(dat,"window=atm;size=550x650")
else
data["authAccount"] = null
data["emagged"] = emagged
data["lockdown"] = ticks_left_locked_down > 0 ? TRUE : null
data["screen"] = view_screen
data["transactionTargetNumber"] = target_account_num
data["transactionTargetAmount"] = transaction_amount
data["transactionPurpose"] = transaction_purpose
data["card"] = held_card
data["cardName"] = held_card ? held_card.name : "Insert Card"
data["account"] = account_num
data["pin"] = pin_num
data["withdrawal"] = withdrawal
data["withdrawalType"] = withdrawal_type
user << browse(null,"window=atm")
return data
/obj/machinery/atm/Topic(var/href, var/href_list)
if(href_list["choice"])
switch(href_list["choice"])
if("transfer")
if(authenticated_account)
var/transfer_amount = text2num(href_list["funds_amount"])
transfer_amount = round(transfer_amount, 0.01)
if(transfer_amount <= 0)
alert("That is not a valid amount.")
else if(transfer_amount <= authenticated_account.money)
var/target_account_number = text2num(href_list["target_acc_number"])
var/transfer_purpose = href_list["purpose"]
if(charge_to_account(target_account_number, authenticated_account.owner_name, transfer_purpose, machine_id, transfer_amount))
usr << "\icon[src]<span class='info'>Funds transfer successful.</span>"
authenticated_account.money -= transfer_amount
/obj/machinery/atm/ui_act(action, params)
if(..())
return TRUE
switch(action)
if("screen")
view_screen = text2num(params["new_screen"])
//create an entry in the account transaction log
var/datum/transaction/T = new()
T.target_name = "Account #[target_account_number]"
T.purpose = transfer_purpose
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
T.amount = "([transfer_amount])"
authenticated_account.transaction_log.Add(T)
else
usr << "\icon[src]<span class='warning'>Funds transfer failed.</span>"
if("security_level")
if(authenticated_account)
var/new_sec_level = max(min(text2num(params["new_security_level"]), 2), 0)
authenticated_account.security_level = new_sec_level
else
usr << "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>"
if("view_screen")
view_screen = text2num(href_list["view_screen"])
if("change_security_level")
if(authenticated_account)
var/new_sec_level = max( min(text2num(href_list["new_security_level"]), 2), 0)
authenticated_account.security_level = new_sec_level
if("attempt_auth")
if("print")
if(params["print_type"] == "transaction")
// check if they have low security enabled
scan_user(usr)
if(!ticks_left_locked_down && held_card)
var/tried_account_num = text2num(href_list["account_num"])
if(!tried_account_num)
tried_account_num = held_card.associated_account_number
var/tried_pin = text2num(href_list["account_pin"])
authenticated_account = attempt_account_access(tried_account_num, tried_pin, held_card && held_card.associated_account_number == tried_account_num ? 2 : 1)
if(!authenticated_account)
number_incorrect_tries++
if(previous_account_number == tried_account_num)
if(number_incorrect_tries > max_pin_attempts)
//lock down the atm
ticks_left_locked_down = 30
playsound(src, 'sound/machines/buzz-two.ogg', 50, 1)
//create an entry in the account transaction log
var/datum/money_account/failed_account = get_account(tried_account_num)
if(failed_account)
var/datum/transaction/T = new()
T.target_name = failed_account.owner_name
T.purpose = "Unauthorised login attempt"
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
failed_account.transaction_log.Add(T)
else
usr << "\red \icon[src] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining."
previous_account_number = tried_account_num
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1)
else
usr << "\red \icon[src] incorrect pin/account combination entered."
number_incorrect_tries = 0
else
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
ticks_left_timeout = 120
view_screen = NO_SCREEN
//create a transaction log entry
var/datum/transaction/T = new()
T.target_name = authenticated_account.owner_name
T.purpose = "Remote terminal access"
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
usr << "\blue \icon[src] Access granted. Welcome user '[authenticated_account.owner_name].'"
previous_account_number = tried_account_num
if("e_withdrawal")
var/amount = max(text2num(href_list["funds_amount"]),0)
amount = round(amount, 0.01)
if(amount <= 0)
alert("That is not a valid amount.")
else if(authenticated_account && amount > 0)
if(amount <= authenticated_account.money)
playsound(src, 'sound/machines/chime.ogg', 50, 1)
//remove the money
authenticated_account.money -= amount
// spawn_money(amount,src.loc)
spawn_ewallet(amount,src.loc,usr)
//create an entry in the account transaction log
var/datum/transaction/T = new()
T.target_name = authenticated_account.owner_name
T.purpose = "Credit withdrawal"
T.amount = "([amount])"
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
else
usr << "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>"
if("withdrawal")
var/amount = max(text2num(href_list["funds_amount"]),0)
amount = round(amount, 0.01)
if(amount <= 0)
alert("That is not a valid amount.")
else if(authenticated_account && amount > 0)
if(amount <= authenticated_account.money)
playsound(src, 'sound/machines/chime.ogg', 50, 1)
//remove the money
authenticated_account.money -= amount
spawn_money(amount,src.loc,usr)
//create an entry in the account transaction log
var/datum/transaction/T = new()
T.target_name = authenticated_account.owner_name
T.purpose = "Credit withdrawal"
T.amount = "([amount])"
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
else
usr << "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>"
if("balance_statement")
if(authenticated_account)
var/obj/item/weapon/paper/R = new(src.loc)
R.name = "Account balance: [authenticated_account.owner_name]"
R.info = "<b>NT Automated Teller Account Statement</b><br><br>"
R.info += "<i>Account holder:</i> [authenticated_account.owner_name]<br>"
R.info += "<i>Account number:</i> [authenticated_account.account_number]<br>"
R.info += "<i>Balance:</i> $[authenticated_account.money]<br>"
R.info += "<i>Date and time:</i> [stationtime2text()], [current_date_string]<br><br>"
R.info += "<i>Service terminal ID:</i> [machine_id]<br>"
//stamp the paper
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi')
stampoverlay.icon_state = "paper_stamp-cent"
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
R.overlays += stampoverlay
R.stamps += "<HR><i>This paper has been stamped by the Automatic Teller Machine.</i>"
if(prob(50))
playsound(loc, 'sound/items/polaroid1.ogg', 50, 1)
else
playsound(loc, 'sound/items/polaroid2.ogg', 50, 1)
if ("print_transaction")
if(authenticated_account)
var/obj/item/weapon/paper/R = new(src.loc)
R.name = "Transaction logs: [authenticated_account.owner_name]"
@@ -241,221 +441,29 @@ log transactions
R.overlays += stampoverlay
R.stamps += "<HR><i>This paper has been stamped by the Automatic Teller Machine.</i>"
if(prob(50))
playsound(loc, 'sound/items/polaroid1.ogg', 50, 1)
else
playsound(loc, 'sound/items/polaroid2.ogg', 50, 1)
if(params["print_type"] == "balance")
if(authenticated_account)
var/obj/item/weapon/paper/R = new(src.loc)
R.name = "Account balance: [authenticated_account.owner_name]"
R.info = "<b>NT Automated Teller Account Statement</b><br><br>"
R.info += "<i>Account holder:</i> [authenticated_account.owner_name]<br>"
R.info += "<i>Account number:</i> [authenticated_account.account_number]<br>"
R.info += "<i>Balance:</i> $[authenticated_account.money]<br>"
R.info += "<i>Date and time:</i> [stationtime2text()], [current_date_string]<br><br>"
R.info += "<i>Service terminal ID:</i> [machine_id]<br>"
//stamp the paper
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi')
stampoverlay.icon_state = "paper_stamp-cent"
if(!R.stamped)
R.stamped = new
R.stamped += /obj/item/weapon/stamp
R.overlays += stampoverlay
R.stamps += "<HR><i>This paper has been stamped by the Automatic Teller Machine.</i>"
if(prob(50))
playsound(loc, 'sound/items/polaroid1.ogg', 50, 1)
else
playsound(loc, 'sound/items/polaroid2.ogg', 50, 1)
if("input")
var/response = input("ATM input.", "ATM input.", params["input_current"])
switch(params["input_name"])
if("transactiontarget")
target_account_num = text2num(response)
if("transactionamount")
transaction_amount = text2num(response)
if("transactionpurpose")
transaction_purpose = response
if("account")
account_num = text2num(response)
if("pin")
pin_num = text2num(response)
if("withdrawalamount")
withdrawal = text2num(response)
if("submit")
if(params["submit_type"] == "transaction")
if(authenticated_account)
var/transfer_amount = transaction_amount
transfer_amount = round(transfer_amount, 0.01)
if(transfer_amount <= 0)
alert("That is not a valid amount.")
else if(transfer_amount <= authenticated_account.money)
var/target_account_number = target_account_num
var/transfer_purpose = transaction_purpose
if(charge_to_account(target_account_number, authenticated_account.owner_name, transfer_purpose, machine_id, transfer_amount))
usr << "\icon[src]<span class='info'>Funds transfer successful.</span>"
authenticated_account.money -= transfer_amount
//create an entry in the account transaction log
var/datum/transaction/T = new()
T.target_name = "Account #[target_account_number]"
T.purpose = transfer_purpose
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
T.amount = "([transfer_amount])"
authenticated_account.transaction_log.Add(T)
else
usr << "\icon[src]<span class='warning'>Funds transfer failed.</span>"
else
usr << "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>"
if(params["submit_type"] == "login")
// check if they have low security enabled
scan_user(usr)
if(!ticks_left_locked_down && held_card)
var/tried_account_num = account_num
if(!tried_account_num)
tried_account_num = held_card.associated_account_number
var/tried_pin = pin_num
authenticated_account = attempt_account_access(tried_account_num, tried_pin, held_card && held_card.associated_account_number == tried_account_num ? 2 : 1)
if(!authenticated_account)
number_incorrect_tries++
if(previous_account_number == tried_account_num)
if(number_incorrect_tries > max_pin_attempts)
//lock down the atm
ticks_left_locked_down = 30
playsound(src, 'sound/machines/buzz-two.ogg', 50, 1)
//create an entry in the account transaction log
var/datum/money_account/failed_account = get_account(tried_account_num)
if(failed_account)
var/datum/transaction/T = new()
T.target_name = failed_account.owner_name
T.purpose = "Unauthorised login attempt"
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
failed_account.transaction_log.Add(T)
else
usr << "\icon[src]<span class='warning'>Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining.</span>"
previous_account_number = tried_account_num
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 1)
else
usr << "\icon[src]<span class='warning'>incorrect pin/account combination entered.</span>"
number_incorrect_tries = 0
else
playsound(src, 'sound/machines/twobeep.ogg', 50, 1)
ticks_left_timeout = 120
view_screen = "home"
//create a transaction log entry
var/datum/transaction/T = new()
T.target_name = authenticated_account.owner_name
T.purpose = "Remote terminal access"
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
usr << "\icon[src]<span class='info'>Access granted. Welcome user '[authenticated_account.owner_name].'</span>"
previous_account_number = tried_account_num
if("withdrawal_type")
withdrawal_type = text2num(params["type"])
if("withdraw")
if(withdrawal_type == 1)
var/amount = max(withdrawal,0)
amount = round(amount, 0.01)
if(amount <= 0)
alert("That is not a valid amount.")
else if(authenticated_account && amount > 0)
if(amount <= authenticated_account.money)
playsound(src, 'sound/machines/chime.ogg', 50, 1)
//remove the money
authenticated_account.money -= amount
spawn_money(amount,src.loc,usr)
//create an entry in the account transaction log
var/datum/transaction/T = new()
T.target_name = authenticated_account.owner_name
T.purpose = "Credit withdrawal"
T.amount = "([amount])"
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
else
usr << "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>"
else if(withdrawal_type == 2)
var/amount = max(withdrawal,0)
amount = round(amount, 0.01)
if(amount <= 0)
alert("That is not a valid amount.")
else if(authenticated_account && amount > 0)
if(amount <= authenticated_account.money)
playsound(src, 'sound/machines/chime.ogg', 50, 1)
//remove the money
authenticated_account.money -= amount
// spawn_money(amount,src.loc)
spawn_ewallet(amount,src.loc,usr)
//create an entry in the account transaction log
var/datum/transaction/T = new()
T.target_name = authenticated_account.owner_name
T.purpose = "Credit withdrawal"
T.amount = "([amount])"
T.source_terminal = machine_id
T.date = current_date_string
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
else
usr << "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>"
else
usr << "<span class='warning'>Error! Select a withdrawal method!</span>"
withdrawal = 0
if("insert_card")
if(!held_card)
//this might happen if the user had the browser window open when somebody emagged it
if(emagged > 0)
usr << "\icon[src]<span class='warning'>The ATM card reader rejected your ID because this machine has been sabotaged!</span>"
if(prob(50))
playsound(loc, 'sound/items/polaroid1.ogg', 50, 1)
else
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/weapon/card/id))
usr.drop_item()
I.loc = src
held_card = I
else
release_held_id(usr)
playsound(loc, 'sound/items/polaroid2.ogg', 50, 1)
if("logout")
authenticated_account = null
account_num = 0
pin_num = 0
view_screen = 0
target_account_num = 0
transaction_purpose = 0
transaction_amount = 0
withdrawal = 0
if("insert_card")
if(!held_card)
//this might happen if the user had the browser window open when somebody emagged it
if(emagged > 0)
usr << "\red \icon[src] The ATM card reader rejected your ID because this machine has been sabotaged!"
else
var/obj/item/I = usr.get_active_hand()
if (istype(I, /obj/item/weapon/card/id))
usr.drop_item()
I.loc = src
held_card = I
else
release_held_id(usr)
if("logout")
authenticated_account = null
//usr << browse(null,"window=atm")
return TRUE
src.attack_hand(usr)
//stolen wholesale and then edited a bit from newscasters, which are awesome and by Agouri
/obj/machinery/atm/proc/scan_user(mob/living/carbon/human/human_user as mob)
@@ -470,7 +478,7 @@ log transactions
if(I)
authenticated_account = attempt_account_access(I.associated_account_number)
if(authenticated_account)
human_user << "\icon[src]<span class='info'>Access granted. Welcome user '[authenticated_account.owner_name].'</span>"
human_user << "\blue \icon[src] Access granted. Welcome user '[authenticated_account.owner_name].'"
//create a transaction log entry
var/datum/transaction/T = new()
@@ -481,7 +489,7 @@ log transactions
T.time = stationtime2text()
authenticated_account.transaction_log.Add(T)
view_screen = 0
view_screen = NO_SCREEN
// put the currently held id on the ground or in the hand of the user
/obj/machinery/atm/proc/release_held_id(mob/living/carbon/human/human_user as mob)
+1 -4
View File
@@ -720,10 +720,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/observer/dead/canface()
return 1
/mob/proc/can_admin_interact()
return 0
/mob/observer/dead/can_admin_interact()
/mob/observer/dead/proc/can_admin_interact()
return check_rights(R_ADMIN, 0, src)
/mob/observer/dead/verb/toggle_ghostsee()
-1
View File
@@ -1,6 +1,5 @@
/mob/Logout()
nanomanager.user_logout(src) // this is used to clean up (remove) this user's Nano UIs
tgui_process.on_logout(src)
player_list -= src
log_access("Logout: [key_name(src)]")
if(admin_datums[src.ckey])
+1 -7
View File
@@ -576,10 +576,4 @@ var/list/global/organ_rel_size = list(
)
/mob/proc/flash_eyes(intensity = FLASH_PROTECTION_MODERATE, override_blindness_check = FALSE, affect_silicon = FALSE, visual = FALSE, type = /obj/screen/fullscreen/flash)
return
/proc/get_both_hands(mob/living/carbon/M)
if(!istype(M))
return
var/list/hands = list(M.l_hand, M.r_hand)
return hands
return
-9
View File
@@ -1,9 +0,0 @@
/*
This state only checks if user is conscious.
*/
/var/global/datum/topic_state/hands/hands_state = new()
/datum/topic_state/hands/can_use_topic(var/src_object, var/mob/user)
. = user.shared_ui_interaction(src_object)
if(. > STATUS_CLOSE)
. = min(., user.hands_can_use_topic(src_object))
+1 -1
View File
@@ -1,6 +1,6 @@
/datum/nano_module
var/name
var/datum/host
var/host
/datum/nano_module/New(var/host)
src.host = host
+41 -1
View File
@@ -5,6 +5,32 @@
var/open_uis[0]
// a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list()
// a list of asset filenames which are to be sent to the client on user logon
var/list/asset_files = list()
/**
* Create a new nanomanager instance.
* This proc generates a list of assets which are to be sent to each client on connect
*
* @return /nanomanager new nanomanager object
*/
/datum/nanomanager/New()
var/list/nano_asset_dirs = list(\
"nano/css/",\
"nano/images/",\
"nano/js/",\
"nano/templates/"\
)
var/list/filenames = null
for (var/path in nano_asset_dirs)
filenames = flist(path)
for(var/filename in filenames)
if(copytext(filename, length(filename)) != "/") // filenames which end in "/" are actually directories, which we want to ignore
if(fexists(path + filename))
asset_files.Add(fcopy_rsc(path + filename)) // add this file to asset_files for sending to clients when they connect
return
/**
* Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
@@ -228,4 +254,18 @@
oldMob.open_uis.Cut()
return 1 // success
return 1 // success
/**
* Sends all nano assets to the client
* This is called on user login
*
* @param client /client The user's client
*
* @return nothing
*/
/datum/nanomanager/proc/send_resources(client)
for(var/file in asset_files)
client << browse_rsc(file) // send the file to the client
+11 -10
View File
@@ -57,21 +57,22 @@
world.log << "NanoMapGen: <B>GENERATE MAP ([startX],[startY],[currentZ]) to ([endX],[endY],[currentZ])</B>"
usr << "NanoMapGen: <B>GENERATE MAP ([startX],[startY],[currentZ]) to ([endX],[endY],[currentZ])</B>"
var/count = 0;
for(var/WorldX = startX, WorldX <= endX, WorldX++)
for(var/WorldY = startY, WorldY <= endY, WorldY++)
var/turf/T = locate(WorldX, WorldY, currentZ)
var/list/atoms = T.contents + T
atoms = sortByVar(atoms, "layer")
for(var/atom/A in atoms)
if(A.type == /turf/space|| istype(A, /mob) || A.invisibility > 0)
continue
var/icon/TurfIcon = new(A.icon, A.icon_state, A.dir, 1, 0)
TurfIcon.Scale(NANOMAP_ICON_SIZE, NANOMAP_ICON_SIZE)
var/atom/Turf = locate(WorldX, WorldY, currentZ)
Tile.Blend(TurfIcon, ICON_OVERLAY, ((WorldX - 1) * NANOMAP_ICON_SIZE) + (A.pixel_x * NANOMAP_ICON_SIZE / 32), ((WorldY - 1) * NANOMAP_ICON_SIZE) + (A.pixel_y * NANOMAP_ICON_SIZE / 32))
var/icon/TurfIcon = new(Turf.icon, Turf.icon_state)
TurfIcon.Scale(NANOMAP_ICON_SIZE, NANOMAP_ICON_SIZE)
CHECK_TICK
Tile.Blend(TurfIcon, ICON_OVERLAY, ((WorldX - 1) * NANOMAP_ICON_SIZE), ((WorldY - 1) * NANOMAP_ICON_SIZE))
count++
if (count % 8000 == 0)
world.log << "NanoMapGen: <B>[count] tiles done</B>"
sleep(1)
var/mapFilename = "nanomap_z[currentZ]-new.png"
+14 -23
View File
@@ -96,9 +96,6 @@ nanoui is used to open and update nano browser uis
add_common_assets()
var/datum/asset/assets = get_asset_datum(/datum/asset/nanoui)
assets.send(user, ntemplate_filename)
/**
* Use this proc to add assets which are common to (and required by) all nano uis
*
@@ -106,13 +103,15 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/proc/add_common_assets()
add_script("libraries.min.js") // A JS file comprising of jQuery, doT.js and jQuery Timer libraries (compressed together)
add_script("nano.js") // A JS file of the NanoUI JavaScript compressed into one file.
add_stylesheet("nanoui.css") // Concatenated CSS sheet common to all UIs, contains all of the standard NanoUI styling.
// CodeMirror
add_script("codemirror-compressed.js") // A custom minified JavaScript file of CodeMirror, with the following plugins: CSS Mode, NTSL Mode, CSS-hint addon, Search addon, Sublime Keymap.
add_stylesheet("codemirror.css") // A CSS sheet containing the basic stylings and formatting information for CodeMirror.
add_stylesheet("cm_lesser-dark.css") // A theme for CodeMirror to use, which closely resembles the rest of the NanoUI style.
add_script("nano_utility.js") // The NanoUtility JS, this is used to store utility functions.
add_script("nano_template.js") // The NanoTemplate JS, this is used to render templates.
add_script("nano_state_manager.js") // The NanoStateManager JS, it handles updates from the server and passes data to the current state
add_script("nano_state.js") // The NanoState JS, this is the base state which all states must inherit from
add_script("nano_state_default.js") // The NanoStateDefault JS, this is the "default" state (used by all UIs by default), which inherits from NanoState
add_script("nano_base_callbacks.js") // The NanoBaseCallbacks JS, this is used to set up (before and after update) callbacks which are common to all UIs
add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all UIs
add_stylesheet("shared.css") // this CSS sheet is common to all UIs
add_stylesheet("icons.css") // this CSS sheet is common to all UIs
/**
* Set the current status (also known as visibility) of this ui.
@@ -187,15 +186,7 @@ nanoui is used to open and update nano browser uis
"autoUpdateContent" = auto_update_content,
"showMap" = show_map,
"mapZLevel" = map_z_level,
"user" = list(
"name" = user.name,
"fancy" = user.client.is_preference_enabled(/datum/client_preference/browser_style)
),
"window" = list(
"width" = width,
"height" = height,
"ref" = window_id
)
"user" = list("name" = user.name)
)
return config_data
@@ -343,7 +334,7 @@ nanoui is used to open and update nano browser uis
/datum/nanoui/proc/get_html()
// before the UI opens, add the layout files based on the layout key
//add_stylesheet("layout_[layout_key].css")
add_stylesheet("layout_[layout_key].css")
add_template("layout", "layout_[layout_key].tmpl")
var/head_content = ""
@@ -392,9 +383,9 @@ nanoui is used to open and update nano browser uis
</div>
<noscript>
<div id='uiNoScript'>
<h1>Javascript Required</h1>
<p>Javascript is required in order to use this NanoUI interface.</p>
<p>Please enable Javascript in Internet Explorer, and restart your game.</p>
<h2>JAVASCRIPT REQUIRED</h2>
<p>Your Internet Explorer's Javascript is disabled (or broken).<br/>
Enable Javascript and then open this UI again.</p>
</div>
</noscript>
</body>
+18 -13
View File
@@ -43,7 +43,7 @@
return
/obj/item/weapon/clipboard/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(istype(W, /obj/item/weapon/paper) || istype(W, /obj/item/weapon/photo))
user.drop_item()
W.loc = src
@@ -106,20 +106,20 @@
else if(href_list["write"])
var/obj/item/weapon/P = locate(href_list["write"])
if(P && (P.loc == src) && istype(P, /obj/item/weapon/paper) && (P == toppaper) )
var/obj/item/I = usr.get_active_hand()
if(istype(I, /obj/item/weapon/pen))
P.attackby(I, usr)
else if(href_list["remove"])
var/obj/item/P = locate(href_list["remove"])
if(P && (P.loc == src) && (istype(P, /obj/item/weapon/paper) || istype(P, /obj/item/weapon/photo)) )
P.loc = usr.loc
usr.put_in_hands(P)
if(P == toppaper)
@@ -129,25 +129,30 @@
toppaper = newtop
else
toppaper = null
else if(href_list["rename"])
var/obj/item/weapon/O = locate(href_list["rename"])
if(O && (O.loc == src))
if(istype(O, /obj/item/weapon/paper))
var/obj/item/weapon/paper/to_rename = O
to_rename.rename()
else if(istype(O, /obj/item/weapon/photo))
var/obj/item/weapon/photo/to_rename = O
to_rename.rename()
else if(href_list["read"])
var/obj/item/weapon/paper/P = locate(href_list["read"])
if(P && (P.loc == src) && istype(P, /obj/item/weapon/paper) )
P.show_content(usr)
if(!(istype(usr, /mob/living/carbon/human) || istype(usr, /mob/observer/dead) || istype(usr, /mob/living/silicon)))
usr << browse("<HTML><HEAD><TITLE>[P.name]</TITLE></HEAD><BODY>[stars(P.info)][P.stamps]</BODY></HTML>", "window=[P.name]")
onclose(usr, "[P.name]")
else
usr << browse("<HTML><HEAD><TITLE>[P.name]</TITLE></HEAD><BODY>[P.info][P.stamps]</BODY></HTML>", "window=[P.name]")
onclose(usr, "[P.name]")
else if(href_list["look"])
var/obj/item/weapon/photo/P = locate(href_list["look"])
+6 -1
View File
@@ -102,7 +102,12 @@
else if(href_list["read"])
var/obj/item/weapon/paper/P = locate(href_list["read"])
if(P && (P.loc == src) && istype(P))
P.show_content(usr)
if(!(istype(usr, /mob/living/carbon/human) || istype(usr, /mob/observer/dead) || istype(usr, /mob/living/silicon)))
usr << browse("<HTML><HEAD><TITLE>[P.name]</TITLE></HEAD><BODY>[stars(P.info)][P.stamps]</BODY></HTML>", "window=[P.name]")
onclose(usr, "[P.name]")
else
usr << browse("<HTML><HEAD><TITLE>[P.name]</TITLE></HEAD><BODY>[P.info][P.stamps]</BODY></HTML>", "window=[P.name]")
onclose(usr, "[P.name]")
else if(href_list["look"])
var/obj/item/weapon/photo/P = locate(href_list["look"])
if(P && (P.loc == src) && istype(P))
+10 -17
View File
@@ -79,22 +79,13 @@
user << "<span class='notice'>You have to go closer if you want to read it.</span>"
return
/obj/item/weapon/paper/proc/show_content(var/mob/user, var/forceshow = 0, var/forcestars = 0, var/infolinks = 0, var/view = 1)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper)
assets.send(user)
var/data
if((!(istype(usr, /mob/living/carbon/human) || istype(usr, /mob/observer/dead) || istype(usr, /mob/living/silicon)) && !forceshow) || forcestars)
data = "<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)][stamps]</BODY></HTML>"
if(view)
usr << browse(data, "window=[name]")
onclose(usr, "[name]")
/obj/item/weapon/paper/proc/show_content(var/mob/user, var/forceshow=0)
if(!(istype(user, /mob/living/carbon/human) || istype(user, /mob/observer/dead) || istype(user, /mob/living/silicon)) && !forceshow)
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)][stamps]</BODY></HTML>", "window=[name]")
onclose(user, "[name]")
else
data = "<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[infolinks ? info_links : info][stamps]</BODY></HTML>"
if(view)
usr << browse(data, "window=[name]")
onclose(usr, "[name]")
return data
user << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info][stamps]</BODY></HTML>", "window=[name]")
onclose(user, "[name]")
/obj/item/weapon/paper/verb/rename()
set name = "Rename paper"
@@ -141,9 +132,11 @@
else //cyborg or AI not seeing through a camera
dist = get_dist(src, user)
if(dist < 2)
show_content(user, forceshow = 1)
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[info][stamps]</BODY></HTML>", "window=[name]")
onclose(usr, "[name]")
else
show_content(user, forcestars = 1)
usr << browse("<HTML><HEAD><TITLE>[name]</TITLE></HEAD><BODY>[stars(info)][stamps]</BODY></HTML>", "window=[name]")
onclose(usr, "[name]")
return
/obj/item/weapon/paper/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
+4 -1
View File
@@ -122,7 +122,10 @@
if(istype(pages[page], /obj/item/weapon/paper))
var/obj/item/weapon/paper/P = W
dat += P.show_content(usr, view = 0)
if(!(istype(usr, /mob/living/carbon/human) || istype(usr, /mob/observer/dead) || istype(usr, /mob/living/silicon)))
dat+= "<HTML><HEAD><TITLE>[P.name]</TITLE></HEAD><BODY>[stars(P.info)][P.stamps]</BODY></HTML>"
else
dat+= "<HTML><HEAD><TITLE>[P.name]</TITLE></HEAD><BODY>[P.info][P.stamps]</BODY></HTML>"
user << browse(dat, "window=[name]")
else if(istype(pages[page], /obj/item/weapon/photo))
var/obj/item/weapon/photo/P = W
+72 -55
View File
@@ -726,22 +726,26 @@
if(wiresexposed && !istype(user, /mob/living/silicon/ai))
wires.Interact(user)
return tg_ui_interact(user)
return ui_interact(user)
/obj/machinery/power/apc/ui_data(mob/user)
var/list/data = list()
data["locked"] = (locked && !emagged) ? 1 : 0
data["isOperating"] = operating
data["externalPower"] = main_status
data["powerCellStatus"] = cell ? cell.percent() : null
data["chargeMode"] = chargemode
data["chargingStatus"] = charging
data["totalLoad"] = round(lastused_total)
data["totalCharging"] = round(lastused_charging)
data["coverLocked"] = coverlocked
data["siliconUser"] = issilicon(user) || isobserver(user) //I add observer here so admins can have more control, even if it makes 'siliconUser' seem inaccurate.
data["powerChannels"] = list(
/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!user)
return
var/list/data = list(
"locked" = (locked && !emagged) ? 1 : 0,
"isOperating" = operating,
"externalPower" = main_status,
"powerCellStatus" = cell ? cell.percent() : null,
"chargeMode" = chargemode,
"chargingStatus" = charging,
"totalLoad" = round(lastused_total),
"totalCharging" = round(lastused_charging),
"coverLocked" = coverlocked,
"siliconUser" = issilicon(user) || isobserver(user), //I add observer here so admins can have more control, even if it makes 'siliconUser' seem inaccurate.
"powerChannels" = list(
list(
"title" = "Equipment",
"powerLoad" = lastused_equip,
@@ -773,14 +777,20 @@
)
)
)
)
return data
/obj/machinery/power/apc/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = default_state)
ui = tgui_process.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "apc", "[area.name] - APC" , 520, issilicon(user) ? 535 : 460, master_ui, state)
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 465 : 440)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/power/apc/proc/report()
return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
@@ -847,59 +857,66 @@
return 0
return 1
/obj/machinery/power/apc/ui_act(action, params)
/obj/machinery/power/apc/Topic(href, href_list)
if(..())
return TRUE
return 1
if(!can_use(usr, 1))
return TRUE
return 1
if(locked && !issilicon(usr) )
if(isobserver(usr) )
var/mob/observer/dead/O = usr //Added to allow admin nanoUI interactions.
if(!O.can_admin_interact() ) //NanoUI /should/ make this not needed, but better safe than sorry.
usr << "Try as you might, your ghostly fingers can't press the buttons."
return TRUE
return 1
else
usr << "You must unlock the panel to use this!"
return TRUE
return 1
switch(action)
if("cover")
coverlocked = !coverlocked
if (href_list["lock"])
coverlocked = !coverlocked
if("breaker")
toggle_breaker()
else if (href_list["breaker"])
toggle_breaker()
if("charge")
chargemode = !chargemode
if(!chargemode)
charging = 0
else if (href_list["cmode"])
chargemode = !chargemode
if(!chargemode)
charging = 0
update_icon()
if("channel")
if(params["eqp"])
equipment = setsubsystem(text2num(params["eqp"]))
update()
else if(params["lgt"])
lighting = setsubsystem(text2num(params["lgt"]))
update()
else if(params["env"])
environ = setsubsystem(text2num(params["env"]))
update()
else if (href_list["eqp"])
var/val = text2num(href_list["eqp"])
equipment = setsubsystem(val)
update_icon()
update()
if("overload")
if(istype(usr, /mob/living/silicon))
src.overload_lighting()
else if (href_list["lgt"])
var/val = text2num(href_list["lgt"])
lighting = setsubsystem(val)
update_icon()
update()
if("lock")
if(istype(usr, /mob/living/silicon))
if(emagged || (stat & (BROKEN|MAINT)))
usr << "The APC does not respond to the command."
else
locked = !locked
else if (href_list["env"])
var/val = text2num(href_list["env"])
environ = setsubsystem(val)
update_icon()
update()
src.update_icon()
return TRUE
else if (href_list["overload"])
if(istype(usr, /mob/living/silicon))
src.overload_lighting()
else if (href_list["toggleaccess"])
if(istype(usr, /mob/living/silicon))
if(emagged || (stat & (BROKEN|MAINT)))
usr << "The APC does not respond to the command."
else
locked = !locked
update_icon()
return 0
/obj/machinery/power/apc/proc/toggle_breaker()
operating = !operating
-98
View File
@@ -1,98 +0,0 @@
/**
* tgui external
*
* Contains all external tgui declarations.
**/
/**
* public
*
* Used to open and update UIs.
* If this proc is not implemented properly, the UI will not update correctly.
*
* required user mob The mob who opened/is using the UI.
* optional ui_key string The ui_key of the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
* optional master_ui datum/tgui The parent UI.
* optional state datum/ui_state The state used to determine status.
**/
/datum/proc/tg_ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_default_state)
return -1 // Not implemented.
/**
* public
*
* Data to be sent to the UI.
* This must be implemented for a UI to work.
*
* required user mob The mob interacting with the UI.
*
* return list Data to be sent to the UI.
**/
/datum/proc/ui_data(mob/user, ui_key = "main")
return list() // Not implemented.
/**
* public
*
* Called on a UI when the UI receieves a href.
* Think of this as Topic().
*
* required action string The action/button that has been invoked by the user.
* required params list A list of parameters attached to the button.
*
* return bool If the UI should be updated or not.
**/
/datum/proc/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(!ui || ui.status != UI_INTERACTIVE)
return 1 // If UI is not interactive or usr calling Topic is not the UI user, bail.
/**
* private
*
* The UI's host object (usually src_object).
* This allows modules/datums to have the UI attached to them,
* and be a part of another object.
**/
/datum/proc/ui_host()
return src // Default src.
/**
* global
*
* Used to track the current screen.
**/
/datum/var/ui_screen = "home"
/**
* global
*
* Used to track UIs for a mob.
**/
/mob/var/list/tg_open_uis = list()
/**
* verb
*
* Called by UIs when they are closed.
* Must be a verb so winset() can call it.
*
* required uiref ref The UI that was closed.
**/
/client/verb/uiclose(ref as text)
// Name the verb, and hide it from the user panel.
set name = "uiclose"
set hidden = 1
// Get the UI based on the ref.
var/datum/tgui/ui = locate(ref)
// If we found the UI, close it.
if(istype(ui))
ui.close()
// Unset machine just to be sure.
if(src && src.mob)
src.mob.unset_machine()
-223
View File
@@ -1,223 +0,0 @@
/**
* tgui process
*
* Contains all tgui state and process code.
**/
/**
* public
*
* Get a open UI given a user, src_object, and ui_key and try to update it with data.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* required ui_key string The ui_key of the UI.
* optional ui datum/tgui The UI to be updated, if it exists.
* optional force_open bool If the UI should be re-opened instead of updated.
*
* return datum/tgui The found UI.
**/
/datum/controller/process/tgui/proc/try_update_ui(mob/user, datum/src_object, ui_key, datum/tgui/ui, force_open = 0)
if(isnull(ui)) // No UI was passed, so look for one.
ui = get_open_ui(user, src_object, ui_key)
if(!isnull(ui))
var/data = src_object.ui_data(user) // Get data from the src_object.
if(!force_open) // UI is already open; update it.
ui.push_data(data)
else // Re-open it anyways.
ui.reinitialize(null, data)
return ui // We found the UI, return it.
else
return null // We couldn't find a UI.
/**
* private
*
* Get a open UI given a user, src_object, and ui_key.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object/datum which owns the UI.
* required ui_key string The ui_key of the UI.
*
* return datum/tgui The found UI.
**/
/datum/controller/process/tgui/proc/get_open_ui(mob/user, datum/src_object, ui_key)
var/src_object_key = "\ref[src_object]"
if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list))
return null // No UIs open.
else if(isnull(tg_open_uis[src_object_key][ui_key]) || !istype(tg_open_uis[src_object_key][ui_key], /list))
return null // No UIs open for this object.
for(var/datum/tgui/ui in tg_open_uis[src_object_key][ui_key]) // Find UIs for this object.
if(ui.user == user) // Make sure we have the right user
return ui
return null // Couldn't find a UI!
/**
* private
*
* Update all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs updated.
**/
/datum/controller/process/tgui/proc/update_uis(datum/src_object)
var/src_object_key = "\ref[src_object]"
if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list))
return 0 // Couldn't find any UIs for this object.
var/update_count = 0
for(var/ui_key in tg_open_uis[src_object_key])
for(var/datum/tgui/ui in tg_open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user && ui.src_object.ui_host()) // Check the UI is valid.
ui.process(force = 1) // Update the UI.
update_count++ // Count each UI we update.
return update_count
/**
* private
*
* Close all UIs attached to src_object.
*
* required src_object datum The object/datum which owns the UIs.
*
* return int The number of UIs closed.
**/
/datum/controller/process/tgui/proc/close_uis(datum/src_object)
var/src_object_key = "\ref[src_object]"
if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list))
return 0 // Couldn't find any UIs for this object.
var/close_count = 0
for(var/ui_key in tg_open_uis[src_object_key])
for(var/datum/tgui/ui in tg_open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user && ui.src_object.ui_host()) // Check the UI is valid.
ui.close() // Close the UI.
close_count++ // Count each UI we close.
return close_count
/**
* private
*
* Update all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only update UIs belonging this src_object.
* optional ui_key string If provided, only update UIs with this UI key.
*
* return int The number of UIs updated.
**/
/datum/controller/process/tgui/proc/update_user_uis(mob/user, datum/src_object = null, ui_key = null)
if(isnull(user.tg_open_uis) || !istype(user.tg_open_uis, /list) || tg_open_uis.len == 0)
return 0 // Couldn't find any UIs for this user.
var/update_count = 0
for(var/datum/tgui/ui in user.tg_open_uis)
if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.process(force = 1) // Update the UI.
update_count++ // Count each UI we upadte.
return update_count
/**
* private
*
* Close all UIs belonging to a user.
*
* required user mob The mob who opened/is using the UI.
* optional src_object datum If provided, only close UIs belonging this src_object.
* optional ui_key string If provided, only close UIs with this UI key.
*
* return int The number of UIs closed.
**/
/datum/controller/process/tgui/proc/close_user_uis(mob/user, datum/src_object = null, ui_key = null)
if(isnull(user.tg_open_uis) || !istype(user.tg_open_uis, /list) || tg_open_uis.len == 0)
return 0 // Couldn't find any UIs for this user.
var/close_count = 0
for(var/datum/tgui/ui in user.tg_open_uis)
if((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
ui.close() // Close the UI.
close_count++ // Count each UI we close.
return close_count
/**
* private
*
* Add a UI to the list of open UIs.
*
* required ui datum/tgui The UI to be added.
**/
/datum/controller/process/tgui/proc/on_open(datum/tgui/ui)
var/src_object_key = "\ref[ui.src_object]"
if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list))
tg_open_uis[src_object_key] = list(ui.ui_key = list()) // Make a list for the ui_key and src_object.
else if(isnull(tg_open_uis[src_object_key][ui.ui_key]) || !istype(tg_open_uis[src_object_key][ui.ui_key], /list))
tg_open_uis[src_object_key][ui.ui_key] = list() // Make a list for the ui_key.
// Append the UI to all the lists.
ui.user.tg_open_uis |= ui
var/list/uis = tg_open_uis[src_object_key][ui.ui_key]
uis |= ui
processing_uis |= ui
/**
* private
*
* Remove a UI from the list of open UIs.
*
* required ui datum/tgui The UI to be removed.
*
* return bool If the UI was removed or not.
**/
/datum/controller/process/tgui/proc/on_close(datum/tgui/ui)
var/src_object_key = "\ref[ui.src_object]"
if(isnull(tg_open_uis[src_object_key]) || !istype(tg_open_uis[src_object_key], /list))
return 0 // It wasn't open.
else if(isnull(tg_open_uis[src_object_key][ui.ui_key]) || !istype(tg_open_uis[src_object_key][ui.ui_key], /list))
return 0 // It wasn't open.
processing_uis.Remove(ui) // Remove it from the list of processing UIs.
if(ui.user) // If the user exists, remove it from them too.
ui.user.tg_open_uis.Remove(ui)
var/list/uis = tg_open_uis[src_object_key][ui.ui_key] // Remove it from the list of open UIs.
uis.Remove(ui)
return 1 // Let the caller know we did it.
/**
* private
*
* Handle client logout, by closing all their UIs.
*
* required user mob The mob which logged out.
*
* return int The number of UIs closed.
**/
/datum/controller/process/tgui/proc/on_logout(mob/user)
return close_user_uis(user)
/**
* private
*
* Handle clients switching mobs, by transfering their UIs.
*
* required user source The client's original mob.
* required user target The client's new mob.
*
* return bool If the UIs were transferred.
**/
/datum/controller/process/tgui/proc/on_transfer(mob/source, mob/target)
if(!source || isnull(source.tg_open_uis) || !istype(source.tg_open_uis, /list) || tg_open_uis.len == 0)
return 0 // The old mob had no open UIs.
if(isnull(target.tg_open_uis) || !istype(target.tg_open_uis, /list))
target.tg_open_uis = list() // Create a list for the new mob if needed.
for(var/datum/tgui/ui in source.tg_open_uis)
ui.user = target // Inform the UIs of their new owner.
target.tg_open_uis.Add(ui) // Transfer all the UIs.
source.tg_open_uis.Cut() // Clear the old list.
return 1 // Let the caller know we did it.
-110
View File
@@ -1,110 +0,0 @@
/**
* tgui states
*
* Base state and helpers for states. Just does some sanity checks, implement a state for in-depth checks.
**/
/**
* public
*
* Checks the UI state for a mob.
*
* required user mob The mob who opened/is using the UI.
* required state datum/ui_state The state to check.
*
* return UI_state The state of the UI.
**/
/datum/proc/ui_status(mob/user, datum/ui_state/state)
var/datum/src_object = ui_host()
if(src_object != src)
return src_object.ui_status(user, state)
if(isobserver(user)) // Special-case ghosts.
if(user.can_admin_interact())
return UI_INTERACTIVE // If they turn it on, admins can interact.
if(get_dist(src_object, src) < user.client.view)
return UI_UPDATE // Regular ghosts can only view.
return UI_CLOSE // To keep too many UIs from being opened.
return state.can_use_topic(src_object, user) // Check if the state allows interaction.
/**
* private
*
* Checks if a user can use src_object's UI, and returns the state.
* Can call a mob proc, which allows overrides for each mob.
*
* required src_object datum The object/datum which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
**/
/datum/ui_state/proc/can_use_topic(src_object, mob/user)
return UI_CLOSE // Don't allow interaction by default.
/**
* public
*
* Standard interaction/sanity checks. Different mob types may have overrides.
*
* return UI_state The state of the UI.
**/
/mob/proc/shared_ui_interaction(src_object)
if(!client) // Close UIs if mindless.
return UI_CLOSE
else if(stat) // Disable UIs if unconcious.
return UI_DISABLED
else if(incapacitated() || lying) // Update UIs if incapicitated but concious.
return UI_UPDATE
return UI_INTERACTIVE
/mob/living/silicon/ai/shared_ui_interaction(src_object)
if(lacks_power()) // Disable UIs if the AI is unpowered.
return UI_DISABLED
return ..()
/mob/living/silicon/robot/shared_ui_interaction(src_object)
if(cell.charge <= 0 || lockcharge) // Disable UIs if the Borg is unpowered or locked.
return UI_DISABLED
return ..()
/**
* public
*
* Check the distance for a living mob.
* Really only used for checks outside the context of a mob.
* Otherwise, use shared_living_ui_distance().
*
* required src_object The object which owns the UI.
* required user mob The mob who opened/is using the UI.
*
* return UI_state The state of the UI.
**/
/atom/proc/contents_ui_distance(src_object, mob/living/user)
return user.shared_living_ui_distance(src_object) // Just call this mob's check.
/**
* public
*
* Distance versus interaction check.
*
* required src_object atom/movable The object which owns the UI.
*
* return UI_state The state of the UI.
**/
/mob/living/proc/shared_living_ui_distance(atom/movable/src_object)
if(!(src_object in view(src))) // If the object is obscured, close it.
return UI_CLOSE
var/dist = get_dist(src_object, src)
if(dist <= 1) // Open and interact if 1-0 tiles away.
return UI_INTERACTIVE
else if(dist <= 2) // View only if 2-3 tiles away.
return UI_UPDATE
else if(dist <= 5) // Disable if 5 tiles away.
return UI_DISABLED
return UI_CLOSE // Otherwise, we got nothing.
/mob/living/carbon/human/shared_living_ui_distance(atom/movable/src_object)
if((TK in mutations))
return UI_INTERACTIVE
return ..()
-12
View File
@@ -1,12 +0,0 @@
/**
* tgui state: admin_state
*
* Checks that the user is an admin, end-of-story.
**/
/var/global/datum/ui_state/admin_state/tg_admin_state = new()
/datum/ui_state/admin_state/can_use_topic(src_object, mob/user)
if(check_rights(R_ADMIN, 0, user))
return UI_INTERACTIVE
return UI_CLOSE
-12
View File
@@ -1,12 +0,0 @@
/**
* tgui state: conscious_state
*
* Only checks if the user is conscious.
**/
/var/global/datum/ui_state/conscious_state/tg_conscious_state = new()
/datum/ui_state/conscious_state/can_use_topic(src_object, mob/user)
if(user.stat == CONSCIOUS)
return UI_INTERACTIVE
return UI_CLOSE
-12
View File
@@ -1,12 +0,0 @@
/**
* tgui state: contained_state
*
* Checks that the user is inside the src_object.
**/
/var/global/datum/ui_state/contained_state/tg_contained_state = new()
/datum/ui_state/contained_state/can_use_topic(atom/src_object, mob/user)
if(!src_object.contains(user))
return UI_CLOSE
return user.shared_ui_interaction(src_object)
@@ -1,12 +0,0 @@
/**
* tgui state: deep_inventory_state
*
* Checks that the src_object is in the user's deep (backpack, box, toolbox, etc) inventory.
**/
/var/global/datum/ui_state/deep_inventory_state/tg_deep_inventory_state = new()
/datum/ui_state/deep_inventory_state/can_use_topic(src_object, mob/user)
if(!user.contains(src_object))
return UI_CLOSE
return user.shared_ui_interaction(src_object)
-55
View File
@@ -1,55 +0,0 @@
/**
* tgui state: default_state
*
* Checks a number of things -- mostly physical distance for humans and view for robots.
**/
/var/global/datum/ui_state/default/tg_default_state = new()
/datum/ui_state/default/can_use_topic(src_object, mob/user)
return user.tg_default_can_use_topic(src_object) // Call the individual mob-overriden procs.
/mob/proc/tg_default_can_use_topic(src_object)
return UI_CLOSE // Don't allow interaction by default.
/mob/living/tg_default_can_use_topic(src_object)
. = shared_ui_interaction(src_object)
if(. > UI_CLOSE && loc)
. = min(., loc.contents_ui_distance(src_object, src)) // Check the distance...
if(. == UI_INTERACTIVE) // Non-human living mobs can only look, not touch.
return UI_UPDATE
/mob/living/carbon/human/tg_default_can_use_topic(src_object)
. = shared_ui_interaction(src_object)
if(. > UI_CLOSE)
. = min(., shared_living_ui_distance(src_object)) // Check the distance...
// Derp a bit if we have brain loss.
if(prob(getBrainLoss()))
return UI_UPDATE
/mob/living/silicon/robot/tg_default_can_use_topic(src_object)
. = shared_ui_interaction(src_object)
if(. <= UI_DISABLED)
return
// Robots can interact with anything they can see.
if(get_dist(src, src_object) <= client.view)
return UI_INTERACTIVE
return UI_DISABLED // Otherwise they can keep the UI open.
/mob/living/silicon/ai/tg_default_can_use_topic(src_object)
. = shared_ui_interaction(src_object)
if(. < UI_INTERACTIVE)
return
// The AI can interact with anything it can see nearby, or with cameras.
if((get_dist(src, src_object) <= client.view) || cameranet.checkTurfVis(get_turf_pixel(src_object)))
return UI_INTERACTIVE
return UI_CLOSE
/mob/living/silicon/pai/tg_default_can_use_topic(src_object)
// pAIs can only use themselves and the owner's radio.
if((src_object == src || src_object == radio) && !stat)
return UI_INTERACTIVE
else
return ..()
-20
View File
@@ -1,20 +0,0 @@
/**
* tgui state: hands_state
*
* Checks that the src_object is in the user's hands.
**/
/var/global/datum/ui_state/hands_state/tg_hands_state = new()
/datum/ui_state/hands_state/can_use_topic(src_object, mob/user)
. = user.shared_ui_interaction(src_object)
if(. > UI_CLOSE)
return min(., user.hands_can_use_topic(src_object))
/mob/proc/hands_can_use_topic(src_object)
return UI_CLOSE
/mob/living/hands_can_use_topic(src_object)
if(src_object in get_both_hands(src))
return UI_INTERACTIVE
return UI_CLOSE
-12
View File
@@ -1,12 +0,0 @@
/**
* tgui state: inventory_state
*
* Checks that the src_object is in the user's top-level (hand, ear, pocket, belt, etc) inventory.
**/
/var/global/datum/ui_state/inventory_state/tg_inventory_state = new()
/datum/ui_state/inventory_state/can_use_topic(src_object, mob/user)
if(!(src_object in user))
return UI_CLOSE
return user.shared_ui_interaction(src_object)
-26
View File
@@ -1,26 +0,0 @@
/**
* tgui state: notcontained_state
*
* Checks that the user is not inside src_object, and then makes the default checks.
**/
/var/global/datum/ui_state/notcontained_state/tg_notcontained_state = new()
/datum/ui_state/notcontained_state/can_use_topic(atom/src_object, mob/user)
. = user.shared_ui_interaction(src_object)
if(. > UI_CLOSE)
return min(., user.notcontained_can_use_topic(src_object))
/mob/proc/notcontained_can_use_topic(src_object)
return UI_CLOSE
/mob/living/notcontained_can_use_topic(atom/src_object)
if(src_object.contains(src))
return UI_CLOSE // Close if we're inside it.
return tg_default_can_use_topic(src_object)
/mob/living/silicon/notcontained_can_use_topic(src_object)
return tg_default_can_use_topic(src_object) // Silicons use default bevhavior.
/mob/living/simple_animal/drone/notcontained_can_use_topic(src_object)
return tg_default_can_use_topic(src_object) // Drones use default bevhavior.
-24
View File
@@ -1,24 +0,0 @@
/**
* tgui state: physical_state
*
* Short-circuits the default state to only check physical distance.
**/
/var/global/datum/ui_state/physical/tg_physical_state = new()
/datum/ui_state/physical/can_use_topic(src_object, mob/user)
. = user.shared_ui_interaction(src_object)
if(. > UI_CLOSE)
return min(., user.physical_can_use_topic(src_object))
/mob/proc/physical_can_use_topic(src_object)
return UI_CLOSE
/mob/living/physical_can_use_topic(src_object)
return shared_living_ui_distance(src_object)
/mob/living/silicon/physical_can_use_topic(src_object)
return max(UI_UPDATE, shared_living_ui_distance(src_object)) // Silicons can always see.
/mob/living/silicon/ai/physical_can_use_topic(src_object)
return UI_UPDATE // AIs are not physical.
-12
View File
@@ -1,12 +0,0 @@
/**
* tgui state: self_state
*
* Only checks that the user and src_object are the same.
**/
/var/global/datum/ui_state/self_state/tg_self_state = new()
/datum/ui_state/self_state/can_use_topic(src_object, mob/user)
if(src_object != user)
return UI_CLOSE
return user.shared_ui_interaction(src_object)
-14
View File
@@ -1,14 +0,0 @@
/**
* tgui state: z_state
*
* Only checks that the Z-level of the user and src_object are the same.
**/
/var/global/datum/ui_state/z_state/tg_z_state = new()
/datum/ui_state/z_state/can_use_topic(src_object, mob/user)
var/turf/turf_obj = get_turf(src_object)
var/turf/turf_usr = get_turf(user)
if(turf_obj && turf_usr && turf_obj.z == turf_usr.z)
return UI_INTERACTIVE
return UI_CLOSE
-369
View File
@@ -1,369 +0,0 @@
/**
* tgui
*
* /tg/station user interface library
**/
/**
* tgui datum (represents a UI).
**/
/datum/tgui
var/mob/user // The mob who opened/is using the UI.
var/datum/src_object // The object which owns the UI.
var/title // The title of te UI.
var/ui_key // The ui_key of the UI. This allows multiple UIs for one src_object.
var/window_id // The window_id for browse() and onclose().
var/width = 0 // The window width.
var/height = 0 // The window height
var/window_options = list( // Extra options to winset().
"focus" = FALSE,
"titlebar" = TRUE,
"can_resize" = TRUE,
"can_minimize" = TRUE,
"can_maximize" = FALSE,
"can_close" = TRUE,
"auto_format" = FALSE
)
var/style = "nanotrasen" // The style to be used for this UI.
var/interface // The interface (template) to be used for this UI.
var/autoupdate = TRUE // Update the UI every MC tick.
var/initialized = FALSE // If the UI has been initialized yet.
var/list/initial_data // The data (and datastructure) used to initialize the UI.
var/status = UI_INTERACTIVE // The status/visibility of the UI.
var/datum/ui_state/state = null // Topic state used to determine status/interactability.
var/datum/tgui/master_ui // The parent UI.
var/list/datum/tgui/children = list() // Children of this UI.
/**
* public
*
* Create a new UI.
*
* required user mob The mob who opened/is using the UI.
* required src_object datum The object or datum which owns the UI.
* required ui_key string The ui_key of the UI.
* required interface string The interface used to render the UI.
* optional title string The title of the UI.
* optional width int The window width.
* optional height int The window height.
* optional master_ui datum/tgui The parent UI.
* optional state datum/ui_state The state used to determine status.
*
* return datum/tgui The requested UI.
**/
/datum/tgui/New(mob/user, datum/src_object, ui_key, interface, title, width = 0, height = 0, datum/tgui/master_ui = null, datum/ui_state/state = tg_default_state)
src.user = user
src.src_object = src_object
src.ui_key = ui_key
src.window_id = "\ref[src_object]-[ui_key]"
set_interface(interface)
if(title)
src.title = sanitize(title)
if(width)
src.width = width
if(height)
src.height = height
src.master_ui = master_ui
if(master_ui)
master_ui.children += src
src.state = state
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/tgui)
assets.send(user)
/**
* public
*
* Open this UI (and initialize it with data).
**/
/datum/tgui/proc/open()
if(!user.client)
return // Bail if there is no client.
update_status(push = 0) // Update the window status.
if(status < UI_UPDATE)
return // Bail if we're not supposed to open.
if(!initial_data)
set_initial_data(src_object.ui_data(user)) // Get the UI data.
var/window_size = ""
if(width && height) // If we have a width and height, use them.
window_size = "size=[width]x[height];"
var/debugable = check_rights(R_DEBUG, 0, user)
user << browse(get_html(debugable), "window=[window_id];[window_size][list2params(window_options)]") // Open the window.
winset(user, window_id, "on-close=\"uiclose \ref[src]\"") // Instruct the client to signal UI when the window is closed.
tgui_process.on_open(src)
/**
* public
*
* Reinitialize the UI.
* (Possibly with a new interface and/or data).
*
* optional template string The name of the new interface.
* optional data list The new initial data.
**/
/datum/tgui/proc/reinitialize(interface, list/data)
if(interface)
set_interface(interface) // Set a new interface.
if(data)
set_initial_data(data) // Replace the initial_data.
open()
/**
* public
*
* Close the UI, and all its children.
**/
/datum/tgui/proc/close()
user << browse(null, "window=[window_id]") // Close the window.
tgui_process.on_close(src)
for(var/datum/tgui/child in children) // Loop through and close all children.
child.close()
children.Cut()
state = null
master_ui = null
qdel(src)
/**
* public
*
* Sets the browse() window options for this UI.
*
* required window_options list The window options to set.
**/
/datum/tgui/proc/set_window_options(list/window_options)
src.window_options = window_options
/**
* public
*
* Set the style for this UI.
*
* required style string The new UI style.
**/
/datum/tgui/proc/set_style(style)
src.style = lowertext(style)
/**
* public
*
* Set the interface (template) for this UI.
*
* required interface string The new UI interface.
**/
/datum/tgui/proc/set_interface(interface)
src.interface = lowertext(interface)
/**
* public
*
* Enable/disable auto-updating of the UI.
*
* required state bool Enable/disable auto-updating.
**/
/datum/tgui/proc/set_autoupdate(state = 1)
autoupdate = state
/**
* private
*
* Set the data to initialize the UI with.
* The datastructure cannot be changed by subsequent updates.
*
* optional data list The data/datastructure to initialize the UI with.
**/
/datum/tgui/proc/set_initial_data(list/data)
initial_data = data
/**
* private
*
* Generate HTML for this UI.
*
* optional bool inline If the JSON should be inlined into the HTML (for debugging).
*
* return string UI HTML output.
**/
/datum/tgui/proc/get_html(var/inline)
var/html
// Poplate HTML with JSON if we're supposed to inline.
if(inline)
html = replacetextEx(tgui_process.basehtml, "{}", get_json(initial_data))
else
html = tgui_process.basehtml
html = replacetextEx(html, "\[ref]", "\ref[src]")
html = replacetextEx(html, "\[style]", style)
return html
/**
* private
*
* Get the config data/datastructure to initialize the UI with.
*
* return list The config data.
**/
/datum/tgui/proc/get_config_data()
var/list/config_data = list(
"title" = title,
"status" = status,
"screen" = src_object.ui_screen,
"style" = style,
"interface" = interface,
"fancy" = user.is_preference_enabled(/datum/client_preference/tgui_style),
"locked" = user.is_preference_enabled(/datum/client_preference/tgui_monitor),
"window" = window_id,
"ref" = "\ref[src]",
"user" = list(
"name" = user.name,
"ref" = "\ref[user]"
),
"srcObject" = list(
"name" = "[src_object]",
"ref" = "\ref[src_object]"
)
)
return config_data
/**
* private
*
* Package the data to send to the UI, as JSON.
* This includes the UI data and config_data.
*
* return string The packaged JSON.
**/
/datum/tgui/proc/get_json(list/data)
var/list/json_data = list()
json_data["config"] = get_config_data()
if(!isnull(data))
json_data["data"] = data
// Generate the JSON.
var/json = json_encode(json_data)
// Strip #255/improper.
json = replacetext(json, "\proper", "")
json = replacetext(json, "\improper", "")
return json
/**
* private
*
* Handle clicks from the UI.
* Call the src_object's ui_act() if status is UI_INTERACTIVE.
* If the src_object's ui_act() returns 1, update all UIs attacked to it.
**/
/datum/tgui/Topic(href, href_list)
if(user != usr)
return // Something is not right here.
var/action = href_list["action"]
var/params = href_list; params -= "action"
switch(action)
if("tgui:initialize")
user << output(url_encode(get_json(initial_data)), "[window_id].browser:initialize")
initialized = TRUE
if("tgui:view")
if(params["screen"])
src_object.ui_screen = params["screen"]
tgui_process.update_uis(src_object)
if("tgui:link")
user << link(params["url"])
if("tgui:fancy")
user.set_preference(/datum/client_preference/tgui_style, TRUE)
if("tgui:nofrills")
user.set_preference(/datum/client_preference/tgui_style, FALSE)
else
update_status(push = 0) // Update the window state.
if(src_object.ui_act(action, params, src, state)) // Call ui_act() on the src_object.
tgui_process.update_uis(src_object) // Update if the object requested it.
/**
* private
*
* Update the UI.
* Only updates the data if update is true, otherwise only updates the status.
*
* optional force bool If the UI should be forced to update.
**/
/datum/tgui/proc/process(force = 0)
var/datum/host = src_object.ui_host()
if(!src_object || !host || !user) // If the object or user died (or something else), abort.
close()
return
if(status && (force || autoupdate))
update() // Update the UI if the status and update settings allow it.
else
update_status(push = 1) // Otherwise only update status.
/**
* private
*
* Push data to an already open UI.
*
* required data list The data to send.
* optional force bool If the update should be sent regardless of state.
**/
/datum/tgui/proc/push_data(data, force = 0)
update_status(push = 0) // Update the window state.
if(!initialized)
return // Cannot update UI if it is not set up yet.
if(status <= UI_DISABLED && !force)
return // Cannot update UI, we have no visibility.
// Send the new JSON to the update() Javascript function.
user << output(url_encode(get_json(data)), "[window_id].browser:update")
/**
* private
*
* Updates the UI by interacting with the src_object again, which will hopefully
* call try_ui_update on it.
*
* optional force_open bool If force_open should be passed to ui_interact.
**/
/datum/tgui/proc/update(force_open = 0)
src_object.tg_ui_interact(user, ui_key, src, force_open, master_ui, state)
/**
* private
*
* Update the status/visibility of the UI for its user.
*
* optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
**/
/datum/tgui/proc/update_status(push = 0)
var/status = src_object.ui_status(user, state)
if(master_ui)
status = min(status, master_ui.status)
set_status(status, push)
if(status == UI_CLOSE)
close()
/**
* private
*
* Set the status/visibility of the UI.
*
* required status int The status to set (UI_CLOSE/UI_DISABLED/UI_UPDATE/UI_INTERACTIVE).
* optional push bool Push an update to the UI (an update is always sent for UI_DISABLED).
**/
/datum/tgui/proc/set_status(status, push = 0)
if(src.status != status) // Only update if status has changed.
if(src.status == UI_DISABLED)
src.status = status
if(push)
update()
else
src.status = status
if(status == UI_DISABLED || push) // Update if the UI just because disabled, or a push is requested.
push_data(null, force = 1)
+97 -48
View File
@@ -1,4 +1,5 @@
body {
body
{
padding: 0;
margin: 0;
background-color: #272727;
@@ -7,12 +8,14 @@ body {
line-height: 170%;
}
hr {
hr
{
background-color: #40628a;
height: 1px;
}
a, a:link, a:visited, a:active, .linkOn, .linkOff {
a, a:link, a:visited, a:active, .linkOn, .linkOff
{
color: #ffffff;
text-decoration: none;
background: #40628a;
@@ -23,12 +26,14 @@ a, a:link, a:visited, a:active, .linkOn, .linkOff {
white-space:nowrap;
}
a:hover {
a:hover
{
color: #40628a;
background: #ffffff;
}
a.white, a.white:link, a.white:visited, a.white:active {
a.white, a.white:link, a.white:visited, a.white:active
{
color: #40628a;
text-decoration: none;
background: #ffffff;
@@ -38,29 +43,34 @@ a.white, a.white:link, a.white:visited, a.white:active {
cursor:default;
}
a.white:hover {
a.white:hover
{
color: #ffffff;
background: #40628a;
}
.linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover {
.linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover
{
color: #ffffff;
background: #2f943c;
border-color: #24722e;
}
.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover {
.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover
{
color: #ffffff;
background: #999999;
border-color: #666666;
}
a.icon, .linkOn.icon, .linkOff.icon {
a.icon, .linkOn.icon, .linkOff.icon
{
position: relative;
padding: 1px 4px 2px 20px;
}
a.icon img, .linkOn.icon img {
a.icon img, .linkOn.icon img
{
position: absolute;
top: 0;
left: 0;
@@ -68,13 +78,15 @@ a.icon img, .linkOn.icon img {
height: 18px;
}
a.icon64, .linkOn.icon64, .linkOff.icon64 {
a.icon64, .linkOn.icon64, .linkOff.icon64
{
position: relative;
padding: 1px 4px 2px 68px;
font-size: 55px;
}
a.icon64 img, .linkOn.icon64 img {
a.icon64 img, .linkOn.icon64 img
{
position: absolute;
top: 0;
left: 0;
@@ -82,49 +94,60 @@ a.icon64 img, .linkOn.icon64 img {
height: 66px;
}
ul {
ul
{
padding: 4px 0 0 10px;
margin: 0;
list-style-type: none;
}
li {
li
{
padding: 0 0 2px 0;
}
img, a img {
img, a img
{
border-style:none;
}
h1, h2, h3, h4, h5, h6 {
h1, h2, h3, h4, h5, h6
{
margin: 0;
padding: 16px 0 8px 0;
color: #517087;
}
h1 {
h1
{
font-size: 15px;
}
h2 {
h2
{
font-size: 14px;
}
h3 {
h3
{
font-size: 13px;
}
h4 {
h4
{
font-size: 12px;
}
.uiWrapper {
.uiWrapper
{
width: 100%;
height: 100%;
padding-top:32px;
}
.uiTitle {
.uiTitle
{
clear: both;
padding: 6px 8px 6px 8px;
border-bottom: 2px solid #161616;
@@ -133,7 +156,8 @@ h4 {
font-size: 16px;
}
.uiTitleWrapper {
.uiTitleWrapper
{
position:fixed;
top:0px;
left:0px;
@@ -141,7 +165,8 @@ h4 {
z-index: 10
}
.uiTitleButtons {
.uiTitleButtons
{
position:fixed;
top:0px;
right:0px;
@@ -150,39 +175,47 @@ h4 {
}
.uiTitle.icon {
.uiTitle.icon
{
padding: 6px 8px 6px 42px;
background-position: 2px 50%;
background-repeat: no-repeat;
}
.uiContent {
.uiContent
{
clear: both;
padding: 8px;
font-family: Verdana, Geneva, sans-serif;
}
.good {
.good
{
color: #00ff00;
}
.average {
.average
{
color: #d09000;
}
.bad {
.bad
{
color: #ff0000;
}
.highlight {
.highlight
{
color: #8BA5C4;
}
.dark {
.dark
{
color: #272727;
}
.notice {
.notice
{
position: relative;
background: #E9C183;
color: #15345A;
@@ -192,11 +225,13 @@ h4 {
margin: 4px;
}
.notice.icon {
.notice.icon
{
padding: 2px 4px 0 20px;
}
.notice img {
.notice img
{
position: absolute;
top: 0;
left: 0;
@@ -204,11 +239,13 @@ h4 {
height: 16px;
}
div.notice {
div.notice
{
clear: both;
}
.statusDisplay {
.statusDisplay
{
background: #000000;
color: #ffffff;
border: 1px solid #40628a;
@@ -216,18 +253,21 @@ div.notice {
margin: 3px 0;
}
.block {
.block
{
padding: 8px;
margin: 10px 4px 4px 4px;
border: 1px solid #40628a;
background-color: #202020;
}
.block h3 {
.block h3
{
padding: 0;
}
.progressBar {
.progressBar
{
width: 240px;
height: 14px;
border: 1px solid #666666;
@@ -236,46 +276,55 @@ div.notice {
overflow: hidden;
}
.progressFill {
.progressFill
{
width: 100%;
height: 100%;
background: #40628a;
overflow: hidden;
}
.progressFill.good {
.progressFill.good
{
color: #ffffff;
background: #00ff00;
}
.progressFill.average {
.progressFill.average
{
color: #ffffff;
background: #d09000;
}
.progressFill.bad {
.progressFill.bad
{
color: #ffffff;
background: #ff0000;
}
.progressFill.highlight {
.progressFill.highlight
{
color: #ffffff;
background: #8BA5C4;
}
.clearBoth {
.clearBoth
{
clear: both;
}
.clearLeft {
.clearLeft
{
clear: left;
}
.clearRight {
.clearRight
{
clear: right;
}
.line {
.line
{
width: 100%;
clear: both;
}
+4 -2
View File
@@ -1,9 +1,11 @@
.statusLabel {
.statusLabel
{
width: 128px;
float: left;
overflow: hidden;
}
.statusValue {
.statusValue
{
float: left;
}
+8 -4
View File
@@ -1,21 +1,25 @@
.getblockstring {
.getblockstring
{
font-family: Fixed, monospace;
}
.blockString {
.blockString
{
width: 55px;
height: 19px;
padding: 0 8px 8px 0;
float: left;
}
.statusLabel {
.statusLabel
{
width: 128px;
float: left;
overflow: hidden;
}
.statusValue {
.statusValue
{
float: left;
}
+4 -2
View File
@@ -1,9 +1,11 @@
.statusLabel {
.statusLabel
{
width: 128px;
float: left;
overflow: hidden;
}
.statusValue {
.statusValue
{
float: left;
}
-38
View File
@@ -1,38 +0,0 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# wip (For works in progress)
# tweak
# soundadd
# sounddel
# rscadd (general adding of nice things)
# rscdel (general deleting of nice things)
# imageadd
# imagedel
# maptweak
# spellcheck (typo fixes)
# experiment
#################################
# Your name.
author: Sin4
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
changes:
- rscadd: "Upgrades NanoUI to version used by Paradise."
- rscadd: "Ports tgui from Baystation."
- rscadd: "Airlock electronics, APC, ATM, Brig Door Timers, Space Heaters, and Canisters now use tgui."

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

-26
View File
@@ -1718,32 +1718,6 @@ window "mainwindow"
macro = "macro"
menu = "menu"
on-close = ""
elem "asset_cache_browser"
type = BROWSER
pos = 424,208
size = 1x1
anchor1 = none
anchor2 = none
font-family = ""
font-size = 0
font-style = ""
text-color = #000000
background-color = none
is-visible = false
is-disabled = false
is-transparent = false
is-default = false
border = none
drop-zone = false
right-click = false
saved-params = ""
on-size = ""
show-history = false
show-url = false
auto-format = true
use-title = false
on-show = ""
on-hide = ""
elem "hotkey_toggle"
type = BUTTON
pos = 560,420
-2
View File
@@ -1,2 +0,0 @@
node_modules/
bower_components/
-108
View File
@@ -1,108 +0,0 @@
### Settings ###
util = require("gulp-util")
s =
min: util.env.min
# Project Paths
input =
fonts: "**/*.{eot,woff2}"
images: "images"
layouts: "layouts/"
scripts:
lib: "scripts/libraries"
main: "scripts/nano"
styles: "styles"
templates: "templates/"
output =
dir: "assets"
scripts:
lib: "libraries.min.js"
main: "nano.js"
css: "nanoui.css"
### Pacakages ###
bower = require "main-bower-files"
child_process = require "child_process"
del = require "del"
gulp = require "gulp"
merge = require "merge-stream"
### Plugins ###
g = require("gulp-load-plugins")({replaceString: /^gulp(-|\.)|-/g})
p =
autoprefixer: require "autoprefixer"
gradient: require "postcss-filter-gradient"
opacity: require "postcss-opacity"
rgba: require "postcss-color-rgba-fallback"
plsfilters: require "pleeease-filters"
### Helpers ###
glob = (path) ->
"#{path}/*"
### Tasks ###
gulp.task "default", ["fonts", "scripts", "styles"]
gulp.task "clean", ->
del glob output.dir
gulp.task "watch", ->
gulp.watch [glob input.images], ["reload"]
gulp.watch [glob input.layouts], ["reload"]
gulp.watch [glob input.scripts.lib], ["reload"]
gulp.watch [glob input.scripts.main], ["reload"]
gulp.watch [glob input.styles], ["reload"]
gulp.watch [glob input.templates], ["reload"]
gulp.task "reload", ["default"], ->
child_process.exec "reload.bat", (err, stdout, stderr) ->
return console.log err if err
gulp.task "fonts", ["clean"], ->
gulp.src bower input.fonts
.pipe gulp.dest output.dir
gulp.task "scripts", ["clean"], ->
lib = gulp.src glob input.scripts.lib
etc = gulp.src bower "**/*.js"
merged = merge lib, etc
.pipe g.order(["jquery.js",
"jquery*.js",
"*.js"])
.pipe g.concat(output.scripts.lib)
.pipe g.if(s.min, g.uglify().on('error', util.log))
.pipe gulp.dest output.dir
main = gulp.src glob input.scripts.main
.pipe g.order(["nano_utility.js",
"nano_state_manager.js"
"*.js"])
.pipe g.concat(output.scripts.main)
.pipe g.if(s.min, g.uglify().on('error', util.log))
.pipe gulp.dest output.dir
gulp.task "styles", ["clean"], ->
lib = gulp.src bower "**/*.css"
.pipe g.replace("../fonts/", "")
main = gulp.src glob input.styles
.pipe g.filter(["*.less", "!_*.less"])
.pipe g.less({paths: [input.images]})
.pipe g.postcss([
p.autoprefixer({browsers: ["last 2 versions", "ie >= 8"]}),
p.gradient,
p.opacity,
p.rgba({oldie: true}),
p.plsfilters({oldIE: true})
])
combined = merge lib, main
combined
.pipe g.if(s.min, g.cssnano({discardComments: {removeAll: true}}), g.csscomb())
.pipe g.concat(output.css)
.pipe gulp.dest output.dir
-2
View File
@@ -1,2 +0,0 @@
require('coffee-script/register');
require('./Gulpfile.coffee');
-107
View File
@@ -1,107 +0,0 @@
# NanoUI
NanoUI is a user interface library, used for over 100 different interfaces, and rising.
It is more complicated than the other two UI systems in use, the `/datum/browser` and
`browse()` systems, but offers pre-made libraries, JavaScript, and a modified doT
template engine.
This README is not yet complete, but gives a basic rundown of how the folder structure
works. I'll get around to finishing it one day.
## Contributors
This section is for listing the contributors to NanoUI.
- -tg-station/Neersighted
- Special thanks goes to Neersighted for creating most of the newest and best features
of NanoUI. Everything between using the Gulp build system to switching to LESS styles
has been directly adapated and/or copied from his original work for -tg-station and
their UI system, tgui.
Systems ported/adapted from -tg-station and Neersighted include, but are not limited
to:
- NanoUI's JavaScript controlling the "fancy" borderless window mode.
- The NanoTrasen.svg logo (Licensed under CC 3.0 BY-SA).
- The Gulp buildscript concept, as well as a large amount of the actual
Gulpfile.coffee.
- The packages in bower.json and packages.json files were hand-picked by Neersighted
for usage in compiling NanoUI.
- A considerable amount of this README is adapated from Neersighted's documentation.
- The concepts following: Using FontAwesome instead of icon16, Using LESS to expand
NanoUI's CSS style.
NanoUI is licensed under AGPLv3. This applies to it's serverside `DM` code as well as it's
clientside `JavaScript` and `LESS` code. The file `nano/images/nanotrasen.svg` is licensed
under CC 3.0 BY-SA, and was created by Neersighted. All other image files in the
`nano/images/` directory are subject to the standard image license applied to the Paradise
repository icons.
## Folder Rundown
### /assets
The assets folder is used by the Gulp compiling system, and stores the minified version of
the NanoUI JavaScript Library and prerequisites. Everything within this folder is sent to
the client as-is.
### /codemirror
This folder contains all of the JavaScript and CSS for CodeMirror. It is sent to the
client as-is. CodeMirror only has it's own folder due to the fact that it can't be
directly compiled into the NanoUI files.
### /images
This folder is used to store any image files. It is sent to the client as-is.
### /layouts
This folder is used for the central "layout" template files, which is loaded before the
UI's actual template file. It is sent to the client as-is.
### /scripts
This folder is used for anything that will be compiled by the Gulp compilation system.
Currently, it is split into two folders. The file names must start with a number, as this
is how Gulp decides what order to put the concatenated and possibly minified files in.
Anything within this folder is not sent to the client directly.
#### /scripts/libraries
This folder is used to store the source code of the prerequisites of NanoUI. Currently,
it contains jQuery, jQuery UI, jQuery timers, and the doT template system.
#### /scripts/nano
This folder contains the primary JavaScript for NanoUI.
### /styles
This folder is used for NanoUI's LESS styles. These are compiled via gulp into the file
`nanoui.css`. LESS is a system that expands upon CSS in order to make it better, as well
as less complicated.
Any LESS file that is prefixed with the `_` character will be ignored during compilation.
These files are still included, however, via `@import`, view the file
[`nanoui.less`](http://github.com/ParadiseSS13/Paradise/blob/master/nano/styles/nanoui.less) to see how this works.
### /templates
This folder is used to store the .tmpl files which are later compiled by the NanoUtility
JavaScript, using a modified version of the doT template engine. It is sent to the client
as-is.
## Compiling
To compile any changes to the NanoUI JavaScript, you must first setup the building
environment.
### Prerequisites
You will first need to install the primary prerequisite of NanoUI, [Node.js](https://nodejs.org).
Node.js is used to obtain all of the remaining prerequisites to compile NanoUI. This is
done by running the following commands.
- `npm install -g gulp bower`
- `npm install`
- `bower install`
### Running Gulp
NanoUI is built using the `gulp` task automation system. This system uses the contents
of the `Gulpfile.js` and `Gulpfile.coffee` files to perform compilation tasks.
In order to build an un-minified version of NanoUI, you may simply run `gulp` in the
`nanoui` directory. However, this should only be used while testing, and you should run
the command `gulp --min` before commiting changes, in order to produce minified
JavaScript.
+4
View File
@@ -0,0 +1,4 @@
copy css\* "%USERPROFILE%\Documents\BYOND\cache" /y
copy images\* "%USERPROFILE%\Documents\BYOND\cache" /y
copy js\* "%USERPROFILE%\Documents\BYOND\cache" /y
copy templates\* "%USERPROFILE%\Documents\BYOND\cache" /y
Binary file not shown.
Binary file not shown.

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