Skip to content

Commit

Permalink
Feature: Multiple rotating views on title screen
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsmh committed Sep 5, 2021
1 parent 9c74dc2 commit 26d2973
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 2 deletions.
164 changes: 164 additions & 0 deletions src/intro_gui.cpp
Expand Up @@ -11,12 +11,14 @@
#include "error.h"
#include "gui.h"
#include "window_gui.h"
#include "window_func.h"
#include "textbuf_gui.h"
#include "network/network.h"
#include "genworld.h"
#include "network/network_gui.h"
#include "network/network_content.h"
#include "landscape_type.h"
#include "landscape.h"
#include "strings_func.h"
#include "fios.h"
#include "ai/ai_gui.hpp"
Expand All @@ -25,6 +27,10 @@
#include "language.h"
#include "rev.h"
#include "highscore.h"
#include "signs_base.h"
#include "viewport_func.h"
#include "vehicle_base.h"
#include <regex>

#include "widgets/intro_widget.h"

Expand All @@ -33,13 +39,171 @@

#include "safeguards.h"


struct IntroGameViewportCommand {
enum AlignmentH : byte {
LEFT,
CENTRE,
RIGHT,
};
enum AlignmentV : byte {
TOP,
MIDDLE,
BOTTOM,
};

int command_index;
Point position;
VehicleID vehicle;
uint delay;
int zoom_adjust;
bool pan_to_next;
AlignmentH align_h;
AlignmentV align_v;

IntroGameViewportCommand() : command_index(0), vehicle(INVALID_VEHICLE), delay(0), zoom_adjust(0), pan_to_next(false), align_h(CENTRE), align_v(MIDDLE)
{
}

Point PositionForViewport(const Viewport *vp)
{
if (this->vehicle != INVALID_VEHICLE) {
const Vehicle *v = Vehicle::Get(this->vehicle);
this->position = RemapCoords(v->x_pos, v->y_pos, v->z_pos);
}

Point p;
switch (this->align_h) {
case LEFT: p.x = this->position.x; break;
case CENTRE: p.x = this->position.x - vp->virtual_width / 2; break;
case RIGHT: p.x = this->position.x - vp->virtual_width; break;
}
switch (this->align_v) {
case TOP: p.y = this->position.y; break;
case MIDDLE: p.y = this->position.y - vp->virtual_height / 2; break;
case BOTTOM: p.y = this->position.y - vp->virtual_height; break;
}
return p;
}
};


