code:
#include "Database/Terms.hpp"

Terms::Terms(const Terms& other)
: IModifiable(other)
, m_basic(other.m_basic)
, m_commands(other.m_commands)
, m_messages(other.m_messages)
, m_params(other.m_params)
, m_oldbasic(other.m_oldbasic)
, m_oldcommands(other.m_oldcommands)
, m_oldmessages(other.m_oldmessages)
, m_oldparams(other.m_oldparams) {}

Terms& Terms::operator=(const Terms& other) {
  IModifiable::operator=(other);
  m_basic = other.m_basic;
  m_commands = other.m_commands;
  m_messages = other.m_messages;
  m_params = other.m_params;
  m_oldbasic = other.m_oldbasic;
  m_oldcommands = other.m_oldcommands;
  m_oldmessages = other.m_oldmessages;
  m_oldparams = other.m_oldparams;
  return *this;
}

Terms::Terms(Terms&& other) noexcept
: IModifiable(std::move(other))
, m_basic(std::move(other.m_basic))
, m_commands(std::move(other.m_commands))
, m_messages(std::move(other.m_messages))
, m_params(std::move(other.m_params))
, m_oldbasic(std::move(other.m_oldbasic))
, m_oldcommands(std::move(other.m_oldcommands))
, m_oldmessages(std::move(other.m_oldmessages))
, m_oldparams(std::move(other.m_oldparams)) {}

Terms& Terms::operator=(Terms&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_basic = std::move(other.m_basic);
  m_commands = std::move(other.m_commands);
  m_messages = std::move(other.m_messages);
  m_params = std::move(other.m_params);
  m_oldbasic = std::move(other.m_oldbasic);
  m_oldcommands = std::move(other.m_oldcommands);
  m_oldmessages = std::move(other.m_oldmessages);
  m_oldparams = std::move(other.m_oldparams);
  return *this;
}

std::vector<std::optional<std::string>>& Terms::basic() { return m_basic; }
const std::vector<std::optional<std::string>>& Terms::basic() const { return m_basic; }
void Terms::setBasic(std::vector<std::optional<std::string>>& value) {
  if (m_basic == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(basic);
  m_basic = value;
  if (!signalsDisabled()) {
   emit_signal( basicModified(), this, value);
  }
  setModified();
}

std::vector<std::optional<std::string>>& Terms::commands() { return m_commands; }
const std::vector<std::optional<std::string>>& Terms::commands() const { return m_commands; }
void Terms::setCommands(std::vector<std::optional<std::string>>& value) {
  if (m_commands == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(commands);
  m_commands = value;
  if (!signalsDisabled()) {
    emit_signal(commandsModified(), this, value);
  }
  setModified();
}

Messages& Terms::messages() { return m_messages; }
const Messages& Terms::messages() const { return m_messages; }
void Terms::setMessages(const Messages& value) {
  if (m_messages == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(messages);
  m_messages = value;
  if (!signalsDisabled()) {
    emit_signal(messagesModified(), this, value);
  }
  setModified();
}

std::vector<std::optional<std::string>>& Terms::params() { return m_params; }
const std::vector<std::optional<std::string>>& Terms::params() const { return m_params; }
void Terms::setParams(std::vector<std::optional<std::string>>& value) {
  if (m_params == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(params);
  m_params = value;
  if (!signalsDisabled()) {
    emit_signal(paramsModified(), this, value);
  }
  setModified();
}

void Terms::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(basic);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(commands);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(messages);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(params);
  m_messages.restoreOriginal();
}
void Terms::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(basic);
  MODIFIABLE_ACCEPT_VALUE(commands);
  MODIFIABLE_ACCEPT_VALUE(messages);
  MODIFIABLE_ACCEPT_VALUE(params);
  m_messages.acceptChanges();
}
nlohmann::ordered_json Terms::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_VALUE(basic),
      MODIFIABLE_SERIALIZE_VALUE(commands),
      MODIFIABLE_SERIALIZE_CHILD_VALUE(messages),
      MODIFIABLE_SERIALIZE_VALUE(params),
  };
}

rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>& Terms::basicModified() {
  if (!m_basicModified) {
    m_basicModified.emplace();
  }
  return *m_basicModified;
}

rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>& Terms::commandsModified() {
  if (!m_commandsModified) {
    m_commandsModified.emplace();
  }
  return *m_commandsModified;
}

rpgmutils::signal<void(Terms*, const Messages&)>& Terms::messagesModified() {
  if (!m_messagesModified) {
    m_messagesModified.emplace();
  }
  return *m_messagesModified;
}

rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>& Terms::paramsModified() {
  if (!m_paramsModified) {
    m_paramsModified.emplace();
  }
  return *m_paramsModified;
}

void to_json(nlohmann::ordered_json& j, const Terms& terms) {
  j = {
      {"basic", terms.m_basic},
      {"commands", terms.m_commands},
      {"messages", terms.m_messages},
      {"params", terms.m_params},
  };
}

void from_json(const nlohmann::ordered_json& j, Terms& terms) {
  terms.m_basic = j.value("basic", terms.m_basic);
  terms.m_commands = j.value("commands", terms.m_commands);
  terms.m_messages = j.value("messages", terms.m_messages);
  terms.m_params = j.value("params", terms.m_params);
}


code:
#pragma once

#include "Database/Messages.hpp"

#include <nlohmann/json.hpp>
#include <string>
#include <vector>

class Terms final : public IModifiable {
  friend void to_json(nlohmann::ordered_json& j, const Terms& terms);
  friend void from_json(const nlohmann::ordered_json& j, Terms& terms);

public:
  Terms() = default;
  Terms(const Terms& other);
  Terms& operator=(const Terms& other);
  Terms(Terms&& other) noexcept;
  Terms& operator=(Terms&& other) noexcept;

  std::vector<std::optional<std::string>>& basic();
  const std::vector<std::optional<std::string>>& basic() const;
  void setBasic(std::vector<std::optional<std::string>>& value);

  std::vector<std::optional<std::string>>& commands();
  const std::vector<std::optional<std::string>>& commands() const;
  void setCommands(std::vector<std::optional<std::string>>& value);

  Messages& messages();
  const Messages& messages() const;
  void setMessages(const Messages& value);

  std::vector<std::optional<std::string>>& params();
  const std::vector<std::optional<std::string>>& params() const;
  void setParams(std::vector<std::optional<std::string>>& value);

  void restoreOriginal() override;
  void acceptChanges() override;
  nlohmann::ordered_json serializeOldValues() const override;

  bool isModified() const override { return IModifiable::isModified() | m_messages.isModified(); }

  rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>& basicModified();
  rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>& commandsModified();
  rpgmutils::signal<void(Terms*, const Messages&)>& messagesModified();
  rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>& paramsModified();

  bool operator==(const Terms& rhs) const { return m_basic == rhs.m_basic && m_commands == rhs.m_commands && m_params == rhs.m_params && m_messages == rhs.m_messages; }

private:
  std::vector<std::optional<std::string>> m_basic;
  std::vector<std::optional<std::string>> m_commands;
  Messages m_messages;
  std::vector<std::optional<std::string>> m_params;

  std::optional<std::vector<std::optional<std::string>>> m_oldbasic;
  std::optional<std::vector<std::optional<std::string>>> m_oldcommands;
  std::optional<Messages> m_oldmessages;
  std::optional<std::vector<std::optional<std::string>>> m_oldparams;

  std::optional<rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>> m_basicModified;
  std::optional<rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>> m_commandsModified;
  std::optional<rpgmutils::signal<void(Terms*, const Messages&)>> m_messagesModified;
  std::optional<rpgmutils::signal<void(Terms*, const std::vector<std::optional<std::string>>&)>> m_paramsModified;
};

void to_json(nlohmann::ordered_json& j, const Terms& terms);
void from_json(const nlohmann::ordered_json& j, Terms& terms);

repo_name: Antidote/openrpgeditor

license: mit


code:
#include "Database/TileHelper.hpp"

#include "Globals.hpp"

#include <array>
#include <cmath>

namespace TileHelper {

bool isVisibleTile(const int tileId) { return tileId > 0 && tileId < TILE_ID_MAX; }

bool isAutoTile(const int tileId) { return tileId >= TILE_ID_A1; }

int getAutoTileKind(const int tileId) { return std::floor((tileId - TILE_ID_A1) / 48); }

int getAutoTileShape(const int tileId) { return (tileId - TILE_ID_A1) % 48; }

int makeAutoTileId(const int kind, const int shape) { return TILE_ID_A1 + kind * 48 + shape; }

bool isSameKindTile(const int tileId1, const int tileId2) { return (isAutoTile(tileId1) && isAutoTile(tileId2) && getAutoTileKind(tileId1) == getAutoTileKind(tileId2)) || tileId1 == tileId2; }

bool isTileA1(const int tileId) { return tileId >= TILE_ID_A1 && tileId < TILE_ID_A2; }

bool isTileA2(const int tileId) { return tileId >= TILE_ID_A2 && tileId < TILE_ID_A3; }

bool isTileA3(const int tileId) { return tileId >= TILE_ID_A3 && tileId < TILE_ID_A4; }

bool isTileA4(const int tileId) { return tileId >= TILE_ID_A4 && tileId < TILE_ID_MAX; }

bool isTileA5(const int tileId) { return tileId >= TILE_ID_A5 && tileId < TILE_ID_A1; }

bool isTileB(const int tileId) { return tileId >= TILE_ID_B && tileId < TILE_ID_C; }

bool isTileC(const int tileId) { return tileId >= TILE_ID_C && tileId < TILE_ID_D; }

bool isTileD(const int tileId) { return tileId >= TILE_ID_D && tileId < TILE_ID_E; }

bool isTileE(const int tileId) { return tileId >= TILE_ID_E && tileId < TILE_ID_A5; }

bool isWaterTile(const int tileId) { return isTileA1(tileId) && !(tileId >= TILE_ID_A1 + 96 && tileId < TILE_ID_A1 + 192); }

bool isWaterfallTile(const int tileId) { return (tileId >= TILE_ID_A1 + 192 && tileId < TILE_ID_A2) && getAutoTileKind(tileId) % 2 == 1; }

bool isGroundTile(const int tileId) { return isTileA1(tileId) || isTileA2(tileId) || isTileA5(tileId); }

bool isShadowingTile(const int tileId) { return isTileA3(tileId) || isTileA4(tileId); }

bool isRoofTile(const int tileId) { return isTileA3(tileId) && getAutoTileKind(tileId) % 16 < 8; }

bool isWallTopTile(const int tileId) { return isTileA4(tileId) && getAutoTileKind(tileId) % 16 < 8; }

bool isWallSideTile(const int tileId) { return (isTileA3(tileId) || isTileA4(tileId)) && getAutoTileKind(tileId) % 16 >= 8; }

bool isWallTile(const int tileId) { return isWallTopTile(tileId) || isWallSideTile(tileId); }

bool isWallOrRoofTile(const int tileId) { return isWallTile(tileId) || isRoofTile(tileId); }

bool isFloorTypeAutotile(const int tileId) { return (isTileA1(tileId) && !isWaterfallTile(tileId)) || isTileA2(tileId) || isWallTopTile(tileId); }

bool isWallTypeAutotile(const int tileId) { return isRoofTile(tileId) || isWallSideTile(tileId); }

bool isWaterfallTypeAutotile(const int tileId) { return isWaterfallTile(tileId); }

bool shouldCreateBorder(const int currentTileId, const int adjacentTileId) {
  if (adjacentTileId < TILE_ID_B || !isAutoTile(currentTileId)) {
    return false;
  }

  if (!isAutoTile(adjacentTileId)) {
    return true;
  }

  if (!isWaterTile(currentTileId) || !isWaterTile(adjacentTileId)) {
    if (!isWaterfallTile(currentTileId) && !isWaterfallTile(adjacentTileId)) {
      return !isSameKindTile(currentTileId, adjacentTileId);
    }
  }

  return false;
}

int floorDirToShape(const int dir) {
  static constexpr std::array table{
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18, 18, 19, 19, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22,
      22, 23, 23, 23, 23, 34, 34, 34, 34, 35, 35, 35, 35, 34, 34, 34, 34, 35, 35, 35, 35, 24, 26, 24, 26, 24, 26, 24, 26, 25, 27, 25, 27, 25, 27, 25, 27, 32, 32, 32, 32, 32, 32,
      32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 28,
      29, 30, 31, 28, 29, 30, 31, 28, 29, 30, 31, 28, 29, 30, 31, 40, 40, 41, 41, 40, 40, 41, 41, 40, 40, 41, 41, 40, 40, 41, 41, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
      33, 33, 33, 33, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 38, 39, 38, 39, 38, 39, 38, 39, 38, 39, 38, 39, 38, 39, 38, 39, 44, 44, 44, 44, 44, 44, 44,
      44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
  };

  return table[dir];
}

int floorShapeToDir(const int shape) {
  static constexpr std::array table{
      0,  1,  2,  3,  4,   5,   6,   7,   8,  9,   10, 11, 12,  13,  14,  15,  25,  27,  29,  31,  35,  39,  43,  47,
      70, 78, 71, 79, 140, 141, 142, 143, 95, 175, 59, 63, 103, 111, 206, 207, 157, 159, 127, 191, 223, 239, 255, 0,
  };

  return table[shape];
}

[[nodiscard]] int wallDirToShape(const int dir) {
  int shape = (dir >> 4) & 0x01;
  if (dir & 0x20) {
    shape |= 0x02;
  }
  if (dir & 0x40) {
    shape |= 0x04;
  }
  if (dir & 0x80) {
    shape |= 0x08;
  }
  return shape;
}

[[nodiscard]] int wallShapeToDir(const int shape) {
  int dir = (shape & 0x01) ? 0x10 : 0;
  if ((shape & 0x2) != 0) {
    dir |= 0x20;
  }
  if ((shape & 0x4) != 0) {
    dir |= 0x40;
  }
  if ((shape & 0x8) != 0) {
    dir |= 0x80;
  }
  return dir;
}

int waterfallShapeToDir(const int shape) {
  int dir = (shape & 0x01) ? 0x10 : 0;

  if (shape & 0x02) {
    dir |= 0x40;
  }

  return dir;
}

int waterfallDirToShape(const int dir) {
  int shape = (dir >> 4) & 1;
  if (dir & 0x40) {
    shape |= 0x2;
  }
  return shape;
}
bool isTilePassable(int tileFlags) {
  if (tileFlags == -1) {
    return true;
  }
  return (tileFlags & static_cast<int>(TileFlags::Impassable)) == 0;
}
bool hasHigherTile(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::PassageHigherTile)) != 0; }
bool isNorthPassage(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::PassageNorth)) == 0; }
bool isSouthPassage(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::PassageSouth)) == 0; }
bool isWestPassage(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::PassageWest)) == 0; }
bool isEastPassage(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::PassageEast)) == 0; }
bool isLadder(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::Ladder)) != 0; }
bool isBush(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::Bush)) != 0; }
bool isCounter(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::Counter)) != 0; }
bool isDamageFloor(int tileFlags) { return (tileFlags & static_cast<int>(TileFlags::Damage)) != 0; }
bool isTerrainTag(int tileFlags) { return (tileFlags >> 12) > 0; }
int getTerrainTag(int tileFlags) { return tileFlags >> 12; }

} // namespace TileHelper


