Merge remote-tracking branch 'upstream/master' into rnd-tgui-rebase

This commit is contained in:
nicetoolbox
2020-10-01 22:22:16 -07:00
114 changed files with 3063 additions and 2001 deletions
+42 -41
View File
@@ -36,13 +36,13 @@ actual development.
Due to limitations of the engine, this may not always be possible; but do try your best.
* Document and explain your pull requests thoroughly. Failure to do so will delay a PR as
we question why changes were made. This is especially important if you're porting a PR
we question why changes were made. This is especially important if you're porting a PR
from another codebase (i.e. TG) and divert from the original. Explaining with single
comment on why you've made changes will help us review the PR faster and understand your
decision making process.
* Any pull request must have a changelog, this is to allow us to know when a PR is deployed
on the live server. Inline changelogs are supported through the format described
* Any pull request must have a changelog, this is to allow us to know when a PR is deployed
on the live server. Inline changelogs are supported through the format described
[here](https://github.com/ParadiseSS13/Paradise/pull/3291#issuecomment-172950466)
and should be used rather than manually edited .yml file changelogs.
@@ -51,14 +51,14 @@ actual development.
commits. Use `git rebase` or `git reset` to update your branches, not `git pull`.
* Please explain why you are submitting the pull request, and how you think your change will be beneficial to the game. Failure to do so will be grounds for rejecting the PR.
* If your pull request is not finished make sure it is at least testable in a live environment. Pull requests that do not at least meet this requirement may be closed at maintainer discretion. You may request a maintainer reopen the pull request when you're ready, or make a new one.
* While we have no issue helping contributors (and especially new contributors) bring reasonably sized contributions up to standards via the pull request review process, larger contributions are expected to pass a higher bar of completeness and code quality *before* you open a pull request. Maintainers may close such pull requests that are deemed to be substantially flawed. You should take some time to discuss with maintainers or other contributors on how to improve the changes.
* While we have no issue helping contributors (and especially new contributors) bring reasonably sized contributions up to standards via the pull request review process, larger contributions are expected to pass a higher bar of completeness and code quality *before* you open a pull request. Maintainers may close such pull requests that are deemed to be substantially flawed. You should take some time to discuss with maintainers or other contributors on how to improve the changes.
#### Using Changelog
* Tags used in changelog include add/rscadd, del/rscdel, fix/fixes, typo/spellcheck.
* Without specifying a name it will default to using your GitHub name.
* Tags used in changelog include add/rscadd, del/rscdel, fix/fixes, typo/spellcheck.
* Without specifying a name it will default to using your GitHub name.
Some examples
```
:cl:
@@ -76,11 +76,11 @@ typo: Fixes some misspelled words under Using Changelog
## Specifications
As mentioned before, you are expected to follow these specifications in order to make everyone's lives easier. It'll save both your time and ours, by making
As mentioned before, you are expected to follow these specifications in order to make everyone's lives easier. It'll save both your time and ours, by making
sure you don't have to make any changes and we don't have to ask you to. Thank you for reading this section!
### Object Oriented Code
As BYOND's Dream Maker (henceforth "DM") is an object-oriented language, code must be object-oriented when possible in order to be more flexible when adding
As BYOND's Dream Maker (henceforth "DM") is an object-oriented language, code must be object-oriented when possible in order to be more flexible when adding
content to it. If you don't know what "object-oriented" means, we highly recommend you do some light research to grasp the basics.
### All BYOND paths must contain the full path
@@ -113,7 +113,7 @@ datum
code
```
The use of this is not allowed in this project *unless the majority of the file is already relatively pathed* as it makes finding definitions via full text
The use of this is not allowed in this project *unless the majority of the file is already relatively pathed* as it makes finding definitions via full text
searching next to impossible. The only exception is the variables of an object may be nested to the object, but must not nest further.
The previous code made compliant:
@@ -167,7 +167,7 @@ ever forming.
```DM
//Good
var/atom/A
var/atom/A
"[A]"
//Bad
@@ -177,7 +177,7 @@ var/atom/A
### Use the pronoun library instead of `\his` macros.
We have a system in code/\_\_HELPERS/pronouns.dm for addressing all forms of pronouns. This is useful in a number of ways;
* BYOND's \his macro can be unpredictable on what object it references.
Take this example: `"[user] waves \his [user.weapon] around, hitting \his opponents!"`.
Take this example: `"[user] waves \his [user.weapon] around, hitting \his opponents!"`.
This will end up referencing the user's gender in the first occurence, but what about the second?
It'll actually print the gender set on the weapon he's carrying, which is unintended - and there's no way around this.
* It always prints the real `gender` variable of the atom it's referencing. This can lead to exposing a mob's gender even when their face is covered,
@@ -217,7 +217,7 @@ You must use tabs to indent your code, NOT SPACES.
Hacky code, such as adding specific checks (ex: `istype(src, /obj/whatever)`), is highly discouraged and only allowed when there is ***no*** other option. (
Protip: 'I couldn't immediately think of a proper way so thus there must be no other option' is not gonna cut it here! If you can't think of anything else, say that outright and admit that you need help with it. Maintainers exist for exactly that reason.)
You can avoid hacky code by using object-oriented methodologies, such as overriding a function (called "procs" in DM) or sectioning code into functions and
You can avoid hacky code by using object-oriented methodologies, such as overriding a function (called "procs" in DM) or sectioning code into functions and
then overriding them as required.
The same also applies to bugfix - If an invalid value is being passed into a proc from something that shouldn't have that value, don't fix it on the proc itself, fix it at its origin! (Where feasible)
@@ -239,15 +239,15 @@ There are two key points here:
Remember: although this tradeoff makes sense in many cases, it doesn't cover them all. Think carefully about your addition before deciding if you need to use it.
### Prefer `Initialize()` over `New()` for atoms
Our game controller is pretty good at handling long operations and lag, but it can't control what happens when the map is loaded, which calls `New` for all atoms on the map. If you're creating a new atom, use the `Initialize` proc to do what you would normally do in `New`. This cuts down on the number of proc calls needed when the world is loaded.
Our game controller is pretty good at handling long operations and lag, but it can't control what happens when the map is loaded, which calls `New` for all atoms on the map. If you're creating a new atom, use the `Initialize` proc to do what you would normally do in `New`. This cuts down on the number of proc calls needed when the world is loaded.
While we normally encourage (and in some cases, even require) bringing out of date code up to date when you make unrelated changes near the out of date code, that is not the case for `New` -> `Initialize` conversions. These systems are generally more dependant on parent and children procs so unrelated random conversions of existing things can cause bugs that take months to figure out.
### No implicit var/
When you declare a parameter in a proc, the var/ is implicit. Do not include any implicit var/ when declaring a variable.
I.e.
Bad:
I.e.
Bad:
````
obj/item/proc1(var/input1, var/input2)
````
@@ -258,7 +258,7 @@ obj/item/proc1(input1, input2)
````
### No magic numbers or strings
This means stuff like having a "mode" variable for an object set to "1" or "2" with no clear indicator of what that means. Make these #defines with a name that
This means stuff like having a "mode" variable for an object set to "1" or "2" with no clear indicator of what that means. Make these #defines with a name that
more clearly states what it's for. For instance:
````DM
/datum/proc/do_the_thing(thing_to_do)
@@ -285,10 +285,10 @@ This is clearer and enhances readability of your code! Get used to doing it!
(if, while, for, etc)
* All control statements must not contain code on the same line as the statement (`if(condition) return`)
* All control statements comparing a variable to a number should use the formula of `thing` `operator` `number`, not the reverse
* All control statements comparing a variable to a number should use the formula of `thing` `operator` `number`, not the reverse
(eg: `if(count <= 10)` not `if(10 >= count)`)
* All control statements must be spaced as `if()`, with the brackets touching the keyword.
* Do not use one-line control statements.
* All control statements must be spaced as `if()`, with the brackets touching the keyword.
* Do not use one-line control statements.
Instead of doing
```
if(x) return
@@ -305,7 +305,7 @@ you must use `to_chat(mob/client/world, "message")`. Failure to do so will lead
### Use early return
Do not enclose a proc in an if-block when returning on a condition is more feasible.
This is bad:
````DM
/datum/datum1/proc/proc1()
@@ -329,11 +329,11 @@ This prevents nesting levels from getting deeper then they need to be.
### Uses addtimer() instead of sleep() or spawn()
If you need to call a proc after a set amount of time, use addtimer() instead of spawn() / sleep() where feasible.
Although it is more complex, it is more performant and unlike spawn() or sleep(), it can be cancelled.
Although it is more complex, it is more performant and unlike spawn() or sleep(), it can be cancelled.
For more details, see https://github.com/tgstation/tgstation/pull/22933.
Look for code example on how to properly use it.
This is bad:
````DM
/datum/datum1/proc/proc1()
@@ -369,13 +369,13 @@ This prevents nesting levels from getting deeper then they need to be.
#### Bitflags
* We prefer using bitshift operators instead of directly typing out the value. I.E.
```
```
#define MACRO_ONE (1<<0)
#define MACRO_TWO (1<<1)
#define MACRO_THREE (1<<2)
```
Is preferable to
```
```
#define MACRO_ONE 1
#define MACRO_TWO 2
#define MACRO_THREE 4
@@ -455,7 +455,7 @@ SS13 has a lot of legacy code that's never been updated. Here are some examples
* All changes to the database's layout(schema) must be specified in the database changelog in SQL, as well as reflected in the schema files
* Any time the schema is changed the `DB_MAJOR_VERSION` defines must be incremented, as well as the example config, with an appropriate conversion kit placed
* Any time the schema is changed the `DB_MAJOR_VERSION` defines must be incremented, as well as the example config, with an appropriate conversion kit placed
in the SQL/updates folder.
* Queries must never specify the database, be it in code, or in text files in the repo.
@@ -463,7 +463,7 @@ in the SQL/updates folder.
### Mapping Standards
* Map Merge
* You MUST run Map Merge prior to opening your PR when updating existing maps to minimize the change differences (even when using third party mapping programs such as FastDMM.)
* Failure to run Map Merge on a map after using third party mapping programs (such as FastDMM) greatly increases the risk of the map's key dictionary
* Failure to run Map Merge on a map after using third party mapping programs (such as FastDMM) greatly increases the risk of the map's key dictionary
becoming corrupted by future edits after running map merge. Resolving the corruption issue involves rebuilding the map's key dictionary;
* Variable Editing (Var-edits)
@@ -487,12 +487,12 @@ in the SQL/updates folder.
Like all languages, Dream Maker has its quirks, some of them are beneficial to us, like these
#### In-To for-loops
```for(var/i = 1, i <= some_value, i++)``` is a fairly standard way to write an incremental for loop in most languages (especially those in the C family), but
```for(var/i = 1, i <= some_value, i++)``` is a fairly standard way to write an incremental for loop in most languages (especially those in the C family), but
DM's ```for(var/i in 1 to some_value)``` syntax is oddly faster than its implementation of the former syntax; where possible, it's advised to use DM's syntax. (
Note, the ```to``` keyword is inclusive, so it automatically defaults to replacing ```<=```; if you want ```<``` then you should write it as ```1 to
Note, the ```to``` keyword is inclusive, so it automatically defaults to replacing ```<=```; if you want ```<``` then you should write it as ```1 to
some_value-1```).
HOWEVER, if either ```some_value``` or ```i``` changes within the body of the for (underneath the ```for(...)``` header) or if you are looping over a list AND
HOWEVER, if either ```some_value``` or ```i``` changes within the body of the for (underneath the ```for(...)``` header) or if you are looping over a list AND
changing the length of the list then you can NOT use this type of for-loop!
### for(var/A in list) VS for(var/i in 1 to list.len)
@@ -510,9 +510,9 @@ for(var/obj/item/sword/S in bag_of_items)
if(!best_sword || S.damage > best_sword.damage)
best_sword = S
```
The above is a simple proc for checking all swords in a container and returning the one with the highest damage, and it uses DM's standard syntax for a
for-loop by specifying a type in the variable of the for's header that DM interprets as a type to filter by. It performs this filter using ```istype()``` (or
some internal-magic similar to ```istype()``` - this is BYOND, after all). This is fine in its current state for ```bag_of_items```, but if ```bag_of_items```
The above is a simple proc for checking all swords in a container and returning the one with the highest damage, and it uses DM's standard syntax for a
for-loop by specifying a type in the variable of the for's header that DM interprets as a type to filter by. It performs this filter using ```istype()``` (or
some internal-magic similar to ```istype()``` - this is BYOND, after all). This is fine in its current state for ```bag_of_items```, but if ```bag_of_items```
contained ONLY swords, or only SUBTYPES of swords, then the above is inefficient. For example:
```DM
var/list/bag_of_swords = list(sword, sword, sword, sword)
@@ -521,10 +521,10 @@ for(var/obj/item/sword/S in bag_of_swords)
if(!best_sword || S.damage > best_sword.damage)
best_sword = S
```
specifies a type for DM to filter by.
specifies a type for DM to filter by.
With the previous example that's perfectly fine, we only want swords, but here the bag only contains swords? Is DM still going to try to filter because we gave
it a type to filter by? YES, and here comes the inefficiency. Wherever a list (or other container, such as an atom (in which case you're technically accessing
With the previous example that's perfectly fine, we only want swords, but here the bag only contains swords? Is DM still going to try to filter because we gave
it a type to filter by? YES, and here comes the inefficiency. Wherever a list (or other container, such as an atom (in which case you're technically accessing
their special contents list, but that's irrelevant)) contains datums of the same datatype or subtypes of the datatype you require for your loop's body,
you can circumvent DM's filtering and automatic ```istype()``` checks by writing the loop as such:
```DM
@@ -535,7 +535,7 @@ for(var/s in bag_of_swords)
if(!best_sword || S.damage > best_sword.damage)
best_sword = S
```
Of course, if the list contains data of a mixed type then the above optimisation is DANGEROUS, as it will blindly typecast all data in the list as the
Of course, if the list contains data of a mixed type then the above optimisation is DANGEROUS, as it will blindly typecast all data in the list as the
specified type, even if it isn't really that type, causing runtime errors (AKA your shit won't work if this happens).
#### Dot variable
@@ -559,7 +559,7 @@ DM has a var keyword, called global. This var keyword is for vars inside of type
```
This does NOT mean that you can access it everywhere like a global var. Instead, it means that that var will only exist once for all instances of its type, in this case that var will only exist once for all mobs - it's shared across everything in its type. (Much more like the keyword `static` in other languages like PHP/C++/C#/Java)
Isn't that confusing?
Isn't that confusing?
There is also an undocumented keyword called `static` that has the same behaviour as global but more correctly describes BYOND's behaviour. Therefore, we always use static instead of global where we need it, as it reduces suprise when reading BYOND code.
@@ -576,7 +576,7 @@ To access it:
GLOB.my_global_here = X
```
There are a few other defines that do other things. `GLOBAL_REAL` shouldn't be used unless you know exactly what you're doing.
There are a few other defines that do other things. `GLOBAL_REAL` shouldn't be used unless you know exactly what you're doing.
`GLOBAL_VAR_INIT` allows you to set an initial value on the var, like `GLOBAL_VAR_INIT(number_one, 1)`.
`GLOBAL_LIST_INIT` allows you to define a list global var with an initial value. Etc.
@@ -589,6 +589,7 @@ pull requests/issues, and merging/closing pull requests.
* [Fox P McCloud](https://github.com/Fox-McCloud)
* [Crazy Lemon](https://github.com/Crazylemon64)
* [Ansari](https://github.com/variableundefined)
* [AffectedArc07](https://github.com/AffectedArc07)
### Maintainer instructions
* Do not `self-merge`; this refers to the practice of opening a pull request, then
@@ -604,6 +605,6 @@ pull requests/issues, and merging/closing pull requests.
hours, to allow other coders and the community time to discuss the proposed changes.
* If the discussion is active, or the change is controversial, the pull request is to be
put on hold until a consensus is reached.
* To keep commit history easy to navigate for future contributors (e.g. Git Blame), squash merge
is to be preferred to normal merge where suitable. Ensure that the squashed commit name is easy
* To keep commit history easy to navigate for future contributors (e.g. Git Blame), squash merge
is to be preferred to normal merge where suitable. Ensure that the squashed commit name is easy
to understand and read. Modify it if needed.
+3
View File
@@ -4,3 +4,6 @@ dreamchecker = true
[code_standards]
disallow_relative_type_definitions = true
disallow_relative_proc_definitions = true
[dmdoc]
use_typepath_names = true
+1
View File
@@ -40,6 +40,7 @@ GLOBAL_LIST_INIT(round_end_sounds, list(
'sound/AI/newroundsexy.ogg' = 2.3 SECONDS,
'sound/misc/apcdestroyed.ogg' = 3 SECONDS,
'sound/misc/bangindonk.ogg' = 1.6 SECONDS,
'sound/misc/berightback.ogg' = 2.9 SECONDS,
'sound/goonstation/misc/newround1.ogg' = 6.9 SECONDS,
'sound/goonstation/misc/newround2.ogg' = 14.8 SECONDS
)) // Maps available round end sounds to their duration
+1 -1
View File
@@ -13,7 +13,7 @@ GLOBAL_DATUM_INIT(powermonitor_repository, /datum/repository/powermonitor, new()
for(var/obj/machinery/computer/monitor/pMon in GLOB.power_monitors)
if( !(pMon.stat & (NOPOWER|BROKEN)) && !pMon.is_secret_monitor )
pMonData[++pMonData.len] = list ("Name" = pMon.name, "ref" = "\ref[pMon]")
pMonData[++pMonData.len] = list ("Name" = pMon.name, "uid" = "[pMon.UID()]")
cache_entry.timestamp = world.time //+ 30 SECONDS
cache_entry.data = pMonData
+2 -2
View File
@@ -518,8 +518,8 @@ GLOBAL_VAR_INIT(record_id_num, 1001)
clothes_s = new /icon('icons/mob/uniform.dmi', "cargotech_s")
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
if("Shaft Miner")
clothes_s = new /icon('icons/mob/uniform.dmi', "miner_s")
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
clothes_s = new /icon('icons/mob/uniform.dmi', "explorer_s")
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "explorer"), ICON_UNDERLAY)
if("Lawyer")
clothes_s = new /icon('icons/mob/uniform.dmi', "internalaffairs_s")
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "brown"), ICON_UNDERLAY)
-4
View File
@@ -59,10 +59,6 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
return uplink_items
/datum/nano_item_lists
var/list/items_nano
var/list/items_reference
// You can change the order of the list by putting datums before/after one another OR
// you can use the last variable to make sure it appears last, well have the category appear last.
+1 -1
View File
@@ -182,7 +182,7 @@
var/datum/data/pda/app/notekeeper/N = PDA.find_program(/datum/data/pda/app/notekeeper)
if(N)
itemname = PDA.name
info = N.notehtml
info = N.note
to_chat(U, "You hold \the [itemname] up to the camera ...")
U.changeNext_move(CLICK_CD_MELEE)
for(var/mob/O in GLOB.player_list)
+41 -33
View File
@@ -12,7 +12,7 @@
/obj/machinery/computer/brigcells/attack_ai(mob/user)
attack_hand(user)
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/brigcells/attack_hand(mob/user)
add_fingerprint(user)
@@ -21,38 +21,46 @@
if(!allowed(user))
to_chat(user, "<span class='warning'>Access denied.</span>")
return
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/brigcells/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "brig_cells.tmpl", "Brig Cell Management", 1000, 400)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/brigcells/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "BrigCells", "Brig Cell Management", 1000, 400, master_ui, state)
ui.open()
ui.set_autoupdate(TRUE)
/obj/machinery/computer/brigcells/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
var/list/timers = list()
for(var/obj/machinery/door_timer/T in GLOB.celltimers_list)
var/timer = list()
timer["cell_id"] = T.name
timer["occupant"] = T.occupant
timer["crimes"] = T.crimes
timer["brigged_by"] = T.officer
if(T.time == 0)
timer["background"] = "'background-color:#007f47'"
else
timer["background"] = "'background-color:#890E26'"
timer["time_set"] = seconds_to_clock(T.time / 10)
timer["time_left"] = seconds_to_clock(T.timeleft())
timer["ref"] = "\ref[T]"
timers[++timers.len] += timer
timers = sortByKey(timers, "cell_id")
data["cells"] = timers
return data
/obj/machinery/computer/brigcells/tgui_data(mob/user)
var/list/data = list()
var/list/timers = list()
for(var/obj/machinery/door_timer/T in GLOB.celltimers_list)
var/timer = list()
timer["cell_id"] = T.name
timer["occupant"] = T.occupant
timer["crimes"] = T.crimes
timer["brigged_by"] = T.officer
timer["time_set_seconds"] = round(T.timetoset / 10, 1)
timer["time_left_seconds"] = round(T.timeleft(), 1)
timer["ref"] = "\ref[T]"
timers[++timers.len] += timer
timers = sortByKey(timers, "cell_id")
data["cells"] = timers
return data
/obj/machinery/computer/brigcells/Topic(href, href_list)
if(href_list["release"])
var/obj/machinery/door_timer/T = locate(href_list["release"])
T.timer_end()
T.Radio.autosay("Timer stopped manually from a cell management console.", T.name, "Security", list(z))
/obj/machinery/computer/brigcells/tgui_act(action, params)
if (..())
return FALSE
if(!allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return FALSE
if (action == "release")
var/ref = params["ref"]
var/obj/machinery/door_timer/T = locate(ref)
if (T)
T.timer_end()
T.Radio.autosay("Timer stopped manually from a cell management console.", T.name, "Security", list(z))
return TRUE
return FALSE
+41 -5
View File
@@ -9,8 +9,17 @@
light_color = LIGHT_COLOR_ORANGE
circuit = /obj/item/circuitboard/powermonitor
var/datum/powernet/powernet = null
var/datum/nano_module/power_monitor/power_monitor
var/datum/tgui_module/power_monitor/power_monitor
/// Will this monitor be hidden from viewers?
var/is_secret_monitor = FALSE
/// How many records to keep of supply and demand
var/record_size = 60
/// Interval between power snapshots
var/record_interval = 5 SECONDS
/// Time to next record power
var/next_record = 0
/// The history list itself of the power
var/list/history = list()
/obj/machinery/computer/monitor/secret //Hides the power monitor (such as ones on ruins & CentCom) from PDA's to prevent metagaming.
name = "outdated power monitoring console"
@@ -28,6 +37,8 @@
..()
GLOB.powermonitor_repository.update_cache()
powernet = find_powernet()
history["supply"] = list()
history["demand"] = list()
/obj/machinery/computer/monitor/Destroy()
GLOB.power_monitors -= src
@@ -56,10 +67,35 @@
return
// Update the powernet
powernet = find_powernet()
ui_interact(user)
tgui_interact(user)
/obj/machinery/computer/monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
power_monitor.ui_interact(user, ui_key, ui, force_open)
/obj/machinery/computer/monitor/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
power_monitor.tgui_interact(user, ui_key, ui, force_open)
/obj/machinery/computer/monitor/interact(mob/user)
power_monitor.ui_interact(user)
power_monitor.tgui_interact(user)
/obj/machinery/computer/monitor/process()
record()
/**
* Power snapshot recording proc
*
* This proc handles recording powernet history for the graph on the TGUI
* It is called every process(), but only logs every 5 seconds
*/
/obj/machinery/computer/monitor/proc/record()
if(world.time >= next_record)
next_record = world.time + record_interval
if(!powernet)
return
var/list/supply = history["supply"]
supply += powernet.viewavail
if(length(supply) > record_size)
supply.Cut(1, 2)
var/list/demand = history["demand"]
demand += powernet.viewload
if(length(demand) > record_size)
demand.Cut(1, 2)
-1
View File
@@ -56,7 +56,6 @@ GLOBAL_LIST_EMPTY(airlock_overlays)
autoclose = TRUE
explosion_block = 1
assemblytype = /obj/structure/door_assembly
normalspeed = 1
siemens_strength = 1
var/security_level = 0 //How much are wires secured
var/aiControlDisabled = AICONTROLDISABLED_OFF
+1
View File
@@ -226,6 +226,7 @@
occupant = CELL_NONE
crimes = CELL_NONE
time = 0
timetoset = 0
officer = CELL_NONE
releasetime = 0
printed = 0
+1 -1
View File
@@ -20,7 +20,7 @@
var/locked = FALSE //whether the door is bolted or not.
var/glass = FALSE
var/welded = FALSE
var/normalspeed = 1
var/normalspeed = TRUE
var/auto_close_time = 150
var/auto_close_time_dangerous = 15
var/assemblytype //the type of door frame to drop during deconstruction
@@ -87,11 +87,15 @@
energy_drain = 100
range = MECHA_MELEE | MECHA_RANGED
var/atom/movable/locked
var/cooldown_timer = 0
var/mode = 1 //1 - gravsling 2 - gravpush
/obj/item/mecha_parts/mecha_equipment/gravcatapult/action(atom/movable/target)
if(!action_checks(target))
return
if(cooldown_timer > world.time)
occupant_message("<span class='warning'>[src] is still recharging.</span>")
return
switch(mode)
if(1)
if(!locked)
@@ -106,6 +110,7 @@
locked.throw_at(target, 14, 1.5)
locked = null
send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",get_equip_info())
cooldown_timer = world.time + 3 SECONDS
return 1
else
locked = null
@@ -125,6 +130,7 @@
step_away(A,target)
sleep(2)
var/turf/T = get_turf(target)
cooldown_timer = world.time + 3 SECONDS
log_game("[key_name(chassis.occupant)] used a Gravitational Catapult in ([T.x],[T.y],[T.z])")
return 1
+12 -4
View File
@@ -1,6 +1,7 @@
#define WAND_OPEN "Open Door"
#define WAND_BOLT "Toggle Bolts"
#define WAND_EMERGENCY "Toggle Emergency Access"
#define WAND_SPEED "Change Closing Speed"
/obj/item/door_remote
icon_state = "gangtool-white"
@@ -21,7 +22,7 @@
for(var/region in region_access)
ID.access += get_region_accesses(region)
ID.access += additional_access
ID.access = uniquelist(ID.access) //remove duplicates
ID.access = uniquelist(ID.access)
/obj/item/door_remote/Destroy()
QDEL_NULL(ID)
@@ -34,8 +35,11 @@
if(WAND_BOLT)
mode = WAND_EMERGENCY
if(WAND_EMERGENCY)
mode = WAND_SPEED
if(WAND_SPEED)
mode = WAND_OPEN
to_chat(user, "Now in mode: [mode].")
to_chat(user, "<span class='notice'>Now in mode: [mode].</span>")
/obj/item/door_remote/afterattack(obj/machinery/door/airlock/D, mob/user)
if(!istype(D))
@@ -64,10 +68,13 @@
D.lock()
if(WAND_EMERGENCY)
if(D.emergency)
D.emergency = 0
D.emergency = FALSE
else
D.emergency = 1
D.emergency = TRUE
D.update_icon()
if(WAND_SPEED)
D.normalspeed = !D.normalspeed
to_chat(user, "<span class='notice'>[D] is now in [D.normalspeed ? "normal" : "fast"] mode.</span>")
else
to_chat(user, "<span class='danger'>[src] does not have access to this door.</span>")
@@ -144,3 +151,4 @@
#undef WAND_OPEN
#undef WAND_BOLT
#undef WAND_EMERGENCY
#undef WAND_SPEED
+77 -154
View File
@@ -9,14 +9,12 @@ A list of items and costs is stored under the datum of every game mode, alongsid
GLOBAL_LIST_EMPTY(world_uplinks)
/obj/item/uplink
var/welcome // Welcoming menu message
var/uses // Numbers of crystals
var/hidden_crystals = 0
var/list/uplink_items // List of categories with lists of items
var/list/ItemsReference // List of references with an associated item
var/list/nanoui_items // List of items for NanoUI use
var/nanoui_menu = 0 // The current menu we are in
var/list/nanoui_data = new // Additional data for NanoUI use
/// List of categories with items inside
var/list/uplink_cats
/// List of all items in total (For buying random)
var/list/uplink_items
var/purchase_log = ""
var/uplink_owner = null//text-only
@@ -26,12 +24,11 @@ GLOBAL_LIST_EMPTY(world_uplinks)
var/temp_category
var/uplink_type = "traitor"
/obj/item/uplink/nano_host()
/obj/item/uplink/tgui_host()
return loc
/obj/item/uplink/New()
..()
welcome = SSticker.mode.uplink_welcome
uses = SSticker.mode.uplink_uses
uplink_items = get_uplink_items()
@@ -41,97 +38,45 @@ GLOBAL_LIST_EMPTY(world_uplinks)
GLOB.world_uplinks -= src
return ..()
/obj/item/uplink/proc/generate_items(mob/user as mob)
var/datum/nano_item_lists/IL = generate_item_lists(user)
nanoui_items = IL.items_nano
ItemsReference = IL.items_reference
// BS12 no longer use this menu but there are forks that do, hency why we keep it
/obj/item/uplink/proc/generate_menu(mob/user as mob)
/**
* Build the item lists for use with the UI
*
* Generates a list of items for use in the UI, based on job and other parameters
*
* Arguments:
* * user - User to check
*/
/obj/item/uplink/proc/generate_item_lists(mob/user)
if(!job)
job = user.mind.assigned_role
var/dat = "<B>[src.welcome]</B><BR>"
dat += "Telecrystals left: [src.uses]<BR>"
dat += "<HR>"
dat += "<B>Request item:</B><BR>"
dat += "<I>Each item costs a number of telecrystals as indicated by the number following its name.</I><br>"
var/category_items = 1
for(var/category in uplink_items)
if(category_items < 1)
dat += "<i>We apologize, as you could not afford anything from this category.</i><br>"
dat += "<br>"
dat += "<b>[category]</b><br>"
category_items = 0
for(var/datum/uplink_item/I in uplink_items[category])
if(I.cost > uses)
continue
if(I.job && I.job.len)
if(!(I.job.Find(job)))
continue
dat += "<A href='byond://?src=[UID()];buy_item=[I.reference];cost=[I.cost]'>[I.name]</A> ([I.cost])"
if(I.hijack_only)
dat += " (HIJACK ONLY)"
dat += " <BR>"
category_items++
dat += "<A href='byond://?src=[UID()];buy_item=random'>Random Item (??)</A><br>"
dat += "<HR>"
return dat
/*
Built the item lists for use with NanoUI
*/
/obj/item/uplink/proc/generate_item_lists(mob/user as mob)
if(!job)
job = user.mind.assigned_role
var/list/nano = new
var/list/reference = new
var/list/cats = list()
for(var/category in uplink_items)
nano[++nano.len] = list("Category" = category, "items" = list())
cats[++cats.len] = list("cat" = category, "items" = list())
for(var/datum/uplink_item/I in uplink_items[category])
if(I.job && I.job.len)
if(!(I.job.Find(job)))
continue
nano[nano.len]["items"] += list(list("Name" = sanitize(I.name), "Description" = sanitize(I.description()),"Cost" = I.cost, "hijack_only" = I.hijack_only, "obj_path" = I.reference))
reference[I.reference] = I
cats[cats.len]["items"] += list(list("name" = sanitize(I.name), "desc" = sanitize(I.description()),"cost" = I.cost, "hijack_only" = I.hijack_only, "obj_path" = I.reference, "refundable" = I.refundable))
uplink_items[I.reference] = I
var/datum/nano_item_lists/result = new
result.items_nano = nano
result.items_reference = reference
return result
uplink_cats = cats
//If 'random' was selected
/obj/item/uplink/proc/chooseRandomItem()
if(uses <= 0)
return
var/list/random_items = new
for(var/IR in ItemsReference)
var/datum/uplink_item/UI = ItemsReference[IR]
var/list/random_items = list()
for(var/IR in uplink_items)
var/datum/uplink_item/UI = uplink_items[IR]
if(UI.cost <= uses && UI.limited_stock != 0)
random_items += UI
return pick(random_items)
/obj/item/uplink/Topic(href, href_list)
if(..())
return 1
if(href_list["refund"])
refund(usr)
if(href_list["buy_item"] == "random")
var/datum/uplink_item/UI = chooseRandomItem()
href_list["buy_item"] = UI.reference
return buy(UI, "RN")
else
var/datum/uplink_item/UI = ItemsReference[href_list["buy_item"]]
return buy(UI, UI ? UI.reference : "")
/obj/item/uplink/proc/buy(var/datum/uplink_item/UI, var/reference)
if(!UI)
return
@@ -141,17 +86,9 @@ GLOBAL_LIST_EMPTY(world_uplinks)
UI.buy(src,usr)
if(UI.limited_stock > 0) // only decrement it if it's actually limited
UI.limited_stock--
SSnanoui.update_uis(src)
SStgui.update_uis(src)
/* var/list/L = UI.spawn_item(get_turf(usr),src)
if(ishuman(usr))
var/mob/living/carbon/human/A = usr
for(var/obj/I in L)
A.put_in_any_hand_if_possible(I)
purchase_log[UI] = purchase_log[UI] + 1 */
return 1
return TRUE
/obj/item/uplink/proc/refund(mob/user as mob)
var/obj/item/I = user.get_active_hand()
@@ -167,6 +104,8 @@ GLOBAL_LIST_EMPTY(world_uplinks)
to_chat(user, "<span class='notice'>[I] refunded.</span>")
qdel(I)
return
// If we are here, we didnt refund
to_chat(user, "<span class='warning'>[I] is not refundable.</span>")
// HIDDEN UPLINK - Can be stored in anything but the host item has to have a trigger for it.
/* How to create an uplink in 3 easy steps!
@@ -208,92 +147,76 @@ GLOBAL_LIST_EMPTY(world_uplinks)
/obj/item/uplink/hidden/proc/check_trigger(mob/user as mob, var/value, var/target)
if(value == target)
trigger(user)
return 1
return 0
return TRUE
return FALSE
/*
NANO UI FOR UPLINK WOOP WOOP
*/
/obj/item/uplink/hidden/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.inventory_state)
var/title = "Remote Uplink"
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
/obj/item/uplink/hidden/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_inventory_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, 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, "uplink.tmpl", title, 700, 600, state = state)
// open the new ui window
ui = new(user, src, ui_key, "Uplink", name, 900, 600, master_ui, state)
ui.open()
/obj/item/uplink/hidden/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.inventory_state)
var/data[0]
/obj/item/uplink/hidden/tgui_data(mob/user)
var/list/data = list()
data["welcome"] = welcome
data["crystals"] = uses
data["menu"] = nanoui_menu
if(!nanoui_items)
generate_items(user)
data["nano_items"] = nanoui_items
data["category_choice"] = temp_category
data += nanoui_data
return data
/obj/item/uplink/hidden/tgui_static_data(mob/user)
var/list/data = list()
// Actual items
if(!uplink_cats || !uplink_items)
generate_item_lists(user)
data["cats"] = uplink_cats
// Exploitable info
var/list/exploitable = list()
for(var/datum/data/record/L in GLOB.data_core.general)
exploitable += list(list(
"name" = html_encode(L.fields["name"]),
"sex" = html_encode(L.fields["sex"]),
"age" = html_encode(L.fields["age"]),
"species" = html_encode(L.fields["species"]),
"rank" = html_encode(L.fields["rank"]),
"fingerprint" = html_encode(L.fields["fingerprint"])
))
data["exploitable"] = exploitable
return data
// Interaction code. Gathers a list of items purchasable from the paren't uplink and displays it. It also adds a lock button.
/obj/item/uplink/hidden/interact(mob/user)
ui_interact(user)
tgui_interact(user)
// The purchasing code.
/obj/item/uplink/hidden/Topic(href, href_list)
if(usr.stat || usr.restrained())
return 1
/obj/item/uplink/hidden/tgui_act(action, list/params)
if(..())
return
if(!( istype(usr, /mob/living/carbon/human)))
return 1
var/mob/user = usr
var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main")
if((usr.contents.Find(src.loc) || (in_range(src.loc, usr) && istype(src.loc.loc, /turf))))
usr.set_machine(src)
if(..(href, href_list))
return 1
else if(href_list["lock"])
. = TRUE
switch(action)
if("lock")
toggle()
uses += hidden_crystals
hidden_crystals = 0
ui.close()
return 1
if(href_list["menu"])
nanoui_menu = text2num(href_list["menu"])
update_nano_data(href_list["id"])
if(href_list["category"])
temp_category = href_list["category"]
update_nano_data()
SStgui.close_uis(src)
SSnanoui.update_uis(src)
return 1
if("refund")
refund(usr)
/obj/item/uplink/hidden/proc/update_nano_data(var/id)
if(nanoui_menu == 1)
var/permanentData[0]
for(var/datum/data/record/L in sortRecord(GLOB.data_core.general))
permanentData[++permanentData.len] = list(Name = sanitize(L.fields["name"]),"id" = L.fields["id"])
nanoui_data["exploit_records"] = permanentData
if("buyRandom")
var/datum/uplink_item/UI = chooseRandomItem()
return buy(UI, "RN")
if(nanoui_menu == 11)
nanoui_data["exploit_exists"] = 0
if("buyItem")
var/datum/uplink_item/UI = uplink_items[params["item"]]
return buy(UI, UI ? UI.reference : "")
for(var/datum/data/record/L in GLOB.data_core.general)
if(L.fields["id"] == id)
nanoui_data["exploit"] = list() // Setting this to equal L.fields passes it's variables that are lists as reference instead of value.
nanoui_data["exploit"]["name"] = html_encode(L.fields["name"])
nanoui_data["exploit"]["sex"] = html_encode(L.fields["sex"])
nanoui_data["exploit"]["age"] = html_encode(L.fields["age"])
nanoui_data["exploit"]["species"] = html_encode(L.fields["species"])
nanoui_data["exploit"]["rank"] = html_encode(L.fields["rank"])
nanoui_data["exploit"]["fingerprint"] = html_encode(L.fields["fingerprint"])
nanoui_data["exploit_exists"] = 1
break
// I placed this here because of how relevant it is.
// You place this in your uplinkable item to check if an uplink is active or not.
@@ -124,7 +124,7 @@ GLOBAL_LIST_INIT(leather_recipes, list (
new/datum/stack_recipe("leather satchel", /obj/item/storage/backpack/satchel, 5),
new/datum/stack_recipe("bandolier", /obj/item/storage/belt/bandolier, 5),
new/datum/stack_recipe("leather jacket", /obj/item/clothing/suit/jacket/leather, 7),
new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/laceup, 2),
new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/leather, 2),
new/datum/stack_recipe("leather overcoat", /obj/item/clothing/suit/jacket/leather/overcoat, 10),
new/datum/stack_recipe("hide mantle", /obj/item/clothing/suit/unathi/mantle, 4)))
+6
View File
@@ -263,6 +263,12 @@
if(prob(50 / severity) && severity < 3)
qdel(src)
/obj/machinery/mineral/equipment_vendor/Destroy()
if(inserted_id)
inserted_id.forceMove(loc)
return ..()
/**********************Mining Equiment Vendor (Golem)**************************/
/obj/machinery/mineral/equipment_vendor/golem
@@ -58,6 +58,7 @@
if(INTENT_HELP)
M.visible_message("<span class='notice'>[M] pets [src]!</span>", \
"<span class='notice'>You pet [src]!</span>")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if("grab")
grabbedby(M)
else
@@ -4,7 +4,7 @@
var/datum/nano_module/atmos_control/atmos_control
var/datum/tgui_module/crew_monitor/crew_monitor
var/datum/nano_module/law_manager/law_manager
var/datum/nano_module/power_monitor/silicon/power_monitor
var/datum/tgui_module/power_monitor/digital/power_monitor
/mob/living/silicon
var/list/silicon_subsystems = list(
@@ -67,5 +67,5 @@
set category = "Subsystems"
set name = "Power Monitor"
power_monitor.ui_interact(usr, state = GLOB.self_state)
power_monitor.tgui_interact(usr, state = GLOB.self_state)
@@ -513,16 +513,16 @@
if(4)
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
if(JOB_MINER)
clothes_s = new /icon(uniform_dmi, "miner_s")
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "black"), ICON_UNDERLAY)
clothes_s = new /icon(uniform_dmi, "explorer_s")
clothes_s.Blend(new /icon('icons/mob/feet.dmi', "explorer"), ICON_UNDERLAY)
clothes_s.Blend(new /icon('icons/mob/hands.dmi', "bgloves"), ICON_UNDERLAY)
if(prob(1))
clothes_s.Blend(new /icon('icons/mob/head.dmi', "bearpelt"), ICON_OVERLAY)
switch(backbag)
if(2)
clothes_s.Blend(new /icon('icons/mob/back.dmi', "backpack"), ICON_OVERLAY)
clothes_s.Blend(new /icon('icons/mob/back.dmi', "explorerpack"), ICON_OVERLAY)
if(3)
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-eng"), ICON_OVERLAY)
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel-explorer"), ICON_OVERLAY)
if(4)
clothes_s.Blend(new /icon('icons/mob/back.dmi', "satchel"), ICON_OVERLAY)
if(JOB_LAWYER)
@@ -1,53 +0,0 @@
/datum/nano_module/power_monitor
name = "Power monitor"
var/select_monitor = 0
var/obj/machinery/computer/monitor/powermonitor
/datum/nano_module/power_monitor/silicon
select_monitor = 1
/datum/nano_module/power_monitor/New()
..()
if(!select_monitor)
powermonitor = nano_host()
/datum/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.default_state)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 700, state = state)
ui.open()
ui.set_auto_update(1)
/datum/nano_module/power_monitor/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
var/data[0]
data["powermonitor"] = powermonitor
if(select_monitor)
data["select_monitor"] = 1
data["powermonitors"] = GLOB.powermonitor_repository.powermonitor_data()
if(powermonitor && !isnull(powermonitor.powernet))
if(select_monitor && (powermonitor.stat & (NOPOWER|BROKEN)))
powermonitor = null
return
data["poweravail"] = powermonitor.powernet.avail
data["powerload"] = powermonitor.powernet.viewload
data["powerdemand"] = powermonitor.powernet.load
data["apcs"] = GLOB.apc_repository.apc_data(powermonitor.powernet)
return data
/datum/nano_module/power_monitor/Topic(href, href_list)
if(..())
return 1
if(href_list["selectmonitor"])
if(issilicon(usr))
powermonitor = locate(href_list["selectmonitor"])
powermonitor.powernet = powermonitor.find_powernet() // Refresh the powernet of the monitor
return 1
if(href_list["return"])
if(issilicon(usr))
powermonitor = null
return 1
+11 -156
View File
@@ -1,6 +1,9 @@
//The advanced pea-green monochrome lcd of tomorrow.
// EDIT 2020-09-21: We have had NanoUI PDAs for years, and I am now finally TGUI-ing them
// They arent pea green trash. I DEFY YOU COMMENTS!!! -aa
/// Global list of all PDAs in the world
GLOBAL_LIST_EMPTY(PDAs)
@@ -22,7 +25,6 @@ GLOBAL_LIST_EMPTY(PDAs)
var/obj/item/cartridge/cartridge = null //current cartridge
var/datum/data/pda/app/current_app = null
var/datum/data/pda/app/lastapp = null
var/ui_tick = 0
//Secondary variables
var/model_name = "Thinktronic 5230 Personal Data Assistant"
@@ -47,7 +49,6 @@ GLOBAL_LIST_EMPTY(PDAs)
new/datum/data/pda/app/messenger,
new/datum/data/pda/app/manifest,
new/datum/data/pda/app/atmos_scanner,
new/datum/data/pda/utility/scanmode/notes,
new/datum/data/pda/utility/flashlight)
var/list/shortcut_cache = list()
var/list/shortcut_cat_order = list()
@@ -101,92 +102,11 @@ GLOBAL_LIST_EMPTY(PDAs)
if((!istype(over_object, /obj/screen)) && can_use())
return attack_self(M)
/obj/item/pda/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.inventory_state)
ui_tick++
var/datum/nanoui/old_ui = SSnanoui.get_open_ui(user, src, "main")
var/auto_update = 1
if(!current_app)
return
if(current_app.update == PDA_APP_NOUPDATE && current_app == lastapp)
auto_update = 0
if(old_ui && (current_app == lastapp && ui_tick % 5 && current_app.update == PDA_APP_UPDATE_SLOW))
return
lastapp = current_app
var/title = "Personal Data Assistant"
// update the ui if it exists, returns null if no ui is passed/found
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "pda.tmpl", title, 630, 600, state = state)
ui.set_state_key("pda")
// open the new ui window
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(auto_update)
/obj/item/pda/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.inventory_state)
var/data[0]
data["owner"] = owner // Who is your daddy...
data["ownjob"] = ownjob // ...and what does he do?
// update list of shortcuts, only if they changed
if(!shortcut_cache.len)
shortcut_cache = list()
shortcut_cat_order = list()
var/prog_list = programs.Copy()
if(cartridge)
prog_list |= cartridge.programs
for(var/A in prog_list)
var/datum/data/pda/P = A
if(P.hidden)
continue
var/list/cat
if(P.category in shortcut_cache)
cat = shortcut_cache[P.category]
else
cat = list()
shortcut_cache[P.category] = cat
shortcut_cat_order += P.category
cat |= list(list(name = P.name, icon = P.icon, notify_icon = P.notify_icon, ref = "\ref[P]"))
// force the order of a few core categories
shortcut_cat_order = list("General") \
+ sortList(shortcut_cat_order - list("General", "Scanners", "Utilities")) \
+ list("Scanners", "Utilities")
data["idInserted"] = (id ? 1 : 0)
data["idLink"] = (id ? text("[id.registered_name], [id.assignment]") : "--------")
data["useRetro"] = retro_mode
data["cartridge_name"] = cartridge ? cartridge.name : ""
data["stationTime"] = station_time_timestamp()
data["app"] = list()
current_app.update_ui(user, data)
data["app"] |= list(
"name" = current_app.title,
"icon" = current_app.icon,
"template" = current_app.template,
"has_back" = current_app.has_back)
return data
/obj/item/pda/attack_self(mob/user as mob)
user.set_machine(src)
if(active_uplink_check(user))
return
ui_interact(user) //NanoUI requires this proc
tgui_interact(user)
/obj/item/pda/proc/start_program(datum/data/pda/P)
if(P && ((P in programs) || (cartridge && (P in cartridge.programs))))
@@ -212,79 +132,8 @@ GLOBAL_LIST_EMPTY(PDAs)
var/datum/data/pda/P = A
P.pda = src
/obj/item/pda/Topic(href, href_list)
. = ..()
if(.)
return
var/mob/user = usr
var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main")
var/mob/living/U = usr
if(usr.stat == DEAD)
return 0
if(!can_use()) //Why reinvent the wheel? There's a proc that does exactly that.
U.unset_machine()
if(ui)
ui.close()
return 0
add_fingerprint(U)
U.set_machine(src)
if(href_list["radiomenu"] && !isnull(cartridge) && !isnull(cartridge.radio))
cartridge.radio.Topic(href, href_list)
return 1
. = 1
switch(href_list["choice"])
if("Home")//Go home, largely replaces the old Return
var/datum/data/pda/app/main_menu/A = find_program(/datum/data/pda/app/main_menu)
if(A)
start_program(A)
if("StartProgram")
if(href_list["program"])
var/datum/data/pda/app/A = locate(href_list["program"])
if(A)
start_program(A)
if("Eject")//Ejects the cart, only done from hub.
if(!isnull(cartridge))
var/turf/T = loc
if(ismob(T))
T = T.loc
var/obj/item/cartridge/C = cartridge
C.forceMove(T)
if(scanmode in C.programs)
scanmode = null
if(current_app in C.programs)
start_program(find_program(/datum/data/pda/app/main_menu))
if(C.radio)
C.radio.hostpda = null
for(var/datum/data/pda/P in notifying_programs)
if(P in C.programs)
P.unnotify()
cartridge = null
update_shortcuts()
if("Authenticate")//Checks for ID
id_check(usr, 1)
if("Retro")
retro_mode = !retro_mode
if("Ringtone")
return set_ringtone()
else
if(current_app)
. = current_app.Topic(href, href_list)
//EXTRA FUNCTIONS===================================
if((honkamt > 0) && (prob(60)))//For clown virus.
honkamt--
playsound(loc, 'sound/items/bikehorn.ogg', 30, 1)
return // return 1 tells it to refresh the UI in NanoUI
/obj/item/pda/proc/close(mob/user)
var/datum/nanoui/ui = SSnanoui.get_open_ui(user, src, "main")
ui.close()
SStgui.close_uis(src)
/obj/item/pda/verb/verb_reset_pda()
set category = "Object"
@@ -299,6 +148,7 @@ GLOBAL_LIST_EMPTY(PDAs)
notifying_programs.Cut()
overlays -= image('icons/obj/pda.dmi', "pda-r")
to_chat(usr, "<span class='notice'>You press the reset button on \the [src].</span>")
SStgui.update_uis(src)
else
to_chat(usr, "<span class='notice'>You cannot do this while restrained.</span>")
@@ -327,6 +177,7 @@ GLOBAL_LIST_EMPTY(PDAs)
var/mob/M = loc
M.put_in_hands(id)
to_chat(user, "<span class='notice'>You remove the ID from the [name].</span>")
SStgui.update_uis(src)
else
id.forceMove(get_turf(src))
overlays -= image('icons/goonstation/objects/pda_overlay.dmi', id.icon_state)
@@ -403,6 +254,7 @@ GLOBAL_LIST_EMPTY(PDAs)
cartridge.update_programs(src)
update_shortcuts()
to_chat(user, "<span class='notice'>You insert [cartridge] into [src].</span>")
SStgui.update_uis(src)
if(cartridge.radio)
cartridge.radio.hostpda = src
@@ -417,6 +269,7 @@ GLOBAL_LIST_EMPTY(PDAs)
ownrank = idcard.rank
name = "PDA-[owner] ([ownjob])"
to_chat(user, "<span class='notice'>Card scanned.</span>")
SStgui.update_uis(src)
else
//Basic safety check. If either both objects are held by user or PDA is on ground and card is in hand.
if(((src in user.contents) && (C in user.contents)) || (istype(loc, /turf) && in_range(src, user) && (C in user.contents)) )
@@ -424,12 +277,14 @@ GLOBAL_LIST_EMPTY(PDAs)
id_check(user, 2)
to_chat(user, "<span class='notice'>You put the ID into \the [src]'s slot.<br>You can remove it with ALT click.</span>")
overlays += image('icons/goonstation/objects/pda_overlay.dmi', C.icon_state)
SStgui.update_uis(src)
else if(istype(C, /obj/item/paicard) && !src.pai)
user.drop_item()
C.forceMove(src)
pai = C
to_chat(user, "<span class='notice'>You slot \the [C] into [src].</span>")
SStgui.update_uis(src)
else if(istype(C, /obj/item/pen))
var/obj/item/pen/O = locate() in src
if(O)
+7 -4
View File
@@ -69,7 +69,8 @@
pda.current_app = src
return 1
/datum/data/pda/app/proc/update_ui(mob/user as mob, list/data)
/datum/data/pda/app/proc/update_ui(mob/user, list/data)
return
// Utilities just have a button on the home screen, but custom code when clicked
@@ -99,8 +100,10 @@
name = "Disable [base_name]"
pda.update_shortcuts()
return 1
return TRUE
/datum/data/pda/utility/scanmode/proc/scan_mob(mob/living/C as mob, mob/living/user as mob)
/datum/data/pda/utility/scanmode/proc/scan_mob(mob/living/C, mob/living/user)
return
/datum/data/pda/utility/scanmode/proc/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob)
/datum/data/pda/utility/scanmode/proc/scan_atom(atom/A, mob/user)
return
-2
View File
@@ -230,7 +230,6 @@
new/datum/data/pda/app/janitor,
new/datum/data/pda/app/supply,
new/datum/data/pda/app/mule_control,
new/datum/data/pda/app/status_display)
@@ -267,7 +266,6 @@
new/datum/data/pda/app/janitor,
new/datum/data/pda/app/supply,
new/datum/data/pda/app/mule_control,
new/datum/data/pda/app/status_display)
+145 -78
View File
@@ -12,20 +12,24 @@
"message1" = message1 ? message1 : "(none)",
"message2" = message2 ? message2 : "(none)")
/datum/data/pda/app/status_display/Topic(href, list/href_list)
switch(href_list["choice"])
/datum/data/pda/app/status_display/tgui_act(action, list/params)
if(..())
return
. = TRUE
switch(action)
if("Status")
switch(href_list["statdisp"])
switch(params["statdisp"])
if("message")
post_status("message", message1, message2)
if("alert")
post_status("alert", href_list["alert"])
post_status("alert", params["alert"])
if("setmsg1")
message1 = clean_input("Line 1", "Enter Message Text", message1)
if("setmsg2")
message2 = clean_input("Line 2", "Enter Message Text", message2)
else
post_status(href_list["statdisp"])
post_status(params["statdisp"])
/datum/data/pda/app/status_display/proc/post_status(var/command, var/data1, var/data2)
var/datum/radio_frequency/frequency = SSradio.return_frequency(DISPLAY_FREQ)
@@ -57,75 +61,64 @@
/datum/data/pda/app/signaller
name = "Signaler System"
icon = "rss"
template = "pda_signaller"
template = "pda_signaler"
category = "Utilities"
/datum/data/pda/app/signaller/update_ui(mob/user as mob, list/data)
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/signal))
var/obj/item/integrated_radio/signal/R = pda.cartridge.radio
data["signal_freq"] = format_frequency(R.frequency)
data["signal_code"] = R.code
data["frequency"] = R.frequency
data["code"] = R.code
data["minFrequency"] = PUBLIC_LOW_FREQ
data["maxFrequency"] = PUBLIC_HIGH_FREQ
/datum/data/pda/app/signaller/tgui_act(action, list/params)
if(..())
return
. = TRUE
/datum/data/pda/app/signaller/Topic(href, list/href_list)
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/signal))
var/obj/item/integrated_radio/signal/R = pda.cartridge.radio
switch(href_list["choice"])
if("Send Signal")
switch(action)
if("signal")
spawn(0)
R.send_signal("ACTIVATE")
if("Signal Frequency")
var/new_frequency = sanitize_frequency(R.frequency + text2num(href_list["sfreq"]))
if("freq")
var/new_frequency = sanitize_frequency(text2num(params["freq"]) * 10)
R.set_frequency(new_frequency)
if("Signal Code")
R.code += text2num(href_list["scode"])
R.code = round(R.code)
R.code = min(100, R.code)
R.code = max(1, R.code)
if("code")
R.code = clamp(text2num(params["code"]), 1, 100)
/datum/data/pda/app/power
name = "Power Monitor"
icon = "exclamation-triangle"
icon = "bolt"
template = "pda_power"
category = "Engineering"
update = PDA_APP_UPDATE_SLOW
var/obj/machinery/computer/monitor/powmonitor = null
var/datum/tgui_module/power_monitor/digital/pm = new
/datum/data/pda/app/power/update_ui(mob/user as mob, list/data)
update = PDA_APP_UPDATE_SLOW
data.Add(pm.tgui_data())
if(powmonitor && !isnull(powmonitor.powernet))
data["records"] = list(
"powerconnected" = 1,
"poweravail" = powmonitor.powernet.avail,
"powerload" = num2text(powmonitor.powernet.viewload, 10),
"powerdemand" = powmonitor.powernet.load,
"apcs" = GLOB.apc_repository.apc_data(powmonitor.powernet))
has_back = 1
else
data["records"] = list(
"powerconnected" = 0,
"powermonitors" = GLOB.powermonitor_repository.powermonitor_data())
has_back = 0
// All 4 args are important here because proxying matters
/datum/data/pda/app/power/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
/datum/data/pda/app/power/Topic(href, list/href_list)
switch(href_list["choice"])
if("Power Select")
var/pref = href_list["target"]
powmonitor = locate(pref)
update = PDA_APP_UPDATE
if("Back")
powmonitor = null
update = PDA_APP_UPDATE
. = TRUE
// Observe
pm.tgui_act(action, params, ui, state)
/datum/data/pda/app/crew_records
var/datum/data/record/general_records = null
/datum/data/pda/app/crew_records/update_ui(mob/user as mob, list/data)
var/list/records[0]
var/list/records = list()
if(general_records && (general_records in GLOB.data_core.general))
data["records"] = records
@@ -135,23 +128,31 @@
for(var/A in sortRecord(GLOB.data_core.general))
var/datum/data/record/R = A
if(R)
records += list(list(Name = R.fields["name"], "ref" = "\ref[R]"))
records += list(list(Name = R.fields["name"], "uid" = "[R.UID()]"))
data["recordsList"] = records
data["records"] = null
return null
/datum/data/pda/app/crew_records/Topic(href, list/href_list)
switch(href_list["choice"])
/datum/data/pda/app/crew_records/tgui_act(action, list/params)
if(..())
return
. = TRUE
switch(action)
if("Records")
var/datum/data/record/R = locate(href_list["target"])
var/datum/data/record/R = locateUID(params["target"])
if(R && (R in GLOB.data_core.general))
load_records(R)
return
if("Back")
general_records = null
has_back = 0
has_back = FALSE
return
/datum/data/pda/app/crew_records/proc/load_records(datum/data/record/R)
general_records = R
has_back = 1
has_back = TRUE
/datum/data/pda/app/crew_records/medical
name = "Medical Records"
@@ -181,7 +182,7 @@
/datum/data/pda/app/crew_records/security
name = "Security Records"
icon = "tags"
icon = "id-badge"
template = "pda_security"
category = "Security"
@@ -212,8 +213,8 @@
category = "Security"
/datum/data/pda/app/secbot_control/update_ui(mob/user as mob, list/data)
var/botsData[0]
var/beepskyData[0]
var/list/botsData = list()
var/list/beepskyData = list()
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky))
var/obj/item/integrated_radio/beepsky/SC = pda.cartridge.radio
beepskyData["active"] = SC.active ? sanitize(SC.active.name) : null
@@ -229,17 +230,17 @@
for(var/mob/living/simple_animal/bot/B in SC.botlist)
botsCount++
if(B.loc)
botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
botsData[++botsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "uid" = "[B.UID()]")
if(!botsData.len)
botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "uid"= null)
beepskyData["bots"] = botsData
beepskyData["count"] = botsCount
else
beepskyData["active"] = 0
botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
botsData[++botsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "uid"= null)
beepskyData["botstatus"] = list("loca" = null, "mode" = null)
beepskyData["bots"] = botsData
beepskyData["count"] = 0
@@ -247,11 +248,42 @@
data["beepsky"] = beepskyData
/datum/data/pda/app/secbot_control/Topic(href, list/href_list)
switch(href_list["choice"])
/datum/data/pda/app/secbot_control/tgui_act(action, list/params)
if(..())
return
. = TRUE
// Aight listen up. Its time for a comment rant again.
// The old way of doing this was to proxy things directly from the NanoUI into the PDA's cartridge's radio Topic() function directly
// It was AWFUL and took me 30 minutes to even understand
// This is in no way a good solution, but it works atleast
// Why do we rely on this whole "magical radio system" anyways
// Hell, I would rather take GLOBs with direct interactions over this
// WHYYYYYYYYYYYYYYY -aa07
switch(action)
if("Back")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky))
pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist"))
pda.cartridge.radio.Topic(null, list(op = "botlist"))
if("Rescan")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky))
pda.cartridge.radio.Topic(null, list(op = "scanbots"))
if("AccessBot")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky))
pda.cartridge.radio.Topic(null, list(op = "control", bot = params["uid"]))
if("Stop")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky))
pda.cartridge.radio.Topic(null, list(op = "stop"))
if("Go")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky))
pda.cartridge.radio.Topic(null, list(op = "go"))
if("Home")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky))
pda.cartridge.radio.Topic(null, list(op = "home"))
if("Summon")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/beepsky))
pda.cartridge.radio.Topic(null, list(op = "summon"))
/datum/data/pda/app/mule_control
name = "Delivery Bot Control"
@@ -260,8 +292,8 @@
category = "Quartermaster"
/datum/data/pda/app/mule_control/update_ui(mob/user as mob, list/data)
var/muleData[0]
var/mulebotsData[0]
var/list/muleData = list()
var/list/mulebotsData = list()
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
var/obj/item/integrated_radio/mule/QC = pda.cartridge.radio
muleData["active"] = QC.active ? sanitize(QC.active.name) : null
@@ -279,10 +311,10 @@
for(var/mob/living/simple_animal/bot/B in QC.botlist)
mulebotsCount++
if(B.loc)
mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "ref" = "\ref[B]")
mulebotsData[++mulebotsData.len] = list("Name" = sanitize(B.name), "Location" = sanitize(B.loc.loc.name), "uid" = "[B.UID()]")
if(!mulebotsData.len)
mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "uid"= null)
muleData["bots"] = mulebotsData
muleData["count"] = mulebotsCount
@@ -290,28 +322,63 @@
else
muleData["botstatus"] = list("loca" = null, "mode" = -1,"home"=null,"powr" = null,"retn" =null, "pick"=null, "load" = null, "dest" = null)
muleData["active"] = 0
mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "ref"= null)
mulebotsData[++mulebotsData.len] = list("Name" = "No bots found", "Location" = "Invalid", "uid"= null)
muleData["bots"] = mulebotsData
muleData["count"] = 0
has_back = 0
data["mulebot"] = muleData
/datum/data/pda/app/mule_control/Topic(href, list/href_list)
switch(href_list["choice"])
/datum/data/pda/app/mule_control/tgui_act(action, list/params)
if(..())
return
. = TRUE
// Heres the exact same shit as before, but worse
// See L257 to L263 for explanation
switch(action)
if("Back")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(radiomenu = "1", op = "botlist"))
pda.cartridge.radio.Topic(null, list(op = "botlist"))
if("Rescan")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = "scanbots"))
if("AccessBot")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = "control", bot = params["uid"]))
if("Unload")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = "unload"))
if("SetDest")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = "setdest"))
if("SetAutoReturn")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = params["autoReturnType"])) // "retoff" or "reton"
if("SetAutoPickup")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = params["autoPickupType"])) // "pickoff" or "pickon"
if("Stop")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = "stop"))
if("Start")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = "start"))
if("ReturnHome")
if(pda.cartridge && istype(pda.cartridge.radio, /obj/item/integrated_radio/mule))
pda.cartridge.radio.Topic(null, list(op = "home"))
/datum/data/pda/app/supply
name = "Supply Records"
icon = "file-text-o"
template = "pda_supply"
icon = "archive"
template = "pda_supplyrecords"
category = "Quartermaster"
update = PDA_APP_UPDATE_SLOW
/datum/data/pda/app/supply/update_ui(mob/user as mob, list/data)
var/supplyData[0]
var/list/supplyData = list()
if(SSshuttle.supply.mode == SHUTTLE_CALL)
supplyData["shuttle_moving"] = 1
@@ -324,7 +391,7 @@
supplyData["shuttle_time"] = "([SSshuttle.supply.timeLeft(600)] Mins)"
var/supplyOrderCount = 0
var/supplyOrderData[0]
var/list/supplyOrderData = list()
for(var/S in SSshuttle.shoppinglist)
var/datum/supply_order/SO = S
supplyOrderCount++
@@ -337,7 +404,7 @@
supplyData["approved_count"] = supplyOrderCount
var/requestCount = 0
var/requestData[0]
var/list/requestData = list()
for(var/S in SSshuttle.requestlist)
var/datum/supply_order/SO = S
requestCount++
@@ -353,13 +420,13 @@
/datum/data/pda/app/janitor
name = "Custodial Locator"
icon = "trash-o"
icon = "trash"
template = "pda_janitor"
category = "Utilities"
update = PDA_APP_UPDATE_SLOW
/datum/data/pda/app/janitor/update_ui(mob/user as mob, list/data)
var/JaniData[0]
var/list/JaniData = list()
var/turf/cl = get_turf(pda)
if(cl)
@@ -367,7 +434,7 @@
else
JaniData["user_loc"] = list("x" = 0, "y" = 0)
var/MopData[0]
var/list/MopData = list()
for(var/obj/item/mop/M in GLOB.janitorial_equipment)
var/turf/ml = get_turf(M)
if(ml)
@@ -376,7 +443,7 @@
var/direction = get_dir(pda, M)
MopData[++MopData.len] = list ("x" = ml.x, "y" = ml.y, "dir" = uppertext(dir2text(direction)), "status" = M.reagents.total_volume ? "Wet" : "Dry")
var/BucketData[0]
var/list/BucketData = list()
for(var/obj/structure/mopbucket/B in GLOB.janitorial_equipment)
var/turf/bl = get_turf(B)
if(bl)
@@ -385,7 +452,7 @@
var/direction = get_dir(pda,B)
BucketData[++BucketData.len] = list ("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "volume" = B.reagents.total_volume, "max_volume" = B.reagents.maximum_volume)
var/CbotData[0]
var/list/CbotData = list()
for(var/mob/living/simple_animal/bot/cleanbot/B in GLOB.bots_list)
var/turf/bl = get_turf(B)
if(bl)
@@ -394,7 +461,7 @@
var/direction = get_dir(pda,B)
CbotData[++CbotData.len] = list("x" = bl.x, "y" = bl.y, "dir" = uppertext(dir2text(direction)), "status" = B.on ? "Online" : "Offline")
var/CartData[0]
var/list/CartData = list()
for(var/obj/structure/janitorialcart/B in GLOB.janitorial_equipment)
var/turf/bl = get_turf(B)
if(bl)
+43 -32
View File
@@ -6,19 +6,24 @@
/datum/data/pda/app/main_menu/update_ui(mob/user as mob, list/data)
title = pda.name
data["app"]["is_home"] = 1
data["app"]["is_home"] = TRUE
data["apps"] = pda.shortcut_cache
data["categories"] = pda.shortcut_cat_order
data["pai"] = !isnull(pda.pai) // pAI inserted?
var/list/notifying[0]
for(var/P in pda.notifying_programs)
notifying["\ref[P]"] = 1
var/list/notifying = list()
for(var/datum/data/pda/P in pda.notifying_programs)
notifying["[P.UID()]"] = TRUE
data["notifying"] = notifying
/datum/data/pda/app/main_menu/Topic(href, list/href_list)
switch(href_list["choice"])
/datum/data/pda/app/main_menu/tgui_act(action, list/params)
if(..())
return
. = TRUE
switch(action)
if("UpdateInfo")
pda.ownjob = pda.id.assignment
pda.ownrank = pda.id.rank
@@ -28,10 +33,10 @@
if(pda.pai.loc != pda)
pda.pai = null
else
switch(href_list["option"])
if("1") // Configure pAI device
switch(text2num(params["option"]))
if(1) // Configure pAI device
pda.pai.attack_self(usr)
if("2") // Eject pAI device
if(2) // Eject pAI device
var/turf/T = get_turf_or_move(pda.loc)
if(T)
pda.pai.loc = T
@@ -40,10 +45,9 @@
/datum/data/pda/app/notekeeper
name = "Notekeeper"
icon = "sticky-note-o"
template = "pda_notekeeper"
template = "pda_notes"
var/note = null
var/notehtml = ""
var/note
/datum/data/pda/app/notekeeper/start()
. = ..()
@@ -51,16 +55,22 @@
note = "Congratulations, your station has chosen the [pda.model_name]!"
/datum/data/pda/app/notekeeper/update_ui(mob/user as mob, list/data)
data["note"] = note // current pda notes
data["note"] = note // current pda notes
/datum/data/pda/app/notekeeper/Topic(href, list/href_list)
switch(href_list["choice"])
/datum/data/pda/app/notekeeper/tgui_act(action, params)
if(..())
return
. = TRUE
switch(action)
if("Edit")
var/n = input("Please enter message", name, notehtml) as message
var/n = input("Please enter message", name, note) as message
if(pda.loc == usr)
// TGUI will auto-reject supplied HTML
// However, the admin var-edit window will not
// SANITISATION IS IMPORTANT. DO NOT NEGLECT.
note = adminscrub(n)
notehtml = html_decode(note)
note = replacetext(note, "\n", "<br>")
else
pda.close(usr)
@@ -74,8 +84,6 @@
GLOB.data_core.get_manifest_json()
data["manifest"] = GLOB.PDA_Manifest
/datum/data/pda/app/manifest/Topic(href, list/href_list)
/datum/data/pda/app/atmos_scanner
name = "Atmospheric Scan"
icon = "fire"
@@ -84,6 +92,7 @@
update = PDA_APP_UPDATE_SLOW
/datum/data/pda/app/atmos_scanner/update_ui(mob/user as mob, list/data)
var/list/results = list()
var/turf/T = get_turf(user.loc)
if(!isnull(T))
var/datum/gas_mixture/environment = T.return_air()
@@ -97,15 +106,17 @@
var/co2_level = environment.carbon_dioxide/total_moles
var/plasma_level = environment.toxins/total_moles
var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level)
data["aircontents"] = list(
"pressure" = pressure,
"nitrogen" = n2_level*100,
"oxygen" = o2_level*100,
"carbon_dioxide" = co2_level*100,
"plasma" = plasma_level*100,
"other" = unknown_level,
"temp" = environment.temperature-T0C,
"reading" = 1
)
if(isnull(data["aircontents"]))
data["aircontents"] = list("reading" = 0)
results = list(
list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
list("entry" = "Temperature", "units" = "C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
list("entry" = "Oxygen", "units" = "%", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
list("entry" = "Nitrogen", "units" = "%", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
list("entry" = "Carbon Dioxide", "units" = "%", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
list("entry" = "Plasma", "units" = "%", "val" = "[round(plasma_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0),
list("entry" = "Other", "units" = "%", "val" = "[round(unknown_level, 0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0)
)
if(isnull(results))
results = list(list("entry" = "pressure", "units" = "%", "val" = "0", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80))
data["aircontents"] = results
+44 -41
View File
@@ -6,24 +6,22 @@
template = "pda_messenger"
var/toff = 0 //If 1, messenger disabled
var/list/tnote[0] //Current Texts
var/list/tnote = list() //Current Texts
var/last_text //No text spamming
var/m_hidden = 0 // Is the PDA hidden from the PDA list?
var/active_conversation = null // New variable that allows us to only view a single conversation.
var/list/conversations = list() // For keeping up with who we have PDA messsages from.
var/latest_post = 0
var/auto_scroll = 1
/datum/data/pda/app/messenger/start()
. = ..()
unnotify()
latest_post = 0
/datum/data/pda/app/messenger/update_ui(mob/user as mob, list/data)
data["silent"] = notify_silent // does the pda make noise when it receives a message?
data["toff"] = toff // is the messenger function turned off?
data["active_conversation"] = active_conversation // Which conversation are we following right now?
// Yes I know convo is awful, but it lets me stay inside the 80 char TGUI line limit
data["active_convo"] = active_conversation // Which conversation are we following right now?
has_back = active_conversation
if(active_conversation)
@@ -33,22 +31,19 @@
data["convo_name"] = sanitize(c["owner"])
data["convo_job"] = sanitize(c["job"])
break
data["auto_scroll"] = auto_scroll
data["latest_post"] = latest_post
latest_post = tnote.len
else
var/convopdas[0]
var/pdas[0]
var/list/convopdas = list()
var/list/pdas = list()
for(var/A in GLOB.PDAs)
var/obj/item/pda/P = A
var/datum/data/pda/app/messenger/PM = P.find_program(/datum/data/pda/app/messenger)
if(!P.owner || PM.toff || P == pda || PM.m_hidden)
continue
if(conversations.Find("\ref[P]"))
convopdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "1")))
if(conversations.Find("[P.UID()]"))
convopdas.Add(list(list("Name" = "[P]", "uid" = "[P.UID()]", "Detonate" = "[P.detonate]", "inconvo" = "1")))
else
pdas.Add(list(list("Name" = "[P]", "Reference" = "\ref[P]", "Detonate" = "[P.detonate]", "inconvo" = "0")))
pdas.Add(list(list("Name" = "[P]", "uid" = "[P.UID()]", "Detonate" = "[P.detonate]", "inconvo" = "0")))
data["convopdas"] = convopdas
data["pdas"] = pdas
@@ -57,28 +52,30 @@
if(pda.cartridge)
for(var/A in pda.cartridge.messenger_plugins)
var/datum/data/pda/messenger_plugin/P = A
plugins += list(list(name = P.name, icon = P.icon, ref = "\ref[P]"))
plugins += list(list(name = P.name, icon = P.icon, uid = "[P.UID()]"))
data["plugins"] = plugins
if(pda.cartridge)
data["charges"] = pda.cartridge.charges ? pda.cartridge.charges : 0
/datum/data/pda/app/messenger/Topic(href, list/href_list)
if(!pda.can_use())
/datum/data/pda/app/messenger/tgui_act(action, list/params)
if(..())
return
unnotify()
switch(href_list["choice"])
. = TRUE
switch(action)
if("Toggle Messenger")
toff = !toff
if("Toggle Ringer")//If viewing texts then erase them, if not then toggle silent status
notify_silent = !notify_silent
if("Clear")//Clears messages
if(href_list["option"] == "All")
if(params["option"] == "All")
tnote.Cut()
conversations.Cut()
if(href_list["option"] == "Convo")
var/new_tnote[0]
if(params["option"] == "Convo")
var/list/new_tnote = list()
for(var/i in tnote)
if(i["target"] != active_conversation)
new_tnote[++new_tnote.len] = i
@@ -86,36 +83,30 @@
conversations.Remove(active_conversation)
active_conversation = null
latest_post = 0
if("Message")
var/obj/item/pda/P = locate(href_list["target"])
var/obj/item/pda/P = locateUID(params["target"])
create_message(usr, P)
if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp.
active_conversation = href_list["target"]
latest_post = 0
if(params["target"] in conversations) // Need to make sure the message went through, if not welp.
active_conversation = params["target"]
if("Select Conversation")
var/P = href_list["convo"]
var/P = params["target"]
for(var/n in conversations)
if(P == n)
active_conversation = P
latest_post = 0
if("Messenger Plugin")
if(!href_list["target"] || !href_list["plugin"])
if(!params["target"] || !params["plugin"])
return
var/obj/item/pda/P = locate(href_list["target"])
var/obj/item/pda/P = locateUID(params["target"])
if(!P)
to_chat(usr, "PDA not found.")
var/datum/data/pda/messenger_plugin/plugin = locate(href_list["plugin"])
var/datum/data/pda/messenger_plugin/plugin = locateUID(params["plugin"])
if(plugin && (plugin in pda.cartridge.messenger_plugins))
plugin.messenger = src
plugin.user_act(usr, P)
if("Back")
active_conversation = null
latest_post = 0
if("Autoscroll")
auto_scroll = !auto_scroll
/datum/data/pda/app/messenger/proc/create_message(var/mob/living/U, var/obj/item/pda/P)
var/t = input(U, "Please enter message", name, null) as text|null
@@ -180,8 +171,8 @@
useMS.send_pda_message("[P.owner]","[pda.owner]","[t]")
tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "\ref[P]")))
PM.tnote.Add(list(list("sent" = 0, "owner" = "[pda.owner]", "job" = "[pda.ownjob]", "message" = "[t]", "target" = "\ref[pda]")))
tnote.Add(list(list("sent" = 1, "owner" = "[P.owner]", "job" = "[P.ownjob]", "message" = "[t]", "target" = "[P.UID()]")))
PM.tnote.Add(list(list("sent" = 0, "owner" = "[pda.owner]", "job" = "[pda.ownjob]", "message" = "[t]", "target" = "[pda.UID()]")))
pda.investigate_log("<span class='game say'>PDA Message - <span class='name'>[U.key] - [pda.owner]</span> -> <span class='name'>[P.owner]</span>: <span class='message'>[t]</span></span>", "pda")
// Show it to ghosts
@@ -190,13 +181,13 @@
var/ghost_message = "<span class='name'>[pda.owner]</span> ([ghost_follow_link(pda, ghost=M)]) <span class='game say'>PDA Message</span> --> <span class='name'>[P.owner]</span> ([ghost_follow_link(P, ghost=M)]): <span class='message'>[t]</span>"
to_chat(M, "[ghost_message]")
if(!conversations.Find("\ref[P]"))
conversations.Add("\ref[P]")
if(!PM.conversations.Find("\ref[pda]"))
PM.conversations.Add("\ref[pda]")
if(!conversations.Find("[P.UID()]"))
conversations.Add("[P.UID()]")
if(!PM.conversations.Find("[pda.UID()]"))
PM.conversations.Add("[pda.UID()]")
SSnanoui.update_user_uis(U, P) // Update the sending user's PDA UI so that they can see the new message
PM.notify("<b>Message from [pda.owner] ([pda.ownjob]), </b>\"[t]\" (<a href='?src=[PM.UID()];choice=Message;target=\ref[pda]'>Reply</a>)")
SStgui.update_uis(src)
PM.notify("<b>Message from [pda.owner] ([pda.ownjob]), </b>\"[t]\" (<a href='?src=[PM.UID()];choice=Message;target=[pda.UID()]'>Reply</a>)")
log_pda("(PDA: [src.name]) sent \"[t]\" to [P.name]", usr)
else
to_chat(U, "<span class='notice'>ERROR: Messaging server is not responding.</span>")
@@ -230,3 +221,15 @@
/datum/data/pda/app/messenger/proc/can_receive()
return pda.owner && !toff && !hidden
// Handler for the in-chat reply button
/datum/data/pda/app/messenger/Topic(href, href_list)
if(!pda.can_use())
return
unnotify()
switch(href_list["choice"])
if("Message")
var/obj/item/pda/P = locateUID(href_list["target"])
create_message(usr, P)
if(href_list["target"] in conversations) // Need to make sure the message went through, if not welp.
active_conversation = href_list["target"]
+6 -2
View File
@@ -152,8 +152,12 @@
bait = bait.type
new bait(1, get_turf(pda))
/datum/data/pda/app/mob_hunter_game/Topic(href, list/href_list)
switch(href_list["choice"])
/datum/data/pda/app/mob_hunter_game/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
. = TRUE
switch(action)
if("Rename")
assign_nickname()
if("Release")
+106
View File
@@ -0,0 +1,106 @@
// All the TGUI interactions are in their own file to keep things simpler
/obj/item/pda/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_inventory_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "PDA", name, 600, 650, master_ui, state)
ui.open()
/obj/item/pda/tgui_data(mob/user)
var/list/data = list()
data["owner"] = owner
data["ownjob"] = ownjob
// update list of shortcuts, only if they changed
if(!length(shortcut_cache))
shortcut_cache = list()
shortcut_cat_order = list()
var/list/prog_list = programs.Copy()
if(cartridge)
prog_list |= cartridge.programs
for(var/A in prog_list)
var/datum/data/pda/P = A
if(P.hidden)
continue
var/list/cat
if(P.category in shortcut_cache)
cat = shortcut_cache[P.category]
else
cat = list()
shortcut_cache[P.category] = cat
shortcut_cat_order += P.category
cat |= list(list(name = P.name, icon = P.icon, notify_icon = P.notify_icon, uid = "[P.UID()]"))
// force the order of a few core categories
shortcut_cat_order = list("General") \
+ sortList(shortcut_cat_order - list("General", "Scanners", "Utilities")) \
+ list("Scanners", "Utilities")
data["idInserted"] = (id ? TRUE : FALSE)
data["idLink"] = (id ? "[id.registered_name], [id.assignment]" : "--------")
data["cartridge_name"] = cartridge ? cartridge.name : ""
data["stationTime"] = station_time_timestamp()
data["app"] = list()
data["app"] |= list(
"name" = current_app.title,
"icon" = current_app.icon,
"template" = current_app.template,
"has_back" = current_app.has_back)
current_app.update_ui(user, data)
return data
// Yes the stupid amount of args here is important, see L102
/obj/item/pda/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return
add_fingerprint(usr)
. = TRUE
switch(action)
if("Home") //Go home, largely replaces the old Return
var/datum/data/pda/app/main_menu/A = find_program(/datum/data/pda/app/main_menu)
if(A)
start_program(A)
if("StartProgram")
if(params["program"])
var/datum/data/pda/app/A = locateUID(params["program"])
if(A)
start_program(A)
if("Eject")//Ejects the cart, only done from hub.
if(!isnull(cartridge))
var/turf/T = loc
if(ismob(T))
T = T.loc
var/obj/item/cartridge/C = cartridge
C.forceMove(T)
if(scanmode in C.programs)
scanmode = null
if(current_app in C.programs)
start_program(find_program(/datum/data/pda/app/main_menu))
if(C.radio)
C.radio.hostpda = null
for(var/datum/data/pda/P in notifying_programs)
if(P in C.programs)
P.unnotify()
cartridge = null
update_shortcuts()
if("Authenticate")//Checks for ID
id_check(usr, 1)
if("Ringtone")
return set_ringtone()
else
if(current_app)
. = current_app.tgui_act(action, params, ui, state) // It needs proxying through down here so apps actually have their interacts called
if((honkamt > 0) && (prob(60)))//For clown virus.
honkamt--
playsound(loc, 'sound/items/bikehorn.ogg', 30, 1)
+1 -1
View File
@@ -69,7 +69,7 @@
..()
switch(href_list["op"])
if("control")
active = locate(href_list["bot"])
active = locateUID(href_list["bot"])
post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter)
if("scanbots") // find all bots
+2 -55
View File
@@ -29,7 +29,7 @@
/datum/data/pda/utility/toggle_door
name = "Toggle Door"
icon = "external-link"
icon = "external-link-alt"
var/remote_door_id = ""
/datum/data/pda/utility/toggle_door/start()
@@ -111,7 +111,7 @@
/datum/data/pda/utility/scanmode/gas
base_name = "Gas Scanner"
icon = "tachometer"
icon = "tachometer-alt"
/datum/data/pda/utility/scanmode/gas/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob)
if(istype(A, /obj/item/tank))
@@ -138,56 +138,3 @@
var/obj/machinery/atmospherics/unary/tank/T = A
pda.atmosanalyzer_scan(T.air_contents, user, T)
/datum/data/pda/utility/scanmode/notes
base_name = "Note Scanner"
icon = "clipboard"
var/datum/data/pda/app/notekeeper/notes
/datum/data/pda/utility/scanmode/notes/start()
. = ..()
notes = pda.find_program(/datum/data/pda/app/notekeeper)
/datum/data/pda/utility/scanmode/notes/scan_atom(atom/A as mob|obj|turf|area, mob/user as mob)
if(notes && istype(A, /obj/item/paper))
var/obj/item/paper/P = A
var/list/brlist = list("p", "/p", "br", "hr", "h1", "h2", "h3", "h4", "/h1", "/h2", "/h3", "/h4")
// JMO 20140705: Makes scanned document show up properly in the notes. Not pretty for formatted documents,
// as this will clobber the HTML, but at least it lets you scan a document. You can restore the original
// notes by editing the note again. (Was going to allow you to edit, but scanned documents are too long.)
var/raw_scan = sanitize_simple(P.info, list("\t" = "", "ÿ" = ""))
var/formatted_scan = ""
// Scrub out the tags (replacing a few formatting ones along the way)
// Find the beginning and end of the first tag.
var/tag_start = findtext(raw_scan, "<")
var/tag_stop = findtext(raw_scan, ">")
// Until we run out of complete tags...
while(tag_start && tag_stop)
var/pre = copytext(raw_scan, 1, tag_start) // Get the stuff that comes before the tag
var/tag = lowertext(copytext(raw_scan, tag_start + 1, tag_stop)) // Get the tag so we can do intellegent replacement
var/tagend = findtext(tag, " ") // Find the first space in the tag if there is one.
// Anything that's before the tag can just be added as is.
formatted_scan = formatted_scan + pre
// If we have a space after the tag (and presumably attributes) just crop that off.
if(tagend)
tag = copytext(tag, 1, tagend)
if(tag in brlist) // Check if it's I vertical space tag.
formatted_scan = formatted_scan + "<br>" // If so, add some padding in.
raw_scan = copytext(raw_scan, tag_stop + 1) // continue on with the stuff after the tag
// Look for the next tag in what's left
tag_start = findtext(raw_scan, "<")
tag_stop = findtext(raw_scan, ">")
// Anything that is left in the page. just tack it on to the end as is
formatted_scan = formatted_scan + raw_scan
// If there is something in there already, pad it out.
if(length(notes.note) > 0)
notes.note += "<br><br>"
// Store the scanned document to the notes
notes.note += "Scanned Document. Edit to restore previous notes/delete scan.<br>----------<br>" + formatted_scan + "<br>"
// notehtml ISN'T set to allow user to get their old notes back. A better implementation would add a "scanned documents"
// feature to the PDA, which would better convey the availability of the feature, but this will work for now.
// Inform the user
to_chat(user, "<span class='notice'>Paper scanned and OCRed to notekeeper.</span>")//concept of scanning paper copyright brainoblivion 2009
else
to_chat(user, "<span class='warning'>Error scanning [A].</span>")
@@ -517,3 +517,15 @@
description = "Beloved of children and teetotalers."
color = "#E6CDFF"
taste_description = "grape soda"
/datum/reagent/consumable/drink/coco/icecoco
name = "Iced Cocoa"
id = "icecoco"
description = "Hot cocoa and ice, refreshing and cool."
color = "#102838" // rgb: 16, 40, 56
adj_temp_hot = 0
adj_temp_cool = 5
drink_icon = "icedcoffeeglass"
drink_name = "Iced Cocoa"
drink_desc = "A sweeter drink to perk you up and refresh you!"
taste_description = "refreshingly cold cocoa"
@@ -868,3 +868,11 @@
required_reagents = list("hooch" = 1, "absinthe" = 1, "manlydorf" = 1, "syndicatebomb" = 1)
result_amount = 4
mix_message = "<span class='warning'>The mixture turns to a sickening froth.</span>"
/datum/chemical_reaction/icecoco
name = "Iced Cocoa"
id = "icecoco"
result = "icecoco"
required_reagents = list("ice" = 1, "hot_coco" = 3)
result_amount = 4
mix_sound = 'sound/goonstation/misc/drinkfizz.ogg'
@@ -0,0 +1,54 @@
/datum/tgui_module/power_monitor
name = "Power monitor"
var/select_monitor = FALSE
var/obj/machinery/computer/monitor/powermonitor
/datum/tgui_module/power_monitor/digital
select_monitor = TRUE
/datum/tgui_module/power_monitor/New()
..()
if(!select_monitor)
powermonitor = tgui_host()
/datum/tgui_module/power_monitor/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "PowerMonitor", name, 600, 650, master_ui, state)
ui.open()
/datum/tgui_module/power_monitor/tgui_data(mob/user)
var/list/data = list()
data["powermonitor"] = powermonitor
if(select_monitor)
data["select_monitor"] = TRUE
data["powermonitors"] = GLOB.powermonitor_repository.powermonitor_data()
if(powermonitor && !isnull(powermonitor.powernet))
if(select_monitor && (powermonitor.stat & (NOPOWER|BROKEN)))
powermonitor = null
return
data["poweravail"] = DisplayPower(powermonitor.powernet.viewavail)
data["powerdemand"] = DisplayPower(powermonitor.powernet.viewload)
data["history"] = powermonitor.history
data["apcs"] = GLOB.apc_repository.apc_data(powermonitor.powernet)
return data
/datum/tgui_module/power_monitor/tgui_act(action, list/params)
if(..())
return
// Dont allow people to break regular ones
if(!select_monitor)
return
. = TRUE
switch(action)
if("selectmonitor")
powermonitor = locateUID(params["selectmonitor"])
powermonitor.powernet = powermonitor.find_powernet() // Refresh the powernet of the monitor
if("return")
powermonitor = null
Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 B

-34
View File
@@ -1,34 +0,0 @@
<!--
Title: Brig Cell Management
Used In File(s): \code\game\machinery\computer\brigcells.dm
-->
<div class="statusDisplay" style="overflow: auto;">
<span id='maintable_data_archive'>
<table style='width: 100%' id='maintable_data'>
<thead>
<tr>
<th>Cell</th>
<th>Occupant</th>
<th>Crimes</th>
<th>Brigged By</th>
<th>Time Brigged For</th>
<th>Time Left</th>
<th>Release</th>
</tr>
</thead>
<tbody>
{{for data.cells}}
<tr style={{:value.background}}>
<td>{{:value.cell_id}}</td>
<td>{{:value.occupant}}</td>
<td>{{:value.crimes}}</td>
<td>{{:value.brigged_by}}</td>
<td>{{:value.time_set}}</td>
<td>{{:value.time_left}}</td>
<td>{{:helper.link('Release', null, {'release' : value.ref}, null, 'infoButton')}}</td>
</tr>
{{/for}}
</tbody>
</table>
</span>
</div>
-156
View File
@@ -1,156 +0,0 @@
<!--
Title: PDA UI
Used In File(s): \code\game\objects\items\devices\PDA\PDA.dm
-->
{{if data.useRetro}}
<head>
<style type="text/css">
html {
height: 100%;
overflow: auto;
}
.mainBG {
background: #6F7961;
}
.itemLabelNarrow, .itemLabel, .itemLabelWide, .itemLabelWider, .itemLabelWidest {
color: #000000;
font-weight: bold;
}
.good {
color: #444444;
}
.average {
color: #222222;
}
.bad {
color: #333333;
}
.pdanote {
color: #777777;
}
.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton {
color: #000000;
background: #565D4B;
}
.pdalink, .pdalink.disabled {
min-width: 15px;
height: 16px;
text-align: center;
color: #000000;
text-decoration: none;
background: #565D4B;
border: 1px solid #161616;
padding: 0px 4px 4px 4px;
margin: 0 2px 2px 0;
cursor: default;
white-space: nowrap;
}
.pdalink.disabled {
color: #333;
background: #565D4B;
}
#pdaFooter {
background: #6F7961;
}
.pdaFooterButton {
background: none;
color: #000;
}
.pdaFooterButton.disabled {
color: #444 !important;
}
div.clock {
color: black;
}
h1, h2, h3, h4, h5, h6 {
color: #000000;
}
.fixedLeft, .fixedLeftWide, .fixedLeftWider, .fixedLeftWidest, .floatRight {
color: #000000;
}
.floatRight {
min-width: 15px;
height: 16px;
text-align: center;
background: #565D4B;
border: 1px solid #161616;
padding: 0px 4px 4px 4px;
margin: 0 2px 2px 0;
}
.uiIcon16 {
background-image: none;
float: left;
width: auto;
height: auto;
margin: 0 0 0 0;
}
#uiTitleText, #pdaFooter {
color: #000000;
}
.pmon {
background: black;
}
.itemLabel {
color: black;
}
.statusDisplayRecords .good, .statusDisplay .good {
color: #020;
}
.statusDisplayRecords .average, .statusDisplay .average {
color: #110;
}
</style>
</head>
{{/if}}
{{if data.owner}}
<div class="item">
<div class="floatLeft">
{{if data.idInserted}}
{{:helper.link(data.idLink, 'eject', {'choice' : "Authenticate"}, null, 'pdalink fixedLeftWide')}}
{{/if}}
{{if data.cartridge_name}}
{{:helper.link(data.cartridge_name, 'eject', {'choice' : "Eject"}, null, 'pdalink fixedLeftWidest')}}
{{/if}}
{{:helper.link('Toggle R.E.T.R.O. mode', 'gear', {'choice': "Retro"}, null, 'pdalink fixedLeftWide')}}
</div>
<div class="clock">
{{:data.stationTime}}
</div>
</div>
{{if data.app}}
<h2><i class="fa fa-{{:data.app.icon}}"></i>&nbsp;{{:data.app.name}}</h2>
<div id="uiApp"></div>
<div class="pdaFooterButton disabled">&nbsp;</div>
{{/if}}
<div id="pdaFooter">
{{:helper.link("", 'undo', {'choice' : "Back"}, data.app.has_back ? null : 'disabled', 'link pdaFooterButton')}}
{{:helper.link("", 'home', {'choice' : "Home"}, data.app.is_home ? 'disabled' : null, 'link pdaFooterButton')}}
</div>
{{else}}
<div class="wholeScreen">
<br><br><br><br><br><br><br>No Owner information found, please swipe ID
</div>
{{/if}}
-60
View File
@@ -1,60 +0,0 @@
<!--
Title: PDA Atmospheric Scanner UI
Used In File(s): \code\game\objects\items\devices\PDA\cart_apps.dm
-->
<div class="statusDisplay" style="height: 250px; overflow: auto;">
<div class="item">
{{if data.aircontents.reading == 1}}
<div class="itemLabel">
<span class="pdanote">Pressure:</span>
</div>
<div class = "itemContent">
{{:helper.string('<span class="{0}">{1} kPa</span>', data.aircontents.pressure < 80 || data.aircontents.pressure > 120 ? 'bad' : data.aircontents.pressure < 95 || data.aircontents.pressure > 110 ? 'average' : 'good', helper.smoothRound(data.aircontents.pressure, 1))}}
</div>
<div class="itemLabel">
<span class="pdanote">Temperature:</span>
</div>
<div class = "itemContent">
{{:helper.string('<span class="{0}">{1} &deg;C</span>', data.aircontents.temp < 5 || data.aircontents.temp > 35 ? 'bad' : data.aircontents.temp < 15 || data.aircontents.temp > 25 ? 'average' : 'good' , helper.smoothRound(data.aircontents.temp, 1))}}
</div>
<br>
<div class="itemLabel">
<span class="pdanote">Oxygen:</span>
</div>
<div class = "itemContent">
{{:helper.string('<span class="{0}">{1}%</span>', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good', helper.smoothRound(data.aircontents.oxygen, 1))}}
</div>
<div class="itemLabel">
<span class="pdanote">Nitrogen:</span>
</div>
<div class = "itemContent">
{{:helper.string('<span class="{0}">{1}%</span>', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good', helper.smoothRound(data.aircontents.nitrogen, 1))}}
</div>
<div class="itemLabel">
<span class="pdanote">Carbon Dioxide:</span>
</div>
<div class = "itemContent">
{{:helper.string('<span class="{0}">{1}%</span>', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good', helper.smoothRound(data.aircontents.carbon_dioxide, 1))}}
</div>
<div class="itemLabel">
<span class="pdanote">Plasma:</span>
</div>
<div class = "itemContent">
{{:helper.string('<span class="{0}">{1}%</span>', data.aircontents.plasma > 0 ? 'bad' : 'good', helper.smoothRound(data.aircontents.plasma, 1))}}
</div>
{{if data.aircontents.other > 0}}
<div class="itemLabel">
<span class="pdanote">Unknown:</span>
</div>
<div class = "itemContent">
<span class="bad">{{:helper.smoothRound(data.aircontents.other, 1)}}%</span>
</div>
{{/if}}
{{else}}
<div class="itemContent" style="width: 100%;">
<span class="average"><b>Unable to get air reading</b></span>
</div>
{{/if}}
</div>
</div>
-66
View File
@@ -1,66 +0,0 @@
<div class="statusDisplay">
<div class="item">
<span class="good">Current Location:</span>
{{if data.janitor.user_loc.x == 0}}
<span class="bad">Unknown</span>
{{else}}
<span class="average"> {{:data.janitor.user_loc.x}} / {{:data.janitor.user_loc.y}}</span>
{{/if}}
</div>
<div class="item">
{{if data.janitor.mops}}
<span class="good">Mop Locations:</span>
<ul>
{{for data.janitor.mops}}
<li>
<span class="average">({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}</span>
</li>
{{/for}}
</ul>
{{else}}
<span class="bad">Unable to locate Mops</span>
{{/if}}
</div>
<div class="item">
{{if data.janitor.buckets}}
<span class="good">Mop Bucket Locations:</span>
<ul>
{{for data.janitor.buckets}}
<li>
<span class="average">({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Capacity: {{:value.volume}}/{{:value.max_volume}}</span>
</li>
{{/for}}
</ul>
{{else}}
<span class="bad">Unable to locate Mop Buckets</span>
{{/if}}
</div>
<div class="item">
{{if data.janitor.cleanbots}}
<span class="good">Cleanbot Locations:</span>
<ul>
{{for data.janitor.cleanbots}}
<li>
<span class="average">({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Status: {{:value.status}}</span>
</li>
{{/for}}
</ul>
{{else}}
<span class="bad">Unable to locate Cleanbots</span>
{{/if}}
</div>
<div class="item">
{{if data.janitor.carts}}
<span class="good">Janitorial Cart Locations:</span>
<ul>
{{for data.janitor.carts}}
<li>
<span class="average">({{:value.x}} / {{:value.y}}) - {{:value.dir}} - Water Level: {{:value.volume}}/{{:value.max_volume}}</span>
</li>
{{/for}}
</ul>
{{else}}
<span class="bad">Unable to locate Janitorial Carts</span>
{{/if}}
</div>
</div>
-76
View File
@@ -1,76 +0,0 @@
<!--
Title: PDA Home UI
Used In File(s): \code\game\objects\items\devices\PDA\core_apps.dm
-->
<script>
/* flash notify icons */
var notifications = [];
var noteTimer;
function mm_flashNotify() {
notifications.forEach(function(n) {
if(n.item.hasClass("fa-"+n.icon)) {
n.item.removeClass("fa-"+n.icon).addClass("fa-"+n.notifyIcon);
} else {
n.item.removeClass("fa-"+n.notifyIcon).addClass("fa-"+n.icon);
}
});
}
if(!noteTimer) {
noteTimer = window.setInterval(mm_flashNotify, 1000);
}
</script>
<div class="item">
<div class="itemLabelNarrow">
Owner:
</div>
<div class="itemContent">
<span class="average">{{:data.owner}}, {{:data.ownjob}}</span>
</div>
</div>
<div class="item">
<div class="itemLabelNarrow">
ID:
</div>
<div class="itemContent">
{{:helper.link('Update PDA Info', 'refresh', {'choice' : "UpdateInfo"}, data.idInserted ? null : 'disabled', 'pdalink fixedLeftWide')}}
</div>
</div>
<div class="item">
<H2>Functions</H2>
</div>
{{for data.categories : cat : i}}
<div class="item mainmenu">
<div class="itemLabelNarrow">
<b>{{:cat}}</b>:
</div>
<div class="itemContent">
{{for data.apps[cat]}}
{{if value.ref in data.notifying}}
<div data-notify="{{:value.ref}}">
{{:helper.link(value.name, value.notify_icon, {'choice' : "StartProgram", 'program' : value.ref}, null, 'pdalink fixedLeftWide')}}
</div>
<script>
notifications.push({item: $("[data-notify='{{:value.ref}}'] i"), icon: '{{:value.icon}}', notifyIcon: '{{:value.notify_icon}}'});
</script>
{{else}}
{{:helper.link(value.name, value.icon, {'choice' : "StartProgram", 'program' : value.ref}, null, 'pdalink fixedLeftWide')}}
{{/if}}
{{/for}}
</div>
</div>
{{/for}}
{{if data.pai}}
<div class="item">
<div class = "itemLabelNarrow">
<b>PAI Utilities</b>:
</div>
<div class = "itemContent">
{{:helper.link('Configuration', 'gear', {'choice' : "pai", 'option' : "1"}, null, 'pdalink fixedLeft')}}
{{:helper.link('Eject pAI', 'eject', {'choice' : "pai", 'option' : "2"}, null, 'pdalink fixedLeft')}}
</div>
</div>
{{/if}}
-96
View File
@@ -1,96 +0,0 @@
<!--
Title: PDA Crew Manifest UI
Used In File(s): \code\game\objects\items\devices\PDA\core_apps.dm
-->
<div class="item">
<center><table class="pmon"><tbody>
{{if data.manifest.heads}}
<tr><th colspan="3" class="command">Command</th></tr>
{{for data.manifest["heads"]}}
{{if value.rank == "Captain"}}
<tr><td><span class="good">{{:value.name}}</span></td><td><span class="good">{{:value.rank}}</span></td><td><span class="good">{{:value.active}}</span></td></tr>
{{else}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/if}}
{{/for}}
{{/if}}
{{if data.manifest.sec}}
<tr><th colspan="3" class="sec">Security</th></tr>
{{for data.manifest["sec"]}}
{{if value.rank == "Head of Security"}}
<tr><td><span class="good">{{:value.name}}</span></td><td><span class="good">{{:value.rank}}</span></td><td><span class="good">{{:value.active}}</span></td></tr>
{{else}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/if}}
{{/for}}
{{/if}}
{{if data.manifest.eng}}
<tr><th colspan="3" class="eng">Engineering</th></tr>
{{for data.manifest["eng"]}}
{{if value.rank == "Chief Engineer"}}
<tr><td><span class="good">{{:value.name}}</span></td><td><span class="good">{{:value.rank}}</span></td><td><span class="good">{{:value.active}}</span></td></tr>
{{else}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/if}}
{{/for}}
{{/if}}
{{if data.manifest.med}}
<tr><th colspan="3" class="med">Medical</th></tr>
{{for data.manifest["med"]}}
{{if value.rank == "Chief Medical Officer"}}
<tr><td><span class="good">{{:value.name}}</span></td><td><span class="good">{{:value.rank}}</span></td><td><span class="good">{{:value.active}}</span></td></tr>
{{else}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/if}}
{{/for}}
{{/if}}
{{if data.manifest.sci}}
<tr><th colspan="3" class="sci">Science</th></tr>
{{for data.manifest["sci"]}}
{{if value.rank == "Research Director"}}
<tr><td><span class="good">{{:value.name}}</span></td><td><span class="good">{{:value.rank}}</span></td><td><span class="good">{{:value.active}}</span></td></tr>
{{else}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/if}}
{{/for}}
{{/if}}
{{if data.manifest.ser}}
<tr><th colspan="3" class="ser">Service</th></tr>
{{for data.manifest["ser"]}}
{{if value.rank == "Head of Personnel"}}
<tr><td><span class="good">{{:value.name}}</span></td><td><span class="good">{{:value.rank}}</span></td><td><span class="good">{{:value.active}}</span></td></tr>
{{else}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/if}}
{{/for}}
{{/if}}
{{if data.manifest.sup}}
<tr><th colspan="3" class="sup">Supply</th></tr>
{{for data.manifest["sup"]}}
{{if value.rank == "Head of Personnel"}}
<tr><td><span class="good">{{:value.name}}</span></td><td><span class="good">{{:value.rank}}</span></td><td><span class="good">{{:value.active}}</span></td></tr>
{{else value.rank == "Quartermaster"}}
<tr><td><span class="qm-job">{{:value.name}}</span></td><td><span class="qm-job">{{:value.rank}}</span></td><td><span class="qm-job">{{:value.active}}</span></td></tr>
{{else}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/if}}
{{/for}}
{{/if}}
{{if data.manifest.civ}}
<tr><th colspan="3" class="civ">Civilian</th></tr>
{{for data.manifest["civ"]}}
{{if value.rank == "Head of Personnel"}}
<tr><td><span class="good">{{:value.name}}</span></td><td><span class="good">{{:value.rank}}</span></td><td><span class="good">{{:value.active}}</span></td></tr>
{{else}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/if}}
{{/for}}
{{/if}}
{{if data.manifest.misc}}
<tr><th colspan="3" class="misc">Misc</th></tr>
{{for data.manifest["misc"]}}
<tr><td><span class="average">{{:value.name}}</span></td><td><span class="average">{{:value.rank}}</span></td><td><span class="average">{{:value.active}}</span></td></tr>
{{/for}}
{{/if}}
</tbody></table></center>
</div>
-54
View File
@@ -1,54 +0,0 @@
{{if !data.records}}
<div class="item">
<div class="itemLabel">Select a record:</div>
</div>
{{for data.recordsList}}
<div class="item">
{{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}}
</div>
{{empty}}
<div class="item">
<span class="average">No records found.</span>
</div>
{{/for}}
{{else}}
<div class="statusDisplayRecords">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{if data.records.general}}
<span class="good">Name: </span> <span class="average">{{:data.records.general.name}} </span><br>
<span class="good">Sex: </span> <span class="average">{{:data.records.general.sex}} </span><br>
<span class="good">Species: </span> <span class="average">{{:data.records.general.species}} </span><br>
<span class="good">Age: </span> <span class="average">{{:data.records.general.age}} </span><br>
<span class="good">Rank: </span> <span class="average">{{:data.records.general.rank}} </span><br>
<span class="good">Fingerprint: </span> <span class="average">{{:data.records.general.fingerprint}} </span><br>
<span class="good">Physical Status: </span> <span class="average">{{:data.records.general.p_stat}} </span><br>
<span class="good">Mental Status: </span> <span class="average">{{:data.records.general.m_stat}} </span><br><br>
{{else}}
<span class="bad">
General Record Lost!<br><br>
</span>
{{/if}}
{{if data.records.medical}}
<div class="item">
<div class="itemLabel">Medical Data:</div>
</div>
<span class="good">Blood Type: </span> <span class="average">{{:data.records.medical.b_type}} </span><br><br>
<span class="good">Minor Disabilities: </span> <span class="average">{{:data.records.medical.mi_dis}} </span><br>
<span class="good">Details: </span> <span class="average">{{:data.records.medical.mi_dis_d}} </span><br><br>
<span class="good">Major Disabilities: </span> <span class="average">{{:data.records.medical.ma_dis}} </span><br>
<span class="good">Details: </span> <span class="average">{{:data.records.medical.ma_dis_d}} </span><br><br>
<span class="good">Allergies: </span> <span class="average">{{:data.records.medical.alg}} </span><br>
<span class="good">Details: </span> <span class="average">{{:data.records.medical.alg_d}} </span><br><br>
<span class="good">Current Disease: </span> <span class="average">{{:data.records.medical.cdi}} </span><br>
<span class="good">Details: </span> <span class="average">{{:data.records.medical.alg_d}} </span><br><br>
<span class="good">Important Notes: </span> <span class="average">{{:data.records.medical.notes}} </span>
{{else}}
<span class="bad">
Medical Record Lost!
</span>
{{/if}}
</div>
</div>
</div>
{{/if}}
-90
View File
@@ -1,90 +0,0 @@
<!--
Title: PDA Messenger UI
Used In File(s): \code\game\objects\items\devices\PDA\core_apps.dm
-->
{{if data.active_conversation}}
<div class="item">
<div class="itemLabel">
<b>Messenger Functions</b>:
</div>
<div class ="itemContent">
{{:helper.link('Delete Conversation', 'trash', {'choice' : "Clear", 'option' : "Convo"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link(data.auto_scroll ? 'Autoscroll: On' : 'Autoscroll: Off', 'level-down', {'choice' : "Autoscroll"}, null, 'pdalink fixedLeftWide')}}
</div>
</div>
<br>
<br>
<H3>Conversation with:&nbsp;<span class="average">{{:data.convo_name}}&nbsp;({{:data.convo_job}})</span></H3>
<div class="statusDisplay" style="overflow: auto;">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{for data.messages}}
{{if data.active_conversation == value.target}}
{{if value.sent==0}}
<span class="average"><B>Them</B>: {{:value.message}}</span><br>
{{else}}
<span class="good"><B>You</B>: {{:value.message}}</span><br>
{{/if}}
{{/if}}
{{/for}}
</div>
</div>
</div>
{{:helper.link('Reply', 'comment', {'choice' : "Message", 'target': data.active_conversation}, null, 'pdalink fixedLeftWidest')}}
<script>
$(function() {
{{if data.auto_scroll && data.latest_post != data.messages.length}}
var body = document.body;
$('html,body').animate({scrollTop: body.scrollHeight}, "fast");
{{/if}}
});
</script>
{{else}}
<div class="item">
<div class="itemLabelNarrow">
<b>Messenger Functions</b>:
</div>
<div class ="itemContent">
{{:helper.link(data.silent==1 ? 'Ringer: Off' : 'Ringer: On', data.silent==1 ? 'volume-off' : 'volume-up', {'choice' : "Toggle Ringer"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link(data.toff==1 ? 'Messenger: Off' : 'Messenger: On',data.toff==1 ? 'close':'check', {'choice' : "Toggle Messenger"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Set Ringtone', 'bell-o', {'choice' : "Ringtone"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Delete all Conversations', 'trash', {'choice' : "Clear", 'option' : "All"}, null, 'pdalink fixedLeftWider')}}
</div>
</div>
{{if data.toff == 0}}
<br>
{{if data.charges}}
<div class="item">
<b>{{:data.charges}} charges left.</b>
<br><br>
</div>
{{/if}}
{{if !data.convopdas.length && !data.pdas.length}}
<b>No other PDAS located</b>
{{else}}
<H3>Current Conversations</H3>
{{for data.convopdas}}
<div class="item">
{{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Select Conversation", 'convo' : value.Reference } , null, 'pdalink')}}
{{if data.charges}}
{{for data.plugins : plugin : i}}
{{:helper.link(plugin.name, plugin.icon, {'choice' : "Messenger Plugin", 'plugin' : plugin.ref, 'target' : value.Reference}, null, 'pdalink fixedLeft')}}
{{/for}}
{{/if}}
</div>
{{/for}}
<H3>Other PDAs</H3>
{{for data.pdas}}
<div class="item">
{{:helper.link(value.Name, 'arrow-circle-down', {'choice' : "Message", 'target' : value.Reference}, null, 'pdalink')}}
{{if data.charges}}
{{for data.plugins : plugin : i}}
{{:helper.link(plugin.name, plugin.icon, {'choice' : "Messenger Plugin", 'plugin' : plugin.ref, 'target' : value.Reference}, null, 'pdalink fixedLeft')}}
{{/for}}
{{/if}}
</div>
{{/for}}
{{/if}}
{{/if}}
{{/if}}
-91
View File
@@ -1,91 +0,0 @@
<div class="item">
<div class="itemLabel">
<table>
<tr>
<td>
Connection Status:
</td>
{{if data.connected}}
<td>
<span class="good">Connected</span>
</td>
<td>
{{:helper.link('Disconnect', 'sign-out', {'choice': 'Disconnect'})}}
</td>
{{else}}
<td>
<span class="bad">No Connection</span>
</td>
<td>
{{:helper.link('Connect', 'sign-in', {'choice': 'Reconnect'})}}
</td>
{{/if}}
</tr>
</table>
</div>
</div>
<hr>
<div class="itemLabel">My Collection:</div>
{{if data.no_collection}}
<div class="statusDisplayRecords">
<div class="item">
<span class="average">Your collection is empty! Go capture some Nano-Mobs!</span>
</div>
</div>
<br>
Wild mobs captured: {{:data.wild_captures}}
{{else}}
<div class="statusDisplayRecords">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{if data.entry}}
{{if data.entry.nickname}}
<span class="good">Name: </span> <span class="average"> {{:data.entry.nickname}}</span><br>
{{/if}}
<span class="good">Species: </span> <span class="average">{{:data.entry.real_name}} </span><br>
<span class="good">Level: </span> <span class="average">{{:data.entry.level}} </span><br>
<span class="good">Primary Type: </span> <span class="average">{{:data.entry.type1}} </span><br>
{{if data.entry.type2}}
<span class="good">Secondary Type: </span> <span class="average">{{:data.entry.type2}} </span><br>
{{/if}}
{{if data.entry.sprite}}
<img src='{{:data.entry.sprite}}'>
{{else}}
<span class="bad">Mob Image Missing!</span>
{{/if}}
{{else}}
<span class="bad">
Mob Data Missing!<br><br>
</span>
{{/if}}
</div>
</div>
</div>
<br>
Wild mobs captured: {{:data.wild_captures}}
<div class="item">
<table>
<tr>
<td>
{{:helper.link('Previous Mob', 'arrow-left', {'choice': 'Prev'})}}
</td>
<td>
{{:helper.link('Transfer Mob', 'exchange', {'choice': 'Transfer'})}}
</td>
<td>
{{:helper.link('Rename Mob', 'pencil', {'choice': 'Rename'})}}
</td>
<td>
{{:helper.link('Release Mob', 'tree', {'choice': 'Release'})}}
</td>
<td>
{{:helper.link('Next Mob', 'arrow-right', {'choice': 'Next'})}}
</td>
</tr>
</table>
{{if data.entry.is_hacked}}
<br>
{{:helper.link('Set Trap', 'bolt', {'choice': 'Set_Trap'})}}
{{/if}}
</div>
{{/if}}
-118
View File
@@ -1,118 +0,0 @@
{{if !data.mulebot.active}}
{{if data.mulebot.count == 0}}
<H1><span class="bad">No bots found.</span></H1>
{{else}}
<div class="item">
Select a MULE:
</div>
<br>
{{for data.mulebot.bots}}
<div class="item">
{{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}})
</div>
{{/for}}
{{/if}}
<br>
{{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}}
{{else}}
<H1><span class="average">{{:data.mulebot.active}}</span></H1>
{{if data.mulebot.botstatus.mode == -1}}
<H1><span class="bad">Waiting for response...</span></H1>
{{else}}
<H1><span class="good">Status:</span></H1>
<div class="item">
<div class="itemLabel">
<span class="good">Location:</span>
</div>
<div class="itemContent">
<span class="average">{{:data.mulebot.botstatus.loca}}</span>
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Mode:</span>
</div>
<div class="itemContent">
<span class="average">
{{if data.mulebot.botstatus.mode == 0}}
Ready
{{else data.mulebot.botstatus.mode == 1}}
Loading/Unloading
{{else data.mulebot.botstatus.mode == 2}}
Navigating to Delivery Location
{{else data.mulebot.botstatus.mode == 3}}
Navigating to Home
{{else data.mulebot.botstatus.mode == 4}}
Waiting for Clear Path
{{else data.mulebot.botstatus.mode == 5 || data.mulebot.botstatus.mode == 6}}
Calculating navigation Path
{{else data.mulebot.botstatus.mode == 7}}
Unable to locate destination
{{/if}}
</span>
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Current Load:</span>
</div>
<div class="itemContent">
<span class="average">
{{:helper.link(data.mulebot.botstatus.load == null ? 'None (Unload)' : data.mulebot.botstatus.load + ' (Unload)', 'archive', {'radiomenu' : "1", 'op' : "unload"},data.mulebot.botstatus.load == null ? 'disabled' : null, 'pdalink fixedLeftWidest')}}
</span>
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Power:</span>
</div>
<div class="itemContent">
<span class="average">
{{:data.mulebot.botstatus.powr}}%
</span>
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Destination:</span>
</div>
<div class="itemContent">
{{:helper.link(data.mulebot.botstatus.dest == null || data.mulebot.botstatus.dest == "" ? 'None (Set)' : data.mulebot.botstatus.dest + ' (Set)', 'gear', {'radiomenu' : "1", 'op' : "setdest"}, null, 'pdalink fixedLeftWidest')}}
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Home:</span>
</div>
<div class="itemContent">
{{if data.mulebot.botstatus.home == null}} None {{else}} {{:data.mulebot.botstatus.home}} {{/if}}
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Auto Return:</span>
</div>
<div class="itemContent">
{{:helper.link(data.mulebot.botstatus.retn == 1 ? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.retn==1 ? "retoff" : "reton")}, null, 'pdalink fixedLeftWidest')}}
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Auto Pickup:</span>
</div>
<div class="itemContent">
{{:helper.link(data.mulebot.botstatus.pick==1? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.pick==1 ? "pickoff" : "pickon")}, null, 'pdalink fixedLeftWidest')}}
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Functions:</span>
</div>
<div class="itemContent">
{{:helper.link('Stop', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, 'pdalink fixedLeft')}}
{{:helper.link('Proceed', 'gear', {'radiomenu' : "1", 'op' : "start"}, null, 'pdalink fixedLeft')}}
{{:helper.link('Return Home', 'gear', {'radiomenu' : "1", 'op' : "home"}, null, 'pdalink fixedLeft')}}
</div>
</div>
{{/if}}
{{/if}}
-21
View File
@@ -1,21 +0,0 @@
<!--
Title: PDA Notekeeper UI
Used In File(s): \code\game\objects\items\devices\PDA\apps.dm
-->
<div class="item">
<div class="itemLabel">
<b>Notes</b>:
</div>
</div>
<div class="statusDisplayRecords">
<div class="item">
<div class="itemContent" style="width: 100%;">
<span class="pdanote">{{:data.note}}</span>
</div>
</div>
</div>
<div class="item">
<div class="itemLabel">
{{:helper.link('Edit Notes', 'pencil-square-o', {'choice': "Edit"}, null, 'pdalink')}}
</div>
</div>
-49
View File
@@ -1,49 +0,0 @@
{{if !data.records.powerconnected}}
<div class="item">
<div class="itemLabel">Select a power monitor:</div>
</div>
{{for data.records.powermonitors}}
<div class="item">
{{:helper.link(value.Name, 'exclamation-circle', {'choice' : "Power Select", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}}
</div>
{{/for}}
{{else}}
<div class="item">
<div class="itemLabelNarrow">
<b>Total Power:</b>
</div>
<div class="itemContent">
<span class="average">{{:data.records.poweravail}} W</span>
</div>
</div>
<div class="item">
<div class="itemLabelNarrow">
<b>Total Load:</b>
</div>
<div class="itemContent">
<span class="average">{{:data.records.powerload}} W</span>
</div>
</div>
<div class="item">
<div class="itemLabelNarrow">
<b>Total Demand:</b>
</div>
<div class="itemContent">
<span class="average">{{:data.records.powerdemand}} W</span>
</div>
</div>
<div class="item">
<table class="curvedEdges" style="text-align: center;"><tbody>
<tr><th>Area</th><th>Equip.</th><th>Lighting</th><th>Environ.</th><th>Cell</th><th>Load</th></tr>
{{for data.records.apcs}}
<tr><td style="text-align: left; font-weight: bold;">{{:value.Name}}</td>
{{:helper.string('<td width="55px" bgcolor="{0}">{1}</td>', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}}
{{:helper.string('<td width="55px" bgcolor="{0}">{1}</td>', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}}
{{:helper.string('<td width="55px" bgcolor="{0}">{1}</td>', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}}
{{:helper.string('<td style="text-align: center;" width="65px" bgcolor="{0}">{1}{2}</td>', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}}
<td width="55px">{{:value.Load}}W</td>
</tr>
{{/for}}
</tbody></table>
</div>
{{/if}}
-59
View File
@@ -1,59 +0,0 @@
{{if !data.beepsky.active}}
{{if data.beepsky.count == 0}}
<H1><span class="bad">No bots found.</span></H1>
{{else}}
<div class="item">
Select a bot:
</div>
<br>
{{for data.beepsky.bots}}
<div class="item">
{{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}})
</div>
{{/for}}
{{/if}}
<br>
{{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}}
{{else}}
<H1><span class="average">{{:data.beepsky.active}}</span></H1>
{{if data.beepsky.botstatus.mode == -1}}
<H1><span class="bad">Waiting for response...</span></H1>
{{else}}
<H1><span class="good">Status:</span></H1>
<div class="item">
<div class="itemLabel">
<span class="good">Location:</span>
</div>
<div class="itemContent">
<span class="average">{{:data.beepsky.botstatus.loca}}</span>
</div>
</div>
<div class="item">
<div class="itemLabel">
<span class="good">Mode:</span>
</div>
<div class="itemContent">
<span class="average">
{{if data.beepsky.botstatus.mode ==0}}
Ready
{{else data.beepsky.botstatus.mode == 1}}
Apprehending target
{{else data.beepsky.botstatus.mode ==2 || data.beepsky.botstatus.mode == 3}}
Arresting target
{{else data.beepsky.botstatus.mode ==4}}
Starting patrol
{{else data.beepsky.botstatus.mode ==5}}
On Patrol
{{else data.beepsky.botstatus.mode ==6}}
Responding to summons
{{/if}}
</span>
</div>
</div>
<div class="item">
{{:helper.link('Stop Patrol', 'gear', {'radiomenu' : "1", 'op' : "stop"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Start Patrol', 'gear', {'radiomenu' : "1", 'op' : "go"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Summon Bot', 'gear', {'radiomenu' : "1", 'op' : "summon"}, null, 'pdalink fixedLeftWide')}}
</div>
{{/if}}
{{/if}}
-50
View File
@@ -1,50 +0,0 @@
{{if !data.records}}
<div class="item">
<div class="itemLabel">Select a record:</div>
</div>
{{for data.recordsList}}
<div class="item">
{{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}}
</div>
{{empty}}
<div class="item">
<span class="average">No records found.</span>
</div>
{{/for}}
{{else}}
<div class="statusDisplayRecords">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{if data.records.general}}
<span class="good">Name: </span> <span class="average"> {{:data.records.general.name}}</span><br>
<span class="good">Sex: </span> <span class="average">{{:data.records.general.sex}} </span><br>
<span class="good">Species: </span> <span class="average">{{:data.records.general.species}} </span><br>
<span class="good">Age: </span> <span class="average">{{:data.records.general.age}} </span><br>
<span class="good">Rank: </span> <span class="average">{{:data.records.general.rank}} </span><br>
<span class="good">Fingerprint: </span> <span class="average">{{:data.records.general.fingerprint}} </span><br>
<span class="good">Physical Status: </span> <span class="average">{{:data.records.general.p_stat}} </span><br>
<span class="good">Mental Status: </span> <span class="average">{{:data.records.general.m_stat}} </span><br><br>
{{else}}
<span class="bad">
General Record Lost!<br><br>
</span>
{{/if}}
{{if data.records.security}}
<div class="item">
<div class="itemLabel">Security Data:</div>
</div>
<span class="good">Criminal Status: </span><span class="average">{{:data.records.security.criminal}} </span><br><br>
<span class="good">Minor Crimes: </span><span class="average">{{:data.records.security.mi_crim}} </span><br>
<span class="good">Details: </span><span class="average">{{:data.records.security.mi_crim_d}} </span><br><br>
<span class="good">Major Crimes: </span><span class="average">{{:data.records.security.ma_crim}} </span><br>
<span class="good">Details: </span><span class="average">{{:data.records.security.ma_crim_d}} </span><br><br>
<span class="good">Important Notes: </span><span class="average">{{:data.records.security.notes}} </span>
{{else}}
<span class="bad">
Security Record Lost!<br><br>
</span>
{{/if}}
</div>
</div>
</div>
{{/if}}
-38
View File
@@ -1,38 +0,0 @@
<!--
Title: PDA Remote Signaller UI
Used In File(s): \code\game\objects\items\devices\PDA\cart_apps.dm
-->
<div class="item">
<div class="itemLabel">
<b>Frequency</b>:
</div>
<div class="itemContent">
{{:data.signal_freq}}
<br>
&nbsp;
{{:helper.link('-1', null, {'choice' : "Signal Frequency", 'sfreq' : "-10"}, null, null)}}&nbsp;
{{:helper.link('-.2', null, {'choice' : "Signal Frequency", 'sfreq' : "-2"}, null, null)}}&nbsp;
{{:helper.link('+.2', null, {'choice' : "Signal Frequency", 'sfreq' : "2"}, null, null)}}&nbsp;
{{:helper.link('+1', null, {'choice' : "Signal Frequency", 'sfreq' : "10"}, null, null)}}
</div>
</div>
<br>
<br>
<div class="item">
<div class="itemLabel">
<b>Code</b>:
</div>
<div class="itemContent">
<span class="average">
{{:data.signal_code}}<br>
</span>
{{:helper.link('-5', null, {'choice' : "Signal Code", 'scode' : "-5"}, null, null)}}
{{:helper.link('-1', null, {'choice' : "Signal Code", 'scode' : "-1"}, null, null)}}
{{:helper.link('+1', null, {'choice' : "Signal Code", 'scode' : "1"}, null, null)}}
{{:helper.link('+5', null, {'choice' : "Signal Code", 'scode' : "5"}, null, null)}}
</div>
</div>
<div class="item">
{{:helper.link('Send Signal', 'exclamation-circle', {'choice' : "Send Signal"}, null, null)}}
</div>
-44
View File
@@ -1,44 +0,0 @@
<!--
Title: PDA Status Display UI
Used In File(s): \code\game\objects\items\devices\PDA\cart_apps.dm
-->
<div class="item">
<div class="itemLabel">
<b>Code</b>:
</div>
<div class="itemContent">
{{:helper.link('Clear', 'trash', {'choice' : "Status", 'statdisp' : "blank"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Shuttle ETA', 'gear', {'cartmenu' : "1", 'choice' : "Status", 'statdisp' : "shuttle"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Message', 'gear', {'choice' : "Status", 'statdisp' : "message"}, null, 'pdalink fixedLeftWide')}}
</div>
</div>
<br>
<div class="item">
<div class="itemLabel">
<b>Message line 1</b>
</div>
<div class="itemContent">
{{:helper.link(data.records.message1 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg1"}, null, 'pdalink fixedLeftWide')}}
</div>
</div>
<div class="item">
<div class="itemLabel">
<b>Message line 2</b>
</div>
<div class="itemContent">
{{:helper.link(data.records.message2 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg2"}, null, 'pdalink fixedLeftWide')}}
</div>
</div>
<br>
<div class="item">
<div class="itemLabel">
<b> ALERT!</b>:
</div>
<div class="itemContent">
{{:helper.link('None', 'bell', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "default"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Red Alert', 'bell', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "redalert"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Lockdown', 'exclamation-circle', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "lockdown"}, null, 'pdalink fixedLeftWide')}}
{{:helper.link('Biohazard', 'exclamation-circle', {'choice' : "Status", 'statdisp' : "alert", 'alert' : "biohazard"}, null, 'pdalink fixedLeftWide')}}
</div>
</div>
-39
View File
@@ -1,39 +0,0 @@
<div class="item">
<div class="itemLabelNarrow">
Location:
</div>
<div class="itemContent">
<span class="average">
{{if data.supply.shuttle_moving}}
Moving to {{:data.supply.shuttle_loc}}
{{else}}
Shuttle at {{:data.supply.shuttle_loc}}
{{/if}}
<br>
{{:data.supply.shuttle_time}}
</span>
</div>
</div>
<div class="statusDisplayRecords">
<div class="item">
<div class="itemContent" style="width: 100%;">
<span class="good"><B>Current Approved Orders</B></span><br>
{{if data.supply.approved_count == 0}}
<span class="average pdanote">No current approved orders </span><br><br>
{{else}}
{{for data.supply.approved}}
<span class="average">#{{:value.Number}} - {{:value.Name}} approved by {{:value.OrderedBy}}<br>{{if value.Comment != ""}} {{:value.Comment}} <br>{{/if}}<br></span>
{{/for}}
{{/if}}
<br><br>
<span class="good"><B>Current Requested Orders</B></span><br>
{{if data.supply.requests_count == 0}}
<span class="average pdanote">No current requested orders</span><br><br>
{{else}}
{{for data.supply.requests}}
<span class="average">#{{:value.Number}} - {{:value.Name}} requested by {{:value.OrderedBy}}<br>{{if value.Comment != ""}} {{:value.Comment}} <br>{{/if}}<br></span>
{{/for}}
{{/if}}
</div>
</div>
</div>
-67
View File
@@ -1,67 +0,0 @@
<!--
Title: Power Monitoring Console
Used In File(s): \code\modules\nano\modules\power_monitor.dm
-->
{{if !data.powermonitor && data.select_monitor}}
<h2>Station Power Monitors</h2>
<div class="item">
Select a power monitor:
</div>
{{for data.powermonitors}}
<div class="item">
{{:helper.link(value.Name, 'gear', { 'selectmonitor' : value.ref }, null, null)}}
</div>
{{empty}}
<h2>Network Error</h2>
<span class='bad'>No power monitors found.</span>
{{/for}}
{{/if}}
{{if data.powermonitor}}
{{if data.select_monitor}}
{{:helper.link('Return', 'gear', { 'return' : 1 }, null, null)}}
{{/if}}
<h2>Powernet Status</h2>
<div class="item">
<div class="itemLabelNarrow">
<b>Total Power:</b>
</div>
<div class="itemContent">
<span class="average">{{:helper.smoothRound(data.poweravail)}} W</span>
</div>
</div>
<div class="item">
<div class="itemLabelNarrow">
<b>Total Load:</b>
</div>
<div class="itemContent">
<span class="average">{{:helper.smoothRound(data.powerload)}} W</span>
</div>
</div>
<div class="item">
<div class="itemLabelNarrow">
<b>Total Demand:</b>
</div>
<div class="itemContent">
<span class="average">{{:helper.smoothRound(data.powerdemand)}} W</span>
</div>
</div>
<div class="item">
<table class="curvedEdges" style="text-align: center;"><tbody>
<tr><th>Area</th><th>Equip.</th><th>Lighting</th><th>Environ.</th><th>Cell</th><th>Load</th></tr>
{{for data.apcs}}
<tr><td style="text-align: left; font-weight: bold;">{{:value.Name}}</td>
{{:helper.string('<td width="55px" bgcolor="{0}">{1}</td>', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}}
{{:helper.string('<td width="55px" bgcolor="{0}">{1}</td>', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}}
{{:helper.string('<td width="55px" bgcolor="{0}">{1}</td>', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}}
{{:helper.string('<td style="text-align: center;" width="65px" bgcolor="{0}">{1}{2}</td>', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}}
<td width="65px">{{:value.Load}}W</td>
</tr>
{{/for}}
</tbody></table>
</div>
{{else}}
{{if !data.select_monitor}}
<h2>Network Error</h2>
<span class='bad'>Power monitor not connected to power network.</span>
{{/if}}
{{/if}}
-101
View File
@@ -1,101 +0,0 @@
<!--
Title: Syndicate Uplink, uses some javascript to change nanoUI up a bit.
Used In File(s): \code\game\objects\items\devices\uplinks.dm
-->
{{:helper.syndicateMode()}}
<script>
{{var tooltiptext = function(desc_text) { var text = ""; if(desc_text){text += desc_text + " ";}return text;};}}
</script>
<center><H1><span class="white">{{:data.welcome}}</span></H1></center>
<H2><span class="itemLabel">Uplink Functions</span></H2>
<br>
<div class="item">
{{:helper.link('Purchase Gear', 'gear', {'menu' : 0, 'category' : null}, null, 'white')}}
{{:helper.link('Exploitable Information', 'gear', {'menu' : 1}, null, 'white')}}
{{:helper.link('Lock Uplink', 'power-off', {'lock' : "1"}, null, 'white')}}
</div>
<br>
{{if data.menu == 0}}
<H2><span class="white">Purchase Gear</span></H2>
<span class="white"><i>Each item costs a number of tele-crystals as indicated by the number following their name.</i></span>
<div class="item">
<div class="itemLabel">
<b>Tele-Crystals</b>:
</div>
<div class="itemContent">
{{:data.crystals}}
</div>
</div>
<br>
{{for data.nano_items}}
{{if value.Category == data.category_choice}}
<div class="item">
{{:helper.link ( value.Category, 'arrow-circle-down', {'menu' : 0, 'category' : null}, null, 'white')}}
</div>
{{else}}
<div class="item">
{{:helper.link ( value.Category, 'arrow-circle-right', {'menu' : 0, 'category' : value.Category}, null, 'white')}}
</div>
{{/if}}
{{if value.Category == data.category_choice}}
<div class="block">
<table>
{{for value.items :itemValue:itemIndex}}
<tr>
<td><div class='floatLeft tooltipRight' data-tooltip='{{:tooltiptext(itemValue.Description)}}'>
{{:helper.link( itemValue.Name, 'gear', {'buy_item' : itemValue.obj_path, 'cost' : itemValue.Cost}, itemValue.Cost > data.crystals ? 'disabled' : null, null)}} - <span class="white">{{:itemValue.Cost}}</span> {{if itemValue.hijack_only}}(HIJACK AGENTS ONLY){{/if}}
</div></td>
</tr>
{{/for}}
</table>
</div>
{{/if}}
{{/for}}
<br>
<div class="item">
{{:helper.link('Buy Random Item' , 'gear', {'buy_item' : 'random'}, data.crystals <= 0 ? 'disabled' : null, 'white')}}
</div>
<div class="item">
{{:helper.link('Refund item in active hand' , 'gear', {refund : 1}, null, 'white')}}
</div>
{{else data.menu == 1}}
<h2><span class="white">Information Record List:</span></h2>
<br>
<div class="item">
Select a Record
</div>
<br>
{{for data.exploit_records}}
<div class="item">
{{:helper.link(value.Name, 'gear', {'menu' : 11, 'id' : value.id}, null, null)}}
</div>
{{/for}}
{{else data.menu == 11}}
<h2><span class="white">Information Record:</span></h2>
<br>
<div class="statusDisplayRecords">
<div class="item">
<div class="itemContent" style="width: 100%;">
{{if data.exploit_exists == 1}}
<span class="good">Name: </span> <span class="average">{{:data.exploit.name}} </span><br>
<span class="good">Sex: </span> <span class="average">{{:data.exploit.sex}} </span><br>
<span class="good">Species: </span> <span class="average">{{:data.exploit.species}} </span><br>
<span class="good">Age: </span> <span class="average">{{:data.exploit.age}} </span><br>
<span class="good">Rank: </span> <span class="average">{{:data.exploit.rank}} </span><br>
<span class="good">Fingerprint: </span> <span class="average">{{:data.exploit.fingerprint}} </span><br>
{{else}}
<span class="bad">
No exploitative information acquired!
<br>
<br>
</span>
{{/if}}
</div>
</div>
</div>
{{/if}}
+2 -1
View File
@@ -2103,7 +2103,6 @@
#include "code\modules\nano\modules\human_appearance.dm"
#include "code\modules\nano\modules\law_manager.dm"
#include "code\modules\nano\modules\nano_module.dm"
#include "code\modules\nano\modules\power_monitor.dm"
#include "code\modules\ninja\energy_katana.dm"
#include "code\modules\ninja\suit\gloves.dm"
#include "code\modules\ninja\suit\head.dm"
@@ -2139,6 +2138,7 @@
#include "code\modules\pda\messenger_plugins.dm"
#include "code\modules\pda\mob_hunt_game_app.dm"
#include "code\modules\pda\PDA.dm"
#include "code\modules\pda\pda_tgui.dm"
#include "code\modules\pda\pdas.dm"
#include "code\modules\pda\radio.dm"
#include "code\modules\pda\utilities.dm"
@@ -2438,6 +2438,7 @@
#include "code\modules\tgui\modules\_base.dm"
#include "code\modules\tgui\modules\crew_monitor.dm"
#include "code\modules\tgui\modules\ert_manager.dm"
#include "code\modules\tgui\modules\power_monitor.dm"
#include "code\modules\tgui\plugins\login.dm"
#include "code\modules\tgui\plugins\modal.dm"
#include "code\modules\tgui\states\admin.dm"
Binary file not shown.
+5 -1
View File
@@ -23,6 +23,7 @@ export const Button = props => {
ellipsis,
content,
iconRotation,
iconColor,
iconSpin,
children,
onclick,
@@ -81,7 +82,10 @@ export const Button = props => {
}}
{...rest}>
{icon && (
<Icon name={icon} rotation={iconRotation} spin={iconSpin} />
<Icon name={icon}
color={iconColor}
rotation={iconRotation}
spin={iconSpin} />
)}
{content}
{children}
@@ -0,0 +1,13 @@
// see seconds_to_clock
const secondsToClock = totalSeconds => {
if (!totalSeconds || totalSeconds < 0) { totalSeconds = 0; }
let minutes = Math.floor(totalSeconds / 60).toString(10);
let seconds = (Math.floor(totalSeconds) % 60).toString(10);
return [minutes, seconds].map(p => p.length < 2 ? '0' + p : p).join(':');
};
export const TimeDisplay = ({ totalSeconds = 0 }) => (
secondsToClock(totalSeconds)
);
+1
View File
@@ -26,3 +26,4 @@ export { Slider } from './Slider';
export { Table } from './Table';
export { Tabs } from './Tabs';
export { Tooltip } from './Tooltip';
export { TimeDisplay } from './TimeDisplay';
+9 -8
View File
@@ -8,14 +8,15 @@ export const UI_CLOSE = -1;
export const COLORS = {
// Department colors
department: {
captain: '#c06616',
security: '#e74c3c',
medbay: '#3498db',
science: '#9b59b6',
engineering: '#f1c40f',
cargo: '#f39c12',
centcom: '#00c100',
other: '#c38312',
command: '#526aff',
security: '#CF0000',
medical: '#009190',
science: '#993399',
engineering: '#A66300',
supply: '#9F8545',
service: '#80A000',
centcom: '#78789B',
other: '#C38312',
},
// Damage type colors
damageType: {
@@ -0,0 +1,75 @@
import { Window } from "../layouts";
import { TimeDisplay, Box, Button, Flex, Icon, Input, LabeledList, Section, Table, Tabs } from '../components';
import { useBackend, useLocalState } from "../backend";
const BrigCellsTableRow = (properties, context) => {
const { cell } = properties;
const { act } = useBackend(context);
const {
cell_id,
occupant,
crimes,
brigged_by,
time_left_seconds,
time_set_seconds,
ref,
} = cell;
let className = '';
if (time_left_seconds > 0) { className += ' BrigCells__listRow--active'; }
const release = () => {
act('release', { ref });
};
return (
<Table.Row className={className}>
<Table.Cell>{cell_id}</Table.Cell>
<Table.Cell>{occupant}</Table.Cell>
<Table.Cell>{crimes}</Table.Cell>
<Table.Cell>{brigged_by}</Table.Cell>
<Table.Cell><TimeDisplay totalSeconds={time_set_seconds} /></Table.Cell>
<Table.Cell><TimeDisplay totalSeconds={time_left_seconds} /></Table.Cell>
<Table.Cell>
<Button type="button" onClick={release}>
Release
</Button>
</Table.Cell>
</Table.Row>
);
};
const BrigCellsTable = ({ cells }) => (
<Table className="BrigCells__list">
<Table.Row>
<Table.Cell header>Cell</Table.Cell>
<Table.Cell header>Occupant</Table.Cell>
<Table.Cell header>Crimes</Table.Cell>
<Table.Cell header>Brigged By</Table.Cell>
<Table.Cell header>Time Brigged For</Table.Cell>
<Table.Cell header>Time Left</Table.Cell>
<Table.Cell header>Release</Table.Cell>
</Table.Row>
{cells.map(cell => (
<BrigCellsTableRow key={cell.ref} cell={cell} />
))}
</Table>
);
export const BrigCells = (properties, context) => {
const { act, data } = useBackend(context);
const { cells } = data;
return (
<Window theme="security" resizable>
<Window.Content scrollable className="Layout__content--flexColumn">
<Flex direction="column" height="100%">
<Section height="100%" flexGrow="1">
<BrigCellsTable cells={cells} />
</Section>
</Flex>
</Window.Content>
</Window>
);
};
+150
View File
@@ -0,0 +1,150 @@
import { useBackend } from "../backend";
import { Button, Box, Section, Flex, Icon } from "../components";
import { Window } from "../layouts";
/* This is all basically stolen from routes.js. */
import { routingError } from "../routes";
const RequirePDAInterface = require.context('./pda', false, /\.js$/);
const GetApp = name => {
let appModule;
try {
appModule = RequirePDAInterface(`./${name}.js`);
} catch (err) {
if (err.code === 'MODULE_NOT_FOUND') {
return routingError('notFound', name);
}
throw err;
}
const Component = appModule[name];
if (!Component) {
return routingError('missingExport', name);
}
return Component;
};
export const PDA = (props, context) => {
const { act, data } = useBackend(context);
const {
app,
owner,
} = data;
if (!owner) {
return (
<Window>
<Window.Content scrollable>
<Section title="Error">
No user data found. Please swipe an ID card.
</Section>
</Window.Content>
</Window>
);
}
const App = GetApp(app.template);
return (
<Window>
<Window.Content scrollable>
<PDAHeader />
<Section
title={
<Box>
<Icon name={app.icon} mr={1} />
{app.name}
</Box>
}
p={1}>
<App />
</Section>
<Box mb={8} />
<PDAFooter />
</Window.Content>
</Window>
);
};
const PDAHeader = (props, context) => {
const { act, data } = useBackend(context);
const {
idInserted,
idLink,
stationTime,
cartridge_name,
} = data;
return (
<Box mb={1}>
<Flex align="center" justify="space-between">
{idInserted ? (
<Flex.Item>
<Button
icon="id-card"
color="transparent"
onClick={() => act("Authenticate")}
content={idLink} />
</Flex.Item>
) : (
<Flex.Item m={1} color="grey">
No ID Inserted
</Flex.Item>
)}
{cartridge_name ? (
<Flex.Item>
<Button
icon="sd-card"
color="transparent"
onClick={() => act("Eject")}
content={"Eject " + cartridge_name} />
</Flex.Item>
) : (
<Flex.Item m={1} color="grey">
No Cartridge Inserted
</Flex.Item>
)}
<Flex.Item grow={1} textAlign="right" bold m={1}>
{stationTime}
</Flex.Item>
</Flex>
</Box>
);
};
const PDAFooter = (props, context) => {
const { act, data } = useBackend(context);
const {
app,
} = data;
return (
<Box className="PDA__footer">
<Flex>
<Flex.Item basis="33%">
<Button
fluid
className="PDA__footer__button"
color="transparent"
iconColor={app.has_back ? "white" : "disabled"}
icon="arrow-alt-circle-left-o"
onClick={() => act("Back")} />
</Flex.Item>
<Flex.Item basis="33%">
<Button
fluid
className="PDA__footer__button"
color="transparent"
iconColor={app.is_home ? "disabled" : "white"}
icon="home"
onClick={() => { act("Home"); }} />
</Flex.Item>
</Flex>
</Box>
);
};
@@ -0,0 +1,297 @@
import { map, sortBy } from 'common/collections';
import { flow } from 'common/fp';
import { toFixed } from 'common/math';
import { pureComponentHooks } from 'common/react';
import { Component, Fragment } from 'inferno';
import { decodeHtmlEntities } from 'common/string';
import { Section, Box, Button, Flex, LabeledList, ProgressBar, ColorBox, Chart, Table, Icon } from "../components";
import { Window } from "../layouts";
import { useBackend, useLocalState } from "../backend";
const PEAK_DRAW = 600000;
export const PowerMonitor = (props, context) => {
return (
<Window resizeable>
<Window.Content scrollable>
<PowerMonitorMainContent />
</Window.Content>
</Window>
);
};
// This constant is so it can be thrown
// into PDAs with minimal effort
export const PowerMonitorMainContent = (props, context) => {
const { act, data } = useBackend(context);
const {
powermonitor,
select_monitor,
} = data;
return (
<Box m={0}>
{(!powermonitor && select_monitor) && (
<SelectionView />
)}
{(powermonitor && (
<DataView />
))}
</Box>
);
};
const SelectionView = (props, context) => {
const { act, data } = useBackend(context);
const {
powermonitors,
} = data;
return (
<Section title="Select Power Monitor">
{powermonitors.map(p => (
<Box key={p}>
<Button
content={p.Name}
icon="arrow-right"
onClick={() => act('selectmonitor', {
selectmonitor: p.uid,
})}
/>
</Box>
))}
</Section>
);
};
const DataView = (props, context) => {
const { act, data } = useBackend(context);
const {
powermonitor,
history,
apcs,
select_monitor,
} = data;
const [
sortByField,
setSortByField,
] = useLocalState(context, 'sortByField', null);
const supply = history.supply[history.supply.length - 1] || 0;
const demand = history.demand[history.demand.length - 1] || 0;
const supplyData = history.supply.map((value, i) => [i, value]);
const demandData = history.demand.map((value, i) => [i, value]);
const maxValue = Math.max(
PEAK_DRAW,
...history.supply,
...history.demand);
// Process area data
const parsedApcs = flow([
map((apc, i) => ({
...apc,
// Generate a unique id
id: apc.name + i,
})),
sortByField === 'name' && sortBy(apc => apc.Name),
sortByField === 'charge' && sortBy(apc => -apc.CellPct),
sortByField === 'draw' && sortBy(apc => -apc.Load),
])(apcs);
return (
<Section title={powermonitor}
buttons={
<Box m={0}>
{select_monitor && (
<Button
content="Back"
icon="arrow-up"
onClick={() => act('return')}
/>
)}
</Box>
}>
<Flex spacing={1}>
<Flex.Item width="200px">
<Section>
<LabeledList>
<LabeledList.Item label="Supply">
<ProgressBar
value={supply}
minValue={0}
maxValue={maxValue}
color="green">
{toFixed(supply / 1000) + ' kW'}
</ProgressBar>
</LabeledList.Item>
<LabeledList.Item label="Draw">
<ProgressBar
value={demand}
minValue={0}
maxValue={maxValue}
color="red">
{toFixed(demand / 1000) + ' kW'}
</ProgressBar>
</LabeledList.Item>
</LabeledList>
</Section>
</Flex.Item>
<Flex.Item grow={1}>
<Section position="relative" height="100%">
<Chart.Line
fillPositionedParent
data={supplyData}
rangeX={[0, supplyData.length - 1]}
rangeY={[0, maxValue]}
strokeColor="rgba(32, 177, 66, 1)"
fillColor="rgba(32, 177, 66, 0.25)" />
<Chart.Line
fillPositionedParent
data={demandData}
rangeX={[0, demandData.length - 1]}
rangeY={[0, maxValue]}
strokeColor="rgba(219, 40, 40, 1)"
fillColor="rgba(219, 40, 40, 0.25)" />
</Section>
</Flex.Item>
</Flex>
<Box mb={1}>
<Box inline mr={2} color="label">
Sort by:
</Box>
<Button.Checkbox
checked={sortByField === 'name'}
content="Name"
onClick={() => setSortByField(sortByField !== 'name' && 'name')} />
<Button.Checkbox
checked={sortByField === 'charge'}
content="Charge"
onClick={() => setSortByField(
sortByField !== 'charge' && 'charge'
)} />
<Button.Checkbox
checked={sortByField === 'draw'}
content="Draw"
onClick={() => setSortByField(sortByField !== 'draw' && 'draw')} />
</Box>
<Table>
<Table.Row header>
<Table.Cell>
Area
</Table.Cell>
<Table.Cell collapsing>
Charge
</Table.Cell>
<Table.Cell textAlign="right">
Draw
</Table.Cell>
<Table.Cell collapsing title="Equipment">
Eqp
</Table.Cell>
<Table.Cell collapsing title="Lighting">
Lgt
</Table.Cell>
<Table.Cell collapsing title="Environment">
Env
</Table.Cell>
</Table.Row>
{parsedApcs.map((area, i) => (
<Table.Row
key={area.id}
className="Table__row candystripe">
<Table.Cell>
{decodeHtmlEntities(area.Name)}
</Table.Cell>
<Table.Cell className="Table__cell text-right text-nowrap">
<AreaCharge
charging={area.CellStatus}
charge={area.CellPct} />
</Table.Cell>
<Table.Cell className="Table__cell text-right text-nowrap">
{area.Load}
</Table.Cell>
<Table.Cell className="Table__cell text-center text-nowrap">
<AreaStatusColorBox status={area.Equipment} />
</Table.Cell>
<Table.Cell className="Table__cell text-center text-nowrap">
<AreaStatusColorBox status={area.Lights} />
</Table.Cell>
<Table.Cell className="Table__cell text-center text-nowrap">
<AreaStatusColorBox status={area.Environment} />
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
);
};
const AreaCharge = props => {
const { charging, charge } = props;
return (
<Fragment>
<Icon
width="18px"
textAlign="center"
name={(
charging === "N" && (
charge > 50
? 'battery-half'
: 'battery-quarter'
)
|| charging === "C" && 'bolt'
|| charging === "F" && 'battery-full'
)}
color={(
charging === "N" && (
charge > 50
? 'yellow'
: 'red'
)
|| charging === "C" && 'yellow'
|| charging === "F" && 'green'
)} />
<Box
inline
width="36px"
textAlign="right">
{toFixed(charge) + '%'}
</Box>
</Fragment>
);
};
AreaCharge.defaultHooks = pureComponentHooks;
const AreaStatusColorBox = props => {
let auto;
let active;
const { status } = props;
switch (status) {
case "AOn":
auto = true;
active = true;
break;
case "AOff":
auto = true;
active = false;
break;
case "On":
auto = false;
active = true;
break;
case "Off":
auto = false;
active = false;
break;
}
const tooltipText = (active ? 'On' : 'Off')
+ ` [${auto ? 'auto' : 'manual'}]`;
return (
<ColorBox
color={active ? 'good' : 'bad'}
content={auto ? undefined : 'M'}
title={tooltipText} />
);
};
AreaStatusColorBox.defaultHooks = pureComponentHooks;
+192
View File
@@ -0,0 +1,192 @@
import { Fragment } from "inferno";
import { useBackend, useLocalState } from "../backend";
import { Button, Box, Section, Tabs, Icon, Flex, Input } from "../components";
import { FlexItem } from "../components/Flex";
import { Window } from "../layouts";
import { createSearch, decodeHtmlEntities } from 'common/string';
import { flow } from 'common/fp';
import { filter, sortBy } from 'common/collections';
const PickTab = index => {
switch (index) {
case 0:
return <ItemsPage />;
case 1:
return <ExploitableInfoPage />;
default:
return "SOMETHING WENT VERY WRONG PLEASE AHELP";
}
};
export const Uplink = (props, context) => {
const { act, data } = useBackend(context);
const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0);
return (
<Window theme="syndicate">
<Window.Content scrollable>
<Tabs>
<Tabs.Tab
key="PurchasePage"
selected={tabIndex === 0}
onClick={() => setTabIndex(0)}
icon="shopping-cart">
Purchase Equipment
</Tabs.Tab>
<Tabs.Tab
key="ExploitableInfo"
selected={tabIndex === 1}
onClick={() => setTabIndex(1)}
icon="user">
Exploitable Information
</Tabs.Tab>
<Tabs.Tab
key="LockUplink"
// This cant ever be selected. Its just a close button.
onClick={() => act('lock')}
icon="lock">
Lock Uplink
</Tabs.Tab>
</Tabs>
{PickTab(tabIndex)}
</Window.Content>
</Window>
);
};
const ItemsPage = (_properties, context) => {
const { act, data } = useBackend(context);
const {
crystals,
cats,
} = data;
// Default to first
const [
uplinkCat,
setUplinkCat,
] = useLocalState(context, 'uplinkTab', cats[0]);
return (
<Section
title={"Current Balance: " + crystals + "TC"}
buttons={
<Fragment>
<Button
content="Random Item"
icon="question"
onClick={() => act('buyRandom')}
/>
<Button
content="Refund Currently Held Item"
icon="undo"
onClick={() => act('refund')}
/>
</Fragment>
}>
<Flex>
<FlexItem>
<Tabs vertical>
{cats.map(c => (
<Tabs.Tab
key={c}
selected={c === uplinkCat}
onClick={() => setUplinkCat(c)}>
{c.cat}
</Tabs.Tab>
))}
</Tabs>
</FlexItem>
<Flex.Item grow={1} basis={0}>
{uplinkCat.items.map(i => (
<Section
key={decodeHtmlEntities(i.name)}
title={decodeHtmlEntities(i.name)}
buttons={
<Button
content={"Buy (" + i.cost + "TC)" + (i.refundable ? " [Refundable]" : "")}
color={i.hijack_only === 1 && "red"}
// Yes I care this much about both of these being able to render at the same time
tooltip={(i.hijack_only === 1 && "Hijack Agents Only!")}
tooltipPosition="left"
onClick={() => act("buyItem", {
item: i.obj_path,
})}
disabled={i.cost > crystals}
/>
}>
<Box italic>
{decodeHtmlEntities(i.desc)}
</Box>
</Section>
))}
</Flex.Item>
</Flex>
</Section>
);
};
const ExploitableInfoPage = (_properties, context) => {
const { act, data } = useBackend(context);
const {
exploitable,
} = data;
// Default to first
const [
selectedRecord,
setSelectedRecord,
] = useLocalState(context, 'selectedRecord', exploitable[0]);
const [
searchText,
setSearchText,
] = useLocalState(context, 'searchText', '');
// Search for peeps
const SelectMembers = (people, searchText = '') => {
const MemberSearch = createSearch(searchText, member => member.name);
return flow([
// Null member filter
filter(member => member?.name),
// Optional search term
searchText && filter(MemberSearch),
// Slightly expensive, but way better than sorting in BYOND
sortBy(member => member.name),
])(people);
};
const crew = SelectMembers(exploitable, searchText);
return (
<Section title="Exploitable Records">
<Flex>
<FlexItem basis={20}>
<Input
fluid
mb={1}
placeholder="Search Crew"
onInput={(e, value) => setSearchText(value)} />
<Tabs vertical>
{crew.map(r => (
<Tabs.Tab
key={r}
selected={r === selectedRecord}
onClick={() => setSelectedRecord(r)}>
{r.name}
</Tabs.Tab>
))}
</Tabs>
</FlexItem>
<Flex.Item grow={1} basis={0}>
<Section title={"Name: " + selectedRecord.name}>
<Box>Age: {selectedRecord.age}</Box>
<Box>Fingerprint: {selectedRecord.fingerprint}</Box>
<Box>Rank: {selectedRecord.rank}</Box>
<Box>Sex: {selectedRecord.sex}</Box>
<Box>Species: {selectedRecord.species}</Box>
</Section>
</Flex.Item>
</Flex>
</Section>
);
};
@@ -0,0 +1,195 @@
import { useBackend } from "../../backend";
import { Box, Section, Table } from "../../components";
import { decodeHtmlEntities } from 'common/string';
import { COLORS } from "../../constants";
const deptCols = COLORS.department;
const HeadRoles = [
"Captain",
"Head of Security",
"Chief Engineer",
"Chief Medical Officer",
"Research Director",
"Head of Personnel",
];
// Head colour check. Abbreviated to save on 80 char
const HCC = role => {
// Return green if they are the head
if (HeadRoles.indexOf(role) !== -1) {
return "green";
}
// Return yellow if its the qm
if (role === "Quartermaster") {
return "yellow";
}
// Return orange if its a regular person
return "orange";
};
// Head bold check. Abbreviated to save on 80 char
const HBC = role => {
// Return true if they are a head, or a QM
if ((HeadRoles.indexOf(role) !== -1) || role === "Quartermaster") {
return true;
} else {
return false;
}
};
const ManifestTable = group => {
return (
group.length > 0 && (
<Table>
<Table.Row header color="white">
<Table.Cell width="50%">Name</Table.Cell>
<Table.Cell width="35%">Rank</Table.Cell>
<Table.Cell width="15%">Active</Table.Cell>
</Table.Row>
{group.map(person => (
<Table.Row
color={HCC(person.rank)}
key={person.name + person.rank}
bold={HBC(person.rank)}>
<Table.Cell>{decodeHtmlEntities(person.name)}</Table.Cell>
<Table.Cell>{decodeHtmlEntities(person.rank)}</Table.Cell>
<Table.Cell>{person.active}</Table.Cell>
</Table.Row>
))}
</Table>
)
);
};
export const CrewManifest = (props, context) => {
const { act, data } = useBackend(context);
// HOW TO USE THIS THING
/*
GLOB.data_core.get_manifest_json()
data["manifest"] = GLOB.PDA_Manifest
*/
// And thats it
const {
manifest,
} = data;
const {
heads,
sec,
eng,
med,
sci,
ser,
sup,
misc,
} = manifest;
return (
<Box>
<Section
title={(
<Box backgroundColor={deptCols.command} m={-1} pt={1} pb={1}>
<Box ml={1} textAlign="center" fontSize={1.4}>
Command
</Box>
</Box>
)}
level={2}>
{ManifestTable(heads)}
</Section>
<Section
title={(
<Box backgroundColor={deptCols.security} m={-1} pt={1} pb={1}>
<Box ml={1} textAlign="center" fontSize={1.4}>
Security
</Box>
</Box>
)}
level={2}>
{ManifestTable(sec)}
</Section>
<Section
title={(
<Box backgroundColor={deptCols.engineering} m={-1} pt={1} pb={1}>
<Box ml={1} textAlign="center" fontSize={1.4}>
Engineering
</Box>
</Box>
)}
level={2}>
{ManifestTable(eng)}
</Section>
<Section
title={(
<Box backgroundColor={deptCols.medical} m={-1} pt={1} pb={1}>
<Box ml={1} textAlign="center" fontSize={1.4}>
Medical
</Box>
</Box>
)}
level={2}>
{ManifestTable(med)}
</Section>
<Section
title={(
<Box backgroundColor={deptCols.science} m={-1} pt={1} pb={1}>
<Box ml={1} textAlign="center" fontSize={1.4}>
Science
</Box>
</Box>
)}
level={2}>
{ManifestTable(sci)}
</Section>
<Section
title={(
<Box backgroundColor={deptCols.service} m={-1} pt={1} pb={1}>
<Box ml={1} textAlign="center" fontSize={1.4}>
Service
</Box>
</Box>
)}
level={2}>
{ManifestTable(ser)}
</Section>
<Section
title={(
<Box backgroundColor={deptCols.supply} m={-1} pt={1} pb={1}>
<Box ml={1} textAlign="center" fontSize={1.4}>
Supply
</Box>
</Box>
)}
level={2}>
{ManifestTable(sup)}
</Section>
<Section
title={(
<Box m={-1} pt={1} pb={1}>
<Box ml={1} textAlign="center" fontSize={1.4}>
Misc
</Box>
</Box>
)}
level={2}>
{ManifestTable(misc)}
</Section>
</Box>
);
};
@@ -0,0 +1,48 @@
import { filter } from 'common/collections';
import { useBackend } from "../../backend";
import { Box, LabeledList } from "../../components";
const getItemColor = (value, min2, min1, max1, max2) => {
if (value < min2) {
return "bad";
} else if (value < min1) {
return "average";
} else if (value > max1) {
return "average";
} else if (value > max2) {
return "bad";
}
return "good";
};
export const pda_atmos_scan = (props, context) => {
const { act, data } = useBackend(context);
const {
aircontents,
} = data;
return (
<Box>
<LabeledList>
{filter(
i => (i.val !== "0")
|| i.entry === "Pressure"
|| i.entry === "Temperature"
)(aircontents)
.map(item => (
<LabeledList.Item
key={item.entry}
label={item.entry}
color={getItemColor(item.val,
item.bad_low,
item.poor_low,
item.poor_high,
item.bad_high)}>
{item.val}{item.units}
</LabeledList.Item>
))}
</LabeledList>
</Box>
);
};
@@ -0,0 +1,59 @@
import { useBackend } from "../../backend";
import { LabeledList, Box } from "../../components";
export const pda_janitor = (props, context) => {
const { act, data } = useBackend(context);
const { janitor } = data;
const {
user_loc,
mops,
buckets,
cleanbots,
carts,
} = janitor;
return (
<LabeledList>
<LabeledList.Item label="Current Location">
{user_loc.x},{user_loc.y}
</LabeledList.Item>
{mops && (
<LabeledList.Item label="Mop Locations">
{mops.map(m => (
<Box key={m}>
{m.x},{m.y} ({m.dir}) - {m.status}
</Box>
))}
</LabeledList.Item>
)}
{buckets && (
<LabeledList.Item label="Mop Bucket Locations">
{buckets.map(b => (
<Box key={b}>
{b.x},{b.y} ({b.dir}) - [{b.volume}/{b.max_volume}]
</Box>
))}
</LabeledList.Item>
)}
{cleanbots && (
<LabeledList.Item label="Cleanbot Locations">
{cleanbots.map(c => (
<Box key={c}>
{c.x},{c.y} ({c.dir}) - {c.status}
</Box>
))}
</LabeledList.Item>
)}
{carts && (
<LabeledList.Item label="Janitorial Cart Locations">
{carts.map(c => (
<Box key={c}>
{c.x},{c.y} ({c.dir}) - [{c.volume}/{c.max_volume}]
</Box>
))}
</LabeledList.Item>
)}
</LabeledList>
);
};
@@ -0,0 +1,77 @@
import { round } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend } from "../../backend";
import { Box, Button, Flex, Icon, LabeledList, ProgressBar, Section } from "../../components";
export const pda_main_menu = (props, context) => {
const { act, data } = useBackend(context);
const {
owner,
ownjob,
idInserted,
categories,
pai,
notifying,
} = data;
return (
<Fragment>
<Box>
<LabeledList>
<LabeledList.Item label="Owner" color="average">
{owner}, {ownjob}
</LabeledList.Item>
<LabeledList.Item label="ID">
<Button
icon="sync"
content="Update PDA Info"
disabled={!idInserted}
onClick={() => act("UpdateInfo")} />
</LabeledList.Item>
</LabeledList>
</Box>
<Section level={2} title="Functions">
<LabeledList>
{categories.map(name => {
let apps = data.apps[name];
if (!apps || !apps.length) {
return null;
} else {
return (
<LabeledList.Item label={name} key={name}>
{apps.map(app => (
<Button
key={app.uid}
icon={(app.uid in notifying) ? app.notify_icon : app.icon}
iconSpin={(app.uid in notifying)}
color={(app.uid in notifying) ? "red" : "transparent"}
content={app.name}
onClick={() => (
act("StartProgram", { program: app.uid })
)} />
))}
</LabeledList.Item>
);
}
})}
</LabeledList>
</Section>
{!!pai && (
<Section level={2} title="pAI">
<Button
fluid
icon="cog"
content="Configuration"
onClick={() => act("pai", { option: 1 })} />
<Button
fluid
icon="eject"
content="Eject pAI"
onClick={() => act("pai", { option: 2 })} />
</Section>
)}
</Fragment>
);
};
@@ -0,0 +1,8 @@
import { useBackend } from "../../backend";
import { CrewManifest } from "../common/CrewManifest";
export const pda_manifest = (props, context) => {
const { act, data } = useBackend(context);
return <CrewManifest />;
};
@@ -0,0 +1,160 @@
import { useBackend, useLocalState } from "../../backend";
import { createSearch } from 'common/string';
import { flow } from 'common/fp';
import { filter, sortBy } from 'common/collections';
import { Box, Input, Button, Section, LabeledList } from "../../components";
export const pda_medical = (props, context) => {
const { act, data } = useBackend(context);
const {
records,
} = data;
return (
<Box>
{!records ? (
<SelectionView />
) : (
<RecordView />
)}
</Box>
);
};
const SelectionView = (props, context) => {
const { act, data } = useBackend(context);
const {
recordsList,
} = data;
const [
searchText,
setSearchText,
] = useLocalState(context, 'searchText', '');
// Search for peeps
const SelectMembers = (people, searchText = '') => {
const MemberSearch = createSearch(searchText, member => member.Name);
return flow([
// Null camera filter
filter(member => member?.Name),
// Optional search term
searchText && filter(MemberSearch),
// Slightly expensive, but way better than sorting in BYOND
sortBy(member => member.Name),
])(recordsList);
};
const formattedRecords = SelectMembers(recordsList, searchText);
return (
<Box>
<Input
fluid
mb={1}
placeholder="Search records..."
onInput={(e, value) => setSearchText(value)} />
{formattedRecords.map(r => (
<Box key={r}>
<Button
content={r.Name}
icon="user"
onClick={() => act('Records', { target: r.uid })}
/>
</Box>
))}
</Box>
);
};
const RecordView = (props, context) => {
const { act, data } = useBackend(context);
const {
records,
} = data;
const {
general,
medical,
} = records;
return (
<Box>
<Section level={2} title="General Data">
{general ? (
<LabeledList>
<LabeledList.Item label="Name">
{general.name}
</LabeledList.Item>
<LabeledList.Item label="Sex">
{general.sex}
</LabeledList.Item>
<LabeledList.Item label="Species">
{general.species}
</LabeledList.Item>
<LabeledList.Item label="Age">
{general.age}
</LabeledList.Item>
<LabeledList.Item label="Rank">
{general.rank}
</LabeledList.Item>
<LabeledList.Item label="Fingerprint">
{general.fingerprint}
</LabeledList.Item>
<LabeledList.Item label="Physical Status">
{general.p_stat}
</LabeledList.Item>
<LabeledList.Item label="Mental Status">
{general.m_stat}
</LabeledList.Item>
</LabeledList>
) : (
<Box color="red" bold>
General record lost!
</Box>
)}
</Section>
<Section level={2} title="Medical Data">
{medical ? (
<LabeledList>
<LabeledList.Item label="Blood Type">
{medical.blood_type}
</LabeledList.Item>
<LabeledList.Item label="Minor Disabilities">
{medical.mi_dis}
</LabeledList.Item>
<LabeledList.Item label="Details">
{medical.mi_dis_d}
</LabeledList.Item>
<LabeledList.Item label="Major Disabilities">
{medical.ma_dis}
</LabeledList.Item>
<LabeledList.Item label="Details">
{medical.ma_dis_d}
</LabeledList.Item>
<LabeledList.Item label="Allergies">
{medical.alg}
</LabeledList.Item>
<LabeledList.Item label="Details">
{medical.alg_d}
</LabeledList.Item>
<LabeledList.Item label="Current Diseases">
{medical.cdi}
</LabeledList.Item>
<LabeledList.Item label="Details">
{medical.cdi_d}
</LabeledList.Item>
<LabeledList.Item label="Important Notes">
{medical.notes}
</LabeledList.Item>
</LabeledList>
) : (
<Box color="red" bold>
Medical record lost!
</Box>
)}
</Section>
</Box>
);
};
@@ -0,0 +1,262 @@
import { filter } from 'common/collections';
import { useBackend, useLocalState } from "../../backend";
import { Box, Button, Icon, LabeledControls, LabeledList, Section } from "../../components";
export const pda_messenger = (props, context) => {
const { act, data } = useBackend(context);
const { active_convo } = data;
if (active_convo) {
return <ActiveConversation />;
}
return <MessengerList />;
};
const ActiveConversation = (props, context) => {
const { act, data } = useBackend(context);
const {
convo_name,
convo_job,
messages,
active_convo,
} = data;
const [
clipboardMode,
setClipboardMode,
] = useLocalState(context, 'clipboardMode', false);
let body = (
<Section
level={2}
title={"Conversation with " + convo_name + " (" + convo_job + ")"}
buttons={
<Button
icon="eye"
selected={clipboardMode}
tooltip="Enter Clipboard Mode"
tooltipPosition="bottom-left"
onClick={() => setClipboardMode(!clipboardMode)} />
}
height="450px"
stretchContents>
<Section style={{
"height": "97%",
"overflow-y": "auto",
}}>
{filter(im => im.target === active_convo)(messages).map((im, i) => (
<Box
textAlign={im.sent ? "right" : "left"}
position="relative"
mb={1}
key={i}>
<Icon
fontSize={2.5}
color={im.sent ? "#4d9121" : "#cd7a0d"}
position="absolute"
left={im.sent ? null : "0px"}
right={im.sent ? "0px" : null}
bottom="-4px"
style={{
"z-index": "0",
"transform": im.sent ? "scale(-1, 1)" : null,
}}
name="comment" />
<Box
inline
backgroundColor={im.sent ? "#4d9121" : "#cd7a0d"}
p={1}
maxWidth="100%"
position="relative"
textAlign={im.sent ? "left" : "right"}
style={{
"z-index": "1",
"border-radius": "10px",
"word-break": "normal",
}}>
{im.sent ? "You:" : "Them:"} {im.message}
</Box>
</Box>
))}
</Section>
<Button
mt={1}
icon="comment"
onClick={() => act("Message", { "target": active_convo })}
content="Reply" />
</Section>
);
if (clipboardMode) {
body = (
<Section
level={2}
title={"Conversation with " + convo_name + " (" + convo_job + ")"}
buttons={
<Button
icon="eye"
selected={clipboardMode}
tooltip="Exit Clipboard Mode"
tooltipPosition="bottom-left"
onClick={() => setClipboardMode(!clipboardMode)} />
}
height="450px"
stretchContents>
<Section style={{
"height": "97%",
"overflow-y": "auto",
}}>
{filter(im => im.target === active_convo)(messages).map((im, i) => (
<Box
key={i}
color={im.sent ? "#4d9121" : "#cd7a0d"}
style={{
"word-break": "normal",
}}>
{im.sent ? "You:" : "Them:"} <Box inline>{im.message}</Box>
</Box>
))}
</Section>
<Button
mt={1}
icon="comment"
onClick={() => act("Message", { "target": active_convo })}
content="Reply" />
</Section>
);
}
return (
<Box>
<LabeledList>
<LabeledList.Item label="Messenger Functions">
<Button
icon="trash"
color="bad"
onClick={() => act("Clear", { option: "Convo" })}>
Delete Conversations
</Button>
</LabeledList.Item>
</LabeledList>
{body}
</Box>
);
};
const MessengerList = (props, context) => {
const { act, data } = useBackend(context);
const {
convopdas,
pdas,
charges,
silent,
toff,
} = data;
return (
<Box>
<LabeledList>
<LabeledList.Item label="Messenger Functions">
<Button
selected={!silent}
icon={silent ? "volume-mute" : "volume-up"}
onClick={() => act("Toggle Ringer")}>
Ringer: {silent ? "Off" : "On"}
</Button>
<Button
color={toff ? "bad" : "green"}
icon="power-off"
onClick={() => act("Toggle Messenger")}>
Messenger: {toff ? "Off" : "On"}
</Button>
<Button
icon="bell"
onClick={() => act("Ringtone")}>
Set Ringtone
</Button>
<Button
icon="trash"
color="bad"
onClick={() => act("Clear", { option: "All" })}>
Delete All Conversations
</Button>
</LabeledList.Item>
</LabeledList>
{!toff && (
<Box mt={2}>
{!!charges && (
<LabeledList>
<LabeledList.Item label="Cartridge Special Function">
{charges} charges left.
</LabeledList.Item>
</LabeledList>
)}
{!convopdas.length && !pdas.length && (
<Box>
No current conversations
</Box>
) || (
<Box>
<PDAList title="Current Conversations"
pdas={convopdas}
msgAct="Select Conversation" />
<PDAList title="Other PDAs" pdas={pdas} msgAct="Message" />
</Box>
)}
</Box>
) || (
<Box color="bad">
Messenger Offline.
</Box>
)}
</Box>
);
};
const PDAList = (props, context) => {
const { act, data } = useBackend(context);
const {
pdas,
title,
msgAct,
} = props;
const {
charges,
plugins,
} = data;
if (!pdas || !pdas.length) {
return (
<Section level={2} title={title}>
No PDAs found.
</Section>
);
}
return (
<Section level={2} title={title}>
{pdas.map(pda => (
<Box key={pda.uid}>
<Button
icon="arrow-circle-down"
content={pda.Name}
onClick={() => act(msgAct, { target: pda.uid })} />
{!!charges && plugins.map(plugin => (
<Button
key={plugin.uid}
icon={plugin.icon}
content={plugin.name}
onClick={() => act("Messenger Plugin", {
plugin: plugin.uid,
target: pda.uid,
})} />
))}
</Box>
))}
</Section>
);
};

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