Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maniac Pictures: Support Origin, Fixed Angle and Frames for duration #2741

Merged
merged 3 commits into from
Mar 25, 2022
Merged
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
46 changes: 32 additions & 14 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2806,14 +2806,15 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { /
}
params.flip_x = (flags & 16) == 16;
params.flip_y = (flags & 32) == 32;

if ((com.parameters[1] >> 8) != 0) {
Output::Warning("Maniac ShowPicture: X/Y origin not supported");
}
params.origin = com.parameters[1] >> 8;

if (params.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) {
Output::Warning("Maniac ShowPicture: Fixed angle not supported");
params.effect_mode = lcf::rpg::SavePicture::Effect_none;
params.effect_power = ValueOrVariable(com.parameters[16] & 0xF, params.effect_power);
int divisor = ValueOrVariable((com.parameters[16] & 0xF0) >> 4, com.parameters[15]);
if (divisor == 0) {
divisor = 1;
}
params.effect_power /= divisor;
}
}
}
Expand All @@ -2832,7 +2833,15 @@ bool Game_Interpreter::CommandShowPicture(lcf::rpg::EventCommand const& com) { /
// RPG_RT will crash if you ask for a picture id greater than the limit that
// version of the engine allows. We allow an arbitrary number of pictures in Player.

Main_Data::game_pictures->Show(pic_id, params);
if (Main_Data::game_pictures->Show(pic_id, params)) {
if (params.origin > 0) {
auto& pic = Main_Data::game_pictures->GetPicture(pic_id);
if (pic.IsRequestPending()) {
pic.MakeRequestImportant();
_async_op = AsyncOp::MakeYield();
}
}
}

return true;
}
Expand Down Expand Up @@ -2889,14 +2898,15 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { /
}
params.flip_x = (flags & 16) == 16;
params.flip_y = (flags & 32) == 32;

if ((com.parameters[1] >> 8) != 0) {
Output::Warning("Maniac MovePicture: X/Y origin not supported");
}
params.origin = com.parameters[1] >> 8;

