AnimationManager and WaveManager split (#1097)

* Move wave and animations into seperate manager

* Add game state knowledge

* Move update functions to managers

* Move reset to manager

* Cleanup and implement reset

* Implement Wave Manager update

* Hook create wave earlier to improve interface
This commit is contained in:
Duncan 2021-08-12 13:35:25 +01:00 committed by GitHub
parent cba3bd06d1
commit f2f9719b75
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 246 additions and 143 deletions

View File

@ -1,6 +1,7 @@
#include "Industry.h"
#include "Interop/Interop.hpp"
#include "Localisation/StringIds.h"
#include "Map/AnimationManager.h"
#include "Map/TileManager.h"
#include "Objects/CargoObject.h"
#include "Objects/IndustryObject.h"
@ -262,7 +263,7 @@ namespace OpenLoco
}
while (animOffsets[0].pos.x != Location::null)
{
TileManager::createAnimation(3, animOffsets->pos + tilePos, baseZ);
AnimationManager::createAnimation(3, animOffsets->pos + tilePos, baseZ);
animOffsets++;
}
}

View File

@ -16,8 +16,10 @@
#include "../Graphics/Gfx.h"
#include "../Gui.h"
#include "../Input.h"
#include "../Map/AnimationManager.h"
#include "../Map/Tile.h"
#include "../Map/TileManager.h"
#include "../Map/WaveManager.h"
#include "../Paint/Paint.h"
#include "../Platform/Platform.h"
#include "../S5/S5.h"
@ -770,7 +772,8 @@ void OpenLoco::Interop::registerHooks()
});
Ui::ProgressBar::registerHooks();
OpenLoco::Map::TileManager::registerHooks();
Map::TileManager::registerHooks();
Map::AnimationManager::registerHooks();
Ui::Windows::PromptBrowse::registerHooks();
Ui::Windows::TextInput::registerHooks();
Ui::Windows::ToolTip::registerHooks();
@ -791,15 +794,13 @@ void OpenLoco::Interop::registerHooks()
// Part of 0x004691FA
registerHook(
0x0046959C,
0x0046956E,
[](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t {
registers backup = regs;
int16_t x = regs.eax;
int16_t i = regs.ebx / 6;
int16_t y = regs.ecx;
Map::Pos2 pos(regs.ax, regs.cx);
Map::SurfaceElement* surface = X86Pointer<Map::SurfaceElement>(regs.esi);
surface->createWave(x, y, i);
WaveManager::createWave(*surface, pos);
regs = backup;
return 0;

View File

@ -0,0 +1,65 @@
#include "AnimationManager.h"
#include "../Interop/Interop.hpp"
using namespace OpenLoco::Interop;
namespace OpenLoco::Map::AnimationManager
{
#pragma pack(push, 1)
struct TileAnimation
{
uint8_t baseZ;
uint8_t type;
Map::Pos2 pos;
};
static_assert(sizeof(TileAnimation) == 6);
#pragma pack(pop)
constexpr size_t maxAnimations = 0x2000;
static loco_global<TileAnimation[maxAnimations], 0x0094C6DC> _animations;
static loco_global<uint16_t, 0x00525F6C> _numAnimations;
// 0x004612A6
void createAnimation(uint8_t type, const Pos2& pos, tile_coord_t baseZ)
{
if (_numAnimations >= maxAnimations)
return;
for (size_t i = 0; i < _numAnimations; i++)
{
auto& animation = _animations[i];
if (animation.type == type && animation.pos == pos && animation.baseZ == baseZ)
{
return;
}
}
auto& newAnimation = _animations[_numAnimations++];
newAnimation.baseZ = baseZ;
newAnimation.type = type;
newAnimation.pos = pos;
}
// 0x00461166
void reset()
{
_numAnimations = 0;
}
// 0x004612EC
void update()
{
call(0x004612EC);
}
void registerHooks()
{
registerHook(
0x004612A6,
[](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t {
createAnimation(regs.dh, { regs.ax, regs.cx }, regs.dl);
return 0;
});
}
}

View File

@ -0,0 +1,10 @@
#pragma once
#include "Map.hpp"
namespace OpenLoco::Map::AnimationManager
{
void createAnimation(uint8_t type, const Pos2& pos, tile_coord_t baseZ);
void reset();
void update();
void registerHooks();
}

View File

@ -3,6 +3,7 @@
#include "../StationManager.h"
#include "../TownManager.h"
#include "../ViewportManager.h"
#include "AnimationManager.h"
#include "Tile.h"
#include "TileManager.h"
@ -64,7 +65,7 @@ namespace OpenLoco::Map
setClearZ(newClearHeight);
if (buildingObj->var_AD != 0)
{
TileManager::createAnimation(5, loc, baseZ());
AnimationManager::createAnimation(5, loc, baseZ());
}
if (buildingObj->flags & BuildingObjectFlags::large_tile)
{

View File

@ -1,65 +0,0 @@
#include "../IndustryManager.h"
#include "../Interop/Interop.hpp"
#include "../Ui/WindowManager.h"
#include "../ViewportManager.h"
#include "Tile.h"
#include "TileManager.h"
using namespace OpenLoco;
using namespace OpenLoco::Interop;
using namespace OpenLoco::Ui;
#pragma pack(push, 1)
struct unk1
{
uint16_t x; // 0x00
uint16_t y; // 0x02
uint16_t frame; // 0x04
};
#pragma pack(pop)
static loco_global<Utility::prng, 0x00525E20> _prng;
static loco_global<unk1[64], 0x009586DC> _9586DC;
static loco_global<int32_t, 0x00e3f0b8> gCurrentRotation;
static Pos2 _offsets[4] = {
Pos2(+32, 0),
Pos2(-32, 0),
Pos2(0, +32),
Pos2(0, -32),
};
// 0x0046959C
void Map::SurfaceElement::createWave(int16_t x, int16_t y, int animationIndex)
{
auto coord2D = gameToScreen(Pos3(x + 16, y + 16, this->water() * 16), gCurrentRotation);
auto w = WindowManager::findWindowShowing(coord2D);
if (w == nullptr)
return;
uint16_t dx2 = _prng->randNext() & 0xFFFF;
if (dx2 > 0x1745)
return;
// Check whether surrounding tiles are water
for (auto offset : _offsets)
{
if (x + offset.x > 0x2FFF)
return;
if (y + offset.y > 0x2FFF)
return;
auto tile = Map::TileManager::get(x + offset.x, y + offset.y);
if (tile.isNull())
return;
auto surface = tile.surface();
if (surface->water() == 0)
return;
}
_9586DC[animationIndex].x = x;
_9586DC[animationIndex].y = y;
_9586DC[animationIndex].frame = 0;
this->setFlag6(true);
ViewportManager::invalidate({ x, y }, this->water() * 16, this->water() * 16, ZoomLevel::full);
}

View File

@ -175,7 +175,6 @@ namespace OpenLoco::Map
_type &= ~0x40;
_type |= state ? 0x40 : 0;
}
void createWave(int16_t x, int16_t y, int animationIndex);
bool hasHighTypeFlag() const { return _type & 0x80; }
void setHighTypeFlag(bool state)
{

View File

@ -10,19 +10,6 @@ using namespace OpenLoco::Interop;
namespace OpenLoco::Map::TileManager
{
#pragma pack(push, 1)
struct TileAnimation
{
uint8_t baseZ;
uint8_t type;
Map::Pos2 pos;
};
static_assert(sizeof(TileAnimation) == 6);
#pragma pack(pop)
constexpr size_t maxAnimations = 0x2000;
static loco_global<TileElement*, 0x005230C8> _elements;
static loco_global<TileElement* [0x30004], 0x00E40134> _tiles;
static loco_global<TileElement*, 0x00F00134> _elementsEnd;
@ -32,8 +19,6 @@ namespace OpenLoco::Map::TileManager
static loco_global<coord_t, 0x00F2448C> _mapSelectionBY;
static loco_global<uint16_t, 0x00F2448E> _word_F2448E;
static loco_global<int16_t, 0x0050A000> _adjustToolSize;
static loco_global<uint16_t, 0x00525F6C> _numAnimations;
static loco_global<TileAnimation[maxAnimations], 0x0094C6DC> _animations;
static loco_global<Map::Pos2, 0x00525F6E> _startUpdateLocation;
constexpr uint16_t mapSelectedTilesSize = 300;
@ -524,33 +509,6 @@ namespace OpenLoco::Map::TileManager
}
}
// 0x004612A6
void createAnimation(uint8_t type, const Pos2& pos, tile_coord_t baseZ)
{
if (_numAnimations >= maxAnimations)
return;
for (size_t i = 0; i < _numAnimations; i++)
{
auto& animation = _animations[i];
if (animation.type == type && animation.pos == pos && animation.baseZ == baseZ)
{
return;
}
}
auto& newAnimation = _animations[_numAnimations++];
newAnimation.baseZ = baseZ;
newAnimation.type = type;
newAnimation.pos = pos;
}
// 0x00461166
void resetAnimations()
{
_numAnimations = 0;
}
// 0x004C5596
uint16_t countSurroundingWaterTiles(const Pos2& pos)
{
@ -695,13 +653,6 @@ namespace OpenLoco::Map::TileManager
void registerHooks()
{
registerHook(
0x004612A6,
[](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t {
createAnimation(regs.dh, { regs.ax, regs.cx }, regs.dl);
return 0;
});
// This hook can be removed once sub_4599B3 has been implemented
registerHook(
0x004BE048,

View File

@ -31,8 +31,6 @@ namespace OpenLoco::Map::TileManager
void setMapSelectionCorner(const uint8_t corner);
uint8_t getMapSelectionCorner();
void resetSurfaceClearance();
void createAnimation(uint8_t type, const Pos2& pos, tile_coord_t baseZ);
void resetAnimations();
uint16_t countSurroundingWaterTiles(const Pos2& pos);
uint16_t countSurroundingTrees(const Pos2& pos);
void update();

View File

@ -0,0 +1,124 @@
#include "WaveManager.h"
#include "../Core/LocoFixedVector.hpp"
#include "../Interop/Interop.hpp"
#include "../Ui/WindowManager.h"
#include "../Utility/Prng.hpp"
#include "../ViewportManager.h"
#include "TileManager.h"
namespace OpenLoco::Map::WaveManager
{
using namespace OpenLoco::Interop;
using namespace OpenLoco::Ui;
#pragma pack(push, 1)
struct Wave
{
Map::Pos2 loc; // 0x00
uint16_t frame; // 0x04
bool empty() const
{
return loc.x == Location::null;
}
};
#pragma pack(pop)
static loco_global<Wave[64], 0x009586DC> _waves;
static loco_global<Utility::prng, 0x00525E20> _prng; // not the gPrng
const static Pos2 _offsets[4] = {
Pos2(+32, 0),
Pos2(-32, 0),
Pos2(0, +32),
Pos2(0, -32),
};
static LocoFixedVector<Wave> waves()
{
return LocoFixedVector<Wave>(_waves);
}
// 0x0046956E
void createWave(SurfaceElement& surface, const Map::Pos2& pos)
{
const auto waveIndex = getWaveIndex(pos);
if (!_waves[getWaveIndex(pos)].empty())
{
return;
}
auto vpPoint = gameToScreen(Pos3(pos.x + 16, pos.y + 16, surface.water() * 16), WindowManager::getCurrentRotation());
auto w = WindowManager::findWindowShowing(vpPoint);
if (w == nullptr)
return;
uint16_t dx2 = _prng->randNext() & 0xFFFF;
if (dx2 > 0x1745)
return;
// Check whether surrounding tiles are water
for (const auto& offset : _offsets)
{
auto searchLoc = pos + offset;
if (!Map::validCoords(searchLoc))
return;
const auto tile = TileManager::get(searchLoc);
if (tile.isNull())
return;
const auto* nearbySurface = tile.surface();
if (nearbySurface == nullptr)
return;
if (nearbySurface->water() == 0)
return;
}
_waves[waveIndex].loc = pos;
_waves[waveIndex].frame = 0;
surface.setFlag6(true);
ViewportManager::invalidate(pos, surface.water() * 16, surface.water() * 16, ZoomLevel::full);
}
// 0x004C56F6
void update()
{
if (!(addr<0x00525E28, uint32_t>() & 1) || (scenarioTicks() & 0x3))
{
return;
}
for (auto& wave : waves())
{
auto tile = TileManager::get(wave.loc);
auto* surface = tile.surface();
if (surface == nullptr)
{
wave.loc.x = Location::null;
continue;
}
ViewportManager::invalidate(wave.loc, surface->water() * 4, surface->water() * 4, ZoomLevel::full);
if (surface->water())
{
wave.frame++;
if (wave.frame < 16)
{
continue;
}
}
// Wave removed if 16 frames or no water
wave.loc.x = Location::null;
surface->setFlag6(false);
}
}
// 0x004C4BC0
void reset()
{
for (auto& wave : _waves)
{
wave.loc.x = Location::null;
}
}
}

View File

@ -0,0 +1,14 @@
#pragma once
#include "Tile.h"
namespace OpenLoco::Map::WaveManager
{
void update();
void reset();
void createWave(SurfaceElement& surface, const Map::Pos2& pos);
constexpr uint8_t getWaveIndex(const Map::TilePos2& pos)
{
return (pos.x & 0x7) | ((pos.y & 0x7) << 3);
}
}

View File

@ -43,7 +43,9 @@
#include "Localisation/LanguageFiles.h"
#include "Localisation/Languages.h"
#include "Localisation/StringIds.h"
#include "Map/AnimationManager.h"
#include "Map/TileManager.h"
#include "Map/WaveManager.h"
#include "MultiPlayer.h"
#include "Objects/ObjectManager.h"
#include "OpenLoco.h"
@ -810,12 +812,6 @@ namespace OpenLoco
}
}
// 0x004612EC
static void invalidate_map_animations()
{
call(0x004612EC);
}
static void sub_46FFCA()
{
addr<0x010E7D3C, uint32_t>() = 0x2A0015;
@ -845,7 +841,7 @@ namespace OpenLoco
addr<0x00F25374, uint8_t>() = S5::getOptions().madeAnyChanges;
dateTick();
Map::TileManager::update();
call(0x004C56F6);
WaveManager::update();
TownManager::update();
IndustryManager::update();
EntityManager::updateVehicles();
@ -854,7 +850,7 @@ namespace OpenLoco
EntityManager::updateMiscEntities();
sub_46FFCA();
CompanyManager::update();
invalidate_map_animations();
AnimationManager::update();
Audio::updateVehicleNoise();
Audio::updateAmbientNoise();
Title::update();

View File

@ -185,6 +185,11 @@ namespace OpenLoco::S5
uint8_t pad_0[0x6];
};
struct Wave
{
uint8_t pad_0[0x6];
};
struct TileElement
{
private:
@ -256,7 +261,10 @@ namespace OpenLoco::S5
Station stations[1024]; // 0x0C10C4 (0x005E6EDC)
Entity entities[20000]; // 0x1B58C4 (0x006DB6DC)
Animation animations[8192]; // 0x4268C4 (0x0094C6DC)
uint8_t pad_4328C4[0x6DD80]; // 0x4328C4 (0x009586DC)
Wave waves[64]; // 0x4328C4 (0x009586DC)
uint8_t userStrings[2048][32]; // 0x432A44 (0x0095885C)
uint16_t routings[1000][64]; // 0x442A44 (0x0096885C)
uint8_t orders[256000]; // 0x461E44 (0x0096885C)
};
#pragma pack(pop)
static_assert(sizeof(GameState) == 0x4A0644);

View File

@ -7,8 +7,10 @@
#include "IndustryManager.h"
#include "Interop/Interop.hpp"
#include "Localisation/StringIds.h"
#include "Map/AnimationManager.h"
#include "Map/MapGenerator.h"
#include "Map/TileManager.h"
#include "Map/WaveManager.h"
#include "Objects/CargoObject.h"
#include "Objects/ClimateObject.h"
#include "S5/S5.h"
@ -47,16 +49,10 @@ namespace OpenLoco::Scenario
void sub_46115C()
{
addr<0x00525E28, uint32_t>() = 0;
TileManager::resetAnimations();
AnimationManager::reset();
addr<0x0052624C, uint16_t>() = S5::S5FixFlags::fixFlag0 | S5::S5FixFlags::fixFlag1;
}
// 0x004C4BC0
static void sub_4C4BC0()
{
call(0x004C4BC0);
}
Season nextSeason(Season season)
{
switch (season)
@ -180,7 +176,7 @@ namespace OpenLoco::Scenario
Ui::Windows::Construction::Construction::reset();
sub_46115C();
sub_4C4BC0();
WaveManager::reset();
initialiseDate(1900);
initialiseSnowLine();

View File

@ -63,10 +63,12 @@
<ClCompile Include="Localisation\StringManager.cpp" />
<ClCompile Include="Localisation\Unicode.cpp" />
<ClCompile Include="Map\BuildingTile.cpp" />
<ClCompile Include="Map\AnimationManager.cpp" />
<ClCompile Include="Map\MapGenerator.cpp" />
<ClCompile Include="Map\SurfaceTile.cpp" />
<ClCompile Include="Map\Tile.cpp" />
<ClCompile Include="Map\TileManager.cpp" />
<ClCompile Include="Map\WaveManager.cpp" />
<ClCompile Include="Math\Trigonometry.cpp" />
<ClCompile Include="Math\Vector.cpp" />
<ClCompile Include="MessageManager.cpp" />
@ -261,11 +263,13 @@
<ClInclude Include="Localisation\StringIds.h" />
<ClInclude Include="Localisation\Unicode.h" />
<ClInclude Include="Location.hpp" />
<ClInclude Include="Map\AnimationManager.h" />
<ClInclude Include="Map\Map.hpp" />
<ClInclude Include="Map\MapGenerator.h" />
<ClInclude Include="Map\Tile.h" />
<ClInclude Include="Map\TileLoop.hpp" />
<ClInclude Include="Map\TileManager.h" />
<ClInclude Include="Map\WaveManager.h" />
<ClInclude Include="Math\Bound.hpp" />
<ClInclude Include="Math\Trigonometry.hpp" />
<ClInclude Include="Math\Vector.hpp" />
@ -396,4 +400,4 @@
<_NuGetTargetFallbackMoniker>$(_NuGetTargetFallbackMoniker);native,Version=v0.0</_NuGetTargetFallbackMoniker>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>