Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/rwe/LoadingScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,8 @@ namespace rwe
sounds.okToBuild = lookUpSound("OKTOBUILD");
sounds.notOkToBuild = lookUpSound("NOTOKTOBUILD");
sounds.selectMultipleUnits = lookUpSound("SelectMultipleUnits");
sounds.panel = lookUpSound("Panel");
sounds.options = lookUpSound("Options");

auto consoleFont = sceneContext.textureService->getFont("fonts/CONSOLE.FNT");
// The original loads exactly two in-game fonts (0x42A320): COMIX for
Expand Down
3 changes: 2 additions & 1 deletion src/rwe/game/GameScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ namespace rwe
}

updateMusic();
updatePanelSlide();

// Pause halts simulation tick dispatch by not advancing the
// scaled-time accumulator. Speed scales the accumulator using
Expand Down Expand Up @@ -415,7 +416,7 @@ namespace rwe
// convert that to the world, then set the camera's position to there
// (clamped to map bounds)

auto minimapToWorld = minimapToWorldMatrix(simulation.terrain, minimapRect);
auto minimapToWorld = minimapToWorldMatrix(simulation.terrain, slidMinimapRect());
auto mousePos = getMousePosition();
auto worldPos = minimapToWorld * Vector3f(static_cast<float>(mousePos.x) + 0.5f, static_cast<float>(mousePos.y) + 0.5, 0.0f);

Expand Down
21 changes: 21 additions & 0 deletions src/rwe/game/GameScene.h
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,22 @@ namespace rwe
bool leftShiftDown{false};
bool rightShiftDown{false};

/**
* The side panel's slide, 0 with the panel in place and
* PanelSlideExtent with it slid off the left edge. F4 latches it
* away; holding Space slides it away while the key is down and the
* cursor is not on the panel itself. The original's updater
* (0x4948E0, TOTALA-EXE.md "the panel-slide updater") moves it a
* quarter of the remaining distance a frame and never less than a
* pixel, plays the Panel sound as it leaves an end and Options as it
* arrives at one, and 125 is the panel's width less its border.
* Presentation only: the world viewport grows under it.
*/
static constexpr int PanelSlideExtent = 125;
int panelSlide{0};
bool panelSlideLatched{false};
bool spaceDown{false};

struct CameraControlStateFree
{
};
Expand Down Expand Up @@ -845,6 +861,11 @@ namespace rwe
void addBattlePoints(int points);
void updateMusic();

/** Steps the side panel's slide one frame; see panelSlide. */
void updatePanelSlide();
/** The minimap's rectangle where it is drawn this frame, slid with the panel. */
Rectangle2f slidMinimapRect() const;

/** What size the world render textures were made at, so a window resize remakes them. */
std::pair<unsigned int, unsigned int> worldRenderTextureSize{0, 0};

Expand Down
2 changes: 1 addition & 1 deletion src/rwe/game/GameScene_commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ namespace rwe
bool GameScene::isCursorOverMinimap() const
{
auto mousePos = getMousePosition();
return minimapRect.contains(mousePos.x, mousePos.y);
return slidMinimapRect().contains(mousePos.x, mousePos.y);
}

bool GameScene::isCursorOverWorld() const
Expand Down
77 changes: 77 additions & 0 deletions src/rwe/game/GameScene_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,19 @@ namespace rwe
{
showDebugWindow = !showDebugWindow;
}
else if (keysym.key == SDLK_F4)
{
// Toggles bit 7 of the display-options word (0x49639D), the one
// bit of it with no registry name: the side panel slides away
// and stays away until the next press. See panelSlide.
panelSlideLatched = !panelSlideLatched;
}
else if (keysym.key == SDLK_SPACE)
{
// Polled, not dispatched, in the original (0x494942): while it
// is held the panel slides away, and back when it is let go.
spaceDown = true;
}
else if (keysym.key == SDLK_F1)
{
helpVisible = !helpVisible;
Expand Down Expand Up @@ -425,6 +438,70 @@ namespace rwe
{
rightShiftDown = false;
}
else if (keysym.key == SDLK_SPACE)
{
spaceDown = false;
}
}

