8e0816807f
A new condition named "spriteFrameRange" is added. It works like frameRange except it follows frame counters assigned to each sprite. Frame counter picks up the nearest frame counter within 6x6 pixels from the last frame and resets if graphics, palette, bg priority or orientation has changed. The condition can by used by sprite tiles only. For example: <condition>myCondition,spriteFrameRange,301,60 [myCondition]<tile>0,1001,FF0F3600,8,0,1,N
329 lines
No EOL
9.5 KiB
C
329 lines
No EOL
9.5 KiB
C
#pragma once
|
|
#include "stdafx.h"
|
|
#include "HdData.h"
|
|
#include "../Utilities/HexUtilities.h"
|
|
|
|
struct HdPackBaseTileCondition : public HdPackCondition
|
|
{
|
|
int32_t TileX;
|
|
int32_t TileY;
|
|
uint32_t PaletteColors;
|
|
uint8_t TileData[16];
|
|
int32_t TileIndex;
|
|
int32_t PixelOffset;
|
|
|
|
void Initialize(int32_t x, int32_t y, uint32_t palette, int32_t tileIndex, string tileData = "")
|
|
{
|
|
TileX = x;
|
|
TileY = y;
|
|
PixelOffset = (y * 256) + x;
|
|
PaletteColors = palette;
|
|
TileIndex = tileIndex;
|
|
if(tileData.size() == 32) {
|
|
for(int i = 0; i < 16; i++) {
|
|
TileData[i] = HexUtilities::FromHex(tileData.substr(i * 2, 2));
|
|
}
|
|
TileIndex = -1;
|
|
}
|
|
}
|
|
|
|
string ToString() override
|
|
{
|
|
stringstream out;
|
|
out << "<condition>" << Name << "," << GetConditionName() << ",";
|
|
out << TileX << ",";
|
|
out << TileY << ",";
|
|
if(TileIndex >= 0) {
|
|
out << HexUtilities::ToHex(TileIndex) << ",";
|
|
} else {
|
|
for(int i = 0; i < 16; i++) {
|
|
out << HexUtilities::ToHex(TileData[i]);
|
|
}
|
|
}
|
|
out << HexUtilities::ToHex(PaletteColors, true);
|
|
|
|
return out.str();
|
|
}
|
|
};
|
|
|
|
enum class HdPackConditionOperator
|
|
{
|
|
Equal = 0,
|
|
NotEqual = 1,
|
|
GreaterThan = 2,
|
|
LowerThan = 3,
|
|
LowerThanOrEqual = 4,
|
|
GreaterThanOrEqual = 5,
|
|
};
|
|
|
|
struct HdPackBaseMemoryCondition : public HdPackCondition
|
|
{
|
|
static constexpr uint32_t PpuMemoryMarker = 0x80000000;
|
|
uint32_t OperandA;
|
|
HdPackConditionOperator Operator;
|
|
uint32_t OperandB;
|
|
uint8_t Mask;
|
|
|
|
void Initialize(uint32_t operandA, HdPackConditionOperator op, uint32_t operandB, uint8_t mask)
|
|
{
|
|
OperandA = operandA;
|
|
Operator = op;
|
|
OperandB = operandB;
|
|
Mask = mask;
|
|
}
|
|
|
|
bool IsPpuCondition()
|
|
{
|
|
return (OperandA & HdPackBaseMemoryCondition::PpuMemoryMarker) != 0;
|
|
}
|
|
|
|
string ToString() override
|
|
{
|
|
stringstream out;
|
|
out << "<condition>" << Name << "," << GetConditionName() << ",";
|
|
out << HexUtilities::ToHex(OperandA & 0xFFFF) << ",";
|
|
switch(Operator) {
|
|
case HdPackConditionOperator::Equal: out << "=="; break;
|
|
case HdPackConditionOperator::NotEqual: out << "!="; break;
|
|
case HdPackConditionOperator::GreaterThan: out << ">"; break;
|
|
case HdPackConditionOperator::LowerThan: out << "<"; break;
|
|
case HdPackConditionOperator::LowerThanOrEqual: out << "<="; break;
|
|
case HdPackConditionOperator::GreaterThanOrEqual: out << ">="; break;
|
|
}
|
|
out << ",";
|
|
out << HexUtilities::ToHex(OperandB);
|
|
out << ",";
|
|
out << HexUtilities::ToHex(Mask);
|
|
|
|
return out.str();
|
|
}
|
|
};
|
|
|
|
struct HdPackHorizontalMirroringCondition : public HdPackCondition
|
|
{
|
|
string GetConditionName() override { return "hmirror"; }
|
|
string ToString() override { return ""; }
|
|
bool IsExcludedFromFile() override { return true; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
return tile && tile->HorizontalMirroring;
|
|
}
|
|
};
|
|
|
|
struct HdPackVerticalMirroringCondition : public HdPackCondition
|
|
{
|
|
string GetConditionName() override { return "vmirror"; }
|
|
string ToString() override { return ""; }
|
|
bool IsExcludedFromFile() override { return true; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
return tile && tile->VerticalMirroring;
|
|
}
|
|
};
|
|
|
|
struct HdPackBgPriorityCondition : public HdPackCondition
|
|
{
|
|
string GetConditionName() override { return "bgpriority"; }
|
|
string ToString() override { return ""; }
|
|
bool IsExcludedFromFile() override { return true; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
return tile && tile->BackgroundPriority;
|
|
}
|
|
};
|
|
|
|
struct HdPackMemoryCheckCondition : public HdPackBaseMemoryCondition
|
|
{
|
|
HdPackMemoryCheckCondition() { _useCache = true; }
|
|
string GetConditionName() override { return IsPpuCondition() ? "ppuMemoryCheck" : "memoryCheck"; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
uint8_t a = (uint8_t)(screenInfo->WatchedAddressValues[OperandA] & Mask);
|
|
uint8_t b = (uint8_t)(screenInfo->WatchedAddressValues[OperandB] & Mask);
|
|
|
|
switch(Operator) {
|
|
case HdPackConditionOperator::Equal: return a == b;
|
|
case HdPackConditionOperator::NotEqual: return a != b;
|
|
case HdPackConditionOperator::GreaterThan: return a > b;
|
|
case HdPackConditionOperator::LowerThan: return a < b;
|
|
case HdPackConditionOperator::LowerThanOrEqual: return a <= b;
|
|
case HdPackConditionOperator::GreaterThanOrEqual: return a >= b;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
struct HdPackMemoryCheckConstantCondition : public HdPackBaseMemoryCondition
|
|
{
|
|
HdPackMemoryCheckConstantCondition() { _useCache = true; }
|
|
string GetConditionName() override { return IsPpuCondition() ? "ppuMemoryCheckConstant" : "memoryCheckConstant"; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
uint8_t a = (uint8_t)(screenInfo->WatchedAddressValues[OperandA] & Mask);
|
|
uint8_t b = OperandB;
|
|
|
|
switch(Operator) {
|
|
case HdPackConditionOperator::Equal: return a == b;
|
|
case HdPackConditionOperator::NotEqual: return a != b;
|
|
case HdPackConditionOperator::GreaterThan: return a > b;
|
|
case HdPackConditionOperator::LowerThan: return a < b;
|
|
case HdPackConditionOperator::LowerThanOrEqual: return a <= b;
|
|
case HdPackConditionOperator::GreaterThanOrEqual: return a >= b;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
struct HdPackFrameRangeCondition : public HdPackCondition
|
|
{
|
|
uint32_t OperandA;
|
|
uint32_t OperandB;
|
|
|
|
HdPackFrameRangeCondition() { _useCache = true; }
|
|
string GetConditionName() override { return "frameRange"; }
|
|
|
|
void Initialize(uint32_t operandA, uint32_t operandB)
|
|
{
|
|
OperandA = operandA;
|
|
OperandB = operandB;
|
|
}
|
|
|
|
string ToString() override
|
|
{
|
|
stringstream out;
|
|
out << "<condition>" << Name << "," << GetConditionName() << ",";
|
|
out << OperandA << ",";
|
|
out << OperandB;
|
|
|
|
return out.str();
|
|
}
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
return screenInfo->FrameNumber % OperandA >= OperandB;
|
|
}
|
|
};
|
|
|
|
struct HdPackTileAtPositionCondition : public HdPackBaseTileCondition
|
|
{
|
|
HdPackTileAtPositionCondition() { _useCache = true; }
|
|
string GetConditionName() override { return "tileAtPosition"; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
HdPpuTileInfo &targetTile = screenInfo->ScreenTiles[PixelOffset].Tile;
|
|
if(TileIndex >= 0) {
|
|
return targetTile.PaletteColors == PaletteColors && targetTile.TileIndex == TileIndex;
|
|
} else {
|
|
return memcmp(&targetTile.PaletteColors, &PaletteColors, sizeof(PaletteColors) + sizeof(TileData)) == 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct HdPackSpriteAtPositionCondition : public HdPackBaseTileCondition
|
|
{
|
|
HdPackSpriteAtPositionCondition() { _useCache = true; }
|
|
string GetConditionName() override { return "spriteAtPosition"; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
for(int i = 0, len = screenInfo->ScreenTiles[PixelOffset].SpriteCount; i < len; i++) {
|
|
HdPpuTileInfo &targetTile = screenInfo->ScreenTiles[PixelOffset].Sprite[i];
|
|
if(TileIndex >= 0) {
|
|
if(targetTile.PaletteColors == PaletteColors && targetTile.TileIndex == TileIndex) {
|
|
return true;
|
|
}
|
|
} else {
|
|
if(memcmp(&targetTile.PaletteColors, &PaletteColors, sizeof(PaletteColors) + sizeof(TileData)) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
struct HdPackTileNearbyCondition : public HdPackBaseTileCondition
|
|
{
|
|
string GetConditionName() override { return "tileNearby"; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
int pixelIndex = PixelOffset + (y * 256) + x;
|
|
if(pixelIndex < 0 || pixelIndex > PPU::PixelCount) {
|
|
return false;
|
|
}
|
|
|
|
HdPpuTileInfo &targetTile = screenInfo->ScreenTiles[pixelIndex].Tile;
|
|
if(TileIndex >= 0) {
|
|
return targetTile.PaletteColors == PaletteColors && targetTile.TileIndex == TileIndex;
|
|
} else {
|
|
return memcmp(&targetTile.PaletteColors, &PaletteColors, sizeof(PaletteColors) + sizeof(TileData)) == 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct HdPackSpriteNearbyCondition : public HdPackBaseTileCondition
|
|
{
|
|
string GetConditionName() override { return "spriteNearby"; }
|
|
|
|
bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
int xSign = tile && tile->HorizontalMirroring ? -1 : 1;
|
|
int ySign = tile && tile->VerticalMirroring ? -1 : 1;
|
|
int pixelIndex = ((y + TileY * ySign) * 256) + x + (TileX * xSign);
|
|
|
|
if(pixelIndex < 0 || pixelIndex > PPU::PixelCount) {
|
|
return false;
|
|
}
|
|
|
|
for(int i = 0, len = screenInfo->ScreenTiles[pixelIndex].SpriteCount; i < len; i++) {
|
|
HdPpuTileInfo &targetTile = screenInfo->ScreenTiles[pixelIndex].Sprite[i];
|
|
if(TileIndex >= 0) {
|
|
if(targetTile.PaletteColors == PaletteColors && targetTile.TileIndex == TileIndex) {
|
|
return true;
|
|
}
|
|
} else {
|
|
if(memcmp(&targetTile.PaletteColors, &PaletteColors, sizeof(PaletteColors) + sizeof(TileData)) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
struct HdPackSpriteFrameRangeCondition : public HdPackCondition
|
|
{
|
|
uint32_t OperandA;
|
|
uint32_t OperandB;
|
|
|
|
string GetConditionName() override { return "spriteFrameRange"; }
|
|
|
|
void Initialize(uint32_t operandA, uint32_t operandB)
|
|
{
|
|
OperandA = operandA;
|
|
OperandB = operandB;
|
|
}
|
|
|
|
string ToString() override
|
|
{
|
|
stringstream out;
|
|
out << "<condition>" << Name << "," << GetConditionName() << ",";
|
|
out << OperandA << ",";
|
|
out << OperandB;
|
|
|
|
return out.str();
|
|
}
|
|
|
|
bool InternalCheckCondition(HdScreenInfo* screenInfo, int x, int y, HdPpuTileInfo* tile) override
|
|
{
|
|
return (screenInfo->FrameNumber - screenInfo->spriteFrameRanges[tile->OAMIndex].startFrameNumber) % OperandA >= OperandB;
|
|
}
|
|
}; |