Browse Source

Extract objcurs widths into a file

Read from the widths file when using the original CEL.
When using CLX, use width in CLX.
pull/6972/head
Gleb Mazovetskiy 2 years ago
parent
commit
dc59cdaee4
  1. 6
      CMake/Assets.cmake
  2. 151
      Source/cursor.cpp
  3. 5
      Source/engine/clx_sprite.hpp
  4. 3
      Source/inv.cpp
  5. 1
      Source/itemdat.cpp
  6. 3
      Source/itemdat.h
  7. 179
      assets/data/inv/objcurs-widths.txt
  8. 61
      assets/data/inv/objcurs2-widths.txt
  9. 4
      assets/txtdata/items/itemdat.tsv
  10. 38
      test/inv_test.cpp
  11. 11
      test/pack_test.cpp
  12. 11
      test/player_test.cpp
  13. 11
      test/writehero_test.cpp

6
CMake/Assets.cmake

@ -173,6 +173,12 @@ set(devilutionx_assets
ui_art/mainmenuw.clx
ui_art/supportw.clx)
if(NOT UNPACKED_MPQS)
list(APPEND devilutionx_assets
data/inv/objcurs-widths.txt
data/inv/objcurs2-widths.txt)
endif()
if(NOT USE_SDL1 AND NOT VITA)
list(APPEND devilutionx_assets
ui_art/button.png

151
Source/cursor.cpp

@ -7,6 +7,9 @@
#include <cmath>
#include <cstdint>
#include <limits>
#include <string_view>
#include <vector>
#include <fmt/format.h>
@ -17,7 +20,6 @@
#include "engine.h"
#include "engine/backbuffer_state.hpp"
#include "engine/demomode.h"
#include "engine/load_cel.hpp"
#include "engine/point.hpp"
#include "engine/points_in_rectangle_range.hpp"
#include "engine/render/clx_render.hpp"
@ -37,84 +39,20 @@
#include "utils/surface_to_clx.hpp"
#include "utils/utf8.hpp"
#ifdef UNPACKED_MPQS
#include "engine/load_clx.hpp"
#else
#include "engine/load_cel.hpp"
#include "engine/load_file.hpp"
#include "utils/parse_int.hpp"
#endif
namespace devilution {
namespace {
/** Cursor images CEL */
OptionalOwnedClxSpriteList pCursCels;
OptionalOwnedClxSpriteList pCursCels2;
/** Maps from objcurs.cel frame number to frame width. */
const uint16_t InvItemWidth1[] = {
// clang-format off
// Cursors
33, 32, 32, 32, 32, 32, 32, 32, 32, 32, 23,
// Items
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
};
const uint16_t InvItemWidth2[] = {
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
2 * 28, 2 * 28, 1 * 28, 1 * 28, 1 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28
// clang-format on
};
constexpr uint16_t InvItems1Size = sizeof(InvItemWidth1) / sizeof(InvItemWidth1[0]);
constexpr uint16_t InvItems2Size = sizeof(InvItemWidth2) / sizeof(InvItemWidth2[0]);
/** Maps from objcurs.cel frame number to frame height. */
const uint16_t InvItemHeight1[InvItems1Size] = {
// clang-format off
// Cursors
29, 32, 32, 32, 32, 32, 32, 32, 32, 32, 35,
// Items
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28, 2 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
};
const uint16_t InvItemHeight2[InvItems2Size] = {
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28, 1 * 28,
2 * 28, 2 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28, 3 * 28,
3 * 28
// clang-format on
};
OptionalOwnedClxSpriteList *HalfSizeItemSprites;
OptionalOwnedClxSpriteList *HalfSizeItemSpritesRed;
@ -430,6 +368,30 @@ bool TrySelectPixelBased(Point tile)
return false;
}
#ifndef UNPACKED_MPQS
std::vector<uint16_t> ReadWidths(const char *path)
{
size_t len;
const std::unique_ptr<char[]> data = LoadFileInMem<char>(path, &len);
std::string_view str { data.get(), len };
std::vector<uint16_t> result;
while (!str.empty()) {
const char *end;
const ParseIntResult<uint16_t> parseResult = ParseInt<uint16_t>(str, std::numeric_limits<uint16_t>::min(),
std::numeric_limits<uint16_t>::max(), &end);
if (!parseResult.has_value()) {
app_fatal(StrCat("Failed to parse ", path, ": [", str, "]"));
}
result.push_back(parseResult.value());
str.remove_prefix(end - str.data());
while (!str.empty() && (str[0] == '\r' || str[0] == '\n')) {
str.remove_prefix(1);
}
}
return result;
}
#endif
} // namespace
/** Current highlighted monster */
@ -455,9 +417,17 @@ int pcurs;
void InitCursor()
{
assert(!pCursCels);
pCursCels = LoadCel("data\\inv\\objcurs", InvItemWidth1);
if (gbIsHellfire)
pCursCels2 = LoadCel("data\\inv\\objcurs2", InvItemWidth2);
#ifdef UNPACKED_MPQS
pCursCels = LoadClx("data\\inv\\objcurs.clx");
if (gbIsHellfire) {
pCursCels2 = LoadClx("data\\inv\\objcurs2.clx");
}
#else
pCursCels = LoadCel("data\\inv\\objcurs", ReadWidths("data\\inv\\objcurs-widths.txt").data());
if (gbIsHellfire) {
pCursCels2 = LoadCel("data\\inv\\objcurs2", ReadWidths("data\\inv\\objcurs2-widths.txt").data());
}
#endif
ClearCursor();
}
@ -470,22 +440,20 @@ void FreeCursor()
ClxSprite GetInvItemSprite(int cursId)
{
if (cursId <= InvItems1Size)
assert(cursId > 0);
const size_t numSprites = pCursCels->numSprites();
if (static_cast<size_t>(cursId) <= numSprites) {
return (*pCursCels)[cursId - 1];
return (*pCursCels2)[cursId - InvItems1Size - 1];
}
size_t GetNumInvItems()
{
return InvItems1Size + InvItems2Size;
}
assert(gbIsHellfire);
assert(cursId - numSprites <= pCursCels2->numSprites());
return (*pCursCels2)[cursId - numSprites - 1];
}
Size GetInvItemSize(int cursId)
{
const int i = cursId - 1;
if (i >= InvItems1Size)
return { InvItemWidth2[i - InvItems1Size], InvItemHeight2[i - InvItems1Size] };
return { InvItemWidth1[i], InvItemHeight1[i] };
const ClxSprite sprite = GetInvItemSprite(cursId);
return { sprite.width(), sprite.height() };
}
ClxSprite GetHalfSizeItemSprite(int cursId)
@ -502,9 +470,8 @@ void CreateHalfSizeItemSprites()
{
if (HalfSizeItemSprites != nullptr)
return;
const int numInvItems = gbIsHellfire
? InvItems1Size + InvItems2Size - (static_cast<size_t>(CURSOR_FIRSTITEM) - 1)
: InvItems1Size + (static_cast<size_t>(CURSOR_FIRSTITEM) - 1);
const int numInvItems = pCursCels->numSprites() - (static_cast<size_t>(CURSOR_FIRSTITEM) - 1)
+ (gbIsHellfire ? pCursCels2->numSprites() : 0);
HalfSizeItemSprites = new OptionalOwnedClxSpriteList[numInvItems];
HalfSizeItemSpritesRed = new OptionalOwnedClxSpriteList[numInvItems];
const uint8_t *redTrn = GetInfravisionTRN();
@ -538,11 +505,11 @@ void CreateHalfSizeItemSprites()
};
size_t outputIndex = 0;
for (size_t i = static_cast<int>(CURSOR_FIRSTITEM) - 1; i < InvItems1Size; ++i, ++outputIndex) {
for (size_t i = static_cast<int>(CURSOR_FIRSTITEM) - 1, n = pCursCels->numSprites(); i < n; ++i, ++outputIndex) {
createHalfSize((*pCursCels)[i], outputIndex);
}
if (gbIsHellfire) {
for (size_t i = 0; i < InvItems2Size; ++i, ++outputIndex) {
for (size_t i = 0, n = pCursCels2->numSprites(); i < n; ++i, ++outputIndex) {
createHalfSize((*pCursCels2)[i], outputIndex);
}
}

5
Source/engine/clx_sprite.hpp

@ -362,6 +362,11 @@ public:
return ClxSpriteList { *this }[spriteIndex];
}
[[nodiscard]] uint32_t numSprites() const
{
return ClxSpriteList { *this }.numSprites();
}
private:
// For OptionalOwnedClxSpriteList.
OwnedClxSpriteList() = default;

3
Source/inv.cpp

@ -2154,8 +2154,7 @@ int CalculateGold(Player &player)
Size GetInventorySize(const Item &item)
{
int itemSizeIndex = item._iCurs + CURSOR_FIRSTITEM;
auto size = GetInvItemSize(itemSizeIndex);
auto size = GetInvItemSize(item._iCurs + CURSOR_FIRSTITEM);
return { size.width / InventorySlotSizeInPixels.width, size.height / InventorySlotSizeInPixels.height };
}

1
Source/itemdat.cpp

@ -175,7 +175,6 @@ tl::expected<item_cursor_graphic, std::string> ParseItemCursorGraphic(std::strin
if (value == "SHORT_WAR_BOW") return ICURS_SHORT_WAR_BOW;
if (value == "COMPOSITE_STAFF") return ICURS_COMPOSITE_STAFF;
if (value == "SHORT_BATTLE_BOW") return ICURS_SHORT_BATTLE_BOW;
if (value == "GOLD") return ICURS_GOLD;
if (value == "AURIC_AMULET") return ICURS_AURIC_AMULET;
if (value == "RUNE_BOMB") return ICURS_RUNE_BOMB;
if (value == "THEODORE") return ICURS_THEODORE;

3
Source/itemdat.h

@ -71,6 +71,7 @@ enum _item_indexes : int16_t { // TODO defines all indexes in AllItemsList
IDI_BOOK3,
IDI_BOOK4,
IDI_BARBARIAN = 139,
IDI_SHORT_BATTLE_BOW = 148,
IDI_RUNEOFSTONE = 165,
IDI_SORCERER_DIABLO,
IDI_ARENAPOT,
@ -217,7 +218,7 @@ enum item_cursor_graphic : uint8_t {
ICURS_SHORT_WAR_BOW = 165,
ICURS_COMPOSITE_STAFF = 166,
ICURS_SHORT_BATTLE_BOW = 167,
ICURS_GOLD = 168,
// Hellfire items:
ICURS_AURIC_AMULET = 180,
ICURS_RUNE_BOMB = 187,
ICURS_THEODORE = 188,

179
assets/data/inv/objcurs-widths.txt

@ -0,0 +1,179 @@
33
32
32
32
32
32
32
32
32
32
23
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56

61
assets/data/inv/objcurs2-widths.txt

@ -0,0 +1,61 @@
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
28
56
56
28
28
28
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56
56

4
assets/txtdata/items/itemdat.tsv

@ -1,5 +1,5 @@
id dropRate class equipType cursorGraphic itemType uniqueBaseItem name shortName minMonsterLevel durability minDamage maxDamage minArmor maxArmor minStrength minMagic minDexterity specialEffects miscId spell usable value
IDI_GOLD Regular Gold Unequippable GOLD Gold NONE Gold 1 0 0 0 0 0 0 0 0 NONE Null true 0
IDI_GOLD Regular Gold Unequippable GOLD_SMALL Gold NONE Gold 1 0 0 0 0 0 0 0 0 NONE Null true 0
IDI_WARRIOR Never Weapon One-handed SHORT_SWORD Sword NONE Short Sword 2 20 2 6 0 0 18 0 0 NONE Null false 50
IDI_WARRSHLD Never Armor One-handed BUCKLER Shield NONE Buckler 2 10 0 0 3 3 0 0 0 NONE Null false 50
IDI_WARRCLUB Never Weapon One-handed CLUB Mace SPIKCLUB Club 1 20 1 6 0 0 0 0 0 NONE Null false 20
@ -146,7 +146,7 @@ IDI_GREYSUIT Never Quest Unequippable GREY_SUIT Misc NONE Grey Suit 0 0 0 0 0 0
Double Weapon Two-handed HUNTERS_BOW Bow HUNTBOW Hunter's Bow Bow 3 40 2 5 0 0 20 0 35 NONE Null false 350
Double Weapon Two-handed HUNTERS_BOW Bow LONGBOW Long Bow Bow 5 35 1 6 0 0 25 0 30 NONE Null false 250
Double Weapon Two-handed COMPOSITE_BOW Bow COMPBOW Composite Bow Bow 7 45 3 6 0 0 25 0 40 NONE Null false 600
Double Weapon Two-handed SHORT_BATTLE_BOW Bow NONE Short Battle Bow Bow 9 45 3 7 0 0 30 0 50 NONE Null false 750
IDI_SHORT_BATTLE_BOW Double Weapon Two-handed SHORT_BATTLE_BOW Bow NONE Short Battle Bow Bow 9 45 3 7 0 0 30 0 50 NONE Null false 750
Double Weapon Two-handed LONG_BATTLE_BOW Bow BATTLEBOW Long Battle Bow Bow 11 50 1 10 0 0 30 0 60 NONE Null false 1000
Double Weapon Two-handed SHORT_WAR_BOW Bow NONE Short War Bow Bow 15 55 4 8 0 0 35 0 70 NONE Null false 1500
Double Weapon Two-handed LONG_WAR_BOW Bow WARBOW Long War Bow Bow 19 60 1 14 0 0 45 0 80 NONE Null false 2000

1 id dropRate class equipType cursorGraphic itemType uniqueBaseItem name shortName minMonsterLevel durability minDamage maxDamage minArmor maxArmor minStrength minMagic minDexterity specialEffects miscId spell usable value
2 IDI_GOLD Regular Gold Unequippable GOLD GOLD_SMALL Gold NONE Gold 1 0 0 0 0 0 0 0 0 NONE Null true 0
3 IDI_WARRIOR Never Weapon One-handed SHORT_SWORD Sword NONE Short Sword 2 20 2 6 0 0 18 0 0 NONE Null false 50
4 IDI_WARRSHLD Never Armor One-handed BUCKLER Shield NONE Buckler 2 10 0 0 3 3 0 0 0 NONE Null false 50
5 IDI_WARRCLUB Never Weapon One-handed CLUB Mace SPIKCLUB Club 1 20 1 6 0 0 0 0 0 NONE Null false 20
146 Double Weapon Two-handed HUNTERS_BOW Bow HUNTBOW Hunter's Bow Bow 3 40 2 5 0 0 20 0 35 NONE Null false 350
147 Double Weapon Two-handed HUNTERS_BOW Bow LONGBOW Long Bow Bow 5 35 1 6 0 0 25 0 30 NONE Null false 250
148 Double Weapon Two-handed COMPOSITE_BOW Bow COMPBOW Composite Bow Bow 7 45 3 6 0 0 25 0 40 NONE Null false 600
149 IDI_SHORT_BATTLE_BOW Double Weapon Two-handed SHORT_BATTLE_BOW Bow NONE Short Battle Bow Bow 9 45 3 7 0 0 30 0 50 NONE Null false 750
150 Double Weapon Two-handed LONG_BATTLE_BOW Bow BATTLEBOW Long Battle Bow Bow 11 50 1 10 0 0 30 0 60 NONE Null false 1000
151 Double Weapon Two-handed SHORT_WAR_BOW Bow NONE Short War Bow Bow 15 55 4 8 0 0 35 0 70 NONE Null false 1500
152 Double Weapon Two-handed LONG_WAR_BOW Bow WARBOW Long War Bow Bow 19 60 1 14 0 0 45 0 80 NONE Null false 2000

38
test/inv_test.cpp

@ -18,6 +18,14 @@ public:
static void SetUpTestSuite()
{
LoadCoreArchives();
LoadGameArchives();
// The tests need spawn.mpq or diabdat.mpq
// Please provide them so that the tests can run successfully
ASSERT_TRUE(HaveSpawn() || HaveDiabdat());
InitCursor();
LoadSpellData();
LoadItemData();
}
@ -287,26 +295,40 @@ TEST_F(InvTest, RemoveCurrentSpellScrollFirstMatchFromBelt)
EXPECT_TRUE(MyPlayer->SpdList[3].isEmpty());
}
TEST_F(InvTest, ItemSize)
TEST_F(InvTest, ItemSizeRuneOfStone)
{
Item testItem {};
// Inventory sizes are currently determined by examining the sprite size
// rune of stone and grey suit are adjacent in the sprite list so provide an easy check for off-by-one errors
if (!gbIsHellfire) return;
Item testItem {};
InitializeItem(testItem, IDI_RUNEOFSTONE);
EXPECT_EQ(GetInventorySize(testItem), Size(1, 1));
}
TEST_F(InvTest, ItemSizeGreySuit)
{
if (!gbIsHellfire) return;
Item testItem {};
InitializeItem(testItem, IDI_GREYSUIT);
EXPECT_EQ(GetInventorySize(testItem), Size(2, 2));
}
// auric amulet is the first used hellfire sprite, but there's multiple unused sprites before it in the list.
TEST_F(InvTest, ItemSizeAuric)
{
// Auric amulet is the first used hellfire sprite, but there's multiple unused sprites before it in the list.
// unfortunately they're the same size so this is less valuable as a test.
if (!gbIsHellfire) return;
Item testItem {};
InitializeItem(testItem, IDI_AURIC);
EXPECT_EQ(GetInventorySize(testItem), Size(1, 1));
}
// gold is the last diablo sprite, off by ones will end up loading a 1x1 unused sprite from hellfire but maybe
// this'll segfault if we make a mistake in the future?
InitializeItem(testItem, IDI_GOLD);
EXPECT_EQ(GetInventorySize(testItem), Size(1, 1));
TEST_F(InvTest, ItemSizeLastDiabloItem)
{
// Short battle bow is the last diablo sprite, off by ones will end up loading a 1x1 unused sprite from hellfire,.
Item testItem {};
InitializeItem(testItem, IDI_SHORT_BATTLE_BOW);
EXPECT_EQ(GetInventorySize(testItem), Size(2, 3));
}
} // namespace

11
test/pack_test.cpp

@ -2,6 +2,7 @@
#include <gtest/gtest.h>
#include "cursor.h"
#include "monstdat.h"
#include "pack.h"
#include "playerdat.hpp"
@ -879,6 +880,7 @@ public:
Players.resize(2);
MyPlayer = &Players[0];
gbIsMultiplayer = true;
gbIsSpawn = false;
PlayerPack testPack {
0, 0, -1, 9, 0, 2, 61, 24, 0, 0, "MP-Warrior", 0, 120, 25, 60, 60, 37, 0, 85670061, 3921, 13568, 13568, 3904, 3904,
@ -954,6 +956,15 @@ public:
static void SetUpTestSuite()
{
LoadCoreArchives();
LoadGameArchives();
// The tests need spawn.mpq or diabdat.mpq
// Please provide them so that the tests can run successfully
ASSERT_TRUE(HaveSpawn() || HaveDiabdat());
gbIsHellfire = false;
InitCursor();
LoadSpellData();
LoadPlayerDataFiles();
LoadMonsterData();

11
test/player_test.cpp

@ -2,6 +2,8 @@
#include <gtest/gtest.h>
#include "cursor.h"
#include "init.h"
#include "playerdat.hpp"
using namespace devilution;
@ -179,6 +181,15 @@ static void AssertPlayer(Player &player)
TEST(Player, CreatePlayer)
{
LoadCoreArchives();
LoadGameArchives();
// The tests need spawn.mpq or diabdat.mpq
// Please provide them so that the tests can run successfully
ASSERT_TRUE(HaveSpawn() || HaveDiabdat());
InitCursor();
LoadPlayerDataFiles();
LoadItemData();
Players.resize(1);

11
test/writehero_test.cpp

@ -8,6 +8,8 @@
#include <gtest/gtest.h>
#include <picosha2.h>
#include "cursor.h"
#include "init.h"
#include "loadsave.h"
#include "pack.h"
#include "pfile.h"
@ -360,11 +362,19 @@ void AssertPlayer(Player &player)
TEST(Writehero, pfile_write_hero)
{
LoadCoreArchives();
LoadGameArchives();
// The tests need spawn.mpq or diabdat.mpq
// Please provide them so that the tests can run successfully
ASSERT_TRUE(HaveSpawn() || HaveDiabdat());
paths::SetPrefPath(".");
std::remove("multi_0.sv");
gbVanilla = true;
gbIsHellfire = false;
gbIsSpawn = false;
gbIsMultiplayer = true;
gbIsHellfireSaveGame = false;
leveltype = DTYPE_TOWN;
@ -374,6 +384,7 @@ TEST(Writehero, pfile_write_hero)
MyPlayerId = 0;
MyPlayer = &Players[MyPlayerId];
InitCursor();
LoadSpellData();
LoadPlayerDataFiles();
LoadItemData();

Loading…
Cancel
Save