Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/ultima8/games/treasure_loader.h"
/**
* Test suite for the functions in engines/ultima/ultima8/games/treasure_loader.h
*
* TODO: We should test type= values, but they are loaded from the config file
* so we need a way to add those.
*
* That would also allow testing "type", "special", and "mult" values which
* need defaults.
*/
class U8TreasureLoaderTestSuite : public CxxTest::TestSuite {
public:
U8TreasureLoaderTestSuite() {
}
Ultima::Ultima8::TreasureLoader loader;
/* Parse nothing -> should return nothing */
void test_parse_empty() {
Ultima::Std::vector<Ultima::Ultima8::TreasureInfo> t;
bool result = loader.parse("", t);
TS_ASSERT(result);
TS_ASSERT(t.empty());
}
/* Parse a single treasure type */
void test_parse_basic() {
Ultima::Std::vector<Ultima::Ultima8::TreasureInfo> t;
bool result = loader.parse("shape=123,456 frame=2,3 count=4-20 map=23 chance=0.234", t);
TS_ASSERT(result);
TS_ASSERT_EQUALS(t.size(), 1);
const Ultima::Ultima8::TreasureInfo ti = t[0];
TS_ASSERT_EQUALS(ti._shapes.size(), 2);
TS_ASSERT_EQUALS(ti._shapes[0], 123);
TS_ASSERT_EQUALS(ti._shapes[1], 456);
TS_ASSERT_EQUALS(ti._frames.size(), 2);
TS_ASSERT_EQUALS(ti._frames[0], 2);
TS_ASSERT_EQUALS(ti._frames[1], 3);
TS_ASSERT_EQUALS(ti._minCount, 4);
TS_ASSERT_EQUALS(ti._maxCount, 20);
TS_ASSERT_EQUALS(ti._special, "");
TS_ASSERT_EQUALS(ti._map, 23);
TS_ASSERT_EQUALS(ti._chance, 0.234);
}
/* Parse multiple treasure types */
void test_parse_multi() {
Ultima::Std::vector<Ultima::Ultima8::TreasureInfo> t;
bool result = loader.parse("shape=123;shape=456 frame=2-5;shape=888 map=-12", t);
TS_ASSERT(result);
TS_ASSERT_EQUALS(t.size(), 3);
TS_ASSERT_EQUALS(t[0]._shapes.size(), 1);
TS_ASSERT_EQUALS(t[0]._shapes[0], 123);
TS_ASSERT_EQUALS(t[0]._frames.size(), 0);
TS_ASSERT_EQUALS(t[0]._minCount, 1);
TS_ASSERT_EQUALS(t[0]._maxCount, 1);
TS_ASSERT_EQUALS(t[0]._special, "");
TS_ASSERT_EQUALS(t[0]._map, 0);
TS_ASSERT_EQUALS(t[0]._chance, 1);
TS_ASSERT_EQUALS(t[1]._shapes.size(), 1);
TS_ASSERT_EQUALS(t[1]._shapes[0], 456);
TS_ASSERT_EQUALS(t[1]._frames.size(), 4);
TS_ASSERT_EQUALS(t[1]._frames[0], 2);
TS_ASSERT_EQUALS(t[1]._frames[1], 3);
TS_ASSERT_EQUALS(t[1]._frames[2], 4);
TS_ASSERT_EQUALS(t[1]._frames[3], 5);
TS_ASSERT_EQUALS(t[2]._shapes.size(), 1);
TS_ASSERT_EQUALS(t[2]._shapes[0], 888);
TS_ASSERT_EQUALS(t[2]._map, -12);
}
/* Check that various invalid strings don't parse */
void test_parse_invalid() {
Ultima::Std::vector<Ultima::Ultima8::TreasureInfo> t;
bool result;
result = loader.parse("shape=", t);
TS_ASSERT(!result);
result = loader.parse("what", t);
TS_ASSERT(!result);
result = loader.parse("shape=abc", t);
TS_ASSERT(!result);
result = loader.parse("shape=123,123456789", t);
TS_ASSERT(!result);
result = loader.parse("shape=-123", t);
TS_ASSERT(!result);
result = loader.parse("frame=-1,5", t);
TS_ASSERT(!result);
/* TODO: This case falls back to parsing the 10, not great.
result = loader.parse("count=10-1", t);
TS_ASSERT(!result);
*/
result = loader.parse("chance=-1", t);
TS_ASSERT(!result);
}
};

View File

