Skip to content

Commit

Permalink
Implements icon.Insert() (#714)
Browse files Browse the repository at this point in the history
* Implements icon.Insert()

* nuke a reminder comment

* Update OpenDreamShared/Resources/DMIParser.cs

Co-authored-by: wixoa <[email protected]>

* Update OpenDreamShared/Resources/DMIParser.cs

Co-authored-by: wixoa <[email protected]>

* Update OpenDreamShared/Resources/DMIParser.cs

Co-authored-by: wixoa <[email protected]>

* Update OpenDreamRuntime/Procs/Native/DreamProcNativeIcon.cs

Co-authored-by: wixoa <[email protected]>

* review

Co-authored-by: ike709 <[email protected]>
Co-authored-by: wixoa <[email protected]>
  • Loading branch information
3 people authored Oct 30, 2022
1 parent baa5589 commit 986adcf
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 1 deletion.
1 change: 0 additions & 1 deletion DMCompiler/DMStandard/Types/Icon.dm
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
return icon_states(src, mode)

proc/Insert(new_icon, icon_state, dir, frame, moving, delay)
set opendream_unimplemented = TRUE

proc/MapColors(...)
set opendream_unimplemented = TRUE
Expand Down
1 change: 1 addition & 0 deletions OpenDreamRuntime/Procs/Native/DreamProcNative.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public static void SetupNativeProcs(DreamObjectTree objectTree) {
DreamObjectDefinition icon = objectTree.GetObjectDefinition(DreamPath.Icon);
icon.SetNativeProc(DreamProcNativeIcon.NativeProc_Width);
icon.SetNativeProc(DreamProcNativeIcon.NativeProc_Height);
icon.SetNativeProc(DreamProcNativeIcon.NativeProc_Insert);

//DreamObjectDefinition savefile = objectTree.GetObjectDefinitionFromPath(DreamPath.Savefile);
//savefile.SetNativeProc(DreamProcNativeSavefile.NativeProc_Flush);
Expand Down
43 changes: 43 additions & 0 deletions OpenDreamRuntime/Procs/Native/DreamProcNativeIcon.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using OpenDreamRuntime.Objects;
using OpenDreamRuntime.Objects.MetaObjects;
using OpenDreamShared.Dream;

namespace OpenDreamRuntime.Procs.Native {
static class DreamProcNativeIcon {
Expand All @@ -17,6 +18,48 @@ public static DreamValue NativeProc_Height(DreamObject instance, DreamObject usr
return new DreamValue(dreamIconObject.Description.Height);
}

[DreamProc("Insert")]
[DreamProcParameter("new_icon", Type = DreamValue.DreamValueType.DreamObject)]
[DreamProcParameter("icon_state", Type = DreamValue.DreamValueType.String)]
[DreamProcParameter("dir", Type = DreamValue.DreamValueType.Float)]
[DreamProcParameter("frame", Type = DreamValue.DreamValueType.Float)]
[DreamProcParameter("moving", Type = DreamValue.DreamValueType.Float)]
[DreamProcParameter("delay", Type = DreamValue.DreamValueType.Float)]
public static DreamValue NativeProc_Insert(DreamObject instance, DreamObject usr, DreamProcArguments arguments) {
//TODO Figure out what happens when you pass the wrong types as args

if (!arguments.GetArgument(0, "new_icon").TryGetValueAsDreamObject(out var new_icon))
{
// TODO: Implement this
if (arguments.GetArgument(0, "new_icon").TryGetValueAsDreamResource(out _))
{
throw new NotImplementedException("icon.Insert() doesn't support DreamResources yet");
}
}
arguments.GetArgument(1, "icon_state").TryGetValueAsString(out var icon_state);
AtomDirection? dir = null;
if (arguments.GetArgument(2, "dir").TryGetValueAsInteger(out var dirNum))
{
dir = (AtomDirection)dirNum;
}
int? frame = null;
if (arguments.GetArgument(3, "frame").TryGetValueAsInteger(out var frameNum))
{
frame = frameNum;
}
bool moving = !(arguments.GetArgument(4, "moving").TryGetValueAsInteger(out var movingNum) && movingNum == 0);
int? delay = null;
if (arguments.GetArgument(5, "delay").TryGetValueAsInteger(out var delayNum))
{
delay = delayNum;
}

DreamMetaObjectIcon.DreamIconObject instanceIconObject = DreamMetaObjectIcon.ObjectToDreamIcon[instance];
DreamMetaObjectIcon.DreamIconObject newIconObject = DreamMetaObjectIcon.ObjectToDreamIcon[new_icon];
instanceIconObject.Description.InsertIcon(newIconObject.Description, icon_state, dir, frame, delay);

instanceIconObject.Moving = moving ? DreamMetaObjectIcon.DreamIconMovingMode.Movement : DreamMetaObjectIcon.DreamIconMovingMode.NonMovement;
return DreamValue.Null;
}
}
}
60 changes: 60 additions & 0 deletions OpenDreamShared/Resources/DMIParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Text;
using OpenDreamShared.Dream;
using System.Globalization;
using JetBrains.Annotations;

namespace OpenDreamShared.Resources {
public static class DMIParser {
Expand Down Expand Up @@ -44,6 +45,65 @@ public static ParsedDMIDescription CreateEmpty(int width, int height) {
};
}

private static ParsedDMIDescription CloneDescription(ParsedDMIDescription original)
{
Dictionary<string, ParsedDMIState> stateCopy = new(original.States.Count);
foreach (var key in original.States.Keys)
{
stateCopy.Add(key, original.States[key]);
}

return new ParsedDMIDescription() {
Source = original.Source,
Version = original.Version,
Width = original.Width,
Height = original.Height,
States = stateCopy
};
}

public void InsertIcon(ParsedDMIDescription original_icon, string icon_state, AtomDirection? dir, int? frame, float? delay)
{
var icon = CloneDescription(original_icon);
IEnumerable<ParsedDMIState> states;
if (icon_state is null) {
states = icon.States.Values;
} else {
states = new ParsedDMIState[] { icon.States[icon_state] };
}

foreach (var state in states)
{
if (dir is not null)
{
var goodDir = state.Directions[dir.Value];
state.Directions.Clear();
state.Directions = new Dictionary<AtomDirection, ParsedDMIFrame[]>(1) { { dir.Value, goodDir } };
}

if (frame is not null)
{
// TODO Ref says it must start at 1, need to check behavior for when it's less. Manually validate it for now.
var goodFrame = Math.Max(frame.Value, 1);
foreach (var (direction, frames) in state.Directions)
{
state.Directions[direction] = new ParsedDMIFrame[1] { frames[goodFrame] };
if (delay is not null or 0) {
state.Rewind = delay < 0;
frames[goodFrame].Delay = Math.Abs(delay.Value);
}
}
}
}

// All of that above was just to adjust the inserted icon to match the args. Now we can actually insert it.

foreach (var state in states)
{
States[state.Name] = state;
}
}

public bool HasState(string stateName = null) {
return States.ContainsKey(stateName ?? "");
}
Expand Down

0 comments on commit 986adcf

Please sign in to comment.