diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 295cdfce5cb..1d1a1372bc5 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -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. diff --git a/SpacemanDMM.toml b/SpacemanDMM.toml index 9b658dce0fa..81aff0d5576 100644 --- a/SpacemanDMM.toml +++ b/SpacemanDMM.toml @@ -4,3 +4,6 @@ dreamchecker = true [code_standards] disallow_relative_type_definitions = true disallow_relative_proc_definitions = true + +[dmdoc] +use_typepath_names = true diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm index 53040777467..3a0c58bffb3 100644 --- a/code/_globalvars/lists/misc.dm +++ b/code/_globalvars/lists/misc.dm @@ -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 diff --git a/code/datums/cache/powermonitor.dm b/code/datums/cache/powermonitor.dm index 606dd500eda..a11e9b76a41 100644 --- a/code/datums/cache/powermonitor.dm +++ b/code/datums/cache/powermonitor.dm @@ -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 diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index aafe126a0b4..e4268c16cd5 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -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) diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 36bd35462d6..389b21dd6d1 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -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. diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 723e862405d..60beb105dce 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -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) diff --git a/code/game/machinery/computer/brigcells.dm b/code/game/machinery/computer/brigcells.dm index a391bfa4021..b220ded29c5 100644 --- a/code/game/machinery/computer/brigcells.dm +++ b/code/game/machinery/computer/brigcells.dm @@ -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, "Access denied.") 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, "Access denied.") + 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 diff --git a/code/game/machinery/computer/power.dm b/code/game/machinery/computer/power.dm index bb38e59c800..a0bbedf2f73 100644 --- a/code/game/machinery/computer/power.dm +++ b/code/game/machinery/computer/power.dm @@ -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) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 1d6b572d9e5..a732348ac3c 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -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 diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index a4cacc19abd..b2f061e1d67 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -226,6 +226,7 @@ occupant = CELL_NONE crimes = CELL_NONE time = 0 + timetoset = 0 officer = CELL_NONE releasetime = 0 printed = 0 diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 4ed92910c5a..a86ea7d4a6b 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -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 diff --git a/code/game/mecha/equipment/tools/other_tools.dm b/code/game/mecha/equipment/tools/other_tools.dm index 61ba683ad18..8fdbf0880df 100644 --- a/code/game/mecha/equipment/tools/other_tools.dm +++ b/code/game/mecha/equipment/tools/other_tools.dm @@ -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("[src] is still recharging.") + 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 diff --git a/code/game/objects/items/control_wand.dm b/code/game/objects/items/control_wand.dm index 01033e6c123..185a00305de 100644 --- a/code/game/objects/items/control_wand.dm +++ b/code/game/objects/items/control_wand.dm @@ -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, "Now in mode: [mode].") /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, "[D] is now in [D.normalspeed ? "normal" : "fast"] mode.") else to_chat(user, "[src] does not have access to this door.") @@ -144,3 +151,4 @@ #undef WAND_OPEN #undef WAND_BOLT #undef WAND_EMERGENCY +#undef WAND_SPEED diff --git a/code/game/objects/items/devices/uplinks.dm b/code/game/objects/items/devices/uplinks.dm index 77e9eacc6a1..06f728ad748 100644 --- a/code/game/objects/items/devices/uplinks.dm +++ b/code/game/objects/items/devices/uplinks.dm @@ -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 = "[src.welcome]
" - dat += "Telecrystals left: [src.uses]
" - dat += "
" - dat += "Request item:
" - dat += "Each item costs a number of telecrystals as indicated by the number following its name.
" - - var/category_items = 1 - for(var/category in uplink_items) - if(category_items < 1) - dat += "We apologize, as you could not afford anything from this category.
" - dat += "
" - dat += "[category]
" - 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 += "[I.name] ([I.cost])" - if(I.hijack_only) - dat += " (HIJACK ONLY)" - dat += "
" - category_items++ - - dat += "Random Item (??)
" - dat += "
" - 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, "[I] refunded.") qdel(I) return + // If we are here, we didnt refund + to_chat(user, "[I] is not refundable.") // 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. diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index 9f6844c8b9e..8b302cd338a 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -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))) diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index fd2171335ef..675de65fb3e 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -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 diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm index 6ac5f8cded2..36d11b0f2a2 100644 --- a/code/modules/mob/living/silicon/silicon_defense.dm +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -58,6 +58,7 @@ if(INTENT_HELP) M.visible_message("[M] pets [src]!", \ "You pet [src]!") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) if("grab") grabbedby(M) else diff --git a/code/modules/mob/living/silicon/subsystems.dm b/code/modules/mob/living/silicon/subsystems.dm index 65a92d07008..fc3b775f229 100644 --- a/code/modules/mob/living/silicon/subsystems.dm +++ b/code/modules/mob/living/silicon/subsystems.dm @@ -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) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index 77f8cc40da9..d51a58662ef 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -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) diff --git a/code/modules/nano/modules/power_monitor.dm b/code/modules/nano/modules/power_monitor.dm deleted file mode 100644 index 66948243035..00000000000 --- a/code/modules/nano/modules/power_monitor.dm +++ /dev/null @@ -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 diff --git a/code/modules/pda/PDA.dm b/code/modules/pda/PDA.dm index f17666af19d..69b01b53f39 100755 --- a/code/modules/pda/PDA.dm +++ b/code/modules/pda/PDA.dm @@ -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, "You press the reset button on \the [src].") + SStgui.update_uis(src) else to_chat(usr, "You cannot do this while restrained.") @@ -327,6 +177,7 @@ GLOBAL_LIST_EMPTY(PDAs) var/mob/M = loc M.put_in_hands(id) to_chat(user, "You remove the ID from the [name].") + 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, "You insert [cartridge] into [src].") + 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, "Card scanned.") + 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, "You put the ID into \the [src]'s slot.
You can remove it with ALT click.
") 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, "You slot \the [C] into [src].") + SStgui.update_uis(src) else if(istype(C, /obj/item/pen)) var/obj/item/pen/O = locate() in src if(O) diff --git a/code/modules/pda/app.dm b/code/modules/pda/app.dm index 655bb891de5..82047a073c4 100644 --- a/code/modules/pda/app.dm +++ b/code/modules/pda/app.dm @@ -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 diff --git a/code/modules/pda/cart.dm b/code/modules/pda/cart.dm index 6339f5375d7..d4845926786 100644 --- a/code/modules/pda/cart.dm +++ b/code/modules/pda/cart.dm @@ -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) diff --git a/code/modules/pda/cart_apps.dm b/code/modules/pda/cart_apps.dm index d47f4184daf..59168c58871 100644 --- a/code/modules/pda/cart_apps.dm +++ b/code/modules/pda/cart_apps.dm @@ -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) diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm index 41f9f994420..1b4be7e8274 100644 --- a/code/modules/pda/core_apps.dm +++ b/code/modules/pda/core_apps.dm @@ -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", "
") 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 diff --git a/code/modules/pda/messenger.dm b/code/modules/pda/messenger.dm index 5ccef4dee41..4f17cbf041e 100644 --- a/code/modules/pda/messenger.dm +++ b/code/modules/pda/messenger.dm @@ -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("PDA Message - [U.key] - [pda.owner] -> [P.owner]: [t]", "pda") // Show it to ghosts @@ -190,13 +181,13 @@ var/ghost_message = "[pda.owner] ([ghost_follow_link(pda, ghost=M)]) PDA Message --> [P.owner] ([ghost_follow_link(P, ghost=M)]): [t]" 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("Message from [pda.owner] ([pda.ownjob]), \"[t]\" (Reply)") + SStgui.update_uis(src) + PM.notify("Message from [pda.owner] ([pda.ownjob]), \"[t]\" (Reply)") log_pda("(PDA: [src.name]) sent \"[t]\" to [P.name]", usr) else to_chat(U, "ERROR: Messaging server is not responding.") @@ -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"] diff --git a/code/modules/pda/mob_hunt_game_app.dm b/code/modules/pda/mob_hunt_game_app.dm index c72aa6d0d41..256ec0f91d9 100644 --- a/code/modules/pda/mob_hunt_game_app.dm +++ b/code/modules/pda/mob_hunt_game_app.dm @@ -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") diff --git a/code/modules/pda/pda_tgui.dm b/code/modules/pda/pda_tgui.dm new file mode 100644 index 00000000000..5f4a5699c7a --- /dev/null +++ b/code/modules/pda/pda_tgui.dm @@ -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) diff --git a/code/modules/pda/radio.dm b/code/modules/pda/radio.dm index cd549759c1c..48d35e9d033 100644 --- a/code/modules/pda/radio.dm +++ b/code/modules/pda/radio.dm @@ -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 diff --git a/code/modules/pda/utilities.dm b/code/modules/pda/utilities.dm index c527e1dd12d..81a2271db04 100644 --- a/code/modules/pda/utilities.dm +++ b/code/modules/pda/utilities.dm @@ -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 + "
" // 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 += "

