code:
# include(${PROJECT_SOURCE_DIR}/cmake/StaticAnalyzers.cmake)

add_library(
        librpgm STATIC
        # RPGMV Classes
        Database/Actor.cpp
        Database/Actor.hpp
        Database/Actors.cpp
        Database/Actors.hpp
        Database/Animation.cpp
        Database/Animation.hpp
        Database/Animations.cpp
        Database/Animations.hpp
        Database/Armor.cpp
        Database/Armor.hpp
        Database/Armors.cpp
        Database/Armors.hpp
        Database/Audio.cpp
        Database/Audio.hpp
        Database/Battler.cpp
        Database/Battler.hpp
        Database/Class.cpp
        Database/Class.hpp
        Database/Classes.cpp
        Database/Classes.hpp
        Database/ColorFormatter.cpp
        Database/ColorFormatter.hpp
        Database/CommonEvent.cpp
        Database/CommonEvent.hpp
        Database/CommonEvents.cpp
        Database/CommonEvents.hpp
        Database/Damage.cpp
        Database/Database.cpp
        Database/Database.hpp
        Database/Effect.cpp
        Database/Enemies.cpp
        Database/Enemies.hpp
        Database/Enemy.cpp
        Database/Enemy.hpp
        Database/Event.cpp
        Database/Event.hpp
        Database/EventPage.cpp
        Database/EventPage.hpp
        Database/EventParser.cpp
        Database/EventParser.hpp
        Database/GameConstants.cpp
        Database/GameConstants.hpp
        Database/Globals.cpp
        Database/Globals.hpp
        Database/IModifiable.cpp
        Database/IModifiable.hpp
        Database/Item.cpp
        Database/Item.hpp
        Database/Items.cpp
        Database/Items.hpp
        Database/Log.cpp
        Database/Log.hpp
        Database/Map.cpp
        Database/Map.hpp
        Database/MapInfo.cpp
        Database/MapInfo.hpp
        Database/MapInfos.cpp
        Database/MapInfos.hpp
        Database/Messages.cpp
        Database/Messages.hpp
        Database/MovementRoute.cpp
        Database/MovementRoute.hpp
        Database/Plugins.cpp
        Database/Plugins.hpp
        Database/RPGEquations.cpp
        Database/RPGEquations.hpp
        Database/Serializable/ActorsSerializer.cpp
        Database/Serializable/ActorsSerializer.hpp
        Database/Serializable/AnimationsSerializer.cpp
        Database/Serializable/AnimationsSerializer.hpp
        Database/Serializable/ArmorsSerializer.cpp
        Database/Serializable/ArmorsSerializer.hpp
        Database/Serializable/ClassesSerializer.cpp
        Database/Serializable/ClassesSerializer.hpp
        Database/Serializable/CommonEventsSerializer.cpp
        Database/Serializable/CommonEventsSerializer.hpp
        Database/Serializable/EnemiesSerializer.cpp
        Database/Serializable/EnemiesSerializer.hpp
        Database/Serializable/ISerializable.hpp
        Database/Serializable/ItemsSerializer.cpp
        Database/Serializable/ItemsSerializer.hpp
        Database/Serializable/MapSerializer.cpp
        Database/Serializable/MapSerializer.hpp
        Database/Serializable/SkillsSerializer.cpp
        Database/Serializable/SkillsSerializer.hpp
        Database/Serializable/StatesSerializer.cpp
        Database/Serializable/StatesSerializer.hpp
        Database/Serializable/SystemSerializer.cpp
        Database/Serializable/SystemSerializer.hpp
        Database/Serializable/Task.hpp
        Database/Serializable/FileQueue.cpp
        Database/Serializable/FileQueue.hpp
        Database/Serializable/TilesetsSerializer.cpp
        Database/Serializable/TilesetsSerializer.hpp
        Database/Serializable/TroopsSerializer.cpp
        Database/Serializable/TroopsSerializer.hpp
        Database/Serializable/WeaponsSerializer.cpp
        Database/Serializable/WeaponsSerializer.hpp
        Database/Serializable/MapInfosSerializer.cpp
        Database/Serializable/MapInfosSerializer.hpp
        Database/Skill.cpp
        Database/Skill.hpp
        Database/Skills.cpp
        Database/Skills.hpp
        Database/State.cpp
        Database/State.hpp
        Database/States.cpp
        Database/States.hpp
        Database/System.cpp
        Database/System.hpp
        Database/Template.cpp
        Database/Template.hpp
        Database/Templates.cpp
        Database/Templates.hpp
        Database/Terms.cpp
        Database/Terms.hpp
        Database/TileHelper.cpp
        Database/TileHelper.hpp
        Database/Tileset.cpp
        Database/Tileset.hpp
        Database/Tilesets.cpp
        Database/Tilesets.hpp
        # Database/Trait.cpp
        Database/Trait.cpp
        Database/Trait.hpp
        Database/Troop.cpp
        Database/Troop.hpp
        Database/Troops.cpp
        Database/Troops.hpp
        Database/Vehicle.cpp
        Database/Vehicle.hpp
        Database/Versions.hpp
        Database/Weapon.cpp
        Database/Weapon.hpp
        Database/Weapons.cpp
        Database/Weapons.hpp
        Utils/SignalSlot.hpp
        Database/IEventEditor.hpp
        Database/IPageEditor.hpp
        Database/IEventEditor.cpp
        Utils/JavaMath.cpp
        Utils/JavaMath.hpp
        Database/Docs.cpp
        Database/Docs.hpp
        Database/Doc.cpp
        Database/Doc.hpp
        Database/SearchResult.cpp
        Database/SearchResult.hpp
        Database/Locales.cpp
        Database/Locales.hpp
        Database/ProjectConfig.cpp
        Database/ProjectConfig.hpp
        Utils/Typename.hpp
)

target_include_directories(
        librpgm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} nlohmann
        "${CMAKE_SOURCE_DIR}/extern/nano-signal-slot")
target_compile_features(librpgm PRIVATE cxx_std_20)
target_link_libraries(
        librpgm PRIVATE magic_enum nlohmann_json::nlohmann_json
        fmt::fmt-header-only spdlog::spdlog_header_only)
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    target_compile_options(librpgm PRIVATE /utf-8)
endif ()

add_library(
        librpgmeventcmds STATIC
        Database/CommandParser.cpp
        Database/CommandParser.hpp
        Database/EventCommands.hpp
        Database/EventCommands/AbortBattle.cpp
        Database/EventCommands/AbortBattle.hpp
        Database/EventCommands/BattleProcessing.cpp
        Database/EventCommands/BattleProcessing.hpp
        Database/EventCommands/BreakLoop.cpp
        Database/EventCommands/BreakLoop.hpp
        Database/EventCommands/ChangeActorImage.cpp
        Database/EventCommands/ChangeActorImage.hpp
        Database/EventCommands/ChangeArmors.cpp
        Database/EventCommands/ChangeArmors.hpp
        Database/EventCommands/ChangeBattleback.cpp
        Database/EventCommands/ChangeBattleback.hpp
        Database/EventCommands/ChangeBattleBGM.cpp
        Database/EventCommands/ChangeBattleBGM.hpp
        Database/EventCommands/ChangeClass.cpp
        Database/EventCommands/ChangeClass.hpp
        Database/EventCommands/ChangeDefeatME.cpp
        Database/EventCommands/ChangeDefeatME.hpp
        Database/EventCommands/ChangeEncounterDisable.cpp
        Database/EventCommands/ChangeEncounterDisable.hpp
        Database/EventCommands/ChangeEnemyHP.cpp
        Database/EventCommands/ChangeEnemyHP.hpp
        Database/EventCommands/ChangeEnemyMP.cpp
        Database/EventCommands/ChangeEnemyMP.hpp
        Database/EventCommands/ChangeEnemyState.cpp
        Database/EventCommands/ChangeEnemyState.hpp
        Database/EventCommands/ChangeEnemyTP.cpp
        Database/EventCommands/ChangeEnemyTP.hpp
        Database/EventCommands/ChangeEquipment.cpp
        Database/EventCommands/ChangeEquipment.hpp
        Database/EventCommands/ChangeEXP.cpp
        Database/EventCommands/ChangeEXP.hpp
        Database/EventCommands/ChangeFormationAccess.cpp
        Database/EventCommands/ChangeFormationAccess.hpp
        Database/EventCommands/ChangeGold.cpp
        Database/EventCommands/ChangeGold.hpp
        Database/EventCommands/ChangeHP.cpp
        Database/EventCommands/ChangeHP.hpp
        Database/EventCommands/ChangeItems.cpp
        Database/EventCommands/ChangeItems.hpp
        Database/EventCommands/ChangeLevel.cpp
        Database/EventCommands/ChangeLevel.hpp
        Database/EventCommands/ChangeMapDisplayName.cpp
        Database/EventCommands/ChangeMapDisplayName.hpp
        Database/EventCommands/ChangeMenuAccess.cpp
        Database/EventCommands/ChangeMenuAccess.hpp
        Database/EventCommands/ChangeMP.cpp
        Database/EventCommands/ChangeMP.hpp
        Database/EventCommands/ChangeName.cpp
        Database/EventCommands/ChangeName.hpp
        Database/EventCommands/ChangeNickname.cpp
        Database/EventCommands/ChangeNickname.hpp
        Database/EventCommands/ChangeParallax.cpp
        Database/EventCommands/ChangeParallax.cpp
        Database/EventCommands/ChangeParallax.hpp
        Database/EventCommands/ChangeParallax.hpp
        Database/EventCommands/ChangeParameter.cpp
        Database/EventCommands/ChangeParameter.hpp
        Database/EventCommands/ChangePartyMember.cpp
        Database/EventCommands/ChangePartyMember.hpp
        Database/EventCommands/ChangePlayerFollowers.cpp
        Database/EventCommands/ChangePlayerFollowers.hpp
        Database/EventCommands/ChangeProfile.cpp
        Database/EventCommands/ChangeProfile.hpp
        Database/EventCommands/ChangeSaveAccess.cpp
        Database/EventCommands/ChangeSaveAccess.hpp
        Database/EventCommands/ChangeSkill.cpp
        Database/EventCommands/ChangeSkill.hpp
        Database/EventCommands/ChangeState.cpp
        Database/EventCommands/ChangeState.hpp
        Database/EventCommands/ChangeTileset.cpp
        Database/EventCommands/ChangeTileset.hpp
        Database/EventCommands/ChangeTP.cpp
        Database/EventCommands/ChangeTP.hpp
        Database/EventCommands/ChangeTransparency.cpp
        Database/EventCommands/ChangeTransparency.hpp
        Database/EventCommands/ChangeVehicleBGM.cpp
        Database/EventCommands/ChangeVehicleBGM.hpp
        Database/EventCommands/ChangeVehicleImage.cpp
        Database/EventCommands/ChangeVehicleImage.hpp
        Database/EventCommands/ChangeVictoryME.cpp
        Database/EventCommands/ChangeVictoryME.hpp
        Database/EventCommands/ChangeWeapons.cpp
        Database/EventCommands/ChangeWeapons.hpp
        Database/EventCommands/ChangeWindowColor.cpp
        Database/EventCommands/ChangeWindowColor.hpp
        Database/EventCommands/Comment.cpp
        Database/EventCommands/Comment.hpp
        Database/EventCommands/CommonEvent.cpp
        Database/EventCommands/CommonEvent.hpp
        Database/EventCommands/ConditionalBranch.cpp
        Database/EventCommands/ConditionalBranch.hpp
        Database/EventCommands/ControlSelfSwitch.cpp
        Database/EventCommands/ControlSelfSwitch.hpp
        Database/EventCommands/ControlSwitches.cpp
        Database/EventCommands/ControlSwitches.hpp
        Database/EventCommands/ControlTimer.cpp
        Database/EventCommands/ControlTimer.hpp
        Database/EventCommands/ControlVariables.cpp
        Database/EventCommands/ControlVariables.hpp
        Database/EventCommands/End.cpp
        Database/EventCommands/End.hpp
        Database/EventCommands/EnemyAppear.cpp
        Database/EventCommands/EnemyAppear.hpp
        Database/EventCommands/EnemyRecoverAll.cpp
        Database/EventCommands/EnemyRecoverAll.hpp
        Database/EventCommands/EnemyTransform.cpp
        Database/EventCommands/EnemyTransform.hpp
        Database/EventCommands/EraseEvent.cpp
        Database/EventCommands/EraseEvent.hpp
        Database/EventCommands/ErasePicture.cpp
        Database/EventCommands/ErasePicture.hpp
        Database/EventCommands/EventDummy.cpp
        Database/EventCommands/EventDummy.hpp
        Database/EventCommands/ExitEventProcessing.cpp
        Database/EventCommands/ExitEventProcessing.hpp
        Database/EventCommands/FadeinScreen.cpp
        Database/EventCommands/FadeinScreen.hpp
        Database/EventCommands/FadeoutBGM.cpp
        Database/EventCommands/FadeoutBGM.hpp
        Database/EventCommands/FadeoutBGS.cpp
        Database/EventCommands/FadeoutBGS.hpp
        Database/EventCommands/FadeoutScreen.cpp
        Database/EventCommands/FadeoutScreen.hpp
        Database/EventCommands/FlashScreen.cpp
        Database/EventCommands/FlashScreen.hpp
        Database/EventCommands/ForceAction.cpp
        Database/EventCommands/ForceAction.hpp
        Database/EventCommands/GameOver.cpp
        Database/EventCommands/GameOver.hpp
        Database/EventCommands/GatherFollowers.cpp
        Database/EventCommands/GatherFollowers.hpp
        Database/EventCommands/GetLocationInfo.cpp
        Database/EventCommands/GetLocationInfo.hpp
        Database/EventCommands/GetOnOffVehicle.cpp
        Database/EventCommands/GetOnOffVehicle.hpp
        Database/EventCommands/IEventCommand.cpp
        Database/EventCommands/IEventCommand.hpp
        Database/EventCommands/InputNumber.cpp
        Database/EventCommands/InputNumber.hpp
        Database/EventCommands/JumpToLabel.cpp
        Database/EventCommands/JumpToLabel.hpp
        Database/EventCommands/Label.cpp
        Database/EventCommands/Label.hpp
        Database/EventCommands/Loop.cpp
        Database/EventCommands/Loop.hpp
        Database/EventCommands/MovePicture.cpp
        Database/EventCommands/MovePicture.hpp
        Database/EventCommands/NameInput.cpp
        Database/EventCommands/NameInput.hpp
        Database/EventCommands/OpenMenu.cpp
        Database/EventCommands/OpenMenu.hpp
        Database/EventCommands/OpenSave.cpp
        Database/EventCommands/OpenSave.hpp
        Database/EventCommands/PlayBGM.cpp
        Database/EventCommands/PlayBGM.hpp
        Database/EventCommands/PlayBGS.cpp
        Database/EventCommands/PlayBGS.hpp
        Database/EventCommands/PlayME.cpp
        Database/EventCommands/PlayME.hpp
        Database/EventCommands/PlayMovie.cpp
        Database/EventCommands/PlayMovie.hpp
        Database/EventCommands/PlaySE.cpp
        Database/EventCommands/PlaySE.hpp
        Database/EventCommands/Plugin.cpp
        Database/EventCommands/Plugin.hpp
        Database/EventCommands/RecoverAll.cpp
        Database/EventCommands/RecoverAll.hpp
        Database/EventCommands/RepeatAbove.cpp
        Database/EventCommands/RepeatAbove.hpp
        Database/EventCommands/ResumeBGM.cpp
        Database/EventCommands/ResumeBGM.hpp
        Database/EventCommands/ReturnToTitle.cpp
        Database/EventCommands/ReturnToTitle.hpp
        Database/EventCommands/RotatePicture.cpp
        Database/EventCommands/RotatePicture.hpp
        Database/EventCommands/SaveBGM.cpp
        Database/EventCommands/SaveBGM.hpp
        Database/EventCommands/Script.cpp
        Database/EventCommands/Script.hpp
        Database/EventCommands/ScrollingText.cpp
        Database/EventCommands/ScrollingText.hpp
        Database/EventCommands/ScrollMap.cpp
        Database/EventCommands/ScrollMap.hpp
        Database/EventCommands/SelectItem.cpp
        Database/EventCommands/SelectItem.hpp
        Database/EventCommands/SetEventLocation.cpp
        Database/EventCommands/SetEventLocation.hpp
        Database/EventCommands/SetMovementRoute.cpp
        Database/EventCommands/SetMovementRoute.hpp
        Database/EventCommands/SetVehicleLocation.cpp
        Database/EventCommands/SetVehicleLocation.hpp
        Database/EventCommands/SetWeatherEffect.cpp
        Database/EventCommands/SetWeatherEffect.hpp
        Database/EventCommands/ShakeScreen.cpp
        Database/EventCommands/ShakeScreen.hpp
        Database/EventCommands/ShopProcessing.cpp
        Database/EventCommands/ShopProcessing.hpp
        Database/EventCommands/ShowAnimation.cpp
        Database/EventCommands/ShowAnimation.hpp
        Database/EventCommands/ShowBalloonIcon.cpp
        Database/EventCommands/ShowBalloonIcon.hpp
        Database/EventCommands/ShowBattleAnimation.cpp
        Database/EventCommands/ShowBattleAnimation.hpp
        Database/EventCommands/ShowChoice.cpp
        Database/EventCommands/ShowChoice.hpp
        Database/EventCommands/ShowPicture.cpp
        Database/EventCommands/ShowPicture.hpp
        Database/EventCommands/ShowText.cpp
        Database/EventCommands/ShowText.hpp
        Database/EventCommands/StopSE.cpp
        Database/EventCommands/StopSE.hpp
        Database/EventCommands/TintPicture.cpp
        Database/EventCommands/TintPicture.hpp
        Database/EventCommands/TintScreen.cpp
        Database/EventCommands/TintScreen.hpp
        Database/EventCommands/TransferPlayer.cpp
        Database/EventCommands/TransferPlayer.hpp
        Database/EventCommands/UnhandledEvent.cpp
        Database/EventCommands/UnhandledEvent.hpp
        Database/EventCommands/Wait.cpp
        Database/EventCommands/Wait.hpp)

