Browse Source

Clean up owned/unowned CelSprite ambiguity

Makes `CelSprite` unowned and adds a new `OwnedCelSprite` class for
owned sprites.

This clarifies ownership and makes the code cleaner in a number of
places.

Additionally, because the `CelSprite` class is now tiny (1 less
pointer), we can pass it by-value instead of by-reference, removing a
pointer indirection in the rendering functions.
pull/4127/head
Gleb Mazovetskiy 4 years ago
parent
commit
7fede6c4cb
  1. 12
      Source/control.cpp
  2. 2
      Source/controls/modifier_hints.cpp
  3. 2
      Source/controls/touch/renderers.cpp
  4. 6
      Source/cursor.cpp
  5. 2
      Source/cursor.h
  6. 6
      Source/dead.cpp
  7. 2
      Source/dead.h
  8. 2
      Source/debug.cpp
  9. 2
      Source/debug.h
  10. 2
      Source/doom.cpp
  11. 8
      Source/engine/animationinfo.cpp
  12. 11
      Source/engine/animationinfo.h
  13. 73
      Source/engine/cel_sprite.hpp
  14. 8
      Source/engine/load_cel.cpp
  15. 4
      Source/engine/load_cel.hpp
  16. 20
      Source/engine/render/cel_render.cpp
  17. 20
      Source/engine/render/cel_render.hpp
  18. 8
      Source/engine/render/cl2_render.cpp
  19. 8
      Source/engine/render/cl2_render.hpp
  20. 2
      Source/engine/render/text_render.cpp
  21. 2
      Source/engine/render/text_render.hpp
  22. 2
      Source/gendung.cpp
  23. 2
      Source/gendung.h
  24. 8
      Source/gmenu.cpp
  25. 2
      Source/interfac.cpp
  26. 2
      Source/inv.cpp
  27. 26
      Source/items.cpp
  28. 126
      Source/items.h
  29. 2
      Source/loadsave.cpp
  30. 2
      Source/minitext.cpp
  31. 4
      Source/missiles.cpp
  32. 31
      Source/monster.cpp
  33. 15
      Source/monster.h
  34. 2
      Source/panels/charpanel.cpp
  35. 2
      Source/panels/charpanel.hpp
  36. 4
      Source/panels/info_box.cpp
  37. 4
      Source/panels/info_box.hpp
  38. 6
      Source/panels/spell_book.cpp
  39. 4
      Source/panels/spell_icons.cpp
  40. 2
      Source/panels/spell_icons.hpp
  41. 20
      Source/player.cpp
  42. 8
      Source/player.h
  43. 2
      Source/qol/itemlabels.cpp
  44. 2
      Source/quests.cpp
  45. 2
      Source/quests.h
  46. 49
      Source/scrollrt.cpp
  47. 2
      test/animationinfo_test.cpp
  48. 2
      test/inv_test.cpp

12
Source/control.cpp