" - // Store the scanned document to the notes - notes.note += "Scanned Document. Edit to restore previous notes/delete scan.
----------
" + formatted_scan + "
" - // 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, "Paper scanned and OCRed to notekeeper.")//concept of scanning paper copyright brainoblivion 2009 - - else - to_chat(user, "Error scanning [A].") diff --git a/code/modules/reagents/chemistry/reagents/drinks.dm b/code/modules/reagents/chemistry/reagents/drinks.dm index 4bd061c14b4..53187fc8c35 100644 --- a/code/modules/reagents/chemistry/reagents/drinks.dm +++ b/code/modules/reagents/chemistry/reagents/drinks.dm @@ -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" diff --git a/code/modules/reagents/chemistry/recipes/drinks.dm b/code/modules/reagents/chemistry/recipes/drinks.dm index 1f15c95bbf2..ab326d9d9ca 100644 --- a/code/modules/reagents/chemistry/recipes/drinks.dm +++ b/code/modules/reagents/chemistry/recipes/drinks.dm @@ -868,3 +868,11 @@ required_reagents = list("hooch" = 1, "absinthe" = 1, "manlydorf" = 1, "syndicatebomb" = 1) result_amount = 4 mix_message = "The mixture turns to a sickening froth." + +/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' diff --git a/code/modules/tgui/modules/power_monitor.dm b/code/modules/tgui/modules/power_monitor.dm new file mode 100644 index 00000000000..71e12836d78 --- /dev/null +++ b/code/modules/tgui/modules/power_monitor.dm @@ -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 diff --git a/icons/pda_icons/pda_alert.png b/icons/pda_icons/pda_alert.png deleted file mode 100644 index ed35e47800f..00000000000 Binary files a/icons/pda_icons/pda_alert.png and /dev/null differ diff --git a/icons/pda_icons/pda_atmos.png b/icons/pda_icons/pda_atmos.png deleted file mode 100644 index 89a55a0a6cb..00000000000 Binary files a/icons/pda_icons/pda_atmos.png and /dev/null differ diff --git a/icons/pda_icons/pda_back.png b/icons/pda_icons/pda_back.png deleted file mode 100644 index 4708824853f..00000000000 Binary files a/icons/pda_icons/pda_back.png and /dev/null differ diff --git a/icons/pda_icons/pda_bell.png b/icons/pda_icons/pda_bell.png deleted file mode 100644 index 1e989c27473..00000000000 Binary files a/icons/pda_icons/pda_bell.png and /dev/null differ diff --git a/icons/pda_icons/pda_blank.png b/icons/pda_icons/pda_blank.png deleted file mode 100644 index 665861d3c74..00000000000 Binary files a/icons/pda_icons/pda_blank.png and /dev/null differ diff --git a/icons/pda_icons/pda_boom.png b/icons/pda_icons/pda_boom.png deleted file mode 100644 index 70e473c3c4c..00000000000 Binary files a/icons/pda_icons/pda_boom.png and /dev/null differ diff --git a/icons/pda_icons/pda_bucket.png b/icons/pda_icons/pda_bucket.png deleted file mode 100644 index ee030e3a37d..00000000000 Binary files a/icons/pda_icons/pda_bucket.png and /dev/null differ diff --git a/icons/pda_icons/pda_chatroom.png b/icons/pda_icons/pda_chatroom.png deleted file mode 100644 index a00221c4e0d..00000000000 Binary files a/icons/pda_icons/pda_chatroom.png and /dev/null differ diff --git a/icons/pda_icons/pda_clock.PNG b/icons/pda_icons/pda_clock.PNG deleted file mode 100644 index 9abad6c0f3c..00000000000 Binary files a/icons/pda_icons/pda_clock.PNG and /dev/null differ diff --git a/icons/pda_icons/pda_crate.png b/icons/pda_icons/pda_crate.png deleted file mode 100644 index e1e076e2790..00000000000 Binary files a/icons/pda_icons/pda_crate.png and /dev/null differ diff --git a/icons/pda_icons/pda_cuffs.png b/icons/pda_icons/pda_cuffs.png deleted file mode 100644 index 71958c8abc4..00000000000 Binary files a/icons/pda_icons/pda_cuffs.png and /dev/null differ diff --git a/icons/pda_icons/pda_egg.png b/icons/pda_icons/pda_egg.png deleted file mode 100644 index b72bfd97375..00000000000 Binary files a/icons/pda_icons/pda_egg.png and /dev/null differ diff --git a/icons/pda_icons/pda_eject.png b/icons/pda_icons/pda_eject.png deleted file mode 100644 index 4168be03f6a..00000000000 Binary files a/icons/pda_icons/pda_eject.png and /dev/null differ diff --git a/icons/pda_icons/pda_exit.png b/icons/pda_icons/pda_exit.png deleted file mode 100644 index cd983a4a9ab..00000000000 Binary files a/icons/pda_icons/pda_exit.png and /dev/null differ diff --git a/icons/pda_icons/pda_flashlight.png b/icons/pda_icons/pda_flashlight.png deleted file mode 100644 index 3476727930b..00000000000 Binary files a/icons/pda_icons/pda_flashlight.png and /dev/null differ diff --git a/icons/pda_icons/pda_game.png b/icons/pda_icons/pda_game.png deleted file mode 100644 index 3c0ddb8eb0d..00000000000 Binary files a/icons/pda_icons/pda_game.png and /dev/null differ diff --git a/icons/pda_icons/pda_honk.png b/icons/pda_icons/pda_honk.png deleted file mode 100644 index 55632bf40bc..00000000000 Binary files a/icons/pda_icons/pda_honk.png and /dev/null differ diff --git a/icons/pda_icons/pda_locked.PNG b/icons/pda_icons/pda_locked.PNG deleted file mode 100644 index 79fe5829162..00000000000 Binary files a/icons/pda_icons/pda_locked.PNG and /dev/null differ diff --git a/icons/pda_icons/pda_mail.png b/icons/pda_icons/pda_mail.png deleted file mode 100644 index 6bfb1e8cd7b..00000000000 Binary files a/icons/pda_icons/pda_mail.png and /dev/null differ diff --git a/icons/pda_icons/pda_medical.png b/icons/pda_icons/pda_medical.png deleted file mode 100644 index 448063ecf52..00000000000 Binary files a/icons/pda_icons/pda_medical.png and /dev/null differ diff --git a/icons/pda_icons/pda_menu.png b/icons/pda_icons/pda_menu.png deleted file mode 100644 index abd6ccb2257..00000000000 Binary files a/icons/pda_icons/pda_menu.png and /dev/null differ diff --git a/icons/pda_icons/pda_mule.png b/icons/pda_icons/pda_mule.png deleted file mode 100644 index b8c1b636f5e..00000000000 Binary files a/icons/pda_icons/pda_mule.png and /dev/null differ diff --git a/icons/pda_icons/pda_notes.png b/icons/pda_icons/pda_notes.png deleted file mode 100644 index eb076d3ca33..00000000000 Binary files a/icons/pda_icons/pda_notes.png and /dev/null differ diff --git a/icons/pda_icons/pda_power.png b/icons/pda_icons/pda_power.png deleted file mode 100644 index 04175e7c835..00000000000 Binary files a/icons/pda_icons/pda_power.png and /dev/null differ diff --git a/icons/pda_icons/pda_rdoor.png b/icons/pda_icons/pda_rdoor.png deleted file mode 100644 index 6eab5a8817d..00000000000 Binary files a/icons/pda_icons/pda_rdoor.png and /dev/null differ diff --git a/icons/pda_icons/pda_reagent.png b/icons/pda_icons/pda_reagent.png deleted file mode 100644 index b900af5ae66..00000000000 Binary files a/icons/pda_icons/pda_reagent.png and /dev/null differ diff --git a/icons/pda_icons/pda_refresh.png b/icons/pda_icons/pda_refresh.png deleted file mode 100644 index 08439c6bca3..00000000000 Binary files a/icons/pda_icons/pda_refresh.png and /dev/null differ diff --git a/icons/pda_icons/pda_scanner.png b/icons/pda_icons/pda_scanner.png deleted file mode 100644 index eabdc511cde..00000000000 Binary files a/icons/pda_icons/pda_scanner.png and /dev/null differ diff --git a/icons/pda_icons/pda_signaler.png b/icons/pda_icons/pda_signaler.png deleted file mode 100644 index f71398f70d2..00000000000 Binary files a/icons/pda_icons/pda_signaler.png and /dev/null differ diff --git a/icons/pda_icons/pda_status.png b/icons/pda_icons/pda_status.png deleted file mode 100644 index fe955e66a61..00000000000 Binary files a/icons/pda_icons/pda_status.png and /dev/null differ diff --git a/nano/templates/brig_cells.tmpl b/nano/templates/brig_cells.tmpl deleted file mode 100644 index 652c8926378..00000000000 --- a/nano/templates/brig_cells.tmpl +++ /dev/null @@ -1,34 +0,0 @@ - -
- - - - - - - - - - - - - - - {{for data.cells}} - - - - - - - - - - {{/for}} - -
CellOccupantCrimesBrigged ByTime Brigged ForTime LeftRelease
{{:value.cell_id}}{{:value.occupant}}{{:value.crimes}}{{:value.brigged_by}}{{:value.time_set}}{{:value.time_left}}{{:helper.link('Release', null, {'release' : value.ref}, null, 'infoButton')}}
-
-
\ No newline at end of file diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl deleted file mode 100644 index fa8776c71ad..00000000000 --- a/nano/templates/pda.tmpl +++ /dev/null @@ -1,156 +0,0 @@ - -{{if data.useRetro}} - - - -{{/if}} -{{if data.owner}} -
-
- {{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')}} -
-
- {{:data.stationTime}} -
-
- - {{if data.app}} -

 {{:data.app.name}}

-
-
 
- {{/if}} - -
- {{: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')}} -
-{{else}} -
-






No Owner information found, please swipe ID -
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_atmos_scan.tmpl b/nano/templates/pda_atmos_scan.tmpl deleted file mode 100644 index 57f0a356a16..00000000000 --- a/nano/templates/pda_atmos_scan.tmpl +++ /dev/null @@ -1,60 +0,0 @@ - -
-
- {{if data.aircontents.reading == 1}} -
- Pressure: -
-
- {{:helper.string('{1} kPa', 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))}} -
-
- Temperature: -
-
- {{:helper.string('{1} °C', 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))}} -
-
-
- Oxygen: -
-
- {{:helper.string('{1}%', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good', helper.smoothRound(data.aircontents.oxygen, 1))}} -
-
- Nitrogen: -
-
- {{:helper.string('{1}%', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good', helper.smoothRound(data.aircontents.nitrogen, 1))}} -
-
- Carbon Dioxide: -
-
- {{:helper.string('{1}%', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good', helper.smoothRound(data.aircontents.carbon_dioxide, 1))}} -
-
- Plasma: -
-
- {{:helper.string('{1}%', data.aircontents.plasma > 0 ? 'bad' : 'good', helper.smoothRound(data.aircontents.plasma, 1))}} - -
- {{if data.aircontents.other > 0}} -
- Unknown: -
-
- {{:helper.smoothRound(data.aircontents.other, 1)}}% -
- {{/if}} - {{else}} -
- Unable to get air reading -
- {{/if}} -
-
\ No newline at end of file diff --git a/nano/templates/pda_janitor.tmpl b/nano/templates/pda_janitor.tmpl deleted file mode 100644 index 864692d8a04..00000000000 --- a/nano/templates/pda_janitor.tmpl +++ /dev/null @@ -1,66 +0,0 @@ -
-
- Current Location: - {{if data.janitor.user_loc.x == 0}} - Unknown - {{else}} - {{:data.janitor.user_loc.x}} / {{:data.janitor.user_loc.y}} - {{/if}} -
-
- {{if data.janitor.mops}} - Mop Locations: - - {{else}} - Unable to locate Mops - {{/if}} -
-
- {{if data.janitor.buckets}} - Mop Bucket Locations: - - {{else}} - Unable to locate Mop Buckets - {{/if}} -
-
- {{if data.janitor.cleanbots}} - Cleanbot Locations: - - {{else}} - Unable to locate Cleanbots - {{/if}} -
-
- {{if data.janitor.carts}} - Janitorial Cart Locations: - - {{else}} - Unable to locate Janitorial Carts - {{/if}} -
-
diff --git a/nano/templates/pda_main_menu.tmpl b/nano/templates/pda_main_menu.tmpl deleted file mode 100644 index 692cdb7039d..00000000000 --- a/nano/templates/pda_main_menu.tmpl +++ /dev/null @@ -1,76 +0,0 @@ - - - - -
-
- Owner: -
-
- {{:data.owner}}, {{:data.ownjob}} -
-
-
-
- ID: -
-
- {{:helper.link('Update PDA Info', 'refresh', {'choice' : "UpdateInfo"}, data.idInserted ? null : 'disabled', 'pdalink fixedLeftWide')}} -
-
- -
-

Functions

-
-{{for data.categories : cat : i}} - -{{/for}} - -{{if data.pai}} -
-
- PAI Utilities: -
-
- {{:helper.link('Configuration', 'gear', {'choice' : "pai", 'option' : "1"}, null, 'pdalink fixedLeft')}} - {{:helper.link('Eject pAI', 'eject', {'choice' : "pai", 'option' : "2"}, null, 'pdalink fixedLeft')}} -
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_manifest.tmpl b/nano/templates/pda_manifest.tmpl deleted file mode 100644 index ef9e91a088f..00000000000 --- a/nano/templates/pda_manifest.tmpl +++ /dev/null @@ -1,96 +0,0 @@ - -
-
- {{if data.manifest.heads}} - - {{for data.manifest["heads"]}} - {{if value.rank == "Captain"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sec}} - - {{for data.manifest["sec"]}} - {{if value.rank == "Head of Security"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.eng}} - - {{for data.manifest["eng"]}} - {{if value.rank == "Chief Engineer"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.med}} - - {{for data.manifest["med"]}} - {{if value.rank == "Chief Medical Officer"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sci}} - - {{for data.manifest["sci"]}} - {{if value.rank == "Research Director"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.ser}} - - {{for data.manifest["ser"]}} - {{if value.rank == "Head of Personnel"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.sup}} - - {{for data.manifest["sup"]}} - {{if value.rank == "Head of Personnel"}} - - {{else value.rank == "Quartermaster"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.civ}} - - {{for data.manifest["civ"]}} - {{if value.rank == "Head of Personnel"}} - - {{else}} - - {{/if}} - {{/for}} - {{/if}} - {{if data.manifest.misc}} - - {{for data.manifest["misc"]}} - - {{/for}} - {{/if}} -
Command
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Security
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Engineering
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Medical
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Science
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Service
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Supply
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Civilian
{{:value.name}}{{:value.rank}}{{:value.active}}
{{:value.name}}{{:value.rank}}{{:value.active}}
Misc
{{:value.name}}{{:value.rank}}{{:value.active}}
-
\ No newline at end of file diff --git a/nano/templates/pda_medical.tmpl b/nano/templates/pda_medical.tmpl deleted file mode 100644 index 777fb91f4b8..00000000000 --- a/nano/templates/pda_medical.tmpl +++ /dev/null @@ -1,54 +0,0 @@ -{{if !data.records}} -
-
Select a record:
-
- {{for data.recordsList}} -
- {{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} -
- {{empty}} -
- No records found. -
- {{/for}} -{{else}} -
-
-
- {{if data.records.general}} - Name: {{:data.records.general.name}}
- Sex: {{:data.records.general.sex}}
- Species: {{:data.records.general.species}}
- Age: {{:data.records.general.age}}
- Rank: {{:data.records.general.rank}}
- Fingerprint: {{:data.records.general.fingerprint}}
- Physical Status: {{:data.records.general.p_stat}}
- Mental Status: {{:data.records.general.m_stat}}

- {{else}} - - General Record Lost!

-
- {{/if}} - {{if data.records.medical}} -
-
Medical Data:
-
- Blood Type: {{:data.records.medical.b_type}}

- Minor Disabilities: {{:data.records.medical.mi_dis}}
- Details: {{:data.records.medical.mi_dis_d}}

- Major Disabilities: {{:data.records.medical.ma_dis}}
- Details: {{:data.records.medical.ma_dis_d}}

- Allergies: {{:data.records.medical.alg}}
- Details: {{:data.records.medical.alg_d}}

- Current Disease: {{:data.records.medical.cdi}}
- Details: {{:data.records.medical.alg_d}}

- Important Notes: {{:data.records.medical.notes}} - {{else}} - - Medical Record Lost! - - {{/if}} -
-
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_messenger.tmpl b/nano/templates/pda_messenger.tmpl deleted file mode 100644 index 4871934e4e9..00000000000 --- a/nano/templates/pda_messenger.tmpl +++ /dev/null @@ -1,90 +0,0 @@ - -{{if data.active_conversation}} -
-
- Messenger Functions: -
-
- {{: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')}} -
-
-
-
-

Conversation with: {{:data.convo_name}} ({{:data.convo_job}})

-
-
-
- {{for data.messages}} - {{if data.active_conversation == value.target}} - {{if value.sent==0}} - Them: {{:value.message}}
- {{else}} - You: {{:value.message}}
- {{/if}} - {{/if}} - {{/for}} -
-
-
- {{:helper.link('Reply', 'comment', {'choice' : "Message", 'target': data.active_conversation}, null, 'pdalink fixedLeftWidest')}} - -{{else}} -
-
- Messenger Functions: -
-
- {{: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')}} -
-
- {{if data.toff == 0}} -
- {{if data.charges}} -
- {{:data.charges}} charges left. -

-
- {{/if}} - - {{if !data.convopdas.length && !data.pdas.length}} - No other PDAS located - {{else}} -

Current Conversations

- {{for data.convopdas}} -
- {{: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}} -
- {{/for}} -

Other PDAs

- {{for data.pdas}} -
- {{: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}} -
- {{/for}} - {{/if}} - {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_mob_hunt.tmpl b/nano/templates/pda_mob_hunt.tmpl deleted file mode 100644 index dde4ab82a5c..00000000000 --- a/nano/templates/pda_mob_hunt.tmpl +++ /dev/null @@ -1,91 +0,0 @@ -
-
- - - - {{if data.connected}} - - - {{else}} - - - {{/if}} - -
- Connection Status: - - Connected - - {{:helper.link('Disconnect', 'sign-out', {'choice': 'Disconnect'})}} - - No Connection - - {{:helper.link('Connect', 'sign-in', {'choice': 'Reconnect'})}} -
-
-
-
-
My Collection:
-{{if data.no_collection}} -
-
- Your collection is empty! Go capture some Nano-Mobs! -
-
-
- Wild mobs captured: {{:data.wild_captures}} -{{else}} -
-
-
- {{if data.entry}} - {{if data.entry.nickname}} - Name: {{:data.entry.nickname}}
- {{/if}} - Species: {{:data.entry.real_name}}
- Level: {{:data.entry.level}}
- Primary Type: {{:data.entry.type1}}
- {{if data.entry.type2}} - Secondary Type: {{:data.entry.type2}}
- {{/if}} - {{if data.entry.sprite}} - - {{else}} - Mob Image Missing! - {{/if}} - {{else}} - - Mob Data Missing!

-
- {{/if}} -
-
-
-
- Wild mobs captured: {{:data.wild_captures}} -
- - - - - - - - -
- {{:helper.link('Previous Mob', 'arrow-left', {'choice': 'Prev'})}} - - {{:helper.link('Transfer Mob', 'exchange', {'choice': 'Transfer'})}} - - {{:helper.link('Rename Mob', 'pencil', {'choice': 'Rename'})}} - - {{:helper.link('Release Mob', 'tree', {'choice': 'Release'})}} - - {{:helper.link('Next Mob', 'arrow-right', {'choice': 'Next'})}} -
- {{if data.entry.is_hacked}} -
- {{:helper.link('Set Trap', 'bolt', {'choice': 'Set_Trap'})}} - {{/if}} -
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_mule.tmpl b/nano/templates/pda_mule.tmpl deleted file mode 100644 index 369d0830aa5..00000000000 --- a/nano/templates/pda_mule.tmpl +++ /dev/null @@ -1,118 +0,0 @@ -{{if !data.mulebot.active}} - {{if data.mulebot.count == 0}} -

No bots found.

- {{else}} -
- Select a MULE: -
-
- {{for data.mulebot.bots}} -
- {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}}) -
- {{/for}} - {{/if}} -
- {{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}} -{{else}} -

{{:data.mulebot.active}}

- {{if data.mulebot.botstatus.mode == -1}} -

Waiting for response...

- {{else}} -

Status:

-
-
- Location: -
-
- {{:data.mulebot.botstatus.loca}} -
-
-
-
- Mode: -
-
- - {{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}} - -
-
-
-
- Current Load: -
-
- - {{: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')}} - -
-
-
-
- Power: -
-
- - {{:data.mulebot.botstatus.powr}}% - -
-
-
-
- Destination: -
-
- {{: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')}} -
-
-
-
- Home: -
-
- {{if data.mulebot.botstatus.home == null}} None {{else}} {{:data.mulebot.botstatus.home}} {{/if}} -
-
-
-
- Auto Return: -
-
- {{:helper.link(data.mulebot.botstatus.retn == 1 ? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.retn==1 ? "retoff" : "reton")}, null, 'pdalink fixedLeftWidest')}} -
-
-
-
- Auto Pickup: -
-
- {{:helper.link(data.mulebot.botstatus.pick==1? 'ON' : 'OFF', 'gear', {'radiomenu' : "1", 'op' : (data.mulebot.botstatus.pick==1 ? "pickoff" : "pickon")}, null, 'pdalink fixedLeftWidest')}} -
-
-
-
- Functions: -
-
- {{: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')}} -
-
- {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_notekeeper.tmpl b/nano/templates/pda_notekeeper.tmpl deleted file mode 100644 index 53db3be6438..00000000000 --- a/nano/templates/pda_notekeeper.tmpl +++ /dev/null @@ -1,21 +0,0 @@ - -
-
- Notes: -
-
-
-
-
- {{:data.note}} -
-
-
-
-
- {{:helper.link('Edit Notes', 'pencil-square-o', {'choice': "Edit"}, null, 'pdalink')}} -
-
\ No newline at end of file diff --git a/nano/templates/pda_power.tmpl b/nano/templates/pda_power.tmpl deleted file mode 100644 index 7ba04188b71..00000000000 --- a/nano/templates/pda_power.tmpl +++ /dev/null @@ -1,49 +0,0 @@ -{{if !data.records.powerconnected}} -
-
Select a power monitor:
-
- {{for data.records.powermonitors}} -
- {{:helper.link(value.Name, 'exclamation-circle', {'choice' : "Power Select", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} -
- {{/for}} -{{else}} -
-
- Total Power: -
-
- {{:data.records.poweravail}} W -
-
-
-
- Total Load: -
-
- {{:data.records.powerload}} W -
-
-
-
- Total Demand: -
-
- {{:data.records.powerdemand}} W -
-
-
- - - {{for data.records.apcs}} - - {{:helper.string('', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}} - {{:helper.string('', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}} - {{:helper.string('', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}} - {{:helper.string('', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}} - - - {{/for}} -
AreaEquip.LightingEnviron.CellLoad
{{:value.Name}}{1}{1}{1}{1}{2}{{:value.Load}}W
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_secbot.tmpl b/nano/templates/pda_secbot.tmpl deleted file mode 100644 index 6ff8c98e147..00000000000 --- a/nano/templates/pda_secbot.tmpl +++ /dev/null @@ -1,59 +0,0 @@ -{{if !data.beepsky.active}} - {{if data.beepsky.count == 0}} -

No bots found.

- {{else}} -
- Select a bot: -
-
- {{for data.beepsky.bots}} -
- {{:helper.link(value.Name, 'gear', {'radiomenu' : "1", 'op' : "control",'bot' : value.ref}, null, 'pdalink fixedLeftWidest')}} (Location: {{:value.Location}}) -
- {{/for}} - {{/if}} -
- {{:helper.link('Scan for Bots','rss', {'radiomenu' : "1", 'op' : "scanbots"}, null, 'pdalink fixedLeftWidest')}} -{{else}} -

{{:data.beepsky.active}}

- {{if data.beepsky.botstatus.mode == -1}} -

Waiting for response...

- {{else}} -

Status:

-
-
- Location: -
-
- {{:data.beepsky.botstatus.loca}} -
-
-
-
- Mode: -
-
- - {{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}} - -
-
-
- {{: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')}} -
- {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_security.tmpl b/nano/templates/pda_security.tmpl deleted file mode 100644 index 53d40185e05..00000000000 --- a/nano/templates/pda_security.tmpl +++ /dev/null @@ -1,50 +0,0 @@ -{{if !data.records}} -
-
Select a record:
-
- {{for data.recordsList}} -
- {{:helper.link(value.Name, 'user', {'choice' : "Records", 'target' : value.ref}, null, 'pdalink fixedLeftWidest')}} -
- {{empty}} -
- No records found. -
- {{/for}} -{{else}} -
-
-
- {{if data.records.general}} - Name: {{:data.records.general.name}}
- Sex: {{:data.records.general.sex}}
- Species: {{:data.records.general.species}}
- Age: {{:data.records.general.age}}
- Rank: {{:data.records.general.rank}}
- Fingerprint: {{:data.records.general.fingerprint}}
- Physical Status: {{:data.records.general.p_stat}}
- Mental Status: {{:data.records.general.m_stat}}

- {{else}} - - General Record Lost!

-
- {{/if}} - {{if data.records.security}} -
-
Security Data:
-
- Criminal Status: {{:data.records.security.criminal}}

- Minor Crimes: {{:data.records.security.mi_crim}}
- Details: {{:data.records.security.mi_crim_d}}

- Major Crimes: {{:data.records.security.ma_crim}}
- Details: {{:data.records.security.ma_crim_d}}

- Important Notes: {{:data.records.security.notes}} - {{else}} - - Security Record Lost!

-
- {{/if}} -
-
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/pda_signaller.tmpl b/nano/templates/pda_signaller.tmpl deleted file mode 100644 index 2b5f148b025..00000000000 --- a/nano/templates/pda_signaller.tmpl +++ /dev/null @@ -1,38 +0,0 @@ - -
-
- Frequency: -
-
- {{:data.signal_freq}} -
-   - {{: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)}} -
-
-
-
-
-
- Code: -
-
- - {{:data.signal_code}}
-
- {{: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)}} -
-
-
- {{:helper.link('Send Signal', 'exclamation-circle', {'choice' : "Send Signal"}, null, null)}} -
\ No newline at end of file diff --git a/nano/templates/pda_status_display.tmpl b/nano/templates/pda_status_display.tmpl deleted file mode 100644 index 8b153ad0ffd..00000000000 --- a/nano/templates/pda_status_display.tmpl +++ /dev/null @@ -1,44 +0,0 @@ - -
-
- Code: -
-
- {{: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')}} -
-
-
-
-
- Message line 1 -
-
- {{:helper.link(data.records.message1 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg1"}, null, 'pdalink fixedLeftWide')}} -
-
-
-
- Message line 2 -
-
- {{:helper.link(data.records.message2 + ' (set)', 'pencil', {'choice' : "Status", 'statdisp' : "setmsg2"}, null, 'pdalink fixedLeftWide')}} -
-
- -
-
-
- ALERT!: -
-
- {{: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')}} -
-
\ No newline at end of file diff --git a/nano/templates/pda_supply.tmpl b/nano/templates/pda_supply.tmpl deleted file mode 100644 index 810fc193769..00000000000 --- a/nano/templates/pda_supply.tmpl +++ /dev/null @@ -1,39 +0,0 @@ -
-
- Location: -
-
- - {{if data.supply.shuttle_moving}} - Moving to {{:data.supply.shuttle_loc}} - {{else}} - Shuttle at {{:data.supply.shuttle_loc}} - {{/if}} -
- {{:data.supply.shuttle_time}} -
-
-
-
-
-
- Current Approved Orders
- {{if data.supply.approved_count == 0}} - No current approved orders

- {{else}} - {{for data.supply.approved}} - #{{:value.Number}} - {{:value.Name}} approved by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
- {{/for}} - {{/if}} -

- Current Requested Orders
- {{if data.supply.requests_count == 0}} - No current requested orders

- {{else}} - {{for data.supply.requests}} - #{{:value.Number}} - {{:value.Name}} requested by {{:value.OrderedBy}}
{{if value.Comment != ""}} {{:value.Comment}}
{{/if}}
- {{/for}} - {{/if}} -
-
-
\ No newline at end of file diff --git a/nano/templates/power_monitor.tmpl b/nano/templates/power_monitor.tmpl deleted file mode 100644 index c4bb8072373..00000000000 --- a/nano/templates/power_monitor.tmpl +++ /dev/null @@ -1,67 +0,0 @@ - -{{if !data.powermonitor && data.select_monitor}} -

Station Power Monitors

-
- Select a power monitor: -
- {{for data.powermonitors}} -
- {{:helper.link(value.Name, 'gear', { 'selectmonitor' : value.ref }, null, null)}} -
- {{empty}} -

Network Error

- No power monitors found. - {{/for}} -{{/if}} -{{if data.powermonitor}} - {{if data.select_monitor}} - {{:helper.link('Return', 'gear', { 'return' : 1 }, null, null)}} - {{/if}} -

Powernet Status

-
-
- Total Power: -
-
- {{:helper.smoothRound(data.poweravail)}} W -
-
-
-
- Total Load: -
-
- {{:helper.smoothRound(data.powerload)}} W -
-
-
-
- Total Demand: -
-
- {{:helper.smoothRound(data.powerdemand)}} W -
-
-
- - - {{for data.apcs}} - - {{:helper.string('', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}} - {{:helper.string('', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}} - {{:helper.string('', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}} - {{:helper.string('', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}} - - - {{/for}} -
AreaEquip.LightingEnviron.CellLoad
{{:value.Name}}{1}{1}{1}{1}{2}{{:value.Load}}W
-
-{{else}} - {{if !data.select_monitor}} -

Network Error

- Power monitor not connected to power network. - {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/uplink.tmpl b/nano/templates/uplink.tmpl deleted file mode 100644 index 3058bb10bbb..00000000000 --- a/nano/templates/uplink.tmpl +++ /dev/null @@ -1,101 +0,0 @@ - - -{{:helper.syndicateMode()}} - -

{{:data.welcome}}

-

Uplink Functions

-
-
- {{: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')}} -
-
- -{{if data.menu == 0}} -

Purchase Gear

- Each item costs a number of tele-crystals as indicated by the number following their name. -
-
- Tele-Crystals: -
-
- {{:data.crystals}} -
-
-
- - {{for data.nano_items}} - {{if value.Category == data.category_choice}} -
- {{:helper.link ( value.Category, 'arrow-circle-down', {'menu' : 0, 'category' : null}, null, 'white')}} -
- {{else}} -
- {{:helper.link ( value.Category, 'arrow-circle-right', {'menu' : 0, 'category' : value.Category}, null, 'white')}} -
- {{/if}} - {{if value.Category == data.category_choice}} -
- - {{for value.items :itemValue:itemIndex}} - - - - {{/for}} -
- {{:helper.link( itemValue.Name, 'gear', {'buy_item' : itemValue.obj_path, 'cost' : itemValue.Cost}, itemValue.Cost > data.crystals ? 'disabled' : null, null)}} - {{:itemValue.Cost}} {{if itemValue.hijack_only}}(HIJACK AGENTS ONLY){{/if}} -
-
- {{/if}} - {{/for}} -
-
- {{:helper.link('Buy Random Item' , 'gear', {'buy_item' : 'random'}, data.crystals <= 0 ? 'disabled' : null, 'white')}} -
-
- {{:helper.link('Refund item in active hand' , 'gear', {refund : 1}, null, 'white')}} -
- -{{else data.menu == 1}} -

Information Record List:

-
-
- Select a Record -
-
- {{for data.exploit_records}} -
- {{:helper.link(value.Name, 'gear', {'menu' : 11, 'id' : value.id}, null, null)}} -
- {{/for}} - -{{else data.menu == 11}} -

Information Record:

-
-
-
-
- {{if data.exploit_exists == 1}} - Name: {{:data.exploit.name}}
- Sex: {{:data.exploit.sex}}
- Species: {{:data.exploit.species}}
- Age: {{:data.exploit.age}}
- Rank: {{:data.exploit.rank}}
- Fingerprint: {{:data.exploit.fingerprint}}
- {{else}} - - No exploitative information acquired! -
-
-
- {{/if}} -
-
-
-{{/if}} diff --git a/paradise.dme b/paradise.dme index 23e566ede1a..61d25a2730f 100644 --- a/paradise.dme +++ b/paradise.dme @@ -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" diff --git a/sound/misc/berightback.ogg b/sound/misc/berightback.ogg new file mode 100644 index 00000000000..e9a6f6c182b Binary files /dev/null and b/sound/misc/berightback.ogg differ diff --git a/tgui/packages/tgui/components/Button.js b/tgui/packages/tgui/components/Button.js index e5172453432..06e31e5f54e 100644 --- a/tgui/packages/tgui/components/Button.js +++ b/tgui/packages/tgui/components/Button.js @@ -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 && ( - + )} {content} {children} diff --git a/tgui/packages/tgui/components/TimeDisplay.js b/tgui/packages/tgui/components/TimeDisplay.js new file mode 100644 index 00000000000..a50d8b0090c --- /dev/null +++ b/tgui/packages/tgui/components/TimeDisplay.js @@ -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) +); diff --git a/tgui/packages/tgui/components/index.js b/tgui/packages/tgui/components/index.js index 888c852ca5a..d51773c1943 100644 --- a/tgui/packages/tgui/components/index.js +++ b/tgui/packages/tgui/components/index.js @@ -26,3 +26,4 @@ export { Slider } from './Slider'; export { Table } from './Table'; export { Tabs } from './Tabs'; export { Tooltip } from './Tooltip'; +export { TimeDisplay } from './TimeDisplay'; diff --git a/tgui/packages/tgui/constants.js b/tgui/packages/tgui/constants.js index 024278e39b3..0f2fc9aa6b7 100644 --- a/tgui/packages/tgui/constants.js +++ b/tgui/packages/tgui/constants.js @@ -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: { diff --git a/tgui/packages/tgui/interfaces/BrigCells.js b/tgui/packages/tgui/interfaces/BrigCells.js new file mode 100644 index 00000000000..baa3b31d5ed --- /dev/null +++ b/tgui/packages/tgui/interfaces/BrigCells.js @@ -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 ( + + {cell_id} + {occupant} + {crimes} + {brigged_by} + + + + + + + ); +}; + +const BrigCellsTable = ({ cells }) => ( + + + Cell + Occupant + Crimes + Brigged By + Time Brigged For + Time Left + Release + + {cells.map(cell => ( + + ))} +
+); + + +export const BrigCells = (properties, context) => { + const { act, data } = useBackend(context); + const { cells } = data; + + return ( + + + +
+ +
+
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/PDA.js b/tgui/packages/tgui/interfaces/PDA.js new file mode 100644 index 00000000000..1e8759bfe42 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PDA.js @@ -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 ( + + +
+ No user data found. Please swipe an ID card. +
+
+
+ ); + } + + const App = GetApp(app.template); + + return ( + + + + +
+ + {app.name} + + } + p={1}> + +
+ + + +
+
+ ); +}; + +const PDAHeader = (props, context) => { + const { act, data } = useBackend(context); + const { + idInserted, + idLink, + stationTime, + cartridge_name, + } = data; + + return ( + + + {idInserted ? ( + + + + + {body} + + ); +}; + +const MessengerList = (props, context) => { + const { act, data } = useBackend(context); + + const { + convopdas, + pdas, + charges, + silent, + toff, + } = data; + + return ( + + + + + + + + + + {!toff && ( + + {!!charges && ( + + + {charges} charges left. + + + )} + {!convopdas.length && !pdas.length && ( + + No current conversations + + ) || ( + + + + + )} + + ) || ( + + Messenger Offline. + + )} + + ); +}; + +const PDAList = (props, context) => { + const { act, data } = useBackend(context); + + const { + pdas, + title, + msgAct, + } = props; + + const { + charges, + plugins, + } = data; + + if (!pdas || !pdas.length) { + return ( +
+ No PDAs found. +
+ ); + } + + return ( +
+ {pdas.map(pda => ( + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/pda/pda_mob_hunt.js b/tgui/packages/tgui/interfaces/pda/pda_mob_hunt.js new file mode 100644 index 00000000000..7f7956cd2fd --- /dev/null +++ b/tgui/packages/tgui/interfaces/pda/pda_mob_hunt.js @@ -0,0 +1,132 @@ +import { useBackend } from "../../backend"; +import { LabeledList, Box, Button, Section, Flex } from "../../components"; + +export const pda_mob_hunt = (props, context) => { + const { act, data } = useBackend(context); + + const { + connected, + wild_captures, + no_collection, + entry, + } = data; + + return ( + + + + {connected ? ( + + Connected +