void GameScene::updatePanelSlide()
{
// 0x4948E0. With the F4 bit set the position runs to the extent;
// with it clear it runs to zero, unless Space is held and the cursor
// is not on the panel's own gadget, which runs it to the extent
// again. Each frame moves a quarter of what is left, never less
// than a pixel, so the panel starts fast and eases in.
auto mouse = getMousePosition();
auto overPanel = mouse.x >= 0 && mouse.x < GuiSizeLeft - panelSlide;
auto wantHidden = panelSlideLatched || (spaceDown && !overPanel);

auto before = panelSlide;
if (wantHidden && panelSlide < PanelSlideExtent)
{
if (panelSlide == 0 && sounds.panel)
{
playUiSound(*sounds.panel);
}
panelSlide += std::max(1, (PanelSlideExtent - panelSlide) / 4);
if (panelSlide >= PanelSlideExtent)
{
panelSlide = PanelSlideExtent;
if (sounds.options)
{
playUiSound(*sounds.options);
}
}
}
else if (!wantHidden && panelSlide > 0)
{
if (panelSlide == PanelSlideExtent && sounds.panel)
{
playUiSound(*sounds.panel);
}
panelSlide -= std::max(1, panelSlide / 4);
if (panelSlide <= 0)
{
panelSlide = 0;
if (sounds.options)
{
playUiSound(*sounds.options);
}
}
}

if (panelSlide != before && guiVisible)
{
worldViewport.setInset(GuiSizeLeft - panelSlide, GuiSizeTop, GuiSizeRight, GuiSizeBottom);
}
if (currentPanel)
{
currentPanel->setPosition(-panelSlide, currentPanel->getY());
}
}

Rectangle2f GameScene::slidMinimapRect() const
{
return Rectangle2f::fromTopLeft(minimapRect.left() - static_cast<float>(panelSlide), minimapRect.top(), minimapRect.width(), minimapRect.height());
}

void GameScene::onMouseDown(MouseButtonEvent event)
Expand Down
11 changes: 6 additions & 5 deletions src/rwe/game/GameScene_render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,15 +528,16 @@ namespace rwe

void GameScene::renderMinimap()
{
auto minimapDrawRect = slidMinimapRect();
// draw minimap
chromeUiRenderService.drawSpriteAbs(minimapRect, *minimap);
chromeUiRenderService.drawSpriteAbs(minimapDrawRect, *minimap);
if (fogSprite)
{
chromeUiRenderService.drawSpriteAbs(minimapRect, *fogSprite);
chromeUiRenderService.drawSpriteAbs(minimapDrawRect, *fogSprite);
}

auto cameraInverse = computeInverseViewProjectionMatrix(worldCameraState, worldViewport.width(), worldViewport.height());
auto worldToMinimap = worldToMinimapMatrix(simulation.terrain, minimapRect);
auto worldToMinimap = worldToMinimapMatrix(simulation.terrain, minimapDrawRect);

// draw minimap dots
for (const auto& [unitId, unit] : simulation.units)
Expand Down Expand Up @@ -743,7 +744,7 @@ namespace rwe
}

chromeUiRenderService.drawLines(
buildMinimapRing(Vector2f(centre.x, centre.y), radius, minimapRect, false, 0),
buildMinimapRing(Vector2f(centre.x, centre.y), radius, slidMinimapRect(), false, 0),
color);
}
}
Expand Down Expand Up @@ -804,7 +805,7 @@ namespace rwe
auto parity = dashed && ((sceneTime.value / minimapBlinkTicks) % 2 == 1) ? 1 : 0;

chromeUiRenderService.drawLines(
buildMinimapRing(Vector2f(centre.x, centre.y), radius, minimapRect, dashed, parity),
buildMinimapRing(Vector2f(centre.x, centre.y), radius, slidMinimapRect(), dashed, parity),
Color(255, 255, 255));
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/rwe/game/InGameSoundsInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ namespace rwe
std::optional<AudioService::SoundHandle> notOkToBuild;

std::optional<AudioService::SoundHandle> selectMultipleUnits;
/** The side panel leaving an end of its slide, and arriving at one. */
std::optional<AudioService::SoundHandle> panel;
std::optional<AudioService::SoundHandle> options;
};
}
7 changes: 7 additions & 0 deletions src/rwe/ui/UiComponent.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ namespace rwe
int getX() { return posX; }
int getY() { return posY; }

/** Moves the component; a panel's children move with it, drawn and hit-tested alike. */
void setPosition(int x, int y)
{
posX = x;
posY = y;
}

virtual void mouseDown(MouseButtonEvent /*event*/) {}

virtual void mouseUp(MouseButtonEvent /*event*/) {}
Expand Down