code:
#pragma once

namespace TileHelper {
constexpr int TILE_ID_B = 0;
constexpr int TILE_ID_C = 256;
constexpr int TILE_ID_D = 512;
constexpr int TILE_ID_E = 768;
constexpr int TILE_ID_A5 = 1536;
constexpr int TILE_ID_A1 = 2048;
constexpr int TILE_ID_A2 = 2816;
constexpr int TILE_ID_A3 = 4352;
constexpr int TILE_ID_A4 = 5888;
constexpr int TILE_ID_MAX = 8192;

[[nodiscard]] bool isVisibleTile(int tileId);
[[nodiscard]] bool isAutoTile(int tileId);
[[nodiscard]] int getAutoTileKind(int tileId);
[[nodiscard]] int getAutoTileShape(int tileId);
[[nodiscard]] int makeAutoTileId(int kind, int shape);
[[nodiscard]] bool isSameKindTile(int tileId1, int tileId2);
[[nodiscard]] bool isTileA1(int tileId);
[[nodiscard]] bool isTileA2(int tileId);
[[nodiscard]] bool isTileA3(int tileId);
[[nodiscard]] bool isTileA4(int tileId);
[[nodiscard]] bool isTileA5(int tileId);
[[nodiscard]] bool isTileB(int tileId);
[[nodiscard]] bool isTileC(int tileId);
[[nodiscard]] bool isTileD(int tileId);
[[nodiscard]] bool isTileE(int tileId);
[[nodiscard]] bool isWaterTile(int tileId);
[[nodiscard]] bool isWaterfallTile(int tileId);
[[nodiscard]] bool isGroundTile(int tileId);
[[nodiscard]] bool isShadowingTile(int tileId);
[[nodiscard]] bool isRoofTile(int tileId);
[[nodiscard]] bool isWallTopTile(int tileId);
[[nodiscard]] bool isWallSideTile(int tileId);
[[nodiscard]] bool isWallTile(int tileId);
[[nodiscard]] bool isWallOrRoofTile(int tileId);
[[nodiscard]] bool isFloorTypeAutotile(int tileId);
[[nodiscard]] bool isWallTypeAutotile(int tileId);
[[nodiscard]] bool isWaterfallTypeAutotile(int tileId);
[[nodiscard]] bool shouldCreateBorder(int currentTileId, int adjacentTileId);

[[nodiscard]] int floorDirToShape(int dir);
[[nodiscard]] int floorShapeToDir(int shape);

[[nodiscard]] int wallDirToShape(int dir);
[[nodiscard]] int wallShapeToDir(int shape);

[[nodiscard]] int waterfallDirToShape(int dir);
[[nodiscard]] int waterfallShapeToDir(int shape);

[[nodiscard]] bool isTilePassable(int tileFlags);
[[nodiscard]] bool hasHigherTile(int tileFlags);
[[nodiscard]] bool isNorthPassage(int tileFlags);
[[nodiscard]] bool isSouthPassage(int tileFlags);
[[nodiscard]] bool isWestPassage(int tileFlags);
[[nodiscard]] bool isEastPassage(int tileFlags);
[[nodiscard]] bool isLadder(int tileFlags);
[[nodiscard]] bool isBush(int tileFlags);
[[nodiscard]] bool isCounter(int tileFlags);
[[nodiscard]] bool isDamageFloor(int tileFlags);
[[nodiscard]] bool isTerrainTag(int tileFlags);
[[nodiscard]] int getTerrainTag(int tileFlags);
} // namespace TileHelper


code:
#include "Database/Tileset.hpp"
#include "Database/Globals.hpp"

Tileset::Tileset(const Tileset& other)
: IModifiable(other)
, m_id(other.m_id)
, m_flags(other.m_flags)
, m_mode(other.m_mode)
, m_name(other.m_name)
, m_note(other.m_note)
, m_tilesetNames(other.m_tilesetNames)
, m_oldid(other.m_oldid)
, m_oldflags(other.m_oldflags)
, m_oldmode(other.m_oldmode)
, m_oldname(other.m_oldname)
, m_oldnote(other.m_oldnote)
, m_oldtilesetNames(other.m_oldtilesetNames)
, m_isValid(other.m_isValid) {}

Tileset& Tileset::operator=(const Tileset& other) {
  IModifiable::operator=(other);
  m_id = other.m_id;
  m_flags = other.m_flags;
  m_mode = other.m_mode;
  m_name = other.m_name;
  m_note = other.m_note;
  m_tilesetNames = other.m_tilesetNames;
  m_oldid = other.m_oldid;
  m_oldflags = other.m_oldflags;
  m_oldmode = other.m_oldmode;
  m_oldname = other.m_oldname;
  m_oldnote = other.m_oldnote;
  m_oldtilesetNames = other.m_oldtilesetNames;
  m_isValid = other.m_isValid;
  return *this;
}

Tileset::Tileset(Tileset&& other) noexcept
: IModifiable(other)
, m_id(other.m_id)
, m_flags(std::move(other.m_flags))
, m_mode(other.m_mode)
, m_name(std::move(other.m_name))
, m_note(std::move(other.m_note))
, m_tilesetNames(std::move(other.m_tilesetNames))
, m_oldid(other.m_oldid)
, m_oldflags(std::move(other.m_oldflags))
, m_oldmode(other.m_oldmode)
, m_oldname(std::move(other.m_oldname))
, m_oldnote(std::move(other.m_oldnote))
, m_oldtilesetNames(std::move(other.m_oldtilesetNames))
, m_isValid(other.m_isValid) {}

Tileset& Tileset::operator=(Tileset&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_id = other.m_id;
  m_flags = std::move(other.m_flags);
  m_mode = other.m_mode;
  m_name = std::move(other.m_name);
  m_note = std::move(other.m_note);
  m_tilesetNames = std::move(other.m_tilesetNames);
  m_oldid = other.m_oldid;
  m_oldflags = std::move(other.m_oldflags);
  m_oldmode = other.m_oldmode;
  m_oldname = std::move(other.m_oldname);
  m_oldnote = std::move(other.m_oldnote);
  m_oldtilesetNames = std::move(other.m_oldtilesetNames);
  m_isValid = other.m_isValid;
  return *this;
}

[[nodiscard]] int Tileset::id() const { return m_id; }
void Tileset::setId(const int id) {
  if (m_id == id) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(id);
  m_id = id;
  if (!signalsDisabled()) {
  emit_signal(idModified(), this, id);
  }
  setModified();
}

[[nodiscard]] const std::vector<std::optional<int>>& Tileset::flags() const { return m_flags; }

int Tileset::flag(const int id) {
  if (id > TileHelper::TILE_ID_MAX) {
    return 0;
  }
  if (id >= m_flags.size() && m_flags.size() <= TileHelper::TILE_ID_MAX) {
    int i = id - (m_flags.size() - 1);
    while (i--) {
      m_flags.emplace_back();
    }
    m_flags.back() = 0;
  }

  if (id >= m_flags.size()) {
    return 0;
  }
  if (!m_flags[id]) {
    m_flags[id] = 0;
  }
  return *m_flags[id];
}

[[nodiscard]] int Tileset::flag(const int idx) const {
  if (idx > TileHelper::TILE_ID_MAX) {
    return 0;
  }

  if (idx >= 0 && idx < m_flags.size()) {
    return m_flags[idx] ? *m_flags[idx] : 0;
  }
  return 0;
}

void Tileset::setFlags(const std::vector<std::optional<int>>& flags) {
  if (m_flags == flags) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(flags);
  m_flags = flags;
  if (!signalsDisabled()) {
  emit_signal(flagsModified(), this, flags);
  }
  setModified();
}
void Tileset::setFlag(const int idx, const int flag, const bool enabled) {
  MODIFIABLE_SET_OLD_VALUE(flags);
  if (idx >= m_flags.size() && m_flags.size() <= TileHelper::TILE_ID_MAX) {
    int i = idx - (m_flags.size() - 1);
    while (i--) {
      m_flags.emplace_back();
    }
  } else if (idx > TileHelper::TILE_ID_MAX) {
    return;
  }
  if (!m_flags[idx]) {
    m_flags[idx] = 0;
  }

  if (enabled) {
    *m_flags[idx] |= flag;
  } else {
    *m_flags[idx] &= ~flag;
  }
  if (!signalsDisabled()) {
  emit_signal(flagsModified(), this, m_flags);
  }
  setModified();
}

void Tileset::setTerrainTag(const int idx, const int tag) {
  MODIFIABLE_SET_OLD_VALUE(flags);
  if (idx >= m_flags.size() && m_flags.size() <= TileHelper::TILE_ID_MAX) {
    int i = idx - (m_flags.size() - 1);
    while (i--) {
      m_flags.emplace_back();
    }
  } else if (idx > TileHelper::TILE_ID_MAX) {
    return;
  }
  if (!m_flags[idx]) {
    m_flags[idx] = 0;
  }

  *m_flags[idx] = ((tag & 0xFFFFF) << 12) | (*m_flags[idx] & 0xFFF);
  if (!signalsDisabled()) {
  emit_signal(flagsModified(), this, m_flags);
  }
  setModified();
}

[[nodiscard]] Tileset::Mode Tileset::mode() const { return m_mode; }
void Tileset::setMode(const Mode mode) {
  if (m_mode == mode) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(mode);
  m_mode = mode;
  if (!signalsDisabled()) {
  emit_signal(modeModified(), this, mode);
  }
  setModified();
}

[[nodiscard]] const std::string& Tileset::name() const { return m_name; }
void Tileset::setName(const std::string& name) {
  if (m_name == name) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(name);
  m_name = name;
  if (!signalsDisabled()) {
  emit_signal(nameModified(), this, name);
  }
  setModified();
}

[[nodiscard]] const std::string& Tileset::note() const { return m_note; }
void Tileset::setNote(const std::string& note) {
  if (m_note == note) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(note);
  m_note = note;
  if (!signalsDisabled()) {
  emit_signal(noteModified(), this, note);
  }
  setModified();
}

[[nodiscard]] const std::array<std::string, 9>& Tileset::tilesetNames() const { return m_tilesetNames; }
void Tileset::setTilesetNames(const std::array<std::string, 9>& tilesetNames) {
  if (m_tilesetNames == tilesetNames) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(tilesetNames);
  m_tilesetNames = tilesetNames;
  if (!signalsDisabled()) {
  emit_signal(tilesetNamesModified(), this, tilesetNames);
  }
  setModified();
}
[[nodiscard]] const std::string& Tileset::tilesetName(const int idx) const {
  assert(idx >= 0 && idx < m_tilesetNames.size());
  return m_tilesetNames[idx];
}
void Tileset::setTilesetName(const int idx, const std::string& name) {
  assert(idx >= 0 && idx < m_tilesetNames.size());
  if (m_tilesetNames[idx] == name) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(tilesetNames);
  m_tilesetNames[idx] = name;
  if (!signalsDisabled()) {
  emit_signal(tilesetNamesModified(), this, m_tilesetNames);
  }
  setModified();
}

void Tileset::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(id);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(flags);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(mode);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(name);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(note);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(tilesetNames);
}
void Tileset::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(id);
  MODIFIABLE_ACCEPT_VALUE(flags);
  MODIFIABLE_ACCEPT_VALUE(mode);
  MODIFIABLE_ACCEPT_VALUE(name);
  MODIFIABLE_ACCEPT_VALUE(note);
  MODIFIABLE_ACCEPT_VALUE(tilesetNames);
}
nlohmann::ordered_json Tileset::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_VALUE(id),   MODIFIABLE_SERIALIZE_VALUE(flags), MODIFIABLE_SERIALIZE_VALUE(mode),
      MODIFIABLE_SERIALIZE_VALUE(name), MODIFIABLE_SERIALIZE_VALUE(note),  MODIFIABLE_SERIALIZE_VALUE(tilesetNames),
  };
}