@@ -0,0 +1,71 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/ultima8/misc/box.h"
/**
* Test suite for the functions in engines/ultima/ultima8/misc/box.h
*/
class U8BoxTestSuite : public CxxTest::TestSuite {
public:
U8BoxTestSuite() {
}
void test_simple_box() {
// Note: These tests expect Box has reversed coordinates in x and y.
Ultima::Ultima8::Box box;
TS_ASSERT(box.isEmpty());
TS_ASSERT(box.isValid());
TS_ASSERT(!box.overlaps(box));
TS_ASSERT(box == box);
TS_ASSERT(!box.contains(0, 0, 0));
TS_ASSERT(!box.contains(0, 0, 1));
TS_ASSERT(!box.contains(0, -1, 0));
TS_ASSERT(!box.contains(-1, 0, 0));
box.resize(1, 1, 1);
TS_ASSERT(!box.isEmpty());
TS_ASSERT(box.isValid());
TS_ASSERT(box.contains(0, 0, 0));
TS_ASSERT(!box.contains(-1, 0, 0));
TS_ASSERT(!box.contains(0, -1, 0));
TS_ASSERT(!box.contains(0, 0, 1));
TS_ASSERT(box.overlaps(box));
TS_ASSERT(box == box);
box.resize(2, 2, 2);
TS_ASSERT(!box.isEmpty());
TS_ASSERT(box.isValid());
TS_ASSERT(box.overlaps(box));
TS_ASSERT(box == box);
TS_ASSERT(box.contains(-1, -1, 1));
TS_ASSERT(box.contains(-1, -1, 0));
box.moveTo(0, 0, 1);
TS_ASSERT(!box.contains(-1, -1, 0));
TS_ASSERT(box.contains(-1, -1, 2));
Ultima::Ultima8::Box box2(box);
TS_ASSERT(box == box2);
TS_ASSERT(box.overlaps(box2));
TS_ASSERT(box2 == box);
TS_ASSERT(box2.overlaps(box));
Ultima::Ultima8::Box box3(0, 0, 0, 2, 2, 3);
TS_ASSERT(box2 != box3);
TS_ASSERT(box2.overlaps(box3));
TS_ASSERT(box3.overlaps(box2));
box3.resize(1, 1, 1);
TS_ASSERT(!box3.overlaps(box2));
box3.moveTo(2, 2, 2);
box.extend(box3);
TS_ASSERT(!box.isEmpty());
TS_ASSERT(box.isValid());
TS_ASSERT(box._x == 2);
TS_ASSERT(box._y == 2);
TS_ASSERT(box._z == 1);
TS_ASSERT(box._xd == 4);
TS_ASSERT(box._yd == 4);
TS_ASSERT(box._zd == 2);
}
};

View File

@@ -0,0 +1,63 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/ultima8/misc/direction.h"
#include "engines/ultima/ultima8/misc/direction_util.h"
/**
* Test suite for the functions in engines/ultima/ultima8/misc/direction_util.h
*/
class U8DirectionTestSuite : public CxxTest::TestSuite {
public:
U8DirectionTestSuite() {
}
// save some typing later..
static const Ultima::Ultima8::DirectionMode dirmode8 = Ultima::Ultima8::dirmode_8dirs;
static const Ultima::Ultima8::DirectionMode dirmode16 = Ultima::Ultima8::dirmode_16dirs;
// test Direction_Get(deltay, deltax, dirmode)
void _test_direction_get_basic(Ultima::Ultima8::DirectionMode mode) {
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_Get( 1, 1, mode), Ultima::Ultima8::dir_north);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_Get( 0, 1, mode), Ultima::Ultima8::dir_northeast);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_Get(-1, 1, mode), Ultima::Ultima8::dir_east);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_Get(-1, 0, mode), Ultima::Ultima8::dir_southeast);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_Get(-1, -1, mode), Ultima::Ultima8::dir_south);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_Get( 0, -1, mode), Ultima::Ultima8::dir_southwest);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_Get( 1, -1, mode), Ultima::Ultima8::dir_west);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_Get( 1, 0, mode), Ultima::Ultima8::dir_northwest);
}
void test_direction_get() {
_test_direction_get_basic(dirmode8);
_test_direction_get_basic(dirmode16);
}
void _test_direction_get_worlddir(Ultima::Ultima8::DirectionMode mode) {
// Note Y is flipped from what you might expect
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_GetWorldDir(-1, 0, mode), Ultima::Ultima8::dir_north);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_GetWorldDir(-1, 1, mode), Ultima::Ultima8::dir_northeast);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_GetWorldDir( 0, 1, mode), Ultima::Ultima8::dir_east);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_GetWorldDir( 1, 1, mode), Ultima::Ultima8::dir_southeast);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_GetWorldDir( 1, 0, mode), Ultima::Ultima8::dir_south);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_GetWorldDir( 1, -1, mode), Ultima::Ultima8::dir_southwest);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_GetWorldDir( 0, -1, mode), Ultima::Ultima8::dir_west);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_GetWorldDir(-1, -1, mode), Ultima::Ultima8::dir_northwest);
}
void test_direction_get_worlddir() {
_test_direction_get_worlddir(dirmode8);
_test_direction_get_worlddir(dirmode16);
}
void test_direction_conversions() {
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_ToCentidegrees(Ultima::Ultima8::dir_north), 0);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_ToCentidegrees(Ultima::Ultima8::dir_nne), 2250);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_ToCentidegrees(Ultima::Ultima8::dir_east), 9000);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_ToCentidegrees(Ultima::Ultima8::dir_west), 27000);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_FromCentidegrees(2250), Ultima::Ultima8::dir_nne);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_FromCentidegrees(2249), Ultima::Ultima8::dir_nne);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_FromCentidegrees(2251), Ultima::Ultima8::dir_nne);
TS_ASSERT_EQUALS(Ultima::Ultima8::Direction_FromCentidegrees(4500), Ultima::Ultima8::dir_northeast);
}
};

