diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 70f333da19f9..6dce107dd553 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -61,84 +61,37 @@ As mentioned before, you are expected to follow these specifications in order to 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 +### Avoid hacky code +Hacky code, such as adding specific checks, 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.) -(i.e. absolute pathing) - -DM will allow you nest almost any type keyword into a block, such as: - -```DM -datum - datum1 - var - varname1 = 1 - varname2 - static - varname3 - varname4 - proc - proc1() - code - proc2() - code - - datum2 - varname1 = 0 - proc - proc3() - code - proc2() - ..() - code -``` - -The use of this is not allowed in this project 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: - -```DM -/datum/datum1 - var/varname1 - var/varname2 - var/static/varname3 - var/static/varname4 - -/datum/datum1/proc/proc1() - code -/datum/datum1/proc/proc2() - code -/datum/datum1/datum2 - varname1 = 0 -/datum/datum1/datum2/proc/proc3() - code -/datum/datum1/datum2/proc2() - ..() - code -``` - -### No overriding type safety checks +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 use of the : operator to override type safety checks is not allowed. You must cast the variable to the proper type. +### Develop Secure Code -### Type paths must begin with a / +* Player input must always be escaped safely, we recommend you use stripped_input in all cases where you would use input. Essentially, just always treat input from players as inherently malicious and design with that use case in mind -eg: `/datum/thing`, not `datum/thing` +* Calls to the database must be escaped properly - use sanitizeSQL to escape text based database entries from players or admins, and isnum() for number based database entries from players or admins. -### Paths must be in snake case +* All calls to topics must be checked for correctness. Topic href calls can be easily faked by clients, so you should ensure that the call is valid for the state the item is in. Do not rely on the UI code to provide only valid topic calls, because it won't. -eg: `/obj/handheld_tool`, not `/obj/handheldTool` +* Information that players could use to metagame (that is, to identify round information and/or antagonist type via information that would not be available to them in character) should be kept as administrator only. -### Improve code in any files you touch +* It is recommended as well you do not expose information about the players - even something as simple as the number of people who have readied up at the start of the round can and has been used to try to identify the round type. -If there is legacy code in a file you are modifying it is also your responsibility to bring the old code up to standards. In general this means that if you are expanding upon a proc that has single letter var names, improperly formatted var names, etc you should be modernizing that proc. **This does not mean you have to refactor the entirety of the file, although doing so would be appreciated.** +* Where you have code that can cause large-scale modification and *FUN*, make sure you start it out locked behind one of the default admin roles - use common sense to determine which role fits the level of damage a function could do. -### Type paths must be lowercase +### User Interfaces -eg: `/datum/thing/blue`, not `datum/thing/BLUE` or `datum/thing/Blue` +* All new player-facing user interfaces must use TGUI, unless they are critical user interfaces. +* All critical user interfaces must be usable with HTML or the interface.dmf, with tgui being *optional* for this UI. + * Examples of critical user interfaces are the chat box, the observe button, the stat panel, and the chat input. +* Documentation for TGUI can be found at: + * [tgui/README.md](../tgui/README.md) + * [tgui/tutorial-and-examples.md](../tgui/docs/tutorial-and-examples.md) -### Datum type paths must began with "datum" +### Dont override type safety checks -In DM, this is optional, but omitting it makes finding definitions harder. +The use of the : operator to override type safety checks is not allowed. You must cast the variable to the proper type. ### Do not use text/string based type paths @@ -152,387 +105,482 @@ var/path_type = /obj/item/baseball_bat var/path_type = "/obj/item/baseball_bat" ``` -### Use var/name format when declaring variables +### Other Notes -While DM allows other ways of declaring variables, this one should be used for consistency. +* Code should be modular where possible; if you are working on a new addition, then strongly consider putting it in its own file unless it makes sense to put it with similar ones (i.e. a new tool would go in the "tools.dm" file) -### Tabs, not spaces +* Bloated code may be necessary to add a certain feature, which means there has to be a judgement over whether the feature is worth having or not. You can help make this decision easier by making sure your code is modular. -You must use tabs to indent your code, NOT SPACES. +* You are expected to help maintain the code that you add, meaning that if there is a problem then you are likely to be approached in order to fix any issues, runtimes, or bugs. -### No hacky code +* Do not divide when you can easily convert it to multiplication. (ie `4/2` should be done as `4*0.5`) -Hacky code, such as adding specific checks, 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.) +* Separating single lines into more readable blocks is not banned, however you should use it only where it makes new information more accessible, or aids maintainability. We do not have a column limit, and mass conversions will not be received well. -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. +* If you used regex to replace code during development of your code, post the regex in your PR for the benefit of future developers and downstream users. -### No duplicated code +* Changes to the `/config` tree must be made in a way that allows for updating server deployments while preserving previous behaviour. This is due to the fact that the config tree is to be considered owned by the user and not necessarily updated alongside the remainder of the code. The code to preserve previous behaviour may be removed at some point in the future given the OK by maintainers. +* The dlls section of tgs3.json is not designed for dlls that are purely `call()()`ed since those handles are closed between world reboots. Only put in dlls that may have to exist between world reboots. + +## Structural +### No duplicated code (Don't repeat yourself) Copying code from one place to another may be suitable for small, short-time projects, but /tg/station is a long-term project and highly discourages this. Instead you can use object orientation, or simply placing repeated code in a function, to obey this specification easily. -### Document your code - -Our codebase uses an interpreter called SpacemanDMM which includes the helpful ability to provide tooltips and inform you of documentation for various procs and vars. You are required to document any code you add so that it is readable and understandable to the maintainers of the codebase and also to other contributors. -eg: - -```dm -/// This proc causes the object to do a thing to the target mob -/obj/proc/do_thing(mob/target) -``` +### Prefer `Initialize()` over `New()` for atoms -eg2: +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. See here for details on `Initialize`: https://github.com/tgstation/tgstation/blob/34775d42a2db4e0f6734560baadcfcf5f5540910/code/game/atoms.dm#L166 +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 dependent on parent and children procs so unrelated random conversions of existing things can cause bugs that take months to figure out. -```dm -/* This is a special proc that causes the target mob to instantly gib itself - * If the argument recurse_contents is passed a truthy value all mobs inside the contents are also gibbed - */ -/mob/proc/gib_recurse(recurse_contents=FALSE) - if(!recurse_contents) - gib() - return - for(var/mob/other in contents) - other.gib() - gib() -``` +### Files -### Use self-explanatory var names +* Because runtime errors do not give the full path, try to avoid having files with the same name across folders. -When adding any new vars to a type, they must be self-explanatory and concise. -eg:`var/ticks_to_explosion` instead of `var/tte` +* File names should not be mixed case, or contain spaces or any character that would require escaping in a uri. -### Asyncronous proc calls +* Files and path accessed and referenced by code above simply being #included should be strictly lowercase to avoid issues on filesystems where case matters. -If there is something that must be done via an asyncronous call, it is required that it be done using the INVOKE_ASYNC macro. +### RegisterSignal() -### Signal Handlers +#### PROC_REF Macros +When referencing procs in RegisterSignal, Callback and other procs you should use PROC_REF, TYPE_PROC_REF and GLOBAL_PROC_REF macros. +They ensure compilation fails if the reffered to procs change names or get removed. +The macro to be used depends on how the proc you're in relates to the proc you want to use: -If you are registering signal handlers onto a type, the signal handler must have the SIGNAL_HANDLER definition and cannot sleep. If there is code in your signal handler that requires use of the sleep proc you must have your signal hander handle it via an invoke async call. +PROC_REF if the proc you want to use is defined on the current proc type or any of it's ancestor types. +Example: +``` +/mob/proc/funny() + to_chat(world,"knock knock") -### Data caching +/mob/subtype/proc/very_funny() + to_chat(world,"who's there?") -Types and procs that need to create or load large amounts of data that (should) never change needs to be cached into a static var so that in the event the proc needs to load the data again instead of recreating the data it has a cache that it can pull from, this reduces overhead and memory usage. +/mob/subtype/proc/do_something() + // Proc on our own type + RegisterSignal(x, COMSIG_OTHER_FAKE, PROC_REF(very_funny)) + // Proc on ancestor type, /mob is parent type of /mob/subtype + RegisterSignal(x, COMSIG_FAKE, PROC_REF(funny)) +``` -### Startup/Runtime tradeoffs with lists and the "hidden" init proc +TYPE_PROC_REF if the proc you want to use is defined on a different unrelated type +Example: +``` +/obj/thing/proc/funny() + to_chat(world,"knock knock") -First, read the comments in [this BYOND thread](http://www.byond.com/forum/?post=2086980&page=2#comment19776775), starting where the link takes you. +/mob/subtype/proc/do_something() + var/obj/thing/x = new() + // we're referring to /obj/thing proc inside /mob/subtype proc + RegisterSignal(x, COMSIG_FAKE, TYPE_PROC_REF(/obj/thing, funny)) +``` -There are two key points here: +GLOBAL_PROC_REF if the proc you want to use is a global proc. +Example: +``` +/proc/funny() + to_chat(world,"knock knock") -1. Defining a list in the variable's definition calls a hidden proc - init. If you have to define a list at startup, do so in New() (or preferably Initialize()) and avoid the overhead of a second call (Init() and then New()) +/mob/subtype/proc/do_something() + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(funny)), 100)) +``` -2. It also consumes more memory to the point where the list is actually required, even if the object in question may never use it! +Note that the same rules go for verbs too! We have VERB_REF() and TYPE_VERB_REF() as you need it in these same cases. GLOBAL_VERB_REF() isn't a thing however, as verbs are not global. -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. +#### Signal Handlers -### Prefer `Initialize()` over `New()` when possible +All procs that are registered to listen for signals using `RegisterSignal()` must contain at the start of the proc `SIGNAL_HANDLER` eg; +``` +/type/path/proc/signal_callback() + SIGNAL_HANDLER + // rest of the code +``` +This is to ensure that it is clear the proc handles signals and turns on a lint to ensure it does not sleep. -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. See here for details on `Initialize`: https://github.com/tgstation/tgstation/blob/master/code/game/atoms.dm#L49 -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. +Any sleeping behaviour that you need to perform inside a `SIGNAL_HANDLER` proc must be called asynchronously (e.g. with `INVOKE_ASYNC()`) or be redone to work asynchronously. -### No magic numbers or strings +#### `override` -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: +Each atom can only register a signal on the same object once, or else you will get a runtime. Overriding signals is usually a bug, but if you are confident that it is not, you can silence this runtime with `override = TRUE`. -```DM -/datum/proc/do_the_thing(thing_to_do) - switch(thing_to_do) - if(1) - (...) - if(2) - (...) +```dm +RegisterSignal(fork, COMSIG_FORK_STAB, PROC_REF(on_fork_stab), override = TRUE) ``` -There's no indication of what "1" and "2" mean! Instead, you'd do something like this: +If you decide to do this, you should make it clear with a comment explaining why it is necessary. This helps us to understand that the signal override is not a bug, and may help us to remove it in the future if the assumptions change. -```DM -#define DO_THE_THING_REALLY_HARD 1 -#define DO_THE_THING_EFFICIENTLY 2 -/datum/proc/do_the_thing(thing_to_do) - switch(thing_to_do) - if(DO_THE_THING_REALLY_HARD) - (...) - if(DO_THE_THING_EFFICIENTLY) - (...) -``` +### Enforcing parent calling -This is clearer and enhances readability of your code! Get used to doing it! +When adding new signals to root level procs, eg; +``` +/atom/proc/setDir(newdir) + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir) + dir = newdir +``` +The `SHOULD_CALL_PARENT(TRUE)` lint should be added to ensure that overrides/child procs call the parent chain and ensure the signal is sent. -### Control statements +### Avoid unnecessary type checks and obscuring nulls in lists -(if, while, for, etc) +Typecasting in `for` loops carries an implied `istype()` check that filters non-matching types, nulls included. The `as anything` key can be used to skip the check. -- All control statements must not contain code on the same line as the statement (`if (blah) return`) -- 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)`) +If we know the list is supposed to only contain the desired type then we want to skip the check not only for the small optimization it offers, but also to catch any null entries that may creep into the list. -### Use early return +Nulls in lists tend to point to improperly-handled references, making hard deletes hard to debug. Generating a runtime in those cases is more often than not positive. -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() - if (thing1) - if (!thing2) - if (thing3 == 30) - do stuff +var/list/bag_of_atoms = list(new /obj, new /mob, new /atom, new /atom/movable, new /atom/movable) +var/highest_alpha = 0 +for(var/atom/thing in bag_of_atoms) + if(thing.alpha <= highest_alpha) + continue + highest_alpha = thing.alpha ``` This is good: - ```DM -/datum/datum1/proc/proc1() - if (!thing1) - return - if (thing2) - return - if (thing3 != 30) - return - do stuff +var/list/bag_of_atoms = list(new /obj, new /mob, new /atom, new /atom/movable, new /atom/movable) +var/highest_alpha = 0 +for(var/atom/thing as anything in bag_of_atoms) + if(thing.alpha <= highest_alpha) + continue + highest_alpha = thing.alpha ``` -This prevents nesting levels from getting deeper then they need to be. - -### Develop Secure Code - -- Player input must always be escaped safely, we recommend you use stripped_input in all cases where you would use input. Essentially, just always treat input from players as inherently malicious and design with that use case in mind - -- Calls to the database must be escaped properly - use sanitizeSQL to escape text based database entries from players or admins, and isnum() for number based database entries from players or admins. - -- All calls to topics must be checked for correctness. Topic href calls can be easily faked by clients, so you should ensure that the call is valid for the state the item is in. Do not rely on the UI code to provide only valid topic calls, because it won't. +### All `process` procs need to make use of delta-time and be frame independent -- Information that players could use to metagame (that is, to identify round information and/or antagonist type via information that would not be available to them in character) should be kept as administrator only. +In a lot of our older code, `process()` is frame dependent. Here's some example mob code: -- It is recommended as well you do not expose information about the players - even something as simple as the number of people who have readied up at the start of the round can and has been used to try to identify the round type. - -- Where you have code that can cause large-scale modification and _FUN_, make sure you start it out locked behind one of the default admin roles - use common sense to determine which role fits the level of damage a function could do. - -### Files - -- Because runtime errors do not give the full path, try to avoid having files with the same name across folders. - -- File names should not be mixed case, or contain spaces or any character that would require escaping in a uri. - -- Files and path accessed and referenced by code above simply being #included should be strictly lowercase to avoid issues on filesystems where case matters. - -### SQL +```DM +/mob/testmob + var/health = 100 + var/health_loss = 4 //We want to lose 2 health per second, so 4 per SSmobs process -- Do not use the shorthand sql insert format (where no column names are specified) because it unnecessarily breaks all queries on minor column changes and prevents using these tables for tracking outside related info such as in a connected site/forum. +/mob/testmob/process(delta_time) //SSmobs runs once every 2 seconds + health -= health_loss +``` -- 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 +As the mobs subsystem runs once every 2 seconds, the mob now loses 4 health every process, or 2 health per second. This is called frame dependent programming. -- Any time the schema is changed the `schema_revision` table and `DB_MAJOR_VERSION` or `DB_MINOR_VERSION` defines must be incremented. +Why is this an issue? If someone decides to make it so the mobs subsystem processes once every second (2 times as fast), your effects in process() will also be two times as fast. Resulting in 4 health loss per second rather than 2. -- Queries must never specify the database, be it in code, or in text files in the repo. +How do we solve this? By using delta-time. Delta-time is the amount of seconds you would theoretically have between 2 process() calls. In the case of the mobs subsystem, this would be 2 (As there is 2 seconds between every call in `process()`). Here is a new example using delta-time: -- Primary keys are inherently immutable and you must never do anything to change the primary key of a row or entity. This includes preserving auto increment numbers of rows when copying data to a table in a conversion script. No amount of bitching about gaps in ids or out of order ids will save you from this policy. +```DM +/mob/testmob + var/health = 100 + var/health_loss = 2 //Health loss every second -### Mapping Standards +/mob/testmob/process(delta_time) //SSmobs runs once every 2 seconds + health -= health_loss * delta_time +``` -- TGM Format & Map Merge +In the above example, we made our health_loss variable a per second value rather than per process. In the actual process() proc we then make use of deltatime. Because SSmobs runs once every 2 seconds. Delta_time would have a value of 2. This means that by doing health_loss * delta_time, you end up with the correct amount of health_loss per process, but if for some reason the SSmobs subsystem gets changed to be faster or slower in a PR, your health_loss variable will work the same. - - All new maps submitted to the repo through a pull request must be in TGM format (unless there is a valid reason present to have it in the default BYOND format.) This is done using the [Map Merge](https://github.com/tgstation/tgstation/wiki/Map-Merger) utility included in the repo to convert the file to TGM format. - - Likewise, 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 becoming corrupted by future edits after running map merge. Resolving the corruption issue involves rebuilding the map's key dictionary; id est rewriting all the keys contained within the map by reconverting it from BYOND to TGM format - which creates very large differences that ultimately delay the PR process and is extremely likely to cause merge conflicts with other pull requests. +For example, if SSmobs is set to run once every 4 seconds, it would call process once every 4 seconds and multiply your health_loss var by 4 before subtracting it. Ensuring that your code is frame independent. -- Variable Editing (Var-edits) - - While var-editing an item within the editor is perfectly fine, it is preferred that when you are changing the base behavior of an item (how it functions) that you make a new subtype of that item within the code, especially if you plan to use the item in multiple locations on the same map, or across multiple maps. This makes it easier to make corrections as needed to all instances of the item at one time as opposed to having to find each instance of it and change them all individually. - - Subtypes only intended to be used on away mission or ruin maps should be contained within an .dm file with a name corresponding to that map within `code\modules\awaymissions` or `code\modules\ruins` respectively. This is so in the event that the map is removed, that subtype will be removed at the same time as well to minimize leftover/unused data within the repo. - - Please attempt to clean out any dirty variables that may be contained within items you alter through var-editing. For example, due to how DM functions, changing the `pixel_x` variable from 23 to 0 will leave a dirty record in the map's code of `pixel_x = 0`. Likewise this can happen when changing an item's icon to something else and then back. This can lead to some issues where an item's icon has changed within the code, but becomes broken on the map due to it still attempting to use the old entry. - - Areas should not be var-edited on a map to change it's name or attributes. All areas of a single type and it's altered instances are considered the same area within the code, and editing their variables on a map can lead to issues with powernets and event subsystems which are difficult to debug. +## Optimization +### Startup/Runtime tradeoffs with lists and the "hidden" init proc -### User Interfaces +First, read the comments in [this BYOND thread](http://www.byond.com/forum/?post=2086980&page=2#comment19776775), starting where the link takes you. -- All new player-facing user interfaces must use TGUI. -- Raw HTML is permitted for admin and debug UIs. -- Documentation for TGUI can be found at: - - [tgui/README.md](../tgui/README.md) - - [tgui/tutorial-and-examples.md](../tgui/docs/tutorial-and-examples.md) +There are two key points here: -### Don't create code that hangs references +1) Defining a list in the variable's definition calls a hidden proc - init. If you have to define a list at startup, do so in New() (or preferably Initialize()) and avoid the overhead of a second call (Init() and then New()) -This is part of the larger issue of hard deletes, read this file for more info: [Guide to Harddels](HARDDEL_GUIDE.md)) +2) It also consumes more memory to the point where the list is actually required, even if the object in question may never use it! -### Other Notes +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. -- Code should be modular where possible; if you are working on a new addition, then strongly consider putting it in its own file unless it makes sense to put it with similar ones (i.e. a new tool would go in the "tools.dm" file) +### Icons are for image manipulation and defining an obj's `.icon` var, appearances are for everything else. -- Bloated code may be necessary to add a certain feature, which means there has to be a judgement over whether the feature is worth having or not. You can help make this decision easier by making sure your code is modular. +BYOND will allow you to use a raw icon file or even an icon datum for underlays, overlays, and what not (you can even use strings to refer to an icon state on the current icon). The issue is these get converted by BYOND to appearances on every overlay insert or removal involving them, and this process requires inserting the new appearance into the global list of appearances, and informing clients about them. -- You are expected to help maintain the code that you add, meaning that if there is a problem then you are likely to be approached in order to fix any issues, runtimes, or bugs. +Converting them yourself to appearances and storing this converted value will ensure this process only has to happen once for the lifetime of the round. Helper functions exist to do most of the work for you. -- Do not divide when you can easily convert it to multiplication. (ie `4/2` should be done as `4*0.5`) -- If you used regex to replace code during development of your code, post the regex in your PR for the benefit of future developers and downstream users. +Bad: +```dm +/obj/machine/update_overlays(blah) + if (stat & broken) + add_overlay(icon(broken_icon)) //this icon gets created, passed to byond, converted to an appearance, then deleted. + return + if (is_on) + add_overlay("on") //also bad, the converstion to an appearance still has to happen + else + add_overlay(iconstate2appearance(icon, "off")) //this might seem alright, but not storing the value just moves the repeated appearance generation to this proc rather then the core overlay management. It would only be acceptable (and to some degree perferred) if this overlay is only ever added once (like in init code) +``` -- Changes to the `/config` tree must be made in a way that allows for updating server deployments while preserving previous behaviour. This is due to the fact that the config tree is to be considered owned by the user and not necessarily updated alongside the remainder of the code. The code to preserve previous behaviour may be removed at some point in the future given the OK by maintainers. +Good: +```dm +/obj/machine/update_overlays(var/blah) + var/static/on_overlay + var/static/off_overlay + var/static/broken_overlay + if(isnull(on_overlay)) //static vars initialize with global variables, meaning src is null and this won't pass integration tests unless you check. + on_overlay = iconstate2appearance(icon, "on") + off_overlay = iconstate2appearance(icon, "off") + broken_overlay = icon2appearance(broken_icon) + if (stat & broken) + add_overlay(broken_overlay) + return + if (is_on) + add_overlay(on_overlay) + else + add_overlay(off_overlay) + ... +``` -- The dlls section of tgs3.json is not designed for dlls that are purely `call()()`ed since those handles are closed between world reboots. Only put in dlls that may have to exist between world reboots. +Note: images are appearances with extra steps, and don't incur the overhead in conversion. -#### Enforced not enforced -The following coding styles are not only not enforced at all, but are generally frowned upon to change for little to no reason: +### Do not abuse associated lists. -- English/British spelling on var/proc names - - Color/Colour - both are fine, but keep in mind that BYOND uses `color` as a base variable -- Spaces after control statements - - `if()` and `if ()` - nobody cares! +Associated lists that could instead be variables or statically defined number indexed lists will use more memory, as associated lists have a 24 bytes per item overhead (vs 8 for lists and most vars), and are slower to search compared to static/global variables and lists with known indexes. -### Operators -#### Spacing +Bad: +```dm +/obj/machine/update_overlays(var/blah) + var/static/our_overlays + if (isnull(our_overlays)) + our_overlays = list("on" = iconstate2appearance(overlay_icon, "on"), "off" = iconstate2appearance(overlay_icon, "off"), "broken" = iconstate2appearance(overlay_icon, "broken")) + if (stat & broken) + add_overlay(our_overlays["broken"]) + return + ... +``` -- Operators that should be separated by spaces - - Boolean and logic operators like &&, || <, >, ==, etc (but not !) - - Bitwise AND & - - Argument separator operators like , (and ; when used in a forloop) - - Assignment operators like = or += or the like -- Operators that should not be separated by spaces - - Bitwise OR | - - Access operators like . and : - - Parentheses () - - logical not ! +Good: +```dm +#define OUR_ON_OVERLAY 1 +#define OUR_OFF_OVERLAY 2 +#define OUR_BROKEN_OVERLAY 3 + +/obj/machine/update_overlays(var/blah) + var/static/our_overlays + if (isnull(our_overlays)) + our_overlays = list(iconstate2appearance(overlay_icon, "on"), iconstate2appearance(overlay_icon, "off"), iconstate2appearance(overlay_icon, "broken")) + if (stat & broken) + add_overlay(our_overlays[OUR_BROKEN_OVERLAY]) + return + ... -Math operators like +, -, /, \*, etc are up in the air, just choose which version looks more readable. +#undef OUR_ON_OVERLAY +#undef OUR_OFF_OVERLAY +#undef OUR_BROKEN_OVERLAY +``` +Storing these in a flat (non-associated) list saves on memory, and using defines to reference locations in the list saves CPU time searching the list. -#### Use +Also good: +```dm +/obj/machine/update_overlays(var/blah) + var/static/on_overlay + var/static/off_overlay + var/static/broken_overlay + if(isnull(on_overlay)) + on_overlay = iconstate2appearance(overlay_icon, "on") + off_overlay = iconstate2appearance(overlay_icon, "off") + broken_overlay = iconstate2appearance(overlay_icon, "broken") + if (stat & broken) + add_overlay(broken_overlay) + return + ... +``` +Proc variables, static variables, and global variables are resolved at compile time, so the above is equivalent to the second example, but is easier to read, and avoids the need to store a list. -- Bitwise AND - '&' - - Should be written as `bitfield & bitflag` NEVER `bitflag & bitfield`, both are valid, but the latter is confusing and nonstandard. -- Associated lists declarations must have their key value quoted if it's a string - - WRONG: list(a = "b") - - RIGHT: list("a" = "b") +Note: While there has historically been a strong impulse to use associated lists for caching of computed values, this is the easy way out and leaves a lot of hidden overhead. Please keep this in mind when designing core/root systems that are intended for use by other code/coders. It's normally better for consumers of such systems to handle their own caching using vars and number indexed lists, than for you to do it using associated lists. -### Dream Maker Quirks/Tricks +## Dream Maker Quirks/Tricks -Like all languages, Dream Maker has its quirks, some of them are beneficial to us, like these +Like all languages, Dream Maker has its quirks, some of them are beneficial to us, some are harmful. +### Loops #### 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 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 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 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) +#### `for(var/A in list)` versus `for(var/i in 1 to list.len)` The former is faster than the latter, as shown by the following profile results: https://file.house/zy7H.png Code used for the test in a readable format: https://pastebin.com/w50uERkG -#### Istypeless for loops +### Dot variable (`.`) -A name for a differing syntax for writing for-each style loops in DM. It's NOT DM's standard syntax, hence why this is considered a quirk. Take a look at this: +The `.` variable is present in all procs. It refers to the value returned by a proc. -```DM -var/list/bag_of_items = list(sword, apple, coinpouch, sword, sword) -var/obj/item/sword/best_sword -for(var/obj/item/sword/S in bag_of_items) - if(!best_sword || S.damage > best_sword.damage) - best_sword = S +```dm +/proc/return_six() + . = 3 + . *= 2 + +// ...is equivalent to... +/proc/return_six() + var/output = 3 + output *= 2 + return output ``` -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: +At its best, it can make some very common patterns easy to use, and harder to mess up. However, at its worst, it can make it significantly harder to understand what a proc does. -```DM -var/list/bag_of_swords = list(sword, sword, sword, sword) -var/obj/item/sword/best_sword -for(var/obj/item/sword/S in bag_of_swords) - if(!best_sword || S.damage > best_sword.damage) - best_sword = S +```dm +/proc/complex_proc() + if (do_something()) + some_code() + if (do_something_else()) + . = TRUE // Uh oh, what's going on! + + // even + // more + // code + if (bad_condition()) + return // This actually will return something set from earlier! ``` -specifies a type for DM to filter by. +This sort of behavior can create some nasty to debug errors with things returning when you don't expect them to. Would you see `return` and it expect it to return a value, without reading all the code before it? Furthermore, a simple `return` statement cannot easily be checked by the LSP, meaning you can't easily check what is actually being returned. Basically, `return output` lets you go to where `output` is defined/set. `return` does not. -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: +Even in simple cases, this can create some just generally hard to read code, seemingly in the pursuit of being clever. -```DM -var/list/bag_of_swords = list(sword, sword, sword, sword) -var/obj/item/sword/best_sword -for(var/s in bag_of_swords) - var/obj/item/sword/S = s - if(!best_sword || S.damage > best_sword.damage) - best_sword = S +```dm +/client/p_were(gender) + . = "was" + if (gender == PLURAL || gender == NEUTER) + . = "were" ``` -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. +Because of these problems, it is encouraged to prefer standard, explicit return statements. The above code would be best written as: -#### Dot variable +```dm +/client/p_were(gender) + if (gender == PLURAL || gender == NEUTER) + return "were" + else + return "was" +``` -Like other languages in the C family, DM has a `.` or "Dot" operator, used for accessing variables/members/functions of an object instance. -eg: +#### Exception: `. = ..()` -```DM -var/mob/living/carbon/human/H = YOU_THE_READER -H.gib() +As hinted at before, `. = ..()` is *extremely* common. This will call the parent function, and preserve its return type. Code like this: + +```dm +/obj/item/spoon/attack() + . = ..() + visible_message("Whack!") +``` + +...is completely accepted, and in fact, usually *prefered* over: + +```dm +/obj/item/spoon/attack() + var/output = ..() + visible_message("Whack!") + return output ``` -However, DM also has a dot variable, accessed just as `.` on its own, defaulting to a value of null. Now, what's special about the dot operator is that it is automatically returned (as in the `return` statement) at the end of a proc, provided the proc does not already manually return (`return count` for example.) Why is this special? +#### Exception: Runtime resilience -With `.` being everpresent in every proc, can we use it as a temporary variable? Of course we can! However, the `.` operator cannot replace a typecasted variable - it can hold data any other var in DM can, it just can't be accessed as one, although the `.` operator is compatible with a few operators that look weird but work perfectly fine, such as: `.++` for incrementing `.'s` value, or `.[1]` for accessing the first element of `.`, provided that it's a list. +One unique property of DM is the ability for procs to error, but for code to continue. For instance, the following: -## Globals versus static +```dm +/proc/uh_oh() + CRASH("oh no!") -DM has a var keyword, called global. This var keyword is for vars inside of types. For instance: +/proc/main() + to_chat(world, "1") + uh_oh() + to_chat(world, "2") +``` -```DM -mob - var - global - thing = TRUE +...would print both 1 *and* 2, which may be unexpected if you come from other languages. + +This is where `.` provides a new useful behavior--**a proc that runtimes will return `.`**. + +Meaning: + +```dm +/proc/uh_oh() + . = "woah!" + CRASH("oh no!") + +/proc/main() + to_chat(world, uh_oh()) ``` -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) +...will print `woah!`. -Isn't that confusing? +For this reason, it is acceptable for `.` to be used in places where consumers can reasonably continue in the event of a runtime. -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. +If you are using `.` in this case (or for another case that might be acceptable, other than most uses of `. = ..()`), it is still prefered that you explicitly `return .` in order to prevent both editor issues and readability/error-prone issues. -## Pull Request Process +```dm +/proc/uh_oh() + . = "woah!" -There is no strict process when it comes to merging pull requests. Pull requests will sometimes take a while before they are looked at by a maintainer; the bigger the change, the more time it will take before they are accepted into the code. Every team member is a volunteer who is giving up their own time to help maintain and contribute, so please be courteous and respectful. Here are some helpful ways to make it easier for you and for the maintainers when making a pull request. + if (do_something()) + call_code() + if (!working_fine()) + return . // Instead of `return`, we explicitly `return .` -- Make sure your pull request complies to the requirements outlined here + if (some_fail_state()) + CRASH("youch!") -- You are going to be expected to document all your changes in the pull request. Failing to do so will mean delaying it as we will have to question why you made the change. On the other hand, you can speed up the process by making the pull request readable and easy to understand, with diagrams or before/after data. + return . // `return .` is used at the end, to signify it has been used +``` -- We ask that you use the changelog system to document your change, which prevents our players from being caught unaware by changes. +```dm +/obj/item/spoon/super_attack() + . = ..() + if (. == BIGGER_SUPER_ATTACK) + return BIGGER_SUPER_ATTACK // More readable than `.` + + // Due to how common it is, most uses of `. = ..()` do not need a trailing `return .` +``` -- If you are proposing multiple changes, which change many different aspects of the code, you are expected to section them off into different pull requests in order to make it easier to review them and to deny/accept the changes that are deemed acceptable. (This is called atomization, if someone asks you to do it.) +### The BYOND walk procs -- If your pull request rebalances something or adds a large new feature, it may be put up to vote. This vote will usually end 24 hours after it is announced. If the vote passes, the code has not been substantially changed since the vote began, and no maintainers have any pending requested changes, the pull request will likely be merged. If a maintainer deems it so, a controversial tag will be added to the PR, which then requires all votes to require a ratio of 1:2 of likes to dislikes to pass (subject to the topic of the PR), and the vote will go on for at least double the normal time. +BYOND has a few procs that move one atom towards/away from another, `walk()`, `walk_to()`, `walk_towards`, `walk_away()` and `walk_rand()`. -- Reverts of major features must be done three to four weeks (at minimum) after the PR that added it, unless said feature has a server-affecting exploit or error. Reverts of smaller features and rebalances must be done at minimum one week after. +The way they pull this off, while fine for the language itself, makes a mess of our master-controller, and can cause the whole game to slow down. Do not use them. -- Pull requests that are made as alternatives with few changes will be closed by maintainers. Use suggestions on the original pull request instead. +The following is a list of procs, and their safe replacements. -- If your pull request is accepted, the code you add no longer belongs exclusively to you but to everyone; everyone is free to work on it, but you are also free to support or object to any changes being made, which will likely hold more weight, as you're the one who added the feature. It is a shame this has to be explicitly said, but there have been cases where this would've saved some trouble. +* Removing something from the loop `walk(0)` -> `SSmove_manager.stop_looping()` +* Move in a direction `walk()` -> `SSmove_manager.move()` +* Move towards a thing, taking turf density into account`walk_to()` -> `SSmove_manager.move_to()` +* Move in a thing's direction, ignoring turf density `walk_towards()` -> `SSmove_manager.home_onto()` and `SSmove_manager.move_towards_legacy()`, check the documentation to see which you like better +* Move away from something, taking turf density into account `walk_away()` -> `SSmove_manager.move_away()` +* Move to a random place nearby. NOT random walk `walk_rand()` -> `SSmove_manager.move_rand()` is random walk, `SSmove_manager.move_to_rand()` is walk to a random place -- 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. +### BYOND hellspawn -- If your pull request is not finished make sure it is at least testable in a live environment, or at the very least mark it as a draft. Pull requests that do not at least meet this requirement will be closed. You may request a maintainer reopen the pull request when you're ready, or make a new one. +What follows is documentation of inconsistent or strange behavior found in our engine, BYOND. +It's listed here in the hope that it will prevent fruitless debugging in future. -- 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. +#### Icon hell -## Porting features/sprites/sounds/tools from other codebases +Due to how they are internally represented as part of appearance, overlays and underlays which have an icon_state named the same as an icon_state on the parent object will use the parent's icon_state and look completely wrong. This has caused two bugs with underlay lighting whenever a turf had the icon_state of "transparent" or "dark" and their lighting objects also had those states - because when the lighting underlays were in those modes they would be rendered by the client to look like the icons the floor used. When adding something as an overlay or an underlay make sure it can't match icon_state names with whatever you're adding it to. -If you are porting features/tools from other codebases, you must give the original authors credit where it's due. Typically, crediting them in your pull request and the changelog is the recommended way of doing it. Take note of what license they use though, porting stuff from AGPLv3 and GPLv3 codebases are allowed. +## SQL -Regarding sprites & sounds, you must credit the artist and possibly the codebase. All /tg/station assets including icons and sound are under a [Creative Commons 3.0 BY-SA license](https://creativecommons.org/licenses/by-sa/3.0/) unless otherwise indicated. However if you are porting assets from GoonStation or usually any assets under the [Creative Commons 3.0 BY-NC-SA license](https://creativecommons.org/licenses/by-nc-sa/3.0/) are to go into the 'goon' folder of the /tg/station codebase. +* Do not use the shorthand sql insert format (where no column names are specified) because it unnecessarily breaks all queries on minor column changes and prevents using these tables for tracking outside related info such as in a connected site/forum. -## Banned content +* 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 -Do not add any of the following in a Pull Request or risk getting the PR closed: +* Any time the schema is changed the `schema_revision` table and `DB_MAJOR_VERSION` or `DB_MINOR_VERSION` defines must be incremented. -- National Socialist Party of Germany content, National Socialist Party of Germany related content, or National Socialist Party of Germany references -- Code where one line of code is split across mutiple lines (except for multiple, separate strings and comments; in those cases, existing longer lines must not be split up) -- Code adding, removing, or updating the availability of alien races/species/human mutants without prior approval. Pull requests attempting to add or remove features from said races/species/mutants require prior approval as well. -- Code which violates GitHub's [terms of service](https://github.com/site/terms). +* Queries must never specify the database, be it in code, or in text files in the repo. -Just because something isn't on this list doesn't mean that it's acceptable. Use common sense above all else. +* Primary keys are inherently immutable and you must never do anything to change the primary key of a row or entity. This includes preserving auto increment numbers of rows when copying data to a table in a conversion script. No amount of bitching about gaps in ids or out of order ids will save you from this policy. -## Line Endings +* The ttl for data from the database is 10 seconds. You must have a compelling reason to store and reuse data for longer then this. -All newly created, uploaded, or modified files in this codebase are required to be using the Unix Schema for line endings. That means the only acceptable line ending is '**\n**', not '**\r\n**' nor '**\r\r**' +* Do not write stored and transformed data to the database, instead, apply the transformation to the data in the database directly. + * ie: SELECTing a number from the database, doubling it, then updating the database with the doubled number. If the data in the database changed between step 1 and 3, you'll get an incorrect result. Instead, directly double it in the update query. `UPDATE table SET num = num*2` instead of `UPDATE table SET num = [num]`. + * if the transformation is user provided (such as allowing a user to edit a string), you should confirm the value being updated did not change in the database in the intervening time before writing the new user provided data by checking the old value with the current value in the database, and if it has changed, allow the user to decide what to do next. diff --git a/.github/workflows/autowiki.yml b/.github/workflows/autowiki.yml index 15474e651f17..c6f85bade91d 100644 --- a/.github/workflows/autowiki.yml +++ b/.github/workflows/autowiki.yml @@ -19,32 +19,59 @@ jobs: unset SECRET_EXISTS if [ -n "$ENABLER_SECRET" ]; then SECRET_EXISTS=true ; fi echo "SECRETS_ENABLED=$SECRET_EXISTS" >> $GITHUB_OUTPUT + - name: Checkout if: steps.secrets_set.outputs.SECRETS_ENABLED uses: actions/checkout@v3 - - name: Restore BYOND cache + + - name: Setup BYOND cache + id: cache-byond if: steps.secrets_set.outputs.SECRETS_ENABLED uses: actions/cache@v3 with: path: ~/BYOND - key: ${{ runner.os }}-byond-${{ secrets.CACHE_PURGE_KEY }} - - name: Install rust-g + key: ${{ runner.os }}-byond-cache-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('dependencies.sh') }} + + - name: Install BYOND + if: steps.cache-byond.outputs.cache-hit != 'true' && steps.secrets_set.outputs.SECRETS_ENABLED + run: bash tools/ci/install_byond.sh + + - name: Install runtime dependencies if: steps.secrets_set.outputs.SECRETS_ENABLED run: | sudo dpkg --add-architecture i386 sudo apt update || true - sudo apt install -o APT::Immediate-Configure=false libssl-dev:i386 + sudo apt install -o APT::Immediate-configure=false libssl-dev:i386 bash tools/ci/install_rust_g.sh - - name: Install auxmos + + - name: Cache dependencies if: steps.secrets_set.outputs.SECRETS_ENABLED + uses: actions/cache@v3 + with: + path: ~/.byond/bin + key: ${{ runner.os }}-deps-cache-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('dependencies.sh') }} + + - name: Install build dependencies + if: steps.cache-deps.outputs.cache-hit != 'true' && steps.secrets_set.outputs.SECRETS_ENABLED run: | - bash tools/ci/install_auxmos.sh + sudo apt install -o APT::Immediate-Configure=false libgcc-s1:i386 g++-multilib zlib1g-dev:i386 + rustup target add i686-unknown-linux-gnu + + - name: Build auxmos + if: steps.cache-deps.outputs.cache-hit != 'true' && steps.secrets_set.outputs.SECRETS_ENABLED + run: bash tools/ci/build_auxmos.sh + + - name: Build rust-g + if: steps.cache-deps.outputs.cache-hit != 'true' && steps.secrets_set.outputs.SECRETS_ENABLED + run: bash tools/ci/build_rust_g.sh + - name: Compile and generate Autowiki files if: steps.secrets_set.outputs.SECRETS_ENABLED run: | bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup tools/build/build --ci autowiki + - name: Run Autowiki if: steps.secrets_set.outputs.SECRETS_ENABLED env: diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index 99d78dfc1166..47f8b1df9941 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -19,11 +19,26 @@ jobs: with: ref: master - uses: actions/checkout@v3 + - name: Restore SpacemanDMM cache + id: cache-spacemandmm + uses: actions/cache@v3 + with: + path: ~/dreamchecker + key: ${{ runner.os }}-spacemandmm-cache-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('dependencies.sh') }} + - name: Build SpacemanDMM + run: bash tools/ci/build_spaceman_dmm.sh dreamchecker + + - name: Restore BYOND cache + id: cache-byond uses: actions/cache@v3 with: - path: ~/SpacemanDMM - key: ${{ runner.os }}-spacemandmm-${{ secrets.CACHE_PURGE_KEY }} + path: ~/BYOND + key: ${{ runner.os }}-byond-cache-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('dependencies.sh') }} + - name: Install BYOND + if: steps.cache-byond.outputs.cache-hit != 'true' + run: bash tools/ci/install_byond.sh + - name: Restore Yarn cache uses: actions/cache@v3 with: @@ -33,14 +48,15 @@ jobs: ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}- ${{ runner.os }}-build- ${{ runner.os }}- + - name: Install Tools run: | pip3 install setuptools bash tools/ci/install_node.sh - bash tools/ci/install_byond.sh bash tools/ci/install_spaceman_dmm.sh dreamchecker cargo install ripgrep --features pcre2 tools/bootstrap/python -c '' + - name: Run Linters run: | tools/bootstrap/python -m tools.maplint.source --github @@ -52,19 +68,17 @@ jobs: tools/bootstrap/python -m dmi.test tools/bootstrap/python -m mapmerge2.dmm_test ~/dreamchecker > ${GITHUB_WORKSPACE}/output-annotations.txt 2>&1 + - name: Annotate Lints uses: yogstation13/DreamAnnotate@v2 - if: always() with: outputFile: output-annotations.txt - - uses: actions/setup-python@v4 - with: - python-version: "3.9" + - name: Run Check Regex run: | tools/bootstrap/python -m ci.check_regex --log-changes-only --github-actions + - name: Annotate Regex Matches - if: always() run: | cat check_regex_output.txt @@ -74,22 +88,19 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Python setup - uses: actions/setup-python@v4 - with: - python-version: "3.9" + - name: Setup cache id: cache-byond uses: actions/cache@v3 with: path: ~/BYOND - key: ${{ runner.os }}-byond-cache-${{ hashFiles('Dockerfile') }} + key: ${{ runner.os }}-byond-cache-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('dependencies.sh') }} - name: Install BYOND if: steps.cache-byond.outputs.cache-hit != 'true' run: bash tools/ci/install_byond.sh + - name: Compile All Maps run: | - bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup tools/build/build --ci dm -DCIBUILDING -DCITESTING -DALL_MAPS -DFULL_INIT @@ -97,7 +108,7 @@ jobs: if: "!contains(github.event.head_commit.message, '[ci skip]')" name: Integration Tests strategy: - fail-fast: true + fail-fast: false matrix: arg: [ "BASIC_TESTS", @@ -129,6 +140,7 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v3 + - name: Restore Yarn cache uses: actions/cache@v3 with: @@ -138,14 +150,17 @@ jobs: ${{ runner.os }}-build-${{ secrets.CACHE_PURGE_KEY }}- ${{ runner.os }}-build- ${{ runner.os }}- + - name: Compile run: pwsh tools/ci/build.ps1 env: DM_EXE: "C:\\byond\\bin\\dm.exe" + - name: Create artifact run: | md deploy bash tools/deploy.sh ./deploy + - name: Deploy artifact uses: actions/upload-artifact@v3 with: diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index a361ecedc588..9c83d6ab013d 100644 --- a/.github/workflows/run_integration_tests.yml +++ b/.github/workflows/run_integration_tests.yml @@ -27,12 +27,45 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - uses: actions/checkout@v3 - - name: Setup cache + + - name: Setup BYOND cache id: cache-byond uses: actions/cache@v3 with: path: ~/BYOND - key: ${{ runner.os }}-byond-cache-${{ hashFiles('Dockerfile') }} + key: ${{ runner.os }}-byond-cache-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('dependencies.sh') }} + + - name: Install BYOND + if: steps.cache-byond.outputs.cache-hit != 'true' + run: bash tools/ci/install_byond.sh + + - name: Install runtime dependencies + run: | + sudo dpkg --add-architecture i386 + sudo apt update || true + sudo apt install -o APT::Immediate-Configure=false libssl-dev:i386 + + - name: Setup dependencies cache + id: cache-deps + uses: actions/cache@v3 + with: + path: ~/.byond/bin + key: ${{ runner.os }}-deps-cache-${{ secrets.CACHE_PURGE_KEY }}-${{ hashFiles('dependencies.sh') }} + + - name: Install build dependencies + if: steps.cache-deps.outputs.cache-hit != 'true' + run: | + sudo apt install -o APT::Immediate-Configure=false libgcc-s1:i386 g++-multilib zlib1g-dev:i386 + rustup target add i686-unknown-linux-gnu + + - name: Build auxmos + if: steps.cache-deps.outputs.cache-hit != 'true' + run: bash tools/ci/build_auxmos.sh + + - name: Build rust-g + if: steps.cache-deps.outputs.cache-hit != 'true' + run: bash tools/ci/build_rust_g.sh + - name: Setup database run: | sudo systemctl start mysql @@ -40,23 +73,15 @@ jobs: mysql -u root -proot tg_ci < SQL/tgstation_schema.sql mysql -u root -proot -e 'CREATE DATABASE tg_ci_prefixed;' mysql -u root -proot tg_ci_prefixed < SQL/tgstation_schema_prefixed.sql - - name: Install rust-g - run: | - sudo dpkg --add-architecture i386 - sudo apt update || true - sudo apt install -o APT::Immediate-Configure=false libssl-dev:i386 - bash tools/ci/install_rust_g.sh - - name: Install auxmos - run: | - bash tools/ci/install_auxmos.sh + - name: Configure version if: ${{ inputs.major }} run: | echo "BYOND_MAJOR=${{ inputs.major }}" >> $GITHUB_ENV echo "BYOND_MINOR=${{ inputs.minor }}" >> $GITHUB_ENV + - name: Compile Tests run: | - bash tools/ci/install_byond.sh source $HOME/BYOND/byond/bin/byondsetup tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -D${{ inputs.arg }} - name: Run Tests diff --git a/.tgs.yml b/.tgs.yml index b012bdffe231..76a53577b505 100644 --- a/.tgs.yml +++ b/.tgs.yml @@ -3,7 +3,7 @@ version: 1 # The BYOND version to use (kept in sync with dependencies.sh by the "TGS Test Suite" CI job) # Must be interpreted as a string, keep quoted -byond: "514.1588" +byond: "515.1633" # Folders to create in "/Configuration/GameStaticFiles/" static_files: # Config directory should be static diff --git a/Dockerfile b/Dockerfile index 35490ee80596..4a8028dc7fca 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM beestation/byond:514.1583 as base +FROM beestation/byond:515.1616 as base # Install the tools needed to compile our rust dependencies FROM base as rust-build diff --git a/_maps/shuttles/independent/independent_box.dmm b/_maps/shuttles/independent/independent_box.dmm index 3f17359288cc..685f9518f44e 100644 --- a/_maps/shuttles/independent/independent_box.dmm +++ b/_maps/shuttles/independent/independent_box.dmm @@ -331,7 +331,7 @@ /obj/machinery/atmospherics/components/unary/outlet_injector/on{ dir = 8 }, -/turf/open/floor/plating, +/turf/open/floor/plating/airless, /area/ship/external) "bq" = ( /turf/closed/wall/mineral/titanium/nodiagonal, @@ -2227,7 +2227,7 @@ /obj/structure/catwalk/over, /obj/item/cigbutt/roach, /obj/item/reagent_containers/food/snacks/burrito, -/turf/open/floor/plating, +/turf/open/floor/plating/airless, /area/ship/external) "Dr" = ( /obj/machinery/door/airlock{ @@ -2622,7 +2622,7 @@ dir = 8 }, /obj/item/chair/plastic, -/turf/open/floor/plating, +/turf/open/floor/plating/airless, /area/ship/external) "Qh" = ( /obj/machinery/power/apc/auto_name/directional/south, diff --git a/auxmos.dll b/auxmos.dll index 9db02bf27e26..0df77c97b287 100644 Binary files a/auxmos.dll and b/auxmos.dll differ diff --git a/check_regex.yaml b/check_regex.yaml index 062b120ed936..dc1d4d05e71a 100644 --- a/check_regex.yaml +++ b/check_regex.yaml @@ -23,7 +23,7 @@ standards: - exactly: [0, "mangled characters", '[\u0000\uFFFF\uFFFD]'] - exactly: [8, "escapes", '\\\\(red|blue|green|black|b|i[^mc])'] - - exactly: [9, "Del()s", '\WDel\('] + - exactly: [8, "Del()s", '\WDel\('] - exactly: [1, "/atom text paths", '"/atom'] - exactly: [1, "/area text paths", '"/area'] diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index 4600cb626da0..3057df12ab14 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -185,6 +185,10 @@ /// just check density #define ATMOS_PASS_DENSITY -2 +// Adjacency flags +#define ATMOS_ADJACENT_ANY (1<<0) +#define ATMOS_ADJACENT_FIRELOCK (1<<1) + #define CANATMOSPASS(A, O) (A.CanAtmosPass == ATMOS_PASS_PROC ? A.CanAtmosPass(O) : (A.CanAtmosPass == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPass)) #define CANVERTICALATMOSPASS(A, O) (A.CanAtmosPassVertical == ATMOS_PASS_PROC ? A.CanAtmosPass(O, TRUE) : (A.CanAtmosPassVertical == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPassVertical)) @@ -328,6 +332,13 @@ #define GAS_FLAG_DANGEROUS (1<<0) #define GAS_FLAG_BREATH_PROC (1<<1) +// Flag for update_air_ref() +#define AIR_REF_CLOSED_TURF -1 +#define AIR_REF_SPACE_TURF 0 + +#define AIR_REF_PLANETARY_TURF (1<<0) //SIMULATION_DIFFUSE 0b1 +#define AIR_REF_OPEN_TURF (1<<1) //SIMULATION_ALL 0b10 + //HELPERS #define PIPING_LAYER_SHIFT(T, PipingLayer) \ if(T.dir & (NORTH|SOUTH)) { \ diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 0f2f39ee0240..d47980b59c6b 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -149,12 +149,8 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) //subtypesof(), typesof() without the parent path #define subtypesof(typepath) (typesof(typepath) - typepath) -/// Takes a datum as input, returns its ref string, or a cached version of it -/// This allows us to cache \ref creation, which ensures it'll only ever happen once per datum, saving string tree time -/// It is slightly less optimal then a []'d datum, but the cost is massively outweighed by the potential savings -/// It will only work for datums mind, for datum reasons -/// : because of the embedded typecheck -#define text_ref(datum) (isdatum(datum) ? (datum:cached_ref ||= "\ref[datum]") : ("\ref[datum]")) +/// Takes a datum as input, returns its ref string +#define text_ref(datum) ref(datum) //Gets the turf this atom inhabits #define get_turf(A) (get_step(A, 0)) diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index dca885b37b95..2028f45afa83 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -58,6 +58,6 @@ #define QDEL_IN_CLIENT_TIME(item, time) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(qdel), item), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME) #define QDEL_NULL(item) qdel(item); item = null #define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); } -#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(______qdel_list_wrapper), L), time, TIMER_STOPPABLE) +#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(______qdel_list_wrapper), L), time, TIMER_STOPPABLE) #define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); } #define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); } diff --git a/code/__DEFINES/spaceman_dmm.dm b/code/__DEFINES/spaceman_dmm.dm index b62bbee4259a..c4f84d5fce58 100644 --- a/code/__DEFINES/spaceman_dmm.dm +++ b/code/__DEFINES/spaceman_dmm.dm @@ -3,42 +3,72 @@ // The SPACEMAN_DMM define is set by the linter and other tooling when it runs. #ifdef SPACEMAN_DMM + /** + * Sets a return type expression for a proc. The return type can take the forms: + + * `/typepath` - a raw typepath. The return type of the proc is the type named. + + * `param` - a typepath given as a parameter, for procs which return an instance of the passed-in type. + + * `param.type` - the static type of a passed-in parameter, for procs which + * return their input or otherwise another value of the same type. + + * `param[_].type` - the static type of a passed-in parameter, with one level + * of `/list` stripped, for procs which select one item from a list. The `[_]` + * may be repeated to strip more levels of `/list`. + */ #define RETURN_TYPE(X) set SpacemanDMM_return_type = X + /** + * If set, will enable a diagnostic on children of the proc it is set on which do + * not contain any `..()` parent calls. This can help with finding situations + * where a signal or other important handling in the parent proc is being skipped. + * Child procs may set this setting to `0` instead to override the check. + */ #define SHOULD_CALL_PARENT(X) set SpacemanDMM_should_call_parent = X - #define UNLINT(X) SpacemanDMM_unlint(X) + /** + * If set, raise a warning for any child procs that override this one, + * regardless of if it calls parent or not. + * This functions in a similar way to the `final` keyword in some languages. + * This cannot be disabled by child overrides. + */ #define SHOULD_NOT_OVERRIDE(X) set SpacemanDMM_should_not_override = X + /** + * If set, raise a warning if the proc or one of the sub-procs it calls + * uses a blocking call, such as `sleep()` or `input()` without using `set waitfor = 0` + * This cannot be disabled by child overrides. + */ #define SHOULD_NOT_SLEEP(X) set SpacemanDMM_should_not_sleep = X + /** + * If set, ensure a proc is 'pure', such that it does not make any changes + * outside itself or output. This also checks to make sure anything using + * this proc doesn't invoke it without making use of the return value. + * This cannot be disabled by child overrides. + */ #define SHOULD_BE_PURE(X) set SpacemanDMM_should_be_pure = X + ///Private procs can only be called by things of exactly the same type. #define PRIVATE_PROC(X) set SpacemanDMM_private_proc = X + ///Protected procs can only be call by things of the same type *or subtypes*. #define PROTECTED_PROC(X) set SpacemanDMM_protected_proc = X + ///If set, will not lint. + #define UNLINT(X) SpacemanDMM_unlint(X) + + ///If set, overriding their value isn't permitted by types that inherit it. #define VAR_FINAL var/SpacemanDMM_final + ///Private vars can only be called by things of exactly the same type. #define VAR_PRIVATE var/SpacemanDMM_private + ///Protected vars can only be called by things of the same type *or subtypes*. #define VAR_PROTECTED var/SpacemanDMM_protected #else #define RETURN_TYPE(X) #define SHOULD_CALL_PARENT(X) - #define UNLINT(X) X #define SHOULD_NOT_OVERRIDE(X) #define SHOULD_NOT_SLEEP(X) #define SHOULD_BE_PURE(X) #define PRIVATE_PROC(X) #define PROTECTED_PROC(X) + #define UNLINT(X) X + #define VAR_FINAL var #define VAR_PRIVATE var #define VAR_PROTECTED var #endif - -/proc/auxtools_stack_trace(msg) - CRASH(msg) - -/proc/enable_debugging(mode, port) - CRASH("auxtools not loaded") - -/proc/auxtools_expr_stub() - CRASH("auxtools not loaded") - -/world/Del() - var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") - if (debug_server) - LIBCALL(debug_server, "auxtools_shutdown")() - . = ..() diff --git a/code/__HELPERS/_auxtools_api.dm b/code/__HELPERS/_auxtools_api.dm new file mode 100644 index 000000000000..d0e840b7d802 --- /dev/null +++ b/code/__HELPERS/_auxtools_api.dm @@ -0,0 +1,8 @@ +/proc/auxtools_stack_trace(msg) + CRASH(msg) + +/proc/enable_debugging(mode, port) + CRASH("auxtools not loaded") + +/proc/auxtools_expr_stub() + CRASH("auxtools not loaded") diff --git a/code/__HELPERS/_extools_api.dm b/code/__HELPERS/_extools_api.dm deleted file mode 100644 index 16c70f7d2dc5..000000000000 --- a/code/__HELPERS/_extools_api.dm +++ /dev/null @@ -1,23 +0,0 @@ -//#define EXTOOLS_LOGGING // rust_g is used as a fallback if this is undefined - -/proc/extools_log_write() - -/proc/extools_finalize_logging() - -GLOBAL_LIST_EMPTY(auxtools_initialized) - -#define AUXTOOLS_CHECK(LIB)\ - if (!GLOB.auxtools_initialized[LIB] && fexists(LIB)) {\ - var/string = LIBCALL(LIB,"auxtools_init")();\ - if(findtext(string, "SUCCESS")) {\ - GLOB.auxtools_initialized[LIB] = TRUE;\ - } else {\ - CRASH(string);\ - }\ - }\ - -#define AUXTOOLS_SHUTDOWN(LIB)\ - if (GLOB.auxtools_initialized[LIB] && fexists(LIB)){\ - LIBCALL(LIB,"auxtools_shutdown")();\ - GLOB.auxtools_initialized[LIB] = FALSE;\ - }\ diff --git a/code/__HELPERS/bindings.dm b/code/__HELPERS/bindings.dm new file mode 100644 index 000000000000..c2c19136854e --- /dev/null +++ b/code/__HELPERS/bindings.dm @@ -0,0 +1,184 @@ +//THIS FILE IS AUTOMATICALLY GENERATED BY AUXMOS, PLEASE DO NOT TOUCH IT +//PROC DEFINITIONS MAY MOVE AROUND, THIS IS NORMAL + +/* This comment bypasses grep checks */ /var/__auxmos + +/proc/__detect_auxmos() + if (world.system_type == UNIX) + return __auxmos = "libauxmos" + else + return __auxmos = "auxmos" + +#define AUXMOS (__auxmos || __detect_auxmos()) + +/datum/gas_mixture/proc/__auxtools_parse_gas_string(string) + return call_ext(AUXMOS, "byond:parse_gas_string_ffi")(src, string) + +/datum/controller/subsystem/air/proc/get_max_gas_mixes() + return call_ext(AUXMOS, "byond:hook_max_gas_mixes_ffi")() + +/datum/controller/subsystem/air/proc/get_amt_gas_mixes() + return call_ext(AUXMOS, "byond:hook_amt_gas_mixes_ffi")() + +/proc/equalize_all_gases_in_list(gas_list) + return call_ext(AUXMOS, "byond:equalize_all_hook_ffi")(gas_list) + +/datum/gas_mixture/proc/get_oxidation_power(temp) + return call_ext(AUXMOS, "byond:oxidation_power_hook_ffi")(src, temp) + +/datum/gas_mixture/proc/get_fuel_amount(temp) + return call_ext(AUXMOS, "byond:fuel_amount_hook_ffi")(src, temp) + +/datum/gas_mixture/proc/equalize_with(total) + return call_ext(AUXMOS, "byond:equalize_with_hook_ffi")(src, total) + +/datum/gas_mixture/proc/transfer_ratio_to(other, ratio) + return call_ext(AUXMOS, "byond:transfer_ratio_hook_ffi")(src, other, ratio) + +/datum/gas_mixture/proc/transfer_to(other, moles) + return call_ext(AUXMOS, "byond:transfer_hook_ffi")(src, other, moles) + +/datum/gas_mixture/proc/adjust_heat(temp) + return call_ext(AUXMOS, "byond:adjust_heat_hook_ffi")(src, temp) + +/datum/gas_mixture/proc/react(holder) + return call_ext(AUXMOS, "byond:react_hook_ffi")(src, holder) + +/datum/gas_mixture/proc/compare(other) + return call_ext(AUXMOS, "byond:compare_hook_ffi")(src, other) + +/datum/gas_mixture/proc/clear() + return call_ext(AUXMOS, "byond:clear_hook_ffi")(src) + +/datum/gas_mixture/proc/mark_immutable() + return call_ext(AUXMOS, "byond:mark_immutable_hook_ffi")(src) + +/datum/gas_mixture/proc/scrub_into(into, ratio_v, gas_list) + return call_ext(AUXMOS, "byond:scrub_into_hook_ffi")(src, into, ratio_v, gas_list) + +/datum/gas_mixture/proc/get_by_flag(flag_val) + return call_ext(AUXMOS, "byond:get_by_flag_hook_ffi")(src, flag_val) + +/datum/gas_mixture/proc/__remove_by_flag(into, flag_val, amount_val) + return call_ext(AUXMOS, "byond:remove_by_flag_hook_ffi")(src, into, flag_val, amount_val) + +/datum/gas_mixture/proc/divide(num_val) + return call_ext(AUXMOS, "byond:divide_hook_ffi")(src, num_val) + +/datum/gas_mixture/proc/multiply(num_val) + return call_ext(AUXMOS, "byond:multiply_hook_ffi")(src, num_val) + +/datum/gas_mixture/proc/subtract(num_val) + return call_ext(AUXMOS, "byond:subtract_hook_ffi")(src, num_val) + +/datum/gas_mixture/proc/add(num_val) + return call_ext(AUXMOS, "byond:add_hook_ffi")(src, num_val) + +/datum/gas_mixture/proc/adjust_multi(...) + var/list/args_copy = args.Copy() + args_copy.Insert(1, src) + return call_ext(AUXMOS, "byond:adjust_multi_hook_ffi")(arglist(args_copy)) + +/datum/gas_mixture/proc/adjust_moles_temp(id_val, num_val, temp_val) + return call_ext(AUXMOS, "byond:adjust_moles_temp_hook_ffi")(src, id_val, num_val, temp_val) + +/datum/gas_mixture/proc/adjust_moles(id_val, num_val) + return call_ext(AUXMOS, "byond:adjust_moles_hook_ffi")(src, id_val, num_val) + +/datum/gas_mixture/proc/set_moles(gas_id, amt_val) + return call_ext(AUXMOS, "byond:set_moles_hook_ffi")(src, gas_id, amt_val) + +/datum/gas_mixture/proc/get_moles(gas_id) + return call_ext(AUXMOS, "byond:get_moles_hook_ffi")(src, gas_id) + +/datum/gas_mixture/proc/set_volume(vol_arg) + return call_ext(AUXMOS, "byond:set_volume_hook_ffi")(src, vol_arg) + +/datum/gas_mixture/proc/partial_heat_capacity(gas_id) + return call_ext(AUXMOS, "byond:partial_heat_capacity_ffi")(src, gas_id) + +/datum/gas_mixture/proc/set_temperature(arg_temp) + return call_ext(AUXMOS, "byond:set_temperature_hook_ffi")(src, arg_temp) + +/datum/gas_mixture/proc/get_gases() + return call_ext(AUXMOS, "byond:get_gases_hook_ffi")(src) + +/datum/gas_mixture/proc/temperature_share(...) + var/list/args_copy = args.Copy() + args_copy.Insert(1, src) + return call_ext(AUXMOS, "byond:temperature_share_hook_ffi")(arglist(args_copy)) + +/datum/gas_mixture/proc/copy_from(giver) + return call_ext(AUXMOS, "byond:copy_from_hook_ffi")(src, giver) + +/datum/gas_mixture/proc/__remove(into, amount_arg) + return call_ext(AUXMOS, "byond:remove_hook_ffi")(src, into, amount_arg) + +/datum/gas_mixture/proc/__remove_ratio(into, ratio_arg) + return call_ext(AUXMOS, "byond:remove_ratio_hook_ffi")(src, into, ratio_arg) + +/datum/gas_mixture/proc/merge(giver) + return call_ext(AUXMOS, "byond:merge_hook_ffi")(src, giver) + +/datum/gas_mixture/proc/thermal_energy() + return call_ext(AUXMOS, "byond:thermal_energy_hook_ffi")(src) + +/datum/gas_mixture/proc/return_volume() + return call_ext(AUXMOS, "byond:return_volume_hook_ffi")(src) + +/datum/gas_mixture/proc/return_temperature() + return call_ext(AUXMOS, "byond:return_temperature_hook_ffi")(src) + +/datum/gas_mixture/proc/return_pressure() + return call_ext(AUXMOS, "byond:return_pressure_hook_ffi")(src) + +/datum/gas_mixture/proc/total_moles() + return call_ext(AUXMOS, "byond:total_moles_hook_ffi")(src) + +/datum/gas_mixture/proc/set_min_heat_capacity(arg_min) + return call_ext(AUXMOS, "byond:min_heat_cap_hook_ffi")(src, arg_min) + +/datum/gas_mixture/proc/heat_capacity() + return call_ext(AUXMOS, "byond:heat_cap_hook_ffi")(src) + +/datum/gas_mixture/proc/__gasmixture_unregister() + return call_ext(AUXMOS, "byond:unregister_gasmixture_hook_ffi")(src) + +/datum/gas_mixture/proc/__gasmixture_register() + return call_ext(AUXMOS, "byond:register_gasmixture_hook_ffi")(src) + +/proc/process_atmos_callbacks(remaining) + return call_ext(AUXMOS, "byond:atmos_callback_handle_ffi")(remaining) + +/turf/proc/__update_auxtools_turf_adjacency_info() + return call_ext(AUXMOS, "byond:hook_infos_ffi")(src) + +/turf/proc/update_air_ref(flag) + return call_ext(AUXMOS, "byond:hook_register_turf_ffi")(src, flag) + +/datum/controller/subsystem/air/proc/process_turf_equalize_auxtools(remaining) + return call_ext(AUXMOS, "byond:equalize_hook_ffi")(src, remaining) + +/datum/controller/subsystem/air/proc/process_excited_groups_auxtools(remaining) + return call_ext(AUXMOS, "byond:groups_hook_ffi")(src, remaining) + +/datum/controller/subsystem/air/proc/process_turfs_auxtools(remaining) + return call_ext(AUXMOS, "byond:process_turf_hook_ffi")(src, remaining) + +/datum/controller/subsystem/air/proc/finish_turf_processing_auxtools(time_remaining) + return call_ext(AUXMOS, "byond:finish_process_turfs_ffi")(time_remaining) + +/datum/controller/subsystem/air/proc/thread_running() + return call_ext(AUXMOS, "byond:thread_running_hook_ffi")() + +/proc/finalize_gas_refs() + return call_ext(AUXMOS, "byond:finalize_gas_refs_ffi")() + +/datum/controller/subsystem/air/proc/auxtools_update_reactions() + return call_ext(AUXMOS, "byond:update_reactions_ffi")() + +/proc/auxtools_atmos_init(gas_data) + return call_ext(AUXMOS, "byond:hook_init_ffi")(gas_data) + +/proc/_auxtools_register_gas(gas) + return call_ext(AUXMOS, "byond:hook_register_gas_ffi")(gas) diff --git a/code/__byond_version_compat.dm b/code/__byond_version_compat.dm index 08ca94db6c6a..be985a081602 100644 --- a/code/__byond_version_compat.dm +++ b/code/__byond_version_compat.dm @@ -1,28 +1,17 @@ // This file contains defines allowing targeting byond versions newer than the supported //Update this whenever you need to take advantage of more recent byond features -#define MIN_COMPILER_VERSION 514 -#define MIN_COMPILER_BUILD 1556 +#define MIN_COMPILER_VERSION 515 +#define MIN_COMPILER_BUILD 1621 #if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM) //Don't forget to update this part #error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update. -#error You need version 514.1556 or higher -#endif - -#if (DM_VERSION == 514 && DM_BUILD > 1575 && DM_BUILD <= 1577) -#error Your version of BYOND currently has a crashing issue that will prevent you from running Dream Daemon test servers. -#error We require developers to test their content, so an inability to test means we cannot allow the compile. -#error Please consider upgrading to 514.1577 or above. -#endif - -#if (DM_VERSION == 514 && DM_BUILD == 1589) -#warn Warning! Byond 514.1589 has been known to be unstable. Use at your own risk. -#warn Please consider using 514.1588. +#error You need version 515.1621 or higher #endif // Keep savefile compatibilty at minimum supported level #if DM_VERSION >= 515 -/savefile/byond_version = MIN_COMPILER_VERSION +/savefile/byond_version = 514 //TODO: Make this MIN_COMPILER_VERSION before merge #endif // 515 split call for external libraries into call_ext @@ -32,32 +21,37 @@ #define LIBCALL call_ext #endif -// So we want to have compile time guarantees these procs exist on local type, unfortunately 515 killed the .proc/procname syntax so we have to use nameof() +// So we want to have compile time guarantees these methods exist on local type, unfortunately 515 killed the .proc/procname and .verb/verbname syntax so we have to use nameof() +// For the record: GLOBAL_VERB_REF would be useless as verbs can't be global. + #if DM_VERSION < 515 -/// Call by name proc reference, checks if the proc exists on this type or as a global proc + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. #define PROC_REF(X) (.proc/##X) -/// Call by name proc reference, checks if the proc exists on given type or as a global proc +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (.verb/##X) + +/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc #define TYPE_PROC_REF(TYPE, X) (##TYPE.proc/##X) -/// Call by name proc reference, checks if the proc is existing global proc +/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb +#define TYPE_VERB_REF(TYPE, X) (##TYPE.verb/##X) + +/// Call by name proc reference, checks if the proc is an existing global proc #define GLOBAL_PROC_REF(X) (/proc/##X) + #else -/// Call by name proc reference, checks if the proc exists on this type or as a global proc + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. #define PROC_REF(X) (nameof(.proc/##X)) -/// Call by name proc reference, checks if the proc exists on given type or as a global proc -#define TYPE_PROC_REF(TYPE, X) (nameof(##TYPE.proc/##X)) -/// Call by name proc reference, checks if the proc is existing global proc -#define GLOBAL_PROC_REF(X) (/proc/##X) -#endif +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (nameof(.verb/##X)) -// I heard that this was fixed in 1609 (not public currently), but that could be wrong, so keep an eye on this -#if (DM_VERSION == 515 && DM_BUILD < 1609) -/// fcopy will crash on 515 linux if given a non-existant file, instead of returning 0 like on 514 linux or 515 windows -/// var case matches documentation for fcopy. -/world/proc/__fcopy(Src, Dst) - if (!fexists(Src)) - return 0 - return fcopy(Src, Dst) +/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc +#define TYPE_PROC_REF(TYPE, X) (nameof(##TYPE.proc/##X)) +/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb +#define TYPE_VERB_REF(TYPE, X) (nameof(##TYPE.verb/##X)) -#define fcopy(Src, Dst) world.__fcopy(Src, Dst) +/// Call by name proc reference, checks if the proc is an existing global proc +#define GLOBAL_PROC_REF(X) (/proc/##X) #endif diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 419abcd6be70..ee7638ea853d 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -90,16 +90,3 @@ // A reasonable number of maximum overlays an object needs // If you think you need more, rethink it #define MAX_ATOM_OVERLAYS 100 - -#define AUXMOS (world.system_type == MS_WINDOWS ? "auxmos.dll" : __detect_auxmos()) - -/proc/__detect_auxmos() - var/static/auxmos_path - if(!auxmos_path) - if (fexists("./libauxmos.so")) - auxmos_path = "./libauxmos.so" - else if (fexists("[world.GetConfig("env", "HOME")]/.byond/bin/libauxmos.so")) - auxmos_path = "[world.GetConfig("env", "HOME")]/.byond/bin/libauxmos.so" - else - CRASH("Could not find libauxmos.so") - return auxmos_path diff --git a/code/_onclick/hud/credits.dm b/code/_onclick/hud/credits.dm index 0ee063593a8b..e68f12282219 100644 --- a/code/_onclick/hud/credits.dm +++ b/code/_onclick/hud/credits.dm @@ -36,7 +36,7 @@ GLOBAL_LIST_INIT(patrons, world.file2list("[global.config.directory]/patrons.txt if(!C) continue - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(create_credit), C), CREDIT_SPAWN_SPEED * i + (3 * CREDIT_SPAWN_SPEED), TIMER_CLIENT_TIME) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(create_credit), C), CREDIT_SPAWN_SPEED * i + (3 * CREDIT_SPAWN_SPEED), TIMER_CLIENT_TIME) /proc/create_credit(credit) new /atom/movable/screen/credit(null, credit) diff --git a/code/controllers/controller.dm b/code/controllers/controller.dm index e93d9a02fbaf..71583d1c9e29 100644 --- a/code/controllers/controller.dm +++ b/code/controllers/controller.dm @@ -1,7 +1,5 @@ /datum/controller var/name - // The object used for the clickable stat() button. - var/obj/effect/statclick/statclick /datum/controller/proc/Initialize() diff --git a/code/controllers/globals.dm b/code/controllers/globals.dm index ba6603b102cf..0cf0f21cb0ca 100644 --- a/code/controllers/globals.dm +++ b/code/controllers/globals.dm @@ -13,9 +13,15 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars) GLOB = src var/datum/controller/exclude_these = new - gvars_datum_in_built_vars = exclude_these.vars + list(NAMEOF(src, gvars_datum_protected_varlist), NAMEOF(src, gvars_datum_in_built_vars), NAMEOF(src, gvars_datum_init_order)) - QDEL_IN(exclude_these, 0) //signal logging isn't ready - + // I know this is dumb but the nested vars list hangs a ref to the datum. This fixes that + var/list/controller_vars = exclude_these.vars.Copy() + controller_vars["vars"] = null + gvars_datum_in_built_vars = controller_vars + list(NAMEOF(src, gvars_datum_protected_varlist), NAMEOF(src, gvars_datum_in_built_vars), NAMEOF(src, gvars_datum_init_order)) + +#if MIN_COMPILER_VERSION >= 515 && MIN_COMPILER_BUILD > 1627 + #warn datum.vars hanging a ref should now be fixed, there should be no reason to remove the vars list from our controller's vars list anymore +#endif + QDEL_IN(exclude_these, 0) //signal logging isn't ready log_world("[vars.len - gvars_datum_in_built_vars.len] global variables") Initialize() diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 56b50beee9ce..2f325a1b2322 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -9,13 +9,13 @@ SUBSYSTEM_DEF(air) var/cost_turfs = 0 var/cost_groups = 0 var/cost_highpressure = 0 - var/cost_deferred_airs var/cost_hotspots = 0 var/cost_post_process = 0 var/cost_superconductivity = 0 var/cost_pipenets = 0 var/cost_rebuilds = 0 var/cost_atmos_machinery = 0 + var/cost_atmos_machinery_air = 0 var/cost_equalize = 0 var/thread_wait_ticks = 0 var/cur_thread_wait_ticks = 0 @@ -31,8 +31,6 @@ SUBSYSTEM_DEF(air) var/list/rebuild_queue = list() //Subservient to rebuild queue var/list/expansion_queue = list() - var/list/deferred_airs = list() - var/max_deferred_airs = 0 ///List of all currently processing atmos machinery that doesn't interact with the air around it var/list/obj/machinery/atmos_machinery = list() @@ -61,7 +59,7 @@ SUBSYSTEM_DEF(air) var/log_explosive_decompression = TRUE // If things get spammy, admemes can turn this off. - var/planet_equalize_enabled = FALSE + var/planet_equalize_enabled = TRUE // Max number of turfs equalization will grab. var/equalize_turf_limit = 30 // Max number of turfs to look for a space turf, and max number of turfs that will be decompressed. @@ -75,7 +73,6 @@ SUBSYSTEM_DEF(air) // Excited group processing will try to equalize groups with total pressure difference less than this amount. var/excited_group_pressure_goal = 1 - /datum/controller/subsystem/air/stat_entry(msg) msg += "C:{" msg += "HP:[round(cost_highpressure,1)]|" @@ -83,7 +80,8 @@ SUBSYSTEM_DEF(air) msg += "HE:[round(heat_process_time(),1)]|" msg += "SC:[round(cost_superconductivity,1)]|" msg += "PN:[round(cost_pipenets,1)]|" - msg += "AM:[round(cost_atmos_machinery,1)]" + msg += "AM:[round(cost_atmos_machinery,1)]|" + msg += "AA:[round(cost_atmos_machinery_air,1)]" msg += "} " msg += "TC:{" msg += "AT:[round(cost_turfs,1)]|" @@ -92,14 +90,13 @@ SUBSYSTEM_DEF(air) msg += "PO:[round(cost_post_process,1)]" msg += "}" msg += "TH:[round(thread_wait_ticks,1)]|" - msg += "HS:[hotspots.len]|" - msg += "PN:[networks.len]|" - msg += "HP:[high_pressure_delta.len]|" + msg += "HS:[length(hotspots)]|" + msg += "PN:[length(networks)]|" + msg += "HP:[length(high_pressure_delta)]|" msg += "HT:[high_pressure_turfs]|" msg += "LT:[low_pressure_turfs]|" msg += "ET:[num_equalize_processed]|" msg += "GT:[num_group_turfs_processed]|" - msg += "DF:[max_deferred_airs]|" msg += "GA:[get_amt_gas_mixes()]|" msg += "MG:[get_max_gas_mixes()]" return ..() @@ -115,8 +112,6 @@ SUBSYSTEM_DEF(air) /datum/controller/subsystem/air/proc/extools_update_ssair() -/datum/controller/subsystem/air/proc/auxtools_update_reactions() - /proc/reset_all_air() SSair.can_fire = FALSE message_admins("Air reset begun.") @@ -126,22 +121,7 @@ SUBSYSTEM_DEF(air) message_admins("Air reset done.") SSair.can_fire = TRUE -/datum/controller/subsystem/air/proc/thread_running() - return FALSE - -/proc/fix_corrupted_atmos() - -/datum/admins/proc/fixcorruption() - set category = "Debug" - set desc="Fixes air that has weird NaNs (-1.#IND and such). Hopefully." - set name="Fix Infinite Air" - fix_corrupted_atmos() - /datum/controller/subsystem/air/fire(resumed = 0) - if(thread_running()) - pause() - return - var/timer = TICK_USAGE_REAL //Rebuilds can happen at any time, so this needs to be done outside of the normal system @@ -155,35 +135,34 @@ SUBSYSTEM_DEF(air) if(state != SS_RUNNING) return - if(currentpart == SSAIR_PIPENETS || !resumed) + if(currentpart == SSAIR_ACTIVETURFS) timer = TICK_USAGE_REAL - process_pipenets(resumed) - cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + process_turfs(resumed) + cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) if(state != SS_RUNNING) return resumed = 0 - currentpart = SSAIR_ATMOSMACHINERY - // This is only machinery like filters, mixers that don't interact with air - if(currentpart == SSAIR_ATMOSMACHINERY) + + currentpart = SSAIR_EXCITEDGROUPS + + if(currentpart == SSAIR_EXCITEDGROUPS) timer = TICK_USAGE_REAL - process_atmos_machinery(resumed) - cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + process_excited_groups(resumed) + cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) if(state != SS_RUNNING) return resumed = 0 - currentpart = SSAIR_HIGHPRESSURE + currentpart = SSAIR_EQUALIZE - if(currentpart == SSAIR_HIGHPRESSURE) + if(currentpart == SSAIR_EQUALIZE) timer = TICK_USAGE_REAL - process_high_pressure_delta(resumed) - cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + process_turf_equalize(resumed) + cost_equalize = MC_AVERAGE(cost_equalize, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) if(state != SS_RUNNING) return resumed = 0 currentpart = SSAIR_FINALIZE_TURFS - // This literally just waits for the turf processing thread to finish, doesn't do anything else. - // this is necessary cause the next step after this interacts with the air--we get consistency - // issues if we don't wait for it, disappearing gases etc. + if(currentpart == SSAIR_FINALIZE_TURFS) finish_turf_processing(resumed) if(state != SS_RUNNING) @@ -192,19 +171,40 @@ SUBSYSTEM_DEF(air) resumed = 0 thread_wait_ticks = MC_AVERAGE(thread_wait_ticks, cur_thread_wait_ticks) cur_thread_wait_ticks = 0 - currentpart = SSAIR_DEFERRED_AIRS - if(currentpart == SSAIR_DEFERRED_AIRS) + currentpart = SSAIR_PIPENETS + + if(currentpart == SSAIR_PIPENETS || !resumed) + timer = TICK_USAGE_REAL + process_pipenets(resumed) + cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + if(state != SS_RUNNING) + return + resumed = 0 + currentpart = SSAIR_ATMOSMACHINERY + + // This is only machinery like filters, mixers that don't interact with air + if(currentpart == SSAIR_ATMOSMACHINERY) + timer = TICK_USAGE_REAL + process_atmos_machinery(resumed) + cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + if(state != SS_RUNNING) + return + resumed = 0 + currentpart = SSAIR_HIGHPRESSURE + + if(currentpart == SSAIR_HIGHPRESSURE) timer = TICK_USAGE_REAL - process_deferred_airs(resumed) - cost_deferred_airs = MC_AVERAGE(cost_deferred_airs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + process_high_pressure_delta(resumed) + cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) if(state != SS_RUNNING) return resumed = 0 currentpart = SSAIR_ATMOSMACHINERY_AIR + if(currentpart == SSAIR_ATMOSMACHINERY_AIR) timer = TICK_USAGE_REAL process_atmos_air_machinery(resumed) - cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) + cost_atmos_machinery_air = MC_AVERAGE(cost_atmos_machinery_air, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) if(state != SS_RUNNING) return resumed = 0 @@ -218,6 +218,7 @@ SUBSYSTEM_DEF(air) return resumed = 0 currentpart = heat_enabled ? SSAIR_TURF_CONDUCTION : SSAIR_ACTIVETURFS + // Heat -- slow and of questionable usefulness. Off by default for this reason. Pretty cool, though. if(currentpart == SSAIR_TURF_CONDUCTION) timer = TICK_USAGE_REAL @@ -228,46 +229,6 @@ SUBSYSTEM_DEF(air) return resumed = 0 currentpart = SSAIR_ACTIVETURFS - // This simply starts the turf thread. It runs in the background until the FINALIZE_TURFS step, at which point it's waited for. - // This also happens to do all the commented out stuff below, all in a single separate thread. This is mostly so that the - // waiting is consistent. - if(currentpart == SSAIR_ACTIVETURFS) - timer = TICK_USAGE_REAL - process_turfs(resumed) - cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - /* - // Monstermos and/or Putnamos--making large pressure deltas move faster - if(currentpart == SSAIR_EQUALIZE) - timer = TICK_USAGE_REAL - process_turf_equalize(resumed) - cost_equalize = MC_AVERAGE(cost_equalize, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - currentpart = SSAIR_EXCITEDGROUPS - // Making small pressure deltas equalize immediately so they don't process anymore - if(currentpart == SSAIR_EXCITEDGROUPS) - timer = TICK_USAGE_REAL - process_excited_groups(resumed) - cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - currentpart = SSAIR_TURF_POST_PROCESS - // Quick multithreaded "should we display/react?" checks followed by finishing those up before the next step - if(currentpart == SSAIR_TURF_POST_PROCESS) - timer = TICK_USAGE_REAL - post_process_turfs(resumed) - cost_post_process = MC_AVERAGE(cost_post_process, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - currentpart = SSAIR_HOTSPOTS - */ - currentpart = SSAIR_PIPENETS /datum/controller/subsystem/air/Recover() hotspots = SSair.hotspots @@ -280,7 +241,6 @@ SUBSYSTEM_DEF(air) gas_reactions = SSair.gas_reactions high_pressure_delta = SSair.high_pressure_delta currentrun = SSair.currentrun - deferred_airs = SSair.deferred_airs string_mixes = SSair.string_mixes /** @@ -425,31 +385,6 @@ SUBSYSTEM_DEF(air) if (MC_TICK_CHECK) return -/datum/controller/subsystem/air/proc/process_deferred_airs(resumed = 0) - max_deferred_airs = max(deferred_airs.len,max_deferred_airs) - while(deferred_airs.len) - var/list/cur_op = deferred_airs[deferred_airs.len] - deferred_airs.len-- - var/datum/gas_mixture/air1 - var/datum/gas_mixture/air2 - if(isopenturf(cur_op[1])) - var/turf/open/T = cur_op[1] - air1 = T.return_air() - else - air1 = cur_op[1] - if(isopenturf(cur_op[2])) - var/turf/open/T = cur_op[2] - air2 = T.return_air() - else - air2 = cur_op[2] - if(istype(cur_op[3], /datum/callback)) - var/datum/callback/cb = cur_op[3] - cb.Invoke(air1, air2) - else - air1.transfer_ratio_to(air2, cur_op[3]) - if(MC_TICK_CHECK) - return - /datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0) var/seconds = wait * 0.1 if (!resumed) @@ -512,64 +447,23 @@ SUBSYSTEM_DEF(air) if(MC_TICK_CHECK) return + /datum/controller/subsystem/air/proc/process_turf_equalize(resumed = 0) - if(process_turf_equalize_auxtools(resumed,MC_TICK_REMAINING_MS)) + if(process_turf_equalize_auxtools(MC_TICK_REMAINING_MS)) pause() - /* - //cache for sanic speed - var/fire_count = times_fired - if (!resumed) - src.currentrun = active_turfs.Copy() - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - while(currentrun.len) - var/turf/open/T = currentrun[currentrun.len] - currentrun.len-- - if (T) - T.equalize_pressure_in_zone(fire_count) - //equalize_pressure_in_zone(T, fire_count) - if (MC_TICK_CHECK) - return - */ /datum/controller/subsystem/air/proc/process_turfs(resumed = 0) - if(process_turfs_auxtools(resumed,MC_TICK_REMAINING_MS)) + if(process_turfs_auxtools(MC_TICK_REMAINING_MS)) pause() - /* - //cache for sanic speed - var/fire_count = times_fired - if (!resumed) - src.currentrun = active_turfs.Copy() - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - while(currentrun.len) - var/turf/open/T = currentrun[currentrun.len] - currentrun.len-- - if (T) - T.process_cell(fire_count) - if (MC_TICK_CHECK) - return - */ /datum/controller/subsystem/air/proc/process_excited_groups(resumed = 0) - if(process_excited_groups_auxtools(resumed,MC_TICK_REMAINING_MS)) + if(process_excited_groups_auxtools(MC_TICK_REMAINING_MS)) pause() /datum/controller/subsystem/air/proc/finish_turf_processing(resumed = 0) if(finish_turf_processing_auxtools(MC_TICK_REMAINING_MS)) pause() -/datum/controller/subsystem/air/proc/post_process_turfs(resumed = 0) - if(post_process_turfs_auxtools(resumed,MC_TICK_REMAINING_MS)) - pause() - -/datum/controller/subsystem/air/proc/finish_turf_processing_auxtools() -/datum/controller/subsystem/air/proc/process_turfs_auxtools() -/datum/controller/subsystem/air/proc/post_process_turfs_auxtools() -/datum/controller/subsystem/air/proc/process_turf_equalize_auxtools() -/datum/controller/subsystem/air/proc/process_excited_groups_auxtools() -/datum/controller/subsystem/air/proc/get_amt_gas_mixes() -/datum/controller/subsystem/air/proc/get_max_gas_mixes() /datum/controller/subsystem/air/proc/turf_process_time() /datum/controller/subsystem/air/proc/heat_process_time() @@ -607,8 +501,8 @@ SUBSYSTEM_DEF(air) CHECK_TICK //this can't be done with setup_atmos_machinery() because -// all atmos machinery has to initalize before the first -// pipenet can be built. +//all atmos machinery has to initalize before the first +//pipenet can be built. /datum/controller/subsystem/air/proc/setup_pipenets() for (var/obj/machinery/atmospherics/AM in atmos_machinery) var/list/targets = AM.get_rebuild_targets() @@ -642,55 +536,19 @@ SUBSYSTEM_DEF(air) return pipe_init_dirs_cache[type]["[dir]"] -// Once we've got __auxtools_parse_gas_string, replace this with the original preprocess_gas_string (commented out, below); -// there's no need to cache because auxtools can parse strings in an actually reasonable amount of time. -// Atmosphere datums will also require some changes to put them back how they were before. I am sorry -/datum/controller/subsystem/air/proc/get_gas_string_mix(gas_string) +/datum/controller/subsystem/air/proc/preprocess_gas_string(gas_string) if(!string_mixes) generate_atmos() - - var/datum/gas_mixture/ret_mix = string_mixes[gas_string] - if(ret_mix) - return ret_mix - - ret_mix = new(CELL_VOLUME) - var/list/gas_list = params2list(gas_string) - - if(gas_list["TEMP"]) - var/temp = text2num(gas_list["TEMP"]) - gas_list -= "TEMP" - if(!isnum(temp) || temp < TCMB) - temp = TCMB - ret_mix.set_temperature(temp) - ret_mix.clear() - for(var/id in gas_list) - ret_mix.set_moles(id, text2num(gas_list[id])) - ret_mix.mark_immutable() - - string_mixes[gas_string] = ret_mix - return ret_mix + if(!string_mixes[gas_string]) + return gas_string + var/datum/atmosphere/mix = string_mixes[gas_string] + return mix.gas_string /datum/controller/subsystem/air/proc/generate_atmos() string_mixes = list() for(var/T in subtypesof(/datum/atmosphere)) - var/datum/atmosphere/atmostype = new T - string_mixes[initial(atmostype.id)] = atmostype.gasmix - qdel(atmostype) - -// Saved for when we switch to auxmos 2.0 and gain access to __auxtools_parse_gas_string -// /datum/controller/subsystem/air/proc/preprocess_gas_string(gas_string) -// if(!string_mixes) -// generate_atmos() -// if(!string_mixes[gas_string]) -// return gas_string -// var/datum/atmosphere/mix = string_mixes[gas_string] -// return mix.gas_string - -// /datum/controller/subsystem/air/proc/generate_atmos() -// string_mixes = list() -// for(var/T in subtypesof(/datum/atmosphere)) -// var/datum/atmosphere/atmostype = T -// string_mixes[initial(atmostype.id)] = new atmostype + var/datum/atmosphere/atmostype = T + string_mixes[initial(atmostype.id)] = new atmostype #undef SSAIR_EXCITEDGROUPS diff --git a/code/controllers/subsystem/callback.dm b/code/controllers/subsystem/callback.dm index ecc65760f4e8..49820236ebc0 100644 --- a/code/controllers/subsystem/callback.dm +++ b/code/controllers/subsystem/callback.dm @@ -4,11 +4,6 @@ SUBSYSTEM_DEF(callbacks) wait = 1 priority = FIRE_PRIORITY_CALLBACKS -/proc/process_atmos_callbacks() - SScallbacks.can_fire = 0 - SScallbacks.flags |= SS_NO_FIRE - CRASH("Auxtools not found! Callback subsystem shutting itself off.") - /datum/controller/subsystem/callbacks/fire() if(process_atmos_callbacks(MC_TICK_REMAINING_MS)) pause() diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index ae0074e9fb5b..f163553f5f9b 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -140,7 +140,7 @@ SUBSYSTEM_DEF(explosions) else continue - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(wipe_color_and_text), wipe_colours), 100) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(wipe_color_and_text), wipe_colours), 100) /proc/wipe_color_and_text(list/atom/wiping) for(var/i in wiping) diff --git a/code/controllers/subsystem/time_track.dm b/code/controllers/subsystem/time_track.dm index 8dd0696af2fa..d1f6b5402820 100644 --- a/code/controllers/subsystem/time_track.dm +++ b/code/controllers/subsystem/time_track.dm @@ -73,12 +73,9 @@ SUBSYSTEM_DEF(time_track) "air_pipenets_cost", "air_rebuilds_cost", "air_equalize_cost", - "air_post_process_cost", - "air_deferred_airs_cost", "air_hotspot_count", "air_network_count", "air_delta_count", - "air_deferred_airs_count", "air_high_pressure_turfs", "air_low_pressure_turfs", "air_gasmix_count" @@ -143,12 +140,9 @@ SUBSYSTEM_DEF(time_track) SSair.cost_pipenets, SSair.cost_rebuilds, SSair.cost_equalize, - SSair.cost_post_process, - SSair.cost_deferred_airs, length(SSair.hotspots), length(SSair.networks), length(SSair.high_pressure_delta), - length(SSair.deferred_airs), SSair.high_pressure_turfs, SSair.low_pressure_turfs, #ifdef SENDMAPS_PROFILE diff --git a/code/datums/atmosphere/_atmosphere.dm b/code/datums/atmosphere/_atmosphere.dm index 29e7798bd6d7..0652ef5560f6 100644 --- a/code/datums/atmosphere/_atmosphere.dm +++ b/code/datums/atmosphere/_atmosphere.dm @@ -1,8 +1,6 @@ /datum/atmosphere var/id - /// The atmosphere's gasmix. No longer a gas string, because params2list sucks. - /// When auxmos is updated, change this back to a string and use __auxtools_parse_gas_string. - var/datum/gas_mixture/gasmix + var/gas_string var/list/base_gases // A list of gases to always have var/list/normal_gases // A list of allowed gases:base_amount @@ -16,14 +14,15 @@ var/maximum_temp /datum/atmosphere/New() - generate_gas() + generate_gas_string() -/datum/atmosphere/proc/generate_gas() +/datum/atmosphere/proc/generate_gas_string() var/target_pressure = rand(minimum_pressure, maximum_pressure) var/pressure_scalar = target_pressure / maximum_pressure // First let's set up the gasmix and base gases for this template - gasmix = new(CELL_VOLUME) + // We make the string from a gasmix in this proc because gases need to calculate their pressure + var/datum/gas_mixture/gasmix = new gasmix.set_temperature(rand(minimum_temp, maximum_temp)) for(var/i in base_gases) gasmix.set_moles(i, base_gases[i]) @@ -51,4 +50,9 @@ while(gasmix.return_pressure() > target_pressure) gasmix.set_moles(gastype, gasmix.get_moles(gastype) - (gasmix.get_moles(gastype) * 0.1)) gasmix.set_moles(gastype, FLOOR(gasmix.get_moles(gastype), 0.1)) - gasmix.mark_immutable() + // Now finally lets make that string + var/list/gas_string_builder = list() + for(var/i in gasmix.get_gases()) + gas_string_builder += "[GLOB.gas_data.ids[i]]=[gasmix.get_moles(i)]" + gas_string_builder += "TEMP=[gasmix.return_temperature()]" + gas_string = gas_string_builder.Join(";") diff --git a/code/datums/callback.dm b/code/datums/callback.dm index 4fa2078f152b..cdf756b746d9 100644 --- a/code/datums/callback.dm +++ b/code/datums/callback.dm @@ -29,22 +29,21 @@ * ### global proc while in another global proc: * .procname * - * `CALLBACK(GLOBAL_PROC, .some_proc_here)` + * `CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(some_proc_here))` * * ### proc defined on current(src) object (when in a /proc/ and not an override) OR overridden at src or any of it's parents: * .procname * - * `CALLBACK(src, .some_proc_here)` + * `CALLBACK(src, PROC_REF(some_proc_here))` * * ### when the above doesn't apply: * PROC_REF(procname) * * `CALLBACK(src, PROC_REF(some_proc_here))` * + * ### proc defined on a parent of a some type * - * proc defined on a parent of a some type - * - * `TYPE_PROC_REF(/some/type, some_proc_here)` + * `CALLBACK(src, TYPE_PROC_REF(/some/type, some_proc_here))` * * Otherwise you must always provide the full typepath of the proc (/type/of/thing/proc/procname) */ @@ -117,12 +116,6 @@ if (!object) return -#if DM_VERSION <= 514 - if(istext(object) && object != GLOBAL_PROC) - to_chat(usr, "[object] may be an external library. Calling external libraries is disallowed.", confidential = TRUE) - return -#endif - var/list/calling_arguments = arguments if (length(args)) if (length(arguments)) @@ -158,12 +151,6 @@ if (!object) return -#if DM_VERSION <= 514 - if(istext(object) && object != GLOBAL_PROC) - to_chat(usr, "[object] may be an external library. Calling external libraries is disallowed.", confidential = TRUE) - return -#endif - var/list/calling_arguments = arguments if (length(args)) if (length(arguments)) diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 73aab2fb8ca8..e2f478ba7834 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -40,11 +40,6 @@ /// Datum level flags var/datum_flags = NONE - /// A cached version of our \ref - /// The brunt of \ref costs are in creating entries in the string tree (a tree of immutable strings) - /// This avoids doing that more then once per datum by ensuring ref strings always have a reference to them after they're first pulled - var/cached_ref - /// A weak reference to another datum var/datum/weakref/weak_reference diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index 8cb9f50008f4..4b0afce14b47 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -479,7 +479,7 @@ if(prob(85) || (istype(mind_check) && mind_check.mind)) return - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(to_chat), quirk_holder, "You make eye contact with [A]."), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, "You make eye contact with [A]."), 3) /datum/quirk/social_anxiety/proc/eye_contact(datum/source, mob/living/other_mob, triggering_examiner) SIGNAL_HANDLER @@ -504,7 +504,7 @@ msg += "causing you to freeze up!" SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "anxiety_eyecontact", /datum/mood_event/anxiety_eyecontact) - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(to_chat), quirk_holder, "[msg]"), 3) // so the examine signal has time to fire and this will print after + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), quirk_holder, "[msg]"), 3) // so the examine signal has time to fire and this will print after return COMSIG_BLOCK_EYECONTACT /datum/mood_event/anxiety_eyecontact diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index a18550033d04..81cb1908ce89 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -35,7 +35,7 @@ /obj/machinery/door/firedoor/Initialize() . = ..() - air_update_turf(1) + air_update_turf(TRUE) CalculateAffectingAreas() /obj/machinery/door/firedoor/examine(mob/user) diff --git a/code/game/machinery/telecomms/machines/broadcaster.dm b/code/game/machinery/telecomms/machines/broadcaster.dm index ce44158cdcc8..f9cbc692e050 100644 --- a/code/game/machinery/telecomms/machines/broadcaster.dm +++ b/code/game/machinery/telecomms/machines/broadcaster.dm @@ -49,7 +49,7 @@ GLOBAL_VAR_INIT(message_delay, 0) // To make sure restarting the recentmessages if(!GLOB.message_delay) GLOB.message_delay = TRUE - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(end_message_delay)), 1 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(end_message_delay)), 1 SECONDS) /* --- Do a snazzy animation! --- */ flick("broadcaster_send", src) diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index d53e266d28cf..cfd5b8ba34b9 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -113,8 +113,8 @@ LAZYINITLIST(atmos_destination.atmos_adjacent_turfs) if(atmos_source.atmos_adjacent_turfs[atmos_destination] || atmos_destination.atmos_adjacent_turfs[atmos_source]) //Already linked! return FALSE - atmos_source.atmos_adjacent_turfs[atmos_destination] = TRUE - atmos_destination.atmos_adjacent_turfs[atmos_source] = TRUE + atmos_source.atmos_adjacent_turfs[atmos_destination] = ATMOS_ADJACENT_ANY + atmos_destination.atmos_adjacent_turfs[atmos_source] = ATMOS_ADJACENT_ANY atmos_source.air_update_turf(FALSE) atmos_destination.air_update_turf(FALSE) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index de636902eb52..32d923eef985 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -31,14 +31,14 @@ return if(target == user) playsound(src, islist(apply_sounds) ? pick(apply_sounds) : apply_sounds, 25) - if(!do_mob(user, target, self_delay, extra_checks=CALLBACK(target, /mob/living/proc/can_inject, user, TRUE))) + if(!do_mob(user, target, self_delay, extra_checks=CALLBACK(target, TYPE_PROC_REF(/mob/living, can_inject), user, TRUE))) return if(!silent) user.visible_message("[user] starts to apply \the [src] on [user.p_them()]self...", "You begin applying \the [src] on yourself...") else if(other_delay) playsound(src, islist(apply_sounds) ? pick(apply_sounds) : apply_sounds, 25) - if(!do_mob(user, target, other_delay, extra_checks=CALLBACK(target, /mob/living/proc/can_inject, user, TRUE))) + if(!do_mob(user, target, other_delay, extra_checks=CALLBACK(target, TYPE_PROC_REF(/mob/living, can_inject), user, TRUE))) return if(!silent) user.visible_message("[user] starts to apply \the [src] on [target].", "You begin applying \the [src] on [target]...") diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index a976c49fb45c..f53674195d42 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1028,7 +1028,7 @@ if(!M.stat && !isAI(M)) // Checks to make sure whoever's getting shaken is alive/not the AI // Short delay to match up with the explosion sound // Shakes player camera 2 squares for 1 second. - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(shake_camera), M, 2, 1), 0.8 SECONDS) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(shake_camera), M, 2, 1), 0.8 SECONDS) else to_chat(user, "Nothing happens.") diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index 9e201e29b108..fa964a55619b 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -94,7 +94,7 @@ density = FALSE door_opened = TRUE layer = OPEN_DOOR_LAYER - air_update_turf(1) + air_update_turf(TRUE) update_appearance() isSwitchingStates = FALSE @@ -115,7 +115,7 @@ set_opacity(TRUE) door_opened = FALSE layer = initial(layer) - air_update_turf(1) + air_update_turf(TRUE) update_appearance() isSwitchingStates = FALSE diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index 294976f72fc6..89ec5a384320 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -111,4 +111,4 @@ var/atom/oldloc = loc . = ..() if (oldloc) - oldloc.air_update_turf(1) + oldloc.air_update_turf(TRUE) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index d23ef8bca223..49c3823cf1ce 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -58,7 +58,7 @@ if(reinf && anchored) state = RWINDOW_SECURE - air_update_turf(1) + air_update_turf(TRUE) if(fulltile) setDir() @@ -308,12 +308,12 @@ return TRUE /obj/structure/window/proc/after_rotation(mob/user,rotation_type) - air_update_turf(TRUE, FALSE) + air_update_turf(TRUE) add_fingerprint(user) /obj/structure/window/Destroy() density = FALSE - air_update_turf(1) + air_update_turf(TRUE) update_nearby_icons() return ..() diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index 13e8ae7877c7..b7daf1547355 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -162,7 +162,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( return W /turf/open/ChangeTurf(path, list/new_baseturfs, flags) //Resist the temptation to make this default to keeping air. - if ((flags & CHANGETURF_INHERIT_AIR) && ispath(path, /turf/open)) + //don't + if(!SSair.initialized) + return ..() + if ((flags & CHANGETURF_INHERIT_AIR) && ispath(path, /turf/open) && air) var/datum/gas_mixture/stashed_air = new() stashed_air.copy_from(air) . = ..() @@ -170,25 +173,23 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( QDEL_NULL(stashed_air) return var/turf/open/newTurf = . - var/turf_fire_ref if(turf_fire) if(isgroundlessturf(newTurf)) QDEL_NULL(turf_fire) else - turf_fire_ref = turf_fire - newTurf.turf_fire = turf_fire_ref + newTurf.turf_fire = turf_fire newTurf.air.copy_from(stashed_air) - update_air_ref(planetary_atmos ? 1 : 2) + update_air_ref(planetary_atmos ? AIR_REF_PLANETARY_TURF : AIR_REF_OPEN_TURF) QDEL_NULL(stashed_air) else if(turf_fire) QDEL_NULL(turf_fire) if(ispath(path, /turf/open)) . = ..() - if(!istype(air,/datum/gas_mixture)) + if(!istype(air, /datum/gas_mixture)) Initalize_Atmos(0) else - update_air_ref(-1) + update_air_ref(AIR_REF_CLOSED_TURF) . = ..() diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 0e4d5ae8f842..27a3225dbb03 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -158,11 +158,10 @@ baseturfs = /turf/open/indestructible/airblock /turf/open/Initalize_Atmos(times_fired) - if(!blocks_air) - if(!istype(air,/datum/gas_mixture/turf)) - air = new(2500,src) - air.copy_from_turf(src) - update_air_ref(planetary_atmos ? 1 : 2) + if(!istype(air,/datum/gas_mixture/turf)) + air = new(2500, src) + air.copy_from_turf(src) + update_air_ref(planetary_atmos ? AIR_REF_PLANETARY_TURF : AIR_REF_OPEN_TURF) update_visuals() diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm index 5b08beb1c671..0784f2a140a7 100644 --- a/code/game/turfs/open/space/space.dm +++ b/code/game/turfs/open/space/space.dm @@ -40,7 +40,7 @@ if(!space_gas) space_gas = new air = space_gas - update_air_ref(0) + update_air_ref(AIR_REF_SPACE_TURF) vis_contents.Cut() //removes inherited overlays visibilityChanged() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 4202be74b347..4ed4b47297a2 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -155,7 +155,7 @@ GLOBAL_LIST_EMPTY(created_baseturf_lists) var/turf/open/O = src __auxtools_update_turf_temp_info(isspaceturf(get_z_base_turf()) && !O.planetary_atmos) else - update_air_ref(-1) + update_air_ref(AIR_REF_CLOSED_TURF) __auxtools_update_turf_temp_info(isspaceturf(get_z_base_turf())) return INITIALIZE_HINT_NORMAL diff --git a/code/game/world.dm b/code/game/world.dm index aae1ea9d6307..57b925e2973f 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -29,9 +29,6 @@ GLOBAL_VAR(restart_counter) * All atoms in both compiled and uncompiled maps are initialized() */ /world/New() - //Keep the auxtools stuff at the top - AUXTOOLS_CHECK(AUXMOS) - log_world("World loaded at [time_stamp()]!") SSmetrics.world_init_time = REALTIMEOFDAY // Important @@ -277,17 +274,15 @@ GLOBAL_VAR(restart_counter) log_world("World rebooted at [time_stamp()]") shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss. - AUXTOOLS_SHUTDOWN(AUXMOS) ..() #endif //ifdef UNIT_TESTS /world/Del() shutdown_logging() // makes sure the thread is closed before end, else we terminate - AUXTOOLS_SHUTDOWN(AUXMOS) var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") if (debug_server) - call(debug_server, "auxtools_shutdown")() + LIBCALL(debug_server, "auxtools_shutdown")() ..() /world/proc/update_status() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 986399d63299..0539dca13e25 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -204,7 +204,6 @@ GLOBAL_PROTECT(admin_verbs_debug) /client/proc/display_sendmaps, #endif /datum/admins/proc/create_or_modify_area, - /datum/admins/proc/fixcorruption, /datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */ /client/proc/spawn_outpost, /* Allows admins to spawn a new outpost. */ /datum/admins/proc/open_borgopanel, diff --git a/code/modules/admin/view_variables/mass_edit_variables.dm b/code/modules/admin/view_variables/mass_edit_variables.dm index 14b703cd09b3..a2ade649c14d 100644 --- a/code/modules/admin/view_variables/mass_edit_variables.dm +++ b/code/modules/admin/view_variables/mass_edit_variables.dm @@ -67,7 +67,7 @@ if(default == VV_NUM) var/dir_text = "" - if(var_value > 0 && var_value < 16) + if(var_value > 0 && var_value < 32) if(var_value & 1) dir_text += "NORTH" if(var_value & 2) @@ -76,6 +76,10 @@ dir_text += "EAST" if(var_value & 8) dir_text += "WEST" + if(var_value & 16) + dir_text += "UP" + if(var_value & 32) + dir_text += "DOWN" if(dir_text) to_chat(src, "If a direction, direction is: [dir_text]", confidential = TRUE) diff --git a/code/modules/admin/view_variables/modify_variables.dm b/code/modules/admin/view_variables/modify_variables.dm index 91a4e4630185..6c1730746b32 100644 --- a/code/modules/admin/view_variables/modify_variables.dm +++ b/code/modules/admin/view_variables/modify_variables.dm @@ -208,7 +208,7 @@ GLOBAL_PROTECT(VVpixelmovement) if(default == VV_NUM) var/dir_text = "" var/tdir = variable - if(tdir > 0 && tdir < 16) + if(tdir > 0 && tdir < 32) if(tdir & 1) dir_text += "NORTH" if(tdir & 2) @@ -217,6 +217,10 @@ GLOBAL_PROTECT(VVpixelmovement) dir_text += "EAST" if(tdir & 8) dir_text += "WEST" + if(tdir & 16) + dir_text += "UP" + if(tdir & 32) + dir_text += "DOWN" if(dir_text) to_chat(usr, "If a direction, direction is: [dir_text]", confidential = TRUE) @@ -330,7 +334,7 @@ GLOBAL_PROTECT(VVpixelmovement) if(default == VV_NUM) var/dir_text = "" - if(var_value > 0 && var_value < 16) + if(var_value > 0 && var_value < 32) if(var_value & 1) dir_text += "NORTH" if(var_value & 2) @@ -339,6 +343,10 @@ GLOBAL_PROTECT(VVpixelmovement) dir_text += "EAST" if(var_value & 8) dir_text += "WEST" + if(var_value & 16) + dir_text += "UP" + if(var_value & 32) + dir_text += "DOWN" if(dir_text) to_chat(src, "If a direction, direction is: [dir_text]", confidential = TRUE) diff --git a/code/modules/antagonists/abductor/equipment/glands/plasma.dm b/code/modules/antagonists/abductor/equipment/glands/plasma.dm index a3d45b11b99d..a989d56aa3ef 100644 --- a/code/modules/antagonists/abductor/equipment/glands/plasma.dm +++ b/code/modules/antagonists/abductor/equipment/glands/plasma.dm @@ -9,7 +9,7 @@ /obj/item/organ/heart/gland/plasma/activate() to_chat(owner, "You feel bloated.") - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(to_chat), owner, "A massive stomachache overcomes you."), 150) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), owner, "A massive stomachache overcomes you."), 150) addtimer(CALLBACK(src, PROC_REF(vomit_plasma)), 200) /obj/item/organ/heart/gland/plasma/proc/vomit_plasma() diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm index 9fa04c7b6754..31401dab8bb6 100644 --- a/code/modules/antagonists/blob/structures/_blob.dm +++ b/code/modules/antagonists/blob/structures/_blob.dm @@ -32,7 +32,7 @@ setDir(pick(GLOB.cardinals)) update_appearance() if(atmosblock) - air_update_turf(1) + air_update_turf(TRUE) ConsumeTile() /obj/structure/blob/proc/creation_action() //When it's created by the overmind, do this. @@ -41,7 +41,7 @@ /obj/structure/blob/Destroy() if(atmosblock) atmosblock = FALSE - air_update_turf(1) + air_update_turf(TRUE) if(overmind) overmind.blobs_legit -= src //if it was in the legit blobs list, it isn't now GLOB.blobs -= src //it's no longer in the all blobs list either diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm index 10a6125d152d..0c070e8e423f 100644 --- a/code/modules/antagonists/cult/cult_comms.dm +++ b/code/modules/antagonists/cult/cult_comms.dm @@ -283,7 +283,7 @@ B.current.client.images += C.cult_team.blood_target_image attached_action.owner.update_action_buttons_icon() remove_ranged_ability("The marking rite is complete! It will last for 90 seconds.") - C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(reset_blood_target),C.cult_team), 900, TIMER_STOPPABLE) + C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reset_blood_target),C.cult_team), 900, TIMER_STOPPABLE) return TRUE return FALSE @@ -367,7 +367,7 @@ desc = "Remove the Blood Mark you previously set." button_icon_state = "emp" owner.update_action_buttons_icon() - C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(reset_blood_target),C.cult_team), base_cooldown, TIMER_STOPPABLE) + C.cult_team.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(reset_blood_target),C.cult_team), base_cooldown, TIMER_STOPPABLE) addtimer(CALLBACK(src, PROC_REF(reset_button)), base_cooldown) diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index 35e6f7172d8f..7355880e6da1 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -669,7 +669,7 @@ structure_check() searches for nearby cultist structures required for the invoca /obj/effect/rune/wall/proc/update_state() deltimer(density_timer) - air_update_turf(1) + air_update_turf(TRUE) if(density) var/mutable_appearance/shimmer = mutable_appearance('icons/effects/effects.dmi', "barriershimmer", ABOVE_MOB_LAYER) shimmer.appearance_flags |= RESET_COLOR diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm index 339cd462d5a8..ff7ddace1d4b 100644 --- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm +++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm @@ -347,7 +347,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/AI_Module)) minor_announce("Hostile runtime detected in door controllers. Isolation lockdown protocols are now in effect. Please remain calm.","Network Alert:", TRUE) to_chat(owner, "Lockdown initiated. Network reset in 90 seconds.") - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(minor_announce), + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(minor_announce), "Automatic system reboot complete. Have a secure day.", "Network reset:"), 900) diff --git a/code/modules/atmospherics/environmental/LINDA_system.dm b/code/modules/atmospherics/environmental/LINDA_system.dm index 52f9d6443f5e..7c324a3f517a 100644 --- a/code/modules/atmospherics/environmental/LINDA_system.dm +++ b/code/modules/atmospherics/environmental/LINDA_system.dm @@ -18,7 +18,6 @@ /turf/open/CanAtmosPass(turf/T, vertical = FALSE) var/dir = vertical? get_dir_multiz(src, T) : get_dir(src, T) - var/opp = REVERSE_DIR(dir) . = TRUE if(vertical && !(zAirOut(dir, T) && T.zAirIn(dir, src))) . = FALSE @@ -30,11 +29,9 @@ var/turf/other = (O.loc == src ? T : src) if(!(vertical? (CANVERTICALATMOSPASS(O, other)) : (CANATMOSPASS(O, other)))) . = FALSE - if(O.BlockThermalConductivity()) //the direction and open/closed are already checked on CanAtmosPass() so there are no arguments - conductivity_blocked_directions |= dir - T.conductivity_blocked_directions |= opp - if(!.) - return . + +/turf/proc/block_all_conductivity() + conductivity_blocked_directions |= NORTH | SOUTH | EAST | WEST | UP | DOWN /atom/movable/proc/BlockThermalConductivity() // Objects that don't let heat through. return FALSE @@ -42,32 +39,71 @@ /turf/proc/ImmediateCalculateAdjacentTurfs() var/canpass = CANATMOSPASS(src, src) var/canvpass = CANVERTICALATMOSPASS(src, src) + + conductivity_blocked_directions = 0 + + var/src_contains_firelock = 1 + if(locate(/obj/machinery/door/firedoor) in src) + src_contains_firelock |= 2 + + var/list/atmos_adjacent_turfs = list() + for(var/direction in GLOB.cardinals_multiz) - var/turf/T = get_step_multiz(src, direction) - if(isnull(T)) + var/turf/current_turf = get_step_multiz(src, direction) + if(!isopenturf(current_turf)) + conductivity_blocked_directions |= direction + + if(current_turf) + atmos_adjacent_turfs -= current_turf + LAZYREMOVE(current_turf.atmos_adjacent_turfs, src) + continue - if(isopenturf(T) && !(blocks_air || T.blocks_air) && ((direction & (UP|DOWN))? (canvpass && CANVERTICALATMOSPASS(T, src)) : (canpass && CANATMOSPASS(T, src)))) - LAZYINITLIST(atmos_adjacent_turfs) - LAZYINITLIST(T.atmos_adjacent_turfs) - atmos_adjacent_turfs[T] = direction - T.atmos_adjacent_turfs[src] = REVERSE_DIR(direction) - else - if (atmos_adjacent_turfs) - atmos_adjacent_turfs -= T - LAZYREMOVE(T.atmos_adjacent_turfs, src) - T.__update_auxtools_turf_adjacency_info(isspaceturf(T.get_z_base_turf())) - UNSETEMPTY(atmos_adjacent_turfs) - src.atmos_adjacent_turfs = atmos_adjacent_turfs - __update_auxtools_turf_adjacency_info(isspaceturf(get_z_base_turf())) -/turf/proc/set_sleeping(should_sleep) + var/other_contains_firelock = 1 + if(locate(/obj/machinery/door/firedoor) in current_turf) + other_contains_firelock |= 2 -/turf/proc/__update_auxtools_turf_adjacency_info() + //Conductivity Update + var/opp = REVERSE_DIR(direction) + //all these must be above zero for auxmos to even consider them + if(!thermal_conductivity || !heat_capacity || !current_turf.thermal_conductivity || !current_turf.heat_capacity) + conductivity_blocked_directions |= direction + current_turf.conductivity_blocked_directions |= opp + else + for(var/obj/O in contents + current_turf.contents) + if(O.BlockThermalConductivity()) //the direction and open/closed are already checked on CanAtmosPass() so there are no arguments + conductivity_blocked_directions |= direction + current_turf.conductivity_blocked_directions |= opp + break + //End Conductivity Update + + if(!(blocks_air || current_turf.blocks_air) && ((direction & (UP|DOWN))? (canvpass && CANVERTICALATMOSPASS(current_turf, src)) : (canpass && CANATMOSPASS(current_turf, src)))) + atmos_adjacent_turfs[current_turf] = other_contains_firelock | src_contains_firelock + LAZYSET(current_turf.atmos_adjacent_turfs, src, src_contains_firelock) + else + atmos_adjacent_turfs -= current_turf + LAZYREMOVE(current_turf.atmos_adjacent_turfs, src) -//returns a list of adjacent turfs that can share air with this one. -//alldir includes adjacent diagonal tiles that can share -// air with both of the related adjacent cardinal tiles -/turf/proc/GetAtmosAdjacentTurfs(alldir = 0) + current_turf.__update_auxtools_turf_adjacency_info() + UNSETEMPTY(atmos_adjacent_turfs) + src.atmos_adjacent_turfs = atmos_adjacent_turfs + __update_auxtools_turf_adjacency_info() + +/turf/proc/clear_adjacencies() + block_all_conductivity() + for(var/turf/current_turf as anything in atmos_adjacent_turfs) + LAZYREMOVE(current_turf.atmos_adjacent_turfs, src) + current_turf.__update_auxtools_turf_adjacency_info() + + LAZYNULL(atmos_adjacent_turfs) + __update_auxtools_turf_adjacency_info() + +/** + * Returns a list of adjacent turfs that can share air with this one. + * alldir includes adjacent diagonal tiles that can share + * air with both of the related adjacent cardinal tiles + */ +/turf/proc/GetAtmosAdjacentTurfs(alldir = FALSE) var/adjacent_turfs if (atmos_adjacent_turfs) adjacent_turfs = atmos_adjacent_turfs.Copy() @@ -99,20 +135,21 @@ return adjacent_turfs -/atom/proc/air_update_turf(command = 0) - if(!isturf(loc) && command) +/atom/proc/air_update_turf(calculate_adjacencies = FALSE) + var/turf/location = get_turf(src) + if(!location) return - var/turf/T = get_turf(loc) - T.air_update_turf(command) + location.air_update_turf(calculate_adjacencies) -/turf/air_update_turf(command = 0) - if(command) - ImmediateCalculateAdjacentTurfs() +/turf/air_update_turf(calculate_adjacencies = FALSE) + if(!calculate_adjacencies) + return + ImmediateCalculateAdjacentTurfs() /atom/movable/proc/move_update_air(turf/T) if(isturf(T)) - T.air_update_turf(1) - air_update_turf(1) + T.air_update_turf(TRUE) + air_update_turf(TRUE) /atom/proc/atmos_spawn_air(text) //because a lot of people loves to copy paste awful code lets just make an easy proc to spawn your plasma fires var/turf/open/T = get_turf(src) diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index 715139dfd6ba..18b7b99a7310 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -28,19 +28,16 @@ var/list/atmos_overlay_types //gas IDs of current active gas overlays /turf/open/Initialize(mapload, inherited_virtual_z) - if(!blocks_air) - air = new(2500,src) - air.copy_from_turf(src) - update_air_ref(planetary_atmos ? 1 : 2) - . = ..() + air = new(2500,src) + air.copy_from_turf(src) + update_air_ref(planetary_atmos ? AIR_REF_PLANETARY_TURF : AIR_REF_OPEN_TURF) + return ..() /turf/open/Destroy() if(active_hotspot) QDEL_NULL(active_hotspot) return ..() -/turf/proc/update_air_ref() - /////////////////GAS MIXTURE PROCS/////////////////// /turf/open/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air @@ -49,37 +46,25 @@ /turf/open/assume_air_moles(datum/gas_mixture/giver, moles) if(!giver) return FALSE - if(SSair.thread_running()) - SSair.deferred_airs += list(list(giver, air, moles / giver.total_moles())) - else - giver.transfer_to(air, moles) + giver.transfer_to(air, moles) return TRUE /turf/open/assume_air_ratio(datum/gas_mixture/giver, ratio) if(!giver) return FALSE - if(SSair.thread_running()) - SSair.deferred_airs += list(list(giver, air, ratio)) - else - giver.transfer_ratio_to(air, ratio) + giver.transfer_ratio_to(air, ratio) return TRUE /turf/open/transfer_air(datum/gas_mixture/taker, moles) if(!taker || !return_air()) // shouldn't transfer from space return FALSE - if(SSair.thread_running()) - SSair.deferred_airs += list(list(air, taker, moles / air.total_moles())) - else - air.transfer_to(taker, moles) + air.transfer_to(taker, moles) return TRUE /turf/open/transfer_air_ratio(datum/gas_mixture/taker, ratio) if(!taker || !return_air()) return FALSE - if(SSair.thread_running()) - SSair.deferred_airs += list(list(air, taker, ratio)) - else - air.transfer_ratio_to(taker, ratio) + air.transfer_ratio_to(taker, ratio) return TRUE /turf/open/remove_air(amount) @@ -224,7 +209,7 @@ else if(locate(/obj/structure/table) in src) multiplier *= 0.2 for(var/atom/movable/M as anything in src) - if (!M.anchored && !M.pulledby && M.last_high_pressure_movement_air_cycle < SSair.times_fired) + if(!M.anchored && !M.pulledby && M.last_high_pressure_movement_air_cycle < SSair.times_fired && (M.flags_1 & INITIALIZED_1) && !QDELETED(M)) M.experience_pressure_difference(pressure_difference * multiplier, pressure_direction, 0, pressure_specific_target) if(pressure_difference > 100) diff --git a/code/modules/atmospherics/gasmixtures/auxgm.dm b/code/modules/atmospherics/gasmixtures/auxgm.dm index 40691d8e5079..b3a81dbb0e9c 100644 --- a/code/modules/atmospherics/gasmixtures/auxgm.dm +++ b/code/modules/atmospherics/gasmixtures/auxgm.dm @@ -12,8 +12,6 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA // Also allows you to add new gases at runtime -/proc/_auxtools_register_gas(datum/gas/gas) // makes sure auxtools knows stuff about this gas - /datum/auxgm var/list/datums = list() var/list/specific_heats = list() @@ -108,8 +106,6 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA enthalpies[g] = gas.enthalpy _auxtools_register_gas(gas) -/proc/finalize_gas_refs() - /datum/auxgm/New() for(var/gas_path in subtypesof(/datum/gas)) var/datum/gas/gas = new gas_path diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm index 682f8e4f9975..fa3ba14457d5 100644 --- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm +++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm @@ -18,13 +18,10 @@ What are the archived variables for? GLOBAL_LIST_INIT(auxtools_atmos_initialized, FALSE) -/proc/auxtools_atmos_init() - /datum/gas_mixture/New(volume) if (!isnull(volume)) initial_volume = volume - AUXTOOLS_CHECK(AUXMOS) - if(!GLOB.auxtools_atmos_initialized && auxtools_atmos_init()) + if(!GLOB.auxtools_atmos_initialized && auxtools_atmos_init(GLOB.gas_data)) GLOB.auxtools_atmos_initialized = TRUE __gasmixture_register() reaction_results = new @@ -99,12 +96,9 @@ GLOBAL_LIST_INIT(auxtools_atmos_initialized, FALSE) message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Changed volume to [volume].") set_volume(volume) -/* -we use a hook instead /datum/gas_mixture/Del() __gasmixture_unregister() . = ..() -*/ /datum/gas_mixture/vv_edit_var(var_name, var_value) if(var_name == "_extools_pointer_gasmixture" || var_name == "gas_list_view_only") @@ -126,34 +120,12 @@ we use a hook instead dummy["THERMAL ENERGY"] = thermal_energy() return debug_variable("gases (READ ONLY)", dummy, 0, src) -/datum/gas_mixture/proc/__gasmixture_unregister() -/datum/gas_mixture/proc/__gasmixture_register() - /proc/gas_types() var/list/L = subtypesof(/datum/gas) for(var/datum/gas/G as anything in L) L[G] = initial(G.specific_heat) return L -/datum/gas_mixture/proc/heat_capacity() //joules per kelvin - -/datum/gas_mixture/proc/partial_heat_capacity(gas_type) - - /// Calculate moles -/datum/gas_mixture/proc/total_moles() - -/datum/gas_mixture/proc/return_pressure() //kilopascals - -/datum/gas_mixture/proc/return_temperature() //kelvins - -/datum/gas_mixture/proc/set_min_heat_capacity(n) -/datum/gas_mixture/proc/set_temperature(new_temp) -/datum/gas_mixture/proc/set_volume(new_volume) -/datum/gas_mixture/proc/get_moles(gas_type) -/datum/gas_mixture/proc/get_by_flag(flag) -/datum/gas_mixture/proc/set_moles(gas_type, moles) -/datum/gas_mixture/proc/scrub_into(datum/gas_mixture/target, ratio, list/gases) - // VV WRAPPERS - EXTOOLS HOOKED PROCS DO NOT TAKE ARGUMENTS FROM CALL() FOR SOME REASON. /datum/gas_mixture/proc/vv_set_moles(gas_type, moles) return set_moles(gas_type, moles) @@ -166,40 +138,6 @@ we use a hook instead /datum/gas_mixture/proc/vv_react(datum/holder) return react(holder) -/datum/gas_mixture/proc/mark_immutable() -/datum/gas_mixture/proc/mark_vacuum() -/datum/gas_mixture/proc/get_gases() -/datum/gas_mixture/proc/add(amt) -/datum/gas_mixture/proc/subtract(amt) -/datum/gas_mixture/proc/multiply(factor) -/datum/gas_mixture/proc/divide(factor) -//WS Edit Start - Immutable Gax Mix Temperature Gradients -/datum/gas_mixture/proc/create_temperature_gradient(a, b, c) -/datum/gas_mixture/proc/tick_temperature_gradient(step) -//WS Edit End - Immutable Gax Mix Temperature Gradients -/datum/gas_mixture/proc/get_last_share() -/datum/gas_mixture/proc/clear() - -/datum/gas_mixture/proc/adjust_moles(gas_type, amt = 0) - set_moles(gas_type, clamp(get_moles(gas_type) + amt,0,INFINITY)) - -/datum/gas_mixture/proc/adjust_moles_temp(gas_type, amt, temperature) - -/datum/gas_mixture/proc/adjust_multi() - -/datum/gas_mixture/proc/return_volume() //liters - -/datum/gas_mixture/proc/thermal_energy() //joules - - ///Update archived versions of variables. Returns: 1 in all cases -/datum/gas_mixture/proc/archive() - //Update archived versions of variables - //Returns: 1 in all cases - -/datum/gas_mixture/proc/merge(datum/gas_mixture/giver) - //Merges all air from giver into self. Deletes giver. - //Returns: 1 if we are mutable, 0 otherwise - /datum/gas_mixture/proc/remove(amount) //Proportionally removes amount of gas from the gas_mixture //Returns: gas_mixture with the gases removed @@ -208,11 +146,6 @@ we use a hook instead //Removes amount of gas from the gas mixture by flag //Returns: gas_mixture with gases that match the flag removed -/datum/gas_mixture/proc/transfer_to(datum/gas_mixture/target, amount) - -/datum/gas_mixture/proc/transfer_ratio_to(datum/gas_mixture/target, ratio) - //Transfers ratio of gas to target. Equivalent to target.merge(remove_ratio(amount)) but faster. - /datum/gas_mixture/proc/remove_ratio(ratio) //Proportionally removes amount of gas from the gas_mixture //Returns: gas_mixture with the gases removed @@ -221,10 +154,6 @@ we use a hook instead //Creates new, identical gas mixture //Returns: duplicate gas mixture -/datum/gas_mixture/proc/copy_from(datum/gas_mixture/sample) - //Copies variables from sample - //Returns: 1 if we are mutable, 0 otherwise - /datum/gas_mixture/proc/copy_from_turf(turf/model) //Copies all gas info from the turf into the gas list along with temperature //Returns: 1 if we are mutable, 0 otherwise @@ -233,56 +162,18 @@ we use a hook instead //Copies variables from a particularly formatted string. //Returns: 1 if we are mutable, 0 otherwise -/datum/gas_mixture/proc/share(datum/gas_mixture/sharer) - //Performs air sharing calculations between two gas_mixtures assuming only 1 boundary length - //Returns: amount of gas exchanged (+ if sharer received) - -/datum/gas_mixture/proc/temperature_share(datum/gas_mixture/sharer, conduction_coefficient) - //Performs temperature sharing calculations (via conduction) between two gas_mixtures assuming only 1 boundary length - //Returns: new temperature of the sharer - -/datum/gas_mixture/proc/compare(datum/gas_mixture/sample) - //Compares sample to self to see if within acceptable ranges that group processing may be enabled - //Returns: a string indicating what check failed, or "" if check passes - -/datum/gas_mixture/proc/react(turf/open/dump_location) - //Performs various reactions such as combustion or fusion (LOL) - //Returns: 1 if any reaction took place; 0 otherwise - -/datum/gas_mixture/proc/adjust_heat(amt) - //Adjusts the thermal energy of the gas mixture, rather than having to do the full calculation. - //Returns: null - -/datum/gas_mixture/proc/equalize_with(datum/gas_mixture/giver) - //Makes this mix have the same temperature and gas ratios as the giver, but with the same pressure, accounting for volume. - //Returns: null - -/datum/gas_mixture/proc/get_oxidation_power(temp) - //Gets how much oxidation this gas can do, optionally at a given temperature. - -/datum/gas_mixture/proc/get_fuel_amount(temp) - //Gets how much fuel for fires (not counting trit/plasma!) this gas has, optionally at a given temperature. - -/proc/equalize_all_gases_in_list(list/L) - //Makes every gas in the given list have the same pressure, temperature and gas proportions. - //Returns: null - -/datum/gas_mixture/proc/__remove_by_flag() - /datum/gas_mixture/remove_by_flag(flag, amount) var/datum/gas_mixture/removed = new type __remove_by_flag(removed, flag, amount) return removed -/datum/gas_mixture/proc/__remove() /datum/gas_mixture/remove(amount) var/datum/gas_mixture/removed = new type __remove(removed, amount) return removed -/datum/gas_mixture/proc/__remove_ratio() /datum/gas_mixture/remove_ratio(ratio) var/datum/gas_mixture/removed = new type __remove_ratio(removed, ratio) @@ -300,15 +191,10 @@ we use a hook instead parse_gas_string(model.initial_gas_mix) return 1 -// Newer versions of auxmos (2.0+) have a function, __auxtools_parse_gas_string, -// that circumvents the slowdown caused by params2list(). Once auxmos is updated, -// this proc should be changed to a simple wrapper. -// SSair should be updated accordingly to return a string instead of a gas mix as before. /datum/gas_mixture/parse_gas_string(gas_string) - // params2list() is surprisingly expensive, so we have SSair cache it. - var/datum/gas_mixture/string_mixture = SSair.get_gas_string_mix(gas_string) - copy_from(string_mixture) - return 1 + gas_string = SSair.preprocess_gas_string(gas_string) + + return __auxtools_parse_gas_string(gas_string) /datum/gas_mixture/proc/set_analyzer_results(instability) if(!analyzer_results) diff --git a/code/modules/atmospherics/gasmixtures/immutable_mixtures.dm b/code/modules/atmospherics/gasmixtures/immutable_mixtures.dm index ee59bf2e4386..7de056ed0261 100644 --- a/code/modules/atmospherics/gasmixtures/immutable_mixtures.dm +++ b/code/modules/atmospherics/gasmixtures/immutable_mixtures.dm @@ -17,10 +17,6 @@ /datum/gas_mixture/immutable/space initial_temperature = TCMB -/datum/gas_mixture/immutable/space/New() - ..() - mark_vacuum() - /datum/gas_mixture/immutable/space/populate() set_min_heat_capacity(HEAT_CAPACITY_VACUUM) diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm index 383a362a0228..00ca2d22f76c 100644 --- a/code/modules/atmospherics/gasmixtures/reactions.dm +++ b/code/modules/atmospherics/gasmixtures/reactions.dm @@ -529,21 +529,24 @@ G.set_moles(GAS_NITRYL,1) G.set_temperature(15000) G.set_volume(1000) + var/result = G.react() if(result != REACTING) return list("success" = FALSE, "message" = "Reaction didn't go at all!") - if(abs(G.analyzer_results["fusion"] - 0.691869) > 0.01) - var/instability = G.analyzer_results["fusion"] - return list("success" = FALSE, "message" = "Fusion is not calculating analyzer results correctly, should be 0.691869, is instead [instability]") - if(abs(G.get_moles(GAS_PLASMA) - 552.789) > 0.5) - var/plas = G.get_moles(GAS_PLASMA) - return list("success" = FALSE, "message" = "Fusion is not calculating plasma correctly, should be 458.531, is instead [plas]") - if(abs(G.get_moles(GAS_CO2) - 411.096) > 0.5) - var/co2 = G.get_moles(GAS_CO2) - return list("success" = FALSE, "message" = "Fusion is not calculating co2 correctly, should be 505.078, is instead [co2]") - if(abs(G.return_temperature() - 78222) > 200) // I'm not calculating this at all just putting in the values I get when I do it now - var/temp = G.return_temperature() - return list("success" = FALSE, "message" = "Fusion is not calculating temperature correctly, should be around 112232, is instead [temp]") + + var/instability = G.analyzer_results["fusion"] + var/plas = G.get_moles(GAS_PLASMA) + var/co2 = G.get_moles(GAS_CO2) + var/temp = G.return_temperature() + + if(abs(instability - 2.66) > 0.01) + return list("success" = FALSE, "message" = "Fusion is not calculating analyzer results correctly, should be 2.66, is instead [instability]") + if(abs(plas - 458.241) > 0.5) + return list("success" = FALSE, "message" = "Fusion is not calculating plasma correctly, should be 458.241, is instead [plas]") + if(abs(co2 - 505.369) > 0.5) + return list("success" = FALSE, "message" = "Fusion is not calculating co2 correctly, should be 505.369, is instead [co2]") + if(abs(temp - 112291) > 200) // I'm not calculating this at all just putting in the values I get when I do it now + return list("success" = FALSE, "message" = "Fusion is not calculating temperature correctly, should be around 112291, is instead [temp]") return ..() /datum/gas_reaction/nitrousformation //formationn of n2o, esothermic, requires bz as catalyst diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm index ad8dd9761598..9e1cb072a983 100644 --- a/code/modules/atmospherics/machinery/components/components_base.dm +++ b/code/modules/atmospherics/machinery/components/components_base.dm @@ -170,7 +170,7 @@ for(var/i in 1 to device_type) var/datum/gas_mixture/air = airs[i] T.assume_air_moles(air, shared_loss) - air_update_turf(1) + air_update_turf(TRUE) /obj/machinery/atmospherics/components/proc/safe_input(title, text, default_set) var/new_value = input(usr,text,title,default_set) as num|null diff --git a/code/modules/autowiki/autowiki.dm b/code/modules/autowiki/autowiki.dm index 815ac0192f19..33c5bcf2a8c4 100644 --- a/code/modules/autowiki/autowiki.dm +++ b/code/modules/autowiki/autowiki.dm @@ -4,7 +4,7 @@ #if defined(AUTOWIKI) || defined(UNIT_TESTS) /proc/setup_autowiki() Master.sleep_offline_after_initializations = FALSE - SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/generate_autowiki)) + SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(generate_autowiki))) SSticker.start_immediately = TRUE CONFIG_SET(number/round_end_countdown, 0) diff --git a/code/modules/balloon_alert/balloon_alert.dm b/code/modules/balloon_alert/balloon_alert.dm index db4453bfa6b6..19916b30f4f1 100644 --- a/code/modules/balloon_alert/balloon_alert.dm +++ b/code/modules/balloon_alert/balloon_alert.dm @@ -79,7 +79,7 @@ easing = CUBIC_EASING | EASE_IN, ) - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(remove_image_from_client), balloon_alert, viewer_client), BALLOON_TEXT_TOTAL_LIFETIME(duration_mult)) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(remove_image_from_client), balloon_alert, viewer_client), BALLOON_TEXT_TOTAL_LIFETIME(duration_mult)) #undef BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MIN #undef BALLOON_TEXT_CHAR_LIFETIME_INCREASE_MULT diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 4e7a1d2a1145..4153a2f409e5 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -863,11 +863,13 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( var/ab = FALSE var/list/modifiers = params2list(params) + var/button_clicked = LAZYACCESS(modifiers, "button") + var/dragged = LAZYACCESS(modifiers, DRAG) - if(dragged && !LAZYACCESS(modifiers, dragged)) //I don't know what's going on here, but I don't trust it + if(dragged && button_clicked != dragged) return - if (object && object == middragatom && LAZYACCESS(modifiers, LEFT_CLICK)) + if (object && object == middragatom && button_clicked == LEFT_CLICK) ab = max(0, 5 SECONDS-(world.time-middragtime)*0.1) var/mcl = CONFIG_GET(number/minute_click_limit) @@ -916,7 +918,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( //check if the server is overloaded and if it is then queue up the click for next tick //yes having it call a wrapping proc on the subsystem is fucking stupid glad we agree unfortunately byond insists its reasonable - if(!QDELETED(object) && TRY_QUEUE_VERB(VERB_CALLBACK(object, /atom/proc/_Click, location, control, params), VERB_OVERTIME_QUEUE_THRESHOLD, SSinput, control)) + if(!QDELETED(object) && TRY_QUEUE_VERB(VERB_CALLBACK(object, TYPE_PROC_REF(/atom, _Click), location, control, params), VERB_OVERTIME_QUEUE_THRESHOLD, SSinput, control)) return if (prefs.hotkeys) @@ -1039,7 +1041,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( var/mob/living/M = mob M.update_damage_hud() if (prefs.auto_fit_viewport) - addtimer(CALLBACK(src,.verb/fit_viewport,10)) //Delayed to avoid wingets from Login calls. + addtimer(CALLBACK(src, VERB_REF(fit_viewport), 1 SECONDS)) //Delayed to avoid wingets from Login calls. /client/proc/generate_clickcatcher() if(!void) diff --git a/code/modules/events/fake_virus.dm b/code/modules/events/fake_virus.dm index 9e4ac8f570a0..f0f7f04a73ff 100644 --- a/code/modules/events/fake_virus.dm +++ b/code/modules/events/fake_virus.dm @@ -25,7 +25,7 @@ for(var/i=1; i<=rand(1,defacto_min); i++) var/mob/living/carbon/human/onecoughman = pick(fake_virus_victims) if(prob(25))//1/4 odds to get a spooky message instead of coughing out loud - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(to_chat), onecoughman, "[pick("Your head hurts.", "Your head pounds.")]"), rand(30,150)) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), onecoughman, "[pick("Your head hurts.", "Your head pounds.")]"), rand(30,150)) else - addtimer(CALLBACK(onecoughman, .mob/proc/emote, pick("cough", "sniff", "sneeze")), rand(30,150))//deliver the message with a slightly randomized time interval so there arent multiple people coughing at the exact same time + addtimer(CALLBACK(onecoughman, TYPE_PROC_REF(/mob, emote), pick("cough", "sniff", "sneeze")), rand(30,150))//deliver the message with a slightly randomized time interval so there arent multiple people coughing at the exact same time fake_virus_victims -= onecoughman diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index 2f262b562148..258e9a56217f 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -1133,7 +1133,7 @@ GLOBAL_LIST_INIT(hallucination_list, list( return to_chat(target, "You fall into the chasm!") target.Paralyze(40) - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(to_chat), target, "It's surprisingly shallow."), 15) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), target, "It's surprisingly shallow."), 15) QDEL_IN(src, 30) /obj/effect/hallucination/danger/anomaly diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index fe66d3a99836..396f206f7072 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -152,7 +152,6 @@ for(var/turf/turf_to_disable as anything in border) turf_to_disable.blocks_air = TRUE - turf_to_disable.set_sleeping(TRUE) turf_to_disable.air_update_turf(TRUE) // Accept cached maps, but don't save them automatically - we don't want diff --git a/code/modules/mentor/verbs/mentorhelp.dm b/code/modules/mentor/verbs/mentorhelp.dm index c2c82e6230bc..944e1b8196a2 100644 --- a/code/modules/mentor/verbs/mentorhelp.dm +++ b/code/modules/mentor/verbs/mentorhelp.dm @@ -23,7 +23,7 @@ //spam prevention, 60 second delay remove_verb(src, /client/verb/mentorhelp) - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(add_verb), src, /client/verb/mentorhelp), 1 MINUTES, TIMER_STOPPABLE) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(add_verb), src, /client/verb/mentorhelp), 1 MINUTES, TIMER_STOPPABLE) /proc/get_mentor_counts() . = list("total" = 0, "afk" = 0, "present" = 0) diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index 80c3d276d9b8..c4b75883eb67 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -271,7 +271,7 @@ /obj/structure/fans/Initialize(mapload) . = ..() - air_update_turf(1) + air_update_turf(TRUE) //Inivisible, indestructible fans /obj/structure/fans/tiny/invisible diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index f119c7dbc308..86c85d27360a 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -399,8 +399,8 @@ if((GLOB.cult_narsie.souls == GLOB.cult_narsie.soul_goal) && (GLOB.cult_narsie.resolved == FALSE)) GLOB.cult_narsie.resolved = TRUE sound_to_playing_players('sound/machines/alarm.ogg') - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(cult_ending_helper), 1), 120) - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(ending_helper)), 270) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), 1), 120) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ending_helper)), 270) if(client) makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, cultoverride = TRUE) else diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm index 39a0ede9334f..376b4ddcca4b 100644 --- a/code/modules/mob/living/silicon/robot/robot_defense.dm +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -308,7 +308,7 @@ GLOBAL_LIST_INIT(blacklisted_borg_hats, typecacheof(list( //Hats that don't real return spark_system.start() step_away(src, user, 15) - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(_step_away), src, get_turf(user), 15), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), src, get_turf(user), 15), 3) /mob/living/silicon/robot/fire_act() if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index af5875853ce1..19eef279a1dc 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -73,7 +73,7 @@ if(prob(1)) manual_emote(pick("dances around.","chases its tail!")) - INVOKE_ASYNC(GLOBAL_PROC, PROC_REF(dance_rotate), src) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(dance_rotate), src) //Corgis and pugs are now under one dog subtype diff --git a/code/modules/mob/living/simple_animal/hostile/goose.dm b/code/modules/mob/living/simple_animal/hostile/goose.dm index 0d48bdb082e6..a175bb40feca 100644 --- a/code/modules/mob/living/simple_animal/hostile/goose.dm +++ b/code/modules/mob/living/simple_animal/hostile/goose.dm @@ -241,10 +241,10 @@ /mob/living/simple_animal/hostile/retaliate/goose/vomit/proc/deadchat_plays_goose() stop_automated_movement = TRUE AddComponent(/datum/component/deadchat_control, ANARCHY_MODE, list( - "up" = CALLBACK(GLOBAL_PROC, PROC_REF(_step), src, NORTH), - "down" = CALLBACK(GLOBAL_PROC, PROC_REF(_step), src, SOUTH), - "left" = CALLBACK(GLOBAL_PROC, PROC_REF(_step), src, WEST), - "right" = CALLBACK(GLOBAL_PROC, PROC_REF(_step), src, EAST), + "up" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), src, NORTH), + "down" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), src, SOUTH), + "left" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), src, WEST), + "right" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), src, EAST), "vomit" = CALLBACK(src, PROC_REF(vomit_prestart), 25)), 12 SECONDS, 4 SECONDS) /datum/action/cooldown/vomit diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 5a2e3731a703..d475891fc28f 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -559,11 +559,11 @@ // check to see if their face is blocked or, if not, a signal blocks it if(examined_mob.is_face_visible() && SEND_SIGNAL(src, COMSIG_MOB_EYECONTACT, examined_mob, TRUE) != COMSIG_BLOCK_EYECONTACT) var/msg = "You make eye contact with [examined_mob]." - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(to_chat), src, msg), 3) // so the examine signal has time to fire and this will print after + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), src, msg), 3) // so the examine signal has time to fire and this will print after if(is_face_visible() && SEND_SIGNAL(examined_mob, COMSIG_MOB_EYECONTACT, src, FALSE) != COMSIG_BLOCK_EYECONTACT) var/msg = "[src] makes eye contact with you." - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(to_chat), examined_mob, msg), 3) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), examined_mob, msg), 3) ///Can this mob resist (default FALSE) diff --git a/code/modules/mob/mob_say.dm b/code/modules/mob/mob_say.dm index 495f77dc0384..9e03116f1ba3 100644 --- a/code/modules/mob/mob_say.dm +++ b/code/modules/mob/mob_say.dm @@ -13,7 +13,7 @@ //queue this message because verbs are scheduled to process after SendMaps in the tick and speech is pretty expensive when it happens. //by queuing this for next tick the mc can compensate for its cost instead of having speech delay the start of the next tick if(message) - QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, /atom/movable/proc/say, message), SSspeech_controller) + QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_PROC_REF(/atom/movable, say), message), SSspeech_controller) ///Whisper verb /mob/verb/whisper_verb(message as text) @@ -24,7 +24,7 @@ to_chat(usr, "Speech is currently admin-disabled.") return if(message) - QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, /mob/proc/whisper, message), SSspeech_controller) + QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_PROC_REF(/mob, whisper), message), SSspeech_controller) ///whisper a message /mob/proc/whisper(message, datum/language/language=null) @@ -43,7 +43,7 @@ message = trim(copytext_char(sanitize(message), 1, MAX_MESSAGE_LEN)) - QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, /mob/proc/emote, "me", 1, message, TRUE), SSspeech_controller) + QUEUE_OR_CALL_VERB_FOR(VERB_CALLBACK(src, TYPE_PROC_REF(/mob, emote), "me", 1, message, TRUE), SSspeech_controller) ///Speak as a dead person (ghost etc) /mob/proc/say_dead(message) diff --git a/code/modules/modular_computers/computers/item/processor.dm b/code/modules/modular_computers/computers/item/processor.dm index ec4741851545..38c5e9aad8cb 100644 --- a/code/modules/modular_computers/computers/item/processor.dm +++ b/code/modules/modular_computers/computers/item/processor.dm @@ -38,7 +38,7 @@ integrity_failure = machinery_computer.integrity_failure base_active_power_usage = machinery_computer.base_active_power_usage base_idle_power_usage = machinery_computer.base_idle_power_usage - machinery_computer.RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, /obj/machinery/modular_computer/proc/relay_icon_update) //when we update_icon, also update the computer + machinery_computer.RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, TYPE_PROC_REF(/obj/machinery/modular_computer, relay_icon_update)) //when we update_icon, also update the computer /obj/item/modular_computer/processor/relay_qdel() qdel(machinery_computer) diff --git a/code/modules/overmap/ships/controlled_ship_datum.dm b/code/modules/overmap/ships/controlled_ship_datum.dm index bbd56e892095..9c9024126b0a 100644 --- a/code/modules/overmap/ships/controlled_ship_datum.dm +++ b/code/modules/overmap/ships/controlled_ship_datum.dm @@ -133,7 +133,7 @@ QDEL_NULL(ship_account) if(!QDELETED(shipkey)) QDEL_NULL(shipkey) - QDEL_LIST(manifest) + manifest.Cut() job_holder_refs.Cut() job_slots.Cut() blacklisted.Cut() diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm index 23e5155fabf7..7724a38ae43e 100644 --- a/code/modules/paperwork/contract.dm +++ b/code/modules/paperwork/contract.dm @@ -245,7 +245,7 @@ H.fakefire() fulfillContract(H, TRUE)//Revival contracts are always signed in blood addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living/carbon/human, fakefireextinguish)), 5, TIMER_UNIQUE) - addtimer(CALLBACK(src, "resetcooldown"), 300, TIMER_UNIQUE) + addtimer(CALLBACK(src, PROC_REF(resetcooldown)), 300, TIMER_UNIQUE) else ..() diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index 869f3b086b76..1e4660c48953 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -165,7 +165,7 @@ part.main_part = src parts += part part.update_appearance() - part.RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, /obj/machinery/gravity_generator/part/proc/on_update_icon) + part.RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, TYPE_PROC_REF(/obj/machinery/gravity_generator/part, on_update_icon)) /obj/machinery/gravity_generator/main/proc/connected_parts() return parts.len == 8 diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 81f12838c0d3..aefc5249f54d 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -68,7 +68,7 @@ if(player.stat != DEAD && player.loc && !iscultist(player) && !isanimal(player)) souls_needed[player] = TRUE soul_goal = round(1 + LAZYLEN(souls_needed) * 0.75) - INVOKE_ASYNC(GLOBAL_PROC, PROC_REF(begin_the_end)) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(begin_the_end)) /proc/begin_the_end() SSredbot.send_discord_message("admin","Nar'sie has been summoned.","round ending event") @@ -77,7 +77,7 @@ priority_announce("Status report? We detected a anomaly, but it disappeared almost immediately.","Central Command Higher Dimensional Affairs", 'sound/misc/notice1.ogg') GLOB.cult_narsie = null sleep(20) - INVOKE_ASYNC(GLOBAL_PROC, PROC_REF(cult_ending_helper), 2) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), 2) return priority_announce("An acausal dimensional event has been detected in your sector. Event has been flagged EXTINCTION-CLASS. Directing all available assets toward simulating solutions. SOLUTION ETA: 60 SECONDS.","Central Command Higher Dimensional Affairs", 'sound/misc/airraid.ogg') sleep(500) @@ -85,7 +85,7 @@ priority_announce("Simulations aborted, sensors report that the acasual event is normalizing. Good work, crew.","Central Command Higher Dimensional Affairs", 'sound/misc/notice1.ogg') GLOB.cult_narsie = null sleep(20) - INVOKE_ASYNC(GLOBAL_PROC, PROC_REF(cult_ending_helper), 2) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), 2) return priority_announce("Simulations on acausal dimensional event complete. Deploying solution package now. Deployment ETA: ONE MINUTE. ","Central Command Higher Dimensional Affairs") sleep(50) @@ -98,16 +98,18 @@ sleep(20) set_security_level("red") SSshuttle.lockdown = FALSE - INVOKE_ASYNC(GLOBAL_PROC, PROC_REF(cult_ending_helper), 2) + INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), 2) return if(GLOB.cult_narsie.resolved == FALSE) GLOB.cult_narsie.resolved = TRUE sound_to_playing_players('sound/machines/alarm.ogg') - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(cult_ending_helper)), 120) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper)), 120) /obj/singularity/narsie/large/cult/Destroy() send_to_playing_players("\"[pick("Nooooo...", "Not die. How-", "Die. Mort-", "Sas tyen re-")]\"") sound_to_playing_players('sound/magic/demon_dies.ogg', 50) + if(GLOB.cult_narsie == src) + GLOB.cult_narsie = null var/list/all_cults = list() for(var/datum/antagonist/cult/C in GLOB.antagonists) if(!C.owner) diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 93ed8a5d606d..875f9cd441f2 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -480,7 +480,7 @@ /obj/singularity/deadchat_controlled/Initialize(mapload, starting_energy) . = ..() AddComponent(/datum/component/deadchat_control, DEMOCRACY_MODE, list( - "up" = CALLBACK(GLOBAL_PROC, PROC_REF(_step), src, NORTH), - "down" = CALLBACK(GLOBAL_PROC, PROC_REF(_step), src, SOUTH), - "left" = CALLBACK(GLOBAL_PROC, PROC_REF(_step), src, WEST), - "right" = CALLBACK(GLOBAL_PROC, PROC_REF(_step), src, EAST))) + "up" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), src, NORTH), + "down" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), src, SOUTH), + "left" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), src, WEST), + "right" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), src, EAST))) diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index aafa14ea8824..5b7317972175 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -111,7 +111,7 @@ SpinAnimation(10, 1) var/turf/location = get_turf(src) if(bounce_sfx_override) - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(playsound), src, pick(bounce_sfx_override), 20, 1), bounce_delay) //Soft / non-solid turfs that shouldn't make a sound when a shell casing is ejected over them. + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(playsound), src, pick(bounce_sfx_override), 20, 1), bounce_delay) //Soft / non-solid turfs that shouldn't make a sound when a shell casing is ejected over them. return if(!location) return diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index 4aa0bbc2fe94..851a9e38a267 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -68,7 +68,7 @@ else if(setting_type) if(step_away(X, T) && moving_power > 1) //Can happen twice at most. So this is fine. - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(_step_away), X, T), 2) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_away), X, T), 2) else if(step_towards(X, T) && moving_power > 1) - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(_step_towards), X, T), 2) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step_towards), X, T), 2) diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index 58476c423275..534d3b052bc6 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -47,7 +47,7 @@ "[user] forces you to [apply_method] [src].") if(icon_state == "pill4" && prob(5)) //you take the red pill - you stay in Wonderland, and I show you how deep the rabbit hole goes - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(to_chat), M, "[pick(strings(REDPILL_FILE, "redpill_questions"))]"), 50) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), M, "[pick(strings(REDPILL_FILE, "redpill_questions"))]"), 50) if(reagents.total_volume) reagents.trans_to(M, reagents.total_volume, transfered_by = user, method = apply_type) diff --git a/code/modules/shuttle/docking.dm b/code/modules/shuttle/docking.dm index ec0727a2cc24..1f4a36c0c160 100644 --- a/code/modules/shuttle/docking.dm +++ b/code/modules/shuttle/docking.dm @@ -62,8 +62,6 @@ remove_ripples() return DOCKING_IMMOBILIZED - kill_atmos_infos(old_turfs, new_turfs) - var/list/obj/docking_port/mobile/all_towed_shuttles = get_all_towed_shuttles() // Moving to the new location will trample the ripples there at the exact @@ -93,16 +91,6 @@ play_engine_sound(old_dock, launch_sound) return DOCKING_SUCCESS -/obj/docking_port/mobile/proc/kill_atmos_infos(list/old_turfs, list/new_turfs) - for(var/turf/oldT as anything in old_turfs) - oldT.blocks_air = TRUE - oldT.set_sleeping(TRUE) - oldT.air_update_turf(TRUE) - for(var/turf/newT as anything in new_turfs) - newT.blocks_air = TRUE - newT.set_sleeping(TRUE) - newT.air_update_turf(TRUE) - /obj/docking_port/mobile/proc/throw_exception(exception/e) throw e diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 2d48fc3a82a3..f4d68520c879 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -10,6 +10,8 @@ All ShuttleMove procs go here if(!(move_mode & MOVE_AREA) || !isshuttleturf(src)) return move_mode + clear_adjacencies() + return move_mode | MOVE_TURF | MOVE_CONTENTS // Called from the new turf before anything has been moved @@ -20,6 +22,8 @@ All ShuttleMove procs go here if(!(. & MOVE_TURF)) return + clear_adjacencies() + for(var/atom/movable/thing as anything in contents) if(ismob(thing)) if(isliving(thing)) @@ -109,13 +113,11 @@ All ShuttleMove procs go here CRASH("A turf queued to clean up after a shuttle dock somehow didn't have enough skipovers in baseturfs. [oldT]([oldT.type]):[oldT.loc]") if(BT_index != length(baseturfs)) - oldT.ScrapeAway(baseturfs.len - BT_index, CHANGETURF_FORCEOP) + oldT.ScrapeAway(baseturfs.len - BT_index, CHANGETURF_FORCEOP|CHANGETURF_DEFER_CHANGE) return TRUE /turf/proc/lateShuttleMove(turf/oldT) - blocks_air = initial(blocks_air) - oldT.blocks_air = initial(oldT.blocks_air) AfterChange() oldT.AfterChange() diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index 63b6d5c0bfa0..5eed8abc46be 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -376,7 +376,7 @@ for(var/iter in 1 to 5 * power_multiplier) for(var/V in listeners) var/mob/living/L = V - addtimer(CALLBACK(GLOBAL_PROC, PROC_REF(_step), L, direction? direction : pick(GLOB.cardinals)), 10 * (iter - 1)) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_step), L, direction? direction : pick(GLOB.cardinals)), 10 * (iter - 1)) //WALK else if((findtext(message, walk_words))) @@ -398,7 +398,7 @@ else if((findtext(message, helpintent_words))) cooldown = COOLDOWN_MEME for(var/mob/living/carbon/human/H in listeners) - addtimer(CALLBACK(H, /mob/verb/a_intent_change, INTENT_HELP), i * 2) + addtimer(CALLBACK(H, TYPE_VERB_REF(/mob, a_intent_change), INTENT_HELP), i * 2) addtimer(CALLBACK(H, TYPE_PROC_REF(/mob, click_random_mob)), i * 2) i++ @@ -406,7 +406,7 @@ else if((findtext(message, disarmintent_words))) cooldown = COOLDOWN_MEME for(var/mob/living/carbon/human/H in listeners) - addtimer(CALLBACK(H, /mob/verb/a_intent_change, INTENT_DISARM), i * 2) + addtimer(CALLBACK(H, TYPE_VERB_REF(/mob, a_intent_change), INTENT_DISARM), i * 2) addtimer(CALLBACK(H, TYPE_PROC_REF(/mob, click_random_mob)), i * 2) i++ @@ -414,7 +414,7 @@ else if((findtext(message, grabintent_words))) cooldown = COOLDOWN_MEME for(var/mob/living/carbon/human/H in listeners) - addtimer(CALLBACK(H, /mob/verb/a_intent_change, INTENT_GRAB), i * 2) + addtimer(CALLBACK(H, TYPE_VERB_REF(/mob, a_intent_change), INTENT_GRAB), i * 2) addtimer(CALLBACK(H, TYPE_PROC_REF(/mob, click_random_mob)), i * 2) i++ @@ -422,7 +422,7 @@ else if((findtext(message, harmintent_words))) cooldown = COOLDOWN_MEME for(var/mob/living/carbon/human/H in listeners) - addtimer(CALLBACK(H, /mob/verb/a_intent_change, INTENT_HARM), i * 2) + addtimer(CALLBACK(H, TYPE_VERB_REF(/mob, a_intent_change), INTENT_HARM), i * 2) addtimer(CALLBACK(H, TYPE_PROC_REF(/mob, click_random_mob)), i * 2) i++ diff --git a/code/modules/unit_tests/ship_outpost_placement.dm b/code/modules/unit_tests/ship_outpost_placement.dm index 73dc32a088fa..48bbd6a181e3 100644 --- a/code/modules/unit_tests/ship_outpost_placement.dm +++ b/code/modules/unit_tests/ship_outpost_placement.dm @@ -3,6 +3,7 @@ // disabled or intended as subshuttles for(var/name as anything in SSmapping.shuttle_templates) var/datum/map_template/shuttle/map = SSmapping.shuttle_templates[name] + log_world("Loading [map.name]") try // they'll spawn in empty space, and won't be docked new /datum/overmap/ship/controlled(list("x" = 1, "y" = 1), map) @@ -12,7 +13,11 @@ for(var/outpost_type in subtypesof(/datum/overmap/outpost)) var/datum/overmap/outpost/test_outpost = new outpost_type() + log_world("Testing [test_outpost.type]") + for(var/datum/overmap/ship/controlled/cur_ship as anything in SSovermap.controlled_ships) + log_world(" - Docking [cur_ship.source_template.name]") + // already-docked ships are ignored. // this was added to stop runtimes when subshuttles, which were docked to their parent ship, attempted to dock to the outpost as part of this test. // all ships which start undocked will end the loop undocked, so this shouldn't cause any ships to be wrongfully skipped. diff --git a/dependencies.sh b/dependencies.sh index ee382484a0f2..6f5a61810a81 100755 --- a/dependencies.sh +++ b/dependencies.sh @@ -4,11 +4,11 @@ #Final authority on what's required to fully build the project # byond version -export BYOND_MAJOR=514 -export BYOND_MINOR=1588 +export BYOND_MAJOR=515 +export BYOND_MINOR=1633 #rust version -export RUST_VERSION=1.67.1 +export RUST_VERSION=1.73.0 #rust_g git tag export RUST_G_VERSION=3.0.0 @@ -18,13 +18,13 @@ export NODE_VERSION=16 export NODE_VERSION_PRECISE=16.13.0 # SpacemanDMM git tag -export SPACEMAN_DMM_VERSION=suite-1.7.1 +export SPACEMAN_DMM_VERSION=suite-1.8 # Python version for mapmerge and other tools export PYTHON_VERSION=3.9.0 #auxmos repository -export AUXMOS_REPO=https://github.com/shiptest-ss13/auxmos +export AUXMOS_REPO=https://github.com/Putnam3145/auxmos #auxmos version -export AUXMOS_VERSION=v1.2.6 +export AUXMOS_VERSION=v2.5.1 diff --git a/html/changelogs/archive/2024-03.yml b/html/changelogs/archive/2024-03.yml index 0b41f25dfde1..fb2b9011b46e 100644 --- a/html/changelogs/archive/2024-03.yml +++ b/html/changelogs/archive/2024-03.yml @@ -199,3 +199,6 @@ report any issues that may involve ID cards not updating overlays. - code_imp: Outfits now have an id_assignment field. If a job has an id, and an id_assignment, it will automatically apply. +2024-03-17: + GenericDM: + - bugfix: pine trees now correctly show all possible sprite variations diff --git a/shiptest.dme b/shiptest.dme index 3a66a1d5ff30..1f3455c4c948 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -152,12 +152,13 @@ #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" #include "code\__DEFINES\dcs\signals.dm" -#include "code\__HELPERS\_extools_api.dm" +#include "code\__HELPERS\_auxtools_api.dm" #include "code\__HELPERS\_lists.dm" #include "code\__HELPERS\_logging.dm" #include "code\__HELPERS\_string_lists.dm" #include "code\__HELPERS\areas.dm" #include "code\__HELPERS\AStar.dm" +#include "code\__HELPERS\bindings.dm" #include "code\__HELPERS\bitflag_lists.dm" #include "code\__HELPERS\chat.dm" #include "code\__HELPERS\cmp.dm" diff --git a/tools/ci/build_auxmos.sh b/tools/ci/build_auxmos.sh new file mode 100644 index 000000000000..735b7263761a --- /dev/null +++ b/tools/ci/build_auxmos.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -euo pipefail + +source dependencies.sh + +mkdir -p "$HOME/auxmos" +pushd "$HOME/auxmos" + +if [ ! -d .git ] +then + git init + git remote add origin https://github.com/Putnam3145/auxmos.git +fi + +git fetch origin --depth=1 $AUXMOS_VERSION +git reset --hard FETCH_HEAD + +rustup target add i686-unknown-linux-gnu + +env PKG_CONFIG_ALLOW_CROSS=1 cargo build --release --target=i686-unknown-linux-gnu --features "all_reaction_hooks,katmos" + +mkdir -p ~/.byond/bin +cp target/i686-unknown-linux-gnu/release/libauxmos.so ~/.byond/bin/libauxmos.so +chmod +x ~/.byond/bin/libauxmos.so +ldd ~/.byond/bin/libauxmos.so + +popd diff --git a/tools/ci/build_rust_g.sh b/tools/ci/build_rust_g.sh new file mode 100644 index 000000000000..59746a4c3a09 --- /dev/null +++ b/tools/ci/build_rust_g.sh @@ -0,0 +1,27 @@ +#!/bin/bash +set -euo pipefail + +source dependencies.sh + +mkdir -p "$HOME/rust-g" +pushd "$HOME/rust-g" + +if [ ! -d .git ] +then + git init + git remote add origin https://github.com/tgstation/rust-g.git +fi + +git fetch origin --depth=1 $RUST_G_VERSION +git reset --hard FETCH_HEAD + +rustup target add i686-unknown-linux-gnu + +env PKG_CONFIG_ALLOW_CROSS=1 cargo build --release --target=i686-unknown-linux-gnu + +mkdir -p ~/.byond/bin +cp target/i686-unknown-linux-gnu/release/librust_g.so ~/.byond/bin/librust_g.so +chmod +x ~/.byond/bin/librust_g.so +ldd ~/.byond/bin/librust_g.so + +popd diff --git a/tools/ci/build_spaceman_dmm.sh b/tools/ci/build_spaceman_dmm.sh index d63aeac2cc85..526be2e828cc 100755 --- a/tools/ci/build_spaceman_dmm.sh +++ b/tools/ci/build_spaceman_dmm.sh @@ -3,7 +3,8 @@ set -euo pipefail source dependencies.sh -cd $HOME/SpacemanDMM +mkdir -p "$HOME/SpacemanDMM" +cd "$HOME/SpacemanDMM" if [ ! -d .git ] then @@ -11,7 +12,7 @@ then git remote add origin https://github.com/SpaceManiac/SpacemanDMM.git fi -git fetch origin --depth=1 $SPACEMAN_DMM_COMMIT_HASH +git fetch origin --depth=1 $SPACEMAN_DMM_VERSION git reset --hard FETCH_HEAD cargo build --release --bin $1 diff --git a/tools/tgs_scripts/InstallDeps.sh b/tools/tgs_scripts/InstallDeps.sh index b446bd9e55c6..ce3a02a05147 100755 --- a/tools/tgs_scripts/InstallDeps.sh +++ b/tools/tgs_scripts/InstallDeps.sh @@ -18,11 +18,11 @@ if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -x "$has_curl" ] && [ -f "/ if ! [ -x "$has_sudo" ]; then dpkg --add-architecture i386 apt-get update - apt-get install -y build-essential g++-multilib libc6-i386 libstdc++6:i386 lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep + apt-get install -y build-essential clang g++-multilib libc6-i386 libstdc++6:i386 lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep else sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y build-essential g++-multilib libc6-i386 libstdc++6:i386 lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep + sudo apt-get install -y build-essential clang g++-multilib libc6-i386 libstdc++6:i386 lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep fi fi diff --git a/tools/tgs_scripts/PreCompile.sh b/tools/tgs_scripts/PreCompile.sh index 6e34ab65af6a..eb45c8bf362b 100755 --- a/tools/tgs_scripts/PreCompile.sh +++ b/tools/tgs_scripts/PreCompile.sh @@ -53,7 +53,7 @@ cd .. echo "Deploying auxmos..." cd auxmos git checkout "$AUXMOS_VERSION" -env PKG_CONFIG_ALLOW_CROSS=1 RUSTFLAGS="-C target-cpu=native" ~/.cargo/bin/cargo rustc --release --target=i686-unknown-linux-gnu --features "all_reaction_hooks,katmos" -- -C target_cpu=native +env PKG_CONFIG_ALLOW_CROSS=1 RUSTFLAGS="-C target-cpu=native" ~/.cargo/bin/cargo build --release --target=i686-unknown-linux-gnu --features "all_reaction_hooks,katmos" mv target/i686-unknown-linux-gnu/release/libauxmos.so "$1/libauxmos.so" cd ..