target_include_directories(
        librpgmeventcmds PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} nlohmann
        "${CMAKE_SOURCE_DIR}/extern/nano-signal-slot")
target_compile_features(librpgmeventcmds PRIVATE cxx_std_20)
target_link_libraries(
        librpgmeventcmds
        PRIVATE librpgm magic_enum nlohmann_json::nlohmann_json
        fmt::fmt-header-only spdlog::spdlog_header_only)
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    target_compile_options(librpgmeventcmds PRIVATE /utf-8)
endif ()

add_library(
        librpgmmovementroutecmds STATIC
        Database/EventCommands/MovementRoute.hpp
        Database/EventCommands/MovementRoute/BlendMode.cpp
        Database/EventCommands/MovementRoute/BlendMode.hpp
        Database/EventCommands/MovementRoute/ChangeImage.cpp
        Database/EventCommands/MovementRoute/ChangeImage.hpp
        Database/EventCommands/MovementRoute/ChangeOpacity.cpp
        Database/EventCommands/MovementRoute/ChangeOpacity.hpp
        Database/EventCommands/MovementRoute/DirectionFixOFF.cpp
        Database/EventCommands/MovementRoute/DirectionFixOFF.hpp
        Database/EventCommands/MovementRoute/DirectionFixON.cpp
        Database/EventCommands/MovementRoute/DirectionFixON.hpp
        Database/EventCommands/MovementRoute/Frequency.cpp
        Database/EventCommands/MovementRoute/Frequency.hpp
        Database/EventCommands/MovementRoute/IMovementRouteStep.hpp
        Database/EventCommands/MovementRoute/Jump.cpp
        Database/EventCommands/MovementRoute/Jump.hpp
        Database/EventCommands/MovementRoute/Move1StepBackward.cpp
        Database/EventCommands/MovementRoute/Move1StepBackward.hpp
        Database/EventCommands/MovementRoute/Move1StepForward.cpp
        Database/EventCommands/MovementRoute/Move1StepForward.hpp
        Database/EventCommands/MovementRoute/MoveAtRandom.cpp
        Database/EventCommands/MovementRoute/MoveAtRandom.hpp
        Database/EventCommands/MovementRoute/MoveAwayFromPlayer.cpp
        Database/EventCommands/MovementRoute/MoveAwayFromPlayer.hpp
        Database/EventCommands/MovementRoute/MoveDown.cpp
        Database/EventCommands/MovementRoute/MoveDown.hpp
        Database/EventCommands/MovementRoute/MoveLeft.cpp
        Database/EventCommands/MovementRoute/MoveLeft.hpp
        Database/EventCommands/MovementRoute/MoveLowerLeft.cpp
        Database/EventCommands/MovementRoute/MoveLowerLeft.hpp
        Database/EventCommands/MovementRoute/MoveLowerRight.cpp
        Database/EventCommands/MovementRoute/MoveLowerRight.hpp
        Database/EventCommands/MovementRoute/MoveRight.cpp
        Database/EventCommands/MovementRoute/MoveRight.hpp
        Database/EventCommands/MovementRoute/MoveTowardPlayer.cpp
        Database/EventCommands/MovementRoute/MoveTowardPlayer.hpp
        Database/EventCommands/MovementRoute/MoveUp.cpp
        Database/EventCommands/MovementRoute/MoveUp.hpp
        Database/EventCommands/MovementRoute/MoveUpperLeft.cpp
        Database/EventCommands/MovementRoute/MoveUpperLeft.hpp
        Database/EventCommands/MovementRoute/MoveUpperRight.cpp
        Database/EventCommands/MovementRoute/MoveUpperRight.hpp
        Database/EventCommands/MovementRoute/PlaySE.cpp
        Database/EventCommands/MovementRoute/PlaySE.hpp
        Database/EventCommands/MovementRoute/Script.cpp
        Database/EventCommands/MovementRoute/Script.hpp
        Database/EventCommands/MovementRoute/Speed.cpp
        Database/EventCommands/MovementRoute/Speed.hpp
        Database/EventCommands/MovementRoute/SteppingAnimationOFF.cpp
        Database/EventCommands/MovementRoute/SteppingAnimationOFF.hpp
        Database/EventCommands/MovementRoute/SteppingAnimationON.cpp
        Database/EventCommands/MovementRoute/SteppingAnimationON.hpp
        Database/EventCommands/MovementRoute/SwitchOFF.cpp
        Database/EventCommands/MovementRoute/SwitchOFF.hpp
        Database/EventCommands/MovementRoute/SwitchON.cpp
        Database/EventCommands/MovementRoute/SwitchON.hpp
        Database/EventCommands/MovementRoute/ThroughOFF.cpp
        Database/EventCommands/MovementRoute/ThroughOFF.hpp
        Database/EventCommands/MovementRoute/ThroughON.cpp
        Database/EventCommands/MovementRoute/ThroughON.hpp
        Database/EventCommands/MovementRoute/TransparentOFF.cpp
        Database/EventCommands/MovementRoute/TransparentOFF.hpp
        Database/EventCommands/MovementRoute/TransparentON.cpp
        Database/EventCommands/MovementRoute/TransparentON.hpp
        Database/EventCommands/MovementRoute/Turn180Deg.cpp
        Database/EventCommands/MovementRoute/Turn180Deg.hpp
        Database/EventCommands/MovementRoute/Turn90DegLeft.cpp
        Database/EventCommands/MovementRoute/Turn90DegLeft.hpp
        Database/EventCommands/MovementRoute/Turn90DegLeftOrRight.cpp
        Database/EventCommands/MovementRoute/Turn90DegLeftOrRight.hpp
        Database/EventCommands/MovementRoute/Turn90DegRight.cpp
        Database/EventCommands/MovementRoute/Turn90DegRight.hpp
        Database/EventCommands/MovementRoute/TurnAtRandom.cpp
        Database/EventCommands/MovementRoute/TurnAtRandom.hpp
        Database/EventCommands/MovementRoute/TurnAwayFromPlayer.cpp
        Database/EventCommands/MovementRoute/TurnAwayFromPlayer.hpp
        Database/EventCommands/MovementRoute/TurnDown.cpp
        Database/EventCommands/MovementRoute/TurnDown.hpp
        Database/EventCommands/MovementRoute/TurnLeft.cpp
        Database/EventCommands/MovementRoute/TurnLeft.hpp
        Database/EventCommands/MovementRoute/TurnRight.cpp
        Database/EventCommands/MovementRoute/TurnRight.hpp
        Database/EventCommands/MovementRoute/TurnTowardPlayer.cpp
        Database/EventCommands/MovementRoute/TurnTowardPlayer.hpp
        Database/EventCommands/MovementRoute/TurnUp.cpp
        Database/EventCommands/MovementRoute/TurnUp.hpp
        Database/EventCommands/MovementRoute/Wait.cpp
        Database/EventCommands/MovementRoute/Wait.hpp
        Database/EventCommands/MovementRoute/WalkingAnimationOFF.cpp
        Database/EventCommands/MovementRoute/WalkingAnimationOFF.hpp
        Database/EventCommands/MovementRoute/WalkingAnimationON.cpp
        Database/EventCommands/MovementRoute/WalkingAnimationON.hpp)

target_include_directories(
        librpgmmovementroutecmds PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} nlohmann
        "${CMAKE_SOURCE_DIR}/extern/nano-signal-slot")