@ -122,11 +122,11 @@ namespace {
std::optional<OwnedSurface> pLifeBuff; std::optional<OwnedSurface> pLifeBuff;
std::optional<OwnedSurface> pManaBuff; std::optional<OwnedSurface> pManaBuff;
std::optional<CelSprite> talkButtons; std::optional<OwnedCelSprite> talkButtons;
std::optional<CelSprite> pDurIcons; std::optional<OwnedCelSprite> pDurIcons;
std::optional<CelSprite> multiButtons; std::optional<OwnedCelSprite> multiButtons;
std::optional<CelSprite> pPanelButtons; std::optional<OwnedCelSprite> pPanelButtons;
std::optional<CelSprite> pGBoxBuff; std::optional<OwnedCelSprite> pGBoxBuff;
bool PanelButtons[8]; bool PanelButtons[8];
int PanelButtonIndex; int PanelButtonIndex;
@ -518,7 +518,7 @@ void InitControlPan()
CelDrawUnsafeTo(*pBtmBuff, { 0, (PANEL_HEIGHT + 16) - 1 }, LoadCel("CtrlPan\\Panel8.CEL", PANEL_WIDTH), 1); CelDrawUnsafeTo(*pBtmBuff, { 0, (PANEL_HEIGHT + 16) - 1 }, LoadCel("CtrlPan\\Panel8.CEL", PANEL_WIDTH), 1);
{ {
const Point bulbsPosition { 0, 87 }; const Point bulbsPosition { 0, 87 };
const CelSprite statusPanel = LoadCel("CtrlPan\\P8Bulbs.CEL", 88); const OwnedCelSprite statusPanel = LoadCel("CtrlPan\\P8Bulbs.CEL", 88);
CelDrawUnsafeTo(*pLifeBuff, bulbsPosition, statusPanel, 1); CelDrawUnsafeTo(*pLifeBuff, bulbsPosition, statusPanel, 1);
CelDrawUnsafeTo(*pManaBuff, bulbsPosition, statusPanel, 2); CelDrawUnsafeTo(*pManaBuff, bulbsPosition, statusPanel, 2);
} }

2
Source/controls/modifier_hints.cpp

@ -15,7 +15,7 @@
namespace devilution { namespace devilution {
extern std::optional<CelSprite> pSBkIconCels; extern std::optional<OwnedCelSprite> pSBkIconCels;
namespace { namespace {

2
Source/controls/touch/renderers.cpp

@ -139,7 +139,7 @@ void LoadPotionArt(Art *potionArt, SDL_Renderer *renderer)
Point position { 0, 0 }; Point position { 0, 0 };
for (item_cursor_graphic graphic : potionGraphics) { for (item_cursor_graphic graphic : potionGraphics) {
const int frame = CURSOR_FIRSTITEM + graphic; const int frame = CURSOR_FIRSTITEM + graphic;
const CelSprite &potionSprite = GetInvItemSprite(frame); const OwnedCelSprite &potionSprite = GetInvItemSprite(frame);
position.y += potionSize.height; position.y += potionSize.height;
CelClippedDrawTo(Surface(surface.get()), position, potionSprite, frame); CelClippedDrawTo(Surface(surface.get()), position, potionSprite, frame);
} }

6
Source/cursor.cpp

@ -27,8 +27,8 @@
namespace devilution { namespace devilution {
namespace { namespace {
/** Cursor images CEL */ /** Cursor images CEL */
std::optional<CelSprite> pCursCels; std::optional<OwnedCelSprite> pCursCels;
std::optional<CelSprite> pCursCels2; std::optional<OwnedCelSprite> pCursCels2;
constexpr int InvItems1Size = 180; constexpr int InvItems1Size = 180;
/** Maps from objcurs.cel frame number to frame width. */ /** Maps from objcurs.cel frame number to frame width. */
@ -143,7 +143,7 @@ void FreeCursor()
ClearCursor(); ClearCursor();
} }
const CelSprite &GetInvItemSprite(int i) const OwnedCelSprite &GetInvItemSprite(int i)
{ {
return i < InvItems1Size ? *pCursCels : *pCursCels2; return i < InvItems1Size ? *pCursCels : *pCursCels2;
} }

2
Source/cursor.h

@ -61,7 +61,7 @@ inline bool IsItemSprite(int cursId)
void CelDrawCursor(const Surface &out, Point position, int cursId); void CelDrawCursor(const Surface &out, Point position, int cursId);
/** Returns the sprite for the given inventory index. */ /** Returns the sprite for the given inventory index. */
const CelSprite &GetInvItemSprite(int i); const OwnedCelSprite &GetInvItemSprite(int i);
/** Returns the CEL frame index for the given inventory index. */ /** Returns the CEL frame index for the given inventory index. */
int GetInvItemFrame(int i); int GetInvItemFrame(int i);

6
Source/dead.cpp

@ -18,12 +18,10 @@ int8_t stonendx;
namespace { namespace {
void InitDeadAnimationFromMonster(Corpse &corpse, const CMonster &mon) void InitDeadAnimationFromMonster(Corpse &corpse, const CMonster &mon)
{ {
int i = 0;
const auto &animData = mon.GetAnimData(MonsterGraphic::Death); const auto &animData = mon.GetAnimData(MonsterGraphic::Death);
for (const auto &celSprite : animData.CelSpritesForDirections) memcpy(&corpse.data[0], &animData.CelSpritesForDirections[0], sizeof(animData.CelSpritesForDirections[0]) * animData.CelSpritesForDirections.size());
corpse.data[i++] = celSprite->Data();
corpse.frame = animData.Frames; corpse.frame = animData.Frames;
corpse.width = animData.CelSpritesForDirections[0]->Width(); corpse.width = animData.Width;
} }
} // namespace } // namespace

2
Source/dead.h

@ -18,7 +18,7 @@ static constexpr unsigned MaxCorpses = 31;
struct Corpse { struct Corpse {
std::array<const byte *, 8> data; std::array<const byte *, 8> data;
int frame; int frame;
int width; unsigned width;
uint8_t translationPaletteIndex; uint8_t translationPaletteIndex;
}; };

2
Source/debug.cpp

@ -32,7 +32,7 @@
namespace devilution { namespace devilution {
std::optional<CelSprite> pSquareCel; std::optional<OwnedCelSprite> pSquareCel;
bool DebugToggle = false; bool DebugToggle = false;
bool DebugGodMode = false; bool DebugGodMode = false;
bool DebugVision = false; bool DebugVision = false;

2
Source/debug.h

@ -15,7 +15,7 @@
namespace devilution { namespace devilution {
extern std::optional<CelSprite> pSquareCel; extern std::optional<OwnedCelSprite> pSquareCel;
extern bool DebugToggle; extern bool DebugToggle;
extern bool DebugGodMode; extern bool DebugGodMode;
extern bool DebugVision; extern bool DebugVision;

2
Source/doom.cpp

@ -14,7 +14,7 @@
namespace devilution { namespace devilution {
namespace { namespace {
std::optional<CelSprite> DoomCel; std::optional<OwnedCelSprite> DoomCel;
} // namespace } // namespace
bool DoomFlag; bool DoomFlag;

8
Source/engine/animationinfo.cpp

@ -75,7 +75,7 @@ float AnimationInfo::GetAnimationProgress() const
return animationFraction; return animationFraction;
} }
void AnimationInfo::SetNewAnimation(const CelSprite *celSprite, int numberOfFrames, int ticksPerFrame, AnimationDistributionFlags flags /*= AnimationDistributionFlags::None*/, int numSkippedFrames /*= 0*/, int distributeFramesBeforeFrame /*= 0*/, float previewShownGameTickFragments /*= 0.F*/) void AnimationInfo::SetNewAnimation(std::optional<CelSprite> celSprite, int numberOfFrames, int ticksPerFrame, AnimationDistributionFlags flags /*= AnimationDistributionFlags::None*/, int numSkippedFrames /*= 0*/, int distributeFramesBeforeFrame /*= 0*/, float previewShownGameTickFragments /*= 0.F*/)
{ {
if ((flags & AnimationDistributionFlags::RepeatedAction) == AnimationDistributionFlags::RepeatedAction && distributeFramesBeforeFrame != 0 && NumberOfFrames == numberOfFrames && CurrentFrame >= distributeFramesBeforeFrame && CurrentFrame != NumberOfFrames) { if ((flags & AnimationDistributionFlags::RepeatedAction) == AnimationDistributionFlags::RepeatedAction && distributeFramesBeforeFrame != 0 && NumberOfFrames == numberOfFrames && CurrentFrame >= distributeFramesBeforeFrame && CurrentFrame != NumberOfFrames) {
// We showed the same Animation (for example a melee attack) before but truncated the Animation. // We showed the same Animation (for example a melee attack) before but truncated the Animation.
@ -90,7 +90,7 @@ void AnimationInfo::SetNewAnimation(const CelSprite *celSprite, int numberOfFram
ticksPerFrame = 1; ticksPerFrame = 1;
} }
this->pCelSprite = celSprite; this->celSprite = celSprite;
NumberOfFrames = numberOfFrames; NumberOfFrames = numberOfFrames;
CurrentFrame = 1 + numSkippedFrames; CurrentFrame = 1 + numSkippedFrames;
TickCounterOfCurrentFrame = 0; TickCounterOfCurrentFrame = 0;
@ -168,7 +168,7 @@ void AnimationInfo::SetNewAnimation(const CelSprite *celSprite, int numberOfFram
} }
} }
void AnimationInfo::ChangeAnimationData(const CelSprite *celSprite, int numberOfFrames, int ticksPerFrame) void AnimationInfo::ChangeAnimationData(std::optional<CelSprite> celSprite, int numberOfFrames, int ticksPerFrame)
{ {
if (numberOfFrames != NumberOfFrames || ticksPerFrame != TicksPerFrame) { if (numberOfFrames != NumberOfFrames || ticksPerFrame != TicksPerFrame) {
// Ensure that the CurrentFrame is still valid and that we disable ADL cause the calculcated values (for example TickModifier) could be wrong // Ensure that the CurrentFrame is still valid and that we disable ADL cause the calculcated values (for example TickModifier) could be wrong
@ -183,7 +183,7 @@ void AnimationInfo::ChangeAnimationData(const CelSprite *celSprite, int numberOf
RelevantFramesForDistributing = 0; RelevantFramesForDistributing = 0;
TickModifier = 0.0F; TickModifier = 0.0F;
} }
this->pCelSprite = celSprite; this->celSprite = celSprite;
} }
void AnimationInfo::ProcessAnimation(bool reverseAnimation /*= false*/, bool dontProgressAnimation /*= false*/) void AnimationInfo::ProcessAnimation(bool reverseAnimation /*= false*/, bool dontProgressAnimation /*= false*/)

11
Source/engine/animationinfo.h

@ -5,10 +5,11 @@
*/ */
#pragma once #pragma once
#include <stdint.h> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "engine/cel_sprite.hpp" #include "engine/cel_sprite.hpp"
#include "utils/stdcompat/optional.hpp"
namespace devilution { namespace devilution {
@ -37,9 +38,9 @@ enum AnimationDistributionFlags : uint8_t {
class AnimationInfo { class AnimationInfo {
public: public:
/** /**
* @brief Pointer to Animation Sprite * @brief Animation sprite
*/ */
const CelSprite *pCelSprite; std::optional<CelSprite> celSprite;
/** /**
* @brief How many game ticks are needed to advance one Animation Frame * @brief How many game ticks are needed to advance one Animation Frame
*/ */
@ -82,7 +83,7 @@ public:
* @param distributeFramesBeforeFrame Distribute the numSkippedFrames only before this frame * @param distributeFramesBeforeFrame Distribute the numSkippedFrames only before this frame
* @param previewShownGameTickFragments Defines how long (in game ticks fraction) the preview animation was shown * @param previewShownGameTickFragments Defines how long (in game ticks fraction) the preview animation was shown
*/ */
void SetNewAnimation(const CelSprite *celSprite, int numberOfFrames, int ticksPerFrame, AnimationDistributionFlags flags = AnimationDistributionFlags::None, int numSkippedFrames = 0, int distributeFramesBeforeFrame = 0, float previewShownGameTickFragments = 0.F); void SetNewAnimation(std::optional<CelSprite> celSprite, int numberOfFrames, int ticksPerFrame, AnimationDistributionFlags flags = AnimationDistributionFlags::None, int numSkippedFrames = 0, int distributeFramesBeforeFrame = 0, float previewShownGameTickFragments = 0.F);
/** /**
* @brief Changes the Animation Data on-the-fly. This is needed if a animation is currently in progress and the player changes his gear. * @brief Changes the Animation Data on-the-fly. This is needed if a animation is currently in progress and the player changes his gear.
@ -90,7 +91,7 @@ public:
* @param numberOfFrames Number of Frames in Animation * @param numberOfFrames Number of Frames in Animation
* @param ticksPerFrame How many game ticks are needed to advance one Animation Frame * @param ticksPerFrame How many game ticks are needed to advance one Animation Frame
*/ */
void ChangeAnimationData(const CelSprite *celSprite, int numberOfFrames, int ticksPerFrame); void ChangeAnimationData(std::optional<CelSprite> celSprite, int numberOfFrames, int ticksPerFrame);
/** /**
* @brief Process the Animation for a game tick (for example advances the frame) * @brief Process the Animation for a game tick (for example advances the frame)

73
Source/engine/cel_sprite.hpp

@ -7,39 +7,31 @@
namespace devilution { namespace devilution {
class OwnedCelSprite;
/** /**
* Stores a CEL or CL2 sprite and its width(s). * Stores a CEL or CL2 sprite and its width(s).
* * Does not own the data.
* The data may be unowned.
* Eventually we'd like to remove the unowned version.
*/ */
class CelSprite { class CelSprite {
public: public:
CelSprite(std::unique_ptr<byte[]> data, int width) CelSprite(const byte *data, int width)
: data_(std::move(data)) : data_ptr_(data)
, data_ptr_(data_.get())
, width_(width) , width_(width)
{ {
} }
CelSprite(std::unique_ptr<byte[]> data, const int *widths) CelSprite(const byte *data, const int *widths)
: data_(std::move(data)) : data_ptr_(data)
, data_ptr_(data_.get())
, widths_(widths) , widths_(widths)
{ {
} }
/** explicit CelSprite(const OwnedCelSprite &owned);
* Constructs an unowned sprite.
* Ideally we'd like to remove all uses of this constructor.
*/
CelSprite(const byte *data, int width)
: data_ptr_(data)
, width_(width)
{
}
CelSprite(const CelSprite &) = default;
CelSprite(CelSprite &&) noexcept = default; CelSprite(CelSprite &&) noexcept = default;
CelSprite &operator=(const CelSprite &) = default;
CelSprite &operator=(CelSprite &&) noexcept = default; CelSprite &operator=(CelSprite &&) noexcept = default;
[[nodiscard]] const byte *Data() const [[nodiscard]] const byte *Data() const
@ -52,11 +44,54 @@ public:
return widths_ == nullptr ? width_ : widths_[frame]; return widths_ == nullptr ? width_ : widths_[frame];
} }
[[nodiscard]] bool operator==(CelSprite other) const
{
return data_ptr_ == other.data_ptr_;
}
[[nodiscard]] bool operator!=(CelSprite other) const
{
return data_ptr_ != other.data_ptr_;
}
private: private:
std::unique_ptr<byte[]> data_;
const byte *data_ptr_; const byte *data_ptr_;
int width_ = 0; int width_ = 0;
const int *widths_ = nullptr; // unowned const int *widths_ = nullptr; // unowned
}; };
/**
* Stores a CEL or CL2 sprite and its width(s).
* Owns the data.
*/
class OwnedCelSprite : public CelSprite {
public:
OwnedCelSprite(std::unique_ptr<byte[]> data, int width)
: CelSprite(data.get(), width)
, data_(std::move(data))
{
}
OwnedCelSprite(std::unique_ptr<byte[]> data, const int *widths)
: CelSprite(data.get(), widths)
, data_(std::move(data))
{
}
OwnedCelSprite(OwnedCelSprite &&) noexcept = default;
OwnedCelSprite &operator=(OwnedCelSprite &&) noexcept = default;
[[nodiscard]] CelSprite Unowned() const
{
return CelSprite(*this);
}
private:
std::unique_ptr<byte[]> data_;
};
inline CelSprite::CelSprite(const OwnedCelSprite &owned)
: CelSprite(static_cast<const CelSprite &>(owned))
{
}
} // namespace devilution } // namespace devilution

8
Source/engine/load_cel.cpp

@ -4,14 +4,14 @@
namespace devilution { namespace devilution {
CelSprite LoadCel(const char *pszName, int width) OwnedCelSprite LoadCel(const char *pszName, int width)
{ {
return CelSprite(LoadFileInMem(pszName), width); return OwnedCelSprite(LoadFileInMem(pszName), width);
} }
CelSprite LoadCel(const char *pszName, const int *widths) OwnedCelSprite LoadCel(const char *pszName, const int *widths)
{ {
return CelSprite(LoadFileInMem(pszName), widths); return OwnedCelSprite(LoadFileInMem(pszName), widths);
} }
} // namespace devilution } // namespace devilution

4
Source/engine/load_cel.hpp

@ -7,7 +7,7 @@ namespace devilution {
/** /**
* @brief Loads a Cel sprite and sets its width * @brief Loads a Cel sprite and sets its width
*/ */
CelSprite LoadCel(const char *pszName, int width); OwnedCelSprite LoadCel(const char *pszName, int width);
CelSprite LoadCel(const char *pszName, const int *widths); OwnedCelSprite LoadCel(const char *pszName, const int *widths);
} // namespace devilution } // namespace devilution

20
Source/engine/render/cel_render.cpp

@ -580,14 +580,14 @@ void CelBlitLightSafeTo(const Surface &out, Point position, const byte *pRLEByte
} // namespace } // namespace
void CelDrawTo(const Surface &out, Point position, const CelSprite &cel, int frame) void CelDrawTo(const Surface &out, Point position, CelSprite cel, int frame)
{ {
int nDataSize; int nDataSize;
const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize); const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize);
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame)); CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
} }
void CelClippedDrawTo(const Surface &out, Point position, const CelSprite &cel, int frame) void CelClippedDrawTo(const Surface &out, Point position, CelSprite cel, int frame)
{ {
int nDataSize; int nDataSize;
const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize); const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
@ -595,7 +595,7 @@ void CelClippedDrawTo(const Surface &out, Point position, const CelSprite &cel,
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame)); CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
} }
void CelDrawLightTo(const Surface &out, Point position, const CelSprite &cel, int frame, uint8_t *tbl) void CelDrawLightTo(const Surface &out, Point position, CelSprite cel, int frame, uint8_t *tbl)
{ {
int nDataSize; int nDataSize;
const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize); const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize);
@ -606,7 +606,7 @@ void CelDrawLightTo(const Surface &out, Point position, const CelSprite &cel, in
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame)); CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
} }
void CelClippedDrawLightTo(const Surface &out, Point position, const CelSprite &cel, int frame) void CelClippedDrawLightTo(const Surface &out, Point position, CelSprite cel, int frame)
{ {
int nDataSize; int nDataSize;
const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize); const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
@ -617,14 +617,14 @@ void CelClippedDrawLightTo(const Surface &out, Point position, const CelSprite &
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame)); CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
} }
void CelDrawLightRedTo(const Surface &out, Point position, const CelSprite &cel, int frame) void CelDrawLightRedTo(const Surface &out, Point position, CelSprite cel, int frame)
{ {
int nDataSize; int nDataSize;
const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize); const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
RenderCelWithLightTable(out, position, pRLEBytes, nDataSize, cel.Width(frame), GetInfravisionTRN()); RenderCelWithLightTable(out, position, pRLEBytes, nDataSize, cel.Width(frame), GetInfravisionTRN());
} }
void CelDrawItem(const Item &item, const Surface &out, Point position, const CelSprite &cel, int frame) void CelDrawItem(const Item &item, const Surface &out, Point position, CelSprite cel, int frame)
{ {
bool usable = item._iStatFlag; bool usable = item._iStatFlag;
if (!usable) { if (!usable) {
@ -634,7 +634,7 @@ void CelDrawItem(const Item &item, const Surface &out, Point position, const Cel
} }
} }
void CelClippedBlitLightTransTo(const Surface &out, Point position, const CelSprite &cel, int frame) void CelClippedBlitLightTransTo(const Surface &out, Point position, CelSprite cel, int frame)
{ {
int nDataSize; int nDataSize;
const byte *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize); const byte *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
@ -647,14 +647,14 @@ void CelClippedBlitLightTransTo(const Surface &out, Point position, const CelSpr
CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame)); CelBlitSafeTo(out, position, pRLEBytes, nDataSize, cel.Width(frame));
} }
void CelDrawUnsafeTo(const Surface &out, Point position, const CelSprite &cel, int frame) void CelDrawUnsafeTo(const Surface &out, Point position, CelSprite cel, int frame)
{ {
int nDataSize; int nDataSize;
const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize); const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize);
RenderCelClipY(out, position, pRLEBytes, nDataSize, cel.Width(frame), RenderLineMemcpy, NullLineEndFn); RenderCelClipY(out, position, pRLEBytes, nDataSize, cel.Width(frame), RenderLineMemcpy, NullLineEndFn);
} }
void CelBlitOutlineTo(const Surface &out, uint8_t col, Point position, const CelSprite &cel, int frame, bool skipColorIndexZero) void CelBlitOutlineTo(const Surface &out, uint8_t col, Point position, CelSprite cel, int frame, bool skipColorIndexZero)
{ {
int nDataSize; int nDataSize;
const byte *src = CelGetFrameClipped(cel.Data(), frame, &nDataSize); const byte *src = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
@ -664,7 +664,7 @@ void CelBlitOutlineTo(const Surface &out, uint8_t col, Point position, const Cel
RenderCelOutline<false>(out, position, src, nDataSize, cel.Width(frame), col); RenderCelOutline<false>(out, position, src, nDataSize, cel.Width(frame), col);
} }
std::pair<int, int> MeasureSolidHorizontalBounds(const CelSprite &cel, int frame) std::pair<int, int> MeasureSolidHorizontalBounds(CelSprite cel, int frame)
{ {
int nDataSize; int nDataSize;
const byte *src = CelGetFrameClipped(cel.Data(), frame, &nDataSize); const byte *src = CelGetFrameClipped(cel.Data(), frame, &nDataSize);

20
Source/engine/render/cel_render.hpp

@ -18,7 +18,7 @@ namespace devilution {
* Returns a pair of X coordinates containing the start (inclusive) and end (exclusive) * Returns a pair of X coordinates containing the start (inclusive) and end (exclusive)
* of fully transparent columns in the sprite. * of fully transparent columns in the sprite.
*/ */
std::pair<int, int> MeasureSolidHorizontalBounds(const CelSprite &cel, int frame = 1); std::pair<int, int> MeasureSolidHorizontalBounds(CelSprite cel, int frame = 1);
/** /**
* @brief Blit CEL sprite to the back buffer at the given coordinates * @brief Blit CEL sprite to the back buffer at the given coordinates
@ -27,7 +27,7 @@ std::pair<int, int> MeasureSolidHorizontalBounds(const CelSprite &cel, int frame
* @param cel CEL sprite * @param cel CEL sprite
* @param frame CEL frame number * @param frame CEL frame number
*/ */
void CelDrawTo(const Surface &out, Point position, const CelSprite &cel, int frame); void CelDrawTo(const Surface &out, Point position, CelSprite cel, int frame);
/** /**
* @briefBlit CEL sprite to the given buffer, does not perform bounds-checking. * @briefBlit CEL sprite to the given buffer, does not perform bounds-checking.
@ -36,7 +36,7 @@ void CelDrawTo(const Surface &out, Point position, const CelSprite &cel, int fra
* @param cel CEL sprite * @param cel CEL sprite
* @param frame CEL frame number * @param frame CEL frame number
*/ */
void CelDrawUnsafeTo(const Surface &out, Point position, const CelSprite &cel, int frame); void CelDrawUnsafeTo(const Surface &out, Point position, CelSprite cel, int frame);
/** /**
* @brief Same as CelDrawTo but with the option to skip parts of the top and bottom of the sprite * @brief Same as CelDrawTo but with the option to skip parts of the top and bottom of the sprite
@ -45,7 +45,7 @@ void CelDrawUnsafeTo(const Surface &out, Point position, const CelSprite &cel, i
* @param cel CEL sprite * @param cel CEL sprite
* @param frame CEL frame number * @param frame CEL frame number
*/ */
void CelClippedDrawTo(const Surface &out, Point position, const CelSprite &cel, int frame); void CelClippedDrawTo(const Surface &out, Point position, CelSprite cel, int frame);
/** /**
* @brief Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates * @brief Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates
@ -54,7 +54,7 @@ void CelClippedDrawTo(const Surface &out, Point position, const CelSprite &cel,
* @param cel CEL sprite * @param cel CEL sprite
* @param frame CEL frame number * @param frame CEL frame number
*/ */
void CelDrawLightTo(const Surface &out, Point position, const CelSprite &cel, int frame, uint8_t *tbl); void CelDrawLightTo(const Surface &out, Point position, CelSprite cel, int frame, uint8_t *tbl);
/** /**
* @brief Same as CelDrawLightTo but with the option to skip parts of the top and bottom of the sprite * @brief Same as CelDrawLightTo but with the option to skip parts of the top and bottom of the sprite
@ -63,7 +63,7 @@ void CelDrawLightTo(const Surface &out, Point position, const CelSprite &cel, in
* @param cel CEL sprite * @param cel CEL sprite
* @param frame CEL frame number * @param frame CEL frame number
*/ */
void CelClippedDrawLightTo(const Surface &out, Point position, const CelSprite &cel, int frame); void CelClippedDrawLightTo(const Surface &out, Point position, CelSprite cel, int frame);
/** /**
* @brief Same as CelBlitLightSafeTo but with transparency applied * @brief Same as CelBlitLightSafeTo but with transparency applied
@ -72,7 +72,7 @@ void CelClippedDrawLightTo(const Surface &out, Point position, const CelSprite &
* @param cel CEL sprite * @param cel CEL sprite
* @param frame CEL frame number * @param frame CEL frame number
*/ */
void CelClippedBlitLightTransTo(const Surface &out, Point position, const CelSprite &cel, int frame); void CelClippedBlitLightTransTo(const Surface &out, Point position, CelSprite cel, int frame);
/** /**
* @brief Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates, translated to a red hue * @brief Blit CEL sprite, and apply lighting, to the back buffer at the given coordinates, translated to a red hue
@ -81,7 +81,7 @@ void CelClippedBlitLightTransTo(const Surface &out, Point position, const CelSpr
* @param cel CEL sprite * @param cel CEL sprite
* @param frame CEL frame number * @param frame CEL frame number
*/ */
void CelDrawLightRedTo(const Surface &out, Point position, const CelSprite &cel, int frame); void CelDrawLightRedTo(const Surface &out, Point position, CelSprite cel, int frame);
/** /**
* @brief Blit item's CEL sprite recolored red if not usable, normal if usable * @brief Blit item's CEL sprite recolored red if not usable, normal if usable
@ -91,7 +91,7 @@ void CelDrawLightRedTo(const Surface &out, Point position, const CelSprite &cel,
* @param cel CEL sprite * @param cel CEL sprite
* @param frame CEL frame number * @param frame CEL frame number
*/ */
void CelDrawItem(const Item &item, const Surface &out, Point position, const CelSprite &cel, int frame); void CelDrawItem(const Item &item, const Surface &out, Point position, CelSprite cel, int frame);
/** /**
* @brief Blit a solid colder shape one pixel larger than the given sprite shape, to the target buffer at the given coordianates * @brief Blit a solid colder shape one pixel larger than the given sprite shape, to the target buffer at the given coordianates
@ -102,6 +102,6 @@ void CelDrawItem(const Item &item, const Surface &out, Point position, const Cel
* @param frame CEL frame number * @param frame CEL frame number
* @param skipColorIndexZero If true, color in index 0 will be treated as transparent (these are typically used for shadows in sprites) * @param skipColorIndexZero If true, color in index 0 will be treated as transparent (these are typically used for shadows in sprites)
*/ */
void CelBlitOutlineTo(const Surface &out, uint8_t col, Point position, const CelSprite &cel, int frame, bool skipColorIndexZero = true); void CelBlitOutlineTo(const Surface &out, uint8_t col, Point position, CelSprite cel, int frame, bool skipColorIndexZero = true);
} // namespace devilution } // namespace devilution

8
Source/engine/render/cl2_render.cpp

@ -763,7 +763,7 @@ void Cl2ApplyTrans(byte *p, const std::array<uint8_t, 256> &ttbl, int nCel)
} }
} }
void Cl2Draw(const Surface &out, int sx, int sy, const CelSprite &cel, int frame) void Cl2Draw(const Surface &out, int sx, int sy, CelSprite cel, int frame)
{ {
assert(frame > 0); assert(frame > 0);
@ -773,7 +773,7 @@ void Cl2Draw(const Surface &out, int sx, int sy, const CelSprite &cel, int frame
Cl2BlitSafe(out, sx, sy, pRLEBytes, nDataSize, cel.Width(frame)); Cl2BlitSafe(out, sx, sy, pRLEBytes, nDataSize, cel.Width(frame));
} }
void Cl2DrawOutline(const Surface &out, uint8_t col, int sx, int sy, const CelSprite &cel, int frame) void Cl2DrawOutline(const Surface &out, uint8_t col, int sx, int sy, CelSprite cel, int frame)
{ {
assert(frame > 0); assert(frame > 0);
@ -783,7 +783,7 @@ void Cl2DrawOutline(const Surface &out, uint8_t col, int sx, int sy, const CelSp
RenderCl2Outline(out, { sx, sy }, pRLEBytes, nDataSize, cel.Width(frame), col); RenderCl2Outline(out, { sx, sy }, pRLEBytes, nDataSize, cel.Width(frame), col);
} }
void Cl2DrawTRN(const Surface &out, int sx, int sy, const CelSprite &cel, int frame, uint8_t *trn) void Cl2DrawTRN(const Surface &out, int sx, int sy, CelSprite cel, int frame, uint8_t *trn)
{ {
assert(frame > 0); assert(frame > 0);
@ -792,7 +792,7 @@ void Cl2DrawTRN(const Surface &out, int sx, int sy, const CelSprite &cel, int fr
Cl2BlitLightSafe(out, sx, sy, pRLEBytes, nDataSize, cel.Width(frame), trn); Cl2BlitLightSafe(out, sx, sy, pRLEBytes, nDataSize, cel.Width(frame), trn);
} }
void Cl2DrawLight(const Surface &out, int sx, int sy, const CelSprite &cel, int frame) void Cl2DrawLight(const Surface &out, int sx, int sy, CelSprite cel, int frame)
{ {
assert(frame > 0); assert(frame > 0);

8
Source/engine/render/cl2_render.hpp

@ -30,7 +30,7 @@ void Cl2ApplyTrans(byte *p, const std::array<uint8_t, 256> &ttbl, int nCel);
* @param pCelBuff CL2 buffer * @param pCelBuff CL2 buffer
* @param nCel CL2 frame number * @param nCel CL2 frame number
*/ */
void Cl2Draw(const Surface &out, int sx, int sy, const CelSprite &cel, int frame); void Cl2Draw(const Surface &out, int sx, int sy, CelSprite cel, int frame);
/** /**
* @brief Blit a solid colder shape one pixel larger than the given sprite shape, to the given buffer at the given coordianates * @brief Blit a solid colder shape one pixel larger than the given sprite shape, to the given buffer at the given coordianates
@ -41,7 +41,7 @@ void Cl2Draw(const Surface &out, int sx, int sy, const CelSprite &cel, int frame
* @param pCelBuff CL2 buffer * @param pCelBuff CL2 buffer
* @param nCel CL2 frame number * @param nCel CL2 frame number
*/ */
void Cl2DrawOutline(const Surface &out, uint8_t col, int sx, int sy, const CelSprite &cel, int frame); void Cl2DrawOutline(const Surface &out, uint8_t col, int sx, int sy, CelSprite cel, int frame);
/** /**
* @brief Blit CL2 sprite, and apply given TRN to the given buffer at the given coordinates * @brief Blit CL2 sprite, and apply given TRN to the given buffer at the given coordinates
@ -52,7 +52,7 @@ void Cl2DrawOutline(const Surface &out, uint8_t col, int sx, int sy, const CelSp
* @param nCel CL2 frame number * @param nCel CL2 frame number
* @param TRN to use * @param TRN to use
*/ */
void Cl2DrawTRN(const Surface &out, int sx, int sy, const CelSprite &cel, int frame, uint8_t *trn); void Cl2DrawTRN(const Surface &out, int sx, int sy, CelSprite cel, int frame, uint8_t *trn);
/** /**
* @brief Blit CL2 sprite, and apply lighting, to the given buffer at the given coordinates * @brief Blit CL2 sprite, and apply lighting, to the given buffer at the given coordinates
@ -62,6 +62,6 @@ void Cl2DrawTRN(const Surface &out, int sx, int sy, const CelSprite &cel, int fr
* @param pCelBuff CL2 buffer * @param pCelBuff CL2 buffer
* @param nCel CL2 frame number * @param nCel CL2 frame number
*/ */
void Cl2DrawLight(const Surface &out, int sx, int sy, const CelSprite &cel, int frame); void Cl2DrawLight(const Surface &out, int sx, int sy, CelSprite cel, int frame);
} // namespace devilution } // namespace devilution

2
Source/engine/render/text_render.cpp

@ -25,7 +25,7 @@
namespace devilution { namespace devilution {
std::optional<CelSprite> pSPentSpn2Cels; std::optional<OwnedCelSprite> pSPentSpn2Cels;
namespace { namespace {

2
Source/engine/render/text_render.hpp

@ -123,7 +123,7 @@ private:
* *
* Also used in the stores and the quest log. * Also used in the stores and the quest log.
*/ */
extern std::optional<CelSprite> pSPentSpn2Cels; extern std::optional<OwnedCelSprite> pSPentSpn2Cels;
void LoadSmallSelectionSpinner(); void LoadSmallSelectionSpinner();

2
Source/gendung.cpp

@ -24,7 +24,7 @@ int setpc_w;
int setpc_h; int setpc_h;
std::unique_ptr<uint16_t[]> pSetPiece; std::unique_ptr<uint16_t[]> pSetPiece;
bool setloadflag; bool setloadflag;
std::optional<CelSprite> pSpecialCels; std::optional<OwnedCelSprite> pSpecialCels;
std::unique_ptr<MegaTile[]> pMegaTiles; std::unique_ptr<MegaTile[]> pMegaTiles;
std::unique_ptr<uint16_t[]> pLevelPieces; std::unique_ptr<uint16_t[]> pLevelPieces;
std::unique_ptr<byte[]> pDungeonCels; std::unique_ptr<byte[]> pDungeonCels;

2
Source/gendung.h

@ -150,7 +150,7 @@ extern int setpc_h;
extern std::unique_ptr<uint16_t[]> pSetPiece; extern std::unique_ptr<uint16_t[]> pSetPiece;
/** Specifies whether a single player quest DUN has been loaded. */ /** Specifies whether a single player quest DUN has been loaded. */
extern bool setloadflag; extern bool setloadflag;
extern std::optional<CelSprite> pSpecialCels; extern std::optional<OwnedCelSprite> pSpecialCels;
/** Specifies the tile definitions of the active dungeon type; (e.g. levels/l1data/l1.til). */ /** Specifies the tile definitions of the active dungeon type; (e.g. levels/l1data/l1.til). */
extern std::unique_ptr<MegaTile[]> pMegaTiles; extern std::unique_ptr<MegaTile[]> pMegaTiles;
extern std::unique_ptr<uint16_t[]> pLevelPieces; extern std::unique_ptr<uint16_t[]> pLevelPieces;

8
Source/gmenu.cpp

@ -24,10 +24,10 @@ namespace devilution {
namespace { namespace {
std::optional<CelSprite> optbar_cel; std::optional<OwnedCelSprite> optbar_cel;
std::optional<CelSprite> PentSpin_cel; std::optional<OwnedCelSprite> PentSpin_cel;
std::optional<CelSprite> option_cel; std::optional<OwnedCelSprite> option_cel;
std::optional<CelSprite> sgpLogo; std::optional<OwnedCelSprite> sgpLogo;
bool mouseNavigation; bool mouseNavigation;
TMenuItem *sgpCurrItem; TMenuItem *sgpCurrItem;
int LogoAnim_tick; int LogoAnim_tick;

2
Source/interfac.cpp

@ -26,7 +26,7 @@ namespace devilution {
namespace { namespace {
std::optional<CelSprite> sgpBackCel; std::optional<OwnedCelSprite> sgpBackCel;
uint32_t sgdwProgress; uint32_t sgdwProgress;
int progress_id; int progress_id;

2
Source/inv.cpp

@ -134,7 +134,7 @@ const Point InvRect[] = {
namespace { namespace {
std::optional<CelSprite> pInvCels; std::optional<OwnedCelSprite> pInvCels;
void InvDrawSlotBack(const Surface &out, Point targetPosition, Size size) void InvDrawSlotBack(const Surface &out, Point targetPosition, Size size)
{ {

26
Source/items.cpp

@ -127,7 +127,7 @@ _sfx_id ItemInvSnds[] = {
namespace { namespace {
std::optional<CelSprite> itemanims[ITEMTYPES]; std::optional<OwnedCelSprite> itemanims[ITEMTYPES];
enum class PlayerArmorGraphic : uint8_t { enum class PlayerArmorGraphic : uint8_t {
// clang-format off // clang-format off
@ -2405,7 +2405,7 @@ void CreateMagicItem(Point position, int lvl, ItemType itemType, int imid, int i
int idx = RndTypeItems(itemType, imid, lvl); int idx = RndTypeItems(itemType, imid, lvl);
while (true) { while (true) {
memset(&item, 0, sizeof(item)); item = {};
SetupAllItems(item, idx, AdvanceRndSeed(), 2 * lvl, 1, true, false, delta); SetupAllItems(item, idx, AdvanceRndSeed(), 2 * lvl, 1, true, false, delta);
if (item._iCurs == icurs) if (item._iCurs == icurs)
break; break;
@ -2875,13 +2875,13 @@ void CalcPlrItemVals(Player &player, bool loadgfx)
player._pgfxnum = gfxNum; player._pgfxnum = gfxNum;
ResetPlayerGFX(player); ResetPlayerGFX(player);
SetPlrAnims(player); SetPlrAnims(player);
player.pPreviewCelSprite = nullptr; player.previewCelSprite = std::nullopt;
if (player._pmode == PM_STAND) { if (player._pmode == PM_STAND) {
LoadPlrGFX(player, player_graphic::Stand); LoadPlrGFX(player, player_graphic::Stand);
player.AnimInfo.ChangeAnimationData(&*player.AnimationData[static_cast<size_t>(player_graphic::Stand)].GetCelSpritesForDirection(player._pdir), player._pNFrames, 4); player.AnimInfo.ChangeAnimationData(player.AnimationData[static_cast<size_t>(player_graphic::Stand)].GetCelSpritesForDirection(player._pdir), player._pNFrames, 4);
} else { } else {
LoadPlrGFX(player, player_graphic::Walk); LoadPlrGFX(player, player_graphic::Walk);
player.AnimInfo.ChangeAnimationData(&*player.AnimationData[static_cast<size_t>(player_graphic::Walk)].GetCelSpritesForDirection(player._pdir), player._pWFrames, 1); player.AnimInfo.ChangeAnimationData(player.AnimationData[static_cast<size_t>(player_graphic::Walk)].GetCelSpritesForDirection(player._pdir), player._pWFrames, 1);
} }
} else { } else {
player._pgfxnum = gfxNum; player._pgfxnum = gfxNum;
@ -2919,7 +2919,7 @@ void SetPlrHandItem(Item &item, int itemData)
auto &pAllItem = AllItemsList[itemData]; auto &pAllItem = AllItemsList[itemData];
// zero-initialize struct // zero-initialize struct
memset(&item, 0, sizeof(item)); item = {};
item._itype = pAllItem.itype; item._itype = pAllItem.itype;
item._iCurs = pAllItem.iCurs; item._iCurs = pAllItem.iCurs;
@ -3643,7 +3643,7 @@ void FreeItemGFX()
void GetItemFrm(Item &item) void GetItemFrm(Item &item)
{ {
item.AnimInfo.pCelSprite = &*itemanims[ItemCAnimTbl[item._iCurs]]; item.AnimInfo.celSprite = itemanims[ItemCAnimTbl[item._iCurs]]->Unowned();
} }
void GetItemStr(Item &item) void GetItemStr(Item &item)
@ -4582,7 +4582,7 @@ void CreateSpellBook(Point position, spell_id ispell, bool sendmsg, bool delta)
auto &item = Items[ii]; auto &item = Items[ii];
while (true) { while (true) {
memset(&item, 0, sizeof(*Items)); item = {};
SetupAllItems(item, idx, AdvanceRndSeed(), 2 * lvl, 1, true, false, delta); SetupAllItems(item, idx, AdvanceRndSeed(), 2 * lvl, 1, true, false, delta);
if (item._iMiscId == IMISC_BOOK && item._iSpell == ispell) if (item._iMiscId == IMISC_BOOK && item._iSpell == ispell)
break; break;
@ -4705,7 +4705,7 @@ std::string DebugSpawnItem(std::string itemName)
continue; continue;
Point bkp = item.position; Point bkp = item.position;
memset(&item, 0, sizeof(Item)); item = {};
item.position = bkp; item.position = bkp;
SetupAllItems(item, idx, AdvanceRndSeed(), fake_m.mLevel, 1, false, false, false); SetupAllItems(item, idx, AdvanceRndSeed(), fake_m.mLevel, 1, false, false, false);
@ -4771,7 +4771,7 @@ std::string DebugSpawnUniqueItem(std::string itemName)
return fmt::format("Item not found in {:d} tries!", max_iter); return fmt::format("Item not found in {:d} tries!", max_iter);
Point bkp = item.position; Point bkp = item.position;
memset(&item, 0, sizeof(Item)); item = {};
item.position = bkp; item.position = bkp;
std::uniform_int_distribution<int32_t> dist(0, INT_MAX); std::uniform_int_distribution<int32_t> dist(0, INT_MAX);
SetRndSeed(dist(BetterRng)); SetRndSeed(dist(BetterRng));
@ -4802,11 +4802,11 @@ void Item::SetNewAnimation(bool showAnimation)
{ {
int it = ItemCAnimTbl[_iCurs]; int it = ItemCAnimTbl[_iCurs];
int numberOfFrames = ItemAnimLs[it]; int numberOfFrames = ItemAnimLs[it];
auto *pCelSprite = itemanims[it] ? &*itemanims[it] : nullptr; auto celSprite = itemanims[it] ? std::optional<CelSprite> { itemanims[it]->Unowned() } : std::nullopt;
if (_iCurs != ICURS_MAGIC_ROCK) if (_iCurs != ICURS_MAGIC_ROCK)
AnimInfo.SetNewAnimation(pCelSprite, numberOfFrames, 1, AnimationDistributionFlags::ProcessAnimationPending, 0, numberOfFrames); AnimInfo.SetNewAnimation(celSprite, numberOfFrames, 1, AnimationDistributionFlags::ProcessAnimationPending, 0, numberOfFrames);
else else
AnimInfo.SetNewAnimation(pCelSprite, numberOfFrames, 1); AnimInfo.SetNewAnimation(celSprite, numberOfFrames, 1);
_iPostDraw = false; _iPostDraw = false;
_iRequest = false; _iRequest = false;
if (showAnimation) { if (showAnimation) {

126
Source/items.h

@ -173,74 +173,74 @@ constexpr int ItemAnimWidth = 96;
struct Item { struct Item {
/** Randomly generated identifier */ /** Randomly generated identifier */
int32_t _iSeed; int32_t _iSeed = 0;
uint16_t _iCreateInfo; uint16_t _iCreateInfo = 0;
enum ItemType _itype; enum ItemType _itype = ItemType::None;
Point position; Point position = { 0, 0 };
bool _iAnimFlag; bool _iAnimFlag = false;
/* /*
* @brief Contains Information for current Animation * @brief Contains Information for current Animation
*/ */
AnimationInfo AnimInfo; AnimationInfo AnimInfo;
bool _iDelFlag; // set when item is flagged for deletion, deprecated in 1.02 bool _iDelFlag = false; // set when item is flagged for deletion, deprecated in 1.02
uint8_t _iSelFlag; uint8_t _iSelFlag = 0;
bool _iPostDraw; bool _iPostDraw = false;
bool _iIdentified; bool _iIdentified = false;
item_quality _iMagical; item_quality _iMagical = ITEM_QUALITY_NORMAL;
char _iName[64]; char _iName[64] = {};
char _iIName[64]; char _iIName[64] = {};
enum item_equip_type _iLoc; enum item_equip_type _iLoc = ILOC_NONE;
enum item_class _iClass; enum item_class _iClass = ICLASS_NONE;
uint8_t _iCurs; uint8_t _iCurs = 0;
int _ivalue; int _ivalue = 0;
int _iIvalue; int _iIvalue = 0;
uint8_t _iMinDam; uint8_t _iMinDam = 0;
uint8_t _iMaxDam; uint8_t _iMaxDam = 0;
int16_t _iAC; int16_t _iAC = 0;
uint32_t _iFlags; // item_special_effect uint32_t _iFlags = 0; // item_special_effect
enum item_misc_id _iMiscId; enum item_misc_id _iMiscId = IMISC_NONE;
enum spell_id _iSpell; enum spell_id _iSpell = SPL_NULL;
int _iCharges; int _iCharges = 0;
int _iMaxCharges; int _iMaxCharges = 0;
int _iDurability; int _iDurability = 0;
int _iMaxDur; int _iMaxDur = 0;
int16_t _iPLDam; int16_t _iPLDam = 0;
int16_t _iPLToHit; int16_t _iPLToHit = 0;
int16_t _iPLAC; int16_t _iPLAC = 0;
int16_t _iPLStr; int16_t _iPLStr = 0;
int16_t _iPLMag; int16_t _iPLMag = 0;
int16_t _iPLDex; int16_t _iPLDex = 0;
int16_t _iPLVit; int16_t _iPLVit = 0;
int16_t _iPLFR; int16_t _iPLFR = 0;
int16_t _iPLLR; int16_t _iPLLR = 0;
int16_t _iPLMR; int16_t _iPLMR = 0;
int16_t _iPLMana; int16_t _iPLMana = 0;
int16_t _iPLHP; int16_t _iPLHP = 0;
int16_t _iPLDamMod; int16_t _iPLDamMod = 0;
int16_t _iPLGetHit; int16_t _iPLGetHit = 0;
int16_t _iPLLight; int16_t _iPLLight = 0;
int8_t _iSplLvlAdd; int8_t _iSplLvlAdd = 0;
bool _iRequest; bool _iRequest = false;
/** Unique item ID, used as an index into UniqueItemList */ /** Unique item ID, used as an index into UniqueItemList */
int _iUid; int _iUid = 0;
int16_t _iFMinDam; int16_t _iFMinDam = 0;
int16_t _iFMaxDam; int16_t _iFMaxDam = 0;
int16_t _iLMinDam; int16_t _iLMinDam = 0;
int16_t _iLMaxDam; int16_t _iLMaxDam = 0;
int16_t _iPLEnAc; int16_t _iPLEnAc = 0;
enum item_effect_type _iPrePower; enum item_effect_type _iPrePower = IPL_INVALID;
enum item_effect_type _iSufPower; enum item_effect_type _iSufPower = IPL_INVALID;
int _iVAdd1; int _iVAdd1 = 0;
int _iVMult1; int _iVMult1 = 0;
int _iVAdd2; int _iVAdd2 = 0;
int _iVMult2; int _iVMult2 = 0;
int8_t _iMinStr; int8_t _iMinStr = 0;
uint8_t _iMinMag; uint8_t _iMinMag = 0;
int8_t _iMinDex; int8_t _iMinDex = 0;
bool _iStatFlag; bool _iStatFlag = false;
_item_indexes IDidx; _item_indexes IDidx = IDI_NONE;
uint32_t dwBuff; uint32_t dwBuff = 0;
uint32_t _iDamAcFlags; uint32_t _iDamAcFlags = 0;
/** /**
* @brief Checks whether this item is empty or not. * @brief Checks whether this item is empty or not.

2
Source/loadsave.cpp

@ -1055,7 +1055,7 @@ void SavePlayer(SaveHelper &file, const Player &player)
file.WriteLE<int32_t>(player.AnimInfo.NumberOfFrames); file.WriteLE<int32_t>(player.AnimInfo.NumberOfFrames);
file.WriteLE<int32_t>(player.AnimInfo.CurrentFrame); file.WriteLE<int32_t>(player.AnimInfo.CurrentFrame);
// write _pAnimWidth for vanilla compatibility // write _pAnimWidth for vanilla compatibility
int animWidth = player.AnimInfo.pCelSprite == nullptr ? 96 : player.AnimInfo.pCelSprite->Width(); int animWidth = player.AnimInfo.celSprite ? player.AnimInfo.celSprite->Width() : 96;
file.WriteLE<int32_t>(animWidth); file.WriteLE<int32_t>(animWidth);
// write _pAnimWidth2 for vanilla compatibility // write _pAnimWidth2 for vanilla compatibility
file.WriteLE<int32_t>(CalculateWidth2(animWidth)); file.WriteLE<int32_t>(CalculateWidth2(animWidth));

2
Source/minitext.cpp

@ -31,7 +31,7 @@ int qtextSpd;
/** Start time of scrolling */ /** Start time of scrolling */
Uint32 ScrollStart; Uint32 ScrollStart;
/** Graphics for the window border */ /** Graphics for the window border */
std::optional<CelSprite> pTextBoxCels; std::optional<OwnedCelSprite> pTextBoxCels;
/** Pixels for a line of text and the empty space under it. */ /** Pixels for a line of text and the empty space under it. */
const int LineHeight = 38; const int LineHeight = 38;

4
Source/missiles.cpp

@ -2160,7 +2160,7 @@ void InitMissileAnimationFromMonster(Missile &mis, Direction midir, const Monste
const AnimStruct &anim = mon.MType->GetAnimData(graphic); const AnimStruct &anim = mon.MType->GetAnimData(graphic);
mis._mimfnum = static_cast<int32_t>(midir); mis._mimfnum = static_cast<int32_t>(midir);
mis._miAnimFlags = MissileDataFlags::None; mis._miAnimFlags = MissileDataFlags::None;
const auto &celSprite = *anim.CelSpritesForDirections[mis._mimfnum]; CelSprite celSprite = *anim.GetCelSpritesForDirection(midir);
mis._miAnimData = celSprite.Data(); mis._miAnimData = celSprite.Data();
mis._miAnimDelay = anim.Rate; mis._miAnimDelay = anim.Rate;
mis._miAnimLen = anim.Frames; mis._miAnimLen = anim.Frames;
@ -4184,7 +4184,7 @@ void missiles_process_charge()
} else { } else {
graphic = MonsterGraphic::Walk; graphic = MonsterGraphic::Walk;
} }
missile._miAnimData = mon->GetAnimData(graphic).CelSpritesForDirections[missile._mimfnum]->Data(); missile._miAnimData = mon->GetAnimData(graphic).CelSpritesForDirections[missile._mimfnum];
} }
} }

31
Source/monster.cpp

@ -136,6 +136,11 @@ size_t GetNumAnims(const MonsterData &monsterData)
return monsterData.has_special ? 6 : 5; return monsterData.has_special ? 6 : 5;
} }
bool IsDirectionalAnim(const CMonster &monster, size_t animIndex)
{
return monster.mtype != MT_GOLEM || animIndex < 4;
}
void InitMonsterTRN(CMonster &monst) void InitMonsterTRN(CMonster &monst)
{ {
std::array<uint8_t, 256> colorTranslations; std::array<uint8_t, 256> colorTranslations;
@ -149,11 +154,15 @@ void InitMonsterTRN(CMonster &monst)
continue; continue;
} }
for (int j = 0; j < 8; j++) { AnimStruct &anim = monst.Anims[i];
Cl2ApplyTrans( if (IsDirectionalAnim(monst, i)) {
CelGetFrame(monst.Anims[i].cl2Data, j), for (int j = 0; j < 8; j++) {
colorTranslations, Cl2ApplyTrans(anim.CelSpritesForDirections[j], colorTranslations, anim.Frames);
monst.Anims[i].Frames); }
} else {
for (int j = 0; j < 8; j++) {
Cl2ApplyTrans(CelGetFrame(anim.CelSpritesForDirections[0], j), colorTranslations, anim.Frames);
}
} }
} }
} }
@ -680,8 +689,7 @@ void DeleteMonster(int i)
void NewMonsterAnim(Monster &monster, MonsterGraphic graphic, Direction md, AnimationDistributionFlags flags = AnimationDistributionFlags::None, int numSkippedFrames = 0, int distributeFramesBeforeFrame = 0) void NewMonsterAnim(Monster &monster, MonsterGraphic graphic, Direction md, AnimationDistributionFlags flags = AnimationDistributionFlags::None, int numSkippedFrames = 0, int distributeFramesBeforeFrame = 0)
{ {
const auto &animData = monster.MType->GetAnimData(graphic); const auto &animData = monster.MType->GetAnimData(graphic);
const auto *pCelSprite = &*animData.CelSpritesForDirections[static_cast<size_t>(md)]; monster.AnimInfo.SetNewAnimation(animData.GetCelSpritesForDirection(md), animData.Frames, animData.Rate, flags, numSkippedFrames, distributeFramesBeforeFrame);
monster.AnimInfo.SetNewAnimation(pCelSprite, animData.Frames, animData.Rate, flags, numSkippedFrames, distributeFramesBeforeFrame);
monster._mFlags &= ~(MFLAG_LOCK_ANIMATION | MFLAG_ALLOW_SPECIAL); monster._mFlags &= ~(MFLAG_LOCK_ANIMATION | MFLAG_ALLOW_SPECIAL);
monster._mdir = md; monster._mdir = md;
} }
@ -3726,17 +3734,18 @@ void InitMonsterGFX(int monst)
continue; continue;
} }
anim.cl2Data = &monster.animData[animOffsets[animIndex]];
anim.Frames = monsterData.Frames[animIndex]; anim.Frames = monsterData.Frames[animIndex];
anim.Rate = monsterData.Rate[animIndex]; anim.Rate = monsterData.Rate[animIndex];
anim.Width = width;
if (monster.mtype != MT_GOLEM || (animletter[animIndex] != 's' && animletter[animIndex] != 'd')) { byte *cl2Data = &monster.animData[animOffsets[animIndex]];
if (IsDirectionalAnim(monster, animIndex)) {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
anim.CelSpritesForDirections[i].emplace(CelGetFrame(anim.cl2Data, i), width); anim.CelSpritesForDirections[i] = CelGetFrame(cl2Data, i);
} }
} else { } else {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
anim.CelSpritesForDirections[i].emplace(anim.cl2Data, width); anim.CelSpritesForDirections[i] = cl2Data;
} }
} }
} }

15
Source/monster.h

@ -132,14 +132,16 @@ enum class LeaderRelation : uint8_t {
}; };
struct AnimStruct { struct AnimStruct {
byte *cl2Data; [[nodiscard]] std::optional<CelSprite> GetCelSpritesForDirection(Direction direction) const
std::array<std::optional<CelSprite>, 8> CelSpritesForDirections;
inline const std::optional<CelSprite> &GetCelSpritesForDirection(Direction direction) const
{ {
return CelSpritesForDirections[static_cast<size_t>(direction)]; const byte *spriteData = CelSpritesForDirections[static_cast<size_t>(direction)];
if (spriteData == nullptr)
return std::nullopt;
return CelSprite(spriteData, static_cast<int>(Width));
} }
std::array<byte *, 8> CelSpritesForDirections;
unsigned Width;
int Frames; int Frames;
int Rate; int Rate;
}; };
@ -230,10 +232,9 @@ struct Monster { // note: missing field _mAFNum
void ChangeAnimationData(MonsterGraphic graphic, Direction direction) void ChangeAnimationData(MonsterGraphic graphic, Direction direction)
{ {
auto &animationData = this->MType->GetAnimData(graphic); auto &animationData = this->MType->GetAnimData(graphic);
auto &celSprite = animationData.GetCelSpritesForDirection(direction);
// Passing the Frames and Rate properties here is only relevant when initialising a monster, but doesn't cause any harm when switching animations. // Passing the Frames and Rate properties here is only relevant when initialising a monster, but doesn't cause any harm when switching animations.
this->AnimInfo.ChangeAnimationData(celSprite ? &*celSprite : nullptr, animationData.Frames, animationData.Rate); this->AnimInfo.ChangeAnimationData(animationData.GetCelSpritesForDirection(direction), animationData.Frames, animationData.Rate);
} }
/** /**

2
Source/panels/charpanel.cpp

@ -16,7 +16,7 @@
namespace devilution { namespace devilution {
std::optional<CelSprite> pChrButtons; std::optional<OwnedCelSprite> pChrButtons;
/** Map of hero class names */ /** Map of hero class names */
const char *const ClassStrTbl[] = { const char *const ClassStrTbl[] = {

2
Source/panels/charpanel.hpp

@ -6,7 +6,7 @@
namespace devilution { namespace devilution {
extern std::optional<CelSprite> pChrButtons; extern std::optional<OwnedCelSprite> pChrButtons;
extern const char *const ClassStrTbl[]; extern const char *const ClassStrTbl[];
void DrawChr(const Surface &); void DrawChr(const Surface &);

4
Source/panels/info_box.cpp

@ -4,8 +4,8 @@
namespace devilution { namespace devilution {
std::optional<CelSprite> pSTextBoxCels; std::optional<OwnedCelSprite> pSTextBoxCels;
std::optional<CelSprite> pSTextSlidCels; std::optional<OwnedCelSprite> pSTextSlidCels;
void InitInfoBoxGfx() void InitInfoBoxGfx()
{ {

4
Source/panels/info_box.hpp

@ -10,14 +10,14 @@ namespace devilution {
* *
* Used in stores, the quest log, the help window, and the unique item info window. * Used in stores, the quest log, the help window, and the unique item info window.
*/ */
extern std::optional<CelSprite> pSTextBoxCels; extern std::optional<OwnedCelSprite> pSTextBoxCels;
/** /**
* @brief Info box scrollbar graphics. * @brief Info box scrollbar graphics.
* *
* Used in stores and `DrawDiabloMsg`. * Used in stores and `DrawDiabloMsg`.
*/ */
extern std::optional<CelSprite> pSTextSlidCels; extern std::optional<OwnedCelSprite> pSTextSlidCels;
void InitInfoBoxGfx(); void InitInfoBoxGfx();
void FreeInfoBoxGfx(); void FreeInfoBoxGfx();

6
Source/panels/spell_book.cpp

@ -21,12 +21,12 @@
namespace devilution { namespace devilution {
std::optional<CelSprite> pSBkIconCels; std::optional<OwnedCelSprite> pSBkIconCels;
namespace { namespace {
std::optional<CelSprite> pSBkBtnCel; std::optional<OwnedCelSprite> pSBkBtnCel;
std::optional<CelSprite> pSpellBkCel; std::optional<OwnedCelSprite> pSpellBkCel;
/** Maps from spellbook page number and position to spell_id. */ /** Maps from spellbook page number and position to spell_id. */
spell_id SpellPages[6][7] = { spell_id SpellPages[6][7] = {

4
Source/panels/spell_icons.cpp

@ -9,7 +9,7 @@
namespace devilution { namespace devilution {
namespace { namespace {
std::optional<CelSprite> pSpellCels; std::optional<OwnedCelSprite> pSpellCels;
uint8_t SplTransTbl[256]; uint8_t SplTransTbl[256];
} // namespace } // namespace
@ -87,7 +87,7 @@ void DrawSpellCel(const Surface &out, Point position, int nCel)
DrawSpellCel(out, position, *pSpellCels, nCel); DrawSpellCel(out, position, *pSpellCels, nCel);
} }
void DrawSpellCel(const Surface &out, Point position, const CelSprite &sprite, int nCel) void DrawSpellCel(const Surface &out, Point position, const OwnedCelSprite &sprite, int nCel)
{ {
CelDrawLightTo(out, position, sprite, nCel, SplTransTbl); CelDrawLightTo(out, position, sprite, nCel, SplTransTbl);
} }

2
Source/panels/spell_icons.hpp

@ -27,7 +27,7 @@ void DrawSpellCel(const Surface &out, Point position, int nCel);
* @param sprite Icons sprite sheet. * @param sprite Icons sprite sheet.
* @param nCel Index of the cel frame to draw. 0 based. * @param nCel Index of the cel frame to draw. 0 based.
*/ */
void DrawSpellCel(const Surface &out, Point position, const CelSprite &sprite, int nCel); void DrawSpellCel(const Surface &out, Point position, const OwnedCelSprite &sprite, int nCel);
void SetSpellTrans(spell_type t); void SetSpellTrans(spell_type t);

20
Source/player.cpp

@ -2270,9 +2270,9 @@ void Player::UpdatePreviewCelSprite(_cmd_id cmdId, Point point, uint16_t wParam1
return; return;
LoadPlrGFX(*this, *graphic); LoadPlrGFX(*this, *graphic);
auto &celSprites = AnimationData[static_cast<size_t>(*graphic)].CelSpritesForDirections[static_cast<size_t>(dir)]; std::optional<CelSprite> celSprites = AnimationData[static_cast<size_t>(*graphic)].GetCelSpritesForDirection(dir);
if (celSprites && pPreviewCelSprite != &*celSprites) { if (celSprites && previewCelSprite != celSprites) {
pPreviewCelSprite = &*celSprites; previewCelSprite = celSprites;
progressToNextGameTickWhenPreviewWasSet = gfProgressToNextGameTick; progressToNextGameTickWhenPreviewWasSet = gfProgressToNextGameTick;
} }
} }
@ -2401,7 +2401,7 @@ void InitPlayerGFX(Player &player)
void ResetPlayerGFX(Player &player) void ResetPlayerGFX(Player &player)
{ {
player.AnimInfo.pCelSprite = nullptr; player.AnimInfo.celSprite = std::nullopt;
for (auto &animData : player.AnimationData) { for (auto &animData : player.AnimationData) {
for (auto &celSprite : animData.CelSpritesForDirections) for (auto &celSprite : animData.CelSpritesForDirections)
celSprite = std::nullopt; celSprite = std::nullopt;
@ -2413,14 +2413,12 @@ void NewPlrAnim(Player &player, player_graphic graphic, Direction dir, int numbe
{ {
LoadPlrGFX(player, graphic); LoadPlrGFX(player, graphic);
auto &celSprite = player.AnimationData[static_cast<size_t>(graphic)].CelSpritesForDirections[static_cast<size_t>(dir)]; std::optional<CelSprite> celSprite = player.AnimationData[static_cast<size_t>(graphic)].GetCelSpritesForDirection(dir);
CelSprite *pCelSprite = celSprite ? &*celSprite : nullptr;
float previewShownGameTickFragments = 0.F; float previewShownGameTickFragments = 0.F;
if (pCelSprite == player.pPreviewCelSprite && !player.IsWalking()) if (celSprite == player.previewCelSprite && !player.IsWalking())
previewShownGameTickFragments = clamp(1.F - player.progressToNextGameTickWhenPreviewWasSet, 0.F, 1.F); previewShownGameTickFragments = clamp(1.F - player.progressToNextGameTickWhenPreviewWasSet, 0.F, 1.F);
player.AnimInfo.SetNewAnimation(pCelSprite, numberOfFrames, delayLen, flags, numSkippedFrames, distributeFramesBeforeFrame, previewShownGameTickFragments); player.AnimInfo.SetNewAnimation(celSprite, numberOfFrames, delayLen, flags, numSkippedFrames, distributeFramesBeforeFrame, previewShownGameTickFragments);
} }
void SetPlrAnims(Player &player) void SetPlrAnims(Player &player)
@ -3488,7 +3486,7 @@ void ProcessPlayers()
CheckNewPath(pnum, tplayer); CheckNewPath(pnum, tplayer);
} while (tplayer); } while (tplayer);
player.pPreviewCelSprite = nullptr; player.previewCelSprite = std::nullopt;
player.AnimInfo.ProcessAnimation(); player.AnimInfo.ProcessAnimation();
} }
} }
@ -3711,7 +3709,7 @@ void SyncPlrAnim(int pnum)
app_fatal("SyncPlrAnim"); app_fatal("SyncPlrAnim");
} }
player.AnimInfo.pCelSprite = &*player.AnimationData[static_cast<size_t>(graphic)].CelSpritesForDirections[static_cast<size_t>(player._pdir)]; player.AnimInfo.celSprite = player.AnimationData[static_cast<size_t>(graphic)].GetCelSpritesForDirection(player._pdir);
// Ensure ScrollInfo is initialized correctly // Ensure ScrollInfo is initialized correctly
ScrollViewPort(player, WalkSettings[static_cast<size_t>(player._pdir)].scrollDir); ScrollViewPort(player, WalkSettings[static_cast<size_t>(player._pdir)].scrollDir);
} }

8
Source/player.h

@ -201,7 +201,7 @@ struct PlayerAnimationData {
*/ */
std::unique_ptr<byte[]> RawData; std::unique_ptr<byte[]> RawData;
inline const std::optional<CelSprite> &GetCelSpritesForDirection(Direction direction) const [[nodiscard]] std::optional<CelSprite> GetCelSpritesForDirection(Direction direction) const
{ {
return CelSpritesForDirections[static_cast<size_t>(direction)]; return CelSpritesForDirections[static_cast<size_t>(direction)];
} }
@ -231,9 +231,9 @@ struct Player {
/** /**
* @brief Contains a optional preview CelSprite that is displayed until the current command is handled by the game logic * @brief Contains a optional preview CelSprite that is displayed until the current command is handled by the game logic
*/ */
CelSprite *pPreviewCelSprite; std::optional<CelSprite> previewCelSprite;
/** /**
* @brief Contains the progress to next game tick when pPreviewCelSprite was set * @brief Contains the progress to next game tick when previewCelSprite was set
*/ */
float progressToNextGameTickWhenPreviewWasSet; float progressToNextGameTickWhenPreviewWasSet;
int _plid; int _plid;
@ -689,7 +689,7 @@ struct Player {
} }
/** /**
* @brief Updates pPreviewCelSprite according to new requested command * @brief Updates previewCelSprite according to new requested command
* @param cmdId What command is requested * @param cmdId What command is requested
* @param point Point for the command * @param point Point for the command
* @param wParam1 First Parameter * @param wParam1 First Parameter

2
Source/qol/itemlabels.cpp

@ -77,7 +77,7 @@ void AddItemToLabelQueue(int id, int x, int y)
nameWidth += MarginX * 2; nameWidth += MarginX * 2;
int index = ItemCAnimTbl[item._iCurs]; int index = ItemCAnimTbl[item._iCurs];
if (!labelCenterOffsets[index]) { if (!labelCenterOffsets[index]) {
std::pair<int, int> itemBounds = MeasureSolidHorizontalBounds(*item.AnimInfo.pCelSprite, item.AnimInfo.CurrentFrame); std::pair<int, int> itemBounds = MeasureSolidHorizontalBounds(*item.AnimInfo.celSprite, item.AnimInfo.CurrentFrame);
labelCenterOffsets[index].emplace((itemBounds.first + itemBounds.second) / 2); labelCenterOffsets[index].emplace((itemBounds.first + itemBounds.second) / 2);
} }

2
Source/quests.cpp

@ -29,7 +29,7 @@
namespace devilution { namespace devilution {
bool QuestLogIsOpen; bool QuestLogIsOpen;
std::optional<CelSprite> pQLogCel; std::optional<OwnedCelSprite> pQLogCel;
/** Contains the quests of the current game. */ /** Contains the quests of the current game. */
Quest Quests[MAXQUESTS]; Quest Quests[MAXQUESTS];
Point ReturnLvlPosition; Point ReturnLvlPosition;

2
Source/quests.h

@ -74,7 +74,7 @@ struct QuestData {
}; };
extern bool QuestLogIsOpen; extern bool QuestLogIsOpen;
extern std::optional<CelSprite> pQLogCel; extern std::optional<OwnedCelSprite> pQLogCel;
extern DVL_API_FOR_TEST Quest Quests[MAXQUESTS]; extern DVL_API_FOR_TEST Quest Quests[MAXQUESTS];
extern Point ReturnLvlPosition; extern Point ReturnLvlPosition;
extern dungeon_type ReturnLevelType; extern dungeon_type ReturnLevelType;

49
Source/scrollrt.cpp

@ -312,8 +312,8 @@ void DrawMissilePrivate(const Surface &out, const Missile &missile, Point target
return; return;
} }
int nCel = missile._miAnimFrame; int nCel = missile._miAnimFrame;
const int frames = LoadLE32(missile._miAnimData); const uint32_t frames = LoadLE32(missile._miAnimData);
if (nCel < 1 || frames > 50 || nCel > frames) { if (nCel < 1 || frames > 50 || nCel > static_cast<int>(frames)) {
Log("Draw Missile 2: frame {} of {}, missile type=={}", nCel, frames, missile._mitype); Log("Draw Missile 2: frame {} of {}, missile type=={}", nCel, frames, missile._mitype);
return; return;
} }
@ -352,7 +352,7 @@ void DrawMissile(const Surface &out, Point tilePosition, Point targetBufferPosit
*/ */
void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosition, const Monster &monster) void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosition, const Monster &monster)
{ {
if (monster.AnimInfo.pCelSprite == nullptr) { if (!monster.AnimInfo.celSprite) {
Log("Draw Monster \"{}\": NULL Cel Buffer", monster.mName); Log("Draw Monster \"{}\": NULL Cel Buffer", monster.mName);
return; return;
} }
@ -419,7 +419,7 @@ void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosit
}; };
int nCel = monster.AnimInfo.GetFrameToUseForRendering(); int nCel = monster.AnimInfo.GetFrameToUseForRendering();
const uint32_t frames = LoadLE32(monster.AnimInfo.pCelSprite->Data()); const uint32_t frames = LoadLE32(monster.AnimInfo.celSprite->Data());
if (nCel < 1 || frames > 50 || nCel > static_cast<int>(frames)) { if (nCel < 1 || frames > 50 || nCel > static_cast<int>(frames)) {
Log( Log(
"Draw Monster \"{}\" {}: facing {}, frame {} of {}", "Draw Monster \"{}\" {}: facing {}, frame {} of {}",
@ -431,7 +431,7 @@ void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosit
return; return;
} }
const auto &cel = *monster.AnimInfo.pCelSprite; const auto &cel = *monster.AnimInfo.celSprite;
if (!IsTileLit(tilePosition)) { if (!IsTileLit(tilePosition)) {
Cl2DrawTRN(out, targetBufferPosition.x, targetBufferPosition.y, cel, nCel, GetInfravisionTRN()); Cl2DrawTRN(out, targetBufferPosition.x, targetBufferPosition.y, cel, nCel, GetInfravisionTRN());
@ -455,7 +455,7 @@ void DrawMonster(const Surface &out, Point tilePosition, Point targetBufferPosit
*/ */
void DrawPlayerIconHelper(const Surface &out, int pnum, missile_graphic_id missileGraphicId, Point position, bool lighting) void DrawPlayerIconHelper(const Surface &out, int pnum, missile_graphic_id missileGraphicId, Point position, bool lighting)
{ {
position.x += CalculateWidth2(Players[pnum].AnimInfo.pCelSprite->Width()) - MissileSpriteData[missileGraphicId].animWidth2; position.x += CalculateWidth2(Players[pnum].AnimInfo.celSprite->Width()) - MissileSpriteData[missileGraphicId].animWidth2;
int width = MissileSpriteData[missileGraphicId].animWidth; int width = MissileSpriteData[missileGraphicId].animWidth;
const byte *pCelBuff = MissileSpriteData[missileGraphicId].GetFirstFrame(); const byte *pCelBuff = MissileSpriteData[missileGraphicId].GetFirstFrame();
@ -509,22 +509,22 @@ void DrawPlayer(const Surface &out, int pnum, Point tilePosition, Point targetBu
auto &player = Players[pnum]; auto &player = Players[pnum];
const auto *pCelSprite = player.AnimInfo.pCelSprite; std::optional<CelSprite> sprite = player.AnimInfo.celSprite;
int nCel = player.AnimInfo.GetFrameToUseForRendering(); int nCel = player.AnimInfo.GetFrameToUseForRendering();
if (player.pPreviewCelSprite != nullptr) { if (player.previewCelSprite) {
pCelSprite = player.pPreviewCelSprite; sprite = player.previewCelSprite;
nCel = 1; nCel = 1;
} }
if (pCelSprite == nullptr) { if (!sprite) {
Log("Drawing player {} \"{}\": NULL CelSprite", pnum, player._pName); Log("Drawing player {} \"{}\": NULL CelSprite", pnum, player._pName);
return; return;
} }
targetBufferPosition -= { CalculateWidth2(pCelSprite == nullptr ? 96 : pCelSprite->Width()), 0 }; targetBufferPosition -= { CalculateWidth2(sprite ? sprite->Width() : 96), 0 };
int frames = SDL_SwapLE32(*reinterpret_cast<const DWORD *>(pCelSprite->Data())); int frames = SDL_SwapLE32(*reinterpret_cast<const DWORD *>(sprite->Data()));
if (nCel < 1 || frames > 50 || nCel > frames) { if (nCel < 1 || frames > 50 || nCel > frames) {
const char *szMode = "unknown action"; const char *szMode = "unknown action";
if (player._pmode <= PM_QUIT) if (player._pmode <= PM_QUIT)
@ -541,16 +541,16 @@ void DrawPlayer(const Surface &out, int pnum, Point tilePosition, Point targetBu
} }
if (pnum == pcursplr) if (pnum == pcursplr)
Cl2DrawOutline(out, 165, targetBufferPosition.x, targetBufferPosition.y, *pCelSprite, nCel); Cl2DrawOutline(out, 165, targetBufferPosition.x, targetBufferPosition.y, *sprite, nCel);
if (pnum == MyPlayerId) { if (pnum == MyPlayerId) {
Cl2Draw(out, targetBufferPosition.x, targetBufferPosition.y, *pCelSprite, nCel); Cl2Draw(out, targetBufferPosition.x, targetBufferPosition.y, *sprite, nCel);
DrawPlayerIcons(out, pnum, targetBufferPosition, true); DrawPlayerIcons(out, pnum, targetBufferPosition, true);
return; return;
} }
if (!IsTileLit(tilePosition) || (Players[MyPlayerId]._pInfraFlag && LightTableIndex > 8)) { if (!IsTileLit(tilePosition) || (Players[MyPlayerId]._pInfraFlag && LightTableIndex > 8)) {
Cl2DrawTRN(out, targetBufferPosition.x, targetBufferPosition.y, *pCelSprite, nCel, GetInfravisionTRN()); Cl2DrawTRN(out, targetBufferPosition.x, targetBufferPosition.y, *sprite, nCel, GetInfravisionTRN());
DrawPlayerIcons(out, pnum, targetBufferPosition, true); DrawPlayerIcons(out, pnum, targetBufferPosition, true);
return; return;
} }
@ -561,7 +561,7 @@ void DrawPlayer(const Surface &out, int pnum, Point tilePosition, Point targetBu
else else
LightTableIndex -= 5; LightTableIndex -= 5;
Cl2DrawLight(out, targetBufferPosition.x, targetBufferPosition.y, *pCelSprite, nCel); Cl2DrawLight(out, targetBufferPosition.x, targetBufferPosition.y, *sprite, nCel);
DrawPlayerIcons(out, pnum, targetBufferPosition, false); DrawPlayerIcons(out, pnum, targetBufferPosition, false);
LightTableIndex = l; LightTableIndex = l;
@ -581,7 +581,7 @@ void DrawDeadPlayer(const Surface &out, Point tilePosition, Point targetBufferPo
auto &player = Players[i]; auto &player = Players[i];
if (player.plractive && player._pHitPoints == 0 && player.plrlevel == (BYTE)currlevel && player.position.tile == tilePosition) { if (player.plractive && player._pHitPoints == 0 && player.plrlevel == (BYTE)currlevel && player.position.tile == tilePosition) {
dFlags[tilePosition.x][tilePosition.y] |= DungeonFlag::DeadPlayer; dFlags[tilePosition.x][tilePosition.y] |= DungeonFlag::DeadPlayer;
const Displacement center { CalculateWidth2(player.AnimInfo.pCelSprite == nullptr ? 96 : player.AnimInfo.pCelSprite->Width()), 0 }; const Displacement center { CalculateWidth2(player.AnimInfo.celSprite ? player.AnimInfo.celSprite->Width() : 96), 0 };
const Point playerRenderPosition { targetBufferPosition + player.position.offset - center }; const Point playerRenderPosition { targetBufferPosition + player.position.offset - center };
DrawPlayer(out, i, tilePosition, playerRenderPosition); DrawPlayer(out, i, tilePosition, playerRenderPosition);
} }
@ -713,15 +713,15 @@ void DrawItem(const Surface &out, Point tilePosition, Point targetBufferPosition
if (item._iPostDraw == pre) if (item._iPostDraw == pre)
return; return;
const auto *cel = item.AnimInfo.pCelSprite; std::optional<CelSprite> cel = item.AnimInfo.celSprite;
if (cel == nullptr) { if (!cel) {
Log("Draw Item \"{}\" 1: NULL CelSprite", item._iIName); Log("Draw Item \"{}\" 1: NULL CelSprite", item._iIName);
return; return;
} }
int nCel = item.AnimInfo.GetFrameToUseForRendering(); int nCel = item.AnimInfo.GetFrameToUseForRendering();
int frames = SDL_SwapLE32(*(DWORD *)cel->Data()); const uint32_t frames = LoadLE32(cel->Data());
if (nCel < 1 || frames > 50 || nCel > frames) { if (nCel < 1 || frames > 50 || nCel > static_cast<int>(frames)) {
Log("Draw \"{}\" Item 1: frame {} of {}, item type=={}", item._iIName, nCel, frames, ItemTypeToString(item._itype)); Log("Draw \"{}\" Item 1: frame {} of {}, item type=={}", item._iIName, nCel, frames, ItemTypeToString(item._itype));
return; return;
} }
@ -750,11 +750,12 @@ void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBuffe
auto &towner = Towners[mi]; auto &towner = Towners[mi];
int px = targetBufferPosition.x - CalculateWidth2(towner._tAnimWidth); int px = targetBufferPosition.x - CalculateWidth2(towner._tAnimWidth);
const Point position { px, targetBufferPosition.y }; const Point position { px, targetBufferPosition.y };
CelSprite sprite { towner._tAnimData, towner._tAnimWidth };
if (mi == pcursmonst) { if (mi == pcursmonst) {
CelBlitOutlineTo(out, 166, position, CelSprite(towner._tAnimData, towner._tAnimWidth), towner._tAnimFrame); CelBlitOutlineTo(out, 166, position, sprite, towner._tAnimFrame);
} }
assert(towner._tAnimData); assert(towner._tAnimData);
CelClippedDrawTo(out, position, CelSprite(towner._tAnimData, towner._tAnimWidth), towner._tAnimFrame); CelClippedDrawTo(out, position, sprite, towner._tAnimFrame);
return; return;
} }
@ -776,7 +777,7 @@ void DrawMonsterHelper(const Surface &out, Point tilePosition, Point targetBuffe
return; return;
} }
const CelSprite &cel = *monster.AnimInfo.pCelSprite; CelSprite cel = *monster.AnimInfo.celSprite;
Displacement offset = monster.position.offset; Displacement offset = monster.position.offset;
if (monster.IsWalking()) { if (monster.IsWalking()) {

2
test/animationinfo_test.cpp

@ -75,7 +75,7 @@ void RunAnimationTest(const std::vector<TestData *> &vecTestData)
for (TestData *x : vecTestData) { for (TestData *x : vecTestData) {
auto setNewAnimationData = dynamic_cast<SetNewAnimationData *>(x); auto setNewAnimationData = dynamic_cast<SetNewAnimationData *>(x);
if (setNewAnimationData != nullptr) { if (setNewAnimationData != nullptr) {
animInfo.SetNewAnimation(nullptr, setNewAnimationData->_NumberOfFrames, setNewAnimationData->_DelayLen, setNewAnimationData->_Params, setNewAnimationData->_NumSkippedFrames, setNewAnimationData->_DistributeFramesBeforeFrame); animInfo.SetNewAnimation(std::nullopt, setNewAnimationData->_NumberOfFrames, setNewAnimationData->_DelayLen, setNewAnimationData->_Params, setNewAnimationData->_NumSkippedFrames, setNewAnimationData->_DistributeFramesBeforeFrame);
} }
auto gameTickData = dynamic_cast<GameTickData *>(x); auto gameTickData = dynamic_cast<GameTickData *>(x);

2
test/inv_test.cpp

@ -21,7 +21,7 @@ void set_up_scroll(Item &item, spell_id spell)
void clear_inventory() void clear_inventory()
{ {
for (int i = 0; i < NUM_INV_GRID_ELEM; i++) { for (int i = 0; i < NUM_INV_GRID_ELEM; i++) {
memset(&Players[MyPlayerId].InvList[i], 0, sizeof(Item)); Players[MyPlayerId].InvList[i] = {};
Players[MyPlayerId].InvGrid[i] = 0; Players[MyPlayerId].InvGrid[i] = 0;
} }
Players[MyPlayerId]._pNumInv = 0; Players[MyPlayerId]._pNumInv = 0;

Loading…
Cancel
Save