if (params.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) {
Output::Warning("Maniac MovePicture: Fixed angle not supported");
params.effect_mode = lcf::rpg::SavePicture::Effect_none;
params.effect_power = ValueOrVariable(com.parameters[16] & 0xF, params.effect_power);
int divisor = ValueOrVariable((com.parameters[16] & 0xF0) >> 4, com.parameters[15]);
if (divisor == 0) {
divisor = 1;
}
params.effect_power /= divisor;
}
}
} else {
Expand All @@ -2910,14 +2920,22 @@ bool Game_Interpreter::CommandMovePicture(lcf::rpg::EventCommand const& com) { /
params.magnify = std::max(0, std::min(params.magnify, 2000));
params.top_trans = std::max(0, std::min(params.top_trans, 100));
params.bottom_trans = std::max(0, std::min(params.bottom_trans, 100));
params.duration = std::max(0, std::min(params.duration, 10000));
params.duration = std::max(Player::IsPatchManiac() ? -10000 : 0, std::min(params.duration, 10000));

if (pic_id <= 0) {
Output::Error("MovePicture: Requested invalid picture id ({})", pic_id);
}

Main_Data::game_pictures->Move(pic_id, params);

if (params.origin > 0) {
auto& pic = Main_Data::game_pictures->GetPicture(pic_id);
if (pic.IsRequestPending()) {
pic.MakeRequestImportant();
_async_op = AsyncOp::MakeYield();
}
}

if (wait)
SetupWait(params.duration);

Expand Down
110 changes: 98 additions & 12 deletions src/game_pictures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,11 @@ bool Game_Pictures::Picture::Show(const ShowParams& params) {
SyncCurrentToFinish<true>(data);
data.start_x = data.current_x;
data.start_y = data.current_y;
data.current_rotation = 0.0;
if (data.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) {
data.current_rotation = data.finish_effect_power;
} else {
data.current_rotation = 0.0;
}
data.current_waver = 0;
data.time_left = 0;

Expand Down Expand Up @@ -228,10 +232,13 @@ bool Game_Pictures::Picture::Show(const ShowParams& params) {
data.easyrpg_flip |= params.flip_y ? lcf::rpg::SavePicture::EasyRpgFlip_y : 0;
data.easyrpg_blend_mode = params.blend_mode;

// Not saved as the coordinate system is directly transformed to "center"
origin = params.origin;

return result;
}

void Game_Pictures::Show(int id, const ShowParams& params) {
bool Game_Pictures::Show(int id, const ShowParams& params) {
auto& pic = GetPicture(id);
if (pic.Show(params)) {
if (pic.sprite && !pic.data.name.empty()) {
Expand All @@ -240,14 +247,20 @@ void Game_Pictures::Show(int id, const ShowParams& params) {
pic.sprite->SetVisible(false);
}
RequestPictureSprite(pic);
return true;
}
return false;
}

void Game_Pictures::Picture::Move(const MoveParams& params) {
const bool ignore_position = Player::IsLegacy() && data.fixed_to_map;

SetNonEffectParams(params, !ignore_position);
data.time_left = params.duration * DEFAULT_FPS / 10;
if (params.duration < 0) {
data.time_left = -params.duration;
} else {
data.time_left = params.duration * DEFAULT_FPS / 10;
}

// Note that data.effect_mode doesn't necessarily reflect the
// last effect set. Possible states are:
Expand Down Expand Up @@ -288,6 +301,10 @@ void Game_Pictures::Picture::Move(const MoveParams& params) {
data.easyrpg_flip = params.flip_x ? lcf::rpg::SavePicture::EasyRpgFlip_x : 0;
data.easyrpg_flip |= params.flip_y ? lcf::rpg::SavePicture::EasyRpgFlip_y : 0;
data.easyrpg_blend_mode = params.blend_mode;

// Not saved as the coordinate system is directly transformed to "center"
origin = params.origin;
ApplyOrigin(true);
}

void Game_Pictures::Move(int id, const MoveParams& params) {
Expand Down Expand Up @@ -338,25 +355,21 @@ void Game_Pictures::RequestPictureSprite(Picture& pic) {

FileRequestAsync* request = AsyncHandler::RequestFile("Picture", name);
request->SetGraphicFile(true);

int pic_id = pic.data.ID;

pic.request_id = request->Bind([this, pic_id](FileRequestResult*) {
OnPictureSpriteReady(pic_id);
});
pic.request_id = request->Bind(&Game_Pictures::OnPictureSpriteReady, this, pic.data.ID);
request->Start();
}


void Game_Pictures::Picture::OnPictureSpriteReady() const {
void Game_Pictures::Picture::OnPictureSpriteReady() {
auto bitmap = Cache::Picture(data.name, data.use_transparent_color);

sprite->SetBitmap(bitmap);
sprite->OnPictureShow();
sprite->SetVisible(true);

ApplyOrigin(false);
}

void Game_Pictures::OnPictureSpriteReady(int id) {
void Game_Pictures::OnPictureSpriteReady(FileRequestResult*, int id) {
auto* pic = GetPicturePtr(id);
if (EP_LIKELY(pic)) {
pic->request_id = nullptr;
Expand All @@ -368,6 +381,74 @@ void Game_Pictures::OnPictureSpriteReady(int id) {
}
}

void Game_Pictures::Picture::ApplyOrigin(bool is_move) {
if (origin == 0) {
return;
}

double x;
double y;

if (is_move) {
x = data.finish_x;
y = data.finish_y;
} else {
x = data.current_x;
y = data.current_y;
}

double width = sprite->GetWidth();
double height = sprite->GetHeight();

switch (origin) {
case 1:
// Top-Left
x += width / 2;
y += height / 2;
break;
case 2:
// Bottom-Left
x += (width / 2);
y -= (height / 2);
break;
case 3:
// Top-Right
x -= (width / 2);
y += (height / 2);
break;
case 4:
// Bottom-Right
x -= (width / 2);
y -= (height / 2);
break;
case 5:
// Top
y += (height / 2);
break;
case 6:
// Bottom
y -= (height / 2);
break;
case 7:
// Left
x += (width / 2);
break;
case 8:
// Right
x -= (width / 2);
break;
}

if (!is_move) {
data.current_x = x;
data.current_y = y;
data.start_x = x;
data.start_y = y;
}
data.finish_x = x;
data.finish_y = y;
}

void Game_Pictures::Picture::OnMapScrolled(int dx16, int dy16) {
if (data.fixed_to_map && IsOnMap()) {
// Instead of modifying the Ox/Oy offset the real position is altered
Expand Down Expand Up @@ -458,6 +539,11 @@ void Game_Pictures::Picture::Update(bool is_battle) {
data.current_waver += 8;
}

// Update fixed angle
if (data.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) {
data.current_rotation = data.current_effect_power;
}

// RPG Maker 2k3 1.12: Animated spritesheets
if (Player::IsRPG2k3E()
&& data.spritesheet_speed > 0
Expand Down
9 changes: 6 additions & 3 deletions src/game_pictures.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class Game_Pictures {
bool flip_x = false;
bool flip_y = false;
int blend_mode = 0;
int origin = 0;
};
struct ShowParams : Params {
std::string name;
Expand All @@ -79,7 +80,7 @@ class Game_Pictures {
int duration = 0;
};

void Show(int id, const ShowParams& params);
bool Show(int id, const ShowParams& params);
void Move(int id, const MoveParams& params);
void Erase(int id);
void EraseAll();
Expand All @@ -98,6 +99,7 @@ class Game_Pictures {
lcf::rpg::SavePicture data;
FileRequestBinding request_id;
bool needs_update = false;
int origin = 0;

void Update(bool is_battle);

Expand All @@ -116,7 +118,8 @@ class Game_Pictures {
bool IsRequestPending() const;
void MakeRequestImportant() const;

void OnPictureSpriteReady() const;
void OnPictureSpriteReady();
void ApplyOrigin(bool is_move);
void OnMapScrolled(int dx, int dy);
};

Expand All @@ -125,7 +128,7 @@ class Game_Pictures {

private:
void RequestPictureSprite(Picture& pic);
void OnPictureSpriteReady(int id);
void OnPictureSpriteReady(FileRequestResult*, int id);

std::vector<Picture> pictures;
std::deque<Sprite_Picture> sprites;
Expand Down
8 changes: 7 additions & 1 deletion src/sprite_picture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,13 @@ void Sprite_Picture::Draw(Bitmap& dst) {
SetOx(sr.width / 2);
SetOy(sr.height / 2);

SetAngle(data.effect_mode != lcf::rpg::SavePicture::Effect_wave ? data.current_rotation * (2 * M_PI) / 256 : 0.0);
if (data.effect_mode == lcf::rpg::SavePicture::Effect_maniac_fixed_angle) {
SetAngle(data.current_rotation * (2 * M_PI) / 360);
} else if (data.effect_mode != lcf::rpg::SavePicture::Effect_wave) {
SetAngle(data.current_rotation * (2 * M_PI) / 256);
} else {
SetAngle(0.0);
}
SetWaverPhase(data.effect_mode == lcf::rpg::SavePicture::Effect_wave ? data.current_waver * (2 * M_PI) / 256 : 0.0);
SetWaverDepth(data.effect_mode == lcf::rpg::SavePicture::Effect_wave ? data.current_effect_power * 2 : 0);

Expand Down