View File

@@ -0,0 +1,42 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/ultima8/misc/id_man.h"
/**
* Test suite for the functions in engines/ultima/ultima8/misc/id_man.h
*/
class U8IdManTestSuite : public CxxTest::TestSuite {
public:
U8IdManTestSuite() {
}
void test_trim_spaces() {
Ultima::Ultima8::idMan idman = Ultima::Ultima8::idMan(1234, 5678);
TS_ASSERT(!idman.isFull());
TS_ASSERT(!idman.isIDUsed(1234));
uint16 newid = idman.getNewID();
TS_ASSERT_EQUALS(newid, 1234);
TS_ASSERT(idman.isIDUsed(1234));
bool reserved = idman.reserveID(1234);
TS_ASSERT(!reserved);
reserved = idman.reserveID(1235);
TS_ASSERT(reserved);
TS_ASSERT(idman.isIDUsed(1235));
uint16 newid2 = idman.getNewID();
TS_ASSERT_EQUALS(newid2, 1236);
TS_ASSERT(idman.isIDUsed(1236));
bool reserved2 = idman.reserveID(2000);
TS_ASSERT(reserved2);
TS_ASSERT(idman.isIDUsed(2000));
idman.clearAll();
idman.setNewMax(2001);
TS_ASSERT(!idman.isFull());
TS_ASSERT(!idman.isIDUsed(2000));
TS_ASSERT(!idman.isIDUsed(1234));
}
};

View File

@@ -0,0 +1,49 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/shared/std/string.h"
#include "engines/ultima/ultima8/misc/util.h"
/**
* Test suite for the functions in engines/ultima/ultima8/misc/util.h
*/
class U8UtilTestSuite : public CxxTest::TestSuite {
public:
U8UtilTestSuite() {
}
void test_split_string() {
Ultima::Std::string s1 = "abc,def";
Ultima::Std::vector<Ultima::Std::string> v1;
Ultima::Ultima8::SplitString(s1, ',', v1);
TS_ASSERT_EQUALS(v1.size(), 2);
TS_ASSERT_EQUALS(v1[0], "abc");
TS_ASSERT_EQUALS(v1[1], "def");
Ultima::Std::string s2;
Ultima::Std::vector<Ultima::Std::string> v2;
Ultima::Ultima8::SplitString(s2, ',', v1);
TS_ASSERT_EQUALS(v1.size(), 0);
Ultima::Std::string s3 = " aa bb ";
Ultima::Ultima8::SplitString(s3, ' ', v1);
TS_ASSERT_EQUALS(v1.size(), 6);
TS_ASSERT_EQUALS(v1[0], "");
TS_ASSERT_EQUALS(v1[1], "aa");
}
void test_string_to_argv() {
Common::Array<Common::String> v;
Common::String s;
Ultima::Ultima8::StringToArgv(s, v);
TS_ASSERT_EQUALS(v.size(), 0);
// Test it strips leading space on args, and includes spaces inside ""s
s = "abc \\t\\nescape \"\\ me\\ \\\" !\" ";
Ultima::Ultima8::StringToArgv(s, v);
TS_ASSERT_EQUALS(v.size(), 3);
TS_ASSERT_EQUALS(v[0], "abc");
TS_ASSERT_EQUALS(v[1], "escape");
TS_ASSERT_EQUALS(v[2], " me \" !");
}
};

View File