rpgmutils::signal<void(Tileset*, int)>& Tileset::idModified() {
  if (!m_idModified) {
    m_idModified.emplace();
  }
  return *m_idModified;
}
rpgmutils::signal<void(Tileset*, const std::vector<std::optional<int>>&)>& Tileset::flagsModified() {
  if (!m_flagsModified) {
    m_flagsModified.emplace();
  }
  return *m_flagsModified;
}
rpgmutils::signal<void(Tileset*, Tileset::Mode)>& Tileset::modeModified() {
  if (!m_modeModified) {
    m_modeModified.emplace();
  }
  return *m_modeModified;
}
rpgmutils::signal<void(Tileset*, const std::string&)>& Tileset::nameModified() {
  if (!m_nameModified) {
    m_nameModified.emplace();
  }
  return *m_nameModified;
}
rpgmutils::signal<void(Tileset*, const std::string&)>& Tileset::noteModified() {
  if (!m_noteModified) {
    m_noteModified.emplace();
  }
  return *m_noteModified;
}
rpgmutils::signal<void(Tileset*, const std::array<std::string, 9>&)>& Tileset::tilesetNamesModified() {
  if (!m_tilesetNamesModified) {
    m_tilesetNamesModified.emplace();
  }
  return *m_tilesetNamesModified;
}

void to_json(nlohmann::ordered_json& j, const Tileset& tileset) {
  j = {
      {"id", tileset.m_id}, {"flags", tileset.m_flags}, {"mode", tileset.m_mode}, {"name", tileset.m_name}, {"note", tileset.m_note}, {"tilesetNames", tileset.m_tilesetNames},
  };
}

void from_json(const nlohmann::ordered_json& j, Tileset& tileset) {
  tileset.m_id = j.value("id", tileset.m_id);
  tileset.m_flags = j.value("flags", tileset.m_flags);
  tileset.m_mode = j.value("mode", tileset.m_mode);
  tileset.m_name = j.value("name", tileset.m_name);
  tileset.m_note = j.value("note", tileset.m_note);
  tileset.m_tilesetNames = j.value("tilesetNames", tileset.m_tilesetNames);
}


code:
#pragma once

#include "Database/IModifiable.hpp"
#include "Database/TileHelper.hpp"

#include <array>
#include <string>
#include <vector>

#include <nlohmann/json.hpp>

class Tileset final : public IModifiable {
public:
  friend class TilesetsSerializer;
  friend void to_json(nlohmann::ordered_json& j, const Tileset& tileset);
  friend void from_json(const nlohmann::ordered_json& j, Tileset& tileset);
  enum class Mode {
    World,
    Area,
  };

  Tileset() = default;
  Tileset(const Tileset& other);
  Tileset& operator=(const Tileset& other);
  Tileset(Tileset&& other) noexcept;
  Tileset& operator=(Tileset&& other) noexcept;

  [[nodiscard]] int id() const;
  void setId(int id);

  [[nodiscard]] const std::vector<std::optional<int>>& flags() const;

  int flag(int id);
  [[nodiscard]] int flag(int idx) const;

  void setFlags(const std::vector<std::optional<int>>& flags);
  void setFlag(int idx, int flag, bool enabled = true);

  void setTerrainTag(int idx, int tag);
  [[nodiscard]] Mode mode() const;
  void setMode(Mode mode);

  [[nodiscard]] const std::string& name() const;
  void setName(const std::string& name);

  [[nodiscard]] const std::string& note() const;
  void setNote(const std::string& note);

  [[nodiscard]] const std::array<std::string, 9>& tilesetNames() const;
  void setTilesetNames(const std::array<std::string, 9>& tilesetNames);
  [[nodiscard]] const std::string& tilesetName(int idx) const;
  void setTilesetName(int idx, const std::string& name);

  void restoreOriginal() override;
  void acceptChanges() override;
  nlohmann::ordered_json serializeOldValues() const override;

  rpgmutils::signal<void(Tileset*, int)>& idModified();
  rpgmutils::signal<void(Tileset*, const std::vector<std::optional<int>>&)>& flagsModified();
  rpgmutils::signal<void(Tileset*, Mode)>& modeModified();
  rpgmutils::signal<void(Tileset*, const std::string&)>& nameModified();
  rpgmutils::signal<void(Tileset*, const std::string&)>& noteModified();
  rpgmutils::signal<void(Tileset*, const std::array<std::string, 9>&)>& tilesetNamesModified();

  [[nodiscard]] bool isValid() const { return m_isValid; }
  void setValid(const bool isValid) { m_isValid = isValid; }

private:
  int m_id;
  std::vector<std::optional<int>> m_flags;
  Mode m_mode;
  std::string m_name;
  std::string m_note;
  std::array<std::string, 9> m_tilesetNames;

  std::optional<int> m_oldid;
  std::optional<std::vector<std::optional<int>>> m_oldflags;
  std::optional<Mode> m_oldmode;
  std::optional<std::string> m_oldname;
  std::optional<std::string> m_oldnote;
  std::optional<std::array<std::string, 9>> m_oldtilesetNames;

  std::optional<rpgmutils::signal<void(Tileset*, int)>> m_idModified;
  std::optional<rpgmutils::signal<void(Tileset*, const std::vector<std::optional<int>>&)>> m_flagsModified;
  std::optional<rpgmutils::signal<void(Tileset*, Mode)>> m_modeModified;
  std::optional<rpgmutils::signal<void(Tileset*, const std::string&)>> m_nameModified;
  std::optional<rpgmutils::signal<void(Tileset*, const std::string&)>> m_noteModified;
  std::optional<rpgmutils::signal<void(Tileset*, const std::array<std::string, 9>&)>> m_tilesetNamesModified;

  /*!
   * @name m_isValid
   * @details
   * Indicates that this is an actual valid entry and not a dummy
   *
   * When making a new entry make sure to set this to true or it won't be
   * serialized.
   */
  bool m_isValid{false};
};
void to_json(nlohmann::json& j, const Tileset& tileset);
void from_json(const nlohmann::json& j, Tileset& tileset);


code: #include "Database/Tilesets.hpp"


code:
#pragma once

#include "Database/Tileset.hpp"

class Tilesets final : public IModifiable {
public:
  [[nodiscard]] Tileset* tileset(const int id) {
    for (auto& item : m_tilesets) {
      if (item.id() == id && item.isValid()) {
        return &item;
      }
    }
    return nullptr;
  }

  [[nodiscard]] const Tileset* tileset(const int id) const {
    for (const auto& item : m_tilesets) {
      if (item.id() == id && item.isValid()) {
        return &item;
      }
    }

    return nullptr;
  }

  [[nodiscard]] std::vector<Tileset>& tilesets() { return m_tilesets; }
  [[nodiscard]] const std::vector<Tileset>& tilesets() const { return m_tilesets; }
  [[nodiscard]] int count() const { return static_cast<int>(m_tilesets.size() - 1); }

  void resize(int newSize) {
    ++newSize;
    const int oldSize = static_cast<int>(m_tilesets.size());
    m_tilesets.resize(newSize);
    if (newSize > oldSize) {
      for (int i = oldSize; i < m_tilesets.size(); ++i) {
        m_tilesets[i].setId(i);
      }
    }
  }

  bool isModified() const override {
    return IModifiable::isModified() | std::ranges::any_of(m_tilesets, [](const Tileset& tileset) { return tileset.isModified(); });
  }

private:
  std::vector<Tileset> m_tilesets;
};


code:
#include "Database/Trait.hpp"

void to_json(nlohmann::ordered_json& j, const Trait& t) {
  j = {
      {"code", t.m_code},
      {"dataId", t.m_dataId},
      {"value", t.m_value},
  };
}

void from_json(const nlohmann::ordered_json& j, Trait& t) {
  t.m_code = j.value("code", t.m_code);
  t.m_dataId = j.value("dataId", t.m_dataId);
  t.m_value = j.value("value", t.m_value);
}

Trait::Trait(const Trait& trait)
: IModifiable(trait)
, m_code(trait.m_code)
, m_dataId(trait.m_dataId)
, m_value(trait.m_value) {}
Trait& Trait::operator=(const Trait& trait) {
  IModifiable::operator=(trait);
  m_code = trait.m_code;
  m_dataId = trait.m_dataId;
  m_value = trait.m_value;
  return *this;
}
Trait::Trait(Trait&& trait) noexcept
: m_code(trait.m_code)
, m_dataId(trait.m_dataId)
, m_value(trait.m_value)
, IModifiable(std::move(trait)) {}
Trait& Trait::operator=(Trait&& trait) noexcept {
  m_code = trait.m_code;
  m_dataId = trait.m_dataId;
  m_value = trait.m_value;
  IModifiable::operator=(std::move(trait));
  return *this;
}

TraitCode Trait::code() const { return m_code; }
void Trait::setCode(const TraitCode code) {
  MODIFIABLE_SET_OLD_VALUE(code);
  m_code = code;
  if (!signalsDisabled()) {
  emit_signal(codeModified(), this, code);
  }
  setModified();
}

[[nodiscard]] int Trait::dataId() const { return m_dataId; }
void Trait::setDataId(const int dataId) {
  MODIFIABLE_SET_OLD_VALUE(dataId);
  m_dataId = dataId;
  if (!signalsDisabled()) {
  emit_signal(dataIdModified(), this, dataId);
  }
  setModified();
}

[[nodiscard]] double Trait::value() const { return m_value; }
void Trait::setValue(const double value) {
  MODIFIABLE_SET_OLD_VALUE(value);
  m_value = value;
  if (!signalsDisabled()) {
  emit_signal(valueModified(), this, value);
  }
  setModified();
}

void Trait::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(code);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(dataId);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(value);
}

void Trait::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(code);
  MODIFIABLE_ACCEPT_VALUE(dataId);
  MODIFIABLE_ACCEPT_VALUE(value);
}

nlohmann::ordered_json Trait::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_VALUE(code),
      MODIFIABLE_SERIALIZE_VALUE(dataId),
      MODIFIABLE_SERIALIZE_VALUE(value),
  };
}

rpgmutils::signal<void(Trait*, TraitCode)>& Trait::codeModified() {
  if (!m_codeModified) {
    m_codeModified.emplace();
  }
  return *m_codeModified;
}

rpgmutils::signal<void(Trait*, int)>& Trait::dataIdModified() {
  if (!m_dataIdModified) {
    m_dataIdModified.emplace();
  }
  return *m_dataIdModified;
}

rpgmutils::signal<void(Trait*, double)>& Trait::valueModified() {
  if (!m_valueModified) {
    m_valueModified.emplace();
  }
  return *m_valueModified;
}


code:
#pragma once

#include "Database/Globals.hpp"
#include "IModifiable.hpp"

#include "nlohmann/json.hpp"

class Trait final : public IModifiable {
  friend void to_json(nlohmann::ordered_json& j, const Trait& trait);
  friend void from_json(const nlohmann::ordered_json& j, Trait& trait);

public:
  Trait() = default;
  Trait(const Trait& trait);
  Trait& operator=(const Trait& trait);
  Trait(Trait&& trait) noexcept;
  Trait& operator=(Trait&& trait) noexcept;

  TraitCode code() const;
  void setCode(TraitCode code);
  [[nodiscard]] int dataId() const;
  void setDataId(int dataId);
  [[nodiscard]] double value() const;
  void setValue(double value);

  void restoreOriginal() override;
  void acceptChanges() override;
  nlohmann::ordered_json serializeOldValues() const override;

  // Signals
  rpgmutils::signal<void(Trait*, TraitCode)>& codeModified();
  rpgmutils::signal<void(Trait*, int)>& dataIdModified();
  rpgmutils::signal<void(Trait*, double)>& valueModified();

  bool operator==(const Trait& trait) const { return m_code == trait.m_code && m_dataId == trait.m_dataId && m_value == trait.m_value; }

private:
  TraitCode m_code = TraitCode::Element_Rate;
  int m_dataId = 1;
  double m_value = 1.f;

  // !!!DO NOT CHANGE CASING!!!
  std::optional<TraitCode> m_oldcode;
  std::optional<int> m_olddataId;
  std::optional<double> m_oldvalue;

  std::optional<rpgmutils::signal<void(Trait*, TraitCode)>> m_codeModified;
  std::optional<rpgmutils::signal<void(Trait*, int)>> m_dataIdModified;
  std::optional<rpgmutils::signal<void(Trait*, double)>> m_valueModified;
};
void to_json(nlohmann::ordered_json& j, const Trait& trait);
void from_json(const nlohmann::ordered_json& j, Trait& trait);


code:
#include "Database/Troop.hpp"
#include "Database/CommandParser.hpp"

Troop::Member::Member(const Member& other)
: IModifiable(other)
, m_enemyId(other.m_enemyId)
, m_x(other.m_x)
, m_y(other.m_y)
, m_hidden(other.m_hidden)
, m_oldenemyId(other.m_oldenemyId)
, m_oldx(other.m_oldx)
, m_oldy(other.m_oldy)
, m_oldhidden(other.m_oldhidden) {}

Troop::Member& Troop::Member::operator=(const Member& other) {
  IModifiable::operator=(other);
  m_enemyId = other.m_enemyId;
  m_x = other.m_x;
  m_y = other.m_y;
  m_hidden = other.m_hidden;
  m_oldenemyId = other.m_oldenemyId;
  m_oldx = other.m_oldx;
  m_oldy = other.m_oldy;
  m_oldhidden = other.m_oldhidden;
  return *this;
}

