diff --git a/Content.IntegrationTests/DMProject/Tests/atom_appearance.dm b/Content.IntegrationTests/DMProject/Tests/atom_appearance.dm
new file mode 100644
index 0000000000..4b07dda7e3
--- /dev/null
+++ b/Content.IntegrationTests/DMProject/Tests/atom_appearance.dm
@@ -0,0 +1,10 @@
+/obj/thingtocopy
+ name = "hello"
+ desc = "this is a thing"
+
+/proc/test_appearance()
+ var/obj/thingtocopy/T = new()
+ var/obj/otherthing = new()
+ otherthing.appearance = T.appearance
+ ASSERT(otherthing.name == T.name)
+ ASSERT(otherthing.desc == T.desc)
\ No newline at end of file
diff --git a/Content.IntegrationTests/DMProject/Tests/string_interpolation.dm b/Content.IntegrationTests/DMProject/Tests/string_interpolation.dm
new file mode 100644
index 0000000000..f64128b0c1
--- /dev/null
+++ b/Content.IntegrationTests/DMProject/Tests/string_interpolation.dm
@@ -0,0 +1,13 @@
+/obj/blombo
+ name = "Blombo"
+ gender = FEMALE
+
+/obj/blorpo
+ name = "Blorpo"
+ gender = MALE
+
+/proc/test_string_interpolation()
+ var/obj/blombo/b = new
+ var/obj/blorpo/b2 = new
+ var/result_text = "[b]? Nobody likes \him. \He is awful! Unlike [b2]. \He is pretty cool!"
+ ASSERT(result_text == "Blombo? Nobody likes her. She is awful! Unlike Blorpo. He is pretty cool!")
\ No newline at end of file
diff --git a/Content.IntegrationTests/DMProject/code.dm b/Content.IntegrationTests/DMProject/code.dm
index 894fc35758..6e6827200f 100644
--- a/Content.IntegrationTests/DMProject/code.dm
+++ b/Content.IntegrationTests/DMProject/code.dm
@@ -30,7 +30,9 @@
test_color_matrix()
test_range()
test_verb_duplicate()
+ test_appearance()
test_nonlocal_var()
test_images()
test_filter_init()
+ test_string_interpolation()
world.log << "IntegrationTests successful, /world/New() exiting..."
\ No newline at end of file
diff --git a/Content.IntegrationTests/DMProject/environment.dme b/Content.IntegrationTests/DMProject/environment.dme
index aa33082512..80f5c14baf 100644
--- a/Content.IntegrationTests/DMProject/environment.dme
+++ b/Content.IntegrationTests/DMProject/environment.dme
@@ -1,4 +1,5 @@
#include "code.dm"
+#include "Tests/atom_appearance.dm"
#include "Tests/block.dm"
#include "Tests/color_matrix.dm"
#include "Tests/range.dm"
@@ -6,5 +7,6 @@
#include "Tests/nonlocal_var.dm"
#include "Tests/image.dm"
#include "Tests/filter_initial.dm"
+#include "Tests/string_interpolation.dm"
#include "map.dmm"
#include "interface.dmf"
\ No newline at end of file
diff --git a/Content.Tests/DMProject/Tests/Preprocessor/macro_newline_var.dm b/Content.Tests/DMProject/Tests/Preprocessor/macro_newline_var.dm
index 2d2d609cc8..4aa1d76373 100644
--- a/Content.Tests/DMProject/Tests/Preprocessor/macro_newline_var.dm
+++ b/Content.Tests/DMProject/Tests/Preprocessor/macro_newline_var.dm
@@ -1,8 +1,10 @@
+/datum/var/name
+
#define DEFINE_FLOORS(_PATH, _VARS) \
- /obj/simulated/floor/_PATH{_VARS};\
- /obj/unsimulated/floor/_PATH{_VARS};\
- /obj/simulated/floor/airless/_PATH{_VARS};\
- /obj/unsimulated/floor/airless/_PATH{_VARS};
+ /datum/simulated/floor/_PATH{_VARS};\
+ /datum/unsimulated/floor/_PATH{_VARS};\
+ /datum/simulated/floor/airless/_PATH{_VARS};\
+ /datum/unsimulated/floor/airless/_PATH{_VARS};
var/list/gvars_datum_init_order = list()
@@ -42,8 +44,8 @@ proc/RunTest()
ASSERT(test.len == 4)
InitGlobaltest2()
ASSERT(test2.len == 2)
- var/obj/simulated/floor/carpet/regalcarpet/C1 = new()
- var/obj/simulated/floor/carpet/regalcarpet/border/C2 = new()
+ var/datum/simulated/floor/carpet/regalcarpet/C1 = new()
+ var/datum/simulated/floor/carpet/regalcarpet/border/C2 = new()
ASSERT(C1.name == "regal carpet")
ASSERT(C2.name == "regal carpet border")
diff --git a/Content.Tests/DMProject/Tests/Preprocessor/macro_numeric_path.dm b/Content.Tests/DMProject/Tests/Preprocessor/macro_numeric_path.dm
index a3d4448a56..2adb74318d 100644
--- a/Content.Tests/DMProject/Tests/Preprocessor/macro_numeric_path.dm
+++ b/Content.Tests/DMProject/Tests/Preprocessor/macro_numeric_path.dm
@@ -1,15 +1,17 @@
-/obj/thing_1/dodaa
+/datum/var/name
+
+/datum/thing_1/dodaa
name = "underscore 1 test"
-#define NUMPATH_OBJDEF(num) /obj/thing_##num/name = #num
+#define NUMPATH_OBJDEF(num) /datum/thing_##num/name = #num
NUMPATH_OBJDEF(4)
NUMPATH_OBJDEF(stuff)
/proc/RunTest()
- var/obj/thing_1/dodaa/D = new
+ var/datum/thing_1/dodaa/D = new
ASSERT(D.name == "underscore 1 test")
- var/obj/thing_4/T = new
+ var/datum/thing_4/T = new
ASSERT(T.name == "4")
- var/obj/thing_stuff/Y = new
+ var/datum/thing_stuff/Y = new
ASSERT(Y.name == "stuff")
\ No newline at end of file
diff --git a/Content.Tests/DMProject/Tests/Text/StringInterpolation2.dm b/Content.Tests/DMProject/Tests/Text/StringInterpolation2.dm
index 385d9c0c88..1322bff03a 100644
--- a/Content.Tests/DMProject/Tests/Text/StringInterpolation2.dm
+++ b/Content.Tests/DMProject/Tests/Text/StringInterpolation2.dm
@@ -1,8 +1,8 @@
-/obj/blombo
- name = "Blombo"
+/datum/blombo
+ var/name = "Blombo"
/proc/RunTest()
- var/obj/blombo/b = new
+ var/datum/blombo/b = new
var/result_text = "Nobody likes [b]!"
ASSERT(result_text == "Nobody likes Blombo!")
diff --git a/Content.Tests/DMProject/Tests/Text/StringInterpolation3.dm b/Content.Tests/DMProject/Tests/Text/StringInterpolation3.dm
index 54cb329034..20bea3f509 100644
--- a/Content.Tests/DMProject/Tests/Text/StringInterpolation3.dm
+++ b/Content.Tests/DMProject/Tests/Text/StringInterpolation3.dm
@@ -1,14 +1,23 @@
+/datum/test/var/name
-/obj/blombo
- name = "Blombo"
- gender = FEMALE
-
-/obj/blorpo
- name = "Blorpo"
- gender = MALE
+/datum/test/test1
+ name = ""
+/datum/test/test2
+ name = " " // 3 spaces
+/datum/test/test3
+ name = "\t"
/proc/RunTest()
- var/obj/blombo/b = new
- var/obj/blorpo/b2 = new
- var/result_text = "[b]? Nobody likes \him. \He is awful! Unlike [b2]. \He is pretty cool!"
- ASSERT(result_text == "Blombo? Nobody likes her. She is awful! Unlike Blorpo. He is pretty cool!")
+ var/list/correct = list(
+ "/datum/test/test1: ",
+ "/datum/test/test2: ",
+ "/datum/test/test3: \t"
+ )
+ var/i = 1
+ for (var/T in typesof(/datum/test))
+ if(T == /datum/test)
+ continue
+ var/datum/test/D = new T()
+ var/true_text = correct[i]
+ ASSERT(true_text == "[T]: \the [D]")
+ ++i
diff --git a/Content.Tests/DMProject/Tests/Text/StringInterpolation4.dm b/Content.Tests/DMProject/Tests/Text/StringInterpolation4.dm
index 5688dd1030..e960741bb0 100644
--- a/Content.Tests/DMProject/Tests/Text/StringInterpolation4.dm
+++ b/Content.Tests/DMProject/Tests/Text/StringInterpolation4.dm
@@ -1,21 +1,15 @@
-/obj/test1
- name = ""
-/obj/test2
- name = " " // 3 spaces
-/obj/test3
- name = "\t"
+
/proc/RunTest()
- var/list/correct = list(
- "/obj/test1: ",
- "/obj/test2: ",
- "/obj/test3: \t"
- )
- var/i = 1
- for (var/T in typesof(/obj))
- if(T == /obj)
- continue
- var/obj/O = new T()
- var/true_text = correct[i]
- ASSERT(true_text == "[T]: \the [O]")
- ++i
+ var/text = "["1"]\s"
+ ASSERT(text == "1s")
+ text = "[0]\s"
+ ASSERT(text == "0s")
+ text = "[null]\s"
+ ASSERT(text == "s")
+ text = "[1]\s"
+ ASSERT(text == "1")
+ text = "[1.00000001]\s"
+ ASSERT(text == "1")
+ text = "[1.0001]\s"
+ ASSERT(text == "1.0001s")
diff --git a/Content.Tests/DMProject/Tests/Text/StringInterpolation5.dm b/Content.Tests/DMProject/Tests/Text/StringInterpolation5.dm
index fc768b0371..d2b0eeb0cd 100644
--- a/Content.Tests/DMProject/Tests/Text/StringInterpolation5.dm
+++ b/Content.Tests/DMProject/Tests/Text/StringInterpolation5.dm
@@ -1,11 +1,30 @@
/proc/RunTest()
- var/atom/O = new()
- O.name = "foo"
- O.gender = FEMALE
- var/atom/O2 = new
- O2.name = "foob"
- O2.gender = MALE
- var/text = "[O2], \ref[O], \his"
- ASSERT(findtextEx(text,", his") != 0)
+ var/text = "[0]\th"
+ ASSERT(text == "0th")
+ text = "[1]\th"
+ ASSERT(text == "1st")
+ text = "[2]\th"
+ ASSERT(text == "2nd")
+ text = "[3]\th"
+ ASSERT(text == "3rd")
+ text = "[4]\th"
+ ASSERT(text == "4th")
+ text = "[-1]\th"
+ ASSERT(text == "-1th")
+ text = "[4.52]\th"
+ ASSERT(text == "4th")
+ text = "the fitness [1.7]\th is a"
+ ASSERT(text == "the fitness 1st is a")
+ text = "the fitness [99999999]\th is a"
+ ASSERT(text == "the fitness 100000000th is a")
+ text = "[null]\th"
+ ASSERT(text == "0th")
+ var/datum/D = new
+ text = "[D]\th"
+ ASSERT(text == "0th")
+ var/foo = "bar"
+ text = "[foo]\th"
+ ASSERT(text == "0th")
+
diff --git a/Content.Tests/DMProject/Tests/Text/StringInterpolation6.dm b/Content.Tests/DMProject/Tests/Text/StringInterpolation6.dm
index e960741bb0..4d9b638105 100644
--- a/Content.Tests/DMProject/Tests/Text/StringInterpolation6.dm
+++ b/Content.Tests/DMProject/Tests/Text/StringInterpolation6.dm
@@ -1,15 +1,11 @@
-
-
-/proc/RunTest()
- var/text = "["1"]\s"
- ASSERT(text == "1s")
- text = "[0]\s"
- ASSERT(text == "0s")
- text = "[null]\s"
- ASSERT(text == "s")
- text = "[1]\s"
- ASSERT(text == "1")
- text = "[1.00000001]\s"
- ASSERT(text == "1")
- text = "[1.0001]\s"
- ASSERT(text == "1.0001s")
+/proc/RunTest()
+ ASSERT("\roman[1.5]" == "i")
+ ASSERT("\roman [1.5]" == " i")
+ ASSERT("\Roman[1.5]" == "I")
+ ASSERT("\Roman [1.5]" == " I")
+ ASSERT("\roman shitposts [1]" == " shitposts i")
+ ASSERT("\roman shitposts [1] \the [2] [3]\s" == " shitposts i 3s")
+ ASSERT("\roman[1.#INF]" == "∞")
+ ASSERT("\roman[-1.#INF]" == "-∞")
+ ASSERT("\roman [-1.#INF]" == " -∞")
+ ASSERT("\roman[1.#IND]" == "�")
\ No newline at end of file
diff --git a/Content.Tests/DMProject/Tests/Text/StringInterpolation7.dm b/Content.Tests/DMProject/Tests/Text/StringInterpolation7.dm
index d2b0eeb0cd..9ff619a52a 100644
--- a/Content.Tests/DMProject/Tests/Text/StringInterpolation7.dm
+++ b/Content.Tests/DMProject/Tests/Text/StringInterpolation7.dm
@@ -1,30 +1,39 @@
+/datum/thing
+ var/name = "thing"
+/datum/Thing
+ var/name = "Thing"
+
+/datum/proper_thing
+ var/name = "\proper thing"
+
+/datum/plural_things
+ var/name = "things"
+ var/gender = PLURAL
/proc/RunTest()
- var/text = "[0]\th"
- ASSERT(text == "0th")
- text = "[1]\th"
- ASSERT(text == "1st")
- text = "[2]\th"
- ASSERT(text == "2nd")
- text = "[3]\th"
- ASSERT(text == "3rd")
- text = "[4]\th"
- ASSERT(text == "4th")
- text = "[-1]\th"
- ASSERT(text == "-1th")
- text = "[4.52]\th"
- ASSERT(text == "4th")
- text = "the fitness [1.7]\th is a"
- ASSERT(text == "the fitness 1st is a")
- text = "the fitness [99999999]\th is a"
- ASSERT(text == "the fitness 100000000th is a")
- text = "[null]\th"
- ASSERT(text == "0th")
- var/datum/D = new
- text = "[D]\th"
- ASSERT(text == "0th")
- var/foo = "bar"
- text = "[foo]\th"
- ASSERT(text == "0th")
+ // Lowercase \a on datums
+ ASSERT("\a [new /datum/thing]" == "a thing")
+ ASSERT("\a [new /datum/Thing]" == "Thing")
+ ASSERT("\a [new /datum/proper_thing]" == "thing")
+ ASSERT("\a [new /datum/plural_things]" == "some things")
+
+ // Uppercase \A on datums
+ ASSERT("\A [new /datum/thing]" == "A thing")
+ ASSERT("\A [new /datum/Thing]" == "Thing")
+ ASSERT("\A [new /datum/proper_thing]" == "thing")
+ ASSERT("\A [new /datum/plural_things]" == "Some things")
+
+ // Lowercase \a on strings
+ ASSERT("\a ["thing"]" == "a thing")
+ ASSERT("\a ["Thing"]" == "Thing")
+ ASSERT("\a ["\proper thing"]" == "thing")
+
+ // Uppercase \A on strings
+ ASSERT("\A ["thing"]" == "A thing")
+ ASSERT("\A ["Thing"]" == "Thing")
+ ASSERT("\A ["\proper thing"]" == "thing")
+ // Invalid \a
+ ASSERT("\a [123]" == "")
+ ASSERT("\A [123]" == "")
\ No newline at end of file
diff --git a/Content.Tests/DMProject/Tests/Text/StringInterpolation8.dm b/Content.Tests/DMProject/Tests/Text/StringInterpolation8.dm
deleted file mode 100644
index 4d9b638105..0000000000
--- a/Content.Tests/DMProject/Tests/Text/StringInterpolation8.dm
+++ /dev/null
@@ -1,11 +0,0 @@
-/proc/RunTest()
- ASSERT("\roman[1.5]" == "i")
- ASSERT("\roman [1.5]" == " i")
- ASSERT("\Roman[1.5]" == "I")
- ASSERT("\Roman [1.5]" == " I")
- ASSERT("\roman shitposts [1]" == " shitposts i")
- ASSERT("\roman shitposts [1] \the [2] [3]\s" == " shitposts i 3s")
- ASSERT("\roman[1.#INF]" == "∞")
- ASSERT("\roman[-1.#INF]" == "-∞")
- ASSERT("\roman [-1.#INF]" == " -∞")
- ASSERT("\roman[1.#IND]" == "�")
\ No newline at end of file
diff --git a/Content.Tests/DMProject/Tests/Text/StringInterpolation9.dm b/Content.Tests/DMProject/Tests/Text/StringInterpolation9.dm
deleted file mode 100644
index 9ff619a52a..0000000000
--- a/Content.Tests/DMProject/Tests/Text/StringInterpolation9.dm
+++ /dev/null
@@ -1,39 +0,0 @@
-/datum/thing
- var/name = "thing"
-
-/datum/Thing
- var/name = "Thing"
-
-/datum/proper_thing
- var/name = "\proper thing"
-
-/datum/plural_things
- var/name = "things"
- var/gender = PLURAL
-
-/proc/RunTest()
- // Lowercase \a on datums
- ASSERT("\a [new /datum/thing]" == "a thing")
- ASSERT("\a [new /datum/Thing]" == "Thing")
- ASSERT("\a [new /datum/proper_thing]" == "thing")
- ASSERT("\a [new /datum/plural_things]" == "some things")
-
- // Uppercase \A on datums
- ASSERT("\A [new /datum/thing]" == "A thing")
- ASSERT("\A [new /datum/Thing]" == "Thing")
- ASSERT("\A [new /datum/proper_thing]" == "thing")
- ASSERT("\A [new /datum/plural_things]" == "Some things")
-
- // Lowercase \a on strings
- ASSERT("\a ["thing"]" == "a thing")
- ASSERT("\a ["Thing"]" == "Thing")
- ASSERT("\a ["\proper thing"]" == "thing")
-
- // Uppercase \A on strings
- ASSERT("\A ["thing"]" == "A thing")
- ASSERT("\A ["Thing"]" == "Thing")
- ASSERT("\A ["\proper thing"]" == "thing")
-
- // Invalid \a
- ASSERT("\a [123]" == "")
- ASSERT("\A [123]" == "")
\ No newline at end of file
diff --git a/OpenDream.sln.DotSettings b/OpenDream.sln.DotSettings
index 3c4c83094e..9303eadec4 100644
--- a/OpenDream.sln.DotSettings
+++ b/OpenDream.sln.DotSettings
@@ -10,6 +10,7 @@
1
1
AABB
+ RT
DM
DMF
DMI
diff --git a/OpenDreamClient/Interface/DebugWindows/IconDebugWindow.xaml.cs b/OpenDreamClient/Interface/DebugWindows/IconDebugWindow.xaml.cs
index bbdec962a0..338956b9f4 100644
--- a/OpenDreamClient/Interface/DebugWindows/IconDebugWindow.xaml.cs
+++ b/OpenDreamClient/Interface/DebugWindows/IconDebugWindow.xaml.cs
@@ -45,6 +45,7 @@ private void Update() {
// Would be nice if we could use ViewVariables instead, but I couldn't find a nice way to do that
// Would be especially nice if we could use VV to make these editable
AddPropertyIfNotDefault("Name", appearance.Name, MutableAppearance.Default.Name);
+ AddPropertyIfNotDefault("Desc", appearance.Desc, MutableAppearance.Default.Desc);
AddPropertyIfNotDefault("Icon State", appearance.IconState, MutableAppearance.Default.IconState);
AddPropertyIfNotDefault("Direction", appearance.Direction, MutableAppearance.Default.Direction);
AddPropertyIfNotDefault("Inherits Direction", appearance.InheritsDirection, MutableAppearance.Default.InheritsDirection);
diff --git a/OpenDreamClient/Rendering/DMISpriteSystem.cs b/OpenDreamClient/Rendering/DMISpriteSystem.cs
index 46f9e10069..562f27a7be 100644
--- a/OpenDreamClient/Rendering/DMISpriteSystem.cs
+++ b/OpenDreamClient/Rendering/DMISpriteSystem.cs
@@ -39,7 +39,9 @@ public override void Shutdown() {
}
private void OnIconSizeChanged(EntityUid uid) {
- _entityManager.TryGetComponent(uid, out var transform);
+ if (!_entityManager.TryGetComponent(uid, out var transform))
+ return;
+
_lookupSystem.FindAndAddToEntityTree(uid, xform: transform);
}
diff --git a/OpenDreamRuntime/AtomManager.cs b/OpenDreamRuntime/AtomManager.cs
index eef1f98338..0a376bce57 100644
--- a/OpenDreamRuntime/AtomManager.cs
+++ b/OpenDreamRuntime/AtomManager.cs
@@ -233,6 +233,7 @@ public void DeleteMovableEntity(DreamObjectMovable movable) {
public bool IsValidAppearanceVar(string name) {
switch (name) {
case "name":
+ case "desc":
case "icon":
case "icon_state":
case "dir":
@@ -277,6 +278,10 @@ public void SetAppearanceVar(MutableAppearance appearance, string varName, Dream
value.TryGetValueAsString(out var name);
appearance.Name = name ?? string.Empty;
break;
+ case "desc":
+ value.TryGetValueAsString(out var desc);
+ appearance.Desc = desc;
+ break;
case "icon":
if (_resourceManager.TryLoadIcon(value, out var icon)) {
appearance.Icon = icon.Id;
@@ -439,6 +444,10 @@ public DreamValue GetAppearanceVar(ImmutableAppearance appearance, string varNam
switch (varName) {
case "name":
return new(appearance.Name);
+ case "desc":
+ if (appearance.Desc == null)
+ return DreamValue.Null;
+ return new(appearance.Desc);
case "icon":
if (appearance.Icon == null)
return DreamValue.Null;
@@ -551,9 +560,9 @@ public DreamValue GetAppearanceVar(ImmutableAppearance appearance, string varNam
/// The atom to find the appearance of.
public ImmutableAppearance MustGetAppearance(DreamObject atom) {
return atom switch {
+ DreamObjectArea area => area.Appearance,
DreamObjectTurf turf => turf.Appearance,
DreamObjectMovable movable => movable.SpriteComponent.Appearance!,
- DreamObjectArea area => area.Appearance,
DreamObjectImage image => image.IsMutableAppearance ? AppearanceSystem!.AddAppearance(image.MutableAppearance!, registerAppearance: false) : image.SpriteComponent!.Appearance!,
_ => throw new Exception($"Cannot get appearance of {atom}")
};
@@ -563,16 +572,15 @@ public ImmutableAppearance MustGetAppearance(DreamObject atom) {
/// Optionally looks up for an appearance. Does not try to create a new one when one is not found for this atom.
///
public bool TryGetAppearance(DreamObject atom, [NotNullWhen(true)] out ImmutableAppearance? appearance) {
- if (atom is DreamObjectTurf turf)
- appearance = turf.Appearance;
- else if (atom is DreamObjectMovable { SpriteComponent.Appearance: not null } movable)
- appearance = movable.SpriteComponent.Appearance;
- else if (atom is DreamObjectImage image)
- appearance = image.IsMutableAppearance ? AppearanceSystem!.AddAppearance(image.MutableAppearance!, registerAppearance: false) : image.SpriteComponent?.Appearance;
- else if (atom is DreamObjectArea area)
- appearance = area.Appearance;
- else
- appearance = null;
+ appearance = atom switch {
+ DreamObjectArea area => area.Appearance,
+ DreamObjectTurf turf => turf.Appearance,
+ DreamObjectMovable { SpriteComponent.Appearance: { } movableAppearance } => movableAppearance,
+ DreamObjectImage image => image.IsMutableAppearance
+ ? AppearanceSystem!.AddAppearance(image.MutableAppearance!, registerAppearance: false)
+ : image.SpriteComponent?.Appearance,
+ _ => null
+ };
return appearance is not null;
}
@@ -692,6 +700,7 @@ public MutableAppearance GetAppearanceFromDefinition(DreamObjectDefinition def)
return appearance;
def.TryGetVariable("name", out var nameVar);
+ def.TryGetVariable("desc", out var descVar);
def.TryGetVariable("icon", out var iconVar);
def.TryGetVariable("icon_state", out var stateVar);
def.TryGetVariable("color", out var colorVar);
@@ -712,6 +721,7 @@ public MutableAppearance GetAppearanceFromDefinition(DreamObjectDefinition def)
appearance = MutableAppearance.Get();
SetAppearanceVar(appearance, "name", nameVar);
+ SetAppearanceVar(appearance, "desc", descVar);
SetAppearanceVar(appearance, "icon", iconVar);
SetAppearanceVar(appearance, "icon_state", stateVar);
SetAppearanceVar(appearance, "color", colorVar);
diff --git a/OpenDreamRuntime/Objects/DreamObject.cs b/OpenDreamRuntime/Objects/DreamObject.cs
index 19794ab9b0..e3e4389248 100644
--- a/OpenDreamRuntime/Objects/DreamObject.cs
+++ b/OpenDreamRuntime/Objects/DreamObject.cs
@@ -376,10 +376,15 @@ public string GetNameUnformatted() {
///
/// Returns the name of this object with no formatting evaluated
///
- ///
public string GetRawName() {
- if (!TryGetVariable("name", out DreamValue nameVar) || !nameVar.TryGetValueAsString(out string? name))
- return ObjectDefinition.Type.ToString();
+ string name = ObjectDefinition.Type;
+
+ if (this is DreamObjectAtom) {
+ if (AtomManager.TryGetAppearance(this, out var appearance))
+ name = appearance.Name;
+ } else if (TryGetVariable("name", out DreamValue nameVar) && nameVar.TryGetValueAsString(out var nameVarStr)) {
+ name = nameVarStr;
+ }
return name;
}
diff --git a/OpenDreamRuntime/Objects/Types/DreamObjectAtom.cs b/OpenDreamRuntime/Objects/Types/DreamObjectAtom.cs
index 63f7a47e29..20cba60f33 100644
--- a/OpenDreamRuntime/Objects/Types/DreamObjectAtom.cs
+++ b/OpenDreamRuntime/Objects/Types/DreamObjectAtom.cs
@@ -4,8 +4,6 @@ namespace OpenDreamRuntime.Objects.Types;
[Virtual]
public class DreamObjectAtom : DreamObject {
- public string? Name;
- public string? Desc;
public readonly DreamOverlaysList Overlays;
public readonly DreamOverlaysList Underlays;
public readonly DreamVisContentsList VisContents;
@@ -21,11 +19,6 @@ public DreamObjectAtom(DreamObjectDefinition objectDefinition) : base(objectDefi
AtomManager.AddAtom(this);
}
- public override void Initialize(DreamProcArguments args) {
- ObjectDefinition.Variables["name"].TryGetValueAsString(out Name);
- ObjectDefinition.Variables["desc"].TryGetValueAsString(out Desc);
- }
-
protected override void HandleDeletion(bool possiblyThreaded) {
// SAFETY: RemoveAtom is not threadsafe.
if (possiblyThreaded) {
@@ -38,6 +31,13 @@ protected override void HandleDeletion(bool possiblyThreaded) {
base.HandleDeletion(possiblyThreaded);
}
+ public string GetRTEntityDesc() {
+ if (AtomManager.TryGetAppearance(this, out var appearance) && appearance.Desc != null)
+ return appearance.Desc;
+
+ return ObjectDefinition.Type;
+ }
+
protected override bool TryGetVar(string varName, out DreamValue value) {
switch (varName) {
// x/y/z/loc should be overriden by subtypes
@@ -49,13 +49,6 @@ protected override bool TryGetVar(string varName, out DreamValue value) {
case "loc":
value = DreamValue.Null;
return true;
-
- case "name":
- value = (Name != null) ? new(Name) : DreamValue.Null;
- return true;
- case "desc":
- value = (Desc != null) ? new(Desc) : DreamValue.Null;
- return true;
case "appearance":
var appearanceCopy = AtomManager.MustGetAppearance(this).ToMutable();
@@ -101,13 +94,6 @@ protected override void SetVar(string varName, DreamValue value) {
case "z":
case "loc":
break;
-
- case "name":
- value.TryGetValueAsString(out Name);
- break;
- case "desc":
- value.TryGetValueAsString(out Desc);
- break;
case "appearance":
if (!AtomManager.TryCreateAppearanceFrom(value, out var newAppearance))
return; // Ignore attempts to set an invalid appearance
diff --git a/OpenDreamRuntime/Objects/Types/DreamObjectMovable.cs b/OpenDreamRuntime/Objects/Types/DreamObjectMovable.cs
index ae565f51ae..685aeced7f 100644
--- a/OpenDreamRuntime/Objects/Types/DreamObjectMovable.cs
+++ b/OpenDreamRuntime/Objects/Types/DreamObjectMovable.cs
@@ -43,7 +43,7 @@ public override void Initialize(DreamProcArguments args) {
if (EntityManager.TryGetComponent(Entity, out MetaDataComponent? metaData)) {
MetaDataSystem?.SetEntityName(Entity, GetDisplayName(), metaData);
- MetaDataSystem?.SetEntityDescription(Entity, Desc ?? string.Empty, metaData);
+ MetaDataSystem?.SetEntityDescription(Entity, GetRTEntityDesc(), metaData);
}
args.GetArgument(0).TryGetValueAsDreamObject(out var loc);
diff --git a/OpenDreamShared/Dream/ImmutableAppearance.cs b/OpenDreamShared/Dream/ImmutableAppearance.cs
index 8dc97ecc2a..5688237d6d 100644
--- a/OpenDreamShared/Dream/ImmutableAppearance.cs
+++ b/OpenDreamShared/Dream/ImmutableAppearance.cs
@@ -29,7 +29,9 @@ public sealed class ImmutableAppearance : IEquatable {
private bool _needsFinalizer;
private int? _storedHashCode;
private readonly SharedAppearanceSystem? _appearanceSystem;
+
[ViewVariables] public readonly string Name = MutableAppearance.Default.Name;
+ [ViewVariables] public readonly string? Desc = MutableAppearance.Default.Desc;
[ViewVariables] public readonly int? Icon = MutableAppearance.Default.Icon;
[ViewVariables] public readonly string? IconState = MutableAppearance.Default.IconState;
[ViewVariables] public readonly AtomDirection Direction = MutableAppearance.Default.Direction;
@@ -76,6 +78,7 @@ public ImmutableAppearance(MutableAppearance appearance, SharedAppearanceSystem?
_appearanceSystem = serverAppearanceSystem;
Name = appearance.Name;
+ Desc = appearance.Desc;
Icon = appearance.Icon;
IconState = appearance.IconState;
Direction = appearance.Direction;
@@ -142,6 +145,7 @@ public bool Equals(ImmutableAppearance? immutableAppearance) {
if (immutableAppearance == null) return false;
if (immutableAppearance.Name != Name) return false;
+ if (immutableAppearance.Desc != Desc) return false;
if (immutableAppearance.Icon != Icon) return false;
if (immutableAppearance.IconState != IconState) return false;
if (immutableAppearance.Direction != Direction) return false;
@@ -150,9 +154,9 @@ public bool Equals(ImmutableAppearance? immutableAppearance) {
if (immutableAppearance.PixelOffset2 != PixelOffset2) return false;
if (immutableAppearance.Color != Color) return false;
if (immutableAppearance.Alpha != Alpha) return false;
- if (immutableAppearance.GlideSize != GlideSize) return false;
+ if (!immutableAppearance.GlideSize.Equals(GlideSize)) return false;
if (!immutableAppearance.ColorMatrix.Equals(ColorMatrix)) return false;
- if (immutableAppearance.Layer != Layer) return false;
+ if (!immutableAppearance.Layer.Equals(Layer)) return false;
if (immutableAppearance.Plane != Plane) return false;
if (immutableAppearance.RenderSource != RenderSource) return false;
if (immutableAppearance.RenderTarget != RenderTarget) return false;
@@ -171,7 +175,6 @@ public bool Equals(ImmutableAppearance? immutableAppearance) {
if (immutableAppearance.MaptextSize != MaptextSize) return false;
if (immutableAppearance.MaptextOffset != MaptextOffset) return false;
-
for (int i = 0; i < Filters.Length; i++) {
if (immutableAppearance.Filters[i] != Filters[i]) return false;
}
@@ -218,6 +221,7 @@ public override int GetHashCode() {
HashCode hashCode = new HashCode();
hashCode.Add(Name);
+ hashCode.Add(Desc);
hashCode.Add(Icon);
hashCode.Add(IconState);
hashCode.Add(Direction);
@@ -283,6 +287,9 @@ public ImmutableAppearance(NetIncomingMessage buffer, IRobustSerializer serializ
case IconAppearanceProperty.Name:
Name = buffer.ReadString();
break;
+ case IconAppearanceProperty.Desc:
+ Desc = buffer.ReadString();
+ break;
case IconAppearanceProperty.Id:
_registeredId = buffer.ReadVariableUInt32();
break;
@@ -448,6 +455,7 @@ public MutableAppearance ToMutable() {
MutableAppearance result = MutableAppearance.Get();
result.Name = Name;
+ result.Desc = Desc;
result.Icon = Icon;
result.IconState = IconState;
result.Direction = Direction;
@@ -496,6 +504,11 @@ public void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serialize
buffer.Write(Name);
}
+ if (Desc != MutableAppearance.Default.Desc) {
+ buffer.Write((byte)IconAppearanceProperty.Desc);
+ buffer.Write(Desc);
+ }
+
if (Icon != null) {
buffer.Write((byte)IconAppearanceProperty.Icon);
buffer.WriteVariableInt32(Icon.Value);
diff --git a/OpenDreamShared/Dream/MutableAppearance.cs b/OpenDreamShared/Dream/MutableAppearance.cs
index 6750f2381b..76c853cb03 100644
--- a/OpenDreamShared/Dream/MutableAppearance.cs
+++ b/OpenDreamShared/Dream/MutableAppearance.cs
@@ -26,6 +26,7 @@ public sealed class MutableAppearance : IEquatable, IDisposab
private static Stack _mutableAppearancePool = new();
[ViewVariables] public string Name = string.Empty;
+ [ViewVariables] public string? Desc = string.Empty;
[ViewVariables] public int? Icon;
[ViewVariables] public string? IconState;
[ViewVariables] public AtomDirection Direction = AtomDirection.South;
@@ -106,6 +107,7 @@ public static MutableAppearance GetCopy(MutableAppearance appearance) {
public void CopyFrom(MutableAppearance appearance) {
Name = appearance.Name;
+ Desc = appearance.Desc;
Icon = appearance.Icon;
IconState = appearance.IconState;
Direction = appearance.Direction;
@@ -149,6 +151,7 @@ public bool Equals(MutableAppearance? appearance) {
if (appearance == null) return false;
if (appearance.Name != Name) return false;
+ if (appearance.Desc != Desc) return false;
if (appearance.Icon != Icon) return false;
if (appearance.IconState != IconState) return false;
if (appearance.Direction != Direction) return false;
@@ -242,6 +245,7 @@ public override int GetHashCode() {
HashCode hashCode = new HashCode();
hashCode.Add(Name);
+ hashCode.Add(Desc);
hashCode.Add(Icon);
hashCode.Add(IconState);
hashCode.Add(Direction);
@@ -376,6 +380,7 @@ public enum AnimationFlags {
//used for encoding for netmessages
public enum IconAppearanceProperty : byte {
Name,
+ Desc,
Icon,
IconState,
Direction,
diff --git a/OpenDreamShared/Network/Messages/MsgAllAppearances.cs b/OpenDreamShared/Network/Messages/MsgAllAppearances.cs
index 6f7a2bc0f4..2d4b1afd91 100644
--- a/OpenDreamShared/Network/Messages/MsgAllAppearances.cs
+++ b/OpenDreamShared/Network/Messages/MsgAllAppearances.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
+using System.Collections.Generic;
using Lidgren.Network;
using OpenDreamShared.Dream;
using Robust.Shared.Network;
@@ -12,6 +9,7 @@ namespace OpenDreamShared.Network.Messages;
public sealed class MsgAllAppearances(Dictionary allAppearances) : NetMessage {
public override MsgGroups MsgGroup => MsgGroups.EntityEvent;
public Dictionary AllAppearances = allAppearances;
+
public MsgAllAppearances() : this(new()) { }
public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) {