@@ -0,0 +1,35 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/ultima8/usecode/bit_set.h"
/**
* Test suite for the functions in engines/ultima/ultima8/usecode/bit_set.h
*/
class U8BitSetTestSuite : public CxxTest::TestSuite {
public:
Ultima::Ultima8::BitSet bs;
U8BitSetTestSuite() {
bs.setSize(0x1000);
}
void test_set_get() {
// Test with bit pattern in second byte of 01110100
// (pos goes from low bit to high bit)
bs.setEntries(10, 5, 0x1D);
TS_ASSERT_EQUALS(bs.getEntries(10, 5), 0x1D);
TS_ASSERT_EQUALS(bs.getEntries(10, 4), 0xD);
TS_ASSERT_EQUALS(bs.getEntries(8, 6), 0xD << 2);
TS_ASSERT_EQUALS(bs.getEntries(8, 7), 0x1D << 2);
TS_ASSERT_EQUALS(bs.getEntries(8, 8), 0x1D << 2);
TS_ASSERT_EQUALS(bs.getEntries(14, 2), 0x1);
TS_ASSERT_EQUALS(bs.getEntries(16, 32), 0);
TS_ASSERT_EQUALS(bs.getEntries(0, 10), 0);
}
void test_clear() {
bs.setEntries(10, 5, 0x15);
bs.setSize(0x1000);
TS_ASSERT_EQUALS(bs.getEntries(10, 5), 0);
TS_ASSERT_EQUALS(bs.getEntries(0, 32), 0);
}
};

View File

@@ -0,0 +1,36 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/ultima8/usecode/uc_list.h"
/**
* Test suite for the functions in engines/ultima/ultima8/usecode/uc_list.h
*/
class U8UCListTestSuite : public CxxTest::TestSuite {
public:
U8UCListTestSuite() {
}
void test_static_list() {
Ultima::Ultima8::UCList l(2);
TS_ASSERT_EQUALS(l.getSize(), 0);
TS_ASSERT_EQUALS(l.getElementSize(), 2);
uint16 test = 0xBEEF;
l.append((uint8*)&test);
TS_ASSERT_EQUALS(l.getSize(), 1);
uint16 test2 = 0xF00D;
l.append((uint8*)&test2);
TS_ASSERT_EQUALS(l.getSize(), 2);
TS_ASSERT(l.inList((uint8*)&test));
l.remove((uint8*)&test);
TS_ASSERT(!l.inList((uint8*)&test));
TS_ASSERT(l.inList((uint8*)&test2));
TS_ASSERT_EQUALS(l.getSize(), 1);
l.free();
TS_ASSERT_EQUALS(l.getSize(), 0);
}
};

View File

@@ -0,0 +1,44 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/ultima8/usecode/uc_stack.h"
/**
* Test suite for the functions in engines/ultima/ultima8/usecode/uc_stack.h
*/
class U8UCStackTestSuite : public CxxTest::TestSuite {
public:
U8UCStackTestSuite() {
}
void test_static_stack() {
Ultima::Ultima8::UCStack stack;
test_for_stack(stack);
}
void test_dynamic_stack() {
Ultima::Ultima8::DynamicUCStack stack;
Ultima::Ultima8::DynamicUCStack stack2(32);
TS_ASSERT_EQUALS(stack2.getSize(), 32);
test_for_stack(stack);
test_for_stack(stack2);
}
private:
void test_for_stack(Ultima::Ultima8::BaseUCStack &s) {
TS_ASSERT_EQUALS(s.stacksize(), 0);
s.push4(0xDEADBEEF);
TS_ASSERT_EQUALS(s.stacksize(), 4);
TS_ASSERT_EQUALS(s.pop2(), 0xBEEF);
TS_ASSERT_EQUALS(s.pop2(), 0xDEAD);
s.push1(0xFE);
TS_ASSERT_EQUALS(s.stacksize(), 1);
s.push1(0xED);
s.push2(0xC0DE);
TS_ASSERT_EQUALS(s.pop2(), 0xC0DE);
TS_ASSERT_EQUALS(s.pop2(), 0xFEED);
TS_ASSERT_EQUALS(s.stacksize(), 0);
TS_ASSERT_EQUALS(s.getSP(), s.getSize());
s.push4(0xCAFEF00D);
TS_ASSERT_EQUALS(s.getSP(), s.getSize()-4);
}
};

View File