target_compile_features(librpgmmovementroutecmds PRIVATE cxx_std_20)
target_link_libraries(
        librpgmmovementroutecmds
        PUBLIC oremath
        PRIVATE librpgm magic_enum nlohmann_json::nlohmann_json
        fmt::fmt-header-only spdlog::spdlog_header_only)
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    target_compile_options(librpgmmovementroutecmds PRIVATE /utf-8)
endif ()


code:
#include "Database/Actor.hpp"

Actor::Actor(const Actor& other)
: IModifiable(other)
, m_id(other.m_id)
, m_battlerName(other.m_battlerName)
, m_characterIndex(other.m_characterIndex)
, m_characterName(other.m_characterName)
, m_classId(other.m_classId)
, m_equips(other.m_equips)
, m_faceIndex(other.m_faceIndex)
, m_faceName(other.m_faceName)
, m_traits(other.m_traits)
, m_initialLevel(other.m_initialLevel)
, m_maxLevel(other.m_maxLevel)
, m_name(other.m_name)
, m_nickname(other.m_nickname)
, m_note(other.m_note)
, m_profile(other.m_profile)
, m_oldid(other.m_oldid)
, m_oldbattlerName(other.m_oldbattlerName)
, m_oldcharacterIndex(other.m_oldcharacterIndex)
, m_oldcharacterName(other.m_oldcharacterName)
, m_oldclassId(other.m_oldclassId)
, m_oldequips(other.m_oldequips)
, m_oldfaceIndex(other.m_oldfaceIndex)
, m_oldfaceName(other.m_oldfaceName)
, m_oldtraits(other.m_oldtraits)
, m_oldinitialLevel(other.m_oldinitialLevel)
, m_oldmaxLevel(other.m_oldmaxLevel)
, m_oldname(other.m_oldname)
, m_oldnickname(other.m_oldnickname)
, m_oldnote(other.m_oldnote)
, m_oldprofile(other.m_oldprofile)
, m_isValid(other.m_isValid) {}

Actor& Actor::operator=(const Actor& other) {
  IModifiable::operator=(other);
  m_id = other.m_id;
  m_battlerName = other.m_battlerName;
  m_characterIndex = other.m_characterIndex;
  m_characterName = other.m_characterName;
  m_classId = other.m_classId;
  m_equips = other.m_equips;
  m_faceIndex = other.m_faceIndex;
  m_faceName = other.m_faceName;
  m_traits = other.m_traits;
  m_initialLevel = other.m_initialLevel;
  m_maxLevel = other.m_maxLevel;
  m_name = other.m_name;
  m_nickname = other.m_nickname;
  m_note = other.m_note;
  m_profile = other.m_profile;

  m_oldid = other.m_oldid;
  m_oldbattlerName = other.m_oldbattlerName;
  m_oldcharacterIndex = other.m_oldcharacterIndex;
  m_oldcharacterName = other.m_oldcharacterName;
  m_oldclassId = other.m_oldclassId;
  m_oldequips = other.m_oldequips;
  m_oldfaceIndex = other.m_oldfaceIndex;
  m_oldfaceName = other.m_oldfaceName;
  m_oldtraits = other.m_oldtraits;
  m_oldinitialLevel = other.m_oldinitialLevel;
  m_oldmaxLevel = other.m_oldmaxLevel;
  m_oldname = other.m_oldname;
  m_oldnickname = other.m_oldnickname;
  m_oldnote = other.m_oldnote;
  m_oldprofile = other.m_oldprofile;
  m_isValid = other.m_isValid;
  return *this;
}

Actor::Actor(Actor&& other) noexcept
: IModifiable(std::move(other))
, m_id(other.m_id)
, m_battlerName(std::move(other.m_battlerName))
, m_characterIndex(other.m_characterIndex)
, m_characterName(std::move(other.m_characterName))
, m_classId(other.m_classId)
, m_equips(std::move(other.m_equips))
, m_faceIndex(other.m_faceIndex)
, m_faceName(std::move(other.m_faceName))
, m_traits(std::move(other.m_traits))
, m_initialLevel(other.m_initialLevel)
, m_maxLevel(other.m_maxLevel)
, m_name(std::move(other.m_name))
, m_nickname(std::move(other.m_nickname))
, m_note(std::move(other.m_note))
, m_profile(std::move(other.m_profile))
, m_oldid(other.m_oldid)
, m_oldbattlerName(std::move(other.m_oldbattlerName))
, m_oldcharacterIndex(other.m_oldcharacterIndex)
, m_oldcharacterName(std::move(other.m_oldcharacterName))
, m_oldclassId(other.m_oldclassId)
, m_oldequips(std::move(other.m_oldequips))
, m_oldfaceIndex(other.m_oldfaceIndex)
, m_oldfaceName(std::move(other.m_oldfaceName))
, m_oldtraits(std::move(other.m_oldtraits))
, m_oldinitialLevel(other.m_oldinitialLevel)
, m_oldmaxLevel(other.m_oldmaxLevel)
, m_oldname(std::move(other.m_oldname))
, m_oldnickname(std::move(other.m_oldnickname))
, m_oldnote(std::move(other.m_oldnote))
, m_oldprofile(std::move(other.m_oldprofile))
, m_isValid(other.m_isValid) {}

Actor& Actor::operator=(Actor&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_id = other.m_id;
  m_battlerName = std::move(other.m_battlerName);
  m_characterIndex = other.m_characterIndex;
  m_characterName = std::move(other.m_characterName);
  m_classId = other.m_classId;
  m_equips = std::move(other.m_equips);
  m_faceIndex = other.m_faceIndex;
  m_faceName = std::move(other.m_faceName);
  m_traits = std::move(other.m_traits);
  m_initialLevel = other.m_initialLevel;
  m_maxLevel = other.m_maxLevel;
  m_name = std::move(other.m_name);
  m_nickname = std::move(other.m_nickname);
  m_note = std::move(other.m_note);
  m_profile = std::move(other.m_profile);

  m_oldid = other.m_oldid;
  m_oldbattlerName = std::move(other.m_oldbattlerName);
  m_oldcharacterIndex = other.m_oldcharacterIndex;
  m_oldcharacterName = std::move(other.m_oldcharacterName);
  m_oldclassId = other.m_oldclassId;
  m_oldequips = std::move(other.m_oldequips);
  m_oldfaceIndex = other.m_oldfaceIndex;
  m_oldfaceName = std::move(other.m_oldfaceName);
  m_oldtraits = std::move(other.m_oldtraits);
  m_oldinitialLevel = other.m_oldinitialLevel;
  m_oldmaxLevel = other.m_oldmaxLevel;
  m_oldname = std::move(other.m_oldname);
  m_oldnickname = std::move(other.m_oldnickname);
  m_oldnote = std::move(other.m_oldnote);
  m_oldprofile = std::move(other.m_oldprofile);

  m_isValid = other.m_isValid;
  return *this;
}

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

const std::string& Actor::battlerName() const { return m_battlerName; }
void Actor::setBattlerName(const std::string& battlerName) {
  MODIFIABLE_SET_OLD_VALUE(battlerName);
  m_battlerName = battlerName;
  if (!signalsDisabled()) {
    emit_signal(battlerNameModified(), this, m_battlerName);
  }
  setModified();
}
int Actor::characterIndex() const { return m_characterIndex; }
void Actor::setCharacterIndex(const int characterIndex) {
  MODIFIABLE_SET_OLD_VALUE(characterIndex);
  m_characterIndex = characterIndex;
  if (!signalsDisabled()) {
    emit_signal(characterIndexModified(), this, m_characterIndex);
  }
  setModified();
}
const std::string& Actor::characterName() const { return m_characterName; }
void Actor::setCharacterName(const std::string& characterName) {
  MODIFIABLE_SET_OLD_VALUE(characterName);
  m_characterName = characterName;
  if (!signalsDisabled()) {
    emit_signal(characterNameModified(), this, m_characterName);
  }
  setModified();
}
int Actor::classId() const { return m_classId; }
void Actor::setClassId(const int classId) {
  MODIFIABLE_SET_OLD_VALUE(classId);
  m_classId = classId;
  if (!signalsDisabled()) {
    emit_signal(classIdModified(), this, m_classId);
  }
  setModified();
}
const std::vector<int>& Actor::equips() const { return m_equips; }
void Actor::setEquips(const std::vector<int>& equips) {
  MODIFIABLE_SET_OLD_VALUE(equips);
  m_equips = equips;
  if (!signalsDisabled()) {
    emit_signal(equipsModified(), this, m_equips);
  }
  setModified();
}
void Actor::addEquip(const int equip) {
  MODIFIABLE_SET_OLD_VALUE(equips);
  m_equips.push_back(equip);
  if (!signalsDisabled()) {
    emit_signal(equipAdded(), this, m_equips.size() - 1, equip);
  }
  setModified();
}

void Actor::setEquip(const int index, const int equip) {
  assert(index < m_equips.size());
  MODIFIABLE_SET_OLD_VALUE(equips);
  if (m_equips.size() <= index) {
    m_equips.resize(index - m_equips.size());
  }
  m_equips[index] = equip;
  if (!signalsDisabled()) {
    emit_signal(equipAdded(), this, index, index);
  }
  setModified();
}

void Actor::removeEquip(const int index) {
  assert(index < m_equips.size());
  MODIFIABLE_SET_OLD_VALUE(equips);
  int oldEquip = m_equips[index];
  m_equips.erase(m_equips.begin() + index);
  if (!signalsDisabled()) {
    emit_signal(equipRemoved(), this, index, oldEquip);
  }
  setModified();
}

int Actor::faceIndex() const { return m_faceIndex; }
void Actor::setFaceIndex(const int faceIndex) {
  MODIFIABLE_SET_OLD_VALUE(faceIndex);
  m_faceIndex = faceIndex;
  if (!signalsDisabled()) {
    emit_signal(faceIndexModified(), this, m_faceIndex);
  }
  setModified();
}

const std::string& Actor::faceName() const { return m_faceName; }
void Actor::setFaceName(const std::string& faceName) {
  MODIFIABLE_SET_OLD_VALUE(faceName);
  m_faceName = faceName;
  if (!signalsDisabled()) {
    emit_signal(faceNameModified(), this, m_faceName);
  }
  setModified();
}

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

Trait& Actor::trait(const int index) {
  assert(index < m_traits.size());
  MODIFIABLE_SET_OLD_VALUE(traits);
  return m_traits[index];
}

int Actor::initialLevel() const { return m_initialLevel; }
void Actor::setInitialLevel(const int initialLevel) {
  MODIFIABLE_SET_OLD_VALUE(initialLevel);
  m_initialLevel = initialLevel;
  if (!signalsDisabled()) {
    emit_signal(initialLevelModified(), this, m_initialLevel);
  }
  setModified();
}

int Actor::maxLevel() const { return m_maxLevel; }
void Actor::setMaxLevel(const int maxLevel) {
  MODIFIABLE_SET_OLD_VALUE(maxLevel);
  m_maxLevel = maxLevel;
  if (!signalsDisabled()) {
    emit_signal(maxLevelModified(), this, m_maxLevel);
  }
  setModified();
}

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

  if (!signalsDisabled()) {
    emit_signal(nicknameModified(), this, m_nickname);
  }
  setModified();
}

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

const std::string& Actor::profile() const { return m_profile; }
void Actor::setProfile(const std::string& profile) {
  MODIFIABLE_SET_OLD_VALUE(profile);
  m_profile = profile;
  if (!signalsDisabled()) {
    emit_signal(profileModified(), this, m_profile);
  }
  setModified();
}

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

/* Signals */
rpgmutils::signal<void(Actor* actor, int newId)>& Actor::idModified() {
  if (!m_idModified) {
    m_idModified.emplace();
  }
  return *m_idModified;
}

rpgmutils::signal<void(Actor* actor, const std::string& name)>& Actor::battlerNameModified() {
  if (!m_battlerNameModified) {
    m_battlerNameModified.emplace();
  }
  return *m_battlerNameModified;
}

rpgmutils::signal<void(Actor* actor, int newIndex)>& Actor::characterIndexModified() {
  if (!m_characterIndexModified) {
    m_characterIndexModified.emplace();
  }

  return *m_characterIndexModified;
}

rpgmutils::signal<void(Actor* actor, const std::string& name)>& Actor::characterNameModified() {
  if (!m_characterNameModified) {
    m_characterNameModified.emplace();
  }
  return *m_characterNameModified;
}

rpgmutils::signal<void(Actor* actor, int newId)>& Actor::classIdModified() {
  if (!m_onClassIdModified) {
    m_onClassIdModified.emplace();
  }

  return *m_onClassIdModified;
}

rpgmutils::signal<void(Actor* actor, const std::vector<int>& newEquips)>& Actor::equipsModified() {
  if (!m_equipsModified) {
    m_equipsModified.emplace();
  }
  return *m_equipsModified;
}