struct SelectGameWindow : public Window {
std::vector<IntroGameViewportCommand> intro_viewport_commands;
size_t cur_viewport_command_index;
uint cur_viewport_command_time;

void ReadIntroGameViewportCommands()
{
intro_viewport_commands.clear();

const char *sign_langauge = "^T\\s*([0-9]+)\\s*([-+A-Z0-9]+)\\s*([0-9]+)";
std::regex re(sign_langauge, std::regex_constants::icase);

std::vector<SignID> signs_to_delete;

for (const Sign *sign : Sign::Iterate()) {
std::smatch match;
if (std::regex_search(sign->name, match, re)) {
IntroGameViewportCommand vc;
vc.command_index = std::stoi(match[1].str());
vc.position = RemapCoords(sign->x, sign->y, sign->z);
vc.delay = std::stoi(match[3].str()) * 1000; // milliseconds

enum IdType {
ID_NONE, ID_VEHICLE
} id_type = ID_NONE;
for (char c : match[2].str()) {
if (isdigit(c)) {
if (id_type == ID_VEHICLE) {
vc.vehicle = vc.vehicle * 10 + (c - '0');
}
} else {
id_type = ID_NONE;
switch (toupper(c)) {
case '-': vc.zoom_adjust = +1; break;
case '+': vc.zoom_adjust = -1; break;
case 'T': vc.align_v = IntroGameViewportCommand::TOP; break;
case 'M': vc.align_v = IntroGameViewportCommand::MIDDLE; break;
case 'B': vc.align_v = IntroGameViewportCommand::BOTTOM; break;
case 'L': vc.align_h = IntroGameViewportCommand::LEFT; break;
case 'C': vc.align_h = IntroGameViewportCommand::CENTRE; break;
case 'R': vc.align_h = IntroGameViewportCommand::RIGHT; break;
case 'P': vc.pan_to_next = true; break;
case 'V': id_type = ID_VEHICLE; vc.vehicle = 0; break;
}
}
}

intro_viewport_commands.push_back(vc);
signs_to_delete.push_back(sign->index);
}
}

std::sort(intro_viewport_commands.begin(), intro_viewport_commands.end(), [](const IntroGameViewportCommand &a, const IntroGameViewportCommand &b) { return a.command_index < b.command_index; });

/* Delete all the consumed signs, from last ID to first ID */
std::sort(signs_to_delete.begin(), signs_to_delete.end(), [](SignID a, SignID b) { return a > b; });
for (SignID sign_id : signs_to_delete) {
delete Sign::Get(sign_id);
}
}

SelectGameWindow(WindowDesc *desc) : Window(desc)
{
this->CreateNestedTree();
this->FinishInitNested(0);
this->OnInvalidateData();

this->ReadIntroGameViewportCommands();

this->cur_viewport_command_index = (size_t)-1;
this->cur_viewport_command_time = 0;
}

void OnRealtimeTick(uint delta_ms) override
{
if (intro_viewport_commands.empty()) return;

bool changed_command = false;
if (this->cur_viewport_command_index >= intro_viewport_commands.size()) {
this->cur_viewport_command_index = 0;
changed_command = true;
} else {
this->cur_viewport_command_time += delta_ms;
if (this->cur_viewport_command_time >= intro_viewport_commands[this->cur_viewport_command_index].delay) {
this->cur_viewport_command_index = (this->cur_viewport_command_index + 1) % intro_viewport_commands.size();
this->cur_viewport_command_time = 0;
changed_command = true;
}
}

IntroGameViewportCommand &vc = intro_viewport_commands[this->cur_viewport_command_index];
Window *mw = FindWindowByClass(WC_MAIN_WINDOW);
Viewport *vp = mw->viewport;

if (!changed_command && !vc.pan_to_next && vc.vehicle == INVALID_VEHICLE) return;

if (changed_command) FixTitleGameZoom(vc.zoom_adjust);

Point pos = vc.PositionForViewport(vp);

if (vc.pan_to_next) {
size_t next_command_index = (this->cur_viewport_command_index + 1) % intro_viewport_commands.size();
IntroGameViewportCommand &nvc = intro_viewport_commands[next_command_index];
Point pos2 = nvc.PositionForViewport(vp);
const double t = this->cur_viewport_command_time / (double)vc.delay;
pos.x = pos.x + (int)(t * (pos2.x - pos.x));
pos.y = pos.y + (int)(t * (pos2.y - pos.y));
}

mw->viewport->dest_scrollpos_x = mw->viewport->scrollpos_x = pos.x;
mw->viewport->dest_scrollpos_y = mw->viewport->scrollpos_y = pos.y;
UpdateViewportPosition(mw);
mw->SetDirty();

/* If there is only one command, we just executed it and don't need to do any more */
if (intro_viewport_commands.size() == 1 && vc.vehicle == INVALID_VEHICLE) intro_viewport_commands.clear();
}

/**
Expand Down
12 changes: 11 additions & 1 deletion src/main_gui.cpp
Expand Up @@ -152,12 +152,22 @@ void ZoomInOrOutToCursorWindow(bool in, Window *w)
}
}

void FixTitleGameZoom()
void FixTitleGameZoom(int zoom_adjust)
{
if (_game_mode != GM_MENU) return;

Viewport *vp = FindWindowByClass(WC_MAIN_WINDOW)->viewport;

vp->zoom = _gui_zoom;
while (zoom_adjust < 0 && vp->zoom != ZOOM_LVL_MIN) {
vp->zoom--;
zoom_adjust++;
}
while (zoom_adjust > 0 && vp->zoom != ZOOM_LVL_MAX) {
vp->zoom++;
zoom_adjust--;
}

vp->virtual_width = ScaleByZoom(vp->width, vp->zoom);
vp->virtual_height = ScaleByZoom(vp->height, vp->zoom);
}
Expand Down
2 changes: 1 addition & 1 deletion src/viewport_func.h
Expand Up @@ -32,7 +32,7 @@ bool MarkAllViewportsDirty(int left, int top, int right, int bottom);
bool DoZoomInOutWindow(ZoomStateChange how, Window *w);
void ZoomInOrOutToCursorWindow(bool in, Window * w);
Point GetTileZoomCenterWindow(bool in, Window * w);
void FixTitleGameZoom();
void FixTitleGameZoom(int zoom_adjust = 0);
void HandleZoomMessage(Window *w, const Viewport *vp, byte widget_zoom_in, byte widget_zoom_out);

/**
Expand Down

0 comments on commit 26d2973

Please sign in to comment.