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> pManaBuff;
std::optional<CelSprite> talkButtons;
std::optional<CelSprite> pDurIcons;
std::optional<CelSprite> multiButtons;
std::optional<CelSprite> pPanelButtons;
std::optional<CelSprite> pGBoxBuff;
std::optional<OwnedCelSprite> talkButtons;
std::optional<OwnedCelSprite> pDurIcons;
std::optional<OwnedCelSprite> multiButtons;
std::optional<OwnedCelSprite> pPanelButtons;
std::optional<OwnedCelSprite> pGBoxBuff;
bool PanelButtons[8];
int PanelButtonIndex;
@ -518,7 +518,7 @@ void InitControlPan()
CelDrawUnsafeTo(*pBtmBuff, { 0, (PANEL_HEIGHT + 16) - 1 }, LoadCel("CtrlPan\\Panel8.CEL", PANEL_WIDTH), 1);
{
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(*pManaBuff, bulbsPosition, statusPanel, 2);
}

2
Source/controls/modifier_hints.cpp

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

2
Source/controls/touch/renderers.cpp

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

6
Source/cursor.cpp

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

6
Source/dead.cpp

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

2
Source/dead.h

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

2
Source/debug.cpp

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

2
Source/debug.h

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

2
Source/doom.cpp

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

8
Source/engine/animationinfo.cpp

@ -75,7 +75,7 @@ float AnimationInfo::GetAnimationProgress() const
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) {
// 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;
}
this->pCelSprite = celSprite;
this->celSprite = celSprite;
NumberOfFrames = numberOfFrames;
CurrentFrame = 1 + numSkippedFrames;
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) {
// 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;
TickModifier = 0.0F;
}
this->pCelSprite = celSprite;
this->celSprite = celSprite;
}
void AnimationInfo::ProcessAnimation(bool reverseAnimation /*= false*/, bool dontProgressAnimation /*= false*/)

11
Source/engine/animationinfo.h