rpgmutils::signal<void(Actor* actor, int index, int newEquip)>& Actor::equipAdded() {
  if (!m_equipAdded) {
    m_equipAdded.emplace();
  }
  return *m_equipAdded;
}

rpgmutils::signal<void(Actor* actor, int index, int newEquip)>& Actor::equipModified() {
  if (!m_equipModified) {
    m_equipModified.emplace();
  }
  return *m_equipModified;
}

rpgmutils::signal<void(Actor* actor, int index, int newEquip)>& Actor::equipRemoved() {
  if (!m_equipRemoved) {
    m_equipRemoved.emplace();
  }
  return *m_equipRemoved;
}

rpgmutils::signal<void(Actor* actor, int newId)>& Actor::faceIndexModified() {
  if (!m_faceIndexModified) {
    m_faceIndexModified.emplace();
  }

  return *m_faceIndexModified;
}

rpgmutils::signal<void(Actor* actor, const std::string& newFaceName)>& Actor::faceNameModified() {
  if (!m_faceNameModified) {
    m_faceNameModified.emplace();
  }
  return *m_faceNameModified;
}

rpgmutils::signal<void(Actor* actor, const std::vector<Trait>& newTraits)>& Actor::traitsModified() {
  if (!m_traitsModified) {
    m_traitsModified.emplace();
  }
  return *m_traitsModified;
}

rpgmutils::signal<void(Actor* actor, const Trait& trait)>& Actor::traitAdded() {
  if (!m_traitAdded) {
    m_traitAdded.emplace();
  }
  return *m_traitAdded;
}

rpgmutils::signal<void(Actor* actor, int newInitialLevel)>& Actor::initialLevelModified() {
  if (!m_initialLevelModified) {
    m_initialLevelModified.emplace();
  }
  return *m_initialLevelModified;
}

rpgmutils::signal<void(Actor* actor, int newMaxLevel)>& Actor::maxLevelModified() {
  if (!m_maxLevelModified) {
    m_maxLevelModified.emplace();
  }
  return *m_maxLevelModified;
}

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

rpgmutils::signal<void(Actor* actor, const std::string& newNickname)>& Actor::nicknameModified() {
  if (!m_nicknameModified) {
    m_nicknameModified.emplace();
  }
  return *m_nicknameModified;
}

rpgmutils::signal<void(Actor* actor, const std::string& newNote)>& Actor::noteModified() {
  if (!m_noteModified) {
    m_noteModified.emplace();
  }
  return *m_noteModified;
}

rpgmutils::signal<void(Actor* actor, const std::string& newProfile)>& Actor::profileModified() {
  if (!m_profileModified) {
    m_profileModified.emplace();
  }
  return *m_profileModified;
}

void Actor::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(id);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(battlerName);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(characterIndex);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(characterName);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(classId);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(equips);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(faceIndex);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(faceName);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(traits);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(initialLevel);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(maxLevel);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(name);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(nickname);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(note);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(profile);
}
void Actor::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(id);
  MODIFIABLE_ACCEPT_VALUE(battlerName);
  MODIFIABLE_ACCEPT_VALUE(characterIndex);
  MODIFIABLE_ACCEPT_VALUE(characterName);
  MODIFIABLE_ACCEPT_VALUE(classId);
  MODIFIABLE_ACCEPT_VALUE(equips);
  MODIFIABLE_ACCEPT_VALUE(faceIndex);
  MODIFIABLE_ACCEPT_VALUE(faceName);
  MODIFIABLE_ACCEPT_VALUE(traits);
  MODIFIABLE_ACCEPT_VALUE(initialLevel);
  MODIFIABLE_ACCEPT_VALUE(maxLevel);
  MODIFIABLE_ACCEPT_VALUE(name);
  MODIFIABLE_ACCEPT_VALUE(nickname);
  MODIFIABLE_ACCEPT_VALUE(note);
  MODIFIABLE_ACCEPT_VALUE(profile);
}

nlohmann::ordered_json Actor::serializeOldValues() const {
  const nlohmann::ordered_json j = {
      MODIFIABLE_SERIALIZE_VALUE(id),           MODIFIABLE_SERIALIZE_VALUE(battlerName), MODIFIABLE_SERIALIZE_VALUE(characterIndex), MODIFIABLE_SERIALIZE_VALUE(characterName),
      MODIFIABLE_SERIALIZE_VALUE(equips),       MODIFIABLE_SERIALIZE_VALUE(faceIndex),   MODIFIABLE_SERIALIZE_VALUE(faceName),       MODIFIABLE_SERIALIZE_VALUE_CHILD_ARRAY(traits),
      MODIFIABLE_SERIALIZE_VALUE(initialLevel), MODIFIABLE_SERIALIZE_VALUE(maxLevel),    MODIFIABLE_SERIALIZE_VALUE(name),           MODIFIABLE_SERIALIZE_VALUE(note),
      MODIFIABLE_SERIALIZE_VALUE(profile),
  };

  return j;
}

void to_json(nlohmann::ordered_json& to, const Actor& actor) {
  to = {
      {"id", actor.m_id},
      {"battlerName", actor.m_battlerName},
      {"characterIndex", actor.m_characterIndex},
      {"characterName", actor.m_characterName},
      {"classId", actor.m_classId},
      {"equips", actor.m_equips},
      {"faceIndex", actor.m_faceIndex},
      {"faceName", actor.m_faceName},
      {"traits", actor.m_traits},
      {"initialLevel", actor.m_initialLevel},
      {"maxLevel", actor.m_maxLevel},
      {"name", actor.m_name},
      {"nickname", actor.m_nickname},
      {"note", actor.m_note},
      {"profile", actor.m_profile},
  };
}
void from_json(const nlohmann::ordered_json& from, Actor& actor) {
  actor.m_id = from.value("id", actor.m_id);
  actor.m_battlerName = from.value("battlerName", actor.m_battlerName);
  actor.m_characterIndex = from.value("characterIndex", actor.m_characterIndex);
  actor.m_characterName = from.value("characterName", actor.m_characterName);
  actor.m_classId = from.value("classId", actor.m_classId);
  actor.m_equips = from.value("equips", actor.m_equips);
  actor.m_faceIndex = from.value("faceIndex", actor.m_faceIndex);
  actor.m_faceName = from.value("faceName", actor.m_faceName);
  actor.m_traits = from.value("traits", actor.m_traits);
  actor.m_initialLevel = from.value("initialLevel", actor.m_initialLevel);
  actor.m_maxLevel = from.value("maxLevel", actor.m_maxLevel);
  actor.m_name = from.value("name", actor.m_name);
  actor.m_nickname = from.value("nickname", actor.m_nickname);
  actor.m_profile = from.value("profile", actor.m_profile);
}

repo_name: Antidote/openrpgeditor

license: mit


code:
#pragma once

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

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

class Actor final : public IModifiable {
  friend void to_json(nlohmann::ordered_json& to, const Actor& actor);
  friend void from_json(const nlohmann::ordered_json& from, Actor& actor);

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

  /**
   *
   * @return
   */
  int id() const;

  /**
   *
   * @param id
   */
  void setId(int id);

  /**
   *
   * @return
   */
  const std::string& battlerName() const;

  /**
   *
   * @param battlerName
   */
  void setBattlerName(const std::string& battlerName);

  /**
   *
   * @return
   */
  int characterIndex() const;

  /**
   *
   * @param characterIndex
   */
  void setCharacterIndex(int characterIndex);

  /**
   *
   * @return
   */
  const std::string& characterName() const;

  /**
   *
   * @param characterName
   */
  void setCharacterName(const std::string& characterName);

  /**
   *
   * @return
   */

  int classId() const;
  /**
   *
   * @param classId
   */
  void setClassId(int classId);

  /**
   *
   * @return
   */
  const std::vector<int>& equips() const;

  /**
   *
   * @param equips
   */
  void setEquips(const std::vector<int>& equips);

  /**
   *
   * @param equip
   */
  void addEquip(int equip);

  /**
   *
   * @param index
   * @param equip
   */
  void setEquip(int index, int equip);

  /**
   *
   * @param index
   */
  void removeEquip(int index);

  /**
   *
   * @return
   */
  int faceIndex() const;

  /**
   *
   * @param faceIndex
   */
  void setFaceIndex(int faceIndex);

  /**
   *
   * @return
   */
  const std::string& faceName() const;

  /**
   *
   * @param faceName
   */
  void setFaceName(const std::string& faceName);

  /**
   *
   * @return
   */
  std::vector<Trait>& traits();

  /**
   *
   * @param traits
   */
  void setTraits(const std::vector<Trait>& traits);

  /**
   *
   * @param index
   * @return
   */
  Trait& trait(int index);

  /**
   *
   * @return
   */
  int initialLevel() const;
  /**
   *
   * @param initialLevel
   */
  void setInitialLevel(int initialLevel);

  /**
   *
   * @return
   */
  int maxLevel() const;

  /**
   *
   * @param maxLevel
   */
  void setMaxLevel(int maxLevel);

  /**
   *
   * @return
   */
  const std::string& name() const;

  /**
   *
   * @param name
   */
  void setName(const std::string& name);

  /**
   *
   * @return
   */
  const std::string& nickname() const;

  /**
   *
   * @param nickname
   */
  void setNickname(const std::string& nickname);

  /**
   *
   * @return
   */
  const std::string& note() const;
  /**
   *
   * @param note
   */
  void setNote(const std::string& note);

  /**
   *
   * @return
   */
  const std::string& profile() const;
  /**
   *
   * @param profile
   */
  void setProfile(const std::string& profile);

  /**
   *
   * @return
   */
  bool isValid() const;
  /**
   *
   * @param valid
   */
  void setValid(bool valid);

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

  /* Signals */
  rpgmutils::signal<void(Actor* actor, int newId)>& idModified();
  rpgmutils::signal<void(Actor* actor, const std::string& name)>& battlerNameModified();
  rpgmutils::signal<void(Actor* actor, int newIndex)>& characterIndexModified();
  rpgmutils::signal<void(Actor* actor, const std::string& name)>& characterNameModified();
  rpgmutils::signal<void(Actor* actor, int newId)>& classIdModified();
  rpgmutils::signal<void(Actor* actor, const std::vector<int>& newEquips)>& equipsModified();
  rpgmutils::signal<void(Actor* actor, int index, int newEquip)>& equipAdded();
  rpgmutils::signal<void(Actor* actor, int index, int newEquip)>& equipModified();
  rpgmutils::signal<void(Actor* actor, int index, int newEquip)>& equipRemoved();
  rpgmutils::signal<void(Actor* actor, int newId)>& faceIndexModified();
  rpgmutils::signal<void(Actor* actor, const std::string& newFaceName)>& faceNameModified();
  rpgmutils::signal<void(Actor* actor, const std::vector<Trait>& newTraits)>& traitsModified();
  rpgmutils::signal<void(Actor* actor, const Trait& trait)>& traitAdded();
  rpgmutils::signal<void(Actor* actor, int newInitialLevel)>& initialLevelModified();
  rpgmutils::signal<void(Actor* actor, int newMaxLevel)>& maxLevelModified();
  rpgmutils::signal<void(Actor* actor, const std::string& newName)>& nameModified();
  rpgmutils::signal<void(Actor* actor, const std::string& newNickname)>& nicknameModified();
  rpgmutils::signal<void(Actor* actor, const std::string& newNote)>& noteModified();
  rpgmutils::signal<void(Actor* actor, const std::string& newProfile)>& profileModified();

  bool isModified() const override {
    return (IModifiable::isModified() | std::ranges::any_of(m_traits, [](const Trait& trait) { return trait.isModified(); }));
  }

private:
  int m_id = 1;
  std::string m_battlerName;
  int m_characterIndex = 0;
  std::string m_characterName;
  int m_classId = 1;
  std::vector<int> m_equips;
  int m_faceIndex = 0;
  std::string m_faceName;
  std::vector<Trait> m_traits;
  int m_initialLevel = 1;
  int m_maxLevel = 99;
  std::string m_name;
  std::string m_nickname;
  std::string m_note;
  std::string m_profile;

  // !!!DO NOT CHANGE CASING!!!
  std::optional<int> m_oldid;
  std::optional<std::string> m_oldbattlerName;
  std::optional<int> m_oldcharacterIndex;
  std::optional<std::string> m_oldcharacterName;
  std::optional<int> m_oldclassId;
  std::optional<std::vector<int>> m_oldequips;
  std::optional<int> m_oldfaceIndex;
  std::optional<std::string> m_oldfaceName;
  std::optional<std::vector<Trait>> m_oldtraits;
  std::optional<int> m_oldinitialLevel;
  std::optional<int> m_oldmaxLevel;
  std::optional<std::string> m_oldname;
  std::optional<std::string> m_oldnickname;
  std::optional<std::string> m_oldnote;
  std::optional<std::string> m_oldprofile;

