kg
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
delta 1411
zcmZuxeK^wz9RF=BW@*DR<+AOBJrB*Cu5-$=JzR)IN={z3%1d4*mr%xUW{Xo7b-Eiq~eddDJ*$EBM@+(cpar{@-M~&fh1Rqi*LMLJwM{Eibpy>EAXNZrCHC(^xkiES~TgSED3>4Lz?7V%jZ~*}H
zE4@8v2hvJr!djAsD42K8!DkyidJ2Cv4FwV^fq)d4iM=rA#dEw(0BXAVAc6oOMFNBD
z`8267+YSs`uj&e0x`3HAa>RIrV^&`Pj2Rne(l?Mmryz?=PU
zKcsOU3Ol(nu;zB?0Iunr;SUX~0b
zhVO8U#+B2u$V?k$O8QZ)q(@(%4xZ)=Ql|<4*
zvfNskl07$|9MAZHhQ)r5n>S&&DcBTsP23|gM57@nX0GWf_6|E-0R-UYO;bJ!>&ioW
zP_&EFxh}}zoFT0L&eV;P&okHbRKJ{iI>`p3VB~Fd?eyY@CG$`W!c&Ie@MW3ba7wic
zBdH$8{h52(eGJDyv|(Ne$^yA_ce6_Gyqrh+?51R-V7UeJ?^zTDZ!765vV3cK_6WGC
z@P&1k=V?={V5|yR6<}rH`F1hBRaz=aZg5Wv+y;Hv5Y^OXYNf@4^$q{4Q-r!y|Z-(nI(XIM<5gCT?awLtrooHBKs}Ga%v7>w=
z0gtZG3&GE8)-uAGs-?7|*-2E%cipT;(A}b4yo8u^iY$u2oK0(?o)@jG@Ops`nZb4)
z^{WPV6@1Y_@+ozrutoxUnSV?M^R3qXct-0p=|YxN%g=v0t|2-u#%IthzTTa)ur3pG
zt+J(@(keYP^f2miX;$0%VZ-88``l;ZbSV%gu(Y0()W)RaDKJZ|;0t&`2
z-ihy@JydWPeeAEL@^JTAP4t9bxe77G;dODc)2Q%UlUF&^x=Qc4>I;>SNn)nv-Nd2=
zs`KV#D^E!O(&0{UOK=D#*;mTTa~qfPeyeA*X?<`JqT8Hu2vg4up`AmKkfu23A8jqP
z0K1O{o6o?-BU~j8SVl@#*G*;WCpW<#mckfww-v@ugC)6p+oq*S;$N3k0XLHjQ^m>a|bT*su_1q(Ji2u>;57Bj{r8U3emN(oeTv@M&UlZ
zb_5BVr^uEWkVEmo5n`&4%>;MT#Sz5QBfzeFF13PC+epY9$vT`U$(ba|)!gJJy7<(J
zm--=Sb4{VCgjNb1GOgfjG|9oR)&OhHAJQ{Iwa&nFcGTQf-idT~7ENTFD
Date: Fri, 3 May 2024 01:47:00 +1200
Subject: [PATCH 32/87] Automatic changelog for PR #82997 [ci skip]
---
html/changelogs/AutoChangeLog-pr-82997.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-82997.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82997.yml b/html/changelogs/AutoChangeLog-pr-82997.yml
new file mode 100644
index 0000000000000..bba9e4e7b6035
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-82997.yml
@@ -0,0 +1,4 @@
+author: "mc-oofert"
+delete-after: True
+changes:
+ - image: "added directional sprites for radiation shutters"
\ No newline at end of file
From 2f660b328ace9d4de950df2a2aa379986178d2cd Mon Sep 17 00:00:00 2001
From: Echriser
Date: Thu, 2 May 2024 11:08:59 -0500
Subject: [PATCH 33/87] Conveyors switches now use left and right click
(#83001)
## About The Pull Request
Replaces current switch behavior from having to spam to get between
forward, off, and reversing states to just use left and right click. It
also removes the previous toggle behavior from the circuit trigger in
favor or the forward, backwards, and stop buttons. Follow up to
suggested changes from #82857
## Why It's Good For The Game
No more spamming left click to get to the state you want, nor worrying
about what the previous direction was and not knowing which way it's
gonna go.
## Changelog
:cl:
qol: conveyors now use left and right click controls
qol: add screentips for conveyor switches
del: removes circuit conveyor circuit default trigger behavior in favor
in favor of the three state triggers
/:cl:
---
code/modules/recycling/conveyor.dm | 53 +++++++++++++++++-------------
1 file changed, 30 insertions(+), 23 deletions(-)
diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm
index 36d73552159c2..6ef15929ecc5e 100644
--- a/code/modules/recycling/conveyor.dm
+++ b/code/modules/recycling/conveyor.dm
@@ -350,8 +350,6 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
/// The current state of the switch.
var/position = CONVEYOR_OFF
- /// Last direction setting.
- var/last_pos = CONVEYOR_BACKWARDS
/// If the switch only operates the conveyor belts in a single direction.
var/oneway = FALSE
/// If the level points the opposite direction when it's turned on.
@@ -372,6 +370,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
AddComponent(/datum/component/usb_port, list(
/obj/item/circuit_component/conveyor_switch,
))
+ register_context()
/obj/machinery/conveyor_switch/Destroy()
LAZYREMOVE(GLOB.conveyors_by_id[id], src)
@@ -397,6 +396,27 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
icon_state = "[base_icon_state]-[invert_icon ? "rev" : "fwd"]"
return ..()
+/obj/machinery/conveyor_switch/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+ if(!held_item)
+ context[SCREENTIP_CONTEXT_LMB] = "Toggle forwards"
+ if(!oneway)
+ context[SCREENTIP_CONTEXT_RMB] = "Toggle backwards"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.tool_behaviour == TOOL_MULTITOOL)
+ context[SCREENTIP_CONTEXT_LMB] = "Set speed"
+ context[SCREENTIP_CONTEXT_RMB] = "View wires"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
+ context[SCREENTIP_CONTEXT_LMB] = "Toggle oneway"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.tool_behaviour == TOOL_CROWBAR)
+ context[SCREENTIP_CONTEXT_LMB] = "Detach"
+ return CONTEXTUAL_SCREENTIP_SET
+ if(held_item.tool_behaviour == TOOL_WRENCH)
+ context[SCREENTIP_CONTEXT_LMB] = "Invert"
+ return CONTEXTUAL_SCREENTIP_SET
+
/// Updates all conveyor belts that are linked to this switch, and tells them to start processing.
/obj/machinery/conveyor_switch/proc/update_linked_conveyors()
for(var/obj/machinery/conveyor/belt in GLOB.conveyors_by_id[id])
@@ -414,28 +434,29 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
CHECK_TICK
/// Updates the switch's `position` and `last_pos` variable. Useful so that the switch can properly cycle between the forwards, backwards and neutral positions.
-/obj/machinery/conveyor_switch/proc/update_position()
+/obj/machinery/conveyor_switch/proc/update_position(direction)
if(position == CONVEYOR_OFF)
if(oneway) //is it a oneway switch
position = oneway
else
- if(last_pos < CONVEYOR_OFF)
+ if(direction == CONVEYOR_FORWARD)
position = CONVEYOR_FORWARD
- last_pos = CONVEYOR_OFF
else
position = CONVEYOR_BACKWARDS
- last_pos = CONVEYOR_OFF
else
- last_pos = position
position = CONVEYOR_OFF
/// Called when a user clicks on this switch with an open hand.
-/obj/machinery/conveyor_switch/interact(mob/user)
+/obj/machinery/conveyor_switch/attack_hand(mob/living/user, list/modifiers)
add_fingerprint(user)
- update_position()
+ if(LAZYACCESS(modifiers, RIGHT_CLICK))
+ update_position(CONVEYOR_BACKWARDS)
+ else
+ update_position(CONVEYOR_FORWARD)
update_appearance()
update_linked_conveyors()
update_linked_switches()
+ return TRUE
/obj/machinery/conveyor_switch/attackby(obj/item/attacking_item, mob/user, params)
if(is_wire_tool(attacking_item))
@@ -588,7 +609,6 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
/obj/item/circuit_component/conveyor_switch
display_name = "Conveyor Switch"
desc = "Allows to control connected conveyor belts."
- circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
/// Direction input ports.
var/datum/port/input/stop
@@ -619,12 +639,6 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
attached_switch = null
return ..()
-/obj/item/circuit_component/conveyor_switch/input_received(datum/port/input/port)
- if(!attached_switch)
- return
-
- INVOKE_ASYNC(src, PROC_REF(update_conveyors), port)
-
/obj/item/circuit_component/conveyor_switch/proc/on_switch_changed()
attached_switch.update_appearance()
attached_switch.update_linked_conveyors()
@@ -646,13 +660,6 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
attached_switch.position = CONVEYOR_BACKWARDS
INVOKE_ASYNC(src, PROC_REF(on_switch_changed))
-/obj/item/circuit_component/conveyor_switch/proc/update_conveyors(datum/port/input/port)
- if(!attached_switch)
- return
-
- attached_switch.update_position()
- INVOKE_ASYNC(src, PROC_REF(on_switch_changed))
-
#undef CONVEYOR_BACKWARDS
#undef CONVEYOR_OFF
#undef CONVEYOR_FORWARD
From 6d043f34f65fc138ca27a69cc905754a68233beb Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 04:09:21 +1200
Subject: [PATCH 34/87] Automatic changelog for PR #83001 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83001.yml | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83001.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83001.yml b/html/changelogs/AutoChangeLog-pr-83001.yml
new file mode 100644
index 0000000000000..36e13fbda33e3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83001.yml
@@ -0,0 +1,6 @@
+author: "Echriser"
+delete-after: True
+changes:
+ - qol: "conveyors now use left and right click controls"
+ - qol: "add screentips for conveyor switches"
+ - rscdel: "removes circuit conveyor circuit default trigger behavior in favor in favor of the three state triggers"
\ No newline at end of file
From b5a9c322b704380e58dbce0d475db02a336be498 Mon Sep 17 00:00:00 2001
From: Zenog400 <41298161+Zenog400@users.noreply.github.com>
Date: Thu, 2 May 2024 09:28:11 -0700
Subject: [PATCH 35/87] More Machine Blessing Options (#82606)
## About The Pull Request
Adds more implants to the pool that the Machine Blessing rite can draw
from, and rebalances the drop rates so that you're more likely to get
thematically-consistent implants.
## Why It's Good For The Game
Currently, the options for what the Machine Blessing rite can give you
are kinda garbage, considering that _one_ implant from the rite is the
same value as _two_ full species conversions. This adds a few more that
are actually useful.
Specific implants added:
- Combat arm (extremely low drop rate)
- Tool arm (higher drop rate)
- Reviver implant (lower drop rate)
- Anti-drop implant
- Anti-stun implant (significantly lower drop rate)
- Welding eyes
Additionally, slightly lowers the drop rate of the breathing tube
implant, because androids don't have lungs
## Changelog
:cl:
add: increased the size of the pool that Machine Blessing draws from
balance: weighted some of the implants that Machine Blessing can give
/:cl:
---------
Co-authored-by: Jacquerel
---
code/modules/religion/rites.dm | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm
index d907191c33ddd..fa7d31c324920 100644
--- a/code/modules/religion/rites.dm
+++ b/code/modules/religion/rites.dm
@@ -128,13 +128,33 @@
/datum/religion_rites/machine_blessing/invoke_effect(mob/living/user, atom/movable/religious_tool)
..()
var/altar_turf = get_turf(religious_tool)
- var/blessing = pick(
- /obj/item/organ/internal/cyberimp/arm/surgery,
+ var/arm = list(
+ /obj/item/organ/internal/cyberimp/arm/combat,
+ /obj/item/organ/internal/cyberimp/arm/surgery = 1000000,
+ /obj/item/organ/internal/cyberimp/arm/toolset = 1500000
+ )
+ var/eyes = list(
/obj/item/organ/internal/cyberimp/eyes/hud/diagnostic,
/obj/item/organ/internal/cyberimp/eyes/hud/medical,
- /obj/item/organ/internal/cyberimp/mouth/breathing_tube,
- /obj/item/organ/internal/cyberimp/chest/thrusters,
- /obj/item/organ/internal/eyes/robotic/glow,
+ /obj/item/organ/internal/eyes/robotic/shield = 2,
+ /obj/item/organ/internal/eyes/robotic/glow
+ )
+ var/chest = list(
+ /obj/item/organ/internal/cyberimp/chest/reviver,
+ /obj/item/organ/internal/cyberimp/chest/thrusters = 2
+ )
+ var/head = list(
+ /obj/item/organ/internal/cyberimp/brain/anti_drop = 100,
+ /obj/item/organ/internal/cyberimp/brain/anti_stun = 10
+ )
+ var/blessing = pick_weight_recursive(
+ list(
+ arm = 15,
+ eyes = 15,
+ chest = 9,
+ head = 10,
+ /obj/item/organ/internal/cyberimp/mouth/breathing_tube = 5,
+ )
)
new blessing(altar_turf)
return TRUE
From 71928e9678b921c5a4dcbad524b27feb8bf01dda Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 04:28:56 +1200
Subject: [PATCH 36/87] Automatic changelog for PR #82606 [ci skip]
---
html/changelogs/AutoChangeLog-pr-82606.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-82606.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82606.yml b/html/changelogs/AutoChangeLog-pr-82606.yml
new file mode 100644
index 0000000000000..90cf1fc2d1751
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-82606.yml
@@ -0,0 +1,5 @@
+author: "Zenog400"
+delete-after: True
+changes:
+ - rscadd: "increased the size of the pool that Machine Blessing draws from"
+ - balance: "weighted some of the implants that Machine Blessing can give"
\ No newline at end of file
From 504f54104ae4958207d127652322a9a04a326520 Mon Sep 17 00:00:00 2001
From: Changelogs
Date: Fri, 3 May 2024 00:22:39 +0000
Subject: [PATCH 37/87] Automatic changelog compile [ci skip]
---
html/changelogs/AutoChangeLog-pr-82606.yml | 5 -----
html/changelogs/AutoChangeLog-pr-82978.yml | 5 -----
html/changelogs/AutoChangeLog-pr-82993.yml | 4 ----
html/changelogs/AutoChangeLog-pr-82997.yml | 4 ----
html/changelogs/AutoChangeLog-pr-83001.yml | 6 ------
html/changelogs/archive/2024-05.yml | 16 ++++++++++++++++
6 files changed, 16 insertions(+), 24 deletions(-)
delete mode 100644 html/changelogs/AutoChangeLog-pr-82606.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-82978.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-82993.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-82997.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83001.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82606.yml b/html/changelogs/AutoChangeLog-pr-82606.yml
deleted file mode 100644
index 90cf1fc2d1751..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82606.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Zenog400"
-delete-after: True
-changes:
- - rscadd: "increased the size of the pool that Machine Blessing draws from"
- - balance: "weighted some of the implants that Machine Blessing can give"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-82978.yml b/html/changelogs/AutoChangeLog-pr-82978.yml
deleted file mode 100644
index e9b93d33a3f38..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82978.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Gaxeer"
-delete-after: True
-changes:
- - bugfix: "fix runtime when no events were drafted to be picked from"
- - config: "make events frequency configurable"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-82993.yml b/html/changelogs/AutoChangeLog-pr-82993.yml
deleted file mode 100644
index 18966acc72ef9..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82993.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "StrangeWeirdKitten"
-delete-after: True
-changes:
- - qol: "You can now quickly stamp papers with a right click"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-82997.yml b/html/changelogs/AutoChangeLog-pr-82997.yml
deleted file mode 100644
index bba9e4e7b6035..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82997.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "mc-oofert"
-delete-after: True
-changes:
- - image: "added directional sprites for radiation shutters"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83001.yml b/html/changelogs/AutoChangeLog-pr-83001.yml
deleted file mode 100644
index 36e13fbda33e3..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83001.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "Echriser"
-delete-after: True
-changes:
- - qol: "conveyors now use left and right click controls"
- - qol: "add screentips for conveyor switches"
- - rscdel: "removes circuit conveyor circuit default trigger behavior in favor in favor of the three state triggers"
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml
index 90ccdc1199d2a..8e615e3cb43ed 100644
--- a/html/changelogs/archive/2024-05.yml
+++ b/html/changelogs/archive/2024-05.yml
@@ -74,3 +74,19 @@
options
nikothedude:
- bugfix: Jousting no longer bypasses pacifism
+2024-05-03:
+ Echriser:
+ - qol: conveyors now use left and right click controls
+ - qol: add screentips for conveyor switches
+ - rscdel: removes circuit conveyor circuit default trigger behavior in favor in
+ favor of the three state triggers
+ Gaxeer:
+ - bugfix: fix runtime when no events were drafted to be picked from
+ - config: make events frequency configurable
+ StrangeWeirdKitten:
+ - qol: You can now quickly stamp papers with a right click
+ Zenog400:
+ - rscadd: increased the size of the pool that Machine Blessing draws from
+ - balance: weighted some of the implants that Machine Blessing can give
+ mc-oofert:
+ - image: added directional sprites for radiation shutters
From c58193910c06ecbe9f979b08d6b208529f1fbdec Mon Sep 17 00:00:00 2001
From: Kyle Spier-Swenson
Date: Thu, 2 May 2024 18:56:38 -0700
Subject: [PATCH 38/87] Bump supported client api version to 515 (#83011)
---
.github/max_required_byond_client.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/max_required_byond_client.txt b/.github/max_required_byond_client.txt
index faf8058076a2a..bd10125cce940 100644
--- a/.github/max_required_byond_client.txt
+++ b/.github/max_required_byond_client.txt
@@ -5,4 +5,4 @@
# (Requiring clients update to connect to the game server is not something we like to spring on them with no notice,
# especially for beta builds where the pager/updater won't let them update without additional configuration.)
-514
+515
From ad968fc793d0f1d57bbf0942f9e3127d12c774ee Mon Sep 17 00:00:00 2001
From: Ikalpo
Date: Thu, 2 May 2024 18:57:01 -0700
Subject: [PATCH 39/87] 13 year old singularity bug fixed (#83005)
## About The Pull Request
Stage 2 singularities have the wrong step size, allowing them to eat the
containment field if they happen to be right next to it.
(For instance, if they are contained in a 3x3 or 4x4 field)
2 lines of code, and that's fixed.
## Why It's Good For The Game
BEFORE
https://github.com/tgstation/tgstation/assets/23534908/821f43f6-85ca-482b-a905-614f2b1c8359
AFTER
https://github.com/tgstation/tgstation/assets/23534908/4580d23a-41f0-4485-8454-4e991aa38344
## The Source
This was introduced in a googlecode commit in 2011:
https://github.com/tgstation/tgstation/blob/337be2c3bcc7a739ffc927ccce9d6aa2b43c114c/code/modules/power/singularity/singularity.dm#L269
No, mport2004, I *don't* think this is right.
## Changelog
:cl:
fix: Stage 2 singularities should no longer escape containment
/:cl:
---
code/datums/components/singularity.dm | 2 +-
code/modules/power/singularity/singularity.dm | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/datums/components/singularity.dm b/code/datums/components/singularity.dm
index 56a6723f21f41..14aaedff7172a 100644
--- a/code/datums/components/singularity.dm
+++ b/code/datums/components/singularity.dm
@@ -286,7 +286,7 @@
if (STAGE_ONE)
steps = 1
if (STAGE_TWO)
- steps = 3//Yes this is right
+ steps = 2
if (STAGE_THREE)
steps = 3
if (STAGE_FOUR)
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index d47d75360946a..74b7bfdbcdcb4 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -340,7 +340,7 @@
if(STAGE_ONE)
steps = 1
if(STAGE_TWO)
- steps = 3//Yes this is right
+ steps = 2
if(STAGE_THREE)
steps = 3
if(STAGE_FOUR)
From 52b0d48f3d38908790f495d318775e5e92b76ea5 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 13:57:20 +1200
Subject: [PATCH 40/87] Automatic changelog for PR #83005 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83005.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83005.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83005.yml b/html/changelogs/AutoChangeLog-pr-83005.yml
new file mode 100644
index 0000000000000..be13b5786e78c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83005.yml
@@ -0,0 +1,4 @@
+author: "Ikalpo"
+delete-after: True
+changes:
+ - bugfix: "Stage 2 singularities should no longer escape containment"
\ No newline at end of file
From 8da332e50b8a2d92beb2683b2db21d817195805e Mon Sep 17 00:00:00 2001
From: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Date: Thu, 2 May 2024 21:02:30 -0500
Subject: [PATCH 41/87] Fix warning on master (#83014)
## Changelog
:cl: Melbert
fix: New machine god blessings now actually works probably
/:cl:
---
code/modules/religion/rites.dm | 55 ++++++++++++++++++----------------
1 file changed, 29 insertions(+), 26 deletions(-)
diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm
index fa7d31c324920..d7d0fa818441c 100644
--- a/code/modules/religion/rites.dm
+++ b/code/modules/religion/rites.dm
@@ -128,33 +128,36 @@
/datum/religion_rites/machine_blessing/invoke_effect(mob/living/user, atom/movable/religious_tool)
..()
var/altar_turf = get_turf(religious_tool)
- var/arm = list(
- /obj/item/organ/internal/cyberimp/arm/combat,
- /obj/item/organ/internal/cyberimp/arm/surgery = 1000000,
- /obj/item/organ/internal/cyberimp/arm/toolset = 1500000
- )
- var/eyes = list(
- /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic,
- /obj/item/organ/internal/cyberimp/eyes/hud/medical,
- /obj/item/organ/internal/eyes/robotic/shield = 2,
- /obj/item/organ/internal/eyes/robotic/glow
- )
- var/chest = list(
- /obj/item/organ/internal/cyberimp/chest/reviver,
- /obj/item/organ/internal/cyberimp/chest/thrusters = 2
- )
- var/head = list(
- /obj/item/organ/internal/cyberimp/brain/anti_drop = 100,
- /obj/item/organ/internal/cyberimp/brain/anti_stun = 10
- )
var/blessing = pick_weight_recursive(
- list(
- arm = 15,
- eyes = 15,
- chest = 9,
- head = 10,
- /obj/item/organ/internal/cyberimp/mouth/breathing_tube = 5,
- )
+ list(
+ // Arms
+ list(
+ /obj/item/organ/internal/cyberimp/arm/combat = 1,
+ /obj/item/organ/internal/cyberimp/arm/surgery = 1000000,
+ /obj/item/organ/internal/cyberimp/arm/toolset = 1500000,
+ ) = 15,
+ // Eyes
+ list(
+ /obj/item/organ/internal/cyberimp/eyes/hud/diagnostic = 1,
+ /obj/item/organ/internal/cyberimp/eyes/hud/medical = 1,
+ /obj/item/organ/internal/eyes/robotic/glow = 1,
+ /obj/item/organ/internal/eyes/robotic/shield = 2,
+ ) = 15,
+ // Chest
+ list(
+ /obj/item/organ/internal/cyberimp/chest/reviver = 1,
+ /obj/item/organ/internal/cyberimp/chest/thrusters = 2,
+ ) = 9,
+ // Brain / Head
+ list(
+ /obj/item/organ/internal/cyberimp/brain/anti_drop = 100,
+ /obj/item/organ/internal/cyberimp/brain/anti_stun = 10,
+ ) = 10,
+ // Misc
+ list(
+ /obj/item/organ/internal/cyberimp/mouth/breathing_tube = 1,
+ ) = 5,
+ )
)
new blessing(altar_turf)
return TRUE
From dc202e7642401d22ff962bf5931ac6cd4e3717f4 Mon Sep 17 00:00:00 2001
From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Date: Fri, 3 May 2024 05:03:19 +0300
Subject: [PATCH 42/87] fixes a few problems in ai targetting (#82998)
## About The Pull Request
fixes #82964 , fixes #82866
## Why It's Good For The Game
fixes several problems with ai targetting. this pr resolves civil war
that was brewing between several mobs. also fixes a major problem where
mobs would only search for targets and not perform any other behaviors.
also fixes a small problem where mobs would constantly stop and start
while chasing targets
## Changelog
:cl:
fix: mobs in the same faction will no longer be at odds against one
another
fix: mobs can now perform behaviors alongside searching for targets
fix: mobs will no longer be starting and stopping when chasing targets
/:cl:
---
code/datums/ai/_ai_controller.dm | 8 ++++++--
code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm | 3 ++-
.../ai/basic_mobs/basic_subtrees/capricious_retaliate.dm | 1 +
.../ai/basic_mobs/basic_subtrees/target_retaliate.dm | 5 +----
4 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm
index 309be50878341..35615c6704c42 100644
--- a/code/datums/ai/_ai_controller.dm
+++ b/code/datums/ai/_ai_controller.dm
@@ -172,9 +172,13 @@ multiple modular subtrees with behaviors
return FALSE
return TRUE
-/datum/ai_controller/proc/recalculate_idle()
+/datum/ai_controller/proc/recalculate_idle(datum/exited)
if(ai_status == AI_STATUS_OFF)
return
+
+ if(exited && (get_dist(pawn, (islist(exited) ? exited[1] : exited)) <= interesting_dist)) //is our target in between interesting cells?
+ return
+
if(should_idle())
set_ai_status(AI_STATUS_IDLE)
@@ -187,7 +191,7 @@ multiple modular subtrees with behaviors
/datum/ai_controller/proc/on_client_exit(datum/source, datum/exited)
SIGNAL_HANDLER
- recalculate_idle()
+ recalculate_idle(exited)
/// Sets the AI on or off based on current conditions, call to reset after you've manually disabled it somewhere
/datum/ai_controller/proc/reset_ai_status()
diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm
index f0ee4bb9bba37..4cf04039e8535 100644
--- a/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm
+++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/targeting.dm
@@ -7,6 +7,7 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/
/datum/ai_behavior/find_potential_targets
action_cooldown = 2 SECONDS
+ behavior_flags = AI_BEHAVIOR_CAN_PLAN_DURING_EXECUTION
/// How far can we see stuff?
var/vision_range = 9
/// Blackboard key for aggro range, uses vision range if not specified
@@ -34,7 +35,7 @@ GLOBAL_LIST_INIT(target_interested_atoms, typecacheof(list(/mob, /obj/machinery/
// If we're using a field rn, just don't do anything yeah?
if(controller.blackboard[BB_FIND_TARGETS_FIELD(type)])
- return
+ return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/list/potential_targets = hearers(aggro_range, get_turf(controller.pawn)) - living_mob //Remove self, so we don't suicide
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm
index a4fc49facc000..52b19036b9a47 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/capricious_retaliate.dm
@@ -21,6 +21,7 @@
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED
pawn.visible_message(span_notice("[pawn] calms down.")) // We can blackboard key this if anyone else actually wants to customise it
controller.clear_blackboard_key(BB_BASIC_MOB_RETALIATE_LIST)
+ controller.clear_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET)
controller.CancelActions() // Otherwise they will try and get one last kick in
return AI_BEHAVIOR_DELAY
diff --git a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm
index d327b1047cf57..042ccb2310c1a 100644
--- a/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm
+++ b/code/datums/ai/basic_mobs/basic_subtrees/target_retaliate.dm
@@ -11,7 +11,6 @@
var/check_faction = FALSE
/datum/ai_planning_subtree/target_retaliate/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick)
- . = ..()
controller.queue_behavior(/datum/ai_behavior/target_from_retaliate_list, BB_BASIC_MOB_RETALIATE_LIST, target_key, targeting_strategy_key, hiding_place_key, check_faction)
/datum/ai_planning_subtree/target_retaliate/check_faction
@@ -35,7 +34,6 @@
var/vision_range = 9
/datum/ai_behavior/target_from_retaliate_list/perform(seconds_per_tick, datum/ai_controller/controller, shitlist_key, target_key, targeting_strategy_key, hiding_location_key, check_faction)
- . = ..()
var/mob/living/living_mob = controller.pawn
var/datum/targeting_strategy/targeting_strategy = GET_TARGETING_STRATEGY(controller.blackboard[targeting_strategy_key])
if(!targeting_strategy)
@@ -58,7 +56,6 @@
enemies_list += potential_target
if(!length(enemies_list))
- controller.clear_blackboard_key(target_key)
return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED
var/atom/new_target = pick_final_target(controller, enemies_list)
@@ -75,7 +72,7 @@
/datum/ai_behavior/target_from_retaliate_list/proc/pick_final_target(datum/ai_controller/controller, list/enemies_list)
return pick(enemies_list)
-/datum/ai_behavior/target_from_retaliate_list/finish_action(datum/ai_controller/controller, succeeded, check_faction)
+/datum/ai_behavior/target_from_retaliate_list/finish_action(datum/ai_controller/controller, succeeded, shitlist_key, target_key, targeting_strategy_key, hiding_location_key, check_faction)
. = ..()
if (succeeded || check_faction)
return
From 8bbfd225cd4d39e33dd6c8600174265aef8fab67 Mon Sep 17 00:00:00 2001
From: Ryll Ryll <3589655+Ryll-Ryll@users.noreply.github.com>
Date: Thu, 2 May 2024 22:03:41 -0400
Subject: [PATCH 43/87] Pacifists can no longer endlessly spam rocket launcher
backblasts (#82992)
## About The Pull Request
Fixes: #82990
Backblasts from a rocket launcher are often the last thing an untrained
person thinks of when they fire a rocket launcher. I did not consider
the moral stance of pacifists who nevertheless try to shoot rocket
launchers when I implemented rocket launcher backblast, because
currently pacifists trying to shoot a loaded rocket launcher can spam
backblast as much as they want, even if they aren't able to actually
shoot.
This PR filters out pacifists before they trigger the backblast, to make
sure only actual live shots deliver the hellpayload to their allies
behind them.
## Why It's Good For The Game
A magical reverse flamethrower with no ammo limit (because at no point
is the rocket in the chamber actually expended when a pacifist fails to
fire it) is bad. A weapon as destructive as that left solely in the
hands of pacifists is even worse.
## Changelog
:cl: Ryll/Shaps
fix: Pacifists can no longer endlessly spam the backblast functionality
of loaded rocket launchers that they cannot actually fire
/:cl:
---------
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
---
code/datums/elements/backblast.dm | 3 +++
1 file changed, 3 insertions(+)
diff --git a/code/datums/elements/backblast.dm b/code/datums/elements/backblast.dm
index 8952afbfeaa21..f5e73977159cd 100644
--- a/code/datums/elements/backblast.dm
+++ b/code/datums/elements/backblast.dm
@@ -38,6 +38,9 @@
/// For firing an actual backblast pellet
/datum/element/backblast/proc/pew(obj/item/gun/weapon, mob/living/user, atom/target)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ return
+
var/turf/origin = get_turf(weapon)
var/backblast_angle = get_angle(target, origin)
explosion(weapon, devastation_range = dev_range, heavy_impact_range = heavy_range, light_impact_range = light_range, flame_range = flame_range, adminlog = FALSE, protect_epicenter = TRUE, explosion_direction = backblast_angle, explosion_arc = blast_angle)
From f70c83cd697246f6e5be418b5b22fe7b12228c6b Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 14:05:27 +1200
Subject: [PATCH 44/87] Automatic changelog for PR #83014 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83014.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83014.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83014.yml b/html/changelogs/AutoChangeLog-pr-83014.yml
new file mode 100644
index 0000000000000..ebd44714a49a6
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83014.yml
@@ -0,0 +1,4 @@
+author: "Melbert"
+delete-after: True
+changes:
+ - bugfix: "New machine god blessings now actually works probably"
\ No newline at end of file
From 854668cb44749bf8989ae4ea4d3d116b6f7192ee Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 14:06:04 +1200
Subject: [PATCH 45/87] Automatic changelog for PR #82998 [ci skip]
---
html/changelogs/AutoChangeLog-pr-82998.yml | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-82998.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82998.yml b/html/changelogs/AutoChangeLog-pr-82998.yml
new file mode 100644
index 0000000000000..696b730fca1ee
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-82998.yml
@@ -0,0 +1,6 @@
+author: "Ben10Omintrix"
+delete-after: True
+changes:
+ - bugfix: "mobs in the same faction will no longer be at odds against one another"
+ - bugfix: "mobs can now perform behaviors alongside searching for targets"
+ - bugfix: "mobs will no longer be starting and stopping when chasing targets"
\ No newline at end of file
From 3e85d915f4ca30ae978edb8f2efd8614d20023e0 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 14:06:26 +1200
Subject: [PATCH 46/87] Automatic changelog for PR #82992 [ci skip]
---
html/changelogs/AutoChangeLog-pr-82992.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-82992.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82992.yml b/html/changelogs/AutoChangeLog-pr-82992.yml
new file mode 100644
index 0000000000000..eb03652dc1470
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-82992.yml
@@ -0,0 +1,4 @@
+author: "Ryll/Shaps"
+delete-after: True
+changes:
+ - bugfix: "Pacifists can no longer endlessly spam the backblast functionality of loaded rocket launchers that they cannot actually fire"
\ No newline at end of file
From 79d858a02536d62bf041f87d92e9ba09256ca38c Mon Sep 17 00:00:00 2001
From: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Date: Thu, 2 May 2024 20:09:30 -0700
Subject: [PATCH 47/87] Detective buff: Fixes detective's candy dispenser
(#83004)
## About The Pull Request
Alt click was broken on detective's hat. Couldn't draw candy corn, oh
no!
This issue is somewhat rightly caused from the alt click refactor, as
its aim was to prevent double interactions from one click. In this case,
both withdrawing morsels and opening storage at the same time
---
code/datums/storage/storage.dm | 18 ++++++++++++-
code/datums/storage/subtypes/pockets.dm | 1 +
code/modules/clothing/head/jobs.dm | 35 ++++++++++++++++++++-----
3 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm
index b1bacfbceab44..9b661688258f1 100644
--- a/code/datums/storage/storage.dm
+++ b/code/datums/storage/storage.dm
@@ -113,6 +113,10 @@
/// If TRUE, shows the contents of the storage in open_storage
var/display_contents = TRUE
+ /// Switch this off if you want to handle click_alt in the parent atom
+ var/click_alt_open = TRUE
+
+
/datum/storage/New(
atom/parent,
max_slots = src.max_slots,
@@ -198,7 +202,7 @@
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(on_preattack))
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(mass_empty))
- RegisterSignals(parent, list(COMSIG_CLICK_ALT, COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), PROC_REF(open_storage_on_signal))
+ RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), PROC_REF(open_storage_on_signal))
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY_SECONDARY, PROC_REF(open_storage_attackby_secondary))
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(close_distance))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(update_actions))
@@ -208,6 +212,7 @@
RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, PROC_REF(on_deconstruct))
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp_act))
RegisterSignal(parent, COMSIG_ATOM_CONTENTS_WEIGHT_CLASS_CHANGED, PROC_REF(contents_changed_w_class))
+ RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(on_click_alt))
/**
* Sets where items are physically being stored in the case it shouldn't be on the parent.
@@ -919,6 +924,17 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
if(display_contents)
return COMPONENT_NO_AFTERATTACK
+
+/// Alt click on the storage item. Default: Open the storage.
+/datum/storage/proc/on_click_alt(datum/source, mob/user)
+ SIGNAL_HANDLER
+
+ if(!click_alt_open)
+ return
+
+ return open_storage_on_signal(source, user)
+
+
/// Opens the storage to the mob, showing them the contents to their UI.
/datum/storage/proc/open_storage(mob/to_show)
if(isobserver(to_show))
diff --git a/code/datums/storage/subtypes/pockets.dm b/code/datums/storage/subtypes/pockets.dm
index 67a8b2dda7804..2b100d5d3232b 100644
--- a/code/datums/storage/subtypes/pockets.dm
+++ b/code/datums/storage/subtypes/pockets.dm
@@ -45,6 +45,7 @@
/datum/storage/pockets/small/fedora/detective
attack_hand_interact = TRUE // so the detectives would discover pockets in their hats
+ click_alt_open = FALSE
/datum/storage/pockets/chefhat
attack_hand_interact = TRUE
diff --git a/code/modules/clothing/head/jobs.dm b/code/modules/clothing/head/jobs.dm
index 4f5d377ddac00..e0b06a5ab6e2f 100644
--- a/code/modules/clothing/head/jobs.dm
+++ b/code/modules/clothing/head/jobs.dm
@@ -166,6 +166,8 @@
desc = "An opulent hat that functions as a radio to God. Or as a lightning rod, depending on who you ask."
icon_state = "bishopmitre"
+#define CANDY_CD_TIME 2 MINUTES
+
//Detective
/obj/item/clothing/head/fedora/det_hat
name = "detective's fedora"
@@ -174,11 +176,12 @@
icon_state = "detective"
inhand_icon_state = "det_hat"
interaction_flags_click = NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING
- /// Cooldown for retrieving precious candy corn on alt click
- var/candy_cooldown = 0
dog_fashion = /datum/dog_fashion/head/detective
- ///Path for the flask that spawns inside their hat roundstart
+ /// Path for the flask that spawns inside their hat roundstart
var/flask_path = /obj/item/reagent_containers/cup/glass/flask/det
+ /// Cooldown for retrieving precious candy corn with rmb
+ COOLDOWN_DECLARE(candy_cooldown)
+
/datum/armor/fedora_det_hat
melee = 25
@@ -189,28 +192,46 @@
acid = 50
wound = 5
+
/obj/item/clothing/head/fedora/det_hat/Initialize(mapload)
. = ..()
create_storage(storage_type = /datum/storage/pockets/small/fedora/detective)
+ register_context()
+
new flask_path(src)
+
/obj/item/clothing/head/fedora/det_hat/examine(mob/user)
. = ..()
. += span_notice("Alt-click to take a candy corn.")
+
+/obj/item/clothing/head/fedora/det_hat/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+
+ context[SCREENTIP_CONTEXT_ALT_LMB] = "Candy Time"
+
+ return CONTEXTUAL_SCREENTIP_SET
+
+
+/// Now to solve where all these keep coming from
/obj/item/clothing/head/fedora/det_hat/click_alt(mob/user)
- if(candy_cooldown >= world.time)
+ if(!COOLDOWN_FINISHED(src, candy_cooldown))
to_chat(user, span_warning("You just took a candy corn! You should wait a couple minutes, lest you burn through your stash."))
return CLICK_ACTION_BLOCKING
- var/obj/item/food/candy_corn/CC = new /obj/item/food/candy_corn(src)
- user.put_in_hands(CC)
+ var/obj/item/food/candy_corn/sweets = new /obj/item/food/candy_corn(src)
+ user.put_in_hands(sweets)
to_chat(user, span_notice("You slip a candy corn from your hat."))
- candy_cooldown = world.time+1200
+ COOLDOWN_START(src, candy_cooldown, CANDY_CD_TIME)
+
return CLICK_ACTION_SUCCESS
+
+#undef CANDY_CD_TIME
+
/obj/item/clothing/head/fedora/det_hat/minor
flask_path = /obj/item/reagent_containers/cup/glass/flask/det/minor
From 5ced3d3521202738df7169dd55c52f266c967438 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 15:09:49 +1200
Subject: [PATCH 48/87] Automatic changelog for PR #83004 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83004.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83004.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83004.yml b/html/changelogs/AutoChangeLog-pr-83004.yml
new file mode 100644
index 0000000000000..c763ac3aa9594
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83004.yml
@@ -0,0 +1,4 @@
+author: "jlsnow301"
+delete-after: True
+changes:
+ - bugfix: "Candy corn is once again available to detective fedoras"
\ No newline at end of file
From 361850adf7df8e1c7f1e65c1ff98ecb0b939c9e9 Mon Sep 17 00:00:00 2001
From: mogeoko <109075486+mogeoko@users.noreply.github.com>
Date: Fri, 3 May 2024 06:05:41 +0200
Subject: [PATCH 49/87] [NO GBP] Multiz deck revert (#82996)
## About The Pull Request
I've probably did unnecessary things in my old PR and it made a little
problem for larvas. Now I revert my mistakes so they can feel great
again.
Partially reverts #81452, fixes
https://github.com/tgstation/tgstation/pull/82996
## Why It's Good For The Game
Larvas can change Z levels using multiz-deck again. Is good or at least
I hope so.
## Changelog
:cl: mogeoko
fix: Ventcrawling mobs can change Z-level using multiz-decks again.
/:cl:
---
code/modules/atmospherics/machinery/atmosmachinery.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index d152cf09e711f..fa8b833234586 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -301,8 +301,8 @@
* * given_layer - the piping_layer we are checking
*/
/obj/machinery/atmospherics/proc/connection_check(obj/machinery/atmospherics/target, given_layer)
- //check if the target & src connect in the same direction
- if(!((initialize_directions & get_dir(src, target)) && (target.initialize_directions & get_dir(target, src))))
+ //if target is not multiz then we have to check if the target & src connect in the same direction
+ if(!istype(target, /obj/machinery/atmospherics/pipe/multiz) && !((initialize_directions & get_dir(src, target)) && (target.initialize_directions & get_dir(target, src))))
return FALSE
//both target & src can't be connected either way
From 4a3996d248546ccb5073fd15c0e3da2d1f379116 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 16:06:03 +1200
Subject: [PATCH 50/87] Automatic changelog for PR #82996 [ci skip]
---
html/changelogs/AutoChangeLog-pr-82996.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-82996.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82996.yml b/html/changelogs/AutoChangeLog-pr-82996.yml
new file mode 100644
index 0000000000000..fada9ce1d19f1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-82996.yml
@@ -0,0 +1,4 @@
+author: "mogeoko"
+delete-after: True
+changes:
+ - bugfix: "Ventcrawling mobs can change Z-level using multiz-decks again."
\ No newline at end of file
From e54ecf4b10a6d4b17441ca6fd74d88617967dd41 Mon Sep 17 00:00:00 2001
From: Xander3359 <66163761+Xander3359@users.noreply.github.com>
Date: Fri, 3 May 2024 03:35:51 -0400
Subject: [PATCH 51/87] Fix crafting bypassing checks (#82833)
## About The Pull Request
Backport from
https://github.com/tgstation/TerraGov-Marine-Corps/pull/15701
Fixes crafting bypassing checks.
## Why It's Good For The Game
Closes https://github.com/tgstation/tgstation/issues/82826
## Changelog
:cl:
fix: You can no longer bypass construction restrictions via the crafting
menu
/:cl:
---
code/__DEFINES/crafting.dm | 22 +
code/controllers/subsystem/materials.dm | 12 +-
code/datums/components/crafting/_recipes.dm | 10 +-
.../datums/components/crafting/atmospheric.dm | 2 +-
code/datums/components/crafting/crafting.dm | 116 ++--
code/datums/components/crafting/doors.dm | 4 +-
.../components/crafting/melee_weapon.dm | 2 +-
code/datums/components/crafting/misc.dm | 2 +-
.../components/crafting/ranged_weapon.dm | 12 +-
code/datums/components/crafting/structures.dm | 8 +-
code/datums/components/crafting/tools.dm | 2 +-
.../datums/components/crafting/weapon_ammo.dm | 4 +-
code/game/objects/items/stacks/rods.dm | 27 +-
.../game/objects/items/stacks/sheets/glass.dm | 34 +-
.../objects/items/stacks/sheets/leather.dm | 80 +--
.../objects/items/stacks/sheets/mineral.dm | 64 +--
.../items/stacks/sheets/sheet_types.dm | 498 +++++++++---------
code/game/objects/items/stacks/stack.dm | 23 +-
.../game/objects/items/stacks/stack_recipe.dm | 30 +-
.../recipes/tablecraft/recipes_bread.dm | 2 +-
.../recipes/tablecraft/recipes_cake.dm | 4 +-
.../recipes/tablecraft/recipes_pie.dm | 6 +-
.../recipes/tablecraft/recipes_sandwich.dm | 2 +-
code/modules/mining/ores_coins.dm | 6 +-
24 files changed, 505 insertions(+), 467 deletions(-)
diff --git a/code/__DEFINES/crafting.dm b/code/__DEFINES/crafting.dm
index 647278aa3ec0b..54dc479aa7306 100644
--- a/code/__DEFINES/crafting.dm
+++ b/code/__DEFINES/crafting.dm
@@ -7,6 +7,28 @@
///If the structure is only "used" i.e. it checks to see if it's nearby and allows crafting, but doesn't delete it
#define CRAFTING_STRUCTURE_USE 0
+//stack recipe placement check types
+/// Checks if there is an object of the result type in any of the cardinal directions
+#define STACK_CHECK_CARDINALS (1<<0)
+/// Checks if there is an object of the result type within one tile
+#define STACK_CHECK_ADJACENT (1<<1)
+
+//---- Defines for var/crafting_flags
+///If this craft must be learned before it becomes available
+#define CRAFT_MUST_BE_LEARNED (1<<0)
+///Should only one object exist on the same turf?
+#define CRAFT_ONE_PER_TURF (1<<1)
+/// Setting this to true will effectively set check_direction to true.
+#define CRAFT_IS_FULLTILE (1<<2)
+/// If this craft should run the direction check, for use when building things like directional windows where you can have more than one per turf
+#define CRAFT_CHECK_DIRECTION (1<<3)
+/// If the craft requires a floor below
+#define CRAFT_ON_SOLID_GROUND (1<<4)
+/// If the craft checks that there are objects with density in the same turf when being built
+#define CRAFT_CHECK_DENSITY (1<<5)
+/// If the created atom will gain custom mat datums
+#define CRAFT_APPLIES_MATS (1<<6)
+
//food/drink crafting defines
//When adding new defines, please make sure to also add them to the encompassing list
#define CAT_FOOD "Foods"
diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm
index b4664323eebfa..3a704d01a82fd 100644
--- a/code/controllers/subsystem/materials.dm
+++ b/code/controllers/subsystem/materials.dm
@@ -21,15 +21,15 @@ SUBSYSTEM_DEF(materials)
var/list/list/material_combos
///List of stackcrafting recipes for materials using base recipes
var/list/base_stack_recipes = list(
- new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("Sink Frame", /obj/structure/sinkframe, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("Material floor tile", /obj/item/stack/tile/material, 1, 4, 20, applies_mats = TRUE, check_density = FALSE, category = CAT_TILES),
- new /datum/stack_recipe("Material airlock assembly", /obj/structure/door_assembly/door_assembly_material, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS),
+ new /datum/stack_recipe("Chair", /obj/structure/chair/greyscale, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE),
+ new /datum/stack_recipe("Toilet", /obj/structure/toilet/greyscale, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE),
+ new /datum/stack_recipe("Sink Frame", /obj/structure/sinkframe, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_FURNITURE),
+ new /datum/stack_recipe("Material floor tile", /obj/item/stack/tile/material, 1, 4, 20, crafting_flags = CRAFT_APPLIES_MATS, category = CAT_TILES),
+ new /datum/stack_recipe("Material airlock assembly", /obj/structure/door_assembly/door_assembly_material, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS),
)
///List of stackcrafting recipes for materials using rigid recipes
var/list/rigid_stack_recipes = list(
- new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_STRUCTURE),
+ new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_STRUCTURE),
)
///A list of dimensional themes used by the dimensional anomaly and other things, most of which require materials to function.
diff --git a/code/datums/components/crafting/_recipes.dm b/code/datums/components/crafting/_recipes.dm
index 09121339d3058..31825ac66118a 100644
--- a/code/datums/components/crafting/_recipes.dm
+++ b/code/datums/components/crafting/_recipes.dm
@@ -23,14 +23,12 @@
var/list/chem_catalysts = list()
///where it shows up in the crafting UI
var/category
- ///Set to FALSE if it needs to be learned first.
- var/always_available = TRUE
///Required machines for the craft, set the assigned value of the typepath to CRAFTING_MACHINERY_CONSUME or CRAFTING_MACHINERY_USE. Lazy associative list: type_path key -> flag value.
var/list/machinery
///Required structures for the craft, set the assigned value of the typepath to CRAFTING_STRUCTURE_CONSUME or CRAFTING_STRUCTURE_USE. Lazy associative list: type_path key -> flag value.
var/list/structures
- ///Should only one object exist on the same turf?
- var/one_per_turf = FALSE
+ /// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT|STACK_CHECK_TRAM_FORBIDDEN|STACK_CHECK_TRAM_EXCLUSIVE)
+ var/placement_checks = NONE
/// Steps needed to achieve the result
var/list/steps
/// Whether the result can be crafted with a crafting menu button
@@ -44,6 +42,9 @@
/// Allows you to craft so that you don't have to click the craft button many times.
var/mass_craftable = FALSE
+ ///crafting_flags var to hold bool values
+ var/crafting_flags = CRAFT_CHECK_DENSITY
+
/datum/crafting_recipe/New()
if(!name && result)
var/atom/atom_result = result
@@ -83,6 +84,7 @@
src.result_amount = stack_recipe.res_amount
src.reqs[material] = stack_recipe.req_amount
src.category = stack_recipe.category || CAT_MISC
+ src.placement_checks = stack_recipe.placement_checks
/**
* Run custom pre-craft checks for this recipe, don't add feedback messages in this because it will spam the client
diff --git a/code/datums/components/crafting/atmospheric.dm b/code/datums/components/crafting/atmospheric.dm
index cb5bba9ab52b2..b2993012e82b0 100644
--- a/code/datums/components/crafting/atmospheric.dm
+++ b/code/datums/components/crafting/atmospheric.dm
@@ -25,7 +25,7 @@
/obj/item/assembly/igniter = 1,
)
blacklist = list(/obj/item/assembly/igniter/condenser)
- one_per_turf = TRUE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF
time = 2 SECONDS
category = CAT_ATMOSPHERIC
diff --git a/code/datums/components/crafting/crafting.dm b/code/datums/components/crafting/crafting.dm
index 6fc560a293f21..7a56f89c8e924 100644
--- a/code/datums/components/crafting/crafting.dm
+++ b/code/datums/components/crafting/crafting.dm
@@ -191,42 +191,86 @@
var/list/contents = get_surroundings(crafter, recipe.blacklist)
var/send_feedback = 1
- if(check_contents(crafter, recipe, contents))
- if(check_tools(crafter, recipe, contents))
- if(recipe.one_per_turf)
- for(var/content in get_turf(crafter))
- if(istype(content, recipe.result))
- return ", object already present."
- //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item
- if(ismob(crafter) && !do_after(crafter, recipe.time, target = crafter))
- return "."
- contents = get_surroundings(crafter, recipe.blacklist)
- if(!check_contents(crafter, recipe, contents))
- return ", missing component."
- if(!check_tools(crafter, recipe, contents))
- return ", missing tool."
- var/list/parts = del_reqs(recipe, crafter)
- var/atom/movable/result
- if(ispath(recipe.result, /obj/item/stack))
- result = new recipe.result(get_turf(crafter.loc), recipe.result_amount || 1)
- else
- result = new recipe.result(get_turf(crafter.loc))
- if(result.atom_storage && recipe.delete_contents)
- for(var/obj/item/thing in result)
- qdel(thing)
- var/datum/reagents/holder = locate() in parts
- if(holder) //transfer reagents from ingredients to result
- if(!ispath(recipe.result, /obj/item/reagent_containers) && result.reagents)
- result.reagents.clear_reagents()
- holder.trans_to(result.reagents, holder.total_volume, no_react = TRUE)
- parts -= holder
- qdel(holder)
- result.CheckParts(parts, recipe)
- if(send_feedback)
- SSblackbox.record_feedback("tally", "object_crafted", 1, result.type)
- return result //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item
+ var/turf/dest_turf = get_turf(crafter)
+
+ if(!check_contents(crafter, recipe, contents))
+ return ", missing component."
+
+ if(!check_tools(crafter, recipe, contents))
return ", missing tool."
- return ", missing component."
+
+
+
+ if((recipe.crafting_flags & CRAFT_ONE_PER_TURF) && (locate(recipe.result) in dest_turf))
+ return ", already one here!"
+
+ if(recipe.crafting_flags & CRAFT_CHECK_DIRECTION)
+ if(!valid_build_direction(dest_turf, crafter.dir, is_fulltile = (recipe.crafting_flags & CRAFT_IS_FULLTILE)))
+ return ", won't fit here!"
+
+ if(recipe.crafting_flags & CRAFT_ON_SOLID_GROUND)
+ if(isclosedturf(dest_turf))
+ return ", cannot be made on a wall!"
+
+ if(is_type_in_typecache(dest_turf, GLOB.turfs_without_ground))
+ if(!locate(/obj/structure/thermoplastic) in dest_turf) // for tram construction
+ return ", must be made on solid ground!"
+
+ if(recipe.crafting_flags & CRAFT_CHECK_DENSITY)
+ for(var/obj/object in dest_turf)
+ if(object.density && !(object.obj_flags & IGNORE_DENSITY) || object.obj_flags & BLOCKS_CONSTRUCTION)
+ return ", something is in the way!"
+
+ if(recipe.placement_checks & STACK_CHECK_CARDINALS)
+ var/turf/nearby_turf
+ for(var/direction in GLOB.cardinals)
+ nearby_turf = get_step(dest_turf, direction)
+ if(locate(recipe.result) in nearby_turf)
+ to_chat(crafter, span_warning("\The [recipe.name] must not be built directly adjacent to another!"))
+ return ", can't be adjacent to another!"
+
+ if(recipe.placement_checks & STACK_CHECK_ADJACENT)
+ if(locate(recipe.result) in range(1, dest_turf))
+ return ", can't be near another!"
+
+ if(recipe.placement_checks & STACK_CHECK_TRAM_FORBIDDEN)
+ if(locate(/obj/structure/transport/linear/tram) in dest_turf || locate(/obj/structure/thermoplastic) in dest_turf)
+ return ", can't be on tram!"
+
+ if(recipe.placement_checks & STACK_CHECK_TRAM_EXCLUSIVE)
+ if(!locate(/obj/structure/transport/linear/tram) in dest_turf)
+ return ", must be made on a tram!"
+
+ //If we're a mob we'll try a do_after; non mobs will instead instantly construct the item
+ if(ismob(crafter) && !do_after(crafter, recipe.time, target = crafter))
+ return "."
+ contents = get_surroundings(crafter, recipe.blacklist)
+ if(!check_contents(crafter, recipe, contents))
+ return ", missing component."
+ if(!check_tools(crafter, recipe, contents))
+ return ", missing tool."
+ var/list/parts = del_reqs(recipe, crafter)
+ var/atom/movable/result
+ if(ispath(recipe.result, /obj/item/stack))
+ result = new recipe.result(get_turf(crafter.loc), recipe.result_amount || 1)
+ result.dir = crafter.dir
+ else
+ result = new recipe.result(get_turf(crafter.loc))
+ result.dir = crafter.dir
+ if(result.atom_storage && recipe.delete_contents)
+ for(var/obj/item/thing in result)
+ qdel(thing)
+ var/datum/reagents/holder = locate() in parts
+ if(holder) //transfer reagents from ingredients to result
+ if(!ispath(recipe.result, /obj/item/reagent_containers) && result.reagents)
+ result.reagents.clear_reagents()
+ holder.trans_to(result.reagents, holder.total_volume, no_react = TRUE)
+ parts -= holder
+ qdel(holder)
+ result.CheckParts(parts, recipe)
+ if(send_feedback)
+ SSblackbox.record_feedback("tally", "object_crafted", 1, result.type)
+ return result //Send the item back to whatever called this proc so it can handle whatever it wants to do with the new item
/*Del reqs works like this:
@@ -369,7 +413,7 @@
qdel(DL)
/datum/component/personal_crafting/proc/is_recipe_available(datum/crafting_recipe/recipe, mob/user)
- if(!recipe.always_available && !(recipe.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
+ if((recipe.crafting_flags & CRAFT_MUST_BE_LEARNED) && !(recipe.type in user?.mind?.learned_recipes)) //User doesn't actually know how to make this.
return FALSE
if (recipe.category == CAT_CULT && !IS_CULTIST(user)) // Skip blood cult recipes if not cultist
return FALSE
diff --git a/code/datums/components/crafting/doors.dm b/code/datums/components/crafting/doors.dm
index e8fcb3fdfd915..d9ed708904e51 100644
--- a/code/datums/components/crafting/doors.dm
+++ b/code/datums/components/crafting/doors.dm
@@ -9,7 +9,7 @@
tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WIRECUTTER, TOOL_WELDER)
time = 10 SECONDS
category = CAT_DOORS
- one_per_turf = TRUE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF
/datum/crafting_recipe/blast_doors
name = "Blast Door"
@@ -22,4 +22,4 @@
tool_behaviors = list(TOOL_SCREWDRIVER, TOOL_MULTITOOL, TOOL_WIRECUTTER, TOOL_WELDER)
time = 30 SECONDS
category = CAT_DOORS
- one_per_turf = TRUE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF
diff --git a/code/datums/components/crafting/melee_weapon.dm b/code/datums/components/crafting/melee_weapon.dm
index 869d223a758c9..1c4150585fccc 100644
--- a/code/datums/components/crafting/melee_weapon.dm
+++ b/code/datums/components/crafting/melee_weapon.dm
@@ -144,7 +144,6 @@
/datum/crafting_recipe/house_edge
name = "House Edge"
result = /obj/item/house_edge
- always_available = FALSE
tool_behaviors = list(TOOL_WRENCH, TOOL_SCREWDRIVER, TOOL_WELDER)
reqs = list(
/obj/item/v8_engine = 1,
@@ -157,6 +156,7 @@
)
time = 10 SECONDS
category = CAT_WEAPON_MELEE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/giant_wrench
name = "Big Slappy"
diff --git a/code/datums/components/crafting/misc.dm b/code/datums/components/crafting/misc.dm
index 264ff98156533..606cf1fc29262 100644
--- a/code/datums/components/crafting/misc.dm
+++ b/code/datums/components/crafting/misc.dm
@@ -11,8 +11,8 @@
time = 3 SECONDS
reqs = list(/obj/item/stack/sheet/bone = 5)
result = /obj/item/skeleton_key
- always_available = FALSE
category = CAT_MISC
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/coffee_cartridge
name = "Bootleg Coffee Cartridge"
diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm
index ace9f2c7c8b0d..0cf681ac2b107 100644
--- a/code/datums/components/crafting/ranged_weapon.dm
+++ b/code/datums/components/crafting/ranged_weapon.dm
@@ -222,7 +222,6 @@
/datum/crafting_recipe/pipegun_prime
name = "Regal Pipegun"
- always_available = FALSE
result = /obj/item/gun/ballistic/rifle/boltaction/pipegun/prime
reqs = list(
/obj/item/gun/ballistic/rifle/boltaction/pipegun = 1,
@@ -235,10 +234,10 @@
tool_paths = list(/obj/item/clothing/gloves/color/yellow, /obj/item/clothing/mask/gas, /obj/item/melee/baton/security/cattleprod)
time = 30 SECONDS //contemplate for a bit
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/deagle_prime //When you factor in the makarov (7 tc), the toolbox (1 tc), and the emag (3 tc), this comes to a total of 18 TC or thereabouts. Igorning the 20k pricetag, obviously.
name = "Regal Condor"
- always_available = FALSE
result = /obj/item/gun/ballistic/automatic/pistol/deagle/regal
reqs = list(
/obj/item/gun/ballistic/automatic/pistol = 1,
@@ -258,6 +257,7 @@
)
time = 30 SECONDS
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/deagle_prime/New()
..()
@@ -265,7 +265,6 @@
/datum/crafting_recipe/deagle_prime_mag
name = "Regal Condor Magazine (10mm Reaper)"
- always_available = FALSE
result = /obj/item/ammo_box/magazine/r10mm
reqs = list(
/obj/item/stack/sheet/iron = 10,
@@ -283,10 +282,10 @@
)
time = 5 SECONDS
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/trash_cannon
name = "Trash Cannon"
- always_available = FALSE
tool_behaviors = list(TOOL_WELDER, TOOL_SCREWDRIVER)
result = /obj/structure/cannon/trash
reqs = list(
@@ -297,6 +296,7 @@
/obj/item/storage/toolbox = 1,
)
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/laser_musket
name = "Laser Musket"
@@ -316,7 +316,6 @@
/datum/crafting_recipe/laser_musket_prime
name = "Heroic Laser Musket"
- always_available = FALSE
result = /obj/item/gun/energy/laser/musket/prime
reqs = list(
/obj/item/gun/energy/laser/musket = 1,
@@ -329,6 +328,7 @@
tool_paths = list(/obj/item/clothing/head/cowboy, /obj/item/clothing/shoes/cowboy)
time = 30 SECONDS //contemplate for a bit
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/smoothbore_disabler
name = "Smoothbore Disabler"
@@ -347,7 +347,6 @@
/datum/crafting_recipe/smoothbore_disabler_prime
name = "Elite Smoothbore Disabler"
- always_available = FALSE
result = /obj/item/gun/energy/disabler/smoothbore/prime
reqs = list(
/obj/item/gun/energy/disabler/smoothbore = 1,
@@ -358,3 +357,4 @@
tool_behaviors = list(TOOL_SCREWDRIVER)
time = 20 SECONDS
category = CAT_WEAPON_RANGED
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
diff --git a/code/datums/components/crafting/structures.dm b/code/datums/components/crafting/structures.dm
index 2cbe2c353020b..c4a9b48ec36b6 100644
--- a/code/datums/components/crafting/structures.dm
+++ b/code/datums/components/crafting/structures.dm
@@ -11,33 +11,33 @@
/datum/crafting_recipe/rib
name = "Colossal Rib"
- always_available = FALSE
reqs = list(
/obj/item/stack/sheet/bone = 10,
/datum/reagent/fuel/oil = 5,
)
result = /obj/structure/statue/bone/rib
category = CAT_STRUCTURE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/skull
name = "Skull Carving"
- always_available = FALSE
reqs = list(
/obj/item/stack/sheet/bone = 6,
/datum/reagent/fuel/oil = 5,
)
result = /obj/structure/statue/bone/skull
category = CAT_STRUCTURE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/halfskull
name = "Cracked Skull Carving"
- always_available = FALSE
reqs = list(
/obj/item/stack/sheet/bone = 3,
/datum/reagent/fuel/oil = 5,
)
result = /obj/structure/statue/bone/skull/half
category = CAT_STRUCTURE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/firecabinet
name = "Fire Axe Cabinet"
@@ -65,7 +65,6 @@
name = "Syndicate Uplink Beacon"
result = /obj/structure/syndicate_uplink_beacon
tool_behaviors = list(TOOL_SCREWDRIVER)
- always_available = FALSE
time = 6 SECONDS
reqs = list(
/obj/item/stack/sheet/iron = 5,
@@ -74,3 +73,4 @@
/obj/item/stack/ore/bluespace_crystal = 1,
)
category = CAT_STRUCTURE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
diff --git a/code/datums/components/crafting/tools.dm b/code/datums/components/crafting/tools.dm
index 8b4b00d006026..d1d303daf8040 100644
--- a/code/datums/components/crafting/tools.dm
+++ b/code/datums/components/crafting/tools.dm
@@ -19,7 +19,6 @@
/datum/crafting_recipe/boneshovel
name = "Serrated Bone Shovel"
- always_available = FALSE
reqs = list(
/obj/item/stack/sheet/bone = 4,
/datum/reagent/fuel/oil = 5,
@@ -27,6 +26,7 @@
)
result = /obj/item/shovel/serrated
category = CAT_TOOLS
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/lasso
name = "Bone Lasso"
diff --git a/code/datums/components/crafting/weapon_ammo.dm b/code/datums/components/crafting/weapon_ammo.dm
index 44b8055b3ff94..55701dbde5349 100644
--- a/code/datums/components/crafting/weapon_ammo.dm
+++ b/code/datums/components/crafting/weapon_ammo.dm
@@ -20,8 +20,8 @@
)
tool_behaviors = list(TOOL_WIRECUTTER)
time = 0.5 SECONDS
- always_available = FALSE
category = CAT_WEAPON_AMMO
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/pulseslug
name = "Pulse Slug Shell"
@@ -85,10 +85,10 @@
/datum/crafting_recipe/trashball
name = "Trashball"
- always_available = FALSE
result = /obj/item/stack/cannonball/trashball
reqs = list(
/obj/item/stack/sheet = 5,
/datum/reagent/consumable/space_cola = 10,
)
category = CAT_WEAPON_AMMO
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 064f933573ca3..63625536b74b5 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -1,19 +1,20 @@
GLOBAL_LIST_INIT(rod_recipes, list ( \
- new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 2.5 SECONDS, one_per_turf = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("linen bin", /obj/structure/bedsheetbin/empty, 2, time = 0.5 SECONDS, one_per_turf = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("railing corner", /obj/structure/railing/corner, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("railing end", /obj/structure/railing/corner/end, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("railing end (flipped)", /obj/structure/railing/corner/end/flip, 1, time = 1 SECONDS, check_direction = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("tank holder", /obj/structure/tank_holder, 2, time = 0.5 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("ladder", /obj/structure/ladder/crafted, 15, time = 15 SECONDS, one_per_turf = TRUE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("grille", /obj/structure/grille, 2, time = 1 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("table frame", /obj/structure/table_frame, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("scooter frame", /obj/item/scooter_frame, 10, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("linen bin", /obj/structure/bedsheetbin/empty, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("railing", /obj/structure/railing, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("railing corner", /obj/structure/railing/corner, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("railing end", /obj/structure/railing/corner/end, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("railing end (flipped)", /obj/structure/railing/corner/end/flip, 1, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_CHECK_DIRECTION, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("tank holder", /obj/structure/tank_holder, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("ladder", /obj/structure/ladder/crafted, 15, time = 15 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
new/datum/stack_recipe("catwalk floor tile", /obj/item/stack/tile/catwalk_tile, 1, 4, 20, category = CAT_TILES), \
- new/datum/stack_recipe("stairs frame", /obj/structure/stairs_frame, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("white cane", /obj/item/cane/white, 3, time = 1 SECONDS, one_per_turf = FALSE, category = CAT_TOOLS), \
- new/datum/stack_recipe("sharpened iron rod", /obj/item/ammo_casing/rebar, 1, time = 0.2 SECONDS, one_per_turf = FALSE, category = CAT_WEAPON_AMMO), \
+ new/datum/stack_recipe("stairs frame", /obj/structure/stairs_frame, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("white cane", /obj/item/cane/white, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_TOOLS), \
+ new/datum/stack_recipe("sharpened iron rod", /obj/item/ammo_casing/rebar, 1, time = 0.2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY, category = CAT_WEAPON_AMMO), \
))
+
/obj/item/stack/rods
name = "iron rod"
desc = "Some rods. Can be used for building or something."
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 1f66b80cf55b7..e93b8c4cea59d 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -9,9 +9,9 @@
* Glass sheets
*/
GLOBAL_LIST_INIT(glass_recipes, list ( \
- new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 1 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("glass shard", /obj/item/shard, time = 0, on_solid_ground = TRUE, category = CAT_MISC), \
+ new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("glass shard", /obj/item/shard, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \
new/datum/stack_recipe("glass tile", /obj/item/stack/tile/glass, 1, 4, 20, category = CAT_TILES) \
))
@@ -82,9 +82,9 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \
return ..()
GLOBAL_LIST_INIT(pglass_recipes, list ( \
- new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 20, on_solid_ground = TRUE, category = CAT_MISC), \
+ new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 20, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \
new/datum/stack_recipe("plasma glass tile", /obj/item/stack/tile/glass/plasma, 1, 4, 20, category = CAT_TILES) \
))
@@ -138,11 +138,11 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \
* Reinforced glass sheets
*/
GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
- new/datum/stack_recipe("windoor frame", /obj/structure/windoor_assembly, 5, time = 0, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("windoor frame", /obj/structure/windoor_assembly, 5, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
null, \
- new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("glass shard", /obj/item/shard, time = 10, on_solid_ground = TRUE, category = CAT_MISC), \
+ new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("glass shard", /obj/item/shard, time = 10, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \
new/datum/stack_recipe("reinforced glass tile", /obj/item/stack/tile/rglass, 1, 4, 20, category = CAT_TILES) \
))
@@ -177,9 +177,9 @@ GLOBAL_LIST_INIT(reinforced_glass_recipes, list ( \
. += GLOB.reinforced_glass_recipes
GLOBAL_LIST_INIT(prglass_recipes, list ( \
- new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/plasma/unanchored, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/plasma/fulltile/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 40, on_solid_ground = TRUE, category = CAT_MISC), \
+ new/datum/stack_recipe("directional reinforced window", /obj/structure/window/reinforced/plasma/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile reinforced window", /obj/structure/window/reinforced/plasma/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 40, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \
new/datum/stack_recipe("reinforced plasma glass tile", /obj/item/stack/tile/rglass/plasma, 1, 4, 20, category = CAT_TILES) \
))
@@ -212,8 +212,8 @@ GLOBAL_LIST_INIT(prglass_recipes, list ( \
. += GLOB.prglass_recipes
GLOBAL_LIST_INIT(titaniumglass_recipes, list(
- new/datum/stack_recipe("shuttle window", /obj/structure/window/reinforced/shuttle/unanchored, 2, time = 0.5 SECONDS, on_solid_ground = TRUE, check_direction = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("titanium glass shard", /obj/item/shard/titanium, time = 40, on_solid_ground = TRUE, category = CAT_MISC) \
+ new/datum/stack_recipe("shuttle window", /obj/structure/window/reinforced/shuttle/unanchored, 2, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("titanium glass shard", /obj/item/shard/titanium, time = 40, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \
))
/obj/item/stack/sheet/titaniumglass
@@ -241,8 +241,8 @@ GLOBAL_LIST_INIT(titaniumglass_recipes, list(
. += GLOB.titaniumglass_recipes
GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
- new/datum/stack_recipe("plastitanium window", /obj/structure/window/reinforced/plasma/plastitanium/unanchored, 2, time = 2 SECONDS, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("plastitanium glass shard", /obj/item/shard/plastitanium, time = 60, on_solid_ground = TRUE, category = CAT_MISC) \
+ new/datum/stack_recipe("plastitanium window", /obj/structure/window/reinforced/plasma/plastitanium/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("plastitanium glass shard", /obj/item/shard/plastitanium, time = 60, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \
))
/obj/item/stack/sheet/plastitaniumglass
diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm
index 851e544ff8a83..2d1636e9e165a 100644
--- a/code/game/objects/items/stacks/sheets/leather.dm
+++ b/code/game/objects/items/stacks/sheets/leather.dm
@@ -14,8 +14,8 @@
merge_type = /obj/item/stack/sheet/animalhide/human
GLOBAL_LIST_INIT(human_recipes, list( \
- new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("human skin hat", /obj/item/clothing/head/fedora/human_leather, 1, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("bloated human costume", /obj/item/clothing/suit/hooded/bloated_human, 5, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("human skin hat", /obj/item/clothing/head/fedora/human_leather, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/human/get_main_recipes()
@@ -55,9 +55,9 @@ GLOBAL_LIST_INIT(human_recipes, list( \
amount = 5
GLOBAL_LIST_INIT(gondola_recipes, list ( \
- new/datum/stack_recipe("gondola mask", /obj/item/clothing/mask/gondola, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("gondola suit", /obj/item/clothing/under/costume/gondola, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("gondola bedsheet", /obj/item/bedsheet/gondola, 1, check_density = FALSE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("gondola mask", /obj/item/clothing/mask/gondola, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("gondola suit", /obj/item/clothing/under/costume/gondola, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("gondola bedsheet", /obj/item/bedsheet/gondola, 1, crafting_flags = NONE, category = CAT_FURNITURE), \
))
/obj/item/stack/sheet/animalhide/gondola
@@ -73,7 +73,7 @@ GLOBAL_LIST_INIT(gondola_recipes, list ( \
. += GLOB.gondola_recipes
GLOBAL_LIST_INIT(corgi_recipes, list ( \
- new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("corgi costume", /obj/item/clothing/suit/hooded/ian_costume, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/corgi/get_main_recipes()
@@ -100,8 +100,8 @@ GLOBAL_LIST_INIT(corgi_recipes, list ( \
merge_type = /obj/item/stack/sheet/animalhide/monkey
GLOBAL_LIST_INIT(monkey_recipes, list ( \
- new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/costume/monkeysuit, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("monkey mask", /obj/item/clothing/mask/gas/monkeymask, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("monkey suit", /obj/item/clothing/suit/costume/monkeysuit, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/monkey/get_main_recipes()
@@ -131,8 +131,8 @@ GLOBAL_LIST_INIT(monkey_recipes, list ( \
merge_type = /obj/item/stack/sheet/animalhide/xeno
GLOBAL_LIST_INIT(xeno_recipes, list ( \
- new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/costume/xenos, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/costume/xenos, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("alien helmet", /obj/item/clothing/head/costume/xenos, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("alien suit", /obj/item/clothing/suit/costume/xenos, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/xeno/get_main_recipes()
@@ -151,11 +151,11 @@ GLOBAL_LIST_INIT(xeno_recipes, list ( \
merge_type = /obj/item/stack/sheet/animalhide/carp
GLOBAL_LIST_INIT(carp_recipes, list ( \
- new/datum/stack_recipe("carp costume", /obj/item/clothing/suit/hooded/carp_costume, 4, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("carp mask", /obj/item/clothing/mask/gas/carp, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("carpskin chair", /obj/structure/chair/comfy/carp, 2, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("carpskin suit", /obj/item/clothing/under/suit/carpskin, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("carpskin fedora", /obj/item/clothing/head/fedora/carpskin, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("carp costume", /obj/item/clothing/suit/hooded/carp_costume, 4, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("carp mask", /obj/item/clothing/mask/gas/carp, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("carpskin chair", /obj/structure/chair/comfy/carp, 2, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("carpskin suit", /obj/item/clothing/under/suit/carpskin, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("carpskin fedora", /obj/item/clothing/head/fedora/carpskin, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/animalhide/carp/get_main_recipes()
@@ -193,33 +193,33 @@ GLOBAL_LIST_INIT(carp_recipes, list ( \
merge_type = /obj/item/stack/sheet/leather
GLOBAL_LIST_INIT(leather_recipes, list ( \
- new/datum/stack_recipe("wallet", /obj/item/storage/wallet, 1, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("muzzle", /obj/item/clothing/mask/muzzle, 2, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("basketball", /obj/item/toy/basketball, 20, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("baseball", /obj/item/toy/beach_ball/baseball, 3, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("saddle", /obj/item/goliath_saddle, 5, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/laceup, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("cowboy boots", /obj/item/clothing/shoes/cowboy, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("botany gloves", /obj/item/clothing/gloves/botanic_leather, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("leather satchel", /obj/item/storage/backpack/satchel/leather, 5, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("sheriff vest", /obj/item/clothing/accessory/vest_sheriff, 4, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("leather jacket", /obj/item/clothing/suit/jacket/leather, 7, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("biker jacket", /obj/item/clothing/suit/jacket/leather/biker, 7, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("wallet", /obj/item/storage/wallet, 1, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("muzzle", /obj/item/clothing/mask/muzzle, 2, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("basketball", /obj/item/toy/basketball, 20, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("baseball", /obj/item/toy/beach_ball/baseball, 3, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("saddle", /obj/item/goliath_saddle, 5, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("leather shoes", /obj/item/clothing/shoes/laceup, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("cowboy boots", /obj/item/clothing/shoes/cowboy, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("botany gloves", /obj/item/clothing/gloves/botanic_leather, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("leather satchel", /obj/item/storage/backpack/satchel/leather, 5, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("sheriff vest", /obj/item/clothing/accessory/vest_sheriff, 4, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("leather jacket", /obj/item/clothing/suit/jacket/leather, 7, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("biker jacket", /obj/item/clothing/suit/jacket/leather/biker, 7, crafting_flags = NONE, category = CAT_CLOTHING), \
new/datum/stack_recipe_list("belts", list( \
- new/datum/stack_recipe("tool belt", /obj/item/storage/belt/utility, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("botanical belt", /obj/item/storage/belt/plant, 2, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("janitorial belt", /obj/item/storage/belt/janitor, 2, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("medical belt", /obj/item/storage/belt/medical, 2, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("security belt", /obj/item/storage/belt/security, 2, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("shoulder holster", /obj/item/storage/belt/holster, 3, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("bandolier", /obj/item/storage/belt/bandolier, 5, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("tool belt", /obj/item/storage/belt/utility, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("botanical belt", /obj/item/storage/belt/plant, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("janitorial belt", /obj/item/storage/belt/janitor, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("medical belt", /obj/item/storage/belt/medical, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("security belt", /obj/item/storage/belt/security, 2, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("shoulder holster", /obj/item/storage/belt/holster, 3, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("bandolier", /obj/item/storage/belt/bandolier, 5, crafting_flags = NONE, category = CAT_CONTAINERS), \
)),
new/datum/stack_recipe_list("cowboy hats", list( \
- new/datum/stack_recipe("sheriff hat", /obj/item/clothing/head/cowboy/brown, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("desperado hat", /obj/item/clothing/head/cowboy/black, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("ten-gallon hat", /obj/item/clothing/head/cowboy/white, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("deputy hat", /obj/item/clothing/head/cowboy/red, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("drifter hat", /obj/item/clothing/head/cowboy/grey, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("sheriff hat", /obj/item/clothing/head/cowboy/brown, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("desperado hat", /obj/item/clothing/head/cowboy/black, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("ten-gallon hat", /obj/item/clothing/head/cowboy/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("deputy hat", /obj/item/clothing/head/cowboy/red, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("drifter hat", /obj/item/clothing/head/cowboy/grey, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
)),
))
@@ -263,7 +263,7 @@ GLOBAL_LIST_INIT(leather_recipes, list ( \
merge_type = /obj/item/stack/sheet/sinew/wolf
GLOBAL_LIST_INIT(sinew_recipes, list ( \
- new/datum/stack_recipe("sinew restraints", /obj/item/restraints/handcuffs/cable/sinew, 1, check_density = FALSE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("sinew restraints", /obj/item/restraints/handcuffs/cable/sinew, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \
))
/obj/item/stack/sheet/sinew/get_main_recipes()
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 1b3d66a7dae92..f6e7d797fd95c 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -24,8 +24,8 @@ Mineral Sheets
*/
GLOBAL_LIST_INIT(sandstone_recipes, list ( \
- new/datum/stack_recipe("sandstone door", /obj/structure/mineral_door/sandstone, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("Breakdown into sand", /obj/item/stack/ore/glass, 1, one_per_turf = FALSE, on_solid_ground = TRUE, category = CAT_MISC) \
+ new/datum/stack_recipe("sandstone door", /obj/structure/mineral_door/sandstone, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("Breakdown into sand", /obj/item/stack/ore/glass, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC) \
))
/obj/item/stack/sheet/mineral/sandstone
@@ -62,7 +62,7 @@ GLOBAL_LIST_INIT(sandstone_recipes, list ( \
merge_type = /obj/item/stack/sheet/mineral/sandbags
GLOBAL_LIST_INIT(sandbag_recipes, list ( \
- new/datum/stack_recipe("sandbags", /obj/structure/barricade/sandbags, 1, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("sandbags", /obj/structure/barricade/sandbags, 1, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
))
/obj/item/stack/sheet/mineral/sandbags/get_main_recipes()
@@ -105,8 +105,8 @@ GLOBAL_LIST_INIT(sandbag_recipes, list ( \
walltype = /turf/closed/wall/mineral/diamond
GLOBAL_LIST_INIT(diamond_recipes, list ( \
- new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("diamond tile", /obj/item/stack/tile/mineral/diamond, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("diamond door", /obj/structure/mineral_door/transparent/diamond, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("diamond tile", /obj/item/stack/tile/mineral/diamond, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/diamond/get_main_recipes()
@@ -130,8 +130,8 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \
walltype = /turf/closed/wall/mineral/uranium
GLOBAL_LIST_INIT(uranium_recipes, list ( \
- new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("uranium door", /obj/structure/mineral_door/uranium, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("uranium tile", /obj/item/stack/tile/mineral/uranium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/uranium/get_main_recipes()
@@ -167,8 +167,8 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
return TOXLOSS//dont you kids know that stuff is toxic?
GLOBAL_LIST_INIT(plasma_recipes, list ( \
- new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("plasma tile", /obj/item/stack/tile/mineral/plasma, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("plasma door", /obj/structure/mineral_door/transparent/plasma, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("plasma tile", /obj/item/stack/tile/mineral/plasma, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/plasma/get_main_recipes()
@@ -198,10 +198,10 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
walltype = /turf/closed/wall/mineral/gold
GLOBAL_LIST_INIT(gold_recipes, list ( \
- new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("gold tile", /obj/item/stack/tile/mineral/gold, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
- new/datum/stack_recipe("blank plaque", /obj/item/plaque, 1, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("Simple Crown", /obj/item/clothing/head/costume/crown, 5, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("golden door", /obj/structure/mineral_door/gold, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("gold tile", /obj/item/stack/tile/mineral/gold, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new/datum/stack_recipe("blank plaque", /obj/item/plaque, 1, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("Simple Crown", /obj/item/clothing/head/costume/crown, 5, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/mineral/gold/get_main_recipes()
@@ -226,8 +226,8 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
walltype = /turf/closed/wall/mineral/silver
GLOBAL_LIST_INIT(silver_recipes, list ( \
- new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("silver tile", /obj/item/stack/tile/mineral/silver, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("silver door", /obj/structure/mineral_door/silver, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("silver tile", /obj/item/stack/tile/mineral/silver, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/silver/get_main_recipes()
@@ -251,7 +251,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
walltype = /turf/closed/wall/mineral/bananium
GLOBAL_LIST_INIT(bananium_recipes, list ( \
- new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("bananium tile", /obj/item/stack/tile/mineral/bananium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/bananium/get_main_recipes()
@@ -282,8 +282,8 @@ GLOBAL_LIST_INIT(bananium_recipes, list ( \
walltype = /turf/closed/wall/mineral/titanium
GLOBAL_LIST_INIT(titanium_recipes, list ( \
- new/datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
- new/datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("Titanium tile", /obj/item/stack/tile/mineral/titanium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new/datum/stack_recipe("Shuttle seat", /obj/structure/chair/comfy/shuttle, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
))
/obj/item/stack/sheet/mineral/titanium/get_main_recipes()
@@ -315,7 +315,7 @@ GLOBAL_LIST_INIT(titanium_recipes, list ( \
walltype = /turf/closed/wall/mineral/plastitanium
GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
- new/datum/stack_recipe("plastitanium tile", /obj/item/stack/tile/mineral/plastitanium, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("plastitanium tile", /obj/item/stack/tile/mineral/plastitanium, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/plastitanium/get_main_recipes()
@@ -341,10 +341,10 @@ GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
material_type = /datum/material/snow
GLOBAL_LIST_INIT(snow_recipes, list ( \
- new/datum/stack_recipe("snow wall", /turf/closed/wall/mineral/snow, 5, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("snowman", /obj/structure/statue/snow/snowman, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("snowball", /obj/item/toy/snowball, 1, check_density = FALSE, category = CAT_WEAPON_RANGED), \
- new/datum/stack_recipe("snow tile", /obj/item/stack/tile/mineral/snow, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("snow wall", /turf/closed/wall/mineral/snow, 5, time = 4 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("snowman", /obj/structure/statue/snow/snowman, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("snowball", /obj/item/toy/snowball, 1, crafting_flags = NONE, category = CAT_WEAPON_RANGED), \
+ new/datum/stack_recipe("snow tile", /obj/item/stack/tile/mineral/snow, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/snow/Initialize(mapload, new_amount, merge, list/mat_override, mat_amt)
@@ -421,12 +421,12 @@ GLOBAL_LIST_INIT(adamantine_recipes, list(
walltype = /turf/closed/wall/mineral/abductor
GLOBAL_LIST_INIT(abductor_recipes, list ( \
- new/datum/stack_recipe("alien bed", /obj/structure/bed/abductor, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 2, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("alien table frame", /obj/structure/table_frame/abductor, 1, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
+ new/datum/stack_recipe("alien bed", /obj/structure/bed/abductor, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("alien locker", /obj/structure/closet/abductor, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("alien table frame", /obj/structure/table_frame/abductor, 1, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("alien airlock assembly", /obj/structure/door_assembly/door_assembly_abductor, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
null, \
- new/datum/stack_recipe("alien floor tile", /obj/item/stack/tile/mineral/abductor, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("alien floor tile", /obj/item/stack/tile/mineral/abductor, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
))
/obj/item/stack/sheet/mineral/abductor/get_main_recipes()
@@ -469,10 +469,10 @@ GLOBAL_LIST_INIT(abductor_recipes, list ( \
//Metal Hydrogen
GLOBAL_LIST_INIT(metalhydrogen_recipes, list(
- new /datum/stack_recipe("incomplete servant golem shell", /obj/item/golem_shell/servant, req_amount=20, res_amount=1, check_density = FALSE, category = CAT_ROBOT),
- new /datum/stack_recipe("ancient armor", /obj/item/clothing/suit/armor/elder_atmosian, req_amount = 5, res_amount = 1, check_density = FALSE, category = CAT_CLOTHING),
- new /datum/stack_recipe("ancient helmet", /obj/item/clothing/head/helmet/elder_atmosian, req_amount = 3, res_amount = 1, check_density = FALSE, category = CAT_CLOTHING),
- new /datum/stack_recipe("metallic hydrogen axe", /obj/item/fireaxe/metal_h2_axe, req_amount = 15, res_amount = 1, check_density = FALSE, category = CAT_WEAPON_MELEE),
+ new /datum/stack_recipe("incomplete servant golem shell", /obj/item/golem_shell/servant, req_amount=20, res_amount=1, crafting_flags = NONE, category = CAT_ROBOT),
+ new /datum/stack_recipe("ancient armor", /obj/item/clothing/suit/armor/elder_atmosian, req_amount = 5, res_amount = 1, crafting_flags = NONE, category = CAT_CLOTHING),
+ new /datum/stack_recipe("ancient helmet", /obj/item/clothing/head/helmet/elder_atmosian, req_amount = 3, res_amount = 1, crafting_flags = NONE, category = CAT_CLOTHING),
+ new /datum/stack_recipe("metallic hydrogen axe", /obj/item/fireaxe/metal_h2_axe, req_amount = 15, res_amount = 1, crafting_flags = NONE, category = CAT_WEAPON_MELEE),
))
/obj/item/stack/sheet/mineral/metal_hydrogen
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index b5d4f596a56a1..36582f3ad5ac1 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -15,127 +15,127 @@
* Iron
*/
GLOBAL_LIST_INIT(metal_recipes, list ( \
- new/datum/stack_recipe("stool", /obj/structure/chair/stool, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("bar stool", /obj/structure/chair/stool/bar, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("bed", /obj/structure/bed, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("double bed", /obj/structure/bed/double, 4, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("stool", /obj/structure/chair/stool, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("bar stool", /obj/structure/chair/stool/bar, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("bed", /obj/structure/bed, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("double bed", /obj/structure/bed/double, 4, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
null, \
new/datum/stack_recipe_list("office chairs", list( \
- new/datum/stack_recipe("dark office chair", /obj/structure/chair/office, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("light office chair", /obj/structure/chair/office/light, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("dark office chair", /obj/structure/chair/office, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("light office chair", /obj/structure/chair/office/light, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
)), \
new/datum/stack_recipe_list("comfy chairs", list( \
- new/datum/stack_recipe("beige comfy chair", /obj/structure/chair/comfy/beige, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("black comfy chair", /obj/structure/chair/comfy/black, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("brown comfy chair", /obj/structure/chair/comfy/brown, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("lime comfy chair", /obj/structure/chair/comfy/lime, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("teal comfy chair", /obj/structure/chair/comfy/teal, 2, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("beige comfy chair", /obj/structure/chair/comfy/beige, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("black comfy chair", /obj/structure/chair/comfy/black, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("brown comfy chair", /obj/structure/chair/comfy/brown, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("lime comfy chair", /obj/structure/chair/comfy/lime, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("teal comfy chair", /obj/structure/chair/comfy/teal, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
)), \
new/datum/stack_recipe_list("sofas", list(
- new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/middle, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/left, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/right, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corner, 1, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE)
+ new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/middle, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/left, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/right, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corner, 1, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE)
)), \
new/datum/stack_recipe_list("corporate sofas", list( \
- new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/corp, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/corp/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/corp/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corp/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("sofa (middle)", /obj/structure/chair/sofa/corp, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("sofa (left)", /obj/structure/chair/sofa/corp/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("sofa (right)", /obj/structure/chair/sofa/corp/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("sofa (corner)", /obj/structure/chair/sofa/corp/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
)), \
new /datum/stack_recipe_list("benches", list( \
- new /datum/stack_recipe("bench (middle)", /obj/structure/chair/sofa/bench, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("bench (left)", /obj/structure/chair/sofa/bench/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("bench (right)", /obj/structure/chair/sofa/bench/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("bench (corner)", /obj/structure/chair/sofa/bench/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (solo)", /obj/structure/chair/sofa/bench/tram/solo, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (middle)", /obj/structure/chair/sofa/bench/tram, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (left)", /obj/structure/chair/sofa/bench/tram/left, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (right)", /obj/structure/chair/sofa/bench/tram/right, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("tram bench (corner)", /obj/structure/chair/sofa/bench/tram/corner, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("bench (middle)", /obj/structure/chair/sofa/bench, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("bench (left)", /obj/structure/chair/sofa/bench/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("bench (right)", /obj/structure/chair/sofa/bench/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("bench (corner)", /obj/structure/chair/sofa/bench/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (solo)", /obj/structure/chair/sofa/bench/tram/solo, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (middle)", /obj/structure/chair/sofa/bench/tram, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (left)", /obj/structure/chair/sofa/bench/tram/left, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (right)", /obj/structure/chair/sofa/bench/tram/right, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("tram bench (corner)", /obj/structure/chair/sofa/bench/tram/corner, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
)), \
new /datum/stack_recipe_list("chess pieces", list( \
- new /datum/stack_recipe("White Pawn", /obj/structure/chess/whitepawn, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Rook", /obj/structure/chess/whiterook, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Knight", /obj/structure/chess/whiteknight, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Bishop", /obj/structure/chess/whitebishop, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Queen", /obj/structure/chess/whitequeen, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White King", /obj/structure/chess/whiteking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Pawn", /obj/structure/chess/blackpawn, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Rook", /obj/structure/chess/blackrook, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Knight", /obj/structure/chess/blackknight, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Bishop", /obj/structure/chess/blackbishop, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Queen", /obj/structure/chess/blackqueen, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black King", /obj/structure/chess/blackking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Pawn", /obj/structure/chess/whitepawn, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Rook", /obj/structure/chess/whiterook, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Knight", /obj/structure/chess/whiteknight, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Bishop", /obj/structure/chess/whitebishop, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Queen", /obj/structure/chess/whitequeen, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White King", /obj/structure/chess/whiteking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Pawn", /obj/structure/chess/blackpawn, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Rook", /obj/structure/chess/blackrook, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Knight", /obj/structure/chess/blackknight, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Bishop", /obj/structure/chess/blackbishop, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Queen", /obj/structure/chess/blackqueen, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black King", /obj/structure/chess/blackking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
)),
new /datum/stack_recipe_list("checkers pieces", list( \
- new /datum/stack_recipe("White Checker Man", /obj/structure/chess/checker/whiteman, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("White Checker King", /obj/structure/chess/checker/whiteking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Checker Man", /obj/structure/chess/checker/blackman, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("Black Checker King", /obj/structure/chess/checker/blackking, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Checker Man", /obj/structure/chess/checker/whiteman, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("White Checker King", /obj/structure/chess/checker/whiteking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Checker Man", /obj/structure/chess/checker/blackman, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("Black Checker King", /obj/structure/chess/checker/blackking, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
)),
null, \
new/datum/stack_recipe("rack parts", /obj/item/rack_parts, category = CAT_FURNITURE), \
- new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
null, \
- new/datum/stack_recipe("atmos canister", /obj/machinery/portable_atmospherics/canister, 10, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ATMOSPHERIC), \
- new/datum/stack_recipe("pipe", /obj/item/pipe/quaternary/pipe/crafted, 1, time = 4 SECONDS, check_density = FALSE, category = CAT_ATMOSPHERIC), \
+ new/datum/stack_recipe("atmos canister", /obj/machinery/portable_atmospherics/canister, 10, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ATMOSPHERIC), \
+ new/datum/stack_recipe("pipe", /obj/item/pipe/quaternary/pipe/crafted, 1, time = 4 SECONDS, crafting_flags = NONE, category = CAT_ATMOSPHERIC), \
null, \
new/datum/stack_recipe("floor tile", /obj/item/stack/tile/iron/base, 1, 4, 20, category = CAT_TILES), \
new/datum/stack_recipe("iron rod", /obj/item/stack/rods, 1, 2, 60, category = CAT_MISC), \
null, \
- new/datum/stack_recipe("wall girders (anchored)", /obj/structure/girder, 2, time = 4 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, placement_checks = STACK_CHECK_TRAM_FORBIDDEN, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("wall girders (anchored)", /obj/structure/girder, 2, time = 4 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, placement_checks = STACK_CHECK_TRAM_FORBIDDEN, trait_booster = TRAIT_QUICK_BUILD, trait_modifier = 0.75, category = CAT_STRUCTURE), \
null, \
null, \
- new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("modular console", /obj/machinery/modular_computer, 10, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("computer frame", /obj/structure/frame/computer, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("modular console", /obj/machinery/modular_computer, 10, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("machine frame", /obj/structure/frame/machine, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
null, \
new /datum/stack_recipe_list("airlock assemblies", list( \
- new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("public airlock assembly", /obj/structure/door_assembly/door_assembly_public, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("science airlock assembly", /obj/structure/door_assembly/door_assembly_science, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("hydroponics airlock assembly", /obj/structure/door_assembly/door_assembly_hydro, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("virology airlock assembly", /obj/structure/door_assembly/door_assembly_viro, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("external maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_extmai, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
+ new /datum/stack_recipe("standard airlock assembly", /obj/structure/door_assembly, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("public airlock assembly", /obj/structure/door_assembly/door_assembly_public, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("command airlock assembly", /obj/structure/door_assembly/door_assembly_com, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("security airlock assembly", /obj/structure/door_assembly/door_assembly_sec, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("engineering airlock assembly", /obj/structure/door_assembly/door_assembly_eng, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("mining airlock assembly", /obj/structure/door_assembly/door_assembly_min, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("atmospherics airlock assembly", /obj/structure/door_assembly/door_assembly_atmo, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("research airlock assembly", /obj/structure/door_assembly/door_assembly_research, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("freezer airlock assembly", /obj/structure/door_assembly/door_assembly_fre, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("science airlock assembly", /obj/structure/door_assembly/door_assembly_science, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("medical airlock assembly", /obj/structure/door_assembly/door_assembly_med, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("hydroponics airlock assembly", /obj/structure/door_assembly/door_assembly_hydro, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("virology airlock assembly", /obj/structure/door_assembly/door_assembly_viro, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_mai, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("external airlock assembly", /obj/structure/door_assembly/door_assembly_ext, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("external maintenance airlock assembly", /obj/structure/door_assembly/door_assembly_extmai, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("airtight hatch assembly", /obj/structure/door_assembly/door_assembly_hatch, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new /datum/stack_recipe("maintenance hatch assembly", /obj/structure/door_assembly/door_assembly_mhatch, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
)), \
null, \
- new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("meatspike frame", /obj/structure/kitchenspike_frame, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 2.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("firelock frame", /obj/structure/firelock_frame, 3, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new/datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("meatspike frame", /obj/structure/kitchenspike_frame, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("reflector frame", /obj/structure/reflector, 5, time = 2.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
null, \
- new/datum/stack_recipe("grenade casing", /obj/item/grenade/chem_grenade, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("light fixture frame", /obj/item/wallframe/light_fixture, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("small light fixture frame", /obj/item/wallframe/light_fixture/small, 1, check_density = FALSE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("grenade casing", /obj/item/grenade/chem_grenade, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("light fixture frame", /obj/item/wallframe/light_fixture, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("small light fixture frame", /obj/item/wallframe/light_fixture/small, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \
null, \
- new/datum/stack_recipe("apc frame", /obj/item/wallframe/apc, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("air alarm frame", /obj/item/wallframe/airalarm, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("fire alarm frame", /obj/item/wallframe/firealarm, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("extinguisher cabinet frame", /obj/item/wallframe/extinguisher_cabinet, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("button frame", /obj/item/wallframe/button, 1, check_density = FALSE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("apc frame", /obj/item/wallframe/apc, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("air alarm frame", /obj/item/wallframe/airalarm, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("fire alarm frame", /obj/item/wallframe/firealarm, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("extinguisher cabinet frame", /obj/item/wallframe/extinguisher_cabinet, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("button frame", /obj/item/wallframe/button, 1, crafting_flags = NONE, category = CAT_EQUIPMENT), \
null, \
- new/datum/stack_recipe("iron door", /obj/structure/mineral_door/iron, 20, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 2, time = 10 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("desk bell", /obj/structure/desk_bell, 2, time = 3 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("floodlight frame", /obj/structure/floodlight_frame, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("voting box", /obj/structure/votebox, 15, time = 5 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 5 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 5 SECONDS, check_density = FALSE, category = CAT_ROBOT), \
- new/datum/stack_recipe("shower frame", /obj/structure/showerframe, 2, time = 2 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("urinal", /obj/item/wallframe/urinal, 2, time = 1 SECONDS, check_density = FALSE, category = CAT_FURNITURE)
+ new/datum/stack_recipe("iron door", /obj/structure/mineral_door/iron, 20, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_APPLIES_MATS, category = CAT_DOORS), \
+ new/datum/stack_recipe("filing cabinet", /obj/structure/filingcabinet, 2, time = 10 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("desk bell", /obj/structure/desk_bell, 2, time = 3 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("floodlight frame", /obj/structure/floodlight_frame, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("voting box", /obj/structure/votebox, 15, time = 5 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("pestle", /obj/item/pestle, 1, time = 5 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("hygienebot assembly", /obj/item/bot_assembly/hygienebot, 2, time = 5 SECONDS, crafting_flags = NONE, category = CAT_ROBOT), \
+ new/datum/stack_recipe("shower frame", /obj/structure/showerframe, 2, time = 2 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("urinal", /obj/item/wallframe/urinal, 2, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE)
))
/obj/item/stack/sheet/iron
@@ -253,14 +253,14 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
* Plasteel
*/
GLOBAL_LIST_INIT(plasteel_recipes, list ( \
- new/datum/stack_recipe("AI core", /obj/structure/ai_core, 4, time = 5 SECONDS, one_per_turf = TRUE, check_density = FALSE, category = CAT_ROBOT),
- new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 5 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY),
- new/datum/stack_recipe("Large Gas Tank", /obj/structure/tank_frame, 4, time=1 SECONDS, one_per_turf=TRUE, check_density = FALSE, category = CAT_ATMOSPHERIC),
- new/datum/stack_recipe("shutter assembly", /obj/machinery/door/poddoor/shutters/preopen/deconstructed, 5, time = 5 SECONDS, one_per_turf = TRUE, check_density = FALSE, category = CAT_DOORS),
+ new/datum/stack_recipe("AI core", /obj/structure/ai_core, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF, category = CAT_ROBOT),
+ new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 5 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY),
+ new/datum/stack_recipe("Large Gas Tank", /obj/structure/tank_frame, 4, time=1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF, category = CAT_ATMOSPHERIC),
+ new/datum/stack_recipe("shutter assembly", /obj/machinery/door/poddoor/shutters/preopen/deconstructed, 5, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_DOORS),
null,
new /datum/stack_recipe_list("airlock assemblies", list( \
- new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS),
- new/datum/stack_recipe("vault door assembly", /obj/structure/door_assembly/door_assembly_vault, 6, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS),
+ new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS),
+ new/datum/stack_recipe("vault door assembly", /obj/structure/door_assembly/door_assembly_vault, 6, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS),
)), \
))
@@ -301,49 +301,49 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
* Wood
*/
GLOBAL_LIST_INIT(wood_recipes, list ( \
- new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
- new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 1 SECONDS, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 3 SECONDS, check_density = FALSE, category = CAT_TOOLS), \
- new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("wooden stairs frame", /obj/structure/stairs_frame/wood, 10, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("wooden fence", /obj/structure/railing/wooden_fence, 2, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("cat house", /obj/structure/cat_house, 5, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
- new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
- new/datum/stack_recipe("wooden barrel", /obj/structure/fermenting_barrel, 8, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT),\
- new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_ENTERTAINMENT),\
- new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("wooden buckler", /obj/item/shield/buckler, 20, time = 4 SECONDS, check_density = FALSE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 5 SECONDS, check_density = FALSE, category = CAT_TOOLS),\
- new/datum/stack_recipe("mannequin", /obj/structure/mannequin/wood, 25, time = 5 SECONDS, one_per_turf = TRUE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("smoking pipe", /obj/item/clothing/mask/cigarette/pipe, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_TOOLS),\
- new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/cup/bucket/wooden, 3, time = 1 SECONDS, check_density = FALSE, category = CAT_CONTAINERS),\
- new/datum/stack_recipe("rake", /obj/item/cultivator/rake, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_TOOLS),\
- new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS),\
- new/datum/stack_recipe("wooden crate", /obj/structure/closet/crate/wooden, 6, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),\
- new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 1.5 SECONDS, check_density = FALSE, category = CAT_WEAPON_MELEE),\
- new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
- new/datum/stack_recipe("mortar", /obj/item/reagent_containers/cup/mortar, 3, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("firebrand", /obj/item/match/firebrand, 2, time = 10 SECONDS, check_density = FALSE, category = CAT_TOOLS), \
- new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 10, time = 6 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
- new/datum/stack_recipe("easel", /obj/structure/easel, 5, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("noticeboard", /obj/item/wallframe/noticeboard, 1, time = 1 SECONDS, one_per_turf = FALSE, on_solid_ground = FALSE, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("test tube rack", /obj/item/storage/test_tube_rack, 1, time = 1 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("wooden sandals", /obj/item/clothing/shoes/sandal, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new/datum/stack_recipe("wood table frame", /obj/structure/table_frame/wood, 2, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("rolling pin", /obj/item/kitchen/rollingpin, 2, time = 3 SECONDS, crafting_flags = NONE, category = CAT_TOOLS), \
+ new/datum/stack_recipe("wooden chair", /obj/structure/chair/wood/, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("winged wooden chair", /obj/structure/chair/wood/wings, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new/datum/stack_recipe("wooden stairs frame", /obj/structure/stairs_frame/wood, 10, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("wooden fence", /obj/structure/railing/wooden_fence, 2, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("cat house", /obj/structure/cat_house, 5, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("coffin", /obj/structure/closet/crate/coffin, 5, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("book case", /obj/structure/bookcase, 4, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("drying rack", /obj/machinery/smartfridge/drying_rack, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \
+ new/datum/stack_recipe("wooden barrel", /obj/structure/fermenting_barrel, 8, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("dog bed", /obj/structure/bed/dogbed, 10, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("dresser", /obj/structure/dresser, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("picture frame", /obj/item/wallframe/picture, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT),\
+ new/datum/stack_recipe("painting frame", /obj/item/wallframe/painting, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_ENTERTAINMENT),\
+ new/datum/stack_recipe("display case chassis", /obj/structure/displaycase_chassis, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("wooden buckler", /obj/item/shield/buckler, 20, time = 4 SECONDS, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 5 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
+ new/datum/stack_recipe("mannequin", /obj/structure/mannequin/wood, 25, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("smoking pipe", /obj/item/clothing/mask/cigarette/pipe, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
+ new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/cup/bucket/wooden, 3, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CONTAINERS),\
+ new/datum/stack_recipe("rake", /obj/item/cultivator/rake, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
+ new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS),\
+ new/datum/stack_recipe("wooden crate", /obj/structure/closet/crate/wooden, 6, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),\
+ new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 1.5 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_MELEE),\
+ new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 1.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \
+ new/datum/stack_recipe("mortar", /obj/item/reagent_containers/cup/mortar, 3, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("firebrand", /obj/item/match/firebrand, 2, time = 10 SECONDS, crafting_flags = NONE, category = CAT_TOOLS), \
+ new/datum/stack_recipe("bonfire", /obj/structure/bonfire, 10, time = 6 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \
+ new/datum/stack_recipe("easel", /obj/structure/easel, 5, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("noticeboard", /obj/item/wallframe/noticeboard, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("test tube rack", /obj/item/storage/test_tube_rack, 1, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \
null, \
new/datum/stack_recipe_list("pews", list(
- new /datum/stack_recipe("pew (middle)", /obj/structure/chair/pew, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("pew (left)", /obj/structure/chair/pew/left, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE)
+ new /datum/stack_recipe("pew (middle)", /obj/structure/chair/pew, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("pew (left)", /obj/structure/chair/pew/left, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("pew (right)", /obj/structure/chair/pew/right, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE)
)),
null, \
))
@@ -380,19 +380,19 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
*/
GLOBAL_LIST_INIT(bamboo_recipes, list ( \
- new/datum/stack_recipe("punji sticks trap", /obj/structure/punji_sticks, 5, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_EQUIPMENT), \
- new/datum/stack_recipe("bamboo spear", /obj/item/spear/bamboospear, 25, time = 9 SECONDS, check_density = FALSE, category = CAT_WEAPON_MELEE), \
- new/datum/stack_recipe("blow gun", /obj/item/gun/syringe/blowgun, 10, time = 7 SECONDS, check_density = FALSE, category = CAT_WEAPON_RANGED), \
- new/datum/stack_recipe("crude syringe", /obj/item/reagent_containers/syringe/crude, 5, time = 1 SECONDS, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("rice hat", /obj/item/clothing/head/costume/rice_hat, 10, time = 7 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("punji sticks trap", /obj/structure/punji_sticks, 5, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_EQUIPMENT), \
+ new/datum/stack_recipe("bamboo spear", /obj/item/spear/bamboospear, 25, time = 9 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_MELEE), \
+ new/datum/stack_recipe("blow gun", /obj/item/gun/syringe/blowgun, 10, time = 7 SECONDS, crafting_flags = NONE, category = CAT_WEAPON_RANGED), \
+ new/datum/stack_recipe("crude syringe", /obj/item/reagent_containers/syringe/crude, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("rice hat", /obj/item/clothing/head/costume/rice_hat, 10, time = 7 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \
null, \
- new/datum/stack_recipe("bamboo stool", /obj/structure/chair/stool/bamboo, 2, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("bamboo mat piece", /obj/item/stack/tile/bamboo, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
+ new/datum/stack_recipe("bamboo stool", /obj/structure/chair/stool/bamboo, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("bamboo mat piece", /obj/item/stack/tile/bamboo, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
null, \
new/datum/stack_recipe_list("bamboo benches", list(
- new /datum/stack_recipe("bamboo bench (middle)", /obj/structure/chair/sofa/bamboo, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("bamboo bench (left)", /obj/structure/chair/sofa/bamboo/left, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),
- new /datum/stack_recipe("bamboo bench (right)", /obj/structure/chair/sofa/bamboo/right, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE)
+ new /datum/stack_recipe("bamboo bench (middle)", /obj/structure/chair/sofa/bamboo, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("bamboo bench (left)", /obj/structure/chair/sofa/bamboo/left, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE),
+ new /datum/stack_recipe("bamboo bench (right)", /obj/structure/chair/sofa/bamboo/right, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE)
)), \
))
@@ -427,41 +427,41 @@ GLOBAL_LIST_INIT(bamboo_recipes, list ( \
* Cloth
*/
GLOBAL_LIST_INIT(cloth_recipes, list ( \
- new/datum/stack_recipe("white jumpskirt", /obj/item/clothing/under/color/jumpskirt/white, 3, check_density = FALSE, category = CAT_CLOTHING), /*Ladies first*/ \
- new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white shoes", /obj/item/clothing/shoes/sneakers/white, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white bandana", /obj/item/clothing/mask/bandana/white, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white jumpskirt", /obj/item/clothing/under/color/jumpskirt/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), /*Ladies first*/ \
+ new/datum/stack_recipe("white jumpsuit", /obj/item/clothing/under/color/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white shoes", /obj/item/clothing/shoes/sneakers/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white scarf", /obj/item/clothing/neck/scarf, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white bandana", /obj/item/clothing/mask/bandana/white, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
null, \
- new/datum/stack_recipe("backpack", /obj/item/storage/backpack, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("satchel", /obj/item/storage/backpack/satchel, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("messenger bag", /obj/item/storage/backpack/messenger, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("duffel bag", /obj/item/storage/backpack/duffelbag, 6, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("backpack", /obj/item/storage/backpack, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("satchel", /obj/item/storage/backpack/satchel, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("messenger bag", /obj/item/storage/backpack/messenger, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("duffel bag", /obj/item/storage/backpack/duffelbag, 6, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new/datum/stack_recipe("plant bag", /obj/item/storage/bag/plants, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("book bag", /obj/item/storage/bag/books, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("mining satchel", /obj/item/storage/bag/ore, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("science bag", /obj/item/storage/bag/xeno, 4, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("construction bag", /obj/item/storage/bag/construction, 4, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("plant bag", /obj/item/storage/bag/plants, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("book bag", /obj/item/storage/bag/books, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("mining satchel", /obj/item/storage/bag/ore, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("chemistry bag", /obj/item/storage/bag/chemistry, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("bio bag", /obj/item/storage/bag/bio, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("science bag", /obj/item/storage/bag/xeno, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("construction bag", /obj/item/storage/bag/construction, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6, check_density = FALSE, category = CAT_TOOLS), \
- new/datum/stack_recipe("rag", /obj/item/reagent_containers/cup/rag, 1, check_density = FALSE, category = CAT_CHEMISTRY), \
- new/datum/stack_recipe("bedsheet", /obj/item/bedsheet, 3, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("double bedsheet", /obj/item/bedsheet/double, 6, check_density = FALSE, category = CAT_FURNITURE), \
- new/datum/stack_recipe("empty sandbag", /obj/item/emptysandbag, 4, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("improvised gauze", /obj/item/stack/medical/gauze/improvised, 1, 2, 6, crafting_flags = NONE, category = CAT_TOOLS), \
+ new/datum/stack_recipe("rag", /obj/item/reagent_containers/cup/rag, 1, crafting_flags = NONE, category = CAT_CHEMISTRY), \
+ new/datum/stack_recipe("bedsheet", /obj/item/bedsheet, 3, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("double bedsheet", /obj/item/bedsheet/double, 6, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("empty sandbag", /obj/item/emptysandbag, 4, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new/datum/stack_recipe("fingerless gloves", /obj/item/clothing/gloves/fingerless, 1, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white softcap", /obj/item/clothing/head/soft/mime, 2, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("white beanie", /obj/item/clothing/head/beanie, 2, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("fingerless gloves", /obj/item/clothing/gloves/fingerless, 1, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white gloves", /obj/item/clothing/gloves/color/white, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white softcap", /obj/item/clothing/head/soft/mime, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("white beanie", /obj/item/clothing/head/beanie, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
null, \
- new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/blindfold, 2, check_density = FALSE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("blindfold", /obj/item/clothing/glasses/blindfold, 2, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
null, \
- new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteen_nineteen, 3, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythree_nineteen, 4, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythree_twentythree, 5, check_density = FALSE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("19x19 canvas", /obj/item/canvas/nineteen_nineteen, 3, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("23x19 canvas", /obj/item/canvas/twentythree_nineteen, 4, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("23x23 canvas", /obj/item/canvas/twentythree_twentythree, 5, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
new/datum/stack_recipe("pillow", /obj/item/pillow, 3, category = CAT_FURNITURE), \
))
@@ -490,10 +490,10 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( \
amount = 5
GLOBAL_LIST_INIT(durathread_recipes, list ( \
- new/datum/stack_recipe("durathread jumpsuit", /obj/item/clothing/under/misc/durathread, 4, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING),
- new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 4 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 2.5 SECONDS, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("durathread jumpsuit", /obj/item/clothing/under/misc/durathread, 4, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING),
+ new/datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 4 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 2.5 SECONDS, crafting_flags = NONE, category = CAT_CLOTHING), \
))
/obj/item/stack/sheet/durathread
@@ -564,61 +564,61 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( \
* Cardboard
*/
GLOBAL_LIST_INIT(cardboard_recipes, list ( \
- new/datum/stack_recipe("box", /obj/item/storage/box, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/costume/cardborg, 3, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/costume/cardborg, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5, check_density = FALSE, category = CAT_ENTERTAINMENT), \
+ new/datum/stack_recipe("box", /obj/item/storage/box, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/costume/cardborg, 3, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/costume/cardborg, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("large box", /obj/structure/closet/cardboard, 4, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("cardboard cutout", /obj/item/cardboard_cutout, 5, crafting_flags = NONE, category = CAT_ENTERTAINMENT), \
null, \
- new/datum/stack_recipe("pizza box", /obj/item/pizzabox, check_density = FALSE, category = CAT_CONTAINERS), \
- new/datum/stack_recipe("folder", /obj/item/folder, check_density = FALSE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("pizza box", /obj/item/pizzabox, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new/datum/stack_recipe("folder", /obj/item/folder, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
//TO-DO: Find a proper way to just change the illustration on the box. Code isn't the issue, input is.
new/datum/stack_recipe_list("fancy boxes", list(
- new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets box", /obj/item/storage/box/donkpockets, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets spicy box", /obj/item/storage/box/donkpockets/donkpocketspicy, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets teriyaki box", /obj/item/storage/box/donkpockets/donkpocketteriyaki, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets pizza box", /obj/item/storage/box/donkpockets/donkpocketpizza, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets berry box", /obj/item/storage/box/donkpockets/donkpocketberry, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("donk-pockets honk box", /obj/item/storage/box/donkpockets/donkpockethonk, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("monkey cube box", /obj/item/storage/box/monkeycubes, check_density = FALSE, category = CAT_CONTAINERS),
- new /datum/stack_recipe("nugget box", /obj/item/storage/fancy/nugget_box, check_density = FALSE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donut box", /obj/item/storage/fancy/donut_box, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets box", /obj/item/storage/box/donkpockets, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets spicy box", /obj/item/storage/box/donkpockets/donkpocketspicy, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets teriyaki box", /obj/item/storage/box/donkpockets/donkpocketteriyaki, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets pizza box", /obj/item/storage/box/donkpockets/donkpocketpizza, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets berry box", /obj/item/storage/box/donkpockets/donkpocketberry, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("donk-pockets honk box", /obj/item/storage/box/donkpockets/donkpockethonk, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("monkey cube box", /obj/item/storage/box/monkeycubes, crafting_flags = NONE, category = CAT_CONTAINERS),
+ new /datum/stack_recipe("nugget box", /obj/item/storage/fancy/nugget_box, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new /datum/stack_recipe("lethal ammo box", /obj/item/storage/box/lethalshot, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("rubber shot ammo box", /obj/item/storage/box/rubbershot, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("bean bag ammo box", /obj/item/storage/box/beanbag, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("flashbang box", /obj/item/storage/box/flashbangs, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("flashes box", /obj/item/storage/box/flashes, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("handcuffs box", /obj/item/storage/box/handcuffs, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("ID card box", /obj/item/storage/box/ids, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("PDA box", /obj/item/storage/box/pdas, check_density = FALSE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("lethal ammo box", /obj/item/storage/box/lethalshot, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("rubber shot ammo box", /obj/item/storage/box/rubbershot, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("bean bag ammo box", /obj/item/storage/box/beanbag, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("flashbang box", /obj/item/storage/box/flashbangs, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("flashes box", /obj/item/storage/box/flashes, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("handcuffs box", /obj/item/storage/box/handcuffs, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("ID card box", /obj/item/storage/box/ids, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("PDA box", /obj/item/storage/box/pdas, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new /datum/stack_recipe("pillbottle box", /obj/item/storage/box/pillbottles, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("beaker box", /obj/item/storage/box/beakers, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("syringe box", /obj/item/storage/box/syringes, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("latex gloves box", /obj/item/storage/box/gloves, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("sterile masks box", /obj/item/storage/box/masks, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("body bag box", /obj/item/storage/box/bodybags, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("perscription glasses box", /obj/item/storage/box/rxglasses, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("medipen box", /obj/item/storage/box/medipens, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("oxygen tank box", /obj/item/storage/box/emergencytank, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("extended oxygen tank box", /obj/item/storage/box/engitank, check_density = FALSE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("pillbottle box", /obj/item/storage/box/pillbottles, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("beaker box", /obj/item/storage/box/beakers, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("syringe box", /obj/item/storage/box/syringes, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("latex gloves box", /obj/item/storage/box/gloves, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("sterile masks box", /obj/item/storage/box/masks, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("body bag box", /obj/item/storage/box/bodybags, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("perscription glasses box", /obj/item/storage/box/rxglasses, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("medipen box", /obj/item/storage/box/medipens, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("oxygen tank box", /obj/item/storage/box/emergencytank, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("extended oxygen tank box", /obj/item/storage/box/engitank, crafting_flags = NONE, category = CAT_CONTAINERS), \
null, \
- new /datum/stack_recipe("survival box", /obj/item/storage/box/survival/crafted, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("extended tank survival box", /obj/item/storage/box/survival/engineer/crafted, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("disk box", /obj/item/storage/box/disks, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("light tubes box", /obj/item/storage/box/lights/tubes, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("light bulbs box", /obj/item/storage/box/lights/bulbs, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("mixed lights box", /obj/item/storage/box/lights/mixed, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("mouse traps box", /obj/item/storage/box/mousetraps, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("bandage box", /obj/item/storage/box/bandages, check_density = FALSE, category = CAT_CONTAINERS)
+ new /datum/stack_recipe("survival box", /obj/item/storage/box/survival/crafted, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("extended tank survival box", /obj/item/storage/box/survival/engineer/crafted, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("disk box", /obj/item/storage/box/disks, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("light tubes box", /obj/item/storage/box/lights/tubes, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("light bulbs box", /obj/item/storage/box/lights/bulbs, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("mixed lights box", /obj/item/storage/box/lights/mixed, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("mouse traps box", /obj/item/storage/box/mousetraps, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("candle box", /obj/item/storage/fancy/candle_box, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("bandage box", /obj/item/storage/box/bandages, crafting_flags = NONE, category = CAT_CONTAINERS)
)),
null, \
@@ -676,18 +676,18 @@ GLOBAL_LIST_INIT(cardboard_recipes, list ( \
*/
GLOBAL_LIST_INIT(bronze_recipes, list ( \
- new/datum/stack_recipe("wall gear", /obj/structure/girder/bronze, 2, time = 2 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_STRUCTURE), \
+ new/datum/stack_recipe("wall gear", /obj/structure/girder/bronze, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_STRUCTURE), \
null,
- new/datum/stack_recipe("directional bronze window", /obj/structure/window/bronze/unanchored, time = 0, on_solid_ground = TRUE, check_direction = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("fulltile bronze window", /obj/structure/window/bronze/fulltile/unanchored, 2, time = 0, on_solid_ground = TRUE, is_fulltile = TRUE, category = CAT_WINDOWS), \
- new/datum/stack_recipe("pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("bronze pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze/seethru, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_DOORS), \
- new/datum/stack_recipe("bronze floor tile", /obj/item/stack/tile/bronze, 1, 4, 20, check_density = FALSE, category = CAT_TILES), \
- new/datum/stack_recipe("bronze hat", /obj/item/clothing/head/costume/bronze, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("bronze suit", /obj/item/clothing/suit/costume/bronze, check_density = FALSE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze, check_density = FALSE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("directional bronze window", /obj/structure/window/bronze/unanchored, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("fulltile bronze window", /obj/structure/window/bronze/fulltile/unanchored, 2, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \
+ new/datum/stack_recipe("pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new/datum/stack_recipe("bronze pinion airlock assembly", /obj/structure/door_assembly/door_assembly_bronze/seethru, 4, time = 5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_DOORS), \
+ new/datum/stack_recipe("bronze floor tile", /obj/item/stack/tile/bronze, 1, 4, 20, crafting_flags = NONE, category = CAT_TILES), \
+ new/datum/stack_recipe("bronze hat", /obj/item/clothing/head/costume/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("bronze suit", /obj/item/clothing/suit/costume/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("bronze boots", /obj/item/clothing/shoes/bronze, crafting_flags = NONE, category = CAT_CLOTHING), \
null,
- new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE), \
+ new/datum/stack_recipe("bronze chair", /obj/structure/chair/bronze, 1, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \
))
/obj/item/stack/sheet/bronze
@@ -784,19 +784,19 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
slapcraft_recipes = slapcraft_recipe_list,\
)
GLOBAL_LIST_INIT(plastic_recipes, list(
- new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
- new /datum/stack_recipe("light tram tile", /obj/item/stack/thermoplastic/light, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
- new /datum/stack_recipe("dark tram tile", /obj/item/stack/thermoplastic, 1, 4, 20, time = 2 SECONDS, check_density = FALSE, category = CAT_TILES), \
- new /datum/stack_recipe("folding plastic chair", /obj/structure/chair/plastic, 2, check_density = FALSE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, one_per_turf = TRUE, on_solid_ground = TRUE, time = 4 SECONDS, category = CAT_FURNITURE), \
- new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/large/empty, 3, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("colo cups", /obj/item/reagent_containers/cup/glass/colocup, 1, check_density = FALSE, category = CAT_CONTAINERS), \
- new /datum/stack_recipe("mannequin", /obj/structure/mannequin/plastic, 25, time = 5 SECONDS, one_per_turf = TRUE, check_density = FALSE, category = CAT_ENTERTAINMENT), \
- new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new /datum/stack_recipe("warning cone", /obj/item/clothing/head/cone, 2, check_density = FALSE, category = CAT_EQUIPMENT), \
- new /datum/stack_recipe("blank wall sign", /obj/item/sign, 1, check_density = FALSE, category = CAT_FURNITURE), \
- new /datum/stack_recipe("rebellion mask", /obj/item/clothing/mask/rebellion, 1, check_density = FALSE, category = CAT_CLOTHING)))
+ new /datum/stack_recipe("plastic floor tile", /obj/item/stack/tile/plastic, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \
+ new /datum/stack_recipe("light tram tile", /obj/item/stack/thermoplastic/light, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \
+ new /datum/stack_recipe("dark tram tile", /obj/item/stack/thermoplastic, 1, 4, 20, time = 2 SECONDS, crafting_flags = NONE, category = CAT_TILES), \
+ new /datum/stack_recipe("folding plastic chair", /obj/structure/chair/plastic, 2, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("plastic flaps", /obj/structure/plasticflaps, 5, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, time = 4 SECONDS, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/empty, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("large water bottle", /obj/item/reagent_containers/cup/glass/waterbottle/large/empty, 3, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("colo cups", /obj/item/reagent_containers/cup/glass/colocup, 1, crafting_flags = NONE, category = CAT_CONTAINERS), \
+ new /datum/stack_recipe("mannequin", /obj/structure/mannequin/plastic, 25, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_ENTERTAINMENT), \
+ new /datum/stack_recipe("wet floor sign", /obj/item/clothing/suit/caution, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new /datum/stack_recipe("warning cone", /obj/item/clothing/head/cone, 2, crafting_flags = NONE, category = CAT_EQUIPMENT), \
+ new /datum/stack_recipe("blank wall sign", /obj/item/sign, 1, crafting_flags = NONE, category = CAT_FURNITURE), \
+ new /datum/stack_recipe("rebellion mask", /obj/item/clothing/mask/rebellion, 1, crafting_flags = NONE, category = CAT_CLOTHING)))
/obj/item/stack/sheet/plastic
name = "plastic"
@@ -820,8 +820,8 @@ GLOBAL_LIST_INIT(plastic_recipes, list(
. += GLOB.plastic_recipes
GLOBAL_LIST_INIT(paperframe_recipes, list(
-new /datum/stack_recipe("paper frame separator", /obj/structure/window/paperframe, 2, one_per_turf = TRUE, on_solid_ground = TRUE, is_fulltile = TRUE, time = 1 SECONDS), \
-new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperframe, 3, one_per_turf = TRUE, on_solid_ground = TRUE, time = 1 SECONDS )))
+new /datum/stack_recipe("paper frame separator", /obj/structure/window/paperframe, 2, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, time = 1 SECONDS), \
+new /datum/stack_recipe("paper frame door", /obj/structure/mineral_door/paperframe, 3, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, time = 1 SECONDS )))
/obj/item/stack/sheet/paperframes
name = "paper frames"
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 18a95cd77d378..4258465f3a07e 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -1,9 +1,3 @@
-//stack recipe placement check types
-/// Checks if there is an object of the result type in any of the cardinal directions
-#define STACK_CHECK_CARDINALS (1<<0)
-/// Checks if there is an object of the result type within one tile
-#define STACK_CHECK_ADJACENT (1<<1)
-
/* Stack type objects!
* Contains:
* Stacks
@@ -423,7 +417,7 @@
return
var/turf/created_turf = covered_turf.place_on_top(recipe.result_type, flags = CHANGETURF_INHERIT_AIR)
builder.balloon_alert(builder, "placed [ispath(recipe.result_type, /turf/open) ? "floor" : "wall"]")
- if(recipe.applies_mats && LAZYLEN(mats_per_unit))
+ if((recipe.crafting_flags & CRAFT_APPLIES_MATS) && LAZYLEN(mats_per_unit))
created_turf.set_custom_materials(mats_per_unit, recipe.req_amount / recipe.res_amount)
else
@@ -439,7 +433,7 @@
builder.investigate_log("crafted [recipe.title]", INVESTIGATE_CRAFTING)
// Apply mat datums
- if(recipe.applies_mats && LAZYLEN(mats_per_unit))
+ if((recipe.crafting_flags & CRAFT_APPLIES_MATS) && LAZYLEN(mats_per_unit))
if(isstack(created))
var/obj/item/stack/crafted_stack = created
crafted_stack.set_mats_per_unit(mats_per_unit, recipe.req_amount / recipe.res_amount)
@@ -484,16 +478,16 @@
return FALSE
var/turf/dest_turf = get_turf(builder)
- if(recipe.one_per_turf && (locate(recipe.result_type) in dest_turf))
+ if((recipe.crafting_flags & CRAFT_ONE_PER_TURF) && (locate(recipe.result_type) in dest_turf))
builder.balloon_alert(builder, "already one here!")
return FALSE
- if(recipe.check_direction)
- if(!valid_build_direction(dest_turf, builder.dir, is_fulltile = recipe.is_fulltile))
+ if(recipe.crafting_flags & CRAFT_CHECK_DIRECTION)
+ if(!valid_build_direction(dest_turf, builder.dir, is_fulltile = (recipe.crafting_flags & CRAFT_IS_FULLTILE)))
builder.balloon_alert(builder, "won't fit here!")
return FALSE
- if(recipe.on_solid_ground)
+ if(recipe.crafting_flags & CRAFT_ON_SOLID_GROUND)
if(isclosedturf(dest_turf))
builder.balloon_alert(builder, "cannot be made on a wall!")
return FALSE
@@ -503,7 +497,7 @@
builder.balloon_alert(builder, "must be made on solid ground!")
return FALSE
- if(recipe.check_density)
+ if(recipe.crafting_flags & CRAFT_CHECK_DENSITY)
for(var/obj/object in dest_turf)
if(object.density && !(object.obj_flags & IGNORE_DENSITY) || object.obj_flags & BLOCKS_CONSTRUCTION)
builder.balloon_alert(builder, "something is in the way!")
@@ -742,6 +736,3 @@
add_hiddenprint_list(GET_ATOM_HIDDENPRINTS(from))
fingerprintslast = from.fingerprintslast
//TODO bloody overlay
-
-#undef STACK_CHECK_CARDINALS
-#undef STACK_CHECK_ADJACENT
diff --git a/code/game/objects/items/stacks/stack_recipe.dm b/code/game/objects/items/stacks/stack_recipe.dm
index bfdc3c8ca5717..4a150f4f2abce 100644
--- a/code/game/objects/items/stacks/stack_recipe.dm
+++ b/code/game/objects/items/stacks/stack_recipe.dm
@@ -15,21 +15,8 @@
var/max_res_amount = 1
/// How long it takes to make
var/time = 0
- /// If only one of the resulting atom is allowed per turf
- var/one_per_turf = FALSE
- /// If the atom is fulltile, as in a fulltile window. This is used for the direction check to prevent fulltile windows from being able to be built over directional stuff.
- /// Setting this to true will effectively set check_direction to true.
- var/is_fulltile = FALSE
- /// If this atom should run the direction check, for use when building things like directional windows where you can have more than one per turf
- var/check_direction = FALSE
- /// If the atom requires a floor below
- var/on_solid_ground = FALSE
- /// If the atom checks that there are objects with density in the same turf when being built. TRUE by default
- var/check_density = TRUE
/// Bitflag of additional placement checks required to place. (STACK_CHECK_CARDINALS|STACK_CHECK_ADJACENT|STACK_CHECK_TRAM_FORBIDDEN|STACK_CHECK_TRAM_EXCLUSIVE)
var/placement_checks = NONE
- /// If TRUE, the created atom will gain custom mat datums
- var/applies_mats = FALSE
/// What trait, if any, boosts the construction speed of this item
var/trait_booster
/// How much the trait above, if supplied, boosts the construct speed of this item
@@ -37,6 +24,9 @@
/// Category for general crafting menu
var/category
+ ///crafting_flags var to hold bool values
+ var/crafting_flags = CRAFT_CHECK_DENSITY
+
/datum/stack_recipe/New(
title,
result_type,
@@ -44,13 +34,8 @@
res_amount = 1,
max_res_amount = 1,
time = 0,
- one_per_turf = FALSE,
- on_solid_ground = FALSE,
- is_fulltile = FALSE,
- check_direction = FALSE,
- check_density = TRUE,
+ crafting_flags = CRAFT_CHECK_DENSITY,
placement_checks = NONE,
- applies_mats = FALSE,
trait_booster,
trait_modifier = 1,
category,
@@ -62,13 +47,7 @@
src.res_amount = res_amount
src.max_res_amount = max_res_amount
src.time = time
- src.one_per_turf = one_per_turf
- src.on_solid_ground = on_solid_ground
- src.is_fulltile = is_fulltile
- src.check_direction = check_direction || is_fulltile
- src.check_density = check_density
src.placement_checks = placement_checks
- src.applies_mats = applies_mats
src.trait_booster = trait_booster
src.trait_modifier = trait_modifier
src.category = src.category || category || CAT_MISC
@@ -88,7 +67,6 @@
on_solid_ground = FALSE,
window_checks = FALSE,
placement_checks = NONE,
- applies_mats = FALSE,
trait_booster,
trait_modifier = 1,
desc,
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
index c05446d35218e..8f78cb01ebc23 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_bread.dm
@@ -150,7 +150,7 @@
)
result = /obj/item/food/croissant/throwing
category = CAT_BREAD
- always_available = FALSE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/breaddog
name = "Living dog/bread hybrid"
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
index b34cc5f36e965..4b56874eb7c6b 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
@@ -184,7 +184,6 @@
/datum/crafting_recipe/food/clowncake
name = "clown cake"
- always_available = FALSE
reqs = list(
/obj/item/food/cake/plain = 1,
/obj/item/food/sundae = 2,
@@ -192,16 +191,17 @@
)
result = /obj/item/food/cake/clown_cake
category = CAT_CAKE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/vanillacake
name = "vanilla cake"
- always_available = FALSE
reqs = list(
/obj/item/food/cake/plain = 1,
/obj/item/food/grown/vanillapod = 2
)
result = /obj/item/food/cake/vanilla_cake
category = CAT_CAKE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/trumpetcake
name = "Spaceman's Cake"
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
index a9f1ad23d8e26..c0c99bbe6523b 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm
@@ -132,7 +132,6 @@
/datum/crafting_recipe/food/mimetart
name = "Mime tart"
- always_available = FALSE
reqs = list(
/datum/reagent/consumable/milk = 5,
/datum/reagent/consumable/sugar = 5,
@@ -141,10 +140,10 @@
)
result = /obj/item/food/pie/mimetart
category = CAT_PIE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/berrytart
name = "Berry tart"
- always_available = FALSE
reqs = list(
/datum/reagent/consumable/milk = 5,
/datum/reagent/consumable/sugar = 5,
@@ -153,10 +152,10 @@
)
result = /obj/item/food/pie/berrytart
category = CAT_PIE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/cocolavatart
name = "Chocolate Lava tart"
- always_available = FALSE
reqs = list(
/datum/reagent/consumable/milk = 5,
/datum/reagent/consumable/sugar = 5,
@@ -166,6 +165,7 @@
)
result = /obj/item/food/pie/cocolavatart
category = CAT_PIE
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/blumpkinpie
name = "Blumpkin pie"
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm
index b0c44629e1853..7761a57fcfdbd 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_sandwich.dm
@@ -118,7 +118,6 @@
/datum/crafting_recipe/food/death_sandwich
name = "Death Sandwich"
- always_available = FALSE
reqs = list(
/obj/item/food/breadslice/plain = 2,
/obj/item/food/salami = 4,
@@ -127,6 +126,7 @@
)
result = /obj/item/food/sandwich/death
category = CAT_SANDWICH
+ crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_MUST_BE_LEARNED
/datum/crafting_recipe/food/toast_sandwich
name = "Toast Sandwich"
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index e94b8d981ffeb..65644b00cc87a 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -107,9 +107,9 @@
merge_type = /obj/item/stack/ore/glass
GLOBAL_LIST_INIT(sand_recipes, list(\
- new /datum/stack_recipe("pile of dirt", /obj/machinery/hydroponics/soil, 3, time = 1 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \
- new /datum/stack_recipe("sandstone", /obj/item/stack/sheet/mineral/sandstone, 1, 1, 50, check_density = FALSE, category = CAT_MISC),\
- new /datum/stack_recipe("aesthetic volcanic floor tile", /obj/item/stack/tile/basalt, 2, 1, 50, check_density = FALSE, category = CAT_TILES)\
+ new /datum/stack_recipe("pile of dirt", /obj/machinery/hydroponics/soil, 3, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ONE_PER_TURF | CRAFT_ON_SOLID_GROUND, category = CAT_TOOLS), \
+ new /datum/stack_recipe("sandstone", /obj/item/stack/sheet/mineral/sandstone, 1, 1, 50, crafting_flags = NONE, category = CAT_MISC),\
+ new /datum/stack_recipe("aesthetic volcanic floor tile", /obj/item/stack/tile/basalt, 2, 1, 50, crafting_flags = NONE, category = CAT_TILES)\
))
/obj/item/stack/ore/glass/Initialize(mapload, new_amount, merge, list/mat_override, mat_amt)
From c5e534ecc4e2056d4837d9fe627f0597079e46b6 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 19:36:15 +1200
Subject: [PATCH 52/87] Automatic changelog for PR #82833 [ci skip]
---
html/changelogs/AutoChangeLog-pr-82833.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-82833.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82833.yml b/html/changelogs/AutoChangeLog-pr-82833.yml
new file mode 100644
index 0000000000000..b9e08edc7e89e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-82833.yml
@@ -0,0 +1,4 @@
+author: "Xander3359"
+delete-after: True
+changes:
+ - bugfix: "You can no longer bypass construction restrictions via the crafting menu"
\ No newline at end of file
From 15fe98edfa00fdbfe2f65c6015ababc738635f42 Mon Sep 17 00:00:00 2001
From: Ghom <42542238+Ghommie@users.noreply.github.com>
Date: Fri, 3 May 2024 13:23:52 +0200
Subject: [PATCH 53/87] Adds a station trait that brightens up IceBox's
surface. (#82945)
## About The Pull Request
This PR adds a positive trait that brings lights to the outdoors surface
areas of Icebox.
## Why It's Good For The Game
Building upon the features of the station traits. This is how it'd look:
![It's Always Sunny On
IceBoxStation](https://github.com/tgstation/tgstation/assets/42542238/af4238e9-c731-41c9-9eaf-8fcb04d6fe4f)
## Changelog
:cl:
add: Adds an Icebox-specific station trait that brightens outdoors areas
on the surface level.
/:cl:
---
code/__DEFINES/traits/declarations.dm | 1 +
code/_globalvars/traits/_traits.dm | 1 +
code/datums/station_traits/positive_traits.dm | 9 +++++++++
code/game/area/areas/mining.dm | 5 +++++
4 files changed, 16 insertions(+)
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index f2cb9069fb64f..a3218bd5db733 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -950,6 +950,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define STATION_TRAIT_BIGGER_PODS "station_trait_bigger_pods"
#define STATION_TRAIT_BIRTHDAY "station_trait_birthday"
#define STATION_TRAIT_BOTS_GLITCHED "station_trait_bot_glitch"
+#define STATION_TRAIT_BRIGHT_DAY "station_trait_bright_day"
#define STATION_TRAIT_CARP_INFESTATION "station_trait_carp_infestation"
#define STATION_TRAIT_CYBERNETIC_REVOLUTION "station_trait_cybernetic_revolution"
#define STATION_TRAIT_EMPTY_MAINT "station_trait_empty_maint"
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index dd0c89c2211c8..91ea4d2be0033 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -79,6 +79,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"STATION_TRAIT_BIGGER_PODS" = STATION_TRAIT_BIGGER_PODS,
"STATION_TRAIT_BIRTHDAY" = STATION_TRAIT_BIRTHDAY,
"STATION_TRAIT_BOTS_GLITCHED" = STATION_TRAIT_BOTS_GLITCHED,
+ "STATION_TRAIT_BRIGHT_DAY" = STATION_TRAIT_BRIGHT_DAY,
"STATION_TRAIT_CARP_INFESTATION" = STATION_TRAIT_CARP_INFESTATION,
"STATION_TRAIT_CYBERNETIC_REVOLUTION" = STATION_TRAIT_CYBERNETIC_REVOLUTION,
"STATION_TRAIT_EMPTY_MAINT" = STATION_TRAIT_EMPTY_MAINT,
diff --git a/code/datums/station_traits/positive_traits.dm b/code/datums/station_traits/positive_traits.dm
index bff2d532570f9..8398e02139d74 100644
--- a/code/datums/station_traits/positive_traits.dm
+++ b/code/datums/station_traits/positive_traits.dm
@@ -292,6 +292,15 @@
weight_multiplier = 3
max_occurrences_modifier = 10 //lotta cows
+/datum/station_trait/bright_day
+ name = "Bright Day"
+ report_message = "The stars shine bright and the clouds are scarcer than usual. It's a bright day here on the Ice Moon's surface."
+ trait_type = STATION_TRAIT_POSITIVE
+ weight = 5
+ show_in_report = TRUE
+ trait_flags = STATION_TRAIT_PLANETARY
+ trait_to_give = STATION_TRAIT_BRIGHT_DAY
+
/datum/station_trait/shuttle_sale
name = "Shuttle Firesale"
report_message = "The Nanotrasen Emergency Dispatch team is celebrating a record number of shuttle calls in the recent quarter. Some of your emergency shuttle options have been discounted!"
diff --git a/code/game/area/areas/mining.dm b/code/game/area/areas/mining.dm
index 1582f7390cf04..38855de366f9f 100644
--- a/code/game/area/areas/mining.dm
+++ b/code/game/area/areas/mining.dm
@@ -209,6 +209,11 @@
name = "Icemoon Wastes"
outdoors = TRUE
+/area/icemoon/surface/outdoors/Initialize(mapload)
+ if(HAS_TRAIT(SSstation, STATION_TRAIT_BRIGHT_DAY))
+ base_lighting_alpha = 145
+ return ..()
+
/area/icemoon/surface/outdoors/nospawn // this is the area you use for stuff to not spawn, but if you still want weather.
/area/icemoon/surface/outdoors/nospawn/New() // unless you roll forested trait lol
From 70eefcd71d4086e0dfbe33658e096253d8668c66 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 23:24:11 +1200
Subject: [PATCH 54/87] Automatic changelog for PR #82945 [ci skip]
---
html/changelogs/AutoChangeLog-pr-82945.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-82945.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82945.yml b/html/changelogs/AutoChangeLog-pr-82945.yml
new file mode 100644
index 0000000000000..a1485366ae2f4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-82945.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - rscadd: "Adds an Icebox-specific station trait that brightens outdoors areas on the surface level."
\ No newline at end of file
From 7778471269a40250f59dd2620fa84bd447a956cd Mon Sep 17 00:00:00 2001
From: cnleth <113535457+cnleth@users.noreply.github.com>
Date: Fri, 3 May 2024 14:32:27 +0300
Subject: [PATCH 55/87] Fire ant colonies created by burning actually contain
fire ants (#83002)
## About The Pull Request
Fire ant colonies created by burning regular ants now give you fire ants
when scooped up
There were 2 lines of code clearing the ants' reagent when they're
burned. They're not needed because ants use `decal_reagent`
Tested and it works without these 2 lines
![fireants](https://github.com/tgstation/tgstation/assets/113535457/aee4ec28-a767-4dfe-b870-2a222848ae3a)
## Why It's Good For The Game
Fixes #82864
## Changelog
:cl:
fix: Fire ant colonies created by burning regular ants will now contain
fire ants as their reagent
/:cl:
---
code/game/objects/effects/decals/cleanable/misc.dm | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm
index f21bfc4788426..0af1e402ee1dd 100644
--- a/code/game/objects/effects/decals/cleanable/misc.dm
+++ b/code/game/objects/effects/decals/cleanable/misc.dm
@@ -412,9 +412,7 @@
. += emissive_appearance(icon, "[icon_state]_light", src, alpha = src.alpha)
/obj/effect/decal/cleanable/ants/fire_act(exposed_temperature, exposed_volume)
- var/obj/effect/decal/cleanable/ants/fire/fire_ants = new(loc)
- fire_ants.reagents.clear_reagents()
- reagents.trans_to(fire_ants, fire_ants.reagents.maximum_volume)
+ new /obj/effect/decal/cleanable/ants/fire(loc)
qdel(src)
/obj/effect/decal/cleanable/ants/fire
From f112369547a7da6fdafd69c1d43baf0fc6f76f77 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Fri, 3 May 2024 23:32:46 +1200
Subject: [PATCH 56/87] Automatic changelog for PR #83002 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83002.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83002.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83002.yml b/html/changelogs/AutoChangeLog-pr-83002.yml
new file mode 100644
index 0000000000000..114603f123725
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83002.yml
@@ -0,0 +1,4 @@
+author: "cnleth"
+delete-after: True
+changes:
+ - bugfix: "Fire ant colonies created by burning regular ants will now contain fire ants as their reagent"
\ No newline at end of file
From 82d5a883252e6f4eec35146bf0365518b49bba5c Mon Sep 17 00:00:00 2001
From: oranges
Date: Sat, 4 May 2024 06:35:20 +1200
Subject: [PATCH 57/87] General IP intel tweaks (#82904)
Co-authored-by: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Co-authored-by: ZephyrTFA
Co-authored-by: Kyle Spier-Swenson
---
code/__DEFINES/admin_verb.dm | 2 +-
.../configuration/entries/general.dm | 14 +-
code/controllers/subsystem/ipintel.dm | 130 +++++++++---------
code/modules/client/client_procs.dm | 2 +-
4 files changed, 72 insertions(+), 76 deletions(-)
diff --git a/code/__DEFINES/admin_verb.dm b/code/__DEFINES/admin_verb.dm
index 7e811c121961c..04806e098b2c4 100644
--- a/code/__DEFINES/admin_verb.dm
+++ b/code/__DEFINES/admin_verb.dm
@@ -87,7 +87,7 @@ _ADMIN_VERB(verb_path_name, verb_permissions, verb_name, verb_desc, verb_categor
#define ADMIN_CATEGORY_OBJECT "Object"
#define ADMIN_CATEGORY_MAPPING "Mapping"
#define ADMIN_CATEGORY_PROFILE "Profile"
-#define ADMIN_CATEGORY_IPINTEL "IPIntel"
+#define ADMIN_CATEGORY_IPINTEL "Admin.IPIntel"
// Visibility flags
#define ADMIN_VERB_VISIBLITY_FLAG_MAPPING_DEBUG "Map-Debug"
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index 98a386b7c8b82..69b3bbcad64f6 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -453,7 +453,7 @@
/datum/config_entry/string/ipintel_email
/datum/config_entry/string/ipintel_email/ValidateAndSet(str_val)
- return str_val != "ch@nge.me" && ..()
+ return str_val != "ch@nge.me" && (!length(str_val) || findtext(str_val, "@")) && ..()
/datum/config_entry/number/ipintel_rating_bad
default = 1
@@ -462,25 +462,25 @@
max_val = 1
/datum/config_entry/flag/ipintel_reject_rate_limited
- default = TRUE
+ default = FALSE
/datum/config_entry/flag/ipintel_reject_bad
- default = TRUE
+ default = FALSE
/datum/config_entry/flag/ipintel_reject_unknown
default = FALSE
/datum/config_entry/number/ipintel_rate_minute
default = 15
-
-/datum/config_entry/number/ipintel_rate_day
- default = 500
+ min_val = 0
/datum/config_entry/number/ipintel_cache_length
default = 7
+ min_val = 0
/datum/config_entry/number/ipintel_exempt_playtime_living
- default = 0
+ default = 5
+ min_val = 0
/datum/config_entry/flag/aggressive_changelog
diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm
index ba4cda13a43d9..9bbaf320139d5 100644
--- a/code/controllers/subsystem/ipintel.dm
+++ b/code/controllers/subsystem/ipintel.dm
@@ -1,26 +1,14 @@
SUBSYSTEM_DEF(ipintel)
name = "XKeyScore"
init_order = INIT_ORDER_XKEYSCORE
- flags = SS_OK_TO_FAIL_INIT|SS_NO_FIRE
+ flags = SS_NO_INIT|SS_NO_FIRE
/// The threshold for probability to be considered a VPN and/or bad IP
var/probability_threshold
- /// The email used in conjuction with https://check.getipintel.net/check.php
- var/contact_email
- /// Maximum number of queries per minute
- var/max_queries_per_minute
- /// Maximum number of queries per day
- var/max_queries_per_day
- /// Query base
- var/query_base
- /// The length of time (days) to cache IP intel
- var/ipintel_cache_length
- /// The living playtime (minutes) for players to be exempt from IPIntel checks
- var/exempt_living_playtime
/// Cache for previously queried IP addresses and those stored in the database
var/list/datum/ip_intel/cached_queries = list()
/// The store for rate limiting
- var/list/rate_limits
+ var/list/rate_limit_minute
/// The ip intel for a given address
/datum/ip_intel
@@ -30,47 +18,39 @@ SUBSYSTEM_DEF(ipintel)
var/address
var/date
-/datum/controller/subsystem/ipintel/Initialize()
+/datum/controller/subsystem/ipintel/OnConfigLoad()
var/list/fail_messages = list()
-
- probability_threshold = CONFIG_GET(number/ipintel_rating_bad)
- if(probability_threshold < 0 || probability_threshold > 1)
- fail_messages += list("invalid probability threshold")
-
- contact_email = CONFIG_GET(string/ipintel_email)
- if(isnull(contact_email) || !findtext(contact_email, "@"))
- fail_messages += list("invalid contact email")
-
- var/max_queries_per_minute = CONFIG_GET(number/ipintel_rate_minute)
- var/max_queries_per_day = CONFIG_GET(number/ipintel_rate_day)
- if(max_queries_per_minute < 0 || max_queries_per_day < 0)
- fail_messages += list("invalid rate limits")
-
- var/query_base = CONFIG_GET(string/ipintel_base)
- if(isnull(query_base))
- fail_messages += list("invalid query base")
-
- var/ipintel_cache_length = CONFIG_GET(number/ipintel_cache_length)
- if(ipintel_cache_length < 0)
- fail_messages += list("invalid cache length")
-
- var/exempt_living_playtime = CONFIG_GET(number/ipintel_exempt_playtime_living)
- if(exempt_living_playtime < 0)
- fail_messages += list("invalid exempt living playtime")
-
+
+ var/contact_email = CONFIG_GET(string/ipintel_email)
+
+ if(!length(contact_email))
+ fail_messages += "No contact email"
+
+ if(!findtext(contact_email, "@"))
+ fail_messages += "Invalid contact email"
+
+ if(!length(CONFIG_GET(string/ipintel_base)))
+ fail_messages += "Invalid query base"
+
+ if (!CONFIG_GET(flag/sql_enabled))
+ fail_messages += "The database is not enabled"
+
if(length(fail_messages))
message_admins("IPIntel: Initialization failed check logs!")
- logger.Log(LOG_CATEGORY_GAME_ACCESS, "IPIntel failed to initialize.", list(
+ logger.Log(LOG_CATEGORY_GAME_ACCESS, "IPIntel is not enabled because the configs are not valid.", list(
"fail_messages" = fail_messages,
))
- return SS_INIT_FAILURE
-
- return SS_INIT_SUCCESS
/datum/controller/subsystem/ipintel/stat_entry(msg)
- return "[..()] | D: [max_queries_per_day - rate_limits[IPINTEL_RATE_LIMIT_DAY]] | M: [max_queries_per_minute - rate_limits[IPINTEL_RATE_LIMIT_MINUTE]]"
+ return "[..()] | M: [CONFIG_GET(number/ipintel_rate_minute) - rate_limit_minute]"
+
+
+/datum/controller/subsystem/ipintel/proc/is_enabled()
+ return length(CONFIG_GET(string/ipintel_email)) && length(CONFIG_GET(string/ipintel_base)) && CONFIG_GET(flag/sql_enabled)
/datum/controller/subsystem/ipintel/proc/get_address_intel_state(address, probability_override)
+ if (!is_enabled())
+ return IPINTEL_GOOD_IP
var/datum/ip_intel/intel = query_address(address)
if(isnull(intel))
stack_trace("query_address did not return an ip intel response")
@@ -81,7 +61,7 @@ SUBSYSTEM_DEF(ipintel)
if(!(intel.query_status in list("success", "cached")))
return IPINTEL_UNKNOWN_QUERY_ERROR
- var/check_probability = probability_override || probability_threshold
+ var/check_probability = probability_override || CONFIG_GET(number/ipintel_rating_bad)
if(intel.result >= check_probability)
return IPINTEL_BAD_IP
return IPINTEL_GOOD_IP
@@ -92,34 +72,32 @@ SUBSYSTEM_DEF(ipintel)
if(minute_key != expected_minute_key)
minute_key = expected_minute_key
- rate_limits[IPINTEL_RATE_LIMIT_MINUTE] = 0
+ rate_limit_minute = 0
- if(rate_limits[IPINTEL_RATE_LIMIT_MINUTE] >= max_queries_per_minute)
+ if(rate_limit_minute >= CONFIG_GET(number/ipintel_rate_minute))
return IPINTEL_RATE_LIMITED_MINUTE
- if(rate_limits[IPINTEL_RATE_LIMIT_DAY] >= max_queries_per_day)
- return IPINTEL_RATE_LIMITED_DAY
return FALSE
/datum/controller/subsystem/ipintel/proc/query_address(address, allow_cached = TRUE)
+ if (!is_enabled())
+ return
if(allow_cached && fetch_cached_ip_intel(address))
return cached_queries[address]
var/is_rate_limited = is_rate_limited()
if(is_rate_limited)
return is_rate_limited
- if(!initialized)
- return IPINTEL_UNKNOWN_INTERNAL_ERROR
-
- rate_limits[IPINTEL_RATE_LIMIT_MINUTE] += 1
- rate_limits[IPINTEL_RATE_LIMIT_DAY] += 1
+ rate_limit_minute += 1
- var/query_base = "https://[src.query_base]/check.php?ip="
- var/query = "[query_base][address]&contact=[contact_email]&flags=b&format=json"
+ var/query_base = "https://[CONFIG_GET(string/ipintel_base)]/check.php?ip="
+ var/query = "[query_base][address]&contact=[CONFIG_GET(string/ipintel_email)]&flags=b&format=json"
var/datum/http_request/request = new
request.prepare(RUSTG_HTTP_METHOD_GET, query)
request.execute_blocking()
var/datum/http_response/response = request.into_response()
- var/list/data = response.body
+ var/list/data = json_decode(response.body)
+ // Log the response
+ logger.Log(LOG_CATEGORY_DEBUG, "ip check response body", data)
var/datum/ip_intel/intel = new
intel.query_status = data["status"]
@@ -133,6 +111,9 @@ SUBSYSTEM_DEF(ipintel)
return intel
/datum/controller/subsystem/ipintel/proc/add_intel_to_database(datum/ip_intel/intel)
+ set waitfor = FALSE //no need to make the client connection wait for this step.
+ if (!SSdbcore.Connect())
+ return
var/datum/db_query/query = SSdbcore.NewQuery(
"INSERT INTO [format_table_name("ipintel")] ( \
ip, \
@@ -150,13 +131,17 @@ SUBSYSTEM_DEF(ipintel)
qdel(query)
/datum/controller/subsystem/ipintel/proc/fetch_cached_ip_intel(address)
- var/date_restrictor
- if(ipintel_cache_length > 0)
- date_restrictor = " AND date > DATE_SUB(NOW(), INTERVAL [ipintel_cache_length] DAY)"
+ if (!SSdbcore.Connect())
+ return
+ var/ipintel_cache_length = CONFIG_GET(number/ipintel_cache_length)
+ var/date_restrictor = ""
+ var/sql_args = list("address" = address)
+ if(ipintel_cache_length > 1)
+ date_restrictor = " AND date > DATE_SUB(NOW(), INTERVAL :ipintel_cache_length DAY)"
+ sql_args["ipintel_cache_length"] = ipintel_cache_length
var/datum/db_query/query = SSdbcore.NewQuery(
- "SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:address)[date_restrictor]", list(
- "address" = address
- )
+ "SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:address)[date_restrictor]",
+ sql_args
)
query.warn_execute()
query.sync()
@@ -178,6 +163,9 @@ SUBSYSTEM_DEF(ipintel)
return TRUE
/datum/controller/subsystem/ipintel/proc/is_exempt(client/player)
+ if(player.holder || GLOB.deadmins[player.ckey])
+ return TRUE
+ var/exempt_living_playtime = CONFIG_GET(number/ipintel_exempt_playtime_living)
if(exempt_living_playtime > 0)
var/list/play_records = player.prefs.exp
if (!play_records.len)
@@ -199,9 +187,13 @@ SUBSYSTEM_DEF(ipintel)
qdel(query)
return FALSE
query.NextRow()
- return !!query.item // if they have a row, they are whitelisted
+ . = !!query.item // if they have a row, they are whitelisted
+ qdel(query)
+
ADMIN_VERB(ipintel_allow, R_BAN, "Whitelist Player VPN", "Allow a player to connect even if they are using a VPN.", ADMIN_CATEGORY_IPINTEL, ckey as text)
+ if (!SSipintel.is_enabled())
+ to_chat(user, "The ipintel system is not currently enabled but you can still edit the whitelists")
if(SSipintel.is_whitelisted(ckey))
to_chat(user, "Player is already whitelisted.")
return
@@ -224,6 +216,8 @@ ADMIN_VERB(ipintel_allow, R_BAN, "Whitelist Player VPN", "Allow a player to conn
message_admins("IPINTEL: [key_name_admin(user)] has whitelisted '[ckey]'")
ADMIN_VERB(ipintel_revoke, R_BAN, "Revoke Player VPN Whitelist", "Revoke a player's VPN whitelist.", ADMIN_CATEGORY_IPINTEL, ckey as text)
+ if (!SSipintel.is_enabled())
+ to_chat(user, "The ipintel system is not currently enabled but you can still edit the whitelists")
if(!SSipintel.is_whitelisted(ckey))
to_chat(user, "Player is not whitelisted.")
return
@@ -238,6 +232,8 @@ ADMIN_VERB(ipintel_revoke, R_BAN, "Revoke Player VPN Whitelist", "Revoke a playe
message_admins("IPINTEL: [key_name_admin(user)] has revoked the VPN whitelist for '[ckey]'")
/client/proc/check_ip_intel()
+ if (!SSipintel.is_enabled())
+ return
if(SSipintel.is_exempt(src) || SSipintel.is_whitelisted(ckey))
return
@@ -275,7 +271,7 @@ ADMIN_VERB(ipintel_revoke, R_BAN, "Revoke Player VPN Whitelist", "Revoke a playe
if(!connection_rejected)
return
-
+
var/list/contact_where = list()
var/forum_url = CONFIG_GET(string/forumurl)
if(forum_url)
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index 2c8c63579e2f5..8e51fa917f4da 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -502,7 +502,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
"[key_name(src)] (IP: [address], ID: [computer_id]) is a new BYOND account [account_age] day[(account_age == 1?"":"s")] old, created on [account_join_date].[new_player_alert_role ? " <@&[new_player_alert_role]>" : ""]"
)
scream_about_watchlists(src)
- check_ip_intel()
validate_key_in_db()
// If we aren't already generating a ban cache, fire off a build request
// This way hopefully any users of request_ban_cache will never need to yield
@@ -532,6 +531,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
to_chat(src, span_warning("Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you."))
update_ambience_pref()
+ check_ip_intel()
//This is down here because of the browse() calls in tooltip/New()
if(!tooltips)
From d176704f2b676fd6d7a1121942369f4c14275931 Mon Sep 17 00:00:00 2001
From: Zephyr <12817816+ZephyrTFA@users.noreply.github.com>
Date: Fri, 3 May 2024 15:37:04 -0400
Subject: [PATCH 58/87] text2num moment for ipintel (#83032)
---
code/controllers/subsystem/ipintel.dm | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm
index 9bbaf320139d5..0f162e2a8616f 100644
--- a/code/controllers/subsystem/ipintel.dm
+++ b/code/controllers/subsystem/ipintel.dm
@@ -20,21 +20,21 @@ SUBSYSTEM_DEF(ipintel)
/datum/controller/subsystem/ipintel/OnConfigLoad()
var/list/fail_messages = list()
-
+
var/contact_email = CONFIG_GET(string/ipintel_email)
-
+
if(!length(contact_email))
fail_messages += "No contact email"
-
+
if(!findtext(contact_email, "@"))
fail_messages += "Invalid contact email"
if(!length(CONFIG_GET(string/ipintel_base)))
fail_messages += "Invalid query base"
-
+
if (!CONFIG_GET(flag/sql_enabled))
fail_messages += "The database is not enabled"
-
+
if(length(fail_messages))
message_admins("IPIntel: Initialization failed check logs!")
logger.Log(LOG_CATEGORY_GAME_ACCESS, "IPIntel is not enabled because the configs are not valid.", list(
@@ -104,6 +104,8 @@ SUBSYSTEM_DEF(ipintel)
if(intel.query_status != "success")
return intel
intel.result = data["result"]
+ if(istext(intel.result))
+ intel.result = text2num(intel.result)
intel.date = SQLtime()
intel.address = address
cached_queries[address] = intel
@@ -140,7 +142,7 @@ SUBSYSTEM_DEF(ipintel)
date_restrictor = " AND date > DATE_SUB(NOW(), INTERVAL :ipintel_cache_length DAY)"
sql_args["ipintel_cache_length"] = ipintel_cache_length
var/datum/db_query/query = SSdbcore.NewQuery(
- "SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:address)[date_restrictor]",
+ "SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON(:address)[date_restrictor]",
sql_args
)
query.warn_execute()
@@ -158,6 +160,8 @@ SUBSYSTEM_DEF(ipintel)
var/datum/ip_intel/intel = new
intel.query_status = "cached"
intel.result = data["intel"]
+ if(istext(intel.result))
+ intel.result = text2num(intel.result)
intel.date = data["date"]
intel.address = address
return TRUE
@@ -189,7 +193,7 @@ SUBSYSTEM_DEF(ipintel)
query.NextRow()
. = !!query.item // if they have a row, they are whitelisted
qdel(query)
-
+
ADMIN_VERB(ipintel_allow, R_BAN, "Whitelist Player VPN", "Allow a player to connect even if they are using a VPN.", ADMIN_CATEGORY_IPINTEL, ckey as text)
if (!SSipintel.is_enabled())
@@ -271,7 +275,7 @@ ADMIN_VERB(ipintel_revoke, R_BAN, "Revoke Player VPN Whitelist", "Revoke a playe
if(!connection_rejected)
return
-
+
var/list/contact_where = list()
var/forum_url = CONFIG_GET(string/forumurl)
if(forum_url)
From 7ca738d168eaf341d215994e77b2e9650d9cdfc3 Mon Sep 17 00:00:00 2001
From: AnturK
Date: Fri, 3 May 2024 21:37:38 +0200
Subject: [PATCH 59/87] Fixes CI not checking warnings. (#83015)
Yeah.
---
.github/workflows/run_integration_tests.yml | 2 +-
tools/build/build.js | 2 +-
tools/build/lib/byond.js | 20 ++++++++++++++------
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml
index 42954b571b6cc..90233292ecb4c 100644
--- a/.github/workflows/run_integration_tests.yml
+++ b/.github/workflows/run_integration_tests.yml
@@ -57,7 +57,7 @@ jobs:
run: |
bash tools/ci/install_byond.sh
source $HOME/BYOND/byond/bin/byondsetup
- tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -WError -NWTG0001
+ tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -Werror -ITG0001 -I"loop_checks"
- name: Run Tests
run: |
source $HOME/BYOND/byond/bin/byondsetup
diff --git a/tools/build/build.js b/tools/build/build.js
index d8207e55310d3..8362e88e7abd9 100644
--- a/tools/build/build.js
+++ b/tools/build/build.js
@@ -86,7 +86,7 @@ export const WarningParameter = new Juke.Parameter({
export const NoWarningParameter = new Juke.Parameter({
type: 'string[]',
- alias: 'NW',
+ alias: 'I',
});
export const CutterTarget = new Juke.Target({
diff --git a/tools/build/lib/byond.js b/tools/build/lib/byond.js
index e4809e3e9a7a7..8b6abcf8fe831 100644
--- a/tools/build/lib/byond.js
+++ b/tools/build/lib/byond.js
@@ -166,13 +166,21 @@ export const DreamMaker = async (dmeFile, options = {}) => {
await testDmVersion(dmPath);
testOutputFile(`${dmeBaseName}.dmb`);
testOutputFile(`${dmeBaseName}.rsc`);
+
const runWithWarningChecks = async (dmPath, args) => {
const execReturn = await Juke.exec(dmPath, args);
- const ignoredWarningCodes = options.ignoreWarningCodes ?? [];
- const reg = ignoredWarningCodes.length > 0 ? new RegExp(`\d+:warning: (?!(${ignoredWarningCodes.join('|')}))`) : /\d+:warning: /;
- if (options.warningsAsErrors && execReturn.combined.match(reg)) {
- Juke.logger.error(`Compile warnings treated as errors`);
- throw new Juke.ExitCode(2);
+ if(options.warningsAsErrors){
+ const ignoredWarningCodes = options.ignoreWarningCodes ?? [];
+ if(ignoredWarningCodes.length > 0 ){
+ Juke.logger.info('Ignored warning codes:', ignoredWarningCodes.join(', '));
+ }
+ const base_regex = '\\d+:warning( \\([a-z_]*\\))?:'
+ const with_ignores = `\\d+:warning( \\([a-z_]*\\))?:(?!(${ignoredWarningCodes.map(x => `.*${x}.*$`).join('|')}))`
+ const reg = ignoredWarningCodes.length > 0 ? new RegExp(with_ignores, "m") : new RegExp(base_regex,"m")
+ if (options.warningsAsErrors && execReturn.combined.match(reg)) {
+ Juke.logger.error(`Compile warnings treated as errors`);
+ throw new Juke.ExitCode(2);
+ }
}
return execReturn;
}
@@ -180,8 +188,8 @@ export const DreamMaker = async (dmeFile, options = {}) => {
const { defines } = options;
if (defines && defines.length > 0) {
Juke.logger.info('Using defines:', defines.join(', '));
-
}
+
await runWithWarningChecks(dmPath, [...defines.map(def => `-D${def}`), dmeFile]);
};
From 28540f275beaece0e51c1772bad358639017e894 Mon Sep 17 00:00:00 2001
From: Profakos
Date: Fri, 3 May 2024 22:10:10 +0200
Subject: [PATCH 60/87] Bepis techs can be found in bitrunning crates, removed
from vendors (#82872)
## About The Pull Request
This PR adds Bepis disks to the main rewards of the Bitrunning crate in
addition to the minerals and domain specific rewards. It also removes it
from the Bepis vending machine.
Once per domain, if its difficult was Medium or higher, and the
completion score was A or S, and if there are still any leftover locked
Bepis tech nodes, a Bepis disk will spawn.
Original PR text
If domain has a reward value greater than one, it has 10% chance per
reward value to drop. No disk is gained if they ran out of techs to
unlock. Most of the domains have a reward value of three, so by the law
of great numbers they probably get one disk per every three domains run,
which should be one disk every 20-30 minutes. At least, if I am correct
that domain runs take about five to ten minutes, and the server cooldown
is three minutes. If I am incorrect, I can edit the drop chance as
needed, of course.
Edit: As I have underestimated how fast Bitrunners can be, I have
decreased the chance to be 5% per reward tier.
## Why It's Good For The Game
- Bepis disks are expensive, and bitrunners need to spend almost all
their NP on gear and abilities
- Downloading secret research data, is flavourful, fitting for invading
the forgotten nooks of cyberspace.
- This will allow Bepis tech to be actually used in rounds
## Changelog
:cl:
balance: Bitrunners can now earn Bepis disks, once per medium domain or
above, if they scored at least an A.
del: Bitrunners can not buy Bepis disks from their vendors.
/:cl:
---
code/modules/bitrunning/orders/bepis.dm | 4 --
code/modules/bitrunning/server/loot.dm | 54 ++++++++++++++-----
.../virtual_domain/virtual_domain.dm | 2 +
3 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/code/modules/bitrunning/orders/bepis.dm b/code/modules/bitrunning/orders/bepis.dm
index 286e9817f3c52..4b7253bdaf24a 100644
--- a/code/modules/bitrunning/orders/bepis.dm
+++ b/code/modules/bitrunning/orders/bepis.dm
@@ -17,7 +17,3 @@
/datum/orderable_item/bepis/sprayoncan
item_path = /obj/item/toy/sprayoncan
cost_per_order = 750
-
-/datum/orderable_item/bepis/pristine
- item_path = /obj/item/disk/design_disk/bepis/remove_tech
- cost_per_order = 1000
diff --git a/code/modules/bitrunning/server/loot.dm b/code/modules/bitrunning/server/loot.dm
index cb4902abfe3ab..aa7b99d6e922a 100644
--- a/code/modules/bitrunning/server/loot.dm
+++ b/code/modules/bitrunning/server/loot.dm
@@ -1,3 +1,9 @@
+#define GRADE_D "D"
+#define GRADE_C "C"
+#define GRADE_B "B"
+#define GRADE_A "A"
+#define GRADE_S "S"
+
/// Handles calculating rewards based on number of players, parts, threats, etc
/obj/machinery/quantum_server/proc/calculate_rewards()
var/rewards_base = 0.8
@@ -28,8 +34,11 @@
var/bonus = calculate_rewards()
+ var/time_difference = world.time - generated_domain.start_time
+ var/grade = grade_completion(time_difference)
+
var/obj/item/paper/certificate = new()
- certificate.add_raw_text(get_completion_certificate())
+ certificate.add_raw_text(get_completion_certificate(time_difference, grade))
certificate.name = "certificate of domain completion"
certificate.update_appearance()
@@ -37,6 +46,10 @@
reward_cache.manifest = certificate
reward_cache.update_appearance()
+ if(can_generate_tech_disk(grade))
+ new /obj/item/disk/design_disk/bepis/remove_tech(reward_cache)
+ generated_domain.disk_reward_spawned = TRUE
+
chosen_forge.start_to_spawn(reward_cache)
return TRUE
@@ -50,7 +63,7 @@
return TRUE
/// Returns the markdown text containing domain completion information
-/obj/machinery/quantum_server/proc/get_completion_certificate()
+/obj/machinery/quantum_server/proc/get_completion_certificate(time_difference, grade)
var/base_points = generated_domain.reward_points
if(domain_randomized)
base_points -= 1
@@ -59,11 +72,9 @@
var/domain_threats = length(spawned_threat_refs)
- var/time_difference = world.time - generated_domain.start_time
-
var/completion_time = "### Completion Time: [DisplayTimeText(time_difference)]\n"
- var/grade = "\n---\n\n# Rating: [grade_completion(time_difference)]"
+ var/completion_grade = "\n---\n\n# Rating: [grade]"
var/text = "# Certificate of Domain Completion\n\n---\n\n"
@@ -75,7 +86,7 @@
if(bonuses <= 1)
text += completion_time
- text += grade
+ text += completion_grade
return text
text += "### Bonuses\n"
@@ -94,10 +105,24 @@
text += "- **Components:** + [servo_rating]\n"
text += completion_time
- text += grade
+ text += completion_grade
return text
+/// Checks if the players should get a bepis reward
+/obj/machinery/quantum_server/proc/can_generate_tech_disk(grade)
+ if(generated_domain.disk_reward_spawned)
+ return FALSE
+
+ if(!LAZYLEN(SSresearch.techweb_nodes_experimental))
+ return FALSE
+
+ var/static/list/passing_grades = list()
+ if(!passing_grades.len)
+ passing_grades = list(GRADE_A,GRADE_S)
+
+ return generated_domain.difficulty >= BITRUNNER_DIFFICULTY_MEDIUM && (grade in passing_grades)
+
/// Grades the player's run based on several factors
/obj/machinery/quantum_server/proc/grade_completion(completion_time)
var/score = length(spawned_threat_refs) * 5
@@ -124,13 +149,18 @@
switch(score)
if(1 to 4)
- return "D"
+ return GRADE_D
if(5 to 7)
- return "C"
+ return GRADE_C
if(8 to 10)
- return "B"
+ return GRADE_B
if(11 to 13)
- return "A"
+ return GRADE_A
else
- return "S"
+ return GRADE_S
+#undef GRADE_D
+#undef GRADE_C
+#undef GRADE_B
+#undef GRADE_A
+#undef GRADE_S
diff --git a/code/modules/bitrunning/virtual_domain/virtual_domain.dm b/code/modules/bitrunning/virtual_domain/virtual_domain.dm
index b316bb97cae1e..21898daad72d7 100644
--- a/code/modules/bitrunning/virtual_domain/virtual_domain.dm
+++ b/code/modules/bitrunning/virtual_domain/virtual_domain.dm
@@ -44,6 +44,8 @@
var/start_time
/// This map is specifically for unit tests. Shouldn't display in game
var/test_only = FALSE
+ /// Has this domain been beaten with high enough score to spawn a tech disk?
+ var/disk_reward_spawned = FALSE
/// Sends a point to any loot signals on the map
/datum/lazy_template/virtual_domain/proc/add_points(points_to_add)
From 0ca5dcb61b2ab41bb051b391adedfcf430923d70 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sat, 4 May 2024 08:10:39 +1200
Subject: [PATCH 61/87] Automatic changelog for PR #82872 [ci skip]
---
html/changelogs/AutoChangeLog-pr-82872.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-82872.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82872.yml b/html/changelogs/AutoChangeLog-pr-82872.yml
new file mode 100644
index 0000000000000..8df2569edf5ba
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-82872.yml
@@ -0,0 +1,5 @@
+author: "Profakos"
+delete-after: True
+changes:
+ - balance: "Bitrunners can now earn Bepis disks, once per medium domain or above, if they scored at least an A."
+ - rscdel: "Bitrunners can not buy Bepis disks from their vendors."
\ No newline at end of file
From cc1df2405ee0ffb14b9e877beaf0d5baf5f2888a Mon Sep 17 00:00:00 2001
From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
Date: Fri, 3 May 2024 20:15:35 +0000
Subject: [PATCH 62/87] Fixes lua breaking when registering signals on turfs
(#83018)
## About The Pull Request
Signals don't get removed on turfs when they're deleted. This fixes that
so that it is reflected in lua as well.
## Why It's Good For The Game
Lua bugfixes
## Changelog
:cl:
fix: Fixed lua scripts breaking when turfs with registered signals get
deleted.
/:cl:
---------
Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
---
lua/SS13_base.lua | 8 +++++++-
lua/handler_group.lua | 2 +-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/lua/SS13_base.lua b/lua/SS13_base.lua
index f49908f094261..ea04c8c6503dd 100644
--- a/lua/SS13_base.lua
+++ b/lua/SS13_base.lua
@@ -100,7 +100,8 @@ function SS13.register_signal(datum, signal, func)
callback:call_proc("RegisterSignal", datum, signal, "Invoke")
local path = { "__SS13_signal_handlers", datumWeakRef, signal, callbackWeakRef, "func" }
callback.vars.arguments = { path }
- if not __SS13_signal_handlers[datumWeakRef]._cleanup then
+ -- Turfs don't remove their signals on deletion.
+ if not __SS13_signal_handlers[datumWeakRef]._cleanup and not SS13.istype(datum, "/turf") then
local cleanupCallback = SS13.new("/datum/callback", SS13.state, "call_function_return_first")
local cleanupPath = { "__SS13_signal_handlers", datumWeakRef, "_cleanup"}
cleanupCallback.vars.arguments = { cleanupPath }
@@ -134,6 +135,11 @@ function SS13.unregister_signal(datum, signal, callback)
local callbackWeakRef = dm.global_proc("WEAKREF", handler_callback)
if not SS13.istype(datum, "/datum/weakref") then
handler_callback:call_proc("UnregisterSignal", datum, signal)
+ else
+ local actualDatum = datum:call_proc("hard_resolve")
+ if SS13.is_valid(actualDatum) then
+ handler_callback:call_proc("UnregisterSignal", actualDatum, signal)
+ end
end
SS13.stop_tracking(handler_callback)
end
diff --git a/lua/handler_group.lua b/lua/handler_group.lua
index fff63ad18e427..0246d33c74488 100644
--- a/lua/handler_group.lua
+++ b/lua/handler_group.lua
@@ -14,7 +14,7 @@ function HandlerGroup:register_signal(datum, signal, func)
if not callback then
return
end
- table.insert(self.registered, { datum = datum, signal = signal, callback = callback })
+ table.insert(self.registered, { datum = dm.global_proc("WEAKREF", datum), signal = signal, callback = callback })
end
-- Clears all the signals that have been registered on this HandlerGroup
From fdbd2b8480f75945d718baf57dabac9622d8ed71 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sat, 4 May 2024 08:15:54 +1200
Subject: [PATCH 63/87] Automatic changelog for PR #83018 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83018.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83018.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83018.yml b/html/changelogs/AutoChangeLog-pr-83018.yml
new file mode 100644
index 0000000000000..d8692ba435c6e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83018.yml
@@ -0,0 +1,4 @@
+author: "Watermelon914"
+delete-after: True
+changes:
+ - bugfix: "Fixed lua scripts breaking when turfs with registered signals get deleted."
\ No newline at end of file
From 053ae55c3a07ff628223f6b5473f3f5ef787ae55 Mon Sep 17 00:00:00 2001
From: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Date: Fri, 3 May 2024 17:12:26 -0700
Subject: [PATCH 64/87] Adds debug dna disk to runtimestation (#83013)
## About The Pull Request
Title || Puts it next to the dna scanner
## Why It's Good For The Game
Easier debugging genetics / dna ui
---
_maps/map_files/debug/runtimestation.dmm | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm
index 1c5a88860bea5..584ba1eb7ee9d 100644
--- a/_maps/map_files/debug/runtimestation.dmm
+++ b/_maps/map_files/debug/runtimestation.dmm
@@ -683,6 +683,10 @@
/obj/effect/turf_decal/tile/blue{
dir = 8
},
+/obj/item/disk/data/debug{
+ pixel_y = 9;
+ pixel_x = 7
+ },
/turf/open/floor/iron/white/corner,
/area/station/medical/medbay)
"cL" = (
From 89c711a3ac9172dc84e6608491ad340bc96d5d5c Mon Sep 17 00:00:00 2001
From: Changelogs
Date: Sat, 4 May 2024 00:20:12 +0000
Subject: [PATCH 65/87] Automatic changelog compile [ci skip]
---
html/changelogs/AutoChangeLog-pr-82833.yml | 4 ---
html/changelogs/AutoChangeLog-pr-82872.yml | 5 ----
html/changelogs/AutoChangeLog-pr-82945.yml | 4 ---
html/changelogs/AutoChangeLog-pr-82992.yml | 4 ---
html/changelogs/AutoChangeLog-pr-82996.yml | 4 ---
html/changelogs/AutoChangeLog-pr-82998.yml | 6 -----
html/changelogs/AutoChangeLog-pr-83002.yml | 4 ---
html/changelogs/AutoChangeLog-pr-83004.yml | 4 ---
html/changelogs/AutoChangeLog-pr-83005.yml | 4 ---
html/changelogs/AutoChangeLog-pr-83014.yml | 4 ---
html/changelogs/AutoChangeLog-pr-83018.yml | 4 ---
html/changelogs/archive/2024-05.yml | 30 ++++++++++++++++++++++
12 files changed, 30 insertions(+), 47 deletions(-)
delete mode 100644 html/changelogs/AutoChangeLog-pr-82833.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-82872.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-82945.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-82992.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-82996.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-82998.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83002.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83004.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83005.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83014.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83018.yml
diff --git a/html/changelogs/AutoChangeLog-pr-82833.yml b/html/changelogs/AutoChangeLog-pr-82833.yml
deleted file mode 100644
index b9e08edc7e89e..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82833.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Xander3359"
-delete-after: True
-changes:
- - bugfix: "You can no longer bypass construction restrictions via the crafting menu"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-82872.yml b/html/changelogs/AutoChangeLog-pr-82872.yml
deleted file mode 100644
index 8df2569edf5ba..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82872.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Profakos"
-delete-after: True
-changes:
- - balance: "Bitrunners can now earn Bepis disks, once per medium domain or above, if they scored at least an A."
- - rscdel: "Bitrunners can not buy Bepis disks from their vendors."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-82945.yml b/html/changelogs/AutoChangeLog-pr-82945.yml
deleted file mode 100644
index a1485366ae2f4..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82945.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ghommie"
-delete-after: True
-changes:
- - rscadd: "Adds an Icebox-specific station trait that brightens outdoors areas on the surface level."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-82992.yml b/html/changelogs/AutoChangeLog-pr-82992.yml
deleted file mode 100644
index eb03652dc1470..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82992.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ryll/Shaps"
-delete-after: True
-changes:
- - bugfix: "Pacifists can no longer endlessly spam the backblast functionality of loaded rocket launchers that they cannot actually fire"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-82996.yml b/html/changelogs/AutoChangeLog-pr-82996.yml
deleted file mode 100644
index fada9ce1d19f1..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82996.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "mogeoko"
-delete-after: True
-changes:
- - bugfix: "Ventcrawling mobs can change Z-level using multiz-decks again."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-82998.yml b/html/changelogs/AutoChangeLog-pr-82998.yml
deleted file mode 100644
index 696b730fca1ee..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-82998.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "Ben10Omintrix"
-delete-after: True
-changes:
- - bugfix: "mobs in the same faction will no longer be at odds against one another"
- - bugfix: "mobs can now perform behaviors alongside searching for targets"
- - bugfix: "mobs will no longer be starting and stopping when chasing targets"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83002.yml b/html/changelogs/AutoChangeLog-pr-83002.yml
deleted file mode 100644
index 114603f123725..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83002.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "cnleth"
-delete-after: True
-changes:
- - bugfix: "Fire ant colonies created by burning regular ants will now contain fire ants as their reagent"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83004.yml b/html/changelogs/AutoChangeLog-pr-83004.yml
deleted file mode 100644
index c763ac3aa9594..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83004.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "jlsnow301"
-delete-after: True
-changes:
- - bugfix: "Candy corn is once again available to detective fedoras"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83005.yml b/html/changelogs/AutoChangeLog-pr-83005.yml
deleted file mode 100644
index be13b5786e78c..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83005.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ikalpo"
-delete-after: True
-changes:
- - bugfix: "Stage 2 singularities should no longer escape containment"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83014.yml b/html/changelogs/AutoChangeLog-pr-83014.yml
deleted file mode 100644
index ebd44714a49a6..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83014.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Melbert"
-delete-after: True
-changes:
- - bugfix: "New machine god blessings now actually works probably"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83018.yml b/html/changelogs/AutoChangeLog-pr-83018.yml
deleted file mode 100644
index d8692ba435c6e..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83018.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Watermelon914"
-delete-after: True
-changes:
- - bugfix: "Fixed lua scripts breaking when turfs with registered signals get deleted."
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml
index 8e615e3cb43ed..304b3ad1b73f3 100644
--- a/html/changelogs/archive/2024-05.yml
+++ b/html/changelogs/archive/2024-05.yml
@@ -90,3 +90,33 @@
- balance: weighted some of the implants that Machine Blessing can give
mc-oofert:
- image: added directional sprites for radiation shutters
+2024-05-04:
+ Ben10Omintrix:
+ - bugfix: mobs in the same faction will no longer be at odds against one another
+ - bugfix: mobs can now perform behaviors alongside searching for targets
+ - bugfix: mobs will no longer be starting and stopping when chasing targets
+ Ghommie:
+ - rscadd: Adds an Icebox-specific station trait that brightens outdoors areas on
+ the surface level.
+ Ikalpo:
+ - bugfix: Stage 2 singularities should no longer escape containment
+ Melbert:
+ - bugfix: New machine god blessings now actually works probably
+ Profakos:
+ - balance: Bitrunners can now earn Bepis disks, once per medium domain or above,
+ if they scored at least an A.
+ - rscdel: Bitrunners can not buy Bepis disks from their vendors.
+ Ryll/Shaps:
+ - bugfix: Pacifists can no longer endlessly spam the backblast functionality of
+ loaded rocket launchers that they cannot actually fire
+ Watermelon914:
+ - bugfix: Fixed lua scripts breaking when turfs with registered signals get deleted.
+ Xander3359:
+ - bugfix: You can no longer bypass construction restrictions via the crafting menu
+ cnleth:
+ - bugfix: Fire ant colonies created by burning regular ants will now contain fire
+ ants as their reagent
+ jlsnow301:
+ - bugfix: Candy corn is once again available to detective fedoras
+ mogeoko:
+ - bugfix: Ventcrawling mobs can change Z-level using multiz-decks again.
From b8af2429c816262f64189d7796110ff75b4620b3 Mon Sep 17 00:00:00 2001
From: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Date: Sat, 4 May 2024 13:16:04 -0500
Subject: [PATCH 66/87] Fix vote `can_be_initiated` mutating the active choices
(#83029)
## About The Pull Request
Closes #83020
This proc, called *every single ui_data tick*, was mutating the vote's
list of choices. Grahhh impure procs grahhh
https://github.com/tgstation/tgstation/blob/f112369547a7da6fdafd69c1d43baf0fc6f76f77/code/datums/votes/map_vote.dm#L57-L60
Weirdly, I have no idea how this *ever* worked, even prior to my PR,
because I didn't touch this or any consuming code. It was called in the
same place, same args, etc. prior to my PR. So I have no idea.
## Changelog
:cl: Melbert
fix: Map vote should work better
/:cl:
---
code/datums/votes/map_vote.dm | 45 +++++++++++++++++++----------------
1 file changed, 24 insertions(+), 21 deletions(-)
diff --git a/code/datums/votes/map_vote.dm b/code/datums/votes/map_vote.dm
index 9b149e812795d..abe452ce4fedf 100644
--- a/code/datums/votes/map_vote.dm
+++ b/code/datums/votes/map_vote.dm
@@ -21,15 +21,23 @@
/datum/vote/map_vote/create_vote()
. = ..()
- check_population(should_key_choices = FALSE)
+ if(!.)
+ return FALSE
+
+ choices -= get_choices_invalid_for_population()
if(length(choices) == 1) // Only one choice, no need to vote. Let's just auto-rotate it to the only remaining map because it would just happen anyways.
- var/de_facto_winner = choices[1]
- var/datum/map_config/change_me_out = global.config.maplist[de_facto_winner]
- SSmapping.changemap(change_me_out)
- to_chat(world, span_boldannounce("The map vote has been skipped because there is only one map left to vote for. The map has been changed to [change_me_out.map_name]."))
- SSmapping.map_voted = TRUE // voted by not voting, very sad.
+ var/datum/map_config/change_me_out = global.config.maplist[choices[1]]
+ finalize_vote(choices[1])// voted by not voting, very sad.
+ to_chat(world, span_boldannounce("The map vote has been skipped because there is only one map left to vote for. \
+ The map has been changed to [change_me_out.map_name]."))
+ return FALSE
+ if(length(choices) == 0)
+ to_chat(world, span_boldannounce("A map vote was called, but there are no maps to vote for! \
+ Players, complain to the admins. Admins, complain to the coders."))
return FALSE
+ return TRUE
+
/datum/vote/map_vote/toggle_votable()
CONFIG_SET(flag/allow_vote_map, !CONFIG_GET(flag/allow_vote_map))
@@ -42,38 +50,33 @@
return .
if(forced)
return VOTE_AVAILABLE
- var/number_of_choices = length(check_population())
- if(number_of_choices < 2)
- return "There [number_of_choices == 1 ? "is only one map" : "are no maps"] to choose from."
+ var/num_choices = length(default_choices - get_choices_invalid_for_population())
+ if(num_choices <= 1)
+ return "There [num_choices == 1 ? "is only one map" : "are no maps"] to choose from."
if(SSmapping.map_vote_rocked)
return VOTE_AVAILABLE
if(SSmapping.map_voted)
return "The next map has already been selected."
return VOTE_AVAILABLE
-/// Before we create a vote, remove all maps from our choices that are outside of our population range.
-/// Note that this can result in zero remaining choices for our vote, which is not ideal (but ultimately okay).
-/// Argument should_key_choices is TRUE, pass as FALSE in a context where choices are already keyed in a list.
-/datum/vote/map_vote/proc/check_population(should_key_choices = TRUE)
- if(should_key_choices)
- for(var/key in default_choices)
- choices[key] = 0
-
+/// Returns a list of all map options that are invalid for the current population.
+/datum/vote/map_vote/proc/get_choices_invalid_for_population()
var/filter_threshold = 0
if(SSticker.HasRoundStarted())
filter_threshold = get_active_player_count(alive_check = FALSE, afk_check = TRUE, human_check = FALSE)
else
filter_threshold = GLOB.clients.len
- for(var/map in choices)
+ var/list/invalid_choices = list()
+ for(var/map in default_choices)
var/datum/map_config/possible_config = config.maplist[map]
if(possible_config.config_min_users > 0 && filter_threshold < possible_config.config_min_users)
- choices -= map
+ invalid_choices += map
else if(possible_config.config_max_users > 0 && filter_threshold > possible_config.config_max_users)
- choices -= map
+ invalid_choices += map
- return choices
+ return invalid_choices
/datum/vote/map_vote/get_vote_result(list/non_voters)
// Even if we have default no vote off,
From dcc2718a122294a123f73bf6a267c1f73ab0a301 Mon Sep 17 00:00:00 2001
From: Isratosh
Date: Sat, 4 May 2024 12:16:17 -0600
Subject: [PATCH 67/87] Cargo scanner no longer kidnaps people (#83026)
## About The Pull Request
Fixes #83022
The universal cargo scanner calls `sell_object(dry_run = TRUE)` to
determine the price without actually selling anything, but an early
return for this case was not included when the proc was overridden for
the `/datum/export/pirate` type, allowing anybody with a cargo scanner
to participate in illegal human trafficking.
The automatic return timer had incorrect args causing a runtime error
which I've also fixed, humans are returned after 6 minutes.
Kidnapping code desperately needs a unification because now there are 3
ways to end up in the holding facility (progression traitor kidnapping
side objective, traitor contractor, pirates) and they all have copy
pasted code but some is different for no reason. This pirate code does
not handle your belongings and you can take anything out of the holding
facility or get your stuff stolen while in there, unlike the other 2
methods which hold your belongings for safe return later.
## Why It's Good For The Game
Fixes a very funny but very lame oversight and also allows for the safe
return of our friends kidnapped by pirates.
## Changelog
:cl:
fix: If kidnapped and ransomed by pirates, you will now properly return
to the station automatically after 6 minutes.
fix: You can no longer be kidnapped and held for ransom by cargo
technicians posing as pirates.
/:cl:
---
code/modules/antagonists/pirate/pirate_shuttle_equipment.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm
index eaa1de48b5865..16cad321853d9 100644
--- a/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm
+++ b/code/modules/antagonists/pirate/pirate_shuttle_equipment.dm
@@ -428,7 +428,7 @@
/datum/export/pirate/ransom/sell_object(mob/living/carbon/human/sold_item, datum/export_report/report, dry_run = TRUE, apply_elastic = TRUE)
. = ..()
- if(. == EXPORT_NOT_SOLD)
+ if(. == EXPORT_NOT_SOLD || dry_run)
return
var/turf/picked_turf = pick(GLOB.holdingfacility)
sold_item.forceMove(picked_turf)
@@ -439,7 +439,7 @@
sold_item.flash_act()
sold_item.adjust_confusion(10 SECONDS)
sold_item.adjust_dizzy(10 SECONDS)
- addtimer(src, CALLBACK(src, PROC_REF(send_back_to_station), sold_item), COME_BACK_FROM_CAPTURE_TIME)
+ addtimer(CALLBACK(src, PROC_REF(send_back_to_station), sold_item), COME_BACK_FROM_CAPTURE_TIME)
to_chat(sold_item, span_hypnophrase("A million voices echo in your head... \"Yaarrr, thanks for the booty, landlubber. \
You will be ransomed back to your station, so it's only a matter of time before we ship you back..."))
From 02e09efb458631ebff88dc73fc618b8584e7b3b2 Mon Sep 17 00:00:00 2001
From: larentoun <31931237+larentoun@users.noreply.github.com>
Date: Sat, 4 May 2024 21:16:30 +0300
Subject: [PATCH 68/87] Fix missing crafting flags (#83025)
## About The Pull Request
fixes https://github.com/tgstation/tgstation/issues/83023
## Changelog
:cl:
fix: Materials are now correctly applied to crafted items (chairs,
toilets, etc)
/:cl:
---
code/game/objects/items/stacks/stack_recipe.dm | 1 +
1 file changed, 1 insertion(+)
diff --git a/code/game/objects/items/stacks/stack_recipe.dm b/code/game/objects/items/stacks/stack_recipe.dm
index 4a150f4f2abce..eabaa706d8879 100644
--- a/code/game/objects/items/stacks/stack_recipe.dm
+++ b/code/game/objects/items/stacks/stack_recipe.dm
@@ -47,6 +47,7 @@
src.res_amount = res_amount
src.max_res_amount = max_res_amount
src.time = time
+ src.crafting_flags = crafting_flags
src.placement_checks = placement_checks
src.trait_booster = trait_booster
src.trait_modifier = trait_modifier
From d258536686d115fd99d6d040506e4ab0faeca0ec Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sun, 5 May 2024 06:16:35 +1200
Subject: [PATCH 69/87] Automatic changelog for PR #83026 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83026.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83026.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83026.yml b/html/changelogs/AutoChangeLog-pr-83026.yml
new file mode 100644
index 0000000000000..97760a11c77da
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83026.yml
@@ -0,0 +1,5 @@
+author: "Isratosh"
+delete-after: True
+changes:
+ - bugfix: "If kidnapped and ransomed by pirates, you will now properly return to the station automatically after 6 minutes."
+ - bugfix: "You can no longer be kidnapped and held for ransom by cargo technicians posing as pirates."
\ No newline at end of file
From 6e57b94657575b151faae472ae7d80fc82bdb040 Mon Sep 17 00:00:00 2001
From: Jacquerel
Date: Sat, 4 May 2024 19:18:33 +0100
Subject: [PATCH 70/87] Blood Brothers should start with objectives (#83030)
## About The Pull Request
Fixes #82064
Fixes a couple of different bugs with Blood Brothers.
- Delegates creating the objectives to the team rather than the ruleset,
so ones created via the traitor panel will also have objectives.
- Creates the objectives after the team has a member mind, so it doesn't
runtime when trying to give that mob the equipment needed to steal a
supermatter sliver.
- Creates the objectives before the first Blood Brother is assigned the
antag datum, so that they will correctly be given the starting
objectives.
- Check the maximum number of brothers that can be recruited when
deciding how many objectives to generate rather than the current number
of members (which would always be 1).
## Changelog
:cl:
fix: Blood Brothers should spawn knowing what their objectives are.
fix: Teams of 3 Blood Brothers will once more have an additional
objective.
/:cl:
---
.../subsystem/dynamic/dynamic_rulesets_roundstart.dm | 5 +----
code/modules/antagonists/brother/brother.dm | 6 ++++--
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm b/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
index 51ecd59925a4d..1f315391a8f2c 100644
--- a/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_rulesets_roundstart.dm
@@ -135,10 +135,7 @@ GLOBAL_VAR_INIT(revolutionary_win, FALSE)
/datum/dynamic_ruleset/roundstart/traitorbro/execute()
for (var/datum/mind/mind in assigned)
- var/datum/team/brother_team/team = new
- team.add_member(mind)
- team.forge_brother_objectives()
- mind.add_antag_datum(/datum/antagonist/brother, team)
+ new /datum/team/brother_team(mind)
GLOB.pre_setup_antags -= mind
return TRUE
diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm
index 49d0ab4ad2300..ca36585a1a1c4 100644
--- a/code/modules/antagonists/brother/brother.dm
+++ b/code/modules/antagonists/brother/brother.dm
@@ -167,13 +167,15 @@
member_name = "blood brother"
var/brothers_left = 2
-/datum/team/brother_team/New()
+/datum/team/brother_team/New(starting_members)
. = ..()
if (prob(10))
brothers_left += 1
/datum/team/brother_team/add_member(datum/mind/new_member)
. = ..()
+ if (!length(objectives))
+ forge_brother_objectives()
if (!new_member.has_antag_datum(/datum/antagonist/brother))
add_brother(new_member.current)
@@ -217,7 +219,7 @@
add_objective(new /datum/objective/convert_brother)
var/is_hijacker = prob(10)
- for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
+ for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (brothers_left > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
From 0cc5cfb178eb63af939a5ceb31f18968a2baac7d Mon Sep 17 00:00:00 2001
From: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Date: Sat, 4 May 2024 13:21:26 -0500
Subject: [PATCH 71/87] Random Name Generation refactor, generate random names
based on languages (for species without name lists, like Felinids and
Podpeople) (#83021)
## About The Pull Request
This PR moves random name generation for species onto their languages.
What does this mean?
- For species with a predefined name list, such as Lizards and Moths,
nothing.
- For species without predefined name lists, such as Felinids, their
names will now be randomly generated from their language's syllables.
![image](https://github.com/tgstation/tgstation/assets/51863163/dddce7a6-5882-4f97-b817-c8922033c8d2)
![image](https://github.com/tgstation/tgstation/assets/51863163/e34e03e9-bcca-45ff-84e4-239e606cd24f)
(In the prefs menu:)
![image](https://github.com/tgstation/tgstation/assets/51863163/eb6ccf9b-8b1c-4637-b46e-66cab9c8aac0)
Why?
- Well, we actually had some dead code that did this. All I did was fix
it up and re-enable it.
- Generates some pretty believable in-universe names for various
languages that are lacking name lists. Obviously defined lists would be
preferred, but until they are added, at least.
- Moves some stuff off of species, which is always nice.
- Also hopefully makes it a tad easier to work with name generation.
There's now a standard framework for getting a random name for a mob,
and for getting a random name based on a species.
Misc:
- Adds a generic `species_prototype` global, uses it in a lot of places
in prefs code.
- Makes `GLOB.species_list` init via the global defines
- Deletes Language SS
- Alphabetizes some instances of admin tooling using the list of all
species IDs
- Docs language stuff
- Deletes random_skin_tone, it does pretty much nothin
## Changelog
:cl: Melbert
refactor: Random Name Generation has been refactored. Report any
instances of people having weird (or "Unknown") names.
qol: Felinids, Slimepeople, Podpeople, and some other species without
defined namelists now automatically generate names based on their
primary language(s).
qol: More non-human names can be generated in codewords (and other misc.
areas) than just lizard names.
/:cl:
---
code/__HELPERS/global_lists.dm | 8 -
code/__HELPERS/mobs.dm | 44 -----
code/__HELPERS/names.dm | 94 +++++++---
code/_globalvars/lists/mobs.dm | 51 +++++-
code/_globalvars/lists/names.dm | 4 +-
code/controllers/subsystem/language.dm | 17 --
code/datums/brain_damage/imaginary_friend.dm | 4 +-
.../diseases/advance/symptoms/voice_change.dm | 2 +-
code/datums/dna.dm | 10 +-
.../machinery/computer/records/security.dm | 6 +-
code/game/objects/items/cardboard_cutouts.dm | 2 +-
code/game/objects/items/debug_items.dm | 3 +-
code/game/objects/structures/headpike.dm | 2 +-
code/modules/admin/create_mob.dm | 4 +-
code/modules/admin/verbs/anonymousnames.dm | 3 +-
code/modules/admin/verbs/secrets.dm | 3 +-
.../modules/client/preferences/_preference.dm | 2 +-
code/modules/client/preferences/clothing.dm | 2 +-
code/modules/client/preferences/names.dm | 15 +-
code/modules/client/preferences/species.dm | 4 +-
.../preferences/species_features/mutants.dm | 2 +-
.../client/preferences/underwear_color.dm | 2 +-
code/modules/jobs/job_types/_job.dm | 20 ++-
code/modules/language/_language.dm | 164 ++++++++++++++++++
...language_holder.dm => _language_holder.dm} | 0
...nguage_manuals.dm => _language_manuals.dm} | 0
.../{language_menu.dm => _language_menu.dm} | 0
code/modules/language/aphasia.dm | 1 +
code/modules/language/beachbum.dm | 2 +-
code/modules/language/buzzwords.dm | 1 +
code/modules/language/calcic.dm | 12 ++
code/modules/language/codespeak.dm | 1 +
code/modules/language/common.dm | 95 +++++-----
code/modules/language/draconic.dm | 20 +++
code/modules/language/drone.dm | 1 +
code/modules/language/language.dm | 107 ------------
code/modules/language/machine.dm | 11 +-
code/modules/language/moffic.dm | 16 ++
code/modules/language/monkey.dm | 9 +
code/modules/language/mushroom.dm | 2 +
code/modules/language/nekomimetic.dm | 13 ++
code/modules/language/piratespeak.dm | 1 +
code/modules/language/shadowtongue.dm | 2 +
code/modules/language/slime.dm | 3 +-
code/modules/language/sylvan.dm | 2 +
code/modules/language/terrum.dm | 19 +-
code/modules/language/voltaic.dm | 18 ++
code/modules/language/xenocommon.dm | 1 +
code/modules/mapping/mapping_helpers.dm | 3 +-
code/modules/mob/dead/observer/observer.dm | 19 +-
.../basic/space_fauna/revenant/_revenant.dm | 6 +-
.../mob/living/carbon/human/_species.dm | 32 +---
code/modules/mob/living/carbon/human/human.dm | 4 +-
.../mob/living/carbon/human/human_helpers.dm | 2 +-
.../carbon/human/species_types/ethereal.dm | 8 -
.../carbon/human/species_types/golems.dm | 9 -
.../human/species_types/lizardpeople.dm | 12 --
.../carbon/human/species_types/monkeys.dm | 3 -
.../carbon/human/species_types/mothmen.dm | 11 --
.../carbon/human/species_types/plasmamen.dm | 11 --
code/modules/mob/living/living_say.dm | 6 +-
.../mob_spawn/ghost_roles/golem_roles.dm | 3 +-
.../mob_spawn/ghost_roles/mining_roles.dm | 6 +-
code/modules/mob_spawn/mob_spawn.dm | 2 +-
code/modules/shuttle/emergency.dm | 3 +-
code/modules/surgery/plastic_surgery.dm | 6 +-
code/modules/unit_tests/preference_species.dm | 4 +-
tgstation.dme | 9 +-
68 files changed, 532 insertions(+), 432 deletions(-)
delete mode 100644 code/controllers/subsystem/language.dm
create mode 100644 code/modules/language/_language.dm
rename code/modules/language/{language_holder.dm => _language_holder.dm} (100%)
rename code/modules/language/{language_manuals.dm => _language_manuals.dm} (100%)
rename code/modules/language/{language_menu.dm => _language_menu.dm} (100%)
delete mode 100644 code/modules/language/language.dm
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 84299fc3021fb..bd991f29d014a 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -2,13 +2,6 @@
/////Initial Building/////
//////////////////////////
-/// Inits GLOB.species_list. Not using GLOBAL_LIST_INIT b/c it depends on GLOB.string_lists
-/proc/init_species_list()
- for(var/species_path in subtypesof(/datum/species))
- var/datum/species/species = new species_path()
- GLOB.species_list[species.id] = species_path
- sort_list(GLOB.species_list, GLOBAL_PROC_REF(cmp_typepaths_asc))
-
/// Inits GLOB.surgeries
/proc/init_surgeries()
var/surgeries = list()
@@ -20,7 +13,6 @@
/// Legacy procs that really should be replaced with proper _INIT macros
/proc/make_datum_reference_lists()
// I tried to eliminate this proc but I couldn't untangle their init-order interdependencies -Dominion/Cyberboss
- init_species_list()
init_keybindings()
GLOB.emote_list = init_emote_list() // WHY DOES THIS NEED TO GO HERE? IT JUST INITS DATUMS
init_crafting_recipes()
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 9bc3beb3a1b39..084e51167eaa6 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -76,47 +76,6 @@
else
return pick(SSaccessories.facial_hairstyles_list)
-/proc/random_unique_name(gender, attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- if(gender == FEMALE)
- . = capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
- else
- . = capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
-
- if(!findname(.))
- break
-
-/proc/random_unique_lizard_name(gender, attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(lizard_name(gender))
-
- if(!findname(.))
- break
-
-/proc/random_unique_plasmaman_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(plasmaman_name())
-
- if(!findname(.))
- break
-
-/proc/random_unique_ethereal_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(ethereal_name())
-
- if(!findname(.))
- break
-
-/proc/random_unique_moth_name(attempts_to_find_unique_name=10)
- for(var/i in 1 to attempts_to_find_unique_name)
- . = capitalize(pick(GLOB.moth_first)) + " " + capitalize(pick(GLOB.moth_last))
-
- if(!findname(.))
- break
-
-/proc/random_skin_tone()
- return pick(GLOB.skin_tones)
-
GLOBAL_LIST_INIT(skin_tones, sort_list(list(
"albino",
"caucasian1",
@@ -155,9 +114,6 @@ GLOBAL_LIST_INIT(skin_tone_names, list(
"mixed4" = "Macadamia",
))
-/// An assoc list of species IDs to type paths
-GLOBAL_LIST_EMPTY(species_list)
-
/proc/age2agedescription(age)
switch(age)
if(0 to 1)
diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm
index 12c34d3a705ca..3a82c8dc1a66c 100644
--- a/code/__HELPERS/names.dm
+++ b/code/__HELPERS/names.dm
@@ -1,20 +1,75 @@
-/proc/lizard_name(gender)
- if(gender == MALE)
- return "[pick(GLOB.lizard_names_male)]-[pick(GLOB.lizard_names_male)]"
- else
- return "[pick(GLOB.lizard_names_female)]-[pick(GLOB.lizard_names_female)]"
+/**
+ * Generate a random name based off of one of the roundstart languages
+ *
+ * * gender - What gender to pick from. Picks between male, female if not provided.
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ * * list/language_weights - A list of language weights to pick from.
+ * If not provided, it will default to a list of roundstart languages, with common being the most likely.
+ */
+/proc/generate_random_name(gender, unique, list/language_weights)
+ if(isnull(language_weights))
+ language_weights = list()
+ for(var/lang_type in GLOB.uncommon_roundstart_languages)
+ language_weights[lang_type] = 1
+ language_weights[/datum/language/common] = 20
+
+ var/datum/language/picked = GLOB.language_datum_instances[pick_weight(language_weights)]
+ if(unique)
+ return picked.get_random_unique_name(gender)
+ return picked.get_random_name(gender)
+
+/**
+ * Generate a random name based off of a species
+ * This will pick a name from the species language, and avoid picking common if there are alternatives
+ *
+ * * gender - What gender to pick from. Picks between male, female if not provided.
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ * * datum/species/species_type - The species to pick from
+ * * include_all - Makes the generated name a mix of all the languages the species can speak rather than just one of them
+ * Does this on a per-name basis, IE "Lizard first name, uncommon last name".
+ */
+/proc/generate_random_name_species_based(gender, unique, datum/species/species_type, include_all = FALSE)
+ ASSERT(ispath(species_type, /datum/species))
+ var/datum/language_holder/holder = GLOB.prototype_language_holders[species_type::species_language_holder]
-/proc/ethereal_name()
- var/tempname = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
- if(prob(65))
- tempname += random_capital_letter()
- return tempname
+ var/list/languages_to_pick_from = list()
+ for(var/language in holder.spoken_languages)
+ languages_to_pick_from[language] = 1
-/proc/plasmaman_name()
- return "[pick(GLOB.plasmaman_names)] \Roman[rand(1,99)]"
+ if(length(languages_to_pick_from) >= 2)
+ // Basically, if we have alternatives, don't pick common it's boring
+ languages_to_pick_from -= /datum/language/common
-/proc/moth_name()
- return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]"
+ if(!include_all || length(languages_to_pick_from) <= 1)
+ return generate_random_name(gender, unique, languages_to_pick_from)
+
+ var/list/name_parts = list()
+ for(var/lang_type in shuffle(languages_to_pick_from))
+ name_parts += GLOB.language_datum_instances[lang_type].get_random_name(gender, name_count = 1, force_use_syllables = TRUE)
+ return jointext(name_parts, " ")
+
+/**
+ * Generates a random name for the mob based on their gender or species (for humans)
+ *
+ * * unique - If the name should be unique, IE, avoid picking names that mobs already have.
+ */
+/mob/proc/generate_random_mob_name(unique)
+ return generate_random_name_species_based(gender, unique, /datum/species/human)
+
+/mob/living/carbon/generate_random_mob_name(unique)
+ return generate_random_name_species_based(gender, unique, dna?.species?.type || /datum/species/human)
+
+/mob/living/silicon/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/basic/drone/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/basic/bot/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
+
+/mob/living/simple_animal/bot/generate_random_mob_name(unique)
+ return generate_random_name(gender, unique, list(/datum/language/machine = 1))
GLOBAL_VAR(command_name)
/proc/command_name()
@@ -194,16 +249,11 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex)
if(1)//1 and 2 can only be selected once each to prevent more than two specific names/places/etc.
switch(rand(1,2))//Mainly to add more options later.
if(1)
- if(names.len && prob(70))
+ if(length(names) && prob(70))
. += pick(names)
else
- if(prob(10))
- . += pick(lizard_name(MALE),lizard_name(FEMALE))
- else
- var/new_name = pick(pick(GLOB.first_names_male,GLOB.first_names_female))
- new_name += " "
- new_name += pick(GLOB.last_names)
- . += new_name
+ . += generate_random_name()
+
if(2)
var/datum/job/job = pick(SSjob.joinable_occupations)
if(job)
diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm
index 4e33aa43708a2..692704be0fffd 100644
--- a/code/_globalvars/lists/mobs.dm
+++ b/code/_globalvars/lists/mobs.dm
@@ -85,11 +85,54 @@ GLOBAL_LIST_EMPTY(revenant_relay_mobs)
///underages who have been reported to security for trying to buy things they shouldn't, so they can't spam
GLOBAL_LIST_EMPTY(narcd_underages)
+/// List of language prototypes to reference, assoc [type] = prototype
+GLOBAL_LIST_INIT_TYPED(language_datum_instances, /datum/language, init_language_prototypes())
+/// List if all language typepaths learnable, IE, those with keys
+GLOBAL_LIST_INIT(all_languages, init_all_languages())
+// /List of language prototypes to reference, assoc "name" = typepath
+GLOBAL_LIST_INIT(language_types_by_name, init_language_types_by_name())
+
+/proc/init_language_prototypes()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+
+ lang_list[lang_type] = new lang_type()
+ return lang_list
-GLOBAL_LIST_EMPTY(language_datum_instances)
-GLOBAL_LIST_EMPTY(all_languages)
-///List of all languages ("name" = type)
-GLOBAL_LIST_EMPTY(language_types_by_name)
+/proc/init_all_languages()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+ lang_list += lang_type
+ return lang_list
+
+/proc/init_language_types_by_name()
+ var/list/lang_list = list()
+ for(var/datum/language/lang_type as anything in typesof(/datum/language))
+ if(!initial(lang_type.key))
+ continue
+ lang_list[initial(lang_type.name)] = lang_type
+ return lang_list
+
+/// An assoc list of species IDs to type paths
+GLOBAL_LIST_INIT(species_list, init_species_list())
+/// List of all species prototypes to reference, assoc [type] = prototype
+GLOBAL_LIST_INIT_TYPED(species_prototypes, /datum/species, init_species_prototypes())
+
+/proc/init_species_list()
+ var/list/species_list = list()
+ for(var/datum/species/species_path as anything in subtypesof(/datum/species))
+ species_list[initial(species_path.id)] = species_path
+ return species_list
+
+/proc/init_species_prototypes()
+ var/list/species_list = list()
+ for(var/species_type in subtypesof(/datum/species))
+ species_list[species_type] = new species_type()
+ return species_list
GLOBAL_LIST_EMPTY(sentient_disease_instances)
diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm
index c51fbaa9eb7a0..81fe08373b31a 100644
--- a/code/_globalvars/lists/names.dm
+++ b/code/_globalvars/lists/names.dm
@@ -8,12 +8,12 @@ GLOBAL_LIST_INIT(first_names, world.file2list("strings/names/first.txt"))
GLOBAL_LIST_INIT(first_names_male, world.file2list("strings/names/first_male.txt"))
GLOBAL_LIST_INIT(first_names_female, world.file2list("strings/names/first_female.txt"))
GLOBAL_LIST_INIT(last_names, world.file2list("strings/names/last.txt"))
-GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt"))
-GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt"))
GLOBAL_LIST_INIT(clown_names, world.file2list("strings/names/clown.txt"))
GLOBAL_LIST_INIT(mime_names, world.file2list("strings/names/mime.txt"))
GLOBAL_LIST_INIT(religion_names, world.file2list("strings/names/religion.txt"))
GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt"))
+GLOBAL_LIST_INIT(lizard_names_male, world.file2list("strings/names/lizard_male.txt"))
+GLOBAL_LIST_INIT(lizard_names_female, world.file2list("strings/names/lizard_female.txt"))
GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt"))
GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt"))
GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt"))
diff --git a/code/controllers/subsystem/language.dm b/code/controllers/subsystem/language.dm
deleted file mode 100644
index 88e92e2f93c5f..0000000000000
--- a/code/controllers/subsystem/language.dm
+++ /dev/null
@@ -1,17 +0,0 @@
-SUBSYSTEM_DEF(language)
- name = "Language"
- init_order = INIT_ORDER_LANGUAGE
- flags = SS_NO_FIRE
-
-/datum/controller/subsystem/language/Initialize()
- for(var/datum/language/language as anything in subtypesof(/datum/language))
- if(!initial(language.key))
- continue
-
- GLOB.all_languages += language
- GLOB.language_types_by_name[initial(language.name)] = language
-
- var/datum/language/instance = new language
- GLOB.language_datum_instances[language] = instance
-
- return SS_INIT_SUCCESS
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index e3891392d1a76..251414241c92d 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -129,8 +129,8 @@
/// Randomise friend name and appearance
/mob/camera/imaginary_friend/proc/setup_friend()
- var/gender = pick(MALE, FEMALE)
- real_name = random_unique_name(gender)
+ gender = pick(MALE, FEMALE)
+ real_name = generate_random_name_species_based(gender, FALSE, /datum/species/human)
name = real_name
human_image = get_flat_human_icon(null, pick(SSjob.joinable_occupations))
Show()
diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm
index 255c2a3f3a7f5..9654365c49d34 100644
--- a/code/datums/diseases/advance/symptoms/voice_change.dm
+++ b/code/datums/diseases/advance/symptoms/voice_change.dm
@@ -54,7 +54,7 @@
else
if(ishuman(M))
var/mob/living/carbon/human/H = M
- H.SetSpecialVoice(H.dna.species.random_name(H.gender))
+ H.SetSpecialVoice(H.generate_random_mob_name())
if(scramble_language && !current_language) // Last part prevents rerolling language with small amounts of cure.
current_language = pick(subtypesof(/datum/language) - /datum/language/common)
H.add_blocked_language(subtypesof(/datum/language) - current_language, LANGUAGE_VOICECHANGE)
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index ab5407bc78ccf..8f5844aa48093 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -451,14 +451,8 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block())
if(create_mutation_blocks) //I hate this
generate_dna_blocks()
if(randomize_features)
- var/static/list/all_species_protoypes
- if(isnull(all_species_protoypes))
- all_species_protoypes = list()
- for(var/species_path in subtypesof(/datum/species))
- all_species_protoypes += new species_path()
-
- for(var/datum/species/random_species as anything in all_species_protoypes)
- features |= random_species.randomize_features()
+ for(var/species_type in GLOB.species_prototypes)
+ features |= GLOB.species_prototypes[species_type].randomize_features()
features["mcolor"] = "#[random_color()]"
diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm
index 0797b4d1890a1..c41779e7384ec 100644
--- a/code/game/machinery/computer/records/security.dm
+++ b/code/game/machinery/computer/records/security.dm
@@ -49,10 +49,8 @@
if(prob(10/severity))
switch(rand(1,5))
if(1)
- if(prob(10))
- target.name = "[pick(lizard_name(MALE),lizard_name(FEMALE))]"
- else
- target.name = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]"
+ target.name = generate_random_name()
+
if(2)
target.gender = pick("Male", "Female", "Other")
if(3)
diff --git a/code/game/objects/items/cardboard_cutouts.dm b/code/game/objects/items/cardboard_cutouts.dm
index 71f3a244a3081..1e6c2b35ede2c 100644
--- a/code/game/objects/items/cardboard_cutouts.dm
+++ b/code/game/objects/items/cardboard_cutouts.dm
@@ -317,7 +317,7 @@
outfit = /datum/outfit/ashwalker/spear
/datum/cardboard_cutout/ash_walker/get_name()
- return lizard_name(pick(MALE, FEMALE))
+ return generate_random_name_species_based(species_type = /datum/species/lizard)
/datum/cardboard_cutout/death_squad
name = "Deathsquad Officer"
diff --git a/code/game/objects/items/debug_items.dm b/code/game/objects/items/debug_items.dm
index 4f6239acbe817..44f53df2c2b2d 100644
--- a/code/game/objects/items/debug_items.dm
+++ b/code/game/objects/items/debug_items.dm
@@ -21,7 +21,7 @@
/obj/item/debug/human_spawner/attack_self(mob/user)
..()
- var/choice = input("Select a species", "Human Spawner", null) in GLOB.species_list
+ var/choice = input("Select a species", "Human Spawner", null) in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
selected_species = GLOB.species_list[choice]
/obj/item/debug/omnitool
@@ -168,4 +168,3 @@
var/turf/loc_turf = get_turf(src)
for(var/spawn_atom in (choice == "No" ? typesof(path) : subtypesof(path)))
new spawn_atom(loc_turf)
-
diff --git a/code/game/objects/structures/headpike.dm b/code/game/objects/structures/headpike.dm
index b4cffdb654d23..fca325744554d 100644
--- a/code/game/objects/structures/headpike.dm
+++ b/code/game/objects/structures/headpike.dm
@@ -36,7 +36,7 @@
victim = locate() in parts_list
if(!victim) //likely a mapspawned one
victim = new(src)
- victim.real_name = random_unique_name(prob(50))
+ victim.real_name = generate_random_name()
spear = locate(speartype) in parts_list
if(!spear)
spear = new speartype(src)
diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm
index fcf9693731e05..509787ffd3a56 100644
--- a/code/modules/admin/create_mob.dm
+++ b/code/modules/admin/create_mob.dm
@@ -16,7 +16,7 @@
/proc/randomize_human(mob/living/carbon/human/human, randomize_mutations = FALSE)
human.gender = human.dna.species.sexes ? pick(MALE, FEMALE, PLURAL, NEUTER) : PLURAL
human.physique = human.gender
- human.real_name = human.dna?.species.random_name(human.gender) || random_unique_name(human.gender)
+ human.real_name = human.generate_random_mob_name()
human.name = human.get_visible_name()
human.set_hairstyle(random_hairstyle(human.gender), update = FALSE)
human.set_facial_hairstyle(random_facial_hairstyle(human.gender), update = FALSE)
@@ -24,7 +24,7 @@
human.set_facial_haircolor(human.hair_color, update = FALSE)
human.eye_color_left = random_eye_color()
human.eye_color_right = human.eye_color_left
- human.skin_tone = random_skin_tone()
+ human.skin_tone = pick(GLOB.skin_tones)
human.dna.species.randomize_active_underwear_only(human)
// Needs to be called towards the end to update all the UIs just set above
human.dna.initialize_dna(newblood_type = random_blood_type(), create_mutation_blocks = randomize_mutations, randomize_features = TRUE)
diff --git a/code/modules/admin/verbs/anonymousnames.dm b/code/modules/admin/verbs/anonymousnames.dm
index 9a71d68637a88..10edb49d99336 100644
--- a/code/modules/admin/verbs/anonymousnames.dm
+++ b/code/modules/admin/verbs/anonymousnames.dm
@@ -131,8 +131,7 @@ GLOBAL_DATUM(current_anonymous_theme, /datum/anonymous_theme)
/datum/anonymous_theme/proc/anonymous_name(mob/target)
var/datum/client_interface/client = GET_CLIENT(target)
var/species_type = client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
- return species.random_name(target.gender,1)
+ return generate_random_name_species_based(target.gender, TRUE, species_type)
/**
* anonymous_ai_name: generates a random name, based off of whatever the round's anonymousnames is set to (but for sillycones).
diff --git a/code/modules/admin/verbs/secrets.dm b/code/modules/admin/verbs/secrets.dm
index b7aa16b6b5fd5..5f5b5f245bb5c 100644
--- a/code/modules/admin/verbs/secrets.dm
+++ b/code/modules/admin/verbs/secrets.dm
@@ -222,7 +222,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
if("allspecies")
if(!is_funmin)
return
- var/result = input(holder, "Please choose a new species","Species") as null|anything in GLOB.species_list
+ var/result = input(holder, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
if(result)
SSblackbox.record_feedback("nested tally", "admin_secrets_fun_used", 1, list("Mass Species Change", "[result]"))
log_admin("[key_name(holder)] turned all humans into [result]")
@@ -724,4 +724,3 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
var/datum/antagonist/malf_ai/antag_datum = new
antag_datum.give_objectives = keep_generic_objecives
assign_admin_objective_and_antag(player, antag_datum)
-
diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm
index 644d57b6d24d1..5fbf5c6953d6a 100644
--- a/code/modules/client/preferences/_preference.dm
+++ b/code/modules/client/preferences/_preference.dm
@@ -331,7 +331,7 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key())
)
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if (!(savefile_key in species.get_features()))
return FALSE
diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm
index 002a7f8c13a33..d0ec072ba472f 100644
--- a/code/modules/client/preferences/clothing.dm
+++ b/code/modules/client/preferences/clothing.dm
@@ -175,7 +175,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_NO_UNDERWEAR in species.inherent_traits)
/datum/preference/choiced/underwear/compile_constant_data()
diff --git a/code/modules/client/preferences/names.dm b/code/modules/client/preferences/names.dm
index 476fc7381a28f..9afc8da18c1aa 100644
--- a/code/modules/client/preferences/names.dm
+++ b/code/modules/client/preferences/names.dm
@@ -45,12 +45,11 @@
target.log_mob_tag("TAG: [target.tag] RENAMED: [key_name(target)]")
/datum/preference/name/real_name/create_informed_default_value(datum/preferences/preferences)
- var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/gender = preferences.read_preference(/datum/preference/choiced/gender)
-
- var/datum/species/species = new species_type
-
- return species.random_name(gender, unique = TRUE)
+ return generate_random_name_species_based(
+ preferences.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ preferences.read_preference(/datum/preference/choiced/species),
+ )
/datum/preference/name/real_name/deserialize(input, datum/preferences/preferences)
input = ..(input)
@@ -73,9 +72,7 @@
savefile_key = "human_name"
/datum/preference/name/backup_human/create_informed_default_value(datum/preferences/preferences)
- var/gender = preferences.read_preference(/datum/preference/choiced/gender)
-
- return random_unique_name(gender)
+ return generate_random_name(preferences.read_preference(/datum/preference/choiced/gender))
/datum/preference/name/clown
savefile_key = "clown_name"
diff --git a/code/modules/client/preferences/species.dm b/code/modules/client/preferences/species.dm
index 9e4923d2b11da..1c74d7981b655 100644
--- a/code/modules/client/preferences/species.dm
+++ b/code/modules/client/preferences/species.dm
@@ -34,7 +34,7 @@
for (var/species_id in get_selectable_species())
var/species_type = GLOB.species_list[species_id]
- var/datum/species/species = new species_type()
+ var/datum/species/species = GLOB.species_prototypes[species_type]
data[species_id] = list()
data[species_id]["name"] = species.name
@@ -47,6 +47,4 @@
data[species_id]["perks"] = species.get_species_perks()
data[species_id]["diet"] = species.get_species_diet()
- qdel(species)
-
return data
diff --git a/code/modules/client/preferences/species_features/mutants.dm b/code/modules/client/preferences/species_features/mutants.dm
index 7ecf25d9abce5..1d18c78ee1ad1 100644
--- a/code/modules/client/preferences/species_features/mutants.dm
+++ b/code/modules/client/preferences/species_features/mutants.dm
@@ -9,7 +9,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_FIXED_MUTANT_COLORS in species.inherent_traits)
/datum/preference/color/mutant_color/create_default_value()
diff --git a/code/modules/client/preferences/underwear_color.dm b/code/modules/client/preferences/underwear_color.dm
index 6e64b4423e50a..1304bdaf2da8d 100644
--- a/code/modules/client/preferences/underwear_color.dm
+++ b/code/modules/client/preferences/underwear_color.dm
@@ -8,7 +8,7 @@
return FALSE
var/species_type = preferences.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
return !(TRAIT_NO_UNDERWEAR in species.inherent_traits)
/datum/preference/color/underwear_color/apply_to_human(mob/living/carbon/human/target, value)
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 6c5c2f4f03967..9cbd711d98161 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -117,7 +117,7 @@
/// RPG job names, for the memes
var/rpg_title
- /// Alternate titles to register as pointing to this job.
+ /// Alternate titles to register as pointing to this job.
var/list/alternate_titles
/// Does this job ignore human authority?
@@ -543,11 +543,11 @@
dna.species.roundstart_changed = TRUE
apply_pref_name(/datum/preference/name/backup_human, player_client)
if(CONFIG_GET(flag/force_random_names))
- var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
-
- var/gender = player_client.prefs.read_preference(/datum/preference/choiced/gender)
- real_name = species.random_name(gender, TRUE)
+ real_name = generate_random_name_species_based(
+ player_client.prefs.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ player_client.prefs.read_preference(/datum/preference/choiced/species),
+ )
dna.update_dna_identity()
@@ -569,9 +569,11 @@
if(!player_client)
return // Disconnected while checking the appearance ban.
- var/species_type = player_client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
- organic_name = species.random_name(player_client.prefs.read_preference(/datum/preference/choiced/gender), TRUE)
+ organic_name = generate_random_name_species_based(
+ player_client.prefs.read_preference(/datum/preference/choiced/gender),
+ TRUE,
+ player_client.prefs.read_preference(/datum/preference/choiced/species),
+ )
else
if(!player_client)
return // Disconnected while checking the appearance ban.
diff --git a/code/modules/language/_language.dm b/code/modules/language/_language.dm
new file mode 100644
index 0000000000000..94ea4a6aa4027
--- /dev/null
+++ b/code/modules/language/_language.dm
@@ -0,0 +1,164 @@
+/// maximum of 50 specific scrambled lines per language
+#define SCRAMBLE_CACHE_LEN 50
+
+/// Datum based languages. Easily editable and modular.
+/datum/language
+ /// Fluff name of language if any.
+ var/name = "an unknown language"
+ /// Short description for 'Check Languages'.
+ var/desc = "A language."
+ /// Character used to speak in language
+ /// If key is null, then the language isn't real or learnable.
+ var/key
+ /// Various language flags.
+ var/flags = NONE
+ /// Used when scrambling text for a non-speaker.
+ var/list/syllables
+ /// List of characters that will randomly be inserted between syllables.
+ var/list/special_characters
+ /// Likelihood of making a new sentence after each syllable.
+ var/sentence_chance = 5
+ /// Likelihood of getting a space in the random scramble string
+ var/space_chance = 55
+ /// Spans to apply from this language
+ var/list/spans
+ /// Cache of recently scrambled text
+ /// This allows commonly reused words to not require a full re-scramble every time.
+ var/list/scramble_cache = list()
+ /// The language that an atom knows with the highest "default_priority" is selected by default.
+ var/default_priority = 0
+ /// If TRUE, when generating names, we will always use the default human namelist, even if we have syllables set.
+ /// This is to be used for languages with very outlandish syllable lists (like pirates).
+ var/always_use_default_namelist = FALSE
+ /// Icon displayed in the chat window when speaking this language.
+ /// if you are seeing someone speak popcorn language, then something is wrong.
+ var/icon = 'icons/misc/language.dmi'
+ /// Icon state displayed in the chat window when speaking this language.
+ var/icon_state = "popcorn"
+
+ /// By default, random names picks this many names
+ var/default_name_count = 2
+ /// By default, random names picks this many syllables (min)
+ var/default_name_syllable_min = 2
+ /// By default, random names picks this many syllables (max)
+ var/default_name_syllable_max = 4
+ /// What char to place in between randomly generated names
+ var/random_name_spacer = " "
+
+/// Checks whether we should display the language icon to the passed hearer.
+/datum/language/proc/display_icon(atom/movable/hearer)
+ var/understands = hearer.has_language(src.type)
+ if((flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD) && understands)
+ return FALSE
+ if((flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD) && !understands)
+ return FALSE
+ return TRUE
+
+/// Returns the icon to display in the chat window when speaking this language.
+/datum/language/proc/get_icon()
+ var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
+ return sheet.icon_tag("language-[icon_state]")
+
+/// Simple helper for getting a default firstname lastname
+/datum/language/proc/default_name(gender = NEUTER)
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+ if(gender == FEMALE)
+ return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
+ return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
+
+
+/**
+ * Generates a random name this language would use.
+ *
+ * * gender: What gender to generate from, if neuter / plural coin flips between male and female
+ * * name_count: How many names to generate in, by default 2, for firstname lastname
+ * * syllable_count: How many syllables to generate in each name, min
+ * * syllable_max: How many syllables to generate in each name, max
+ * * force_use_syllables: If the name should be generated from the syllables list.
+ * Only used for subtypes which implement custom name lists. Also requires the language has syllables set.
+ */
+/datum/language/proc/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+ if(!length(syllables) || always_use_default_namelist)
+ return default_name(gender)
+
+ var/list/full_name = list()
+ for(var/i in 1 to name_count)
+ var/new_name = ""
+ for(var/j in 1 to rand(default_name_syllable_min, default_name_syllable_max))
+ new_name += pick_weight_recursive(syllables)
+ full_name += capitalize(LOWER_TEXT(new_name))
+
+ return jointext(full_name, random_name_spacer)
+
+/// Generates a random name, and attempts to ensure it is unique (IE, no other mob in the world has it)
+/datum/language/proc/get_random_unique_name(...)
+ var/result = get_random_name(arglist(args))
+ for(var/i in 1 to 10)
+ if(!findname(result))
+ break
+ result = get_random_name(arglist(args))
+
+ return result
+
+/datum/language/proc/check_cache(input)
+ var/lookup = scramble_cache[input]
+ if(lookup)
+ scramble_cache -= input
+ scramble_cache[input] = lookup
+ . = lookup
+
+/datum/language/proc/add_to_cache(input, scrambled_text)
+ // Add it to cache, cutting old entries if the list is too long
+ scramble_cache[input] = scrambled_text
+ if(scramble_cache.len > SCRAMBLE_CACHE_LEN)
+ scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1)
+
+/datum/language/proc/scramble(input)
+
+ if(!length(syllables))
+ return stars(input)
+
+ // If the input is cached already, move it to the end of the cache and return it
+ var/lookup = check_cache(input)
+ if(lookup)
+ return lookup
+
+ var/input_size = length_char(input)
+ var/scrambled_text = ""
+ var/capitalize = TRUE
+
+ while(length_char(scrambled_text) < input_size)
+ var/next = (length(scrambled_text) && length(special_characters) && prob(1)) ? pick(special_characters) : pick_weight_recursive(syllables)
+ if(capitalize)
+ next = capitalize(next)
+ capitalize = FALSE
+ scrambled_text += next
+ var/chance = rand(100)
+ if(chance <= sentence_chance)
+ scrambled_text += ". "
+ capitalize = TRUE
+ else if(chance > sentence_chance && chance <= space_chance)
+ scrambled_text += " "
+
+ scrambled_text = trim(scrambled_text)
+ var/ending = copytext_char(scrambled_text, -1)
+ if(ending == ".")
+ scrambled_text = copytext_char(scrambled_text, 1, -2)
+ var/input_ending = copytext_char(input, -1)
+ if(input_ending in list("!","?","."))
+ scrambled_text += input_ending
+
+ add_to_cache(input, scrambled_text)
+
+ return scrambled_text
+
+#undef SCRAMBLE_CACHE_LEN
diff --git a/code/modules/language/language_holder.dm b/code/modules/language/_language_holder.dm
similarity index 100%
rename from code/modules/language/language_holder.dm
rename to code/modules/language/_language_holder.dm
diff --git a/code/modules/language/language_manuals.dm b/code/modules/language/_language_manuals.dm
similarity index 100%
rename from code/modules/language/language_manuals.dm
rename to code/modules/language/_language_manuals.dm
diff --git a/code/modules/language/language_menu.dm b/code/modules/language/_language_menu.dm
similarity index 100%
rename from code/modules/language/language_menu.dm
rename to code/modules/language/_language_menu.dm
diff --git a/code/modules/language/aphasia.dm b/code/modules/language/aphasia.dm
index 9d4e317c4d881..2d82b79892ee7 100644
--- a/code/modules/language/aphasia.dm
+++ b/code/modules/language/aphasia.dm
@@ -7,3 +7,4 @@
space_chance = 20
default_priority = 10
icon_state = "aphasia"
+ always_use_default_namelist = TRUE // Shouldn't generate names for this anyways
diff --git a/code/modules/language/beachbum.dm b/code/modules/language/beachbum.dm
index d78be9788f35b..bd319e717ffd0 100644
--- a/code/modules/language/beachbum.dm
+++ b/code/modules/language/beachbum.dm
@@ -17,5 +17,5 @@
"heavy", "stellar", "excellent", "triumphant", "babe", "four",
"tail", "trim", "tube", "wobble", "roll", "gnarly", "epic",
)
-
icon_state = "beach"
+ always_use_default_namelist = TRUE
diff --git a/code/modules/language/buzzwords.dm b/code/modules/language/buzzwords.dm
index c46088c0ad5b9..2ed033bca345b 100644
--- a/code/modules/language/buzzwords.dm
+++ b/code/modules/language/buzzwords.dm
@@ -8,3 +8,4 @@
)
icon_state = "buzz"
default_priority = 90
+ always_use_default_namelist = TRUE // Otherwise we get Bzzbzbz Zzzbzbz.
diff --git a/code/modules/language/calcic.dm b/code/modules/language/calcic.dm
index f4882e1105b95..477e442203bc1 100644
--- a/code/modules/language/calcic.dm
+++ b/code/modules/language/calcic.dm
@@ -13,4 +13,16 @@
icon_state = "calcic"
default_priority = 90
+/datum/language/calcic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ return "[pick(GLOB.plasmaman_names)] \Roman[rand(1, 99)]"
+
// Yeah, this goes to skeletons too, since it's basically just skeleton clacking.
diff --git a/code/modules/language/codespeak.dm b/code/modules/language/codespeak.dm
index 09db7ef511b4b..242095b3bb7fa 100644
--- a/code/modules/language/codespeak.dm
+++ b/code/modules/language/codespeak.dm
@@ -5,6 +5,7 @@
default_priority = 0
flags = TONGUELESS_SPEECH | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD
icon_state = "codespeak"
+ always_use_default_namelist = TRUE // No syllables anyways
/datum/language/codespeak/scramble(input)
var/lookup = check_cache(input)
diff --git a/code/modules/language/common.dm b/code/modules/language/common.dm
index 2dc7294983c0a..6bad808fef262 100644
--- a/code/modules/language/common.dm
+++ b/code/modules/language/common.dm
@@ -7,50 +7,51 @@
default_priority = 100
icon_state = "galcom"
-
-//Syllable Lists
-/*
- This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed,
- and the english syllables had to be duplicated so that there is roughly a 50-50 weighting.
-
- Sources:
- http://www.sttmedia.com/syllablefrequency-english
- http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm
-*/
-/datum/language/common/syllables = list(
- // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese
- list(
- "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao",
- "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai",
- "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun",
- "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei",
- "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e",
- "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang",
- "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha",
- "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan",
- "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan",
- "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai",
- "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian",
- "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang",
- "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na",
- "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning",
- "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng",
- "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin",
- "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou",
- "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha",
- "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui",
- "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te",
- "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan",
- "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu",
- "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan",
- "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao",
- "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi",
- "zong", "zou", "zuan", "zui", "zun", "zuo", "zu",
- ),
- list(
- "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
- "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
- "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
- "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi",
- ),
-)
+ // Default namelist is the human namelist, and common is the human language, so might as well.
+ // Feel free to remove this at some point because common can generate some pretty cool names.
+ always_use_default_namelist = TRUE
+ /**
+ * This list really long, mainly because I can't make up my mind about which mandarin syllables should be removed,
+ * and the english syllables had to be duplicated so that there is roughly a 50-50 weighting.
+ *
+ * Sources:
+ * http://www.sttmedia.com/syllablefrequency-english
+ * http://www.chinahighlights.com/travelguide/learning-chinese/pinyin-syllables.htm
+ */
+ syllables = list(
+ // each sublist has an equal chance of being picked, so each syllable has an equal chance of being english or chinese
+ list(
+ "a", "ai", "an", "ang", "ao", "ba", "bai", "ban", "bang", "bao", "bei", "ben", "beng", "bi", "bian", "biao",
+ "bie", "bin", "bing", "bo", "bu", "ca", "cai", "can", "cang", "cao", "ce", "cei", "cen", "ceng", "cha", "chai",
+ "chan", "chang", "chao", "che", "chen", "cheng", "chi", "chong", "chou", "chu", "chua", "chuai", "chuan", "chuang", "chui", "chun",
+ "chuo", "ci", "cong", "cou", "cu", "cuan", "cui", "cun", "cuo", "da", "dai", "dan", "dang", "dao", "de", "dei",
+ "den", "deng", "di", "dian", "diao", "die", "ding", "diu", "dong", "dou", "du", "duan", "dui", "dun", "duo", "e",
+ "ei", "en", "er", "fa", "fan", "fang", "fei", "fen", "feng", "fo", "fou", "fu", "ga", "gai", "gan", "gang",
+ "gao", "ge", "gei", "gen", "geng", "gong", "gou", "gu", "gua", "guai", "guan", "guang", "gui", "gun", "guo", "ha",
+ "hai", "han", "hang", "hao", "he", "hei", "hen", "heng", "hm", "hng", "hong", "hou", "hu", "hua", "huai", "huan",
+ "huang", "hui", "hun", "huo", "ji", "jia", "jian", "jiang", "jiao", "jie", "jin", "jing", "jiong", "jiu", "ju", "juan",
+ "jue", "jun", "ka", "kai", "kan", "kang", "kao", "ke", "kei", "ken", "keng", "kong", "kou", "ku", "kua", "kuai",
+ "kuan", "kuang", "kui", "kun", "kuo", "la", "lai", "lan", "lang", "lao", "le", "lei", "leng", "li", "lia", "lian",
+ "liang", "liao", "lie", "lin", "ling", "liu", "long", "lou", "lu", "luan", "lun", "luo", "ma", "mai", "man", "mang",
+ "mao", "me", "mei", "men", "meng", "mi", "mian", "miao", "mie", "min", "ming", "miu", "mo", "mou", "mu", "na",
+ "nai", "nan", "nang", "nao", "ne", "nei", "nen", "neng", "ng", "ni", "nian", "niang", "niao", "nie", "nin", "ning",
+ "niu", "nong", "nou", "nu", "nuan", "nuo", "o", "ou", "pa", "pai", "pan", "pang", "pao", "pei", "pen", "peng",
+ "pi", "pian", "piao", "pie", "pin", "ping", "po", "pou", "pu", "qi", "qia", "qian", "qiang", "qiao", "qie", "qin",
+ "qing", "qiong", "qiu", "qu", "quan", "que", "qun", "ran", "rang", "rao", "re", "ren", "reng", "ri", "rong", "rou",
+ "ru", "rua", "ruan", "rui", "run", "ruo", "sa", "sai", "san", "sang", "sao", "se", "sei", "sen", "seng", "sha",
+ "shai", "shan", "shang", "shao", "she", "shei", "shen", "sheng", "shi", "shou", "shu", "shua", "shuai", "shuan", "shuang", "shui",
+ "shun", "shuo", "si", "song", "sou", "su", "suan", "sui", "sun", "suo", "ta", "tai", "tan", "tang", "tao", "te",
+ "teng", "ti", "tian", "tiao", "tie", "ting", "tong", "tou", "tu", "tuan", "tui", "tun", "tuo", "wa", "wai", "wan",
+ "wang", "wei", "wen", "weng", "wo", "wu", "xi", "xia", "xian", "xiang", "xiao", "xie", "xin", "xing", "xiong", "xiu",
+ "xu", "xuan", "xue", "xun", "ya", "yan", "yang", "yao", "ye", "yi", "yin", "ying", "yong", "you", "yu", "yuan",
+ "yue", "yun", "za", "zai", "zan", "zang", "zao", "ze", "zei", "zen", "zeng", "zha", "zhai", "zhan", "zhang", "zhao",
+ "zhe", "zhei", "zhen", "zheng", "zhi", "zhong", "zhou", "zhu", "zhua", "zhuai", "zhuan", "zhuang", "zhui", "zhun", "zhuo", "zi",
+ "zong", "zou", "zuan", "zui", "zun", "zuo", "zu",
+ ),
+ list(
+ "al", "an", "ar", "as", "at", "ea", "ed", "en", "er", "es", "ha", "he", "hi", "in", "is", "it",
+ "le", "me", "nd", "ne", "ng", "nt", "on", "or", "ou", "re", "se", "st", "te", "th", "ti", "to",
+ "ve", "wa", "all", "and", "are", "but", "ent", "era", "ere", "eve", "for", "had", "hat", "hen", "her", "hin",
+ "his", "ing", "ion", "ith", "not", "ome", "oul", "our", "sho", "ted", "ter", "tha", "the", "thi",
+ ),
+ )
diff --git a/code/modules/language/draconic.dm b/code/modules/language/draconic.dm
index f812c8dc1311a..55ebd1ec20267 100644
--- a/code/modules/language/draconic.dm
+++ b/code/modules/language/draconic.dm
@@ -13,5 +13,25 @@
"ra", "ar", "re", "er", "ri", "ir", "ro", "or", "ru", "ur", "rs", "sr",
"a", "a", "e", "e", "i", "i", "o", "o", "u", "u", "s", "s"
)
+ special_characters = list("-")
icon_state = "lizard"
default_priority = 90
+ default_name_syllable_min = 3
+ default_name_syllable_max = 5
+ random_name_spacer = "-"
+
+/datum/language/draconic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+ if(gender != MALE)
+ gender = pick(MALE, FEMALE)
+
+ if(gender == MALE)
+ return "[pick(GLOB.lizard_names_male)][random_name_spacer][pick(GLOB.lizard_names_male)]"
+ return "[pick(GLOB.lizard_names_female)][random_name_spacer][pick(GLOB.lizard_names_female)]"
diff --git a/code/modules/language/drone.dm b/code/modules/language/drone.dm
index 5b47533d45e3a..09fb6546e4a16 100644
--- a/code/modules/language/drone.dm
+++ b/code/modules/language/drone.dm
@@ -11,3 +11,4 @@
default_priority = 20
icon_state = "drone"
+ always_use_default_namelist = TRUE // Nonsense language
diff --git a/code/modules/language/language.dm b/code/modules/language/language.dm
deleted file mode 100644
index 9fc2abf0f5a9f..0000000000000
--- a/code/modules/language/language.dm
+++ /dev/null
@@ -1,107 +0,0 @@
-#define SCRAMBLE_CACHE_LEN 50 //maximum of 50 specific scrambled lines per language
-
-/*
- Datum based languages. Easily editable and modular.
-*/
-
-/datum/language
- var/name = "an unknown language" // Fluff name of language if any.
- var/desc = "A language." // Short description for 'Check Languages'.
- var/key // Character used to speak in language
- // If key is null, then the language isn't real or learnable.
- var/flags // Various language flags.
- var/list/syllables // Used when scrambling text for a non-speaker.
- var/sentence_chance = 5 // Likelihood of making a new sentence after each syllable.
- var/space_chance = 55 // Likelihood of getting a space in the random scramble string
- var/list/spans = list()
- var/list/scramble_cache = list()
- var/default_priority = 0 // the language that an atom knows with the highest "default_priority" is selected by default.
-
- // if you are seeing someone speak popcorn language, then something is wrong.
- var/icon = 'icons/misc/language.dmi'
- var/icon_state = "popcorn"
-
-/datum/language/proc/display_icon(atom/movable/hearer)
- var/understands = hearer.has_language(src.type)
- if(flags & LANGUAGE_HIDE_ICON_IF_UNDERSTOOD && understands)
- return FALSE
- if(flags & LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD && !understands)
- return FALSE
- return TRUE
-
-/datum/language/proc/get_icon()
- var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/chat)
- return sheet.icon_tag("language-[icon_state]")
-
-/datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4, syllable_divisor=2)
- if(!syllables || !syllables.len)
- if(gender == FEMALE)
- return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
- else
- return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
-
- var/full_name = ""
- var/new_name = ""
-
- for(var/i in 0 to name_count)
- new_name = ""
- var/Y = rand(FLOOR(syllable_count/syllable_divisor, 1), syllable_count)
- for(var/x in Y to 0)
- new_name += pick_weight_recursive(syllables)
- full_name += " [capitalize(LOWER_TEXT(new_name))]"
-
- return "[trim(full_name)]"
-
-/datum/language/proc/check_cache(input)
- var/lookup = scramble_cache[input]
- if(lookup)
- scramble_cache -= input
- scramble_cache[input] = lookup
- . = lookup
-
-/datum/language/proc/add_to_cache(input, scrambled_text)
- // Add it to cache, cutting old entries if the list is too long
- scramble_cache[input] = scrambled_text
- if(scramble_cache.len > SCRAMBLE_CACHE_LEN)
- scramble_cache.Cut(1, scramble_cache.len-SCRAMBLE_CACHE_LEN-1)
-
-/datum/language/proc/scramble(input)
-
- if(!syllables || !syllables.len)
- return stars(input)
-
- // If the input is cached already, move it to the end of the cache and return it
- var/lookup = check_cache(input)
- if(lookup)
- return lookup
-
- var/input_size = length_char(input)
- var/scrambled_text = ""
- var/capitalize = TRUE
-
- while(length_char(scrambled_text) < input_size)
- var/next = pick_weight_recursive(syllables)
- if(capitalize)
- next = capitalize(next)
- capitalize = FALSE
- scrambled_text += next
- var/chance = rand(100)
- if(chance <= sentence_chance)
- scrambled_text += ". "
- capitalize = TRUE
- else if(chance > sentence_chance && chance <= space_chance)
- scrambled_text += " "
-
- scrambled_text = trim(scrambled_text)
- var/ending = copytext_char(scrambled_text, -1)
- if(ending == ".")
- scrambled_text = copytext_char(scrambled_text, 1, -2)
- var/input_ending = copytext_char(input, -1)
- if(input_ending in list("!","?","."))
- scrambled_text += input_ending
-
- add_to_cache(input, scrambled_text)
-
- return scrambled_text
-
-#undef SCRAMBLE_CACHE_LEN
diff --git a/code/modules/language/machine.dm b/code/modules/language/machine.dm
index 36962a712a1b5..4be282a5e2812 100644
--- a/code/modules/language/machine.dm
+++ b/code/modules/language/machine.dm
@@ -14,7 +14,16 @@
icon_state = "eal"
-/datum/language/machine/get_random_name()
+/datum/language/machine/get_random_name(
+ gender = NEUTER,
+ name_count = 2,
+ syllable_min = 2,
+ syllable_max = 4,
+ unique = FALSE,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
if(prob(70))
return "[pick(GLOB.posibrain_names)]-[rand(100, 999)]"
return pick(GLOB.ai_names)
diff --git a/code/modules/language/moffic.dm b/code/modules/language/moffic.dm
index 1d0aea96697fb..fb8dea63dcc83 100644
--- a/code/modules/language/moffic.dm
+++ b/code/modules/language/moffic.dm
@@ -13,4 +13,20 @@
icon_state = "moth"
default_priority = 90
+ default_name_syllable_min = 5
+ default_name_syllable_max = 10
+
+/datum/language/moffic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]"
+
+
// Fuck guest accounts, and fuck language testing.
diff --git a/code/modules/language/monkey.dm b/code/modules/language/monkey.dm
index e44f6a6268e25..423e94f22bd8c 100644
--- a/code/modules/language/monkey.dm
+++ b/code/modules/language/monkey.dm
@@ -7,3 +7,12 @@
default_priority = 80
icon_state = "animal"
+
+/datum/language/monkey/get_random_name(
+ gender = NEUTER,
+ name_count = 2,
+ syllable_min = 2,
+ syllable_max = 4,
+ force_use_syllables = FALSE,
+)
+ return "monkey ([rand(1, 999)])"
diff --git a/code/modules/language/mushroom.dm b/code/modules/language/mushroom.dm
index 08d494cc04d64..910489fd6dd9e 100644
--- a/code/modules/language/mushroom.dm
+++ b/code/modules/language/mushroom.dm
@@ -5,3 +5,5 @@
sentence_chance = 0
default_priority = 80
syllables = list("poof", "pff", "pFfF", "piff", "puff", "pooof", "pfffff", "piffpiff", "puffpuff", "poofpoof", "pifpafpofpuf")
+ default_name_syllable_min = 1
+ default_name_syllable_max = 2
diff --git a/code/modules/language/nekomimetic.dm b/code/modules/language/nekomimetic.dm
index 82edc2afcb57a..4be943f84417a 100644
--- a/code/modules/language/nekomimetic.dm
+++ b/code/modules/language/nekomimetic.dm
@@ -12,3 +12,16 @@
)
icon_state = "neko"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 2
+
+/datum/language/nekomimetic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(prob(33))
+ return default_name(gender)
+ return ..()
diff --git a/code/modules/language/piratespeak.dm b/code/modules/language/piratespeak.dm
index 5f6cb4897715d..a2faddb544f7c 100644
--- a/code/modules/language/piratespeak.dm
+++ b/code/modules/language/piratespeak.dm
@@ -10,3 +10,4 @@
"shiver", "timbers", "matey", "swashbuckler"
)
icon_state = "pirate"
+ always_use_default_namelist = TRUE
diff --git a/code/modules/language/shadowtongue.dm b/code/modules/language/shadowtongue.dm
index 9c0adb5eea3ff..351589393856b 100644
--- a/code/modules/language/shadowtongue.dm
+++ b/code/modules/language/shadowtongue.dm
@@ -16,3 +16,5 @@
)
icon_state = "shadow"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
diff --git a/code/modules/language/slime.dm b/code/modules/language/slime.dm
index fcb471774118a..15960898673d6 100644
--- a/code/modules/language/slime.dm
+++ b/code/modules/language/slime.dm
@@ -2,7 +2,8 @@
name = "Slime"
desc = "A melodic and complex language spoken by slimes. Some of the notes are inaudible to humans."
key = "k"
- syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix","*","!")
+ syllables = list("qr","qrr","xuq","qil","quum","xuqm","vol","xrim","zaoo","qu-uu","qix","qoo","zix")
+ special_characters = list("!","*")
default_priority = 70
icon_state = "slime"
diff --git a/code/modules/language/sylvan.dm b/code/modules/language/sylvan.dm
index 68cb73f9d525a..4f66fb5931c1a 100644
--- a/code/modules/language/sylvan.dm
+++ b/code/modules/language/sylvan.dm
@@ -13,3 +13,5 @@
)
icon_state = "plant"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
diff --git a/code/modules/language/terrum.dm b/code/modules/language/terrum.dm
index 361106ed16c93..63b527202f4ca 100644
--- a/code/modules/language/terrum.dm
+++ b/code/modules/language/terrum.dm
@@ -7,8 +7,25 @@
"sha", "vu", "nah", "ha", "yom", "ma", "cha", "ar", "et", "mol", "lua",
"ch", "na", "sh", "ni", "yah", "bes", "ol", "hish", "ev", "la", "ot", "la",
"khe", "tza", "chak", "hak", "hin", "hok", "lir", "tov", "yef", "yfe",
- "cho", "ar", "kas", "kal", "ra", "lom", "im", "'", "'", "'", "'", "bok",
+ "cho", "ar", "kas", "kal", "ra", "lom", "im", "bok",
"erev", "shlo", "lo", "ta", "im", "yom"
)
+ special_characters = list("'")
icon_state = "golem"
default_priority = 90
+
+/datum/language/terrum/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ var/name = pick(GLOB.golem_names)
+ // 3% chance to be given a human surname for "lore reasons"
+ if (prob(3))
+ name += " [pick(GLOB.last_names)]"
+ return name
diff --git a/code/modules/language/voltaic.dm b/code/modules/language/voltaic.dm
index 40fa9dcb1e826..90ab90dbe48e0 100644
--- a/code/modules/language/voltaic.dm
+++ b/code/modules/language/voltaic.dm
@@ -12,3 +12,21 @@
)
icon_state = "volt"
default_priority = 90
+ default_name_syllable_min = 2
+ default_name_syllable_max = 3
+
+
+/datum/language/voltaic/get_random_name(
+ gender = NEUTER,
+ name_count = default_name_count,
+ syllable_min = default_name_syllable_min,
+ syllable_max = default_name_syllable_max,
+ force_use_syllables = FALSE,
+)
+ if(force_use_syllables)
+ return ..()
+
+ var/picked = "[pick(GLOB.ethereal_names)] [random_capital_letter()]"
+ if(prob(65))
+ picked += random_capital_letter()
+ return picked
diff --git a/code/modules/language/xenocommon.dm b/code/modules/language/xenocommon.dm
index c5e6366715d8e..f4949b7d73cb4 100644
--- a/code/modules/language/xenocommon.dm
+++ b/code/modules/language/xenocommon.dm
@@ -6,3 +6,4 @@
default_priority = 50
icon_state = "xeno"
+ always_use_default_namelist = TRUE // Sssss Ssss?
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index a2ffa244679b6..ff46cfc0b64e7 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -914,8 +914,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
var/datum/species/new_human_species = GLOB.species_list[species_to_pick]
if(new_human_species)
new_human.set_species(new_human_species)
- new_human_species = new_human.dna.species
- new_human.fully_replace_character_name(new_human.real_name, new_human_species.random_name(new_human.gender, TRUE, TRUE))
+ new_human.fully_replace_character_name(new_human.real_name, new_human.generate_random_mob_name())
else
stack_trace("failed to spawn cadaver with species ID [species_to_pick]") //if it's invalid they'll just be a human, so no need to worry too much aside from yelling at the server owner lol.
else
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index f7e4b56cab274..1d2a8d1570f0f 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -89,15 +89,10 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
gender = body.gender
if(body.mind && body.mind.name)
- if(body.mind.ghostname)
- name = body.mind.ghostname
- else
- name = body.mind.name
+ name = body.mind.ghostname || body.mind.name
else
- if(body.real_name)
- name = body.real_name
- else
- name = random_unique_name(gender)
+ name = body.real_name || generate_random_mob_name(gender)
+
mind = body.mind //we don't transfer the mind but we keep a reference to it.
@@ -125,8 +120,8 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER)
abstract_move(T)
- if(!name) //To prevent nameless ghosts
- name = random_unique_name(gender)
+ //To prevent nameless ghosts
+ name ||= generate_random_mob_name(FALSE)
real_name = name
if(!fun_verbs)
@@ -838,7 +833,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
client.prefs.apply_character_randomization_prefs()
var/species_type = client.prefs.read_preference(/datum/preference/choiced/species)
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if(species.check_head_flags(HEAD_HAIR))
hairstyle = client.prefs.read_preference(/datum/preference/choiced/hairstyle)
hair_color = ghostify_color(client.prefs.read_preference(/datum/preference/color/hair_color))
@@ -847,8 +842,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
facial_hairstyle = client.prefs.read_preference(/datum/preference/choiced/facial_hairstyle)
facial_hair_color = ghostify_color(client.prefs.read_preference(/datum/preference/color/facial_hair_color))
- qdel(species)
-
update_appearance()
/mob/dead/observer/can_perform_action(atom/movable/target, action_bitflags)
diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
index 21943d39d3d1b..d2b5edc58cced 100644
--- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
+++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm
@@ -102,7 +102,7 @@
RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned))
RegisterSignal(src, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(on_move))
RegisterSignal(src, COMSIG_LIVING_LIFE, PROC_REF(on_life))
- set_random_revenant_name()
+ name = generate_random_mob_name()
GLOB.revenant_relay_mobs |= src
@@ -357,13 +357,13 @@
returnable_list += span_bold("Be sure to read the wiki page to learn more.")
return returnable_list
-/mob/living/basic/revenant/proc/set_random_revenant_name()
+/mob/living/basic/revenant/generate_random_mob_name()
var/list/built_name_strings = list()
built_name_strings += pick(strings(REVENANT_NAME_FILE, "spirit_type"))
built_name_strings += " of "
built_name_strings += pick(strings(REVENANT_NAME_FILE, "adverb"))
built_name_strings += pick(strings(REVENANT_NAME_FILE, "theme"))
- name = built_name_strings.Join("")
+ return built_name_strings.Join("")
/mob/living/basic/revenant/proc/on_baned(obj/item/weapon, mob/living/user)
SIGNAL_HANDLER
diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm
index adfe93d318dba..24a35e683e36d 100644
--- a/code/modules/mob/living/carbon/human/_species.dm
+++ b/code/modules/mob/living/carbon/human/_species.dm
@@ -222,14 +222,12 @@ GLOBAL_LIST_EMPTY(features_by_species)
var/list/selectable_species = list()
for(var/species_type in subtypesof(/datum/species))
- var/datum/species/species = new species_type
+ var/datum/species/species = GLOB.species_prototypes[species_type]
if(species.check_roundstart_eligible())
selectable_species += species.id
- var/datum/language_holder/temp_holder = new species.species_language_holder
+ var/datum/language_holder/temp_holder = GLOB.prototype_language_holders[species.species_language_holder]
for(var/datum/language/spoken_language as anything in temp_holder.understood_languages)
GLOB.uncommon_roundstart_languages |= spoken_language
- qdel(temp_holder)
- qdel(species)
GLOB.uncommon_roundstart_languages -= /datum/language/common
if(!selectable_species.len)
@@ -248,32 +246,6 @@ GLOBAL_LIST_EMPTY(features_by_species)
return TRUE
return FALSE
-/**
- * Generates a random name for a carbon.
- *
- * This generates a random unique name based on a human's species and gender.
- * Arguments:
- * * gender - The gender that the name should adhere to. Use MALE for male names, use anything else for female names.
- * * unique - If true, ensures that this new name is not a duplicate of anyone else's name currently on the station.
- * * last_name - Do we use a given last name or pick a random new one?
- */
-/datum/species/proc/random_name(gender, unique, last_name)
- if(unique)
- return random_unique_name(gender)
-
- var/randname
- if(gender == MALE)
- randname = pick(GLOB.first_names_male)
- else
- randname = pick(GLOB.first_names_female)
-
- if(last_name)
- randname += " [last_name]"
- else
- randname += " [pick(GLOB.last_names)]"
-
- return randname
-
/**
* Copies some vars and properties over that should be kept when creating a copy of this species.
*
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 07135351a91f2..9d3d8c2d5a81b 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -815,7 +815,7 @@
if(href_list[VV_HK_SET_SPECIES])
if(!check_rights(R_SPAWN))
return
- var/result = input(usr, "Please choose a new species","Species") as null|anything in GLOB.species_list
+ var/result = input(usr, "Please choose a new species","Species") as null|anything in sortTim(GLOB.species_list, GLOBAL_PROC_REF(cmp_text_asc))
if(result)
var/newtype = GLOB.species_list[result]
admin_ticket_log("[key_name_admin(usr)] has modified the bodyparts of [src] to [result]")
@@ -1019,7 +1019,7 @@
/mob/living/carbon/human/species/set_species(datum/species/mrace, icon_update, pref_load)
. = ..()
if(use_random_name)
- fully_replace_character_name(real_name, dna.species.random_name())
+ fully_replace_character_name(real_name, generate_random_mob_name())
/mob/living/carbon/human/species/abductor
race = /datum/species/abductor
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index c7069ad056d4d..3315c5421d376 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -259,7 +259,7 @@
if (preference.is_randomizable())
preference.apply_to_human(src, preference.create_random_value(preferences))
- fully_replace_character_name(real_name, dna.species.random_name())
+ fully_replace_character_name(real_name, generate_random_mob_name())
/**
* Setter for mob height
diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
index e37e7ca81447f..4c307107f153d 100644
--- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm
+++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm
@@ -80,14 +80,6 @@
QDEL_NULL(ethereal_light)
return ..()
-/datum/species/ethereal/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_ethereal_name()
-
- var/randname = ethereal_name()
-
- return randname
-
/datum/species/ethereal/randomize_features()
var/list/features = ..()
features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)]
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index 4e860014554e8..13471b2872b98 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -51,15 +51,6 @@
BODY_ZONE_CHEST = /obj/item/bodypart/chest/golem,
)
- /// Chance that we will generate a human surname, for lore reasons
- var/human_surname_chance = 3
-
-/datum/species/golem/random_name(gender,unique,lastname)
- var/name = pick(GLOB.golem_names)
- if (prob(human_surname_chance))
- name += " [pick(GLOB.last_names)]"
- return name
-
/datum/species/golem/get_physical_attributes()
return "Golems are hardy creatures made out of stone, which are thus naturally resistant to many dangers, including asphyxiation, fire, radiation, electricity, and viruses.\
They gain special abilities depending on the type of material consumed, but they need to consume material to keep their body animated."
diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
index 1b478162de4c6..488d76cbd2136 100644
--- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm
@@ -47,18 +47,6 @@
/datum/species/lizard/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired)
return
-/datum/species/lizard/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_lizard_name(gender)
-
- var/randname = lizard_name(gender)
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
-
/datum/species/lizard/randomize_features()
var/list/features = ..()
features["body_markings"] = pick(SSaccessories.body_markings_list)
diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
index cbd2df699ea1a..ddf0963bb5d24 100644
--- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm
+++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
@@ -41,9 +41,6 @@
payday_modifier = 1.5
ai_controlled_species = TRUE
-/datum/species/monkey/random_name(gender,unique,lastname)
- return "monkey ([rand(1, 999)])"
-
/datum/species/monkey/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load)
. = ..()
passtable_on(human_who_gained_species, SPECIES_TRAIT)
diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
index e52a19b587b9a..54d6fe027e32f 100644
--- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm
@@ -34,17 +34,6 @@
var/mob/living/carbon/human/H = C
handle_mutant_bodyparts(H)
-/datum/species/moth/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_moth_name()
-
- var/randname = moth_name()
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
/datum/species/moth/on_species_gain(mob/living/carbon/human/human_who_gained_species, datum/species/old_species, pref_load)
. = ..()
RegisterSignal(human_who_gained_species, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness))
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 2d053813e5b83..e63e3c39c4885 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -129,17 +129,6 @@
else
give_important_for_life(equipping)
-/datum/species/plasmaman/random_name(gender,unique,lastname)
- if(unique)
- return random_unique_plasmaman_name()
-
- var/randname = plasmaman_name()
-
- if(lastname)
- randname += " [lastname]"
-
- return randname
-
/datum/species/plasmaman/get_scream_sound(mob/living/carbon/human)
return pick(
'sound/voice/plasmaman/plasmeme_scream_1.ogg',
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index 36a020ce3e759..bbcf77986ac79 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -208,9 +208,9 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list(
spans |= speech_span
- if(language)
- var/datum/language/L = GLOB.language_datum_instances[language]
- spans |= L.spans
+ var/datum/language/spoken_lang = GLOB.language_datum_instances[language]
+ if(LAZYLEN(spoken_lang?.spans))
+ spans |= spoken_lang.spans
if(message_mods[MODE_SING])
var/randomnote = pick("\u2669", "\u266A", "\u266B")
diff --git a/code/modules/mob_spawn/ghost_roles/golem_roles.dm b/code/modules/mob_spawn/ghost_roles/golem_roles.dm
index b3475e9207f83..5fc643bffa622 100644
--- a/code/modules/mob_spawn/ghost_roles/golem_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/golem_roles.dm
@@ -36,8 +36,7 @@
if(forced_name || !iscarbon(spawned_mob))
return ..()
- var/datum/species/golem/golem_species = new()
- forced_name = golem_species.random_name()
+ forced_name = generate_random_name_species_based(spawned_mob.gender, TRUE, species_type = /datum/species/golem)
return ..()
/obj/effect/mob_spawn/ghost_role/human/golem/special(mob/living/new_spawn, mob/mob_possessor)
diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm
index 208a74a3edbf5..53fa001097039 100644
--- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm
@@ -194,9 +194,9 @@
/obj/structure/ash_walker_eggshell/Destroy()
if(!egg)
return ..()
- var/mob/living/carbon/human/yolk = new /mob/living/carbon/human/(get_turf(src))
- yolk.fully_replace_character_name(null,random_unique_lizard_name(gender))
+ var/mob/living/carbon/human/yolk = new(get_turf(src))
yolk.set_species(/datum/species/lizard/ashwalker)
+ yolk.fully_replace_character_name(null, yolk.generate_random_mob_name(TRUE))
yolk.underwear = "Nude"
yolk.equipOutfit(/datum/outfit/ashwalker)//this is an authentic mess we're making
yolk.update_body()
@@ -235,7 +235,7 @@
/obj/effect/mob_spawn/ghost_role/human/ash_walker/special(mob/living/carbon/human/spawned_human)
. = ..()
- spawned_human.fully_replace_character_name(null,random_unique_lizard_name(gender))
+ spawned_human.fully_replace_character_name(null, spawned_human.generate_random_mob_name(TRUE))
to_chat(spawned_human, "Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Invade the strange structure of the outsiders if you must. Do not cause unnecessary destruction, as littering the wastes with ugly wreckage is certain to not gain you favor. Glory to the Necropolis!")
spawned_human.mind.add_antag_datum(/datum/antagonist/ashwalker, team)
diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm
index 086254aae3881..ad8c7e6a03ef0 100644
--- a/code/modules/mob_spawn/mob_spawn.dm
+++ b/code/modules/mob_spawn/mob_spawn.dm
@@ -78,7 +78,7 @@
if(skin_tone)
spawned_human.skin_tone = skin_tone
else
- spawned_human.skin_tone = random_skin_tone()
+ spawned_human.skin_tone = pick(GLOB.skin_tones)
spawned_human.update_body(is_creating = TRUE)
/obj/effect/mob_spawn/proc/name_mob(mob/living/spawned_mob, forced_name)
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index 62e13ecb7f9e0..6ac45f9424d99 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -293,13 +293,12 @@
obj_flags |= EMAGGED
SSshuttle.emergency.movement_force = list("KNOCKDOWN" = 60, "THROW" = 20)//YOUR PUNY SEATBELTS can SAVE YOU NOW, MORTAL
- var/datum/species/S = new
for(var/i in 1 to 10)
// the shuttle system doesn't know who these people are, but they
// must be important, surely
var/obj/item/card/id/ID = new(src)
var/datum/job/J = pick(SSjob.joinable_occupations)
- ID.registered_name = S.random_name(pick(MALE, FEMALE))
+ ID.registered_name = generate_random_name_species_based(species_type = /datum/species/human)
ID.assignment = J.title
authorized += ID
diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm
index 9224c29b2db63..8be13802e7cbb 100644
--- a/code/modules/surgery/plastic_surgery.dm
+++ b/code/modules/surgery/plastic_surgery.dm
@@ -94,11 +94,11 @@
else
user.visible_message(span_warning("You have no picture to base the appearance on, reverting to random appearances."))
for(var/i in 1 to 10)
- names += target.dna.species.random_name(target.gender, TRUE)
+ names += target.generate_random_mob_name(TRUE)
else
- for(var/_i in 1 to 9)
+ for(var/j in 1 to 9)
names += "Subject [target.gender == MALE ? "i" : "o"]-[pick("a", "b", "c", "d", "e")]-[rand(10000, 99999)]"
- names += target.dna.species.random_name(target.gender, TRUE) //give one normal name in case they want to do regular plastic surgery
+ names += target.generate_random_mob_name(TRUE) //give one normal name in case they want to do regular plastic surgery
var/chosen_name = tgui_input_list(user, "New name to assign", "Plastic Surgery", names)
if(isnull(chosen_name))
return
diff --git a/code/modules/unit_tests/preference_species.dm b/code/modules/unit_tests/preference_species.dm
index 8e49f49cdd6a4..8d913cc8fb64d 100644
--- a/code/modules/unit_tests/preference_species.dm
+++ b/code/modules/unit_tests/preference_species.dm
@@ -12,7 +12,7 @@
for(var/species_id in get_selectable_species())
var/species_type = GLOB.species_list[species_id]
- var/datum/species/species = new species_type()
+ var/datum/species/species = GLOB.species_prototypes[species_type]
// Check the species decription.
// If it's not overridden, a stack trace will be thrown (and fail the test).
@@ -29,5 +29,3 @@
TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore().")
else if(!islist(species_lore))
TEST_FAIL("Species [species] ([species_type]) is selectable, but did not properly implement get_species_lore() (Did not return a list).")
-
- qdel(species)
diff --git a/tgstation.dme b/tgstation.dme
index 7e6bf667f0c47..c7cea8aae3a54 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -651,7 +651,6 @@
#include "code\controllers\subsystem\ipintel.dm"
#include "code\controllers\subsystem\job.dm"
#include "code\controllers\subsystem\lag_switch.dm"
-#include "code\controllers\subsystem\language.dm"
#include "code\controllers\subsystem\library.dm"
#include "code\controllers\subsystem\lighting.dm"
#include "code\controllers\subsystem\lua.dm"
@@ -4333,6 +4332,10 @@
#include "code\modules\keybindings\bindings_client.dm"
#include "code\modules\keybindings\focus.dm"
#include "code\modules\keybindings\setup.dm"
+#include "code\modules\language\_language.dm"
+#include "code\modules\language\_language_holder.dm"
+#include "code\modules\language\_language_manuals.dm"
+#include "code\modules\language\_language_menu.dm"
#include "code\modules\language\aphasia.dm"
#include "code\modules\language\beachbum.dm"
#include "code\modules\language\buzzwords.dm"
@@ -4341,10 +4344,6 @@
#include "code\modules\language\common.dm"
#include "code\modules\language\draconic.dm"
#include "code\modules\language\drone.dm"
-#include "code\modules\language\language.dm"
-#include "code\modules\language\language_holder.dm"
-#include "code\modules\language\language_manuals.dm"
-#include "code\modules\language\language_menu.dm"
#include "code\modules\language\machine.dm"
#include "code\modules\language\moffic.dm"
#include "code\modules\language\monkey.dm"
From 84b8a3d87da63699aac7b981ac9f536ad3947a38 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sun, 5 May 2024 06:23:13 +1200
Subject: [PATCH 72/87] Automatic changelog for PR #83025 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83025.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83025.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83025.yml b/html/changelogs/AutoChangeLog-pr-83025.yml
new file mode 100644
index 0000000000000..1182b19d5ebde
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83025.yml
@@ -0,0 +1,4 @@
+author: "larentoun"
+delete-after: True
+changes:
+ - bugfix: "Materials are now correctly applied to crafted items (chairs, toilets, etc)"
\ No newline at end of file
From 1a222e7e6fb74c68f29dc7152a22cd5862b666a1 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sun, 5 May 2024 06:25:44 +1200
Subject: [PATCH 73/87] Automatic changelog for PR #83030 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83030.yml | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83030.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83030.yml b/html/changelogs/AutoChangeLog-pr-83030.yml
new file mode 100644
index 0000000000000..5c70f0e277a8a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83030.yml
@@ -0,0 +1,5 @@
+author: "Jacquerel"
+delete-after: True
+changes:
+ - bugfix: "Blood Brothers should spawn knowing what their objectives are."
+ - bugfix: "Teams of 3 Blood Brothers will once more have an additional objective."
\ No newline at end of file
From 2b2d12b4b2d0f98c69c0f284efdb43baa3113d09 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Sun, 5 May 2024 06:25:47 +1200
Subject: [PATCH 74/87] Automatic changelog for PR #83021 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83021.yml | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83021.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83021.yml b/html/changelogs/AutoChangeLog-pr-83021.yml
new file mode 100644
index 0000000000000..6d9ec5542d374
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83021.yml
@@ -0,0 +1,6 @@
+author: "Melbert"
+delete-after: True
+changes:
+ - refactor: "Random Name Generation has been refactored. Report any instances of people having weird (or \"Unknown\") names."
+ - qol: "Felinids, Slimepeople, Podpeople, and some other species without defined namelists now automatically generate names based on their primary language(s)."
+ - qol: "More non-human names can be generated in codewords (and other misc. areas) than just lizard names."
\ No newline at end of file
From 386715ea08556ac369a7c104eeb004458dcb23b0 Mon Sep 17 00:00:00 2001
From: Bloop <13398309+vinylspiders@users.noreply.github.com>
Date: Sat, 4 May 2024 14:32:03 -0400
Subject: [PATCH 75/87] Makes this list a little more downstream friendly (aka
trailing comma pr) (#83028)
## About The Pull Request
That's all. Just makes this easier to add onto with less diffs involved.
## Changelog
Nothing worth mentioning
---------
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
---
code/game/objects/items/stacks/sheets/sheet_types.dm | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 36582f3ad5ac1..be6226f49bf8e 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -774,10 +774,14 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
// As bone and sinew have just a little too many recipes for this, we'll just split them up.
// Sinew slapcrafting will mostly-sinew recipes, and bones will have mostly-bones recipes.
- var/static/list/slapcraft_recipe_list = list(\
- /datum/crafting_recipe/bonedagger, /datum/crafting_recipe/bonespear, /datum/crafting_recipe/boneaxe,\
- /datum/crafting_recipe/bonearmor, /datum/crafting_recipe/skullhelm, /datum/crafting_recipe/bracers
- )
+ var/static/list/slapcraft_recipe_list = list(
+ /datum/crafting_recipe/bonearmor,
+ /datum/crafting_recipe/boneaxe,
+ /datum/crafting_recipe/bonedagger,
+ /datum/crafting_recipe/bonespear,
+ /datum/crafting_recipe/bracers,
+ /datum/crafting_recipe/skullhelm,
+ )
AddComponent(
/datum/component/slapcrafting,\
From 618bd422da9efa7cd667097906ad432056e065d5 Mon Sep 17 00:00:00 2001
From: Changelogs
Date: Sun, 5 May 2024 00:22:42 +0000
Subject: [PATCH 76/87] Automatic changelog compile [ci skip]
---
html/changelogs/AutoChangeLog-pr-83021.yml | 6 ------
html/changelogs/AutoChangeLog-pr-83025.yml | 4 ----
html/changelogs/AutoChangeLog-pr-83026.yml | 5 -----
html/changelogs/AutoChangeLog-pr-83030.yml | 5 -----
html/changelogs/archive/2024-05.yml | 19 +++++++++++++++++++
5 files changed, 19 insertions(+), 20 deletions(-)
delete mode 100644 html/changelogs/AutoChangeLog-pr-83021.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83025.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83026.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83030.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83021.yml b/html/changelogs/AutoChangeLog-pr-83021.yml
deleted file mode 100644
index 6d9ec5542d374..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83021.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "Melbert"
-delete-after: True
-changes:
- - refactor: "Random Name Generation has been refactored. Report any instances of people having weird (or \"Unknown\") names."
- - qol: "Felinids, Slimepeople, Podpeople, and some other species without defined namelists now automatically generate names based on their primary language(s)."
- - qol: "More non-human names can be generated in codewords (and other misc. areas) than just lizard names."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83025.yml b/html/changelogs/AutoChangeLog-pr-83025.yml
deleted file mode 100644
index 1182b19d5ebde..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83025.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "larentoun"
-delete-after: True
-changes:
- - bugfix: "Materials are now correctly applied to crafted items (chairs, toilets, etc)"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83026.yml b/html/changelogs/AutoChangeLog-pr-83026.yml
deleted file mode 100644
index 97760a11c77da..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83026.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Isratosh"
-delete-after: True
-changes:
- - bugfix: "If kidnapped and ransomed by pirates, you will now properly return to the station automatically after 6 minutes."
- - bugfix: "You can no longer be kidnapped and held for ransom by cargo technicians posing as pirates."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83030.yml b/html/changelogs/AutoChangeLog-pr-83030.yml
deleted file mode 100644
index 5c70f0e277a8a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83030.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Jacquerel"
-delete-after: True
-changes:
- - bugfix: "Blood Brothers should spawn knowing what their objectives are."
- - bugfix: "Teams of 3 Blood Brothers will once more have an additional objective."
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml
index 304b3ad1b73f3..0137f16cb44b7 100644
--- a/html/changelogs/archive/2024-05.yml
+++ b/html/changelogs/archive/2024-05.yml
@@ -120,3 +120,22 @@
- bugfix: Candy corn is once again available to detective fedoras
mogeoko:
- bugfix: Ventcrawling mobs can change Z-level using multiz-decks again.
+2024-05-05:
+ Isratosh:
+ - bugfix: If kidnapped and ransomed by pirates, you will now properly return to
+ the station automatically after 6 minutes.
+ - bugfix: You can no longer be kidnapped and held for ransom by cargo technicians
+ posing as pirates.
+ Jacquerel:
+ - bugfix: Blood Brothers should spawn knowing what their objectives are.
+ - bugfix: Teams of 3 Blood Brothers will once more have an additional objective.
+ Melbert:
+ - refactor: Random Name Generation has been refactored. Report any instances of
+ people having weird (or "Unknown") names.
+ - qol: Felinids, Slimepeople, Podpeople, and some other species without defined
+ namelists now automatically generate names based on their primary language(s).
+ - qol: More non-human names can be generated in codewords (and other misc. areas)
+ than just lizard names.
+ larentoun:
+ - bugfix: Materials are now correctly applied to crafted items (chairs, toilets,
+ etc)
From e766f921f6625febca526f39bfcfbe4a6dd7da58 Mon Sep 17 00:00:00 2001
From: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
Date: Sat, 4 May 2024 20:33:52 -0700
Subject: [PATCH 77/87] Code cleanup: Sorting (#83017)
## About The Pull Request
1. Removes code duplication
2. Fully documents `sortTim()`
3. Makes a define with default sortTim behavior, straight and to the
point for 95% of cases
4. Migrates other sorts into the same file
5. Removes some redundancy where they're reassigning a variable using an
in place sorter
For the record, we only use timSort
## Why It's Good For The Game
More documentation, easier to read, uses `length` over `len`, etc
Should be no gameplay effect at all
---
code/__HELPERS/hallucinations.dm | 2 +-
code/__HELPERS/sorts/InsertSort.dm | 19 ----
code/__HELPERS/sorts/MergeSort.dm | 19 ----
code/__HELPERS/sorts/TimSort.dm | 20 ----
code/__HELPERS/sorts/helpers.dm | 95 +++++++++++++++++++
.../sorts/{__main.dm => sort_instance.dm} | 0
code/controllers/subsystem/dcs.dm | 2 +-
code/datums/datum.dm | 2 +-
code/modules/admin/verbs/debug.dm | 2 +-
code/modules/admin/verbs/light_debug.dm | 2 +-
.../malf_ai/malf_ai_module_picker.dm | 2 +-
code/modules/antagonists/pirate/pirate.dm | 2 +-
code/modules/asset_cache/assets/uplink.dm | 2 +-
.../file_system/programs/emojipedia.dm | 2 +-
code/modules/research/stock_parts.dm | 2 +-
code/modules/unit_tests/unit_test.dm | 2 +-
tgstation.dme | 6 +-
17 files changed, 108 insertions(+), 73 deletions(-)
delete mode 100644 code/__HELPERS/sorts/InsertSort.dm
delete mode 100644 code/__HELPERS/sorts/MergeSort.dm
delete mode 100644 code/__HELPERS/sorts/TimSort.dm
create mode 100644 code/__HELPERS/sorts/helpers.dm
rename code/__HELPERS/sorts/{__main.dm => sort_instance.dm} (100%)
diff --git a/code/__HELPERS/hallucinations.dm b/code/__HELPERS/hallucinations.dm
index 1eeab08d87691..edd65ee926abf 100644
--- a/code/__HELPERS/hallucinations.dm
+++ b/code/__HELPERS/hallucinations.dm
@@ -145,7 +145,7 @@ ADMIN_VERB(debug_hallucination_weighted_list_per_type, R_DEBUG, "Show Hallucinat
last_type_weight = this_weight
// Sort by weight descending, where weight is the values (not the keys). We assoc_to_keys later to get JUST the text
- all_weights = sortTim(all_weights, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
+ sortTim(all_weights, GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
var/page_style = ""
var/page_contents = "[page_style][header][jointext(assoc_to_keys(all_weights), "")]
"
diff --git a/code/__HELPERS/sorts/InsertSort.dm b/code/__HELPERS/sorts/InsertSort.dm
deleted file mode 100644
index 2d5ca408ce3b3..0000000000000
--- a/code/__HELPERS/sorts/InsertSort.dm
+++ /dev/null
@@ -1,19 +0,0 @@
-//simple insertion sort - generally faster than merge for runs of 7 or smaller
-/proc/sortInsert(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0)
- if(L && L.len >= 2)
- fromIndex = fromIndex % L.len
- toIndex = toIndex % (L.len+1)
- if(fromIndex <= 0)
- fromIndex += L.len
- if(toIndex <= 0)
- toIndex += L.len + 1
-
- var/datum/sort_instance/SI = GLOB.sortInstance
- if(!SI)
- SI = new
- SI.L = L
- SI.cmp = cmp
- SI.associative = associative
-
- SI.binarySort(fromIndex, toIndex, fromIndex)
- return L
diff --git a/code/__HELPERS/sorts/MergeSort.dm b/code/__HELPERS/sorts/MergeSort.dm
deleted file mode 100644
index 4692534edffd7..0000000000000
--- a/code/__HELPERS/sorts/MergeSort.dm
+++ /dev/null
@@ -1,19 +0,0 @@
-//merge-sort - gernerally faster than insert sort, for runs of 7 or larger
-/proc/sortMerge(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex)
- if(L && L.len >= 2)
- fromIndex = fromIndex % L.len
- toIndex = toIndex % (L.len+1)
- if(fromIndex <= 0)
- fromIndex += L.len
- if(toIndex <= 0)
- toIndex += L.len + 1
-
- var/datum/sort_instance/SI = GLOB.sortInstance
- if(!SI)
- SI = new
- SI.L = L
- SI.cmp = cmp
- SI.associative = associative
-
- SI.mergeSort(fromIndex, toIndex)
- return L
diff --git a/code/__HELPERS/sorts/TimSort.dm b/code/__HELPERS/sorts/TimSort.dm
deleted file mode 100644
index 44f6d170df402..0000000000000
--- a/code/__HELPERS/sorts/TimSort.dm
+++ /dev/null
@@ -1,20 +0,0 @@
-//TimSort interface
-/proc/sortTim(list/L, cmp=/proc/cmp_numeric_asc, associative, fromIndex=1, toIndex=0)
- if(L && L.len >= 2)
- fromIndex = fromIndex % L.len
- toIndex = toIndex % (L.len+1)
- if(fromIndex <= 0)
- fromIndex += L.len
- if(toIndex <= 0)
- toIndex += L.len + 1
-
- var/datum/sort_instance/SI = GLOB.sortInstance
- if(!SI)
- SI = new
-
- SI.L = L
- SI.cmp = cmp
- SI.associative = associative
-
- SI.timSort(fromIndex, toIndex)
- return L
diff --git a/code/__HELPERS/sorts/helpers.dm b/code/__HELPERS/sorts/helpers.dm
new file mode 100644
index 0000000000000..7198286f29fe2
--- /dev/null
+++ b/code/__HELPERS/sorts/helpers.dm
@@ -0,0 +1,95 @@
+/// Sorts the list in place with timSort, default settings.
+#define SORT_TIM(to_sort, associative) if(length(to_sort) >= 2) { \
+ var/datum/sort_instance/sorter = GLOB.sortInstance; \
+ if (isnull(sorter)) { \
+ sorter = new; \
+ } \
+ sorter.L = to_sort; \
+ sorter.cmp = GLOBAL_PROC_REF(cmp_numeric_asc); \
+ sorter.associative = associative; \
+ sorter.timSort(1, 0); \
+}
+
+
+/// Helper for the sorting procs. Prevents some code duplication. Creates /datum/sort_instance/sorter
+#define CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex) \
+ if(length(to_sort) < 2) { \
+ return to_sort; \
+ } \
+ fromIndex = fromIndex % length(to_sort); \
+ toIndex = toIndex % (length(to_sort) + 1); \
+ if (fromIndex <= 0) { \
+ fromIndex += length(to_sort); \
+ } \
+ if (toIndex <= 0) { \
+ toIndex += length(to_sort) + 1; \
+ } \
+ var/datum/sort_instance/sorter = GLOB.sortInstance; \
+ if (isnull(sorter)) { \
+ sorter = new; \
+ } \
+ sorter.L = to_sort; \
+ sorter.cmp = cmp; \
+ sorter.associative = associative;
+
+
+/**
+ * ## Tim Sort
+ * Hybrid sorting algorithm derived from merge sort and insertion sort.
+ *
+ * **Sorts in place**.
+ * You might not need to get the return value.
+ *
+ * @see
+ * https://en.wikipedia.org/wiki/Timsort
+ *
+ * @param {list} to_sort - The list to sort.
+ *
+ * @param {proc} cmp - The comparison proc to use. Default: Numeric ascending.
+ *
+ * @param {boolean} associative - Whether the list is associative. Default: FALSE.
+ *
+ * @param {int} fromIndex - The index to start sorting from. Default: 1.
+ *
+ * @param {int} toIndex - The index to stop sorting at. Default: 0.
+ */
+/proc/sortTim(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
+ CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)
+
+ sorter.timSort(fromIndex, toIndex)
+
+ return to_sort
+
+
+/**
+ * ## Merge Sort
+ * Divide and conquer sorting algorithm.
+ *
+ * @see
+ * - https://en.wikipedia.org/wiki/Merge_sort
+ */
+/proc/sortMerge(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
+ CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)
+
+ sorter.mergeSort(fromIndex, toIndex)
+
+ return to_sort
+
+
+/**
+ * ## Insertion Sort
+ * Simple sorting algorithm that builds the final sorted list one item at a time.
+ *
+
+ * @see
+ * - https://en.wikipedia.org/wiki/Insertion_sort
+ */
+/proc/sortInsert(list/to_sort, cmp = GLOBAL_PROC_REF(cmp_numeric_asc), associative = FALSE, fromIndex = 1, toIndex = 0) as /list
+ CREATE_SORT_INSTANCE(to_sort, cmp, associative, fromIndex, toIndex)
+
+ sorter.binarySort(fromIndex, toIndex)
+
+ return to_sort
+
+
+#undef CREATE_SORT_INSTANCE
diff --git a/code/__HELPERS/sorts/__main.dm b/code/__HELPERS/sorts/sort_instance.dm
similarity index 100%
rename from code/__HELPERS/sorts/__main.dm
rename to code/__HELPERS/sorts/sort_instance.dm
diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm
index eefbede308739..a3dcc26af54fb 100644
--- a/code/controllers/subsystem/dcs.dm
+++ b/code/controllers/subsystem/dcs.dm
@@ -84,7 +84,7 @@ PROCESSING_SUBSYSTEM_DEF(dcs)
fullid += REF(key)
if(named_arguments)
- named_arguments = sortTim(named_arguments, GLOBAL_PROC_REF(cmp_text_asc))
+ sortTim(named_arguments, GLOBAL_PROC_REF(cmp_text_asc))
fullid += named_arguments
return list2params(fullid)
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index 77d787eb85ba0..6288244667e85 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -328,7 +328,7 @@
ASSERT(isatom(src) || isimage(src))
var/atom/atom_cast = src // filters only work with images or atoms.
atom_cast.filters = null
- filter_data = sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE)
+ sortTim(filter_data, GLOBAL_PROC_REF(cmp_filter_data_priority), TRUE)
for(var/filter_raw in filter_data)
var/list/data = filter_data[filter_raw]
var/list/arguments = data.Copy()
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index e56eb1e5101a7..20cdf3514598f 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -765,7 +765,7 @@ ADMIN_VERB(reestablish_tts_connection, R_DEBUG, "Re-establish Connection To TTS"
var/list/sorted = list()
for (var/source in per_source)
sorted += list(list("source" = source, "count" = per_source[source]))
- sorted = sortTim(sorted, GLOBAL_PROC_REF(cmp_timer_data))
+ sortTim(sorted, GLOBAL_PROC_REF(cmp_timer_data))
// Now that everything is sorted, compile them into an HTML output
var/output = ""
diff --git a/code/modules/admin/verbs/light_debug.dm b/code/modules/admin/verbs/light_debug.dm
index ae5b24ff38032..eac81f6ed294b 100644
--- a/code/modules/admin/verbs/light_debug.dm
+++ b/code/modules/admin/verbs/light_debug.dm
@@ -10,7 +10,7 @@
sum[source.source_atom.type] += 1
total += 1
- sum = sortTim(sum, /proc/cmp_numeric_asc, TRUE)
+ sortTim(sum, associative = TRUE)
var/text = ""
for(var/type in sum)
text += "[type] = [sum[type]]\n"
diff --git a/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm b/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm
index 51058f82ac02e..0ac27c14c97bf 100644
--- a/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm
+++ b/code/modules/antagonists/malf_ai/malf_ai_module_picker.dm
@@ -24,7 +24,7 @@
filtered_modules[AM.category][AM] = AM
for(var/category in filtered_modules)
- filtered_modules[category] = sortTim(filtered_modules[category], GLOBAL_PROC_REF(cmp_malfmodules_priority))
+ sortTim(filtered_modules[category], GLOBAL_PROC_REF(cmp_malfmodules_priority))
return filtered_modules
diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm
index 15a028b24d740..0fa80f5524776 100644
--- a/code/modules/antagonists/pirate/pirate.dm
+++ b/code/modules/antagonists/pirate/pirate.dm
@@ -85,7 +85,7 @@
//Lists notable loot.
if(!cargo_hold || !cargo_hold.total_report)
return "Nothing"
- cargo_hold.total_report.total_value = sortTim(cargo_hold.total_report.total_value, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
+ sortTim(cargo_hold.total_report.total_value, cmp = GLOBAL_PROC_REF(cmp_numeric_dsc), associative = TRUE)
var/count = 0
var/list/loot_texts = list()
for(var/datum/export/E in cargo_hold.total_report.total_value)
diff --git a/code/modules/asset_cache/assets/uplink.dm b/code/modules/asset_cache/assets/uplink.dm
index e283b86c04299..e85ee1b35b5c1 100644
--- a/code/modules/asset_cache/assets/uplink.dm
+++ b/code/modules/asset_cache/assets/uplink.dm
@@ -9,7 +9,7 @@
var/list/items = list()
for(var/datum/uplink_category/category as anything in subtypesof(/datum/uplink_category))
categories += category
- categories = sortTim(categories, GLOBAL_PROC_REF(cmp_uplink_category_desc))
+ sortTim(categories, GLOBAL_PROC_REF(cmp_uplink_category_desc))
var/list/new_categories = list()
for(var/datum/uplink_category/category as anything in categories)
diff --git a/code/modules/modular_computers/file_system/programs/emojipedia.dm b/code/modules/modular_computers/file_system/programs/emojipedia.dm
index 6e9bf56a381c8..10be69cc34976 100644
--- a/code/modules/modular_computers/file_system/programs/emojipedia.dm
+++ b/code/modules/modular_computers/file_system/programs/emojipedia.dm
@@ -14,7 +14,7 @@
/datum/computer_file/program/emojipedia/New()
. = ..()
// Sort the emoji list so it's easier to find things and we don't have to keep sorting on ui_data since the number of emojis can not change in-game.
- emoji_list = sortTim(emoji_list, /proc/cmp_text_asc)
+ sortTim(emoji_list, /proc/cmp_text_asc)
/datum/computer_file/program/emojipedia/ui_static_data(mob_user)
var/list/data = list()
diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm
index 79d24b9c55ab9..d4cb4afefdaf0 100644
--- a/code/modules/research/stock_parts.dm
+++ b/code/modules/research/stock_parts.dm
@@ -207,7 +207,7 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good
continue
part_list += component_part
//Sort the parts. This ensures that higher tier items are applied first.
- part_list = sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort))
+ sortTim(part_list, GLOBAL_PROC_REF(cmp_rped_sort))
return part_list
/proc/cmp_rped_sort(obj/item/first_item, obj/item/second_item)
diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm
index 332005070d5b6..9a6f89fddc353 100644
--- a/code/modules/unit_tests/unit_test.dm
+++ b/code/modules/unit_tests/unit_test.dm
@@ -340,7 +340,7 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
if(length(focused_tests))
tests_to_run = focused_tests
- tests_to_run = sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority))
+ sortTim(tests_to_run, GLOBAL_PROC_REF(cmp_unit_test_priority))
var/list/test_results = list()
diff --git a/tgstation.dme b/tgstation.dme
index c7cea8aae3a54..997e0fb51054a 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -504,10 +504,8 @@
#include "code\__HELPERS\paths\jps.dm"
#include "code\__HELPERS\paths\path.dm"
#include "code\__HELPERS\paths\sssp.dm"
-#include "code\__HELPERS\sorts\__main.dm"
-#include "code\__HELPERS\sorts\InsertSort.dm"
-#include "code\__HELPERS\sorts\MergeSort.dm"
-#include "code\__HELPERS\sorts\TimSort.dm"
+#include "code\__HELPERS\sorts\helpers.dm"
+#include "code\__HELPERS\sorts\sort_instance.dm"
#include "code\_globalvars\_regexes.dm"
#include "code\_globalvars\admin.dm"
#include "code\_globalvars\arcade.dm"
From 79ca00076b3df177b06711f873ceeb49e85ed425 Mon Sep 17 00:00:00 2001
From: paganiy <126676387+paganiy@users.noreply.github.com>
Date: Sun, 5 May 2024 16:24:46 +0300
Subject: [PATCH 78/87] Adminmod now has radiation protect module (#83040)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## About The Pull Request
Adminmod now has radprotect module
## Why It's Good For The Game
It’s kind of annoying to heal yourself every minute when you’re
experimenting with a tritium or a supermatter on a local server, so
radprotect module fixes this issue
## Changelog
:cl:
qol: Admin modsuit now has a radiation protect module
/:cl:
Co-authored-by: paganiy
---
code/modules/mod/mod_types.dm | 1 +
1 file changed, 1 insertion(+)
diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm
index f0bca6b0980d3..2789763e12cd2 100644
--- a/code/modules/mod/mod_types.dm
+++ b/code/modules/mod/mod_types.dm
@@ -596,6 +596,7 @@
/obj/item/mod/module/storage/bluespace,
/obj/item/mod/module/emp_shield/advanced,
/obj/item/mod/module/welding,
+ /obj/item/mod/module/rad_protection,
/obj/item/mod/module/stealth/ninja,
/obj/item/mod/module/quick_carry/advanced,
/obj/item/mod/module/magboot/advanced,
From 8e8cfd735315ff584b158c75c66fa4cc0f7322ab Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Mon, 6 May 2024 01:25:04 +1200
Subject: [PATCH 79/87] Automatic changelog for PR #83040 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83040.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83040.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83040.yml b/html/changelogs/AutoChangeLog-pr-83040.yml
new file mode 100644
index 0000000000000..70dc75d07193a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83040.yml
@@ -0,0 +1,4 @@
+author: "paganiy"
+delete-after: True
+changes:
+ - qol: "Admin modsuit now has a radiation protect module"
\ No newline at end of file
From 54bcab1b96e576c0eab21c31dc049a6aea3ee351 Mon Sep 17 00:00:00 2001
From: Nick
Date: Sun, 5 May 2024 19:50:18 +0200
Subject: [PATCH 80/87] Fixes traditional equipment having no name for its
crate (#83051)
## About The Pull Request
This pr fixes the missing name when you order traditional equipment then
just appearing the name
## Why It's Good For The Game
So people know what kind of crate it is at sight
## Changelog
:cl:
fix: fixes traditional equipment crate name
/:cl:
---
code/modules/cargo/packs/security.dm | 1 +
1 file changed, 1 insertion(+)
diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm
index b8e93f2815c0d..e36f9f84cacf1 100644
--- a/code/modules/cargo/packs/security.dm
+++ b/code/modules/cargo/packs/security.dm
@@ -169,6 +169,7 @@
/obj/item/clothing/mask/whistle,
/obj/item/conversion_kit,
)
+ crate_name = "traditional equipment crate"
discountable = SUPPLY_PACK_RARE_DISCOUNTABLE
/// Armory packs
From 4b10ed53426bdc1164678090ff4925403281a5b3 Mon Sep 17 00:00:00 2001
From: orange man <61334995+comfyorange@users.noreply.github.com>
Date: Mon, 6 May 2024 05:50:39 +1200
Subject: [PATCH 81/87] Automatic changelog for PR #83051 [ci skip]
---
html/changelogs/AutoChangeLog-pr-83051.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-83051.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83051.yml b/html/changelogs/AutoChangeLog-pr-83051.yml
new file mode 100644
index 0000000000000..bb64d12981df0
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-83051.yml
@@ -0,0 +1,4 @@
+author: "improvedname"
+delete-after: True
+changes:
+ - bugfix: "fixes traditional equipment crate name"
\ No newline at end of file
From 4fb33f819d5699e04d537f41a96fba902cfa7bbb Mon Sep 17 00:00:00 2001
From: Changelogs
Date: Mon, 6 May 2024 00:21:18 +0000
Subject: [PATCH 82/87] Automatic changelog compile [ci skip]
---
html/changelogs/AutoChangeLog-pr-83040.yml | 4 ----
html/changelogs/AutoChangeLog-pr-83051.yml | 4 ----
html/changelogs/archive/2024-05.yml | 5 +++++
3 files changed, 5 insertions(+), 8 deletions(-)
delete mode 100644 html/changelogs/AutoChangeLog-pr-83040.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-83051.yml
diff --git a/html/changelogs/AutoChangeLog-pr-83040.yml b/html/changelogs/AutoChangeLog-pr-83040.yml
deleted file mode 100644
index 70dc75d07193a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83040.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "paganiy"
-delete-after: True
-changes:
- - qol: "Admin modsuit now has a radiation protect module"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-83051.yml b/html/changelogs/AutoChangeLog-pr-83051.yml
deleted file mode 100644
index bb64d12981df0..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-83051.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "improvedname"
-delete-after: True
-changes:
- - bugfix: "fixes traditional equipment crate name"
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-05.yml b/html/changelogs/archive/2024-05.yml
index 0137f16cb44b7..249d2e84cee3d 100644
--- a/html/changelogs/archive/2024-05.yml
+++ b/html/changelogs/archive/2024-05.yml
@@ -139,3 +139,8 @@
larentoun:
- bugfix: Materials are now correctly applied to crafted items (chairs, toilets,
etc)
+2024-05-06:
+ improvedname:
+ - bugfix: fixes traditional equipment crate name
+ paganiy:
+ - qol: Admin modsuit now has a radiation protect module
From f29af7af9b8d58c9f402ef89e5a34745f48a381f Mon Sep 17 00:00:00 2001
From: Kyle Spier-Swenson
Date: Sun, 5 May 2024 18:53:06 -0700
Subject: [PATCH 83/87] fix ipintel caching to db not working. (#83046)
---
code/controllers/subsystem/ipintel.dm | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm
index 0f162e2a8616f..f49ad56fca54f 100644
--- a/code/controllers/subsystem/ipintel.dm
+++ b/code/controllers/subsystem/ipintel.dm
@@ -119,10 +119,10 @@ SUBSYSTEM_DEF(ipintel)
var/datum/db_query/query = SSdbcore.NewQuery(
"INSERT INTO [format_table_name("ipintel")] ( \
ip, \
- intel, \
+ intel \
) VALUES ( \
- INET_ATON(:address) \
- :result, \
+ INET_ATON(:address), \
+ :result \
)", list(
"address" = intel.address,
"result" = intel.result,
From 16d221f86d43cfc320173e1df0645887d45c5c14 Mon Sep 17 00:00:00 2001
From: oranges
Date: Mon, 6 May 2024 14:19:35 +1200
Subject: [PATCH 84/87] Fix a few mistakes I made (#82887)
Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
---
SQL/database_changelog.md | 14 ++++++--------
SQL/tgstation_schema_prefixed.sql | 13 +++++++++++++
2 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/SQL/database_changelog.md b/SQL/database_changelog.md
index 31b516f2af74e..8ae4c7d42647b 100644
--- a/SQL/database_changelog.md
+++ b/SQL/database_changelog.md
@@ -16,17 +16,15 @@ INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 27);
In any query remember to add a prefix to the table names if you use one.
-----------------------------------------------------
Version 5.27, 26 April 2024, by zephyrtfa
-Add the ip intel table
+Add the ip intel whitelist table
```sql
-DROP TABLE IF EXISTS `ipintel`;
+DROP TABLE IF EXISTS `ipintel_whitelist`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `ipintel` (
- `ip` int(10) unsigned NOT NULL,
- `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
- `intel` double NOT NULL DEFAULT '0',
- PRIMARY KEY (`ip`),
- KEY `idx_ipintel` (`ip`,`intel`,`date`)
+CREATE TABLE `ipintel_whitelist` (
+ `ckey` varchar(32) NOT NULL,
+ `admin_ckey` varchar(32) NOT NULL,
+ PRIMARY KEY (`ckey`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
```
diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql
index 597281f2c2076..fb9a6cbe10fa4 100644
--- a/SQL/tgstation_schema_prefixed.sql
+++ b/SQL/tgstation_schema_prefixed.sql
@@ -214,6 +214,19 @@ CREATE TABLE `SS13_ipintel` (
KEY `idx_ipintel` (`ip`,`intel`,`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `ipintel_whitelist`
+--
+
+DROP TABLE IF EXISTS `SS13_ipintel_whitelist`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `SS13_ipintel_whitelist` (
+ `ckey` varchar(32) NOT NULL,
+ `admin_ckey` varchar(32) NOT NULL,
+ PRIMARY KEY (`ckey`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `SS13_legacy_population`
From 63b019f5d5adad13cd37393b64a69b654958f938 Mon Sep 17 00:00:00 2001
From: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
Date: Mon, 6 May 2024 02:20:03 +0000
Subject: [PATCH 85/87] Fixes auxtools hanging on server shutdown. (#83050)
## About The Pull Request
Does a full shutdown of auxlua when the lua subsystem shuts down. This
should unpin the dll file.
Compare `AUXTOOLS_SHUTDOWN` code with `AUXTOOLS_FULL_SHUTDOWN`, let me
know if I'm mistaken:
### AUXTOOLS_SHUTDOWN
https://github.com/willox/auxtools/blob/bc5b2cf019f0f9b18f46b560a0f730d709171b55/auxtools/src/lib.rs#L346
### AUXTOOLS_FULL_SHUTDOWN
https://github.com/willox/auxtools/blob/bc5b2cf019f0f9b18f46b560a0f730d709171b55/auxtools/src/lib.rs#L365
## Why It's Good For The Game
Fixes auxlua keeping the dll pinned when the server is in a process of
shutting down.
Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
---
code/controllers/subsystem/lua.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/controllers/subsystem/lua.dm b/code/controllers/subsystem/lua.dm
index b9ad7dc1644e3..1ab88a01746b7 100644
--- a/code/controllers/subsystem/lua.dm
+++ b/code/controllers/subsystem/lua.dm
@@ -53,7 +53,7 @@ SUBSYSTEM_DEF(lua)
world.SetConfig("env", "LUAU_PATH", jointext(lua_path, ";"))
/datum/controller/subsystem/lua/Shutdown()
- AUXTOOLS_SHUTDOWN(AUXLUA)
+ AUXTOOLS_FULL_SHUTDOWN(AUXLUA)
/datum/controller/subsystem/lua/proc/queue_resume(datum/lua_state/state, index, arguments)
if(!initialized)
From 6edd087e173bda1f2558a9341f9377e9e2b8e226 Mon Sep 17 00:00:00 2001
From: "candle :)" <68376391+CandleJaxx@users.noreply.github.com>
Date: Sun, 5 May 2024 21:20:34 -0500
Subject: [PATCH 86/87] three more pais (#83038)
## About The Pull Request
adds three pai skins, puppy / kitty / spider
![Screenshot_002](https://github.com/tgstation/tgstation/assets/68376391/9c6a65b1-ae05-40a2-97a0-8083e81397d2)
![Screenshot_003](https://github.com/tgstation/tgstation/assets/68376391/2f45d0d2-218c-4caa-8529-26222254fc4f)
![Screenshot_004](https://github.com/tgstation/tgstation/assets/68376391/3b1a0bf7-81d5-465d-acfe-145252b4adb0)
![Screenshot_005](https://github.com/tgstation/tgstation/assets/68376391/b6bf75f9-bc60-4b11-8393-59ae2fed90b6)
![Screenshot_001](https://github.com/tgstation/tgstation/assets/68376391/a80cdf8b-85a1-4305-bcbf-333fe1a39bfc)
![Screenshot_007](https://github.com/tgstation/tgstation/assets/68376391/17c99793-0f95-4724-8a27-3b52449a1487)
![Screenshot_008](https://github.com/tgstation/tgstation/assets/68376391/83f23d0b-3fbf-455e-8181-e118c691eb38)
![Screenshot_009](https://github.com/tgstation/tgstation/assets/68376391/d8cb1bf0-4daa-491d-80d6-1e162302c5cf)
![Screenshot_010](https://github.com/tgstation/tgstation/assets/68376391/3cd34b0a-363b-4739-b30d-a934b3c68782)
![Screenshot_006](https://github.com/tgstation/tgstation/assets/68376391/1a310903-5e6a-496e-b32e-781fe9130c78)
## Why It's Good For The Game
bounty request downstream, thought i'd push it up here incase yall
wanted it too
## Changelog
:cl:
add: 'puppy' 'kitten' and 'spider' pai skins
/:cl:
---
code/modules/pai/pai.dm | 3 +++
icons/mob/silicon/pai.dmi | Bin 64479 -> 66821 bytes
2 files changed, 3 insertions(+)
diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm
index 428bfd33fce41..2f050f11a5fb0 100644
--- a/code/modules/pai/pai.dm
+++ b/code/modules/pai/pai.dm
@@ -119,6 +119,9 @@
"mouse" = TRUE,
"rabbit" = TRUE,
"repairbot" = TRUE,
+ "kitten" = TRUE,
+ "puppy" = TRUE,
+ "spider" = TRUE,
)
/// List of all available card overlays.
var/static/list/possible_overlays = list(
diff --git a/icons/mob/silicon/pai.dmi b/icons/mob/silicon/pai.dmi
index 2be986d411dbef5035d7eeef957fa3f7bc198906..260b175f3ae3f7f85729ac365183b3bd166ce4c0 100644
GIT binary patch
literal 66821
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