Troop::Member::Member(Member&& other) noexcept
: IModifiable(std::move(other))
, m_enemyId(other.m_enemyId)
, m_x(other.m_x)
, m_y(other.m_y)
, m_hidden(other.m_hidden)
, m_oldenemyId(other.m_oldenemyId)
, m_oldx(other.m_oldx)
, m_oldy(other.m_oldy)
, m_oldhidden(other.m_oldhidden) {}

Troop::Member& Troop::Member::operator=(Member&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_enemyId = other.m_enemyId;
  m_x = other.m_x;
  m_y = other.m_y;
  m_hidden = other.m_hidden;
  m_oldenemyId = other.m_oldenemyId;
  m_oldx = other.m_oldx;
  m_oldy = other.m_oldy;
  m_oldhidden = other.m_oldhidden;
  return *this;
}

int Troop::Member::enemyId() const { return m_enemyId; }
void Troop::Member::setEnemyId(int value) {
  if (m_enemyId == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(enemyId);
  m_enemyId = value;
  if (!signalsDisabled()) {
    emit_signal(enemyIdModified(), this, value);
  }
  setModified();
}

int Troop::Member::x() const { return m_x; }
void Troop::Member::setX(int value) {
  if (m_x == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(x);
  m_x = value;
  if (!signalsDisabled()) {
    emit_signal(xModified(), this, value);
  }
  setModified();
}

int Troop::Member::y() const { return m_y; }
void Troop::Member::setY(int value) {
  if (m_y == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(y);
  m_y = value;
  if (!signalsDisabled()) {
    emit_signal(yModified(), this, value);
  }
  setModified();
}

bool Troop::Member::hidden() const { return m_hidden; }
void Troop::Member::setHidden(bool value) {
  if (m_hidden == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(hidden);
  m_hidden = value;
  if (!signalsDisabled()) {
    emit_signal(hiddenModified(), this, value);
  }
  setModified();
}

void Troop::Member::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(enemyId);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(x);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(y);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(hidden);
}
void Troop::Member::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(enemyId);
  MODIFIABLE_ACCEPT_VALUE(x);
  MODIFIABLE_ACCEPT_VALUE(y);
  MODIFIABLE_ACCEPT_VALUE(hidden);
}
nlohmann::ordered_json Troop::Member::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_VALUE(enemyId),
      MODIFIABLE_SERIALIZE_VALUE(x),
      MODIFIABLE_SERIALIZE_VALUE(y),
      MODIFIABLE_SERIALIZE_VALUE(hidden),
  };
}

rpgmutils::signal<void(Troop::Member*, int)>& Troop::Member::enemyIdModified() {
  if (!m_enemyIdModified) {
    m_enemyIdModified.emplace();
  }
  return *m_enemyIdModified;
}
rpgmutils::signal<void(Troop::Member*, int)>& Troop::Member::xModified() {
  if (!m_xModified) {
    m_xModified.emplace();
  }
  return *m_xModified;
}
rpgmutils::signal<void(Troop::Member*, int)>& Troop::Member::yModified() {
  if (!m_yModified) {
    m_yModified.emplace();
  }
  return *m_yModified;
}
rpgmutils::signal<void(Troop::Member*, bool)>& Troop::Member::hiddenModified() {
  if (!m_hiddenModified) {
    m_hiddenModified.emplace();
  }
  return *m_hiddenModified;
}

Troop::Conditions::Conditions(const Conditions& other)
: IModifiable(other)
, m_actorHp(other.m_actorHp)
, m_actorId(other.m_actorId)
, m_actorValid(other.m_actorValid)
, m_enemyIndex(other.m_enemyIndex)
, m_enemyHp(other.m_enemyHp)
, m_enemyValid(other.m_enemyValid)
, m_switchId(other.m_switchId)
, m_switchValid(other.m_switchValid)
, m_turnA(other.m_turnA)
, m_turnB(other.m_turnB)
, m_turnEnding(other.m_turnEnding)
, m_turnValid(other.m_turnValid)
, m_oldactorHp(other.m_oldactorHp)
, m_oldactorId(other.m_oldactorId)
, m_oldactorValid(other.m_oldactorValid)
, m_oldenemyIndex(other.m_oldenemyIndex)
, m_oldenemyHp(other.m_oldenemyHp)
, m_oldenemyValid(other.m_oldenemyValid)
, m_oldswitchId(other.m_oldswitchId)
, m_oldswitchValid(other.m_oldswitchValid)
, m_oldturnA(other.m_oldturnA)
, m_oldturnB(other.m_oldturnB)
, m_oldturnEnding(other.m_oldturnEnding)
, m_oldturnValid(other.m_oldturnValid) {}

Troop::Conditions& Troop::Conditions::operator=(const Conditions& other) {
  IModifiable::operator=(other);
  m_actorHp = other.m_actorHp;
  m_actorId = other.m_actorId;
  m_actorValid = other.m_actorValid;
  m_enemyIndex = other.m_enemyIndex;
  m_enemyHp = other.m_enemyHp;
  m_enemyValid = other.m_enemyValid;
  m_switchId = other.m_switchId;
  m_switchValid = other.m_switchValid;
  m_turnA = other.m_turnA;
  m_turnB = other.m_turnB;
  m_turnEnding = other.m_turnEnding;
  m_turnValid = other.m_turnValid;
  m_oldactorHp = other.m_oldactorHp;
  m_oldactorId = other.m_oldactorId;
  m_oldactorValid = other.m_oldactorValid;
  m_oldenemyIndex = other.m_oldenemyIndex;
  m_oldenemyHp = other.m_oldenemyHp;
  m_oldenemyValid = other.m_oldenemyValid;
  m_oldswitchId = other.m_oldswitchId;
  m_oldswitchValid = other.m_oldswitchValid;
  m_oldturnA = other.m_oldturnA;
  m_oldturnB = other.m_oldturnB;
  m_oldturnEnding = other.m_oldturnEnding;
  m_oldturnValid = other.m_oldturnValid;
  return *this;
}

Troop::Conditions::Conditions(Conditions&& other) noexcept
: IModifiable(std::move(other))
, m_actorHp(other.m_actorHp)
, m_actorId(other.m_actorId)
, m_actorValid(other.m_actorValid)
, m_enemyIndex(other.m_enemyIndex)
, m_enemyHp(other.m_enemyHp)
, m_enemyValid(other.m_enemyValid)
, m_switchId(other.m_switchId)
, m_switchValid(other.m_switchValid)
, m_turnA(other.m_turnA)
, m_turnB(other.m_turnB)
, m_turnEnding(other.m_turnEnding)
, m_turnValid(other.m_turnValid)
, m_oldactorHp(other.m_oldactorHp)
, m_oldactorId(other.m_oldactorId)
, m_oldactorValid(other.m_oldactorValid)
, m_oldenemyIndex(other.m_oldenemyIndex)
, m_oldenemyHp(other.m_oldenemyHp)
, m_oldenemyValid(other.m_oldenemyValid)
, m_oldswitchId(other.m_oldswitchId)
, m_oldswitchValid(other.m_oldswitchValid)
, m_oldturnA(other.m_oldturnA)
, m_oldturnB(other.m_oldturnB)
, m_oldturnEnding(other.m_oldturnEnding)
, m_oldturnValid(other.m_oldturnValid) {}
Troop::Conditions& Troop::Conditions::operator=(Conditions&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_actorHp = other.m_actorHp;
  m_actorId = other.m_actorId;
  m_actorValid = other.m_actorValid;
  m_enemyIndex = other.m_enemyIndex;
  m_enemyHp = other.m_enemyHp;
  m_enemyValid = other.m_enemyValid;
  m_switchId = other.m_switchId;
  m_switchValid = other.m_switchValid;
  m_turnA = other.m_turnA;
  m_turnB = other.m_turnB;
  m_turnEnding = other.m_turnEnding;
  m_turnValid = other.m_turnValid;
  m_oldactorHp = other.m_oldactorHp;
  m_oldactorId = other.m_oldactorId;
  m_oldactorValid = other.m_oldactorValid;
  m_oldenemyIndex = other.m_oldenemyIndex;
  m_oldenemyHp = other.m_oldenemyHp;
  m_oldenemyValid = other.m_oldenemyValid;
  m_oldswitchId = other.m_oldswitchId;
  m_oldswitchValid = other.m_oldswitchValid;
  m_oldturnA = other.m_oldturnA;
  m_oldturnB = other.m_oldturnB;
  m_oldturnEnding = other.m_oldturnEnding;
  m_oldturnValid = other.m_oldturnValid;
  return *this;
}