  /* Signals */
  std::optional<rpgmutils::signal<void(Actor* actor, int newId)>> m_idModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::string& newName)>> m_battlerNameModified;
  std::optional<rpgmutils::signal<void(Actor* actor, int newIndex)>> m_characterIndexModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::string& newName)>> m_characterNameModified;
  std::optional<rpgmutils::signal<void(Actor* actor, int newId)>> m_onClassIdModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::vector<int>& newEquips)>> m_equipsModified;
  std::optional<rpgmutils::signal<void(Actor* actor, int index, int newEquip)>> m_equipAdded;
  std::optional<rpgmutils::signal<void(Actor* actor, int index, int newEquip)>> m_equipModified;
  std::optional<rpgmutils::signal<void(Actor* actor, int index, int newEquip)>> m_equipRemoved;
  std::optional<rpgmutils::signal<void(Actor* actor, int newIndex)>> m_faceIndexModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::string& newFaceName)>> m_faceNameModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::vector<Trait>& newTraits)>> m_traitsModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const Trait& trait)>> m_traitAdded;
  std::optional<rpgmutils::signal<void(Actor* actor, int newInitialLevel)>> m_initialLevelModified;
  std::optional<rpgmutils::signal<void(Actor* actor, int newMaxLevel)>> m_maxLevelModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::string& newName)>> m_nameModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::string& newNickname)>> m_nicknameModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::string& newNote)>> m_noteModified;
  std::optional<rpgmutils::signal<void(Actor* actor, const std::string& newProfile)>> m_profileModified;

  /*!
   * @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& to, const Actor& actor);
void from_json(const nlohmann::json& from, Actor& actor);


code:
#include "Actors.hpp"

#include <fstream>


code:
#pragma once

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

#include <vector>

#include "nlohmann/json.hpp"

class Actors final : public IModifiable {
public:
  [[nodiscard]] Actor* actor(const int id) {
    for (auto& actor : m_actors) {
      if (actor.id() == id && actor.isValid()) {
        return &actor;
      }
    }
    return nullptr;
  }

  [[nodiscard]] const Actor* actor(const int id) const {
    for (const auto& actor : m_actors) {
      if (actor.id() == id && actor.isValid()) {
        return &actor;
      }
    }

    return nullptr;
  }

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

  bool hasTestActor() const {
    return std::ranges::find_if(m_actors, [](const auto& act) { return act.id() == 0; }) != m_actors.end();
  }
  int count() const { return m_actors.size() - 1; }

  std::vector<Actor>& actorList() { return m_actors; }
  const std::vector<Actor>& actorList() const { return m_actors; }

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

private:
  friend class DBActorsTab;
  std::vector<Actor> m_actors;
};


code:
#include "Animation.hpp"

Animation::Color::Color(const Color& other)
: IModifiable(other)
, m_r(other.m_r)
, m_g(other.m_g)
, m_b(other.m_b)
, m_intensity(other.m_intensity)
, m_oldr(other.m_oldr)
, m_oldg(other.m_oldg)
, m_oldb(other.m_oldb)
, m_oldintensity(other.m_oldintensity) {}

Animation::Color& Animation::Color::operator=(const Color& other) {
  IModifiable::operator=(other);
  m_r = other.m_r;
  m_g = other.m_g;
  m_b = other.m_b;
  m_intensity = other.m_intensity;
  m_oldr = other.m_oldr;
  m_oldg = other.m_oldg;
  m_oldb = other.m_oldb;
  m_oldintensity = other.m_oldintensity;
  return *this;
}

Animation::Color::Color(Color&& other) noexcept
: IModifiable(std::move(other))
, m_r(other.m_r)
, m_g(other.m_g)
, m_b(other.m_b)
, m_intensity(other.m_intensity)
, m_oldr(other.m_oldr)
, m_oldg(other.m_oldg)
, m_oldb(other.m_oldb)
, m_oldintensity(other.m_oldintensity) {}

Animation::Color& Animation::Color::operator=(Color&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_r = other.m_r;
  m_g = other.m_g;
  m_b = other.m_b;
  m_intensity = other.m_intensity;
  m_oldr = other.m_oldr;
  m_oldg = other.m_oldg;
  m_oldb = other.m_oldb;
  m_oldintensity = other.m_oldintensity;
  return *this;
}

int Animation::Color::r() const { return m_r; }

void Animation::Color::setR(const int r) {
  MODIFIABLE_SET_OLD_VALUE(r);
  m_r = r;
  if (!signalsDisabled()) {
    emit_signal(rModified(), this, r);
  }
  setModified(true);
}

int Animation::Color::g() const { return m_g; }

void Animation::Color::setG(const int g) {
  MODIFIABLE_SET_OLD_VALUE(g);
  m_g = g;
  if (!signalsDisabled()) {
    emit_signal(gModified(), this, g);
  }
  setModified(true);
}

int Animation::Color::b() const { return m_b; }

void Animation::Color::setB(const int b) {
  MODIFIABLE_SET_OLD_VALUE(b);
  m_b = b;
  if (!signalsDisabled()) {
    emit_signal(bModified(), this, b);
  }
  setModified(true);
}

int Animation::Color::intensity() const { return m_intensity; }

void Animation::Color::setIntensity(const int intensity) {
  MODIFIABLE_SET_OLD_VALUE(intensity);
  m_intensity = intensity;
  if (!signalsDisabled()) {
    emit_signal(intensityModified(), this, intensity);
  }
  setModified(true);
}

rpgmutils::signal<void(Animation::Color*, int)>& Animation::Color::rModified() {
  if (!m_rModified) {
    m_rModified.emplace();
  }

  return *m_rModified;
}

rpgmutils::signal<void(Animation::Color*, int)>& Animation::Color::gModified() {
  if (!m_gModified) {
    m_gModified.emplace();
  }
  return *m_gModified;
}

rpgmutils::signal<void(Animation::Color*, int)>& Animation::Color::bModified() {
  if (!m_bModified) {
    m_bModified.emplace();
  }
  return *m_bModified;
}

rpgmutils::signal<void(Animation::Color*, int)>& Animation::Color::intensityModified() {
  if (!m_intensityModified) {
    m_intensityModified.emplace();
  }
  return *m_intensityModified;
}

void Animation::Color::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(r);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(g);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(b);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(intensity);
}

void Animation::Color::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(r);
  MODIFIABLE_ACCEPT_VALUE(g);
  MODIFIABLE_ACCEPT_VALUE(b);
  MODIFIABLE_ACCEPT_VALUE(intensity);
}

nlohmann::ordered_json Animation::Color::serializeOldValues() const {
  nlohmann::ordered_json json;
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, r);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, g);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, b);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, intensity);
  return json;
}

Animation::FramePart::FramePart(const FramePart& other)
: IModifiable(other)
, m_pattern(other.m_pattern)
, m_x(other.m_x)
, m_y(other.m_y)
, m_scale(other.m_scale)
, m_rotation(other.m_rotation)
, m_mirror(other.m_mirror)
, m_opacity(other.m_opacity)
, m_blend(other.m_blend)
, m_oldpattern(other.m_oldpattern)
, m_oldx(other.m_oldx)
, m_oldy(other.m_oldy)
, m_oldscale(other.m_oldscale)
, m_oldrotation(other.m_oldrotation)
, m_oldmirror(other.m_oldmirror)
, m_oldopacity(other.m_oldopacity)
, m_oldblend(other.m_oldblend) {}

Animation::FramePart& Animation::FramePart::operator=(const FramePart& other) {
  IModifiable::operator=(other);
  m_pattern = other.m_pattern;
  m_x = other.m_x;
  m_y = other.m_y;
  m_scale = other.m_scale;
  m_rotation = other.m_rotation;
  m_mirror = other.m_mirror;
  m_opacity = other.m_opacity;
  m_blend = other.m_blend;
  m_oldpattern = other.m_oldpattern;
  m_oldx = other.m_oldx;
  m_oldy = other.m_oldy;
  m_oldscale = other.m_oldscale;
  m_oldrotation = other.m_oldrotation;
  m_oldmirror = other.m_oldmirror;
  m_oldopacity = other.m_oldopacity;
  m_oldblend = other.m_oldblend;
  return *this;
}

Animation::FramePart::FramePart(FramePart&& other) noexcept
: IModifiable(std::move(other))
, m_pattern(other.m_pattern)
, m_x(other.m_x)
, m_y(other.m_y)
, m_scale(other.m_scale)
, m_rotation(other.m_rotation)
, m_mirror(other.m_mirror)
, m_opacity(other.m_opacity)
, m_blend(other.m_blend)
, m_oldpattern(other.m_oldpattern)
, m_oldx(other.m_oldx)
, m_oldy(other.m_oldy)
, m_oldscale(other.m_oldscale)
, m_oldrotation(other.m_oldrotation)
, m_oldmirror(other.m_oldmirror)
, m_oldopacity(other.m_oldopacity)
, m_oldblend(other.m_oldblend) {}

Animation::FramePart& Animation::FramePart::operator=(FramePart&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_pattern = other.m_pattern;
  m_x = other.m_x;
  m_y = other.m_y;
  m_scale = other.m_scale;
  m_rotation = other.m_rotation;
  m_mirror = other.m_mirror;
  m_opacity = other.m_opacity;
  m_blend = other.m_blend;
  m_oldpattern = other.m_oldpattern;
  m_oldx = other.m_oldx;
  m_oldy = other.m_oldy;
  m_oldscale = other.m_oldscale;
  m_oldrotation = other.m_oldrotation;
  m_oldmirror = other.m_oldmirror;
  m_oldopacity = other.m_oldopacity;
  m_oldblend = other.m_oldblend;
  return *this;
}

int Animation::FramePart::pattern() const { return m_pattern; }

void Animation::FramePart::setPattern(const int pattern) {
  MODIFIABLE_SET_OLD_VALUE(pattern);
  m_pattern = pattern;
  if (!signalsDisabled()) {
    emit_signal(patternModified(), this, pattern);
  }
  setModified(true);
}

int Animation::FramePart::x() const { return m_x; }

void Animation::FramePart::setX(const int x) {
  MODIFIABLE_SET_OLD_VALUE(x);
  m_x = x;
  if (!signalsDisabled()) {
    emit_signal(xModified(), this, x);
  }
  setModified(true);
}

int Animation::FramePart::y() const { return m_y; }

void Animation::FramePart::setY(const int y) {
  MODIFIABLE_SET_OLD_VALUE(y);
  m_y = y;
  if (!signalsDisabled()) {
    emit_signal(yModified(), this, y);
  }
  setModified(true);
}

int Animation::FramePart::scale() const { return m_scale; }

void Animation::FramePart::setScale(const int scale) {
  MODIFIABLE_SET_OLD_VALUE(scale);
  m_scale = scale;
  if (!signalsDisabled()) {
    emit_signal(scaleModified(), this, scale);
  }
  setModified(true);
}

int Animation::FramePart::rotation() const { return m_rotation; }

void Animation::FramePart::setRotation(const int rotation) {
  MODIFIABLE_SET_OLD_VALUE(rotation);
  m_rotation = rotation;
  if (!signalsDisabled()) {
    emit_signal(rotationModified(), this, rotation);
  }
  setModified(true);
}

Mirror Animation::FramePart::mirror() const { return m_mirror; }

void Animation::FramePart::setMirror(const Mirror mirror) {
  MODIFIABLE_SET_OLD_VALUE(mirror);
  m_mirror = mirror;
  if (!signalsDisabled()) {
    emit_signal(mirrorModified(), this, mirror);
  }
  setModified(true);
}

int Animation::FramePart::opacity() const { return m_opacity; }

void Animation::FramePart::setOpacity(const int opacity) {
  MODIFIABLE_SET_OLD_VALUE(opacity);
  m_opacity = opacity;
  if (!signalsDisabled()) {
    emit_signal(opacityModified(), this, opacity);
  }
  setModified(true);
}

Blend Animation::FramePart::blend() const { return m_blend; }

void Animation::FramePart::setBlend(const Blend blend) {
  MODIFIABLE_SET_OLD_VALUE(blend);
  m_blend = blend;
  if (!signalsDisabled()) {
    emit_signal(blendModified(), this, blend);
  }
  setModified(true);
}
bool Animation::FramePart::showTimeLine() const { return m_show; }
void Animation::FramePart::setShowTimeLine(const bool show) { m_show = show; }
std::string Animation::FramePart::getToolTip() {
  return std::format("Pattern: {}\nX: {}\nY: {}\nScale: {}\nRotation: {}\nMirror: {}\nOpacity: {}\nBlend: {}", m_pattern, m_x, m_y, m_scale, m_rotation, DecodeEnumName(m_mirror), m_opacity,
                     DecodeEnumName(m_blend));
}

rpgmutils::signal<void(Animation::FramePart*, int)>& Animation::FramePart::patternModified() {
  if (!m_patternModified) {
    m_patternModified.emplace();
  }
  return *m_patternModified;
}

rpgmutils::signal<void(Animation::FramePart*, int)>& Animation::FramePart::xModified() {
  if (!m_xModified) {
    m_xModified.emplace();
  }
  return *m_xModified;
}

rpgmutils::signal<void(Animation::FramePart*, int)>& Animation::FramePart::yModified() {
  if (!m_yModified) {
    m_yModified.emplace();
  }
  return *m_yModified;
}

rpgmutils::signal<void(Animation::FramePart*, int)>& Animation::FramePart::scaleModified() {
  if (!m_scaleModified) {
    m_scaleModified.emplace();
  }
  return *m_scaleModified;
}

rpgmutils::signal<void(Animation::FramePart*, int)>& Animation::FramePart::rotationModified() {
  if (!m_rotationModified) {
    m_rotationModified.emplace();
  }
  return *m_rotationModified;
}

rpgmutils::signal<void(Animation::FramePart*, Mirror)>& Animation::FramePart::mirrorModified() {
  if (!m_mirrorModified) {
    m_mirrorModified.emplace();
  }
  return *m_mirrorModified;
}

rpgmutils::signal<void(Animation::FramePart*, int)>& Animation::FramePart::opacityModified() {
  if (!m_opacityModified) {
    m_opacityModified.emplace();
  }
  return *m_opacityModified;
}

rpgmutils::signal<void(Animation::FramePart*, Blend)>& Animation::FramePart::blendModified() {
  if (!m_blendModified) {
    m_blendModified.emplace();
  }
  return *m_blendModified;
}

void Animation::FramePart::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(pattern);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(x);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(y);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(scale);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(rotation);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(mirror);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(opacity);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(blend);
}

void Animation::FramePart::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(pattern);
  MODIFIABLE_ACCEPT_VALUE(x);
  MODIFIABLE_ACCEPT_VALUE(y);
  MODIFIABLE_ACCEPT_VALUE(scale);
  MODIFIABLE_ACCEPT_VALUE(rotation);
  MODIFIABLE_ACCEPT_VALUE(mirror);
  MODIFIABLE_ACCEPT_VALUE(opacity);
  MODIFIABLE_ACCEPT_VALUE(blend);
}

nlohmann::ordered_json Animation::FramePart::serializeOldValues() const {
  nlohmann::ordered_json json;
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, pattern);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, x);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, y);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, scale);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, rotation);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, mirror);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, opacity);
  MODIFIABLE_SERIALIZE_VALUE_FLAT_ARRAY(json, blend);
  return json;
}

Animation::Timing::Timing(const Timing& other)
: IModifiable(other)
, m_flashColor(other.m_flashColor)
, m_flashDuration(other.m_flashDuration)
, m_flashScope(other.m_flashScope)
, m_frame(other.m_frame)
, m_se(other.m_se)
, m_oldflashColor(other.m_oldflashColor)
, m_oldflashDuration(other.m_oldflashDuration)
, m_oldflashScope(other.m_oldflashScope)
, m_oldframe(other.m_oldframe)
, m_oldse(other.m_oldse) {}

Animation::Timing& Animation::Timing::operator=(const Timing& other) {
  IModifiable::operator=(other);
  m_flashColor = other.m_flashColor;
  m_flashDuration = other.m_flashDuration;
  m_flashScope = other.m_flashScope;
  m_frame = other.m_frame;
  m_se = other.m_se;
  m_oldflashColor = other.m_oldflashColor;
  m_oldflashDuration = other.m_oldflashDuration;
  m_oldframe = other.m_oldframe;
  m_oldflashScope = other.m_oldflashScope;
  m_oldse = other.m_oldse;
  return *this;
}

Animation::Timing::Timing(Timing&& other) noexcept
: IModifiable(std::move(other))
, m_flashColor(other.m_flashColor)
, m_flashDuration(other.m_flashDuration)
, m_flashScope(other.m_flashScope)
, m_frame(other.m_frame)
, m_se(std::move(other.m_se))
, m_oldflashColor(other.m_oldflashColor)
, m_oldflashDuration(other.m_oldflashDuration)
, m_oldflashScope(other.m_oldflashScope)
, m_oldframe(other.m_oldframe)
, m_oldse(std::move(other.m_oldse)) {}

Animation::Timing& Animation::Timing::operator=(Timing&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_flashColor = other.m_flashColor;
  m_flashDuration = other.m_flashDuration;
  m_oldflashScope = other.m_oldflashScope;
  m_frame = other.m_frame;
  m_se = std::move(other.m_se);
  m_oldflashColor = other.m_oldflashColor;
  m_oldflashDuration = other.m_oldflashDuration;
  m_oldframe = other.m_oldframe;
  m_oldse = std::move(other.m_oldse);
  return *this;
}

Animation::Color& Animation::Timing::flashColor() { return m_flashColor; }
const Animation::Color& Animation::Timing::flashColor() const { return m_flashColor; }

void Animation::Timing::setFlashColor(const Color& color) {
  MODIFIABLE_SET_OLD_VALUE(flashColor);
  m_flashColor = color;
  if (!signalsDisabled()) {
  emit_signal(flashColorModified(), this, color);
  }
  setModified(true);
}

int Animation::Timing::flashDuration() const { return m_flashDuration; }
void Animation::Timing::setFlashDuration(int duration) {
  MODIFIABLE_SET_OLD_VALUE(flashDuration);
  m_flashDuration = duration;
  if (!signalsDisabled()) {
  emit_signal(flashDurationModified(), this, duration);
  }
  setModified(true);
}

FlashScope Animation::Timing::flashScope() const { return m_flashScope; }
void Animation::Timing::setFlashScope(FlashScope scope) {
  MODIFIABLE_SET_OLD_VALUE(flashScope);
  m_flashScope = scope;
  if (!signalsDisabled()) {
  emit_signal(flashScopeModified(), this, scope);
  }
  setModified(true);
}

int Animation::Timing::frame() const { return m_frame; }
void Animation::Timing::setFrame(int frame) {
  MODIFIABLE_SET_OLD_VALUE(frame);
  m_frame = frame;
  if (!signalsDisabled()) {
  emit_signal(frameModified(), this, frame);
  }
  setModified(true);
}

Audio* Animation::Timing::se() {
  if (m_se) {
    return &*m_se;
  }
  return nullptr;
}
const Audio* Animation::Timing::se() const { return const_cast<Timing*>(this)->se(); }

void Animation::Timing::setSe(const Audio& se) {
  MODIFIABLE_SET_OLD_VALUE(se);
  m_se = se;
  if (!signalsDisabled()) {
  emit_signal(seModified(), this, se);
  }
  setModified(true);
}

bool Animation::Timing::showTimeLine() const { return m_show; }
void Animation::Timing::setTimeLine(bool show) { m_show = show; }
std::string Animation::Timing::getToolTip(bool alt) const {
  if (alt) {
    return std::format("Scope: {}\nRed: {}\nGreen: {}\nBlue: {}\nIntensity: {}\nDuration: {}", DecodeEnumName(m_flashScope), m_flashColor.r(), m_flashColor.g(), m_flashColor.b(),
                       m_flashColor.intensity(), m_flashDuration);
  }
  return std::format("{}\nVolume: {}\nPan: {}\nPitch: {}", m_se->name(), m_se->volume(), m_se->pan(), m_se->pitch());
}

rpgmutils::signal<void(Animation::Timing*, const Animation::Color&)>& Animation::Timing::flashColorModified() {
  if (!m_flashColorModified) {
    m_flashColorModified.emplace();
  }
  return *m_flashColorModified;
}

rpgmutils::signal<void(Animation::Timing*, int)>& Animation::Timing::flashDurationModified() {
  if (!m_flashDurationModified) {
    m_flashDurationModified.emplace();
  }
  return *m_flashDurationModified;
}
rpgmutils::signal<void(Animation::Timing*, FlashScope)>& Animation::Timing::flashScopeModified() {
  if (!m_flashScopeModified) {
    m_flashScopeModified.emplace();
  }
  return *m_flashScopeModified;
}
rpgmutils::signal<void(Animation::Timing*, int)>& Animation::Timing::frameModified() {
  if (!m_frameModified) {
    m_frameModified.emplace();
  }
  return *m_frameModified;
}
rpgmutils::signal<void(Animation::Timing*, const Audio&)>& Animation::Timing::seModified() {
  if (!m_seModified) {
    m_seModified.emplace();
  }
  return *m_seModified;
}

void Animation::Timing::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(flashColor);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(flashDuration);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(flashScope);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(frame);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(se);
}

void Animation::Timing::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(flashColor);
  MODIFIABLE_ACCEPT_VALUE(flashDuration);
  MODIFIABLE_ACCEPT_VALUE(flashScope);
  MODIFIABLE_ACCEPT_VALUE(frame);
  MODIFIABLE_ACCEPT_VALUE(se);
}

nlohmann::ordered_json Animation::Timing::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_CHILD_VALUE(flashColor),
      MODIFIABLE_SERIALIZE_VALUE(flashDuration),
      MODIFIABLE_SERIALIZE_VALUE(flashScope),
      MODIFIABLE_SERIALIZE_VALUE(frame),
      {"se", m_oldse ? m_oldse->serializeOldValues()
             : m_se  ? m_se->serializeOldValues()
                     : nullptr},
  };
}

Animation::Animation(const Animation& other)
: IModifiable(other)
, m_id(other.m_id)
, m_animation1Hue(other.m_animation1Hue)
, m_animation1Name(other.m_animation1Name)
, m_animation2Hue(other.m_animation2Hue)
, m_animation2Name(other.m_animation2Name)
, m_frames(other.m_frames)
, m_name(other.m_name)
, m_position(other.m_position)
, m_timings(other.m_timings)
, m_oldid(other.m_oldid)
, m_oldanimation1Hue(other.m_oldanimation1Hue)
, m_oldanimation1Name(other.m_oldanimation1Name)
, m_oldanimation2Hue(other.m_oldanimation2Hue)
, m_oldanimation2Name(other.m_oldanimation2Name)
, m_oldname(other.m_oldname)
, m_oldposition(other.m_oldposition)
, m_oldtimings(other.m_oldtimings)
, m_isValid(other.m_isValid) {}

Animation& Animation::operator=(const Animation& other) {
  IModifiable::operator=(other);
  m_id = other.m_id;
  m_animation1Hue = other.m_animation1Hue;
  m_animation1Name = other.m_animation1Name;
  m_animation2Hue = other.m_animation2Hue;
  m_animation2Name = other.m_animation2Name;
  m_frames = other.m_frames;
  m_name = other.m_name;
  m_position = other.m_position;
  m_timings = other.m_timings;
  m_oldid = other.m_oldid;
  m_oldanimation1Hue = other.m_oldanimation1Hue;
  m_oldanimation1Name = other.m_oldanimation1Name;
  m_oldanimation2Hue = other.m_oldanimation2Hue;
  m_oldanimation2Name = other.m_oldanimation2Name;
  m_oldposition = other.m_oldposition;
  m_oldtimings = other.m_oldtimings;
  m_isValid = other.m_isValid;
  return *this;
}

Animation::Animation(Animation&& other) noexcept
: IModifiable(std::move(other))
, m_id(other.m_id)
, m_animation1Hue(other.m_animation1Hue)
, m_animation1Name(std::move(other.m_animation1Name))
, m_animation2Hue(other.m_animation2Hue)
, m_animation2Name(std::move(other.m_animation2Name))
, m_frames(std::move(other.m_frames))
, m_name(std::move(other.m_name))
, m_position(other.m_position)
, m_timings(std::move(other.m_timings))
, m_oldid(other.m_oldid)
, m_oldanimation1Hue(other.m_oldanimation1Hue)
, m_oldanimation1Name(std::move(other.m_oldanimation1Name))
, m_oldanimation2Hue(other.m_oldanimation2Hue)
, m_oldanimation2Name(std::move(other.m_oldanimation2Name))
, m_oldname(std::move(other.m_oldname))
, m_oldposition(other.m_oldposition)
, m_oldtimings(std::move(other.m_oldtimings))
, m_isValid(other.m_isValid) {}

Animation& Animation::operator=(Animation&& other) noexcept {
  IModifiable::operator=(std::move(other));
  m_id = other.m_id;
  m_animation1Hue = other.m_animation1Hue;
  m_animation1Name = std::move(other.m_animation1Name);
  m_animation2Hue = other.m_animation2Hue;
  m_animation2Name = std::move(other.m_animation2Name);
  m_frames = std::move(other.m_frames);
  m_name = std::move(other.m_name);
  m_position = other.m_position;
  m_timings = std::move(other.m_timings);
  m_oldid = other.m_oldid;
  m_oldanimation1Hue = other.m_oldanimation1Hue;
  m_oldanimation1Name = std::move(other.m_oldanimation1Name);
  m_oldanimation2Hue = other.m_oldanimation2Hue;
  m_oldanimation2Name = std::move(other.m_oldanimation2Name);
  m_oldposition = other.m_oldposition;
  m_oldtimings = std::move(other.m_oldtimings);
  m_isValid = other.m_isValid;
  return *this;
}

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

int Animation::animation1Hue() const { return m_animation1Hue; }
void Animation::setAnimation1Hue(const int animation1Hue) {
  MODIFIABLE_SET_OLD_VALUE(animation1Hue);
  m_animation1Hue = animation1Hue;
  if (!signalsDisabled()) {
  emit_signal(animation1HueModified(), this, animation1Hue);
  }
  setModified();
}

std::string_view Animation::animation1Name() const { return m_animation1Name; }
void Animation::setAnimation1Name(const std::string_view animation1Name) {
  MODIFIABLE_SET_OLD_VALUE(animation1Name);
  m_animation1Name = animation1Name;
  if (!signalsDisabled()) {
  emit_signal(animation1NameModified(), this, m_animation1Name);
  }
  setModified();
}

int Animation::animation2Hue() const { return m_animation2Hue; }
void Animation::setAnimation2Hue(const int animation2Hue) {
  MODIFIABLE_SET_OLD_VALUE(animation2Hue);
  m_animation2Hue = animation2Hue;
  if (!signalsDisabled()) {
  emit_signal(animation2HueModified(), this, animation2Hue);
  }
  setModified();
}

std::string_view Animation::animation2Name() const { return m_animation2Name; }
void Animation::setAnimation2Name(const std::string_view animation2Name) {
  MODIFIABLE_SET_OLD_VALUE(animation2Name);
  m_animation2Name = animation2Name;
  if (!signalsDisabled()) {
  emit_signal(animation2NameModified(), this, m_animation2Name);
  }
  setModified();
}

std::vector<std::vector<Animation::FramePart>>& Animation::frames() { return m_frames; }
const std::vector<std::vector<Animation::FramePart>>& Animation::frames() const { return m_frames; }
void Animation::setFrames(const std::vector<std::vector<FramePart>>& frames) {
  MODIFIABLE_SET_OLD_VALUE(frames);
  m_frames = frames;
  if (!signalsDisabled()) {
  emit_signal(framesModified(), this, m_frames);
  }
  setModified();
}

const std::vector<Animation::FramePart>& Animation::frame(const int index) const {
  assert(index >= 0 && index < m_frames.size());
  return m_frames[index];
}

void Animation::setFrame(const int index, const std::vector<FramePart>& frame) {
  assert(index >= 0 && index < m_frames.size());
  MODIFIABLE_SET_OLD_VALUE(frames);
  m_frames[index] = frame;
  if (!signalsDisabled()) {
  emit_signal(frameModified(), this, index, frame);
  }
  setModified();
}

bool Animation::showTimeLine(int index) { return m_shows.at(index); }

void Animation::setTimeLine(const int index, bool show) { m_shows.at(index) = show; }
void Animation::setTimeLine(const std::vector<bool>& shows) { m_shows = shows; }

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

Position Animation::position() const { return m_position; }
void Animation::setPosition(const Position position) {
  MODIFIABLE_SET_OLD_VALUE(position);
  m_position = position;
  if (!signalsDisabled()) {
  emit_signal(positionModified(), this, m_position);
  }
  setModified();
}

const std::vector<Animation::Timing>& Animation::timings() const { return m_timings; }
void Animation::setTimings(const std::vector<Timing>& timings) {
  MODIFIABLE_SET_OLD_VALUE(timings);
  m_timings = timings;
  if (!signalsDisabled()) {
  emit_signal(timingsModified(), this, m_timings);
  }
  setModified();
}

Animation::Timing& Animation::timing(const int index) {
  assert(index >= 0 && index < m_timings.size());
  return m_timings[index];
}

const Animation::Timing& Animation::timing(const int index) const {
  assert(index >= 0 && index < m_timings.size());
  return m_timings[index];
}

void Animation::setTiming(const int index, const Timing& timing) {
  assert(index >= 0 && index < m_timings.size());
  MODIFIABLE_SET_OLD_VALUE(timings);
  m_timings[index] = timing;
  if (!signalsDisabled()) {
  emit_signal(timingModified(), this, index, timing);
  }
  setModified();
}
// SIGNALS
rpgmutils::signal<void(Animation*, int)>& Animation::idModified() {
  if (!m_idModified) {
    m_idModified.emplace();
  }
  return *m_idModified;
}

rpgmutils::signal<void(Animation*, int)>& Animation::animation1HueModified() {
  if (!m_animation1HueModified) {
    m_animation1HueModified.emplace();
  }
  return *m_animation1HueModified;
}
rpgmutils::signal<void(Animation*, std::string_view)>& Animation::animation1NameModified() {
  if (!m_animation1NameModified) {
    m_animation1NameModified.emplace();
  }
  return *m_animation1NameModified;
}

rpgmutils::signal<void(Animation*, int)>& Animation::animation2HueModified() {
  if (!m_animation2HueModified) {
    m_animation2HueModified.emplace();
  }
  return *m_animation2HueModified;
}

rpgmutils::signal<void(Animation*, std::string_view)>& Animation::animation2NameModified() {
  if (!m_animation2NameModified) {
    m_animation2NameModified.emplace();
  }
  return *m_animation2NameModified;
}

rpgmutils::signal<void(Animation*, const std::vector<std::vector<Animation::FramePart>>&)>& Animation::framesModified() {
  if (!m_framesModified) {
    m_framesModified.emplace();
  }
  return *m_framesModified;
}

rpgmutils::signal<void(Animation*, int, const std::vector<Animation::FramePart>&)>& Animation::frameModified() {
  if (!m_frameModified) {
    m_frameModified.emplace();
  }
  return *m_frameModified;
}

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

rpgmutils::signal<void(Animation*, Position)>& Animation::positionModified() {
  if (!m_positionModified) {
    m_positionModified.emplace();
  }
  return *m_positionModified;
}

rpgmutils::signal<void(Animation*, const std::vector<Animation::Timing>&)>& Animation::timingsModified() {
  if (!m_timingsModified) {
    m_timingsModified.emplace();
  }
  return *m_timingsModified;
}

rpgmutils::signal<void(Animation*, int, const Animation::Timing&)>& Animation::timingModified() {
  if (!m_timingModified) {
    m_timingModified.emplace();
  }
  return *m_timingModified;
}

void Animation::restoreOriginal() {
  IModifiable::restoreOriginal();
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(id);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(animation1Hue);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(animation1Name);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(animation2Hue);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(animation2Name);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(frames);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(name);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(position);
  MODIFIABLE_RESTORE_ORIGINAL_VALUE(timings);
}

void Animation::acceptChanges() {
  IModifiable::acceptChanges();
  MODIFIABLE_ACCEPT_VALUE(id);
  MODIFIABLE_ACCEPT_VALUE(animation1Hue);
  MODIFIABLE_ACCEPT_VALUE(animation1Name);
  MODIFIABLE_ACCEPT_VALUE(animation2Hue);
  MODIFIABLE_ACCEPT_VALUE(animation2Name);
  MODIFIABLE_ACCEPT_VALUE(frames);
  MODIFIABLE_ACCEPT_VALUE(name);
  MODIFIABLE_ACCEPT_VALUE(position);
  MODIFIABLE_ACCEPT_VALUE(timings);
}

nlohmann::ordered_json Animation::serializeOldValues() const {
  return {
      MODIFIABLE_SERIALIZE_VALUE(id),
      MODIFIABLE_SERIALIZE_VALUE(animation1Hue),
      MODIFIABLE_SERIALIZE_VALUE(animation1Name),
      MODIFIABLE_SERIALIZE_VALUE(animation2Hue),
      MODIFIABLE_SERIALIZE_VALUE(animation2Name),
      MODIFIABLE_SERIALIZE_VALUE(frames),
      MODIFIABLE_SERIALIZE_VALUE(name),
      MODIFIABLE_SERIALIZE_VALUE(position),
      MODIFIABLE_SERIALIZE_VALUE(timings),
  };
}

/* JSON Serialization */
void to_json(nlohmann::ordered_json& to, const Animation::Color& color) {
  to.push_back(color.m_r);
  to.push_back(color.m_g);
  to.push_back(color.m_b);
  to.push_back(color.m_intensity);
}

