Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Core/World/Entities/Definition/States/FrameState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ public void Tick(Entity entity)
return;

CurrentTick--;
if (CurrentTick <= 0)
if (CurrentTick == 0)
{
if (Frame.BranchType == ActorStateBranch.Stop && (Options & FrameStateOptions.DestroyOnStop) != 0)
{
Expand Down
1 change: 1 addition & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- Fix sky texture not working when it's not in the texture namespace.
- Right-extend "block" characters in ENDOOM to emulate VGA "line graphics enable" mode.
- Fix A_Refire not calling noise alert.
- Match Doom behavior in the thing tick function that wouldn't advance the state for zero duration frames and leave them in a -1 loop.

## Misc:
- Refactor of old Status Bar renderer to data-driven SBARDEF format.
Expand Down
77 changes: 77 additions & 0 deletions Tests/Unit/GameAction/Dehacked/FrameStates.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using FluentAssertions;
using Helion.Geometry.Vectors;
using Helion.Resources.IWad;
using Helion.World.Impl.SinglePlayer;
using Xunit;

namespace Helion.Tests.Unit.GameAction.Dehacked;

[Collection("GameActions")]
public class FrameStates
{
private readonly SinglePlayerWorld World;

public FrameStates()
{
World = WorldAllocator.LoadMap("Resources/box.zip", "box.WAD", "MAP01", GetType().Name, (world) => { }, IWadType.Doom2);
}

[Fact(DisplayName = "Setting null death state through missile removes entity")]
public void NullDeathStateRemovesEntity()
{
var def = World.EntityManager.DefinitionComposer.GetByName("DoomImp")!;
def.DeathState = null;
def.Flags.SetSpawnCeiling();
def.Flags.SetMissile();

var entity = GameActions.CreateEntity(World, "DoomImp", Vec3D.Zero, initSpawn: true);
entity.IsDisposed.Should().BeFalse();
GameActions.TickWorld(World, 35);
entity.IsDisposed.Should().BeTrue();
}

[Fact(DisplayName = "Zero tick duration spawn state set -1 and loops")]
public void ZeroTickDurationSpawnState()
{
// The tick function didn't have the same check and wouldn't let a zero duration frame immediately go to the next.
// It would decrement and check if it didn't equal zero and this causes it to be infinitely in a -1 frame.
var def = World.EntityManager.DefinitionComposer.GetByName("DoomImp")!;
var frame = World.ArchiveCollection.EntityFrameTable.Frames[def.SpawnState!.Value];
frame.Ticks = 0;
frame.NextFrameIndex = frame.MasterFrameIndex;

var entity = GameActions.CreateEntity(World, "DoomImp", Vec3D.Zero, initSpawn: true);
entity.FrameState.Frame.Should().Be(frame);
entity.FrameState.CurrentTick.Should().Be(0);
entity.Tick();
entity.FrameState.Frame.Should().Be(frame);
entity.FrameState.CurrentTick.Should().Be(-1);
entity.Tick();
entity.FrameState.Frame.Should().Be(frame);
entity.FrameState.CurrentTick.Should().Be(-1);
}

[Fact(DisplayName = "Zero tick duration after spawn state automatically goes to next frame")]
public void ZeroTickDurationAfterSpawnState()
{
var def = World.EntityManager.DefinitionComposer.GetByName("DoomImp")!;
var frame = World.ArchiveCollection.EntityFrameTable.Frames[def.SpawnState!.Value];
frame.ActionFunction = null;
frame.Ticks = 1;
frame.NextFrameIndex = frame.MasterFrameIndex + 1;
var nextFrame = frame.NextFrame;
nextFrame.ActionFunction = null;
nextFrame.Ticks = 0;
nextFrame.NextFrameIndex = nextFrame.MasterFrameIndex + 1;
var lastFrame = nextFrame.NextFrame;
lastFrame.ActionFunction = null;
lastFrame.Ticks = 69;

var entity = GameActions.CreateEntity(World, "DoomImp", Vec3D.Zero, initSpawn: true);
entity.FrameState.Frame.Should().Be(frame);
entity.FrameState.CurrentTick.Should().Be(1);
entity.Tick();
entity.FrameState.Frame.Should().Be(lastFrame);
entity.FrameState.CurrentTick.Should().Be(69);
}
}
35 changes: 0 additions & 35 deletions Tests/Unit/GameAction/Dehacked/NullState.cs

This file was deleted.

Loading