Skip to content

Commit

Permalink
Adding pixel scrolling support
Browse files Browse the repository at this point in the history
Removing debug code, polishing code

+ Added support for .relative and .centered options for Absolute Pixel pan. Needed to bitmask parameter[4] in order to check for those.

= Renamed a few commands
= Added comments for some functions
- Removed debug code

Adjusting the speed formula

Now it works very well, even has differnet speeds for both H and V. However since Maniac internally uses doubles for screen panning, we might have to do some more work...

Revert "Adjusting the speed formula"

This reverts commit 52fa842.

Adjusting the speed formula Again

Now everything works as it should.

Time to use doubles for everything

Corrected interpolation, and proper scrolling speed

Correct formula for absolute positioning

Absolute Cam Panning now works

Changed some naming scheme

First things to do for Pixel Scrolling

Adding support for commands

However scrolling is a bit jaggy compared to ManiacPatch
  • Loading branch information
ToolMan2k committed Jul 14, 2024
1 parent 4077070 commit 557d0ce
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 5 deletions.
37 changes: 37 additions & 0 deletions src/game_interpreter_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,15 @@ bool Game_Interpreter_Map::CommandPanScreen(lcf::rpg::EventCommand const& com) {
int speed;
bool waiting_pan_screen = false;

// Maniac has new functions for pixel scrolling, which also have X and Y offsets
bool is_maniac = Player::IsPatchManiac();
int h;
int v;
double h_speed;
double v_speed;
bool centered = false;
bool relative = false;

auto& player = *Main_Data::game_player;

switch (com.parameters[0]) {
Expand Down Expand Up @@ -631,6 +640,34 @@ bool Game_Interpreter_Map::CommandPanScreen(lcf::rpg::EventCommand const& com) {
distance /= SCREEN_TILE_SIZE;
break;
}
if (is_maniac && com.parameters.size() > 5) {
h = ValueOrVariableBitfield(com, 1, 0, 2);
v = ValueOrVariableBitfield(com, 1, 1, 3);
waiting_pan_screen = (com.parameters[4] & 0x01) != 0;
speed = ValueOrVariableBitfield(com, 1, 2, 5);
switch (com.parameters[0]) {
case 4: // Relative Pixel Pan (speed)
centered = false;
relative = true;
player.StartPixelPan(h, v, speed, false, centered, relative);
break;
case 5: // Relative Pixel Pan (interpolated)
centered = false;
relative = true;
player.StartPixelPan(h, v, speed, true, centered, relative);
break;
case 6: // Absolute Pixel Pan (speed)
centered = (com.parameters[4] & 0x02) != 0;
relative = (com.parameters[4] & 0x04) != 0;
player.StartPixelPan(h, v, speed, false, centered, relative);
break;
case 7: // Absolute Pixel Pan (interpolated)
centered = (com.parameters[4] & 0x02) != 0;
relative = (com.parameters[4] & 0x04) != 0;
player.StartPixelPan(h, v, speed, true, centered, relative);
break;
}
}

if (waiting_pan_screen) {
// RPG_RT uses the max wait for all pending pan commands, not just the current one.
Expand Down
106 changes: 101 additions & 5 deletions src/game_player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ void Game_Player::MoveTo(int map_id, int x, int y) {
data()->pan_finish_y = GetDefaultPanY();
data()->pan_current_x = GetDefaultPanX();
data()->pan_current_y = GetDefaultPanY();
maniac_pan_current_x = static_cast<double>(GetDefaultPanX());
maniac_pan_current_y = static_cast<double>(GetDefaultPanY());

ResetAnimation();

Expand Down Expand Up @@ -771,6 +773,8 @@ void Game_Player::UnlockPan() {
}

void Game_Player::StartPan(int direction, int distance, int speed) {
bool is_maniac = Player::IsPatchManiac();

distance *= SCREEN_TILE_SIZE;

if (direction == PanUp) {
Expand All @@ -787,20 +791,88 @@ void Game_Player::StartPan(int direction, int distance, int speed) {
data()->pan_finish_x = new_pan;
}

// Maniac uses separate horizontal/vertical pan doubles for everything
if (is_maniac) {
data()->maniac_horizontal_pan_speed = static_cast<double>(2 << speed);

Check failure on line 796 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'

Check failure on line 796 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'
data()->maniac_vertical_pan_speed = static_cast<double>(2 << speed);

Check failure on line 797 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'

Check failure on line 797 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'
}
data()->pan_speed = 2 << speed;
}

void Game_Player::StartPixelPan(int h, int v, int speed, bool interpolated, bool centered, bool relative) {
const bool is_maniac = Player::IsPatchManiac();

if (!is_maniac) {
return;
}

h *= TILE_SIZE;
v *= TILE_SIZE;

int new_pan_x;
int new_pan_y;

double h_speed;
double v_speed;

int pan_current_x = data()->pan_current_x;
int pan_current_y = data()->pan_current_y;
maniac_pan_current_x = static_cast<double>(pan_current_x);
maniac_pan_current_y = static_cast<double>(pan_current_y);

if (relative) {
new_pan_x = data()->pan_finish_x - h;
new_pan_y = data()->pan_finish_y - v;
} else {
if (centered) {
new_pan_x = GetSpriteX() + GetDefaultPanX() - h;
new_pan_y = GetSpriteY() + GetDefaultPanY() - v;
} else {
new_pan_x = GetSpriteX() - h;
new_pan_y = GetSpriteY() - v;
}
}

if (speed == 0) {
// Instant pan if speed is zero
h_speed = std::abs((static_cast<double>(new_pan_x) - maniac_pan_current_x));
v_speed = std::abs((static_cast<double>(new_pan_y) - maniac_pan_current_y));
} else if (interpolated) {
// Interpolate distance by number of frames
h_speed = std::abs((static_cast<double>(new_pan_x) - maniac_pan_current_x)) / (speed + 1);
v_speed = std::abs((static_cast<double>(new_pan_y) - maniac_pan_current_y)) / (speed + 1);
} else {
// Multiply speed by 0.001
h_speed = std::max(static_cast<double>(speed * TILE_SIZE * 0.001), 1.0);
v_speed = std::max(static_cast<double>(speed * TILE_SIZE * 0.001), 1.0);
}

data()->pan_finish_x = new_pan_x;
data()->pan_finish_y = new_pan_y;
data()->maniac_horizontal_pan_speed = h_speed;

Check failure on line 852 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'

Check failure on line 852 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'
data()->maniac_vertical_pan_speed = v_speed;

Check failure on line 853 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'

Check failure on line 853 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'
}

void Game_Player::ResetPan(int speed) {
bool is_maniac = Player::IsPatchManiac();
data()->pan_finish_x = GetDefaultPanX();
data()->pan_finish_y = GetDefaultPanY();
// Maniac uses separate horizontal/vertical pan doubles for everything
if (is_maniac) {
data()->maniac_horizontal_pan_speed = static_cast<double>(2 << speed);

Check failure on line 862 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'

Check failure on line 862 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'
data()->maniac_vertical_pan_speed = static_cast<double>(2 << speed);

Check failure on line 863 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'

Check failure on line 863 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'
}
data()->pan_speed = 2 << speed;
}

int Game_Player::GetPanWait() {
bool is_maniac = Player::IsPatchManiac();
const auto distance = std::max(
std::abs(data()->pan_current_x - data()->pan_finish_x),
std::abs(data()->pan_current_y - data()->pan_finish_y));
const auto speed = data()->pan_speed;
const auto speed = !is_maniac ? data()->pan_speed : static_cast<int>(std::max(
std::abs(data()->maniac_horizontal_pan_speed),

Check failure on line 874 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'

Check failure on line 874 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'
std::abs(data()->maniac_vertical_pan_speed)));

Check failure on line 875 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'

Check failure on line 875 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'
assert(speed > 0);
return distance / speed + (distance % speed != 0);
}
Expand All @@ -809,14 +881,38 @@ void Game_Player::UpdatePan() {
if (!IsPanActive())
return;

bool is_maniac = Player::IsPatchManiac();
const int step = data()->pan_speed;
const int pan_remain_x = data()->pan_current_x - data()->pan_finish_x;
const int pan_remain_y = data()->pan_current_y - data()->pan_finish_y;

int dx = std::min(step, std::abs(pan_remain_x));
dx = pan_remain_x >= 0 ? dx : -dx;
int dy = std::min(step, std::abs(pan_remain_y));
dy = pan_remain_y >= 0 ? dy : -dy;
// Maniac
const double step_x = data()->maniac_horizontal_pan_speed;

Check failure on line 890 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'

Check failure on line 890 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_horizontal_pan_speed'
const double step_y = data()->maniac_vertical_pan_speed;

Check failure on line 891 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / ubuntu:22.04

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'

Check failure on line 891 in src/game_player.cpp

View workflow job for this annotation

GitHub Actions / debian:12

'class lcf::rpg::SavePartyLocation' has no member named 'maniac_vertical_pan_speed'

int dx;
int dy;
if (is_maniac) {
// Maniac uses doubles for smoother screen scrolling
double ddx = std::min(step_x, std::abs(static_cast<double>(pan_remain_x)));
double ddy = std::min(step_y, std::abs(static_cast<double>(pan_remain_y)));

ddx = pan_remain_x >= 0 ? ddx : -ddx;
ddy = pan_remain_y >= 0 ? ddy : -ddy;

maniac_pan_current_x -= ddx;
maniac_pan_current_y -= ddy;

// Depending on the position decimal, floor or ceil the value.
dx = std::round(std::abs(maniac_pan_current_x)) == std::ceil(std::abs(maniac_pan_current_x)) ? static_cast<int>(std::floor(ddx)) : static_cast<int>(std::ceil(ddx));
dy = std::round(std::abs(maniac_pan_current_y)) == std::ceil(std::abs(maniac_pan_current_y)) ? static_cast<int>(std::floor(ddy)) : static_cast<int>(std::ceil(ddy));
} else {
dx = std::min(step, std::abs(pan_remain_x));
dy = std::min(step, std::abs(pan_remain_y));

dx = pan_remain_x >= 0 ? dx : -dx;
dy = pan_remain_y >= 0 ? dy : -dy;
}

int screen_x = Game_Map::GetPositionX();
int screen_y = Game_Map::GetPositionY();
Expand Down
5 changes: 5 additions & 0 deletions src/game_player.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,14 @@ class Game_Player : public Game_PlayerBase {
static int GetDefaultPanX();
static int GetDefaultPanY();

// Maniac uses these coordinates for smooth panning
double maniac_pan_current_x;
double maniac_pan_current_y;

void LockPan();
void UnlockPan();
void StartPan(int direction, int distance, int speed);
void StartPixelPan(int h, int v, int speed, bool interpolated, bool centered, bool relative);
void ResetPan(int speed);

/** @return how many frames it'll take to finish the current pan */
Expand Down

0 comments on commit 557d0ce

Please sign in to comment.