void from_json(const nlohmann::ordered_json& from, Animation::Color& color) {
  from.at(0).get_to(color.m_r);
  from.at(1).get_to(color.m_g);
  from.at(2).get_to(color.m_b);
  from.at(3).get_to(color.m_intensity);
}

void to_json(nlohmann::ordered_json& to, const Animation::FramePart& frame) {
  to.push_back(frame.m_pattern);
  to.push_back(frame.m_x);
  to.push_back(frame.m_y);
  to.push_back(frame.m_scale);
  to.push_back(frame.m_rotation);
  to.push_back(frame.m_mirror);
  to.push_back(frame.m_opacity);
  to.push_back(frame.m_blend);
}

void from_json(const nlohmann::ordered_json& from, Animation::FramePart& frame) {
  from.at(0).get_to(frame.m_pattern);
  from.at(1).get_to(frame.m_x);
  from.at(2).get_to(frame.m_y);
  from.at(3).get_to(frame.m_scale);
  from.at(4).get_to(frame.m_rotation);
  from.at(5).get_to(frame.m_mirror);
  from.at(6).get_to(frame.m_opacity);
  from.at(7).get_to(frame.m_blend);
}

void to_json(nlohmann::ordered_json& to, const Animation::Timing& timing) {
  to = {
      {"flashColor", timing.m_flashColor}, {"flashDuration", timing.m_flashDuration}, {"flashScope", timing.m_flashScope}, {"frame", timing.m_frame}, {"se", timing.m_se},
  };
}