@ -5,10 +5,11 @@
*/
#pragma once
#include <stdint.h>
#include <cstdint>
#include <type_traits>
#include "engine/cel_sprite.hpp"
#include "utils/stdcompat/optional.hpp"
namespace devilution {
@ -37,9 +38,9 @@ enum AnimationDistributionFlags : uint8_t {
class AnimationInfo {
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
*/
@ -82,7 +83,7 @@ public:
* @param distributeFramesBeforeFrame Distribute the numSkippedFrames only before this frame
* @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.
@ -90,7 +91,7 @@ public:
* @param numberOfFrames Number of Frames in Animation
* @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)

73
Source/engine/cel_sprite.hpp

@ -7,39 +7,31 @@
namespace devilution {
class OwnedCelSprite;
/**
* Stores a CEL or CL2 sprite and its width(s).
*
* The data may be unowned.
* Eventually we'd like to remove the unowned version.
* Does not own the data.
*/
class CelSprite {
public:
CelSprite(std::unique_ptr<byte[]> data, int width)
: data_(std::move(data))
, data_ptr_(data_.get())
CelSprite(const byte *data, int width)
: data_ptr_(data)
, width_(width)
{
}
CelSprite(std::unique_ptr<byte[]> data, const int *widths)
: data_(std::move(data))
, data_ptr_(data_.get())
CelSprite(const byte *data, const int *widths)
: data_ptr_(data)
, widths_(widths)
{
}
/**
* 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)
{
}
explicit CelSprite(const OwnedCelSprite &owned);
CelSprite(const CelSprite &) = default;
CelSprite(CelSprite &&) noexcept = default;
CelSprite &operator=(const CelSprite &) = default;
CelSprite &operator=(CelSprite &&) noexcept = default;
[[nodiscard]] const byte *Data() const
@ -52,11 +44,54 @@ public:
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:
std::unique_ptr<byte[]> data_;
const byte *data_ptr_;
int width_ = 0;
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

8
Source/engine/load_cel.cpp

@ -4,14 +4,14 @@
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

4
Source/engine/load_cel.hpp

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

20
Source/engine/render/cel_render.cpp

@ -580,14 +580,14 @@ void CelBlitLightSafeTo(const Surface &out, Point position, const byte *pRLEByte
} // 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;
const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize);
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;
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));
}
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;
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));
}
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;
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));
}
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;
const auto *pRLEBytes = CelGetFrameClipped(cel.Data(), frame, &nDataSize);
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;
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;
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));
}
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;
const auto *pRLEBytes = CelGetFrame(cel.Data(), frame, &nDataSize);
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;
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);
}
std::pair<int, int> MeasureSolidHorizontalBounds(const CelSprite &cel, int frame)
std::pair<int, int> MeasureSolidHorizontalBounds(CelSprite cel, int frame)
{
int 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)
* 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
@ -27,7 +27,7 @@ std::pair<int, int> MeasureSolidHorizontalBounds(const CelSprite &cel, int frame
* @param cel CEL sprite
* @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.
@ -36,7 +36,7 @@ void CelDrawTo(const Surface &out, Point position, const CelSprite &cel, int fra
* @param cel CEL sprite
* @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
@ -45,7 +45,7 @@ void CelDrawUnsafeTo(const Surface &out, Point position, const CelSprite &cel, i
* @param cel CEL sprite
* @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
@ -54,7 +54,7 @@ void CelClippedDrawTo(const Surface &out, Point position, const CelSprite &cel,
* @param cel CEL sprite
* @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
@ -63,7 +63,7 @@ void CelDrawLightTo(const Surface &out, Point position, const CelSprite &cel, in
* @param cel CEL sprite
* @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
@ -72,7 +72,7 @@ void CelClippedDrawLightTo(const Surface &out, Point position, const CelSprite &
* @param cel CEL sprite
* @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
@ -81,7 +81,7 @@ void CelClippedBlitLightTransTo(const Surface &out, Point position, const CelSpr
* @param cel CEL sprite
* @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
@ -91,7 +91,7 @@ void CelDrawLightRedTo(const Surface &out, Point position, const CelSprite &cel,
* @param cel CEL sprite
* @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
@ -102,6 +102,6 @@ void CelDrawItem(const Item &item, const Surface &out, Point position, const Cel
* @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)
*/
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

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);
@ -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));
}
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);
@ -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);
}
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);
@ -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);
}
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);

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 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
@ -41,7 +41,7 @@ void Cl2Draw(const Surface &out, int sx, int sy, const CelSprite &cel, int frame
* @param pCelBuff CL2 buffer
* @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
@ -52,7 +52,7 @@ void Cl2DrawOutline(const Surface &out, uint8_t col, int sx, int sy, const CelSp
* @param nCel CL2 frame number
* @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
@ -62,6 +62,6 @@ void Cl2DrawTRN(const Surface &out, int sx, int sy, const CelSprite &cel, int fr
* @param pCelBuff CL2 buffer
* @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

2
Source/engine/render/text_render.cpp

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

2
Source/engine/render/text_render.hpp

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

2
Source/gendung.cpp

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

2
Source/gendung.h

@ -150,7 +150,7 @@ extern int setpc_h;
extern std::unique_ptr<uint16_t[]> pSetPiece;
/** Specifies whether a single player quest DUN has been loaded. */
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). */
extern std::unique_ptr<MegaTile[]> pMegaTiles;
extern std::unique_ptr<uint16_t[]> pLevelPieces;

8
Source/gmenu.cpp

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

2
Source/interfac.cpp

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

2
Source/inv.cpp

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

26
Source/items.cpp

@ -127,7 +127,7 @@ _sfx_id ItemInvSnds[] = {
namespace {
std::optional<CelSprite> itemanims[ITEMTYPES];
std::optional<OwnedCelSprite> itemanims[ITEMTYPES];
enum class PlayerArmorGraphic : uint8_t {
// 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);
while (true) {
memset(&item, 0, sizeof(item));
item = {};
SetupAllItems(item, idx, AdvanceRndSeed(), 2 * lvl, 1, true, false, delta);
if (item._iCurs == icurs)
break;
@ -2875,13 +2875,13 @@ void CalcPlrItemVals(Player &player, bool loadgfx)
player._pgfxnum = gfxNum;
ResetPlayerGFX(player);
SetPlrAnims(player);
player.pPreviewCelSprite = nullptr;
player.previewCelSprite = std::nullopt;
if (player._pmode == PM_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 {
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 {
player._pgfxnum = gfxNum;
@ -2919,7 +2919,7 @@ void SetPlrHandItem(Item &item, int itemData)
auto &pAllItem = AllItemsList[itemData];
// zero-initialize struct
memset(&item, 0, sizeof(item));
item = {};
item._itype = pAllItem.itype;
item._iCurs = pAllItem.iCurs;
@ -3643,7 +3643,7 @@ void FreeItemGFX()
void GetItemFrm(Item &item)
{
item.AnimInfo.pCelSprite = &*itemanims[ItemCAnimTbl[item._iCurs]];
item.AnimInfo.celSprite = itemanims[ItemCAnimTbl[item._iCurs]]->Unowned();
}
void GetItemStr(Item &item)
@ -4582,7 +4582,7 @@ void CreateSpellBook(Point position, spell_id ispell, bool sendmsg, bool delta)
auto &item = Items[ii];
while (true) {
memset(&item, 0, sizeof(*Items));
item = {};
SetupAllItems(item, idx, AdvanceRndSeed(), 2 * lvl, 1, true, false, delta);
if (item._iMiscId == IMISC_BOOK && item._iSpell == ispell)
break;
@ -4705,7 +4705,7 @@ std::string DebugSpawnItem(std::string itemName)
continue;
Point bkp = item.position;
memset(&item, 0, sizeof(Item));
item = {};
item.position = bkp;
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);
Point bkp = item.position;
memset(&item, 0, sizeof(Item));
item = {};
item.position = bkp;
std::uniform_int_distribution<int32_t> dist(0, INT_MAX);
SetRndSeed(dist(BetterRng));
@ -4802,11 +4802,11 @@ void Item::SetNewAnimation(bool showAnimation)
{
int it = ItemCAnimTbl[_iCurs];
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)
AnimInfo.SetNewAnimation(pCelSprite, numberOfFrames, 1, AnimationDistributionFlags::ProcessAnimationPending, 0, numberOfFrames);
AnimInfo.SetNewAnimation(celSprite, numberOfFrames, 1, AnimationDistributionFlags::ProcessAnimationPending, 0, numberOfFrames);
else
AnimInfo.SetNewAnimation(pCelSprite, numberOfFrames, 1);
AnimInfo.SetNewAnimation(celSprite, numberOfFrames, 1);
_iPostDraw = false;
_iRequest = false;
if (showAnimation) {

126
Source/items.h

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

2
Source/minitext.cpp

@ -31,7 +31,7 @@ int qtextSpd;
/** Start time of scrolling */
Uint32 ScrollStart;
/** 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. */
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);
mis._mimfnum = static_cast<int32_t>(midir);
mis._miAnimFlags = MissileDataFlags::None;
const auto &celSprite = *anim.CelSpritesForDirections[mis._mimfnum];
CelSprite celSprite = *anim.GetCelSpritesForDirection(midir);
mis._miAnimData = celSprite.Data();
mis._miAnimDelay = anim.Rate;
mis._miAnimLen = anim.Frames;
@ -4184,7 +4184,7 @@ void missiles_process_charge()
} else {
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;
}
bool IsDirectionalAnim(const CMonster &monster, size_t animIndex)
{
return monster.mtype != MT_GOLEM || animIndex < 4;
}
void InitMonsterTRN(CMonster &monst)
{
std::array<uint8_t, 256> colorTranslations;
@ -149,11 +154,15 @@ void InitMonsterTRN(CMonster &monst)
continue;
}
for (int j = 0; j < 8; j++) {
Cl2ApplyTrans(
CelGetFrame(monst.Anims[i].cl2Data, j),
colorTranslations,
monst.Anims[i].Frames);
AnimStruct &anim = monst.Anims[i];
if (IsDirectionalAnim(monst, i)) {
for (int j = 0; j < 8; j++) {
Cl2ApplyTrans(anim.CelSpritesForDirections[j], colorTranslations, anim.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)
{
const auto &animData = monster.MType->GetAnimData(graphic);
const auto *pCelSprite = &*animData.CelSpritesForDirections[static_cast<size_t>(md)];
monster.AnimInfo.SetNewAnimation(pCelSprite, animData.Frames, animData.Rate, flags, numSkippedFrames, distributeFramesBeforeFrame);
monster.AnimInfo.SetNewAnimation(animData.GetCelSpritesForDirection(md), animData.Frames, animData.Rate, flags, numSkippedFrames, distributeFramesBeforeFrame);
monster._mFlags &= ~(MFLAG_LOCK_ANIMATION | MFLAG_ALLOW_SPECIAL);
monster._mdir = md;
}
@ -3726,17 +3734,18 @@ void InitMonsterGFX(int monst)
continue;
}
anim.cl2Data = &monster.animData[animOffsets[animIndex]];
anim.Frames = monsterData.Frames[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++) {
anim.CelSpritesForDirections[i].emplace(CelGetFrame(anim.cl2Data, i), width);
anim.CelSpritesForDirections[i] = CelGetFrame(cl2Data, i);
}
} else {
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 {
byte *cl2Data;
std::array<std::optional<CelSprite>, 8> CelSpritesForDirections;
inline const std::optional<CelSprite> &GetCelSpritesForDirection(Direction direction) const
[[nodiscard]] 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 Rate;
};
@ -230,10 +232,9 @@ struct Monster { // note: missing field _mAFNum
void ChangeAnimationData(MonsterGraphic graphic, Direction direction)
{
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.
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 {
std::optional<CelSprite> pChrButtons;
std::optional<OwnedCelSprite> pChrButtons;
/** Map of hero class names */
const char *const ClassStrTbl[] = {

2
Source/panels/charpanel.hpp

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

4
Source/panels/info_box.cpp

@ -4,8 +4,8 @@
namespace devilution {
std::optional<CelSprite> pSTextBoxCels;
std::optional<CelSprite> pSTextSlidCels;
std::optional<OwnedCelSprite> pSTextBoxCels;
std::optional<OwnedCelSprite> pSTextSlidCels;
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.
*/
extern std::optional<CelSprite> pSTextBoxCels;
extern std::optional<OwnedCelSprite> pSTextBoxCels;
/**
* @brief Info box scrollbar graphics.
*
* Used in stores and `DrawDiabloMsg`.
*/
extern std::optional<CelSprite> pSTextSlidCels;
extern std::optional<OwnedCelSprite> pSTextSlidCels;
void InitInfoBoxGfx();
void FreeInfoBoxGfx();

6
Source/panels/spell_book.cpp

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

4
Source/panels/spell_icons.cpp

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

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 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);

20
Source/player.cpp

@ -2270,9 +2270,9 @@ void Player::UpdatePreviewCelSprite(_cmd_id cmdId, Point point, uint16_t wParam1
return;
LoadPlrGFX(*this, *graphic);
auto &celSprites = AnimationData[static_cast<size_t>(*graphic)].CelSpritesForDirections[static_cast<size_t>(dir)];
if (celSprites && pPreviewCelSprite != &*celSprites) {
pPreviewCelSprite = &*celSprites;
std::optional<CelSprite> celSprites = AnimationData[static_cast<size_t>(*graphic)].GetCelSpritesForDirection(dir);
if (celSprites && previewCelSprite != celSprites) {
previewCelSprite = celSprites;
progressToNextGameTickWhenPreviewWasSet = gfProgressToNextGameTick;
}
}
@ -2401,7 +2401,7 @@ void InitPlayerGFX(Player &player)
void ResetPlayerGFX(Player &player)
{
player.AnimInfo.pCelSprite = nullptr;
player.AnimInfo.celSprite = std::nullopt;
for (auto &animData : player.AnimationData) {
for (auto &celSprite : animData.CelSpritesForDirections)
celSprite = std::nullopt;
@ -2413,14 +2413,12 @@ void NewPlrAnim(Player &player, player_graphic graphic, Direction dir, int numbe
{
LoadPlrGFX(player, graphic);
auto &celSprite = player.AnimationData[static_cast<size_t>(graphic)].CelSpritesForDirections[static_cast<size_t>(dir)];
CelSprite *pCelSprite = celSprite ? &*celSprite : nullptr;
std::optional<CelSprite> celSprite = player.AnimationData[static_cast<size_t>(graphic)].GetCelSpritesForDirection(dir);
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);
player.AnimInfo.SetNewAnimation(pCelSprite, numberOfFrames, delayLen, flags, numSkippedFrames, distributeFramesBeforeFrame, previewShownGameTickFragments);
player.AnimInfo.SetNewAnimation(celSprite, numberOfFrames, delayLen, flags, numSkippedFrames, distributeFramesBeforeFrame, previewShownGameTickFragments);
}
void SetPlrAnims(Player &player)
@ -3488,7 +3486,7 @@ void ProcessPlayers()
CheckNewPath(pnum, tplayer);
} while (tplayer);
player.pPreviewCelSprite = nullptr;
player.previewCelSprite = std::nullopt;
player.AnimInfo.ProcessAnimation();
}
}
@ -3711,7 +3709,7 @@ void SyncPlrAnim(int pnum)
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
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;
inline const std::optional<CelSprite> &GetCelSpritesForDirection(Direction direction) const
[[nodiscard]] std::optional<CelSprite> GetCelSpritesForDirection(Direction direction) const
{
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
*/
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;
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 point Point for the command
* @param wParam1 First Parameter

2
Source/qol/itemlabels.cpp

@ -77,7 +77,7 @@ void AddItemToLabelQueue(int id, int x, int y)
nameWidth += MarginX * 2;
int index = ItemCAnimTbl[item._iCurs];
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);
}

2
Source/quests.cpp

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

2
Source/quests.h

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

49
Source/scrollrt.cpp

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

2
test/animationinfo_test.cpp

@ -75,7 +75,7 @@ void RunAnimationTest(const std::vector<TestData *> &vecTestData)
for (TestData *x : vecTestData) {
auto setNewAnimationData = dynamic_cast<SetNewAnimationData *>(x);
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);

2
test/inv_test.cpp

@ -21,7 +21,7 @@ void set_up_scroll(Item &item, spell_id spell)
void clear_inventory()
{
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]._pNumInv = 0;

Loading…
Cancel
Save