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 += "
| Cell | -Occupant | -Crimes | -Brigged By | -Time Brigged For | -Time Left | -Release | -
|---|---|---|---|---|---|---|
| {{: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')}} | -
| 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}} |
| - Connection Status: - | - {{if data.connected}} -- Connected - | -- {{:helper.link('Disconnect', 'sign-out', {'choice': 'Disconnect'})}} - | - {{else}} -- No Connection - | -- {{:helper.link('Connect', 'sign-in', {'choice': 'Reconnect'})}} - | - {{/if}} -
| - {{: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'})}} - | -
| Area | Equip. | Lighting | Environ. | Cell | Load |
|---|---|---|---|---|---|
| {{:value.Name}} | - {{:helper.string('{1} | ', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}} - {{:helper.string('{1} | ', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}} - {{:helper.string('{1} | ', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}} - {{:helper.string('{1}{2} | ', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}} -{{:value.Load}}W | -
| Area | Equip. | Lighting | Environ. | Cell | Load |
|---|---|---|---|---|---|
| {{:value.Name}} | - {{:helper.string('{1} | ', value.Equipment == "On" || value.Equipment == "AOn" ? '#4f7529' : '#8f1414', value.Equipment)}} - {{:helper.string('{1} | ', value.Lights == "On" || value.Lights == "AOn" ? '#4f7529' : '#8f1414', value.Lights)}} - {{:helper.string('{1} | ', value.Environment == "On" || value.Environment == "AOn" ? '#4f7529' : '#8f1414', value.Environment)}} - {{:helper.string('{1}{2} | ', value.CellStatus == "F" ? '#4f7529' : value.CellStatus == "C" ? '#cd6500' : '#8f1414', value.CellStatus == "M" ? 'No Cell' : value.CellPct + '%', value.CellStatus == "M" ? '' : ' (' + value.CellStatus + ')')}} -{{:value.Load}}W | -
- {{: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}}
- |
-