void from_json(const nlohmann::ordered_json& from, Animation::Timing& timing) {
  from.at("flashColor").get_to(timing.m_flashColor);
  from.at("flashDuration").get_to(timing.m_flashDuration);
  from.at("flashScope").get_to(timing.m_flashScope);
  from.at("frame").get_to(timing.m_frame);
  from.at("se").get_to(timing.m_se);
}

void to_json(nlohmann::ordered_json& to, const Animation& animation) {
  to = {
      {"id", animation.m_id},
      {"animation1Hue", animation.m_animation1Hue},
      {"animation1Name", animation.m_animation1Name},
      {"animation2Hue", animation.m_animation2Hue},
      {"animation2Name", animation.m_animation2Name},
      {"frames", animation.m_frames},
      {"name", animation.m_name},
      {"position", animation.m_position},
      {"timings", animation.m_timings},
  };
}

void from_json(const nlohmann::ordered_json& from, Animation& animation) {
  animation.m_id = from.value("id", animation.m_id);
  animation.m_animation1Hue = from.value("animation1Hue", animation.m_animation1Hue);
  animation.m_animation1Name = from.value("animation1Name", animation.m_animation1Name);
  animation.m_animation2Hue = from.value("animation2Hue", animation.m_animation2Hue);
  animation.m_animation2Name = from.value("animation2Name", animation.m_animation2Name);
  animation.m_frames = from.value("frames", animation.m_frames);
  animation.m_name = from.value("name", animation.m_name);
  animation.m_position = from.value("position", animation.m_position);
  animation.m_timings = from.value("timings", animation.m_timings);
}


code:
#pragma once

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

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

class Animation final : public IModifiable {
  friend class AnimationsSerializer;
  friend void to_json(nlohmann::ordered_json& to, const Animation& animation);
  friend void from_json(const nlohmann::ordered_json& from, Animation& animation);

public:
  class Color final : public IModifiable {
    friend void to_json(nlohmann::ordered_json& to, const Color& color);
    friend void from_json(const nlohmann::ordered_json& from, Color& color);

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

    /**
     *
     * @return
     */
    int r() const;

    /**
     *
     * @param r
     */
    void setR(int r);

    /**
     *
     * @return
     */
    int g() const;

    /**
     *
     * @param g
     */
    void setG(int g);

    /**
     *
     * @return
     */
    int b() const;

    /**
     *
     * @param b
     */
    void setB(int b);

    /**
     *
     * @return
     */
    int intensity() const;

    /**
     *
     * @param intensity
     */
    void setIntensity(int intensity);

    // SIGNALS
    rpgmutils::signal<void(Color*, int)>& rModified();
    rpgmutils::signal<void(Color*, int)>& gModified();
    rpgmutils::signal<void(Color*, int)>& bModified();
    rpgmutils::signal<void(Color*, int)>& intensityModified();

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

  private:
    int m_r{0};
    int m_g{0};
    int m_b{0};
    int m_intensity{0};

    std::optional<int> m_oldr;
    std::optional<int> m_oldg;
    std::optional<int> m_oldb;
    std::optional<int> m_oldintensity;