int Troop::Conditions::actorHp() const { return m_actorHp; }
void Troop::Conditions::setActorHp(int value) {
  if (m_actorHp == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(actorHp);
  m_actorHp = value;
  if (!signalsDisabled()) {
    emit_signal(actorHpModified(), this, value);
  }
  setModified();
}

int Troop::Conditions::actorId() const { return m_actorId; }
void Troop::Conditions::setActorId(int value) {
  if (m_actorId == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(actorId);
  m_actorId = value;
  if (!signalsDisabled()) {
    emit_signal(actorIdModified(), this, value);
  }
  setModified();
}

bool Troop::Conditions::actorValid() const { return m_actorValid; }
void Troop::Conditions::setActorValid(const bool value) {
  if (m_actorValid == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(actorValid);
  m_actorValid = value;
  if (!signalsDisabled()) {
    emit_signal(actorValidModified(), this, value);
  }
  setModified();
}

int Troop::Conditions::enemyIndex() const { return m_enemyIndex; }
void Troop::Conditions::setEnemyIndex(const int value) {
  if (m_enemyIndex == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(enemyIndex);
  m_enemyIndex = value;
  if (!signalsDisabled()) {
    emit_signal(enemyIndexModified(), this, value);
  }
  setModified();
}

int Troop::Conditions::enemyHp() const { return m_enemyHp; }
void Troop::Conditions::setEnemyHp(const int value) {
  if (m_enemyHp == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(enemyHp);
  m_enemyHp = value;
  if (!signalsDisabled()) {
    emit_signal(enemyHpModified(), this, value);
  }
  setModified();
}

bool Troop::Conditions::enemyValid() const { return m_enemyValid; }
void Troop::Conditions::setEnemyValid(const bool value) {
  if (m_enemyValid == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(enemyValid);
  m_enemyValid = value;
  if (!signalsDisabled()) {
    emit_signal(enemyValidModified(), this, value);
  }
  setModified();
}

int Troop::Conditions::switchId() const { return m_switchId; }
void Troop::Conditions::setSwitchId(const int value) {
  if (m_switchId == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(switchId);
  m_switchId = value;
  if (!signalsDisabled()) {
    emit_signal(switchIdModified(), this, value);
  }
  setModified();
}

bool Troop::Conditions::switchValid() const { return m_switchValid; }
void Troop::Conditions::setSwitchValid(const bool value) {
  if (m_switchValid == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(switchValid);
  m_switchValid = value;
  if (!signalsDisabled()) {
    emit_signal(switchValidModified(), this, value);
  }
  setModified();
}

int Troop::Conditions::turnA() const { return m_turnA; }
void Troop::Conditions::setTurnA(const int value) {
  if (m_turnA == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(turnA);
  m_turnA = value;
  if (!signalsDisabled()) {
    emit_signal(turnAModified(), this, value);
  }
  setModified();
}

int Troop::Conditions::turnB() const { return m_turnB; }
void Troop::Conditions::setTurnB(const int value) {
  if (m_turnB == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(turnB);
  m_turnB = value;
  if (!signalsDisabled()) {
    emit_signal(turnBModified(), this, value);
  }
  setModified();
}

bool Troop::Conditions::turnEnding() const { return m_turnEnding; }
void Troop::Conditions::setTurnEnding(const bool value) {
  if (m_turnEnding == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(turnEnding);
  m_turnEnding = value;
  if (!signalsDisabled()) {
    emit_signal(turnEndingModified(), this, value);
  }
  setModified();
}

bool Troop::Conditions::turnValid() const { return m_turnValid; }
void Troop::Conditions::setTurnValid(const bool value) {
  if (m_turnValid == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(turnValid);
  m_turnValid = value;
  if (!signalsDisabled()) {
    emit_signal(turnValidModified(), this, value);
  }
  setModified();
}

void Troop::Conditions::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(actorHp);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(actorId);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(actorValid);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(enemyIndex);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(enemyHp);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(enemyValid);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(switchId);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(switchValid);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(turnA);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(turnB);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(turnEnding);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(turnValid);
}
void Troop::Conditions::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(actorHp);
  MODIFIABLE_ACCEPT_VALUE(actorId);
  MODIFIABLE_ACCEPT_VALUE(actorValid);
  MODIFIABLE_ACCEPT_VALUE(enemyIndex);
  MODIFIABLE_ACCEPT_VALUE(enemyHp);
  MODIFIABLE_ACCEPT_VALUE(enemyValid);
  MODIFIABLE_ACCEPT_VALUE(switchId);
  MODIFIABLE_ACCEPT_VALUE(switchValid);
  MODIFIABLE_ACCEPT_VALUE(turnA);
  MODIFIABLE_ACCEPT_VALUE(turnB);
  MODIFIABLE_ACCEPT_VALUE(turnEnding);
  MODIFIABLE_ACCEPT_VALUE(turnValid);
}
nlohmann::ordered_json Troop::Conditions::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_VALUE(actorHp), MODIFIABLE_SERIALIZE_VALUE(actorId),    MODIFIABLE_SERIALIZE_VALUE(actorValid), MODIFIABLE_SERIALIZE_VALUE(enemyIndex),
      MODIFIABLE_SERIALIZE_VALUE(enemyHp), MODIFIABLE_SERIALIZE_VALUE(enemyValid), MODIFIABLE_SERIALIZE_VALUE(switchId),   MODIFIABLE_SERIALIZE_VALUE(switchValid),
      MODIFIABLE_SERIALIZE_VALUE(turnA),   MODIFIABLE_SERIALIZE_VALUE(turnB),      MODIFIABLE_SERIALIZE_VALUE(turnEnding), MODIFIABLE_SERIALIZE_VALUE(turnValid),
  };
}

rpgmutils::signal<void(Troop::Conditions*, int)>& Troop::Conditions::actorHpModified() {
  if (!m_actorHpModified) {
    m_actorHpModified.emplace();
  }
  return *m_actorHpModified;
}
rpgmutils::signal<void(Troop::Conditions*, int)>& Troop::Conditions::actorIdModified() {
  if (!m_actorIdModified) {
    m_actorIdModified.emplace();
  }
  return *m_actorIdModified;
}
rpgmutils::signal<void(Troop::Conditions*, bool)>& Troop::Conditions::actorValidModified() {
  if (!m_actorValidModified) {
    m_actorValidModified.emplace();
  }
  return *m_actorValidModified;
}
rpgmutils::signal<void(Troop::Conditions*, int)>& Troop::Conditions::enemyIndexModified() {
  if (!m_enemyIndexModified) {
    m_enemyIndexModified.emplace();
  }
  return *m_enemyIndexModified;
}
rpgmutils::signal<void(Troop::Conditions*, int)>& Troop::Conditions::enemyHpModified() {
  if (!m_enemyHpModified) {
    m_enemyHpModified.emplace();
  }
  return *m_enemyHpModified;
}
rpgmutils::signal<void(Troop::Conditions*, bool)>& Troop::Conditions::enemyValidModified() {
  if (!m_enemyValidModified) {
    m_enemyValidModified.emplace();
  }
  return *m_enemyValidModified;
}
rpgmutils::signal<void(Troop::Conditions*, int)>& Troop::Conditions::switchIdModified() {
  if (!m_switchIdModified) {
    m_switchIdModified.emplace();
  }
  return *m_switchIdModified;
}
rpgmutils::signal<void(Troop::Conditions*, bool)>& Troop::Conditions::switchValidModified() {
  if (!m_switchValidModified) {
    m_switchValidModified.emplace();
  }
  return *m_switchValidModified;
}
rpgmutils::signal<void(Troop::Conditions*, int)>& Troop::Conditions::turnAModified() {
  if (!m_turnAModified) {
    m_turnAModified.emplace();
  }
  return *m_turnAModified;
}
rpgmutils::signal<void(Troop::Conditions*, int)>& Troop::Conditions::turnBModified() {
  if (!m_turnBModified) {
    m_turnBModified.emplace();
  }
  return *m_turnBModified;
}
rpgmutils::signal<void(Troop::Conditions*, bool)>& Troop::Conditions::turnEndingModified() {
  if (!m_turnEndingModified) {
    m_turnEndingModified.emplace();
  }
  return *m_turnEndingModified;
}
rpgmutils::signal<void(Troop::Conditions*, bool)>& Troop::Conditions::turnValidModified() {
  if (!m_turnValidModified) {
    m_turnValidModified.emplace();
  }
  return *m_turnValidModified;
}

Troop::Page::Page(const Page& other)
: IModifiable(other)
, m_conditions(other.m_conditions)
, m_list(other.m_list)
, m_span(other.m_span)
, m_oldconditions(other.m_oldconditions)
, m_oldlist(other.m_oldlist)
, m_oldspan(other.m_oldspan) {}
Troop::Page& Troop::Page::operator=(const Page& other) {
  IModifiable::operator=(other);
  m_conditions = other.m_conditions;
  m_list = other.m_list;
  m_span = other.m_span;
  m_oldconditions = other.m_oldconditions;
  m_oldlist = other.m_oldlist;
  m_oldspan = other.m_oldspan;
  return *this;
}
Troop::Page::Page(Page&& other) noexcept
: IModifiable(std::move(other))
, m_conditions(std::move(other.m_conditions))
, m_list(std::move(other.m_list))
, m_span(other.m_span)
, m_oldconditions(std::move(other.m_oldconditions))
, m_oldlist(std::move(other.m_oldlist))
, m_oldspan(other.m_oldspan) {}

Troop::Page& Troop::Page::operator=(Page&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_conditions = std::move(other.m_conditions);
  m_list = std::move(other.m_list);
  m_span = other.m_span;
  m_oldconditions = std::move(other.m_oldconditions);
  m_oldlist = std::move(other.m_oldlist);
  m_oldspan = other.m_oldspan;
  return *this;
}

Troop::Conditions& Troop::Page::conditions() { return m_conditions; }
const Troop::Conditions& Troop::Page::conditions() const { return m_conditions; }
void Troop::Page::setConditions(const Conditions& value) {
  if (m_conditions == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(conditions);
  m_conditions = value;
  if (!signalsDisabled()) {
    emit_signal(conditionsModified(), this, value);
  }
  setModified();
}

std::vector<std::shared_ptr<IEventCommand>>& Troop::Page::list() { return m_list; }
const std::vector<std::shared_ptr<IEventCommand>>& Troop::Page::list() const { return m_list; }
void Troop::Page::setList(const std::vector<std::shared_ptr<IEventCommand>>& value) {
  if (m_list == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(list);
  m_list = value;
  if (!signalsDisabled()) {
    emit_signal(listModified(), this, value);
  }
  setModified();
}

int Troop::Page::span() const { return m_span; }
void Troop::Page::setSpan(int value) {
  if (m_span == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(span);
  m_span = value;
  if (!signalsDisabled()) {
    emit_signal(spanModified(), this, value);
  }
  setModified();
}

void Troop::Page::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(conditions);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(list);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(span);
  m_conditions.restoreOriginal();
  std::ranges::for_each(m_list, [&](const std::shared_ptr<IEventCommand>& command) { command->restoreOriginal(); });
}
void Troop::Page::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(conditions);
  MODIFIABLE_ACCEPT_VALUE(list);
  MODIFIABLE_ACCEPT_VALUE(span);
  m_conditions.acceptChanges();
  std::ranges::for_each(m_list, [&](const std::shared_ptr<IEventCommand>& command) { command->acceptChanges(); });
}

nlohmann::ordered_json Troop::Page::serializeOldValues() const {
  nlohmann::ordered_json j;
  j["conditions"] = m_oldconditions ? *m_oldconditions : m_conditions;
  nlohmann::ordered_json list;
  CommandParser::serialize(list, m_oldlist ? *m_oldlist : m_list, false, true);
  j["list"] = list;
  j["span"] = m_oldspan ? *m_oldspan : m_span;

  return j;
}

rpgmutils::signal<void(Troop::Page*, const Troop::Conditions&)>& Troop::Page::conditionsModified() {
  if (!m_conditionsModified) {
    m_conditionsModified.emplace();
  }
  return *m_conditionsModified;
}
rpgmutils::signal<void(Troop::Page*, const std::vector<std::shared_ptr<IEventCommand>>&)>& Troop::Page::listModified() {
  if (!m_listModified) {
    m_listModified.emplace();
  }
  return *m_listModified;
}
rpgmutils::signal<void(Troop::Page*, int)>& Troop::Page::spanModified() {
  if (!m_spanModified) {
    m_spanModified.emplace();
  }
  return *m_spanModified;
}

Troop::Troop(const Troop& other)
: IModifiable(other)
, m_id(other.m_id)
, m_members(other.m_members)
, m_name(other.m_name)
, m_pages(other.m_pages)
, m_oldid(other.m_oldid)
, m_oldmembers(other.m_oldmembers)
, m_oldname(other.m_oldname)
, m_oldpages(other.m_oldpages)
, m_isValid(other.m_isValid) {}

Troop& Troop::operator=(const Troop& other) {
  IModifiable::operator=(other);
  m_id = other.m_id;
  m_members = other.m_members;
  m_name = other.m_name;
  m_pages = other.m_pages;
  m_oldid = other.m_oldid;
  m_oldmembers = other.m_oldmembers;
  m_oldname = other.m_oldname;
  m_oldpages = other.m_oldpages;
  m_isValid = other.m_isValid;
  return *this;
}

Troop::Troop(Troop&& other) noexcept
: IModifiable(std::move(other))
, m_id(other.m_id)
, m_members(std::move(other.m_members))
, m_name(std::move(other.m_name))
, m_pages(std::move(other.m_pages))
, m_oldid(other.m_oldid)
, m_oldmembers(std::move(other.m_oldmembers))
, m_oldname(std::move(other.m_oldname))
, m_oldpages(std::move(other.m_oldpages))
, m_isValid(other.m_isValid) {}

Troop& Troop::operator=(Troop&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_id = other.m_id;
  m_members = std::move(other.m_members);
  m_name = std::move(other.m_name);
  m_pages = std::move(other.m_pages);
  m_oldid = other.m_oldid;
  m_oldmembers = std::move(other.m_oldmembers);
  m_oldname = std::move(other.m_oldname);
  m_oldpages = std::move(other.m_oldpages);
  m_isValid = other.m_isValid;
  return *this;
}

Troop::Member* Troop::member(const int index) {
  if (index < 0 || index >= m_members.size()) {
    return nullptr;
  }

  return &m_members[index];
}

const Troop::Member* Troop::member(const int index) const {
  if (index < 0 || index >= m_members.size()) {
    return nullptr;
  }

  return &m_members[index];
}

int Troop::id() const { return m_id; }
void Troop::setId(const int id) {
  if (m_id == id) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(id);
  m_id = id;
  if (!signalsDisabled()) {
    emit_signal(idModified(), this, id);
  }
  setModified();
}
std::vector<Troop::Member>& Troop::members() { return m_members; }
const std::vector<Troop::Member>& Troop::members() const { return m_members; }
void Troop::setMembers(const std::vector<Member>& value) {
  if (m_members == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(members);
  m_members = value;
  if (!signalsDisabled()) {
    emit_signal(membersModified(), this, value);
  }
  setModified();
}

const std::string& Troop::name() const { return m_name; }
void Troop::setName(const std::string& name) {
  if (m_name == name) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(name);
  m_name = name;
  if (!signalsDisabled()) {
    emit_signal(nameModified(), this, name);
  }
  setModified();
}

std::vector<Troop::Page>& Troop::pages() { return m_pages; }
const std::vector<Troop::Page>& Troop::pages() const { return m_pages; }
void Troop::setPages(const std::vector<Page>& value) {
  if (m_pages == value) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(pages);
  m_pages = value;
  if (!signalsDisabled()) {
    emit_signal(pagesModified(), this, value);
  }
  setModified();
}

void Troop::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(id);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(members);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(name);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(pages);
  std::ranges::for_each(m_members, [&](auto& member) { member.restoreOriginal(); });
  std::ranges::for_each(m_pages, [&](auto& page) { page.restoreOriginal(); });
}
void Troop::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(id);
  MODIFIABLE_ACCEPT_VALUE(members);
  MODIFIABLE_ACCEPT_VALUE(name);
  MODIFIABLE_ACCEPT_VALUE(pages);
  std::ranges::for_each(m_members, [&](auto& member) { member.acceptChanges(); });
  std::ranges::for_each(m_pages, [&](auto& page) { page.acceptChanges(); });
}

nlohmann::ordered_json Troop::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_VALUE(id),
      MODIFIABLE_SERIALIZE_VALUE_CHILD_ARRAY(members),
      MODIFIABLE_SERIALIZE_VALUE(name),
      MODIFIABLE_SERIALIZE_VALUE_CHILD_ARRAY(pages),
  };
}

rpgmutils::signal<void(Troop*, int)>& Troop::idModified() {
  if (!m_idModified) {
    m_idModified.emplace();
  }
  return *m_idModified;
}

rpgmutils::signal<void(Troop*, const std::vector<Troop::Member>&)>& Troop::membersModified() {
  if (!m_membersModified) {
    m_membersModified.emplace();
  }
  return *m_membersModified;
}

rpgmutils::signal<void(Troop*, const std::string&)>& Troop::nameModified() {
  if (!m_nameModified) {
    m_nameModified.emplace();
  }
  return *m_nameModified;
}

rpgmutils::signal<void(Troop*, const std::vector<Troop::Page>&)>& Troop::pagesModified() {
  if (!m_pagesModified) {
    m_pagesModified.emplace();
  }
  return *m_pagesModified;
}

void to_json(nlohmann::ordered_json& j, const Troop::Conditions& c) {
  j = {
      {"actorHp", c.m_actorHp},   {"actorId", c.m_actorId},         {"actorValid", c.m_actorValid}, {"enemyHp", c.m_enemyHp}, {"enemyIndex", c.m_enemyIndex}, {"enemyValid", c.m_enemyValid},
      {"switchId", c.m_switchId}, {"switchValid", c.m_switchValid}, {"turnA", c.m_turnA},           {"turnB", c.m_turnB},     {"turnEnding", c.m_turnEnding}, {"turnValid", c.m_turnValid},
  };
}
void from_json(const nlohmann::ordered_json& j, Troop::Conditions& c) {
  c.m_actorHp = j.value("actorHp", c.m_actorHp);
  c.m_actorId = j.value("actorId", c.m_actorId);
  c.m_actorValid = j.value("actorValid", c.m_actorValid);
  c.m_enemyHp = j.value("enemyHp", c.m_enemyHp);
  c.m_enemyIndex = j.value("enemyIndex", c.m_enemyIndex);
  c.m_enemyValid = j.value("enemyValid", c.m_enemyValid);
  c.m_switchId = j.value("switchId", c.m_switchId);
  c.m_switchValid = j.value("switchValid", c.m_switchValid);
  c.m_turnA = j.value("turnA", c.m_turnA);
  c.m_turnB = j.value("turnB", c.m_turnB);
  c.m_turnEnding = j.value("turnEnding", c.m_turnEnding);
  c.m_turnValid = j.value("turnValid", c.m_turnValid);
}

void to_json(nlohmann::ordered_json& j, const Troop::Page& p) {
  j["conditions"] = p.m_conditions;
  nlohmann::ordered_json list;
  CommandParser::serialize(list, p.m_list);
  j["list"] = list;
  j["span"] = p.m_span;
}

void from_json(const nlohmann::ordered_json& j, Troop::Page& p) {
  p.m_conditions = j.value("conditions", p.m_conditions);
  CommandParser cmdParser;
  p.m_list = cmdParser.parse(j["list"]);
  p.m_span = j.value("span", p.m_span);
}

void to_json(nlohmann::ordered_json& j, const Troop::Member& m) {
  j = {
      {"enemyId", m.m_enemyId},
      {"x", m.m_x},
      {"y", m.m_y},
      {"hidden", m.m_hidden},
  };
}

void from_json(const nlohmann::ordered_json& j, Troop::Member& m) {
  m.m_enemyId = j.value("enemyId", m.m_enemyId);
  m.m_x = j.value("x", m.m_x);
  m.m_y = j.value("y", m.m_y);
  m.m_hidden = j.value("hidden", m.m_hidden);
}

void to_json(nlohmann::ordered_json& j, const Troop& t) {
  j = {
      {"id", t.m_id},
      {"members", t.m_members},
      {"name", t.m_name},
      {"pages", t.m_pages},
  };
}

void from_json(const nlohmann::ordered_json& j, Troop& t) {
  t.m_id = j.value("id", t.m_id);
  t.m_members = j.value("members", t.m_members);
  t.m_name = j.value("name", t.m_name);
  t.m_pages = j.value("pages", t.m_pages);
}


code:
#pragma once
#include "Database/EventCommands/IEventCommand.hpp"

#include <nlohmann/json.hpp>

class Troop final : public IModifiable {
  friend void to_json(nlohmann::ordered_json& j, const Troop& t);
  friend void from_json(const nlohmann::ordered_json& j, Troop& t);
  friend class TroopsSerializer;

public:
  class Member final : public IModifiable {
    friend void to_json(nlohmann::ordered_json& j, const Member& m);
    friend void from_json(const nlohmann::ordered_json& j, Member& m);

  public:
    Member() = default;
    Member(const Member& other);
    Member& operator=(const Member& other);
    Member(Member&& other) noexcept;
    Member& operator=(Member&& other) noexcept;

    int enemyId() const;
    void setEnemyId(int value);

    int x() const;
    void setX(int value);

    int y() const;
    void setY(int value);

    bool hidden() const;
    void setHidden(bool value);

    void restoreOriginal() override;
    void acceptChanges() override;
    nlohmann::ordered_json serializeOldValues() const override;

    rpgmutils::signal<void(Member*, int)>& enemyIdModified();
    rpgmutils::signal<void(Member*, int)>& xModified();
    rpgmutils::signal<void(Member*, int)>& yModified();
    rpgmutils::signal<void(Member*, bool)>& hiddenModified();

    bool operator==(const Member& other) const { return m_enemyId == other.m_enemyId && m_x == other.m_x && m_y == other.m_y && m_hidden == other.m_hidden; }

  private:
    int m_enemyId = 0;
    int m_x = 0;
    int m_y = 0;
    bool m_hidden = false;

    std::optional<int> m_oldenemyId;
    std::optional<int> m_oldx;
    std::optional<int> m_oldy;
    std::optional<bool> m_oldhidden;

    std::optional<rpgmutils::signal<void(Member*, int)>> m_enemyIdModified;
    std::optional<rpgmutils::signal<void(Member*, int)>> m_xModified;
    std::optional<rpgmutils::signal<void(Member*, int)>> m_yModified;
    std::optional<rpgmutils::signal<void(Member*, bool)>> m_hiddenModified;
  };

  class Conditions final : public IModifiable {
    friend void to_json(nlohmann::ordered_json& j, const Conditions& c);
    friend void from_json(const nlohmann::ordered_json& j, Conditions& c);

  public:
    Conditions() = default;
    Conditions(const Conditions& other);
    Conditions& operator=(const Conditions& other);
    Conditions(Conditions&& other) noexcept;
    Conditions& operator=(Conditions&& other) noexcept;

    int actorHp() const;
    void setActorHp(int value);

    int actorId() const;
    void setActorId(int value);

    bool actorValid() const;
    void setActorValid(bool value);

    int enemyIndex() const;
    void setEnemyIndex(int value);

    int enemyHp() const;
    void setEnemyHp(int value);

    bool enemyValid() const;
    void setEnemyValid(bool value);

    int switchId() const;
    void setSwitchId(int value);

    bool switchValid() const;
    void setSwitchValid(bool value);

    int turnA() const;
    void setTurnA(int value);

    int turnB() const;
    void setTurnB(int value);

    bool turnEnding() const;
    void setTurnEnding(bool value);

    bool turnValid() const;
    void setTurnValid(bool value);

    void restoreOriginal() override;
    void acceptChanges() override;
    nlohmann::ordered_json serializeOldValues() const override;

    rpgmutils::signal<void(Conditions*, int)>& actorHpModified();
    rpgmutils::signal<void(Conditions*, int)>& actorIdModified();
    rpgmutils::signal<void(Conditions*, bool)>& actorValidModified();
    rpgmutils::signal<void(Conditions*, int)>& enemyIndexModified();
    rpgmutils::signal<void(Conditions*, int)>& enemyHpModified();
    rpgmutils::signal<void(Conditions*, bool)>& enemyValidModified();
    rpgmutils::signal<void(Conditions*, int)>& switchIdModified();
    rpgmutils::signal<void(Conditions*, bool)>& switchValidModified();
    rpgmutils::signal<void(Conditions*, int)>& turnAModified();
    rpgmutils::signal<void(Conditions*, int)>& turnBModified();
    rpgmutils::signal<void(Conditions*, bool)>& turnEndingModified();
    rpgmutils::signal<void(Conditions*, bool)>& turnValidModified();

    bool operator==(const Conditions& other) const {
      return m_actorHp == other.m_actorHp && m_actorId == other.m_actorId && m_enemyIndex == other.m_enemyIndex && m_enemyHp == other.m_enemyHp && m_enemyValid == other.m_enemyValid &&
             m_switchId == other.m_switchId && m_switchValid == other.m_switchValid && m_turnA == other.m_turnA && m_turnB == other.m_turnB && m_turnEnding == other.m_turnEnding;
    }

  private:
    int m_actorHp{50};
    int m_actorId{1};
    bool m_actorValid{false};
    int m_enemyIndex{0};
    int m_enemyHp{50};
    bool m_enemyValid{false};
    int m_switchId{1};
    bool m_switchValid{false};
    int m_turnA{0};
    int m_turnB{0};
    bool m_turnEnding{false};
    bool m_turnValid{false};

    std::optional<int> m_oldactorHp;
    std::optional<int> m_oldactorId;
    std::optional<bool> m_oldactorValid;
    std::optional<int> m_oldenemyIndex;
    std::optional<int> m_oldenemyHp;
    std::optional<bool> m_oldenemyValid;
    std::optional<int> m_oldswitchId;
    std::optional<bool> m_oldswitchValid;
    std::optional<int> m_oldturnA;
    std::optional<int> m_oldturnB;
    std::optional<bool> m_oldturnEnding;
    std::optional<bool> m_oldturnValid;

    std::optional<rpgmutils::signal<void(Conditions*, int)>> m_actorHpModified;
    std::optional<rpgmutils::signal<void(Conditions*, int)>> m_actorIdModified;
    std::optional<rpgmutils::signal<void(Conditions*, bool)>> m_actorValidModified;
    std::optional<rpgmutils::signal<void(Conditions*, int)>> m_enemyIndexModified;
    std::optional<rpgmutils::signal<void(Conditions*, int)>> m_enemyHpModified;
    std::optional<rpgmutils::signal<void(Conditions*, bool)>> m_enemyValidModified;
    std::optional<rpgmutils::signal<void(Conditions*, int)>> m_switchIdModified;
    std::optional<rpgmutils::signal<void(Conditions*, bool)>> m_switchValidModified;
    std::optional<rpgmutils::signal<void(Conditions*, int)>> m_turnAModified;
    std::optional<rpgmutils::signal<void(Conditions*, int)>> m_turnBModified;
    std::optional<rpgmutils::signal<void(Conditions*, bool)>> m_turnEndingModified;
    std::optional<rpgmutils::signal<void(Conditions*, bool)>> m_turnValidModified;
  };
  class Page final : public IModifiable {
    friend void to_json(nlohmann::ordered_json& j, const Page& p);
    friend void from_json(const nlohmann::ordered_json& j, Page& p);

  public:
    Page() = default;
    Page(const Page& other);
    Page& operator=(const Page& other);
    Page(Page&& other) noexcept;
    Page& operator=(Page&& other) noexcept;

    Conditions& conditions();
    const Conditions& conditions() const;
    void setConditions(const Conditions& value);

    std::vector<std::shared_ptr<IEventCommand>>& list();
    const std::vector<std::shared_ptr<IEventCommand>>& list() const;
    void setList(const std::vector<std::shared_ptr<IEventCommand>>& value);

    int span() const;
    void setSpan(int value);

    void restoreOriginal() override;
    void acceptChanges() override;
    nlohmann::ordered_json serializeOldValues() const override;

    bool isModified() const override {
      bool modified = IModifiable::isModified();
      modified |= m_conditions.isModified();
      modified |= std::ranges::any_of(m_list, [](const std::shared_ptr<IEventCommand>& command) { return command->isModified(); });
      return modified;
    }
    rpgmutils::signal<void(Page*, const Conditions&)>& conditionsModified();
    rpgmutils::signal<void(Page*, const std::vector<std::shared_ptr<IEventCommand>>&)>& listModified();
    rpgmutils::signal<void(Page*, int)>& spanModified();

    bool operator==(const Page& other) const { return m_conditions == m_conditions && m_list == other.m_list && m_span == other.m_span; }

  private:
    Conditions m_conditions;
    std::vector<std::shared_ptr<IEventCommand>> m_list;
    int m_span;

    std::optional<Conditions> m_oldconditions;
    std::optional<std::vector<std::shared_ptr<IEventCommand>>> m_oldlist;
    std::optional<int> m_oldspan;

    std::optional<rpgmutils::signal<void(Page*, const Conditions&)>> m_conditionsModified;
    std::optional<rpgmutils::signal<void(Page*, const std::vector<std::shared_ptr<IEventCommand>>&)>> m_listModified;
    std::optional<rpgmutils::signal<void(Page*, int)>> m_spanModified;
  };

  Troop() = default;
  Troop(const Troop& other);
  Troop& operator=(const Troop& other);
  Troop(Troop&& other) noexcept;
  Troop& operator=(Troop&& other) noexcept;

  Member* member(int index);
  const Member* member(int index) const;

  int id() const;
  void setId(int id);

  std::vector<Member>& members();
  const std::vector<Member>& members() const;
  void setMembers(const std::vector<Member>& value);

  const std::string& name() const;
  void setName(const std::string& name);

  std::vector<Page>& pages();
  const std::vector<Page>& pages() const;
  void setPages(const std::vector<Page>& value);
  void restoreOriginal() override;
  void acceptChanges() override;
  nlohmann::ordered_json serializeOldValues() const override;

  bool isModified() const override {
    bool modified = IModifiable::isModified();
    modified |= std::ranges::any_of(m_members, [](const auto& member) { return member.isModified(); });
    modified |= std::ranges::any_of(m_pages, [](const auto& page) { return page.isModified(); });
    return modified;
  }

  rpgmutils::signal<void(Troop*, int)>& idModified();
  rpgmutils::signal<void(Troop*, const std::vector<Member>&)>& membersModified();
  rpgmutils::signal<void(Troop*, const std::string&)>& nameModified();
  rpgmutils::signal<void(Troop*, const std::vector<Page>&)>& pagesModified();

  bool isValid() const { return m_isValid; }
  void setValid(bool valid) { m_isValid = valid; }

private:
  int m_id;
  std::vector<Member> m_members;
  std::string m_name;
  std::vector<Page> m_pages;

  std::optional<int> m_oldid;
  std::optional<std::vector<Member>> m_oldmembers;
  std::optional<std::string> m_oldname;
  std::optional<std::vector<Page>> m_oldpages;

  std::optional<rpgmutils::signal<void(Troop*, int)>> m_idModified;
  std::optional<rpgmutils::signal<void(Troop*, const std::vector<Member>&)>> m_membersModified;
  std::optional<rpgmutils::signal<void(Troop*, const std::string&)>> m_nameModified;
  std::optional<rpgmutils::signal<void(Troop*, const std::vector<Page>&)>> m_pagesModified;

  /*!
   * @name m_isValid
   * @details
   * Indicates that this is an actual valid entry and not a dummy
   * When making a new entry make sure to set this to true or it won't be
   * serialized.
   */
  bool m_isValid{false};
};
void to_json(nlohmann::ordered_json& j, const Troop::Conditions& c);
void from_json(const nlohmann::ordered_json& j, Troop::Conditions& c);
void to_json(nlohmann::ordered_json& j, const Troop::Page& p);
void from_json(nlohmann::ordered_json& j, Troop::Page& p);
void to_json(nlohmann::ordered_json& j, const Troop::Member& m);
void from_json(const nlohmann::ordered_json& j, Troop::Member& m);
void to_json(nlohmann::ordered_json& j, const Troop& t);
void from_json(const nlohmann::ordered_json& j, Troop& t);


code: #include "Database/Troops.hpp"


code:
#pragma once

#include "Database/Troop.hpp"

#include "nlohmann/json.hpp"

class Troops final : public IModifiable {
public:
  static Troops load(std::string_view filepath);

  bool serialize(std::string_view filename);

  [[nodiscard]] Troop* troop(int id) {
    for (auto& troop : m_troops) {
      if (troop.id() == id && troop.isValid()) {
        return &troop;
      }
    }
    return nullptr;
  }

  [[nodiscard]] const Troop* troop(int id) const {
    for (const auto& troop : m_troops) {
      if (troop.id() == id && troop.isValid()) {
        return &troop;
      }
    }

    return nullptr;
  }
  std::vector<Troop>& troops() { return m_troops; }
  const std::vector<Troop>& troops() const { return m_troops; }
  int count() const { return m_troops.size() - 1; }

  void resize(int newSize) {
    ++newSize;
    const int oldSize = m_troops.size();
    m_troops.resize(newSize);
    if (newSize > oldSize) {
      for (int i = oldSize; i < m_troops.size(); ++i) {
        m_troops[i].setId(i);
      }
    }
    setModified(true);
  }

  bool isModified() const override {
    return IModifiable::isModified() | std::ranges::any_of(m_troops, [](const auto& troop) { return troop.isModified(); });
  }

private:
  std::vector<Troop> m_troops;
};


code:
#include "Database/Vehicle.hpp"

Vehicle::Vehicle(const Vehicle& other)
: IModifiable(other)
, m_bgm(other.m_bgm)
, m_characterIndex(other.m_characterIndex)
, m_characterName(other.m_characterName)
, m_startMapId(other.m_startMapId)
, m_startX(other.m_startX)
, m_startY(other.m_startY)
, m_oldbgm(other.m_oldbgm)
, m_oldcharacterIndex(other.m_oldcharacterIndex)
, m_oldcharacterName(other.m_oldcharacterName)
, m_oldstartMapId(other.m_oldstartMapId)
, m_oldstartX(other.m_oldstartX)
, m_oldstartY(other.m_oldstartY) {}

Vehicle& Vehicle::operator=(const Vehicle& other) {
  IModifiable::operator=(other);
  m_bgm = other.m_bgm;
  m_characterIndex = other.m_characterIndex;
  m_characterName = other.m_characterName;
  m_startMapId = other.m_startMapId;
  m_startX = other.m_startX;
  m_startY = other.m_startY;
  m_oldbgm = other.m_oldbgm;
  m_oldcharacterIndex = other.m_oldcharacterIndex;
  m_oldcharacterName = other.m_oldcharacterName;
  m_oldstartMapId = other.m_oldstartMapId;
  m_oldstartX = other.m_oldstartX;
  m_oldstartY = other.m_oldstartY;
  return *this;
}

Vehicle::Vehicle(Vehicle&& other) noexcept
: IModifiable(std::move(other))
, m_bgm(std::move(other.m_bgm))
, m_characterIndex(other.m_characterIndex)
, m_characterName(std::move(other.m_characterName))
, m_startMapId(other.m_startMapId)
, m_startX(other.m_startX)
, m_startY(other.m_startY)
, m_oldbgm(std::move(other.m_oldbgm))
, m_oldcharacterIndex(other.m_oldcharacterIndex)
, m_oldcharacterName(std::move(other.m_oldcharacterName))
, m_oldstartMapId(other.m_oldstartMapId)
, m_oldstartX(other.m_oldstartX)
, m_oldstartY(other.m_oldstartY) {}

Vehicle& Vehicle::operator=(Vehicle&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_bgm = std::move(other.m_bgm);
  m_characterIndex = other.m_characterIndex;
  m_characterName = std::move(other.m_characterName);
  m_startMapId = other.m_startMapId;
  m_startX = other.m_startX;
  m_startY = other.m_startY;
  m_oldbgm = std::move(other.m_oldbgm);
  m_oldcharacterIndex = other.m_oldcharacterIndex;
  m_oldcharacterName = std::move(other.m_oldcharacterName);
  m_oldstartMapId = other.m_oldstartMapId;
  m_oldstartX = other.m_oldstartX;
  m_oldstartY = other.m_oldstartY;
  return *this;
}

Audio& Vehicle::bgm() { return m_bgm; }
const Audio& Vehicle::bgm() const { return m_bgm; }
void Vehicle::setBgm(const Audio& bgm) {
  if (m_bgm == bgm) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(bgm);
  m_bgm = bgm;
  if (!signalsDisabled()) {
  emit_signal(bgmModified(), this, bgm);
  }
  setModified();
}

int Vehicle::characterIndex() const { return m_characterIndex; }
void Vehicle::setCharacterIndex(int characterIndex) {
  if (m_characterIndex == characterIndex) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(characterIndex);
  m_characterIndex = characterIndex;
  if (!signalsDisabled()) {
  emit_signal(characterIndexModified(), this, characterIndex);
  }
  setModified();
}

const std::string& Vehicle::characterName() const { return m_characterName; }
void Vehicle::setCharacterName(const std::string& characterName) {
  if (m_characterName == characterName) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(characterName);
  m_characterName = characterName;
  if (!signalsDisabled()) {
  emit_signal(characterNameModified(), this, characterName);
  }
  setModified();
}

int Vehicle::startMapId() const { return m_startMapId; }
void Vehicle::setStartMapId(int startMapId) {
  if (m_startMapId == startMapId) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(startMapId);
  m_startMapId = startMapId;
  if (!signalsDisabled()) {
  emit_signal(startMapIdModified(), this, startMapId);
  }
  setModified();
}

int Vehicle::startX() const { return m_startX; }
void Vehicle::setStartX(int startX) {
  if (m_startX == startX) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(startX);
  m_startX = startX;
  if (!signalsDisabled()) {
  emit_signal(startXModified(), this, startX);
  }
  setModified();
}

int Vehicle::startY() const { return m_startY; }
void Vehicle::setStartY(int startY) {
  if (m_startY == startY) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(startY);
  m_startY = startY;
  if (!signalsDisabled()) {
  emit_signal(startYModified(), this, startY);
  }
  setModified();
}

void Vehicle::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(bgm);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(characterIndex);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(characterName);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(startMapId);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(startX);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(startY);
  m_bgm.restoreOriginal();
}

void Vehicle::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(bgm);
  MODIFIABLE_ACCEPT_VALUE(characterIndex);
  MODIFIABLE_ACCEPT_VALUE(characterName);
  MODIFIABLE_ACCEPT_VALUE(startMapId);
  MODIFIABLE_ACCEPT_VALUE(startX);
  MODIFIABLE_ACCEPT_VALUE(startY);
  m_bgm.acceptChanges();
}
nlohmann::ordered_json Vehicle::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_CHILD_VALUE(bgm),  MODIFIABLE_SERIALIZE_VALUE(characterIndex), MODIFIABLE_SERIALIZE_VALUE(characterName),
      MODIFIABLE_SERIALIZE_VALUE(startMapId), MODIFIABLE_SERIALIZE_VALUE(startX),         MODIFIABLE_SERIALIZE_VALUE(startY),
  };
}

rpgmutils::signal<void(Vehicle*, const Audio&)>& Vehicle::bgmModified() {
  if (!m_bgmModified) {
    m_bgmModified.emplace();
  }
  return *m_bgmModified;
}
rpgmutils::signal<void(Vehicle*, int)>& Vehicle::characterIndexModified() {
  if (!m_characterIndexModified) {
    m_characterIndexModified.emplace();
  }
  return *m_characterIndexModified;
}
rpgmutils::signal<void(Vehicle*, const std::string&)>& Vehicle::characterNameModified() {
  if (!m_characterNameModified) {
    m_characterNameModified.emplace();
  }
  return *m_characterNameModified;
}
rpgmutils::signal<void(Vehicle*, int)>& Vehicle::startMapIdModified() {
  if (!m_startMapIdModified) {
    m_startMapIdModified.emplace();
  }
  return *m_startMapIdModified;
}
rpgmutils::signal<void(Vehicle*, int)>& Vehicle::startXModified() {
  if (!m_startXModified) {
    m_startXModified.emplace();
  }
  return *m_startXModified;
}
rpgmutils::signal<void(Vehicle*, int)>& Vehicle::startYModified() {
  if (!m_startYModified) {
    m_startYModified.emplace();
  }
  return *m_startYModified;
}

void to_json(nlohmann::ordered_json& j, const Vehicle& v) {
  j = {
      {"bgm", v.m_bgm}, {"characterIndex", v.m_characterIndex}, {"characterName", v.m_characterName}, {"startMapId", v.m_startMapId}, {"startX", v.m_startX}, {"startY", v.m_startY},
  };
}
void from_json(const nlohmann::ordered_json& j, Vehicle& v) {
  v.m_bgm = j.value("bgm", v.m_bgm);
  v.m_characterIndex = j.value("characterIndex", v.m_characterIndex);
  v.m_characterName = j.value("characterName", v.m_characterName);
  v.m_startMapId = j.value("startMapId", v.m_startMapId);
  v.m_startX = j.value("startX", v.m_startX);
  v.m_startY = j.value("startY", v.m_startY);
}


code:
#pragma once

#include "Database/Audio.hpp"

#include <nlohmann/json.hpp>

class Vehicle final : public IModifiable {
  friend void to_json(nlohmann::ordered_json& j, const Vehicle& v);
  friend void from_json(const nlohmann::ordered_json& j, Vehicle& v);

public:
  Vehicle() = default;
  Vehicle(const Vehicle& other);
  Vehicle& operator=(const Vehicle& other);
  Vehicle(Vehicle&& other) noexcept;
  Vehicle& operator=(Vehicle&& other) noexcept;

  Audio& bgm();
  const Audio& bgm() const;
  void setBgm(const Audio& bgm);

  int characterIndex() const;
  void setCharacterIndex(int characterIndex);

  const std::string& characterName() const;
  void setCharacterName(const std::string& characterName);

  int startMapId() const;
  void setStartMapId(int startMapId);

  int startX() const;
  void setStartX(int startX);

  int startY() const;
  void setStartY(int startY);

  void restoreOriginal() override;
  void acceptChanges() override;
  nlohmann::ordered_json serializeOldValues() const override;

  rpgmutils::signal<void(Vehicle*, const Audio&)>& bgmModified();
  rpgmutils::signal<void(Vehicle*, int)>& characterIndexModified();
  rpgmutils::signal<void(Vehicle*, const std::string&)>& characterNameModified();
  rpgmutils::signal<void(Vehicle*, int)>& startMapIdModified();
  rpgmutils::signal<void(Vehicle*, int)>& startXModified();
  rpgmutils::signal<void(Vehicle*, int)>& startYModified();

  bool operator==(const Vehicle& v) const {
    return m_bgm == v.m_bgm && m_characterIndex == v.m_characterIndex && m_characterName == v.m_characterName && m_startMapId == v.m_startMapId && m_startX == v.m_startX && m_startY == v.m_startY;
  }

private:
  Audio m_bgm;
  int m_characterIndex;
  std::string m_characterName;
  int m_startMapId;
  int m_startX;
  int m_startY;

  std::optional<Audio> m_oldbgm;
  std::optional<int> m_oldcharacterIndex;
  std::optional<std::string> m_oldcharacterName;
  std::optional<int> m_oldstartMapId;
  std::optional<int> m_oldstartX;
  std::optional<int> m_oldstartY;

  std::optional<rpgmutils::signal<void(Vehicle*, const Audio&)>> m_bgmModified;
  std::optional<rpgmutils::signal<void(Vehicle*, int)>> m_characterIndexModified;
  std::optional<rpgmutils::signal<void(Vehicle*, const std::string&)>> m_characterNameModified;
  std::optional<rpgmutils::signal<void(Vehicle*, int)>> m_startMapIdModified;
  std::optional<rpgmutils::signal<void(Vehicle*, int)>> m_startXModified;
  std::optional<rpgmutils::signal<void(Vehicle*, int)>> m_startYModified;
};
void to_json(nlohmann::ordered_json& j, const Vehicle& v);
void from_json(const nlohmann::ordered_json& j, Vehicle& v);


code:
#pragma once

#include <array>
#include <string_view>

using namespace std::string_view_literals;
// clang-format off
static constexpr std::array KnownRPGMVVersions = {
  "RPGMV 1.0.0"sv,
  "RPGMV 1.6.1"sv,
  "RPGMV 1.6.2"sv,
  "RPGMV 1.6.3"sv,
};

static constexpr std::array KnownRPGMZVersions = {
  "RPGMZ 1.0.0"sv,
  "RPGMZ 1.0.2"sv,
  "RPGMZ 1.1.0"sv,
  "RPGMZ 1.1.1"sv,
  "RPGMZ 1.2.0"sv,
  "RPGMZ 1.2.1"sv,
  "RPGMZ 1.3.0"sv,
  "RPGMZ 1.3.1"sv,
  "RPGMZ 1.3.2"sv,
  "RPGMZ 1.4.0"sv,
  "RPGMZ 1.4.3"sv,
  "RPGMZ 1.4.4"sv,
  "RPGMZ 1.5.0"sv,
  "RPGMZ 1.6.0"sv,
  "RPGMZ 1.7.0"sv,
  "RPGMZ 1.8.0"sv,
  "RPGMZ 1.8.1"sv,
  "RPGMZ 1.9.0"sv,
};

// clang-format on


code:
#include "Database/Weapon.hpp"

Weapon::Weapon(const Weapon& other)
: IModifiable(other)
, m_id(other.m_id)
, m_animationId(other.m_animationId)
, m_description(other.m_description)
, m_etypeId(other.m_etypeId)
, m_traits(other.m_traits)
, m_iconIndex(other.m_iconIndex)
, m_name(other.m_name)
, m_note(other.m_note)
, m_params(other.m_params)
, m_price(other.m_price)
, m_wtypeId(other.m_wtypeId)
, m_oldid(other.m_oldid)
, m_oldanimationId(other.m_oldanimationId)
, m_olddescription(other.m_olddescription)
, m_oldetypeId(other.m_oldetypeId)
, m_oldtraits(other.m_oldtraits)
, m_oldiconIndex(other.m_oldiconIndex)
, m_oldname(other.m_oldname)
, m_oldnote(other.m_oldnote)
, m_oldparams(other.m_oldparams)
, m_oldprice(other.m_oldprice)
, m_oldwtypeId(other.m_oldwtypeId)
, m_isValid(other.m_isValid) {}

Weapon& Weapon::operator=(const Weapon& other) {
  IModifiable::operator=(other);
  m_id = other.m_id;
  m_animationId = other.m_animationId;
  m_description = other.m_description;
  m_etypeId = other.m_etypeId;
  m_traits = other.m_traits;
  m_iconIndex = other.m_iconIndex;
  m_name = other.m_name;
  m_note = other.m_note;
  m_params = other.m_params;
  m_price = other.m_price;
  m_wtypeId = other.m_wtypeId;
  m_oldid = other.m_oldid;
  m_oldanimationId = other.m_oldanimationId;
  m_olddescription = other.m_olddescription;
  m_oldetypeId = other.m_oldetypeId;
  m_oldtraits = other.m_oldtraits;
  m_oldiconIndex = other.m_oldiconIndex;
  m_oldname = other.m_oldname;
  m_oldnote = other.m_oldnote;
  m_oldparams = other.m_oldparams;
  m_oldprice = other.m_oldprice;
  m_oldwtypeId = other.m_oldwtypeId;
  m_isValid = other.m_isValid;
  return *this;
}

Weapon::Weapon(Weapon&& other) noexcept
: IModifiable(std::move(other))
, m_id(other.m_id)
, m_animationId(other.m_animationId)
, m_description(std::move(other.m_description))
, m_etypeId(other.m_etypeId)
, m_traits(std::move(other.m_traits))
, m_iconIndex(other.m_iconIndex)
, m_name(std::move(other.m_name))
, m_note(std::move(other.m_note))
, m_params(std::move(other.m_params))
, m_price(other.m_price)
, m_wtypeId(other.m_wtypeId)
, m_oldid(other.m_oldid)
, m_oldanimationId(other.m_oldanimationId)
, m_olddescription(std::move(other.m_olddescription))
, m_oldetypeId(other.m_oldetypeId)
, m_oldtraits(std::move(other.m_oldtraits))
, m_oldiconIndex(other.m_oldiconIndex)
, m_oldname(std::move(other.m_oldname))
, m_oldnote(std::move(other.m_oldnote))
, m_oldparams(std::move(other.m_oldparams))
, m_oldprice(other.m_oldprice)
, m_oldwtypeId(other.m_oldwtypeId)
, m_isValid(other.m_isValid) {}

Weapon& Weapon::operator=(Weapon&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_id = other.m_id;
  m_animationId = other.m_animationId;
  m_description = std::move(other.m_description);
  m_etypeId = other.m_etypeId;
  m_traits = std::move(other.m_traits);
  m_iconIndex = other.m_iconIndex;
  m_name = std::move(other.m_name);
  m_note = std::move(other.m_note);
  m_params = std::move(other.m_params);
  m_price = other.m_price;
  m_wtypeId = other.m_wtypeId;
  m_oldid = other.m_oldid;
  m_oldanimationId = other.m_oldanimationId;
  m_olddescription = std::move(other.m_olddescription);
  m_oldetypeId = other.m_oldetypeId;
  m_oldtraits = std::move(other.m_oldtraits);
  m_oldiconIndex = other.m_oldiconIndex;
  m_oldname = std::move(other.m_oldname);
  m_oldnote = std::move(other.m_oldnote);
  m_oldparams = std::move(other.m_oldparams);
  m_oldprice = other.m_oldprice;
  m_oldwtypeId = other.m_oldwtypeId;
  m_isValid = other.m_isValid;
  return *this;
}

[[nodiscard]] int Weapon::id() const { return m_id; }
void Weapon::setId(const int id) {
  if (m_id == id) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(id);
  m_id = id;
  if (!signalsDisabled()) {
    emit_signal(idModified(), this, id);
  }
  setModified();
}

[[nodiscard]] int Weapon::animationId() const { return m_animationId; }
void Weapon::setAnimationId(const int animationId) {
  if (m_animationId == animationId) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(animationId);
  m_animationId = animationId;
  if (!signalsDisabled()) {
    emit_signal(animationIdModified(), this, animationId);
  }
  setModified();
}

[[nodiscard]] const std::string& Weapon::description() const { return m_description; }
void Weapon::setDescription(const std::string& description) {
  if (m_description == description) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(description);
  m_description = description;
  if (!signalsDisabled()) {
  emit_signal(descriptionModified(), this, description);
  }
  setModified();
}

[[nodiscard]] int Weapon::etypeId() const { return m_etypeId; }
void Weapon::setEtypeId(const int etypeId) {
  if (m_etypeId == etypeId) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(etypeId);
  m_etypeId = etypeId;
  if (!signalsDisabled()) {
  emit_signal(etypeIdModified(), this, etypeId);
  }
  setModified();
}

[[nodiscard]] std::vector<Trait>& Weapon::traits() { return m_traits; }
void Weapon::setTraits(const std::vector<Trait>& traits) {
  if (m_traits == traits) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(traits);
  m_traits = traits;
  if (!signalsDisabled()) {
  emit_signal(traitsModified(), this, m_traits);
  }
  setModified();
}

[[nodiscard]] int Weapon::iconIndex() const { return m_iconIndex; }
void Weapon::setIconIndex(const int iconIndex) {
  if (m_iconIndex == iconIndex) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(iconIndex);
  m_iconIndex = iconIndex;
  if (!signalsDisabled()) {
  emit_signal(iconIndexModified(), this, m_iconIndex);
  }
  setModified();
}

[[nodiscard]] const std::string& Weapon::name() const { return m_name; }
void Weapon::setName(const std::string& name) {
  if (m_name == name) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(name);
  m_name = name;
  if (!signalsDisabled()) {
  emit_signal(nameModified(), this, m_name);
  }
  setModified();
}

[[nodiscard]] const std::string& Weapon::note() const { return m_note; }
void Weapon::setNote(const std::string& note) {
  if (m_note == note) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(note);
  m_note = note;
  if (!signalsDisabled()) {
  emit_signal(noteModified(), this, m_note);
  }
  setModified();
}

std::array<int, 8>& Weapon::params() { return m_params; }
void Weapon::setParams(const std::array<int, 8>& params) {
  if (m_params == params) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(params);
  m_params = params;
  if (!signalsDisabled()) {
  emit_signal(paramsModified(), this, m_params);
  }
  setModified();
}
[[nodiscard]] int Weapon::param(const int idx) const {
  assert(idx >= 0 && idx < m_params.size());
  return m_params[idx];
}
void Weapon::setParam(const int idx, const int param) {
  assert(param >= 0 && param < m_params.size());
  if (m_params[idx] == param) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(params);
  m_params[idx] = param;
  if (!signalsDisabled()) {
  emit_signal(paramsModified(), this, m_params);
  }
  setModified();
}

[[nodiscard]] int Weapon::price() const { return m_price; }
void Weapon::setPrice(const int price) {
  if (m_price == price) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(price);
  m_price = price;
  if (!signalsDisabled()) {
  emit_signal(priceModified(), this, m_price);
  }
  setModified();
}

[[nodiscard]] int Weapon::wtypeId() const { return m_wtypeId; }
void Weapon::setWtypeId(const int wtypeId) {
  if (m_wtypeId == wtypeId) {
    return;
  }
  MODIFIABLE_SET_OLD_VALUE(wtypeId);
  m_wtypeId = wtypeId;
  if (!signalsDisabled()) {
  emit_signal(wtypeIdModified(), this, m_wtypeId);
  }
  setModified();
}

void Weapon::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(id);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(animationId);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(description);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(etypeId);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(traits);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(iconIndex);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(name);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(note);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(params);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(price);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(wtypeId);
  std::ranges::for_each(m_traits, [](Trait& trait) { trait.restoreOriginal(); });
}
void Weapon::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(id);
  MODIFIABLE_ACCEPT_VALUE(animationId);
  MODIFIABLE_ACCEPT_VALUE(description);
  MODIFIABLE_ACCEPT_VALUE(etypeId);
  MODIFIABLE_ACCEPT_VALUE(traits);
  MODIFIABLE_ACCEPT_VALUE(iconIndex);
  MODIFIABLE_ACCEPT_VALUE(name);
  MODIFIABLE_ACCEPT_VALUE(note);
  MODIFIABLE_ACCEPT_VALUE(params);
  MODIFIABLE_ACCEPT_VALUE(price);
  MODIFIABLE_ACCEPT_VALUE(wtypeId);
  std::ranges::for_each(m_traits, [](Trait& trait) { trait.acceptChanges(); });
}
nlohmann::ordered_json Weapon::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_VALUE(id),     MODIFIABLE_SERIALIZE_VALUE(animationId), MODIFIABLE_SERIALIZE_VALUE(description), MODIFIABLE_SERIALIZE_VALUE(etypeId),
      MODIFIABLE_SERIALIZE_VALUE(traits), MODIFIABLE_SERIALIZE_VALUE(iconIndex),   MODIFIABLE_SERIALIZE_VALUE(name),        MODIFIABLE_SERIALIZE_VALUE(note),
      MODIFIABLE_SERIALIZE_VALUE(params), MODIFIABLE_SERIALIZE_VALUE(price),       MODIFIABLE_SERIALIZE_VALUE(wtypeId),
  };
}

