Merge remote-tracking branch 'upstream/master' into rnd-tgui-rebase
@@ -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.
|
||||
|
||||
@@ -4,3 +4,6 @@ dreamchecker = true
|
||||
[code_standards]
|
||||
disallow_relative_type_definitions = true
|
||||
disallow_relative_proc_definitions = true
|
||||
|
||||
[dmdoc]
|
||||
use_typepath_names = true
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -226,6 +226,7 @@
|
||||
occupant = CELL_NONE
|
||||
crimes = CELL_NONE
|
||||
time = 0
|
||||
timetoset = 0
|
||||
officer = CELL_NONE
|
||||
releasetime = 0
|
||||
printed = 0
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)))
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"]
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
Before Width: | Height: | Size: 259 B |
|
Before Width: | Height: | Size: 224 B |
|
Before Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 226 B |
|
Before Width: | Height: | Size: 189 B |
|
Before Width: | Height: | Size: 241 B |
|
Before Width: | Height: | Size: 220 B |
|
Before Width: | Height: | Size: 223 B |
|
Before Width: | Height: | Size: 222 B |
|
Before Width: | Height: | Size: 234 B |
|
Before Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 242 B |
|
Before Width: | Height: | Size: 226 B |
|
Before Width: | Height: | Size: 241 B |
|
Before Width: | Height: | Size: 221 B |
|
Before Width: | Height: | Size: 262 B |
|
Before Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 215 B |
|
Before Width: | Height: | Size: 216 B |
|
Before Width: | Height: | Size: 203 B |
|
Before Width: | Height: | Size: 229 B |
|
Before Width: | Height: | Size: 230 B |
|
Before Width: | Height: | Size: 218 B |
|
Before Width: | Height: | Size: 215 B |
|
Before Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 219 B |
|
Before Width: | Height: | Size: 234 B |
|
Before Width: | Height: | Size: 241 B |
|
Before Width: | Height: | Size: 238 B |
|
Before Width: | Height: | Size: 230 B |
@@ -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>
|
||||
@@ -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> {{:data.app.name}}</h2>
|
||||
<div id="uiApp"></div>
|
||||
<div class="pdaFooterButton disabled"> </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}}
|
||||
@@ -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} °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>
|
||||
@@ -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>
|
||||
@@ -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}}
|
||||
@@ -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>
|
||||
@@ -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}}
|
||||
@@ -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: <span class="average">{{:data.convo_name}} ({{: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}}
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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>
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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>
|
||||
|
||||
{{:helper.link('-1', null, {'choice' : "Signal Frequency", 'sfreq' : "-10"}, null, null)}}
|
||||
{{:helper.link('-.2', null, {'choice' : "Signal Frequency", 'sfreq' : "-2"}, null, null)}}
|
||||
|
||||
{{:helper.link('+.2', null, {'choice' : "Signal Frequency", 'sfreq' : "2"}, null, null)}}
|
||||
{{: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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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}}
|
||||
@@ -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}}
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
@@ -26,3 +26,4 @@ export { Slider } from './Slider';
|
||||
export { Table } from './Table';
|
||||
export { Tabs } from './Tabs';
|
||||
export { Tooltip } from './Tooltip';
|
||||
export { TimeDisplay } from './TimeDisplay';
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
};
|
||||