@@ -0,0 +1,872 @@
#include <cxxtest/TestSuite.h>
#include "engines/ultima/ultima8/world/sort_item.h"
/**
* Test suite for the functions in engines/ultima/ultima8/world/sort_item.h
*
* Be aware that the x and y coordinates go opposite to what you might expect,
* see the notes in sort_item.h
*/
class U8SortItemTestSuite : public CxxTest::TestSuite {
public:
U8SortItemTestSuite() {
}
/**
* Floor tile placed in position not consistent with others nearby
* Test case for rendering issue at MainActor::teleport 37 18168 17656 104
*/
void test_screenspace_position() {
Ultima::Ultima8::SortItem si1;
si1._solid = true;
si1._occl = true;
si1._roof = true;
si1._land = true;
// Normal placement
Ultima::Ultima8::Box b1(18047, 17663, 104, 128, 128, 104);
si1.setBoxBounds(b1, 0, 0);
TS_ASSERT(si1._sxBot == 96);
TS_ASSERT(si1._syBot == 4358);
// Inconsistent placement
Ultima::Ultima8::Box b2(18168, 17656, 104, 128, 128, 104);
si1.setBoxBounds(b2, 0, 0);
TS_ASSERT(si1._sxBot == 128);
TS_ASSERT(si1._syBot == 4374);
}
/* Non-overlapping with lower Y position should always be below */
void test_basic_y_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(0, 32, 0, 32, 32, 8);
Ultima::Ultima8::Box b2(0, 64, 0, 32, 32, 8);
si1.setBoxBounds(b1, 0, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/* Non-overlapping with lower X position should always be below */
void test_basic_x_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(32, 0, 0, 32, 32, 8);
Ultima::Ultima8::Box b2(64, 0, 0, 32, 32, 8);
si1.setBoxBounds(b1, 0, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/* Non-overlapping with lower Z position should always be below */
void test_basic_z_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(32, 32, 0, 32, 32, 8);
Ultima::Ultima8::Box b2(32, 32, 8, 32, 32, 8);
si1.setBoxBounds(b1, 0, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/* Sprites should always be at the top regardless of x/y/z */
void test_sprite_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(59454, 49246, 80, 32, 160, 16);
si1.setBoxBounds(b1, 0, 0);
Ultima::Ultima8::Box b2(59440, 49144, 63, 32, 32, 63);
si2.setBoxBounds(b2, 0, 0);
si2._sprite = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Inventory items can have a z at the same z of the surface below them
* Test case for keycard rendering issue at MainActor::teleport 9 34174 41502 0
*/
void test_inv_item_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(34142, 41150, 0, 256, 64, 8);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._land = true;
Ultima::Ultima8::Box b2(34110, 41118, 0, 64, 64, 0);
si2.setBoxBounds(b2, 0, 0);
si2._invitem = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/* Overlapping flat items (generally the floor) follow a set of rules */
void test_flat_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(0, 0, 0, 32, 32, 0);
Ultima::Ultima8::Box b2(0, 0, 0, 32, 32, 0);
si1.setBoxBounds(b1, 0, 0);
si2.setBoxBounds(b2, 0, 0);
// If one has a higher z, it's above
si2._z = 1;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
si2._z = 0;
// Animated always gets drawn above
si1._anim = true;
TS_ASSERT(si2.below(si1));
TS_ASSERT(!si1.below(si2));
si1._anim = false;
// Trans always gets drawn above
si1._trans = true;
TS_ASSERT(si2.below(si1));
TS_ASSERT(!si1.below(si2));
si1._trans = false;
// Draw always gets drawn below
si1._draw = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
si1._draw = false;
// Solid always gets drawn below
si1._solid = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
si1._solid = false;
// Occludes always get drawn below
si1._occl = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
si1._occl = false;
// Large flat squares get drawn below
si1._fbigsq = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
si1._fbigsq = false;
}
/**
* Overlapping non-flat items also follow a set of rules
* Test case for rendering issue at MainActor::teleport 6 7642 19776 48
*/
void test_non_flat_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(7679, 19743, 48, 128, 32, 8);
si1.setBoxBounds(b1, 0, 0);
si1._occl = true;
si1._roof = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(7642, 19776, 48, 64, 64, 40);
si2.setBoxBounds(b2, 0, 0);
si2._solid = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Bug in original game rendering order for roof pieces
* Test case for rendering issue at MainActor::teleport 41 15484 13660 96
*/
void test_main_actor_roof_bug() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(15484, 13660, 96, 64, 64, 40);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
Ultima::Ultima8::Box b2(15423, 13631, 104, 128, 32, 8);
si2.setBoxBounds(b2, 0, 0);
si2._occl = true;
si2._roof = true;
si2._land = true;
// This roof is below main actor
TS_ASSERT(!si1.below(si2));
TS_ASSERT(si2.below(si1));
Ultima::Ultima8::Box b3(15551, 13631, 104, 128, 32, 8);
si2.setBoxBounds(b2, 0, 0);
si2._occl = true;
si2._roof = true;
si2._land = true;
// Original Game: This roof is above main actor
//TS_ASSERT(si1.below(si2));
//TS_ASSERT(!si2.below(si1));
// Our Behavior: This roof is below main actor
TS_ASSERT(!si1.below(si2));
TS_ASSERT(si2.below(si1));
}
/**
* Overlapping non-flat items draw transparent after
* Test case for rendering issue at MainActor::teleport 41 17627 16339 48
* Wall with window should render after non-window wall
*/
void test_nonflat_transparent_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(17407, 16127, 48, 32, 96, 40);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
Ultima::Ultima8::Box b2(17407, 16191, 48, 32, 128, 40);
si2.setBoxBounds(b2, 0, 0);
si2._trans = true;
si2._solid = true;
si2._land = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping non-flat items partially in front draw after
* Test case for rendering issue at MainActor::teleport 37 22730 18016 56
*/
void test_nonflat_partial_front_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(22591, 17599, 56, 160, 160, 8);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(22719, 17695, 56, 160, 160, 8);
si2.setBoxBounds(b2, 0, 0);
si2._solid = true;
si2._land = true;
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping lower Z position transparent non-solid draw after
* Test case for rendering issue at MainActor::teleport 50 2316 7812 48
* Skeleton in niche should render before cobweb
*/
void test_ignore_z_non_solid_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(2212, 7804, 64, 192, 32, 8);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._land = true;
Ultima::Ultima8::Box b2(2207, 7839, 48, 0, 96, 48);
si2.setBoxBounds(b2, 0, 0);
si2._trans = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping x-flat vs non-flat items
* Test case for rendering issue at MainActor::teleport 40 13103 9951 48
* Tapestry should draw after wall
*/
void test_x_flat_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(13247, 9983, 48, 32, 128, 40);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._occl = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(13244, 9876, 48, 0, 96, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping x-flat vs non-flat floor where z order not clear
* Test case for rendering issue at MainActor::teleport 37 17620 19260 104
* Tapestry should draw after floor
*/
void test_x_flat_z_tolerance_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(17663, 19199, 96, 256, 256, 8);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._occl = true;
si1._roof = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(17410, 19110, 96, 0, 96, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping x-flat vs non-flat wall with x-flat far inside wall
* Test case for rendering issue at MainActor::teleport 37 17619 17767 104
* Tapestry should draw after wall again
*/
void test_x_flat_vs_thin_wall_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(17439, 17535, 104, 32, 128, 40);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._occl = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(17410, 17502, 96, 0, 96, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping x-flat vs non-flat items but the flat item was misplaced
* Test case for rendering issue at MainActor::teleport 41 19411 15787 48
*/
void test_misplaced_flat_bug() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(19199, 15871, 88, 64, 128, 16);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._occl = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(19167, 15775, 56, 0, 128, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(!si1.below(si2));
TS_ASSERT(si2.below(si1));
}
/**
* Overlapping x-flats differing in y position and slightly by x position
* Test case for rendering issue at MainActor::teleport 37 17631 17831 104
*/
void test_x_flat_layered_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(17410, 17806, 96, 0, 96, 40);
si1.setBoxBounds(b1, 0, 0);
si1._fixed = true;
Ultima::Ultima8::Box b2(17408, 17888, 96, 0, 96, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping y-flats differing in x position
* Test case for rendering issue at MainActor::teleport 8 2063 1207 48
*/
void test_y_flat_layered_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(2175, 1055, 48, 96, 0, 40);
si1.setBoxBounds(b1, 0, 0);
si1._fixed = true;
Ultima::Ultima8::Box b2(2111, 1055, 48, 96, 0, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping y-flats vs non-flat item only by one pixel edge
* Test case for rendering issue at MainActor::teleport 8 2143 1215 48
*/
void test_y_flat_edge_overlap_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(2239, 1055, 48, 64, 32, 40);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(2175, 1055, 48, 96, 0, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
// These share a one pixel edge, but we need to ignore that currently to prevent paint dependency cycles
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Completely Overlapping y-flats differing only in item number and frame
* Test case for rendering issue at MainActor::teleport 37 17628 19668 56
*/
void test_y_flat_same_position_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(17599, 19455, 56, 128, 0, 40);
si1.setBoxBounds(b1, 0, 0);
si1._fixed = true;
si1._shapeNum = 322;
si1._frame = 1;
Ultima::Ultima8::Box b2(17599, 19455, 56, 128, 0, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
si2._shapeNum = 322;
si2._frame = 3;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping y-flat vs non-flat items
* Test case for rendering issue at MainActor::teleport 37 18992 17664 104
*/
void test_y_flat_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(19007, 17439, 104, 64, 32, 40);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._occl = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(19008, 17432, 104, 96, 0, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping y-flat vs z-flat floor where z order not clear
* Test case for rendering issue at MainActor::teleport 37 22546 18656 56
* Vines should draw after floor
*/
void test_y_flat_z_tolerance_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(22271, 18431, 56, 128, 128, 0);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._occl = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(22367, 18399, 48, 128, 0, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping fixed y-flat vs non-fixed non-flat items where the flat should draw first
* Test case for rendering issue at MainActor::teleport 3 12355 5467 8
* Barrel at docks render after flat vines
*/
void test_y_flat_exception_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(12255, 5503, 0, 128, 0, 40);
si1.setBoxBounds(b1, 0, 0);
si1._fixed = true;
Ultima::Ultima8::Box b2(12260, 5532, 8, 64, 64, 16);
si2.setBoxBounds(b2, 0, 0);
si2._solid = true;
si2._land = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping y-flat vs non-flat items where they intersect in opposing directions
* Test case for rendering issue at MainActor::teleport 41 20583 10083 48
*/
void test_y_flat_intersect_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(20479, 9887, 48, 64, 128, 40);
si1.setBoxBounds(b1, 0, 0);
si1._trans = true;
si1._solid = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(20543, 9855, 48, 96, 0, 16);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping z-flat vs x-flat items
* Test case for rendering issue at MainActor::teleport 37 17736 18320 144
*/
void test_z_flat_vs_x_flat_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(17535, 18559, 144, 128, 128, 0);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
si1._occl = true;
si1._roof = true;
si1._land = true;
si1._fixed = true;
Ultima::Ultima8::Box b2(17440, 18448, 106, 0, 96, 40);
si2.setBoxBounds(b2, 0, 0);
si2._fixed = true;
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
TS_ASSERT(!si1.below(si2));
TS_ASSERT(si2.below(si1));
}
/**
* Overlapping non-flat items clearly in z - avatar above candle
* Test case for rendering issue at MainActor::teleport 6 7774 19876 48
*/
void test_nonflat_z_clear_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(7839, 19839, 24, 64, 64, 24);
si1.setBoxBounds(b1, 0, 0);
si1._anim = true;
si1._solid = true;
Ultima::Ultima8::Box b2(7774, 19876, 48, 64, 64, 40);
si2.setBoxBounds(b2, 0, 0);
si2._solid = true;
// Due to screenspace calculation changes these no longer overlap
//TS_ASSERT(si1.overlap(si2));
//TS_ASSERT(si2.overlap(si1));
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Overlapping non-flat items - animated vs occluding
* Test case for rendering issue at MainActor::teleport 3 20747 2227 0
* This looks like a possible rendering test easter egg in the original game
*/
void test_anim_easter_egg() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(20735, 1919, 0, 64, 64, 16);
si1.setBoxBounds(b1, 0, 0);
si1._anim = true;
Ultima::Ultima8::Box b2(20799, 1919, 0, 128, 32, 40);
si2.setBoxBounds(b2, 0, 0);
si2._solid = true;
si2._occl = true;
si2._land = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
/**
* Test case for rendering armor of flames spell
*/
void test_armor_of_flames_sort() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(13655, 5111, 8, 64, 64, 16);
si1.setBoxBounds(b1, 0, 0);
si1._solid = true;
Ultima::Ultima8::Box b2(13655, 5111, 8, 96, 96, 72);
si2.setBoxBounds(b2, 0, 0);
si2._anim = true;
si2._trans = true;
TS_ASSERT(si1.below(si2));
TS_ASSERT(!si2.below(si1));
}
void test_basic_occludes() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(0, 0, 0, 128, 128, 16);
si1.setBoxBounds(b1, 0, 0);
si2.setBoxBounds(b1, 0, 0);
TS_ASSERT(si1.occludes(si2));
TS_ASSERT(si2.occludes(si1));
Ultima::Ultima8::Box b2(0, 0, 0, 128, 128, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(si1.occludes(si2));
TS_ASSERT(!si2.occludes(si1));
}
/**
* Overlapping non-flat does occlude flat due to frame offset
* Test case for rendering issue at MainActor::teleport 49 19167 17582 48
*/
void test_frame_offset_occludes() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(0, 0, 0, 128, 128, 16);
Ultima::Ultima8::Box b2(0, 0, 0, 128, 128, 0);
si1.setBoxBounds(b1, 0, 0);
si2.setBoxBounds(b2, 0, 0);
// ShapeFrame (240:1)
si1._sr.left = si1._sxBot - 32;
si1._sr.top = si1._syBot - 48;
si1._sr.right = si1._sr.left + 65;
si1._sr.bottom = si1._sr.top + 48;
// ShapeFrame (301:1)
si2._sr.left = si2._sxBot - 31;
si2._sr.top = si2._syBot - 31;
si2._sr.right = si2._sr.left + 62;
si2._sr.bottom = si2._sr.top + 32;
TS_ASSERT(!si1.occludes(si2));
TS_ASSERT(!si2.occludes(si1));
}
void test_basic_contains() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::Box b1(0, 0, 0, 128, 128, 16);
si1.setBoxBounds(b1, 0, 0);
// Inside bounds
TS_ASSERT(si1.contains(si1._sxBot, si1._syBot - 1));
TS_ASSERT(si1.contains(si1._sxTop, si1._syTop + 1));
TS_ASSERT(si1.contains(si1._sxLeft + 1, (si1._syTop + si1._syBot) / 2));
TS_ASSERT(si1.contains(si1._sxRight - 1, (si1._syTop + si1._syBot) / 2));
TS_ASSERT(si1.contains((si1._sxLeft + si1._sxRight) / 2, (si1._syTop + si1._syBot) / 2));
// Inclusive of left and top
TS_ASSERT(si1.contains(si1._sxTop, si1._syTop));
TS_ASSERT(si1.contains(si1._sxLeft, (si1._syTop + si1._syBot) / 2));
// Inclusive of right and bottom
TS_ASSERT(si1.contains(si1._sxBot, si1._syBot));
TS_ASSERT(si1.contains(si1._sxRight, (si1._syTop + si1._syBot) / 2));
// Outside bounds
TS_ASSERT(!si1.contains(si1._sxBot, si1._syBot + 1));
TS_ASSERT(!si1.contains(si1._sxTop, si1._syTop - 1));
TS_ASSERT(!si1.contains(si1._sxLeft - 1, (si1._syTop + si1._syBot) / 2));
TS_ASSERT(!si1.contains(si1._sxRight + 1, (si1._syTop + si1._syBot) / 2));
TS_ASSERT(!si1.contains(si1._sxLeft, si1._syTop));
TS_ASSERT(!si1.contains(si1._sxLeft, si1._syBot));
TS_ASSERT(!si1.contains(si1._sxRight, si1._syTop));
TS_ASSERT(!si1.contains(si1._sxRight, si1._syBot));
TS_ASSERT(!si1.contains(si1._sxBot + 1, si1._syBot));
TS_ASSERT(!si1.contains(si1._sxBot - 1, si1._syBot));
TS_ASSERT(!si1.contains(si1._sxTop + 1, si1._syTop));
TS_ASSERT(!si1.contains(si1._sxTop - 1, si1._syTop));
}
void test_basic_overlap() {
Ultima::Ultima8::SortItem si1;
Ultima::Ultima8::SortItem si2;
Ultima::Ultima8::Box b1(0, 0, 0, 128, 128, 16);
si1.setBoxBounds(b1, 0, 0);
si2.setBoxBounds(b1, 0, 0);
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
Ultima::Ultima8::Box b2(0, 0, 0, 128, 128, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(si1.overlap(si2));
TS_ASSERT(si2.overlap(si1));
// Check outside bounds using flats
b1 = Ultima::Ultima8::Box(0, 0, 0, 128, 128, 0);
si1.setBoxBounds(b1, 0, 0);
b2 = Ultima::Ultima8::Box(128, 0, 0, 128, 128, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
b2 = Ultima::Ultima8::Box(-128, 0, 0, 128, 128, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
b2 = Ultima::Ultima8::Box(0, 128, 0, 128, 128, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
b2 = Ultima::Ultima8::Box(0, -128, 0, 128, 128, 0);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
// Check edge left & right bounds using non-flats
b1 = Ultima::Ultima8::Box(0, 0, 0, 128, 128, 32);
si1.setBoxBounds(b1, 0, 0);
b2 = Ultima::Ultima8::Box(128, -128, 0, 128, 128, 32);
si2.setBoxBounds(b2, 0, 0);
// These often share a one pixel edge, but we need to ignore that currently to prevent paint dependency cycles
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
b2 = Ultima::Ultima8::Box(-128, 128, 0, 128, 128, 32);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
// Check outside left & right bounds using non-flats
b2 = Ultima::Ultima8::Box(160, -128, 0, 128, 128, 32);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
b2 = Ultima::Ultima8::Box(-128, 160, 0, 128, 128, 32);
si2.setBoxBounds(b2, 0, 0);
TS_ASSERT(!si1.overlap(si2));
TS_ASSERT(!si2.overlap(si1));
}
};