    std::optional<rpgmutils::signal<void(Color*, int)>> m_rModified;
    std::optional<rpgmutils::signal<void(Color*, int)>> m_gModified;
    std::optional<rpgmutils::signal<void(Color*, int)>> m_bModified;
    std::optional<rpgmutils::signal<void(Color*, int)>> m_intensityModified;
  };

  class FramePart final : public IModifiable {
    friend void to_json(nlohmann::ordered_json& to, const FramePart& frame);
    friend void from_json(const nlohmann::ordered_json& from, FramePart& frame);

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

    /**
     *
     * @return
     */
    int pattern() const;

    /**
     *
     * @param pattern
     */
    void setPattern(int pattern);

    /**
     *
     * @return
     */
    int x() const;

    /**
     *
     * @param x
     */
    void setX(int x);

    /**
     *
     * @return
     */
    int y() const;

    /**
     *
     * @param y
     */
    void setY(int y);

    /**
     *
     * @return
     */
    int scale() const;

    /**
     *
     * @param scale
     */
    void setScale(int scale);

    /**
     *
     * @return
     */
    int rotation() const;

    /**
     *
     * @param rotation
     */
    void setRotation(int rotation);

    /**
     *
     * @return
     */
    Mirror mirror() const;

    /**
     *
     * @param mirror
     */
    void setMirror(Mirror mirror);

    /**
     *
     * @return
     */
    int opacity() const;

    /**
     *
     * @param opacity
     */
    void setOpacity(int opacity);

    /**
     *
     * @return
     */
    Blend blend() const;

    /**
     *
     * @param blend
     */
    void setBlend(Blend blend);

    /**
     *
     * @return
     */
    bool showTimeLine() const;
    void setShowTimeLine(bool show);
    std::string getToolTip();

    /* SIGNALS */
    rpgmutils::signal<void(FramePart*, int)>& patternModified();
    rpgmutils::signal<void(FramePart*, int)>& xModified();
    rpgmutils::signal<void(FramePart*, int)>& yModified();
    rpgmutils::signal<void(FramePart*, int)>& scaleModified();
    rpgmutils::signal<void(FramePart*, int)>& rotationModified();
    rpgmutils::signal<void(FramePart*, Mirror)>& mirrorModified();
    rpgmutils::signal<void(FramePart*, int)>& opacityModified();
    rpgmutils::signal<void(FramePart*, Blend)>& blendModified();

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

  private:
    int m_pattern;
    int m_x;
    int m_y;
    int m_scale;
    int m_rotation;
    Mirror m_mirror;
    int m_opacity;
    Blend m_blend;
    bool m_show{false};

    std::optional<int> m_oldpattern;
    std::optional<int> m_oldx;
    std::optional<int> m_oldy;
    std::optional<int> m_oldscale;
    std::optional<int> m_oldrotation;
    std::optional<Mirror> m_oldmirror;
    std::optional<int> m_oldopacity;
    std::optional<Blend> m_oldblend;

    std::optional<rpgmutils::signal<void(FramePart*, int)>> m_patternModified;
    std::optional<rpgmutils::signal<void(FramePart*, int)>> m_xModified;
    std::optional<rpgmutils::signal<void(FramePart*, int)>> m_yModified;
    std::optional<rpgmutils::signal<void(FramePart*, int)>> m_scaleModified;
    std::optional<rpgmutils::signal<void(FramePart*, int)>> m_rotationModified;
    std::optional<rpgmutils::signal<void(FramePart*, Mirror)>> m_mirrorModified;
    std::optional<rpgmutils::signal<void(FramePart*, int)>> m_opacityModified;
    std::optional<rpgmutils::signal<void(FramePart*, Blend)>> m_blendModified;
  };

  class Timing final : public IModifiable {
    friend void to_json(nlohmann::ordered_json& to, const Timing& timing);
    friend void from_json(const nlohmann::ordered_json& from, Timing& timing);

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

    Color& flashColor();
    const Color& flashColor() const;
    void setFlashColor(const Color& color);

    int flashDuration() const;
    void setFlashDuration(int duration);

    FlashScope flashScope() const;
    void setFlashScope(FlashScope scope);

    int frame() const;
    void setFrame(int frame);

    Audio* se();
    const Audio* se() const;
    void setSe(const Audio& se);

    bool showTimeLine() const;
    void setTimeLine(bool show);
    std::string getToolTip(bool alt) const;

    // SIGNALS
    rpgmutils::signal<void(Timing*, const Color&)>& flashColorModified();
    rpgmutils::signal<void(Timing*, int)>& flashDurationModified();
    rpgmutils::signal<void(Timing*, FlashScope)>& flashScopeModified();
    rpgmutils::signal<void(Timing*, int)>& frameModified();
    rpgmutils::signal<void(Timing*, const Audio&)>& seModified();

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

    bool isModified() const override { return IModifiable::isModified() | (se() && se()->isModified()); }

  private:
    Color m_flashColor;
    int m_flashDuration{};
    FlashScope m_flashScope{};
    int m_frame{};
    std::optional<Audio> m_se{};
    bool m_show{false};

    std::optional<Color> m_oldflashColor;
    std::optional<int> m_oldflashDuration;
    std::optional<FlashScope> m_oldflashScope;
    std::optional<int> m_oldframe;
    std::optional<Audio> m_oldse;

    std::optional<rpgmutils::signal<void(Timing*, const Color&)>> m_flashColorModified;
    std::optional<rpgmutils::signal<void(Timing*, int)>> m_flashDurationModified;
    std::optional<rpgmutils::signal<void(Timing*, FlashScope)>> m_flashScopeModified;
    std::optional<rpgmutils::signal<void(Timing*, int)>> m_frameModified;
    std::optional<rpgmutils::signal<void(Timing*, const Audio&)>> m_seModified;
  };

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

  /**
   *
   * @return
   */
  int id() const;

  /**
   *
   * @param id
   */
  void setId(int id);

  /**
   *
   * @return
   */
  int animation1Hue() const;

  /**
   *
   * @param hue
   */
  void setAnimation1Hue(int hue);

  /**
   *
   * @return
   */
  std::string_view animation1Name() const;

  /**
   *
   * @param animation1Name
   */
  void setAnimation1Name(std::string_view animation1Name);

  /**
   *
   * @return
   */
  int animation2Hue() const;

  /**
   *
   * @param hue
   */
  void setAnimation2Hue(int hue);

  /**
   *
   * @return
   */
  std::string_view animation2Name() const;

  /**
   *
   * @param animation2Name
   */
  void setAnimation2Name(std::string_view animation2Name);

  /**
   *
   * @return
   */
  std::vector<std::vector<FramePart>>& frames();
  /**
   *
   * @return
   */
  const std::vector<std::vector<FramePart>>& frames() const;

  /**
   *
   * @param frames
   */
  void setFrames(const std::vector<std::vector<FramePart>>& frames);

  /**
   *
   * @param index
   * @return
   */
  const std::vector<FramePart>& frame(int index) const;

  /**
   *
   * @param index
   * @param frame
   */
  void setFrame(int index, const std::vector<FramePart>& frame);

  /**
   *
   * @return
   */
  const std::string& name() const;

  /**
   *
   * @param name
   */
  void setName(std::string_view name);

  /**
   *
   * @return
   */
  Position position() const;

  /**
   *
   * @param position
   */
  void setPosition(Position position);

  /**
   *
   * @return
   */
  const std::vector<Timing>& timings() const;

  /**
   *
   * @param timings
   */
  void setTimings(const std::vector<Timing>& timings);

  /**
   *
   * @param index
   * @return
   */
  Timing& timing(int index);
  /**
   *
   * @param index
   * @return
   */
  const Timing& timing(int index) const;

  /**
   *
   * @param index
   * @param timing
   */
  void setTiming(int index, const Timing& timing);

  /**
   *
   *
   */
  bool showTimeLine(int index);
  /**
   *
   * @param index
   * @param show
   */
  void setTimeLine(int index, bool show);

  void setTimeLine(const std::vector<bool>& shows);

  /**
   *
   * @return
   */
  bool isValid() const { return m_isValid; }

  /**
   *
   * @param valid
   */
  void setValid(const bool valid) { m_isValid = valid; }

  // SIGNALS
  rpgmutils::signal<void(Animation*, int)>& idModified();
  rpgmutils::signal<void(Animation*, int)>& animation1HueModified();
  rpgmutils::signal<void(Animation*, std::string_view)>& animation1NameModified();
  rpgmutils::signal<void(Animation*, int)>& animation2HueModified();
  rpgmutils::signal<void(Animation*, std::string_view)>& animation2NameModified();
  rpgmutils::signal<void(Animation*, const std::vector<std::vector<FramePart>>&)>& framesModified();
  rpgmutils::signal<void(Animation*, int, const std::vector<FramePart>&)>& frameModified();
  rpgmutils::signal<void(Animation*, std::string_view)>& nameModified();
  rpgmutils::signal<void(Animation*, Position)>& positionModified();
  rpgmutils::signal<void(Animation*, const std::vector<Timing>&)>& timingsModified();
  rpgmutils::signal<void(Animation*, int, const Timing&)>& timingModified();

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

  bool isModified() const override {
    return IModifiable::isModified() |
           std::ranges::any_of(m_frames, [](const std::vector<FramePart>& parts) { return std::ranges::any_of(parts, [](const FramePart& part) { return part.isModified(); }); }) |
           std::ranges::any_of(m_timings, [](const Timing& timing) { return timing.isModified(); });
  }

private:
  int m_id = 0;
  int m_animation1Hue = 0;
  std::string m_animation1Name;
  int m_animation2Hue = 0;
  std::string m_animation2Name;
  std::vector<std::vector<FramePart>> m_frames;
  std::string m_name;
  Position m_position = Position::Head;
  std::vector<Timing> m_timings;
  std::vector<bool> m_shows;

  // !!!DO NOT CHANGE CASING!!!
  std::optional<int> m_oldid;
  std::optional<int> m_oldanimation1Hue;
  std::optional<std::string> m_oldanimation1Name;
  std::optional<int> m_oldanimation2Hue;
  std::optional<std::string> m_oldanimation2Name;
  std::optional<std::vector<std::vector<FramePart>>> m_oldframes;
  std::optional<std::string> m_oldname;
  std::optional<Position> m_oldposition;
  std::optional<std::vector<Timing>> m_oldtimings;

  /* Signals */
  std::optional<rpgmutils::signal<void(Animation*, int)>> m_idModified;
  std::optional<rpgmutils::signal<void(Animation*, int)>> m_animation1HueModified;
  std::optional<rpgmutils::signal<void(Animation*, std::string_view)>> m_animation1NameModified;
  std::optional<rpgmutils::signal<void(Animation*, int)>> m_animation2HueModified;
  std::optional<rpgmutils::signal<void(Animation*, std::string_view)>> m_animation2NameModified;
  std::optional<rpgmutils::signal<void(Animation*, const std::vector<std::vector<FramePart>>&)>> m_framesModified;
  std::optional<rpgmutils::signal<void(Animation*, int, const std::vector<FramePart>&)>> m_frameModified;
  std::optional<rpgmutils::signal<void(Animation*, std::string_view)>> m_nameModified;
  std::optional<rpgmutils::signal<void(Animation*, Position)>> m_positionModified;
  std::optional<rpgmutils::signal<void(Animation*, const std::vector<Timing>&)>> m_timingsModified;
  std::optional<rpgmutils::signal<void(Animation*, int, const Timing&)>> m_timingModified;

  /*!
   * @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& to, const Animation::Color& color);
void from_json(const nlohmann::ordered_json& from, Animation::Color& color);
void to_json(nlohmann::ordered_json& to, const Animation::FramePart& frame);
void from_json(const nlohmann::ordered_json& from, Animation::FramePart& frame);
void to_json(nlohmann::ordered_json& to, const Animation::Timing& timing);
void from_json(const nlohmann::ordered_json& from, Animation::Timing& timing);
void to_json(nlohmann::ordered_json& to, const Animation& animation);
void from_json(const nlohmann::ordered_json& from, Animation& animation);


code:
#include "Database/Animations.hpp"

#include <fstream>
#include <nlohmann/json.hpp>


code:
#pragma once
#include <string_view>

#include "Database/Animation.hpp"

class Animations final : public IModifiable {
public:
  std::vector<Animation>& animations() { return m_animations; }
  const std::vector<Animation>& animations() const { return m_animations; }

  [[nodiscard]] Animation* animation(const int id) {
    for (auto& animation : m_animations) {
      if (animation.id() == id && animation.isValid()) {
        return &animation;
      }
    }
    return nullptr;
  }

  [[nodiscard]] const Animation* animation(const int id) const {
    for (const auto& animation : m_animations) {
      if (animation.id() == id && animation.isValid()) {
        return &animation;
      }
    }

    return nullptr;
  }
  int count() const { return m_animations.size() - 1; }

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

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

private:
  std::vector<Animation> m_animations;
};