rpgmutils::signal<void(Weapon*, int)>& Weapon::idModified() {
  if (!m_idModified) {
    m_idModified.emplace();
  }
  return *m_idModified;
}
rpgmutils::signal<void(Weapon*, int)>& Weapon::animationIdModified() {
  if (!m_animationIdModified) {
    m_animationIdModified.emplace();
  }
  return *m_animationIdModified;
}
rpgmutils::signal<void(Weapon*, const std::string&)>& Weapon::descriptionModified() {
  if (!m_descriptionModified) {
    m_descriptionModified.emplace();
  }
  return *m_descriptionModified;
}
rpgmutils::signal<void(Weapon*, int)>& Weapon::etypeIdModified() {
  if (!m_etypeIdModified) {
    m_etypeIdModified.emplace();
  }
  return *m_etypeIdModified;
}
rpgmutils::signal<void(Weapon*, const std::vector<Trait>&)>& Weapon::traitsModified() {
  if (!m_traitsModified) {
    m_traitsModified.emplace();
  }
  return *m_traitsModified;
}
rpgmutils::signal<void(Weapon*, int)>& Weapon::iconIndexModified() {
  if (!m_iconIndexModified) {
    m_iconIndexModified.emplace();
  }
  return *m_iconIndexModified;
}
rpgmutils::signal<void(Weapon*, const std::string&)>& Weapon::nameModified() {
  if (!m_nameModified) {
    m_nameModified.emplace();
  }
  return *m_nameModified;
}
rpgmutils::signal<void(Weapon*, const std::string&)>& Weapon::noteModified() {
  if (!m_noteModified) {
    m_noteModified.emplace();
  }
  return *m_noteModified;
}
rpgmutils::signal<void(Weapon*, const std::array<int, 8>&)>& Weapon::paramsModified() {
  if (!m_paramsModified) {
    m_paramsModified.emplace();
  }
  return *m_paramsModified;
}
rpgmutils::signal<void(Weapon*, int)>& Weapon::priceModified() {
  if (!m_priceModified) {
    m_priceModified.emplace();
  }
  return *m_priceModified;
}
rpgmutils::signal<void(Weapon*, int)>& Weapon::wtypeIdModified() {
  if (!m_wtypeIdModified) {
    m_wtypeIdModified.emplace();
  }
  return *m_wtypeIdModified;
}

void to_json(nlohmann::ordered_json& j, const Weapon& w) {
  j = {
      {"id", w.m_id},
      {"animationId", w.m_animationId},
      {"description", w.m_description},
      {"etypeId", w.m_etypeId},
      {"traits", w.m_traits},
      {"iconIndex", w.m_iconIndex},
      {"name", w.m_name},
      {"note", w.m_note},
      {"params", w.m_params},
      {"price", w.m_price},
      {"wtypeId", w.m_wtypeId},
  };
}

void from_json(const nlohmann::ordered_json& j, Weapon& w) {
  w.m_id = j.value("id", w.m_id);
  w.m_animationId = j.value("animationId", w.m_animationId);
  w.m_description = j.value("description", w.m_description);
  w.m_etypeId = j.value("etypeId", w.m_etypeId);
  w.m_traits = j.value("traits", w.m_traits);
  w.m_iconIndex = j.value("iconIndex", w.m_iconIndex);
  w.m_name = j.value("name", w.m_name);
  w.m_note = j.value("note", w.m_note);
  w.m_params = j.value("params", w.m_params);
  w.m_price = j.value("price", w.m_price);
  w.m_wtypeId = j.value("wtypeId", w.m_wtypeId);
}