mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 05:38:56 +00:00
AGS: Share animation cycling algo between Buttons and RoomObjects
From upstream fd28a2548e39c85478d98e26b51713cd687acada
This commit is contained in:
parent
3a01a16e12
commit
09d4069428
@ -25,6 +25,7 @@
|
||||
#include "ags/shared/ac/view.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/engine/ac/global_translation.h"
|
||||
#include "ags/engine/ac/object.h"
|
||||
#include "ags/engine/ac/string.h"
|
||||
#include "ags/engine/ac/view_frame.h"
|
||||
#include "ags/engine/debugging/debug_log.h"
|
||||
@ -43,6 +44,15 @@ using namespace AGS::Shared;
|
||||
|
||||
// *** BUTTON FUNCTIONS
|
||||
|
||||
// Update the actual button's image from the current animation frame
|
||||
void UpdateButtonState(const AnimatingGUIButton &abtn) {
|
||||
_GP(guibuts)[abtn.buttonid].Image = _GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].pic;
|
||||
_GP(guibuts)[abtn.buttonid].CurrentImage = _GP(guibuts)[abtn.buttonid].Image;
|
||||
_GP(guibuts)[abtn.buttonid].PushedImage = 0;
|
||||
_GP(guibuts)[abtn.buttonid].MouseOverImage = 0;
|
||||
_GP(guibuts)[abtn.buttonid].NotifyParentChanged();
|
||||
}
|
||||
|
||||
void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat, int blocking, int direction, int sframe) {
|
||||
int guin = butt->ParentId;
|
||||
int objn = butt->Id;
|
||||
@ -73,24 +83,17 @@ void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat
|
||||
// if it's already animating, stop it
|
||||
FindAndRemoveButtonAnimation(guin, objn);
|
||||
|
||||
// Prepare button
|
||||
int buttonId = _GP(guis)[guin].GetControlID(objn);
|
||||
_GP(guibuts)[buttonId].PushedImage = 0;
|
||||
_GP(guibuts)[buttonId].MouseOverImage = 0;
|
||||
|
||||
// reverse animation starts at the *previous frame*
|
||||
if (direction) {
|
||||
if (--sframe < 0)
|
||||
sframe = _GP(views)[view].loops[loop].numFrames - (-sframe);
|
||||
sframe++; // set on next frame, first call to Update will decrement
|
||||
} else {
|
||||
sframe--; // set on prev frame, first call to Update will increment
|
||||
}
|
||||
|
||||
int but_id = _GP(guis)[guin].GetControlID(objn);
|
||||
AnimatingGUIButton abtn;
|
||||
abtn.ongui = guin;
|
||||
abtn.onguibut = objn;
|
||||
abtn.buttonid = buttonId;
|
||||
abtn.buttonid = but_id;
|
||||
abtn.view = view;
|
||||
abtn.loop = loop;
|
||||
abtn.speed = speed;
|
||||
@ -98,14 +101,11 @@ void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat
|
||||
abtn.blocking = blocking;
|
||||
abtn.direction = direction;
|
||||
abtn.frame = sframe;
|
||||
abtn.wait = 0;
|
||||
abtn.wait = abtn.speed + _GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].speed;
|
||||
_GP(animbuts).push_back(abtn);
|
||||
// launch into the first frame
|
||||
if (UpdateAnimatingButton(_GP(animbuts).size() - 1)) {
|
||||
debug_script_warn("AnimateButton: no frames to animate (button: %s, view: %d, loop: %d)",
|
||||
butt->GetScriptName().GetCStr(), view, loop);
|
||||
StopButtonAnimation(_GP(animbuts).size() - 1);
|
||||
}
|
||||
// launch into the first frame, and play the first frame's sound
|
||||
UpdateButtonState(abtn);
|
||||
CheckViewFrame(abtn.view, abtn.loop, abtn.frame);
|
||||
|
||||
// Blocking animate
|
||||
if (blocking)
|
||||
@ -243,59 +243,19 @@ void AddButtonAnimation(const AnimatingGUIButton &abtn) {
|
||||
}
|
||||
|
||||
// returns 1 if animation finished
|
||||
int UpdateAnimatingButton(int bu) {
|
||||
bool UpdateAnimatingButton(int bu) {
|
||||
AnimatingGUIButton &abtn = _GP(animbuts)[bu];
|
||||
|
||||
if (abtn.wait > 0) {
|
||||
abtn.wait--;
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
ViewStruct *tview = &_GP(views)[abtn.view];
|
||||
|
||||
if (abtn.direction) { // backwards
|
||||
abtn.frame--;
|
||||
if (abtn.frame < 0) {
|
||||
if ((abtn.loop > 0) && tview->loops[abtn.loop - 1].RunNextLoop()) {
|
||||
// go to next loop
|
||||
abtn.loop--;
|
||||
abtn.frame = tview->loops[abtn.loop].numFrames - 1;
|
||||
} else if (abtn.repeat) {
|
||||
// multi-loop anim, go back
|
||||
while (tview->loops[abtn.loop].RunNextLoop())
|
||||
abtn.loop++;
|
||||
abtn.frame = tview->loops[abtn.loop].numFrames - 1;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
} else { // forwards
|
||||
abtn.frame++;
|
||||
if (abtn.frame >= tview->loops[abtn.loop].numFrames) {
|
||||
if (tview->loops[abtn.loop].RunNextLoop()) {
|
||||
// go to next loop
|
||||
abtn.loop++;
|
||||
abtn.frame = 0;
|
||||
} else if (abtn.repeat) {
|
||||
abtn.frame = 0;
|
||||
// multi-loop anim, go back
|
||||
while ((abtn.loop > 0) &&
|
||||
(tview->loops[abtn.loop - 1].RunNextLoop()))
|
||||
abtn.loop--;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CycleViewAnim(abtn.view, abtn.loop, abtn.frame, !abtn.direction,
|
||||
abtn.repeat != 0 ? ANIM_REPEAT : ANIM_ONCE))
|
||||
return false;
|
||||
CheckViewFrame(abtn.view, abtn.loop, abtn.frame);
|
||||
|
||||
// update the button's image
|
||||
_GP(guibuts)[abtn.buttonid].Image = tview->loops[abtn.loop].frames[abtn.frame].pic;
|
||||
_GP(guibuts)[abtn.buttonid].CurrentImage = _GP(guibuts)[abtn.buttonid].Image;
|
||||
_GP(guibuts)[abtn.buttonid].PushedImage = 0;
|
||||
_GP(guibuts)[abtn.buttonid].MouseOverImage = 0;
|
||||
_GP(guibuts)[abtn.buttonid].NotifyParentChanged();
|
||||
|
||||
abtn.wait = abtn.speed + tview->loops[abtn.loop].frames[abtn.frame].speed;
|
||||
return 0;
|
||||
abtn.wait = abtn.speed + _GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].speed;
|
||||
UpdateButtonState(abtn);
|
||||
return true;
|
||||
}
|
||||
|
||||
void StopButtonAnimation(int idxn) {
|
||||
|
@ -48,7 +48,8 @@ void Button_SetPushedGraphic(GUIButton *guil, int slotn);
|
||||
int Button_GetTextColor(GUIButton *butt);
|
||||
void Button_SetTextColor(GUIButton *butt, int newcol);
|
||||
|
||||
int UpdateAnimatingButton(int bu);
|
||||
// Update button's animation, returns whether the animation continues
|
||||
bool UpdateAnimatingButton(int bu);
|
||||
size_t GetAnimatingButtonCount();
|
||||
AnimatingGUIButton *GetAnimatingButtonByIndex(int idxn);
|
||||
void AddButtonAnimation(const AnimatingGUIButton &abtn);
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "ags/engine/ac/route_finder.h"
|
||||
#include "ags/engine/gfx/graphics_driver.h"
|
||||
#include "ags/shared/ac/view.h"
|
||||
#include "ags/engine/ac/view_frame.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/shared/gfx/gfx_def.h"
|
||||
#include "ags/shared/gui/gui_main.h"
|
||||
@ -552,6 +553,72 @@ int check_click_on_object(int roomx, int roomy, int mood) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// General view animation algorithm: find next loop and frame, depending on anim settings
|
||||
bool CycleViewAnim(int view, uint16_t &o_loop, uint16_t &o_frame, bool forwards, int repeat) {
|
||||
// Allow multi-loop repeat: idk why, but original engine behavior
|
||||
// was to only check this for forward animation, not backward
|
||||
const bool multi_loop_repeat = !forwards || (_GP(play).no_multiloop_repeat == 0);
|
||||
|
||||
ViewStruct *aview = &_GP(views)[view];
|
||||
uint16_t loop = o_loop;
|
||||
uint16_t frame = o_frame;
|
||||
bool done = false;
|
||||
|
||||
if (forwards) {
|
||||
if (frame + 1 >= aview->loops[loop].numFrames) { // Reached the last frame in the loop, find out what to do next
|
||||
if (aview->loops[loop].RunNextLoop()) {
|
||||
// go to next loop
|
||||
loop++;
|
||||
frame = 0;
|
||||
} else {
|
||||
// If either ANIM_REPEAT or ANIM_ONCERESET:
|
||||
// reset to the beginning of a multiloop animation
|
||||
if (repeat != ANIM_ONCE) {
|
||||
frame = 0;
|
||||
if (multi_loop_repeat)
|
||||
while ((loop > 0) && (aview->loops[loop - 1].RunNextLoop()))
|
||||
loop--;
|
||||
} else { // if ANIM_ONCE, stop at the last frame
|
||||
frame = aview->loops[loop].numFrames - 1;
|
||||
}
|
||||
|
||||
if (repeat != ANIM_REPEAT) // either ANIM_ONCE or ANIM_ONCERESET
|
||||
done = true; // finished animation
|
||||
}
|
||||
} else
|
||||
frame++;
|
||||
} else // backwards
|
||||
{
|
||||
if (frame == 0) { // Reached the first frame in the loop, find out what to do next
|
||||
if ((loop > 0) && aview->loops[loop - 1].RunNextLoop()) {
|
||||
// go to next loop
|
||||
loop--;
|
||||
frame = aview->loops[loop].numFrames - 1;
|
||||
} else {
|
||||
// If either ANIM_REPEAT or ANIM_ONCERESET:
|
||||
// reset to the beginning of a multiloop animation
|
||||
if (repeat != ANIM_ONCE) {
|
||||
if (multi_loop_repeat)
|
||||
while (aview->loops[loop].RunNextLoop())
|
||||
loop++;
|
||||
frame = aview->loops[loop].numFrames - 1;
|
||||
} else { // if ANIM_ONCE, stop at the first frame
|
||||
frame = 0;
|
||||
}
|
||||
|
||||
if (repeat != ANIM_REPEAT) // either ANIM_ONCE or ANIM_ONCERESET
|
||||
done = true; // finished animation
|
||||
}
|
||||
} else
|
||||
frame--;
|
||||
}
|
||||
|
||||
// Update object values
|
||||
o_loop = loop;
|
||||
o_frame = frame;
|
||||
return !done; // have we finished animating?
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Script API Functions
|
||||
|
@ -102,6 +102,10 @@ int is_pos_in_sprite(int xx, int yy, int arx, int ary, Shared::Bitmap *sprit
|
||||
// X and Y co-ordinates must be in native format
|
||||
// X and Y are ROOM coordinates
|
||||
int check_click_on_object(int roomx, int roomy, int mood);
|
||||
// General view animation algorithm: find next loop and frame, depending on anim settings;
|
||||
// loop and frame values are passed by reference and will be updated;
|
||||
// returns whether the animation should continue.
|
||||
bool CycleViewAnim(int view, uint16_t &loop, uint16_t &frame, bool forwards, int repeat);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "ags/shared/ac/common_defines.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/engine/ac/game_state.h"
|
||||
#include "ags/engine/ac/object.h"
|
||||
#include "ags/engine/ac/runtime_defines.h"
|
||||
#include "ags/engine/ac/view_frame.h"
|
||||
#include "ags/engine/debugging/debug_log.h"
|
||||
@ -79,24 +80,15 @@ void RoomObject::UpdateCyclingView(int ref_id) {
|
||||
if (cycling == 0) return;
|
||||
if (view == (uint16_t)-1) return;
|
||||
if (wait > 0) {
|
||||
wait--;
|
||||
return;
|
||||
wait--; return;
|
||||
}
|
||||
|
||||
if (cycling >= ANIM_BACKWARDS) {
|
||||
|
||||
update_cycle_view_backwards();
|
||||
|
||||
} else { // Animate forwards
|
||||
|
||||
update_cycle_view_forwards();
|
||||
|
||||
} // end if forwards
|
||||
cycling = CycleViewAnim(view, loop, frame, cycling < ANIM_BACKWARDS, cycling % ANIM_BACKWARDS);
|
||||
|
||||
ViewFrame *vfptr = &_GP(views)[view].loops[loop].frames[frame];
|
||||
if (vfptr->pic > UINT16_MAX)
|
||||
debug_script_warn("Warning: object's (id %d) sprite %d is outside of internal range (%d), reset to 0",
|
||||
ref_id, vfptr->pic, UINT16_MAX);
|
||||
ref_id, vfptr->pic, UINT16_MAX);
|
||||
num = Math::InRangeOrDef<uint16_t>(vfptr->pic, 0);
|
||||
|
||||
if (cycling == 0)
|
||||
@ -106,54 +98,6 @@ void RoomObject::UpdateCyclingView(int ref_id) {
|
||||
CheckViewFrame(view, loop, frame);
|
||||
}
|
||||
|
||||
|
||||
void RoomObject::update_cycle_view_forwards() {
|
||||
frame++;
|
||||
if (frame >= _GP(views)[view].loops[loop].numFrames) {
|
||||
// go to next loop thing
|
||||
if (_GP(views)[view].loops[loop].RunNextLoop()) {
|
||||
if (loop + 1 >= _GP(views)[view].numLoops)
|
||||
quit("!Last loop in a view requested to move to next loop");
|
||||
loop++;
|
||||
frame = 0;
|
||||
} else if (cycling % ANIM_BACKWARDS == ANIM_ONCE) {
|
||||
// leave it on the last frame
|
||||
cycling = 0;
|
||||
frame--;
|
||||
} else {
|
||||
if (_GP(play).no_multiloop_repeat == 0) {
|
||||
// multi-loop anims, go back to start of it
|
||||
while ((loop > 0) &&
|
||||
(_GP(views)[view].loops[loop - 1].RunNextLoop()))
|
||||
loop--;
|
||||
}
|
||||
if (cycling % ANIM_BACKWARDS == ANIM_ONCERESET)
|
||||
cycling = 0;
|
||||
frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RoomObject::update_cycle_view_backwards() {
|
||||
// animate backwards
|
||||
if (frame > 0) {
|
||||
frame--;
|
||||
} else {
|
||||
if ((loop > 0) &&
|
||||
(_GP(views)[view].loops[loop - 1].RunNextLoop())) {
|
||||
// If it's a Go-to-next-loop on the previous one, then go back
|
||||
loop--;
|
||||
frame = _GP(views)[view].loops[loop].numFrames - 1;
|
||||
} else if (cycling % ANIM_BACKWARDS == ANIM_ONCE) {
|
||||
// leave it on the first frame
|
||||
cycling = 0;
|
||||
frame = 0;
|
||||
} else { // repeating animation
|
||||
frame = _GP(views)[view].loops[loop].numFrames - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RoomObject::ReadFromSavegame(Stream *in, int save_ver) {
|
||||
x = in->ReadInt32();
|
||||
y = in->ReadInt32();
|
||||
|
@ -79,8 +79,6 @@ struct RoomObject {
|
||||
}
|
||||
|
||||
void UpdateCyclingView(int ref_id);
|
||||
void update_cycle_view_forwards();
|
||||
void update_cycle_view_backwards();
|
||||
|
||||
void ReadFromSavegame(Shared::Stream *in, int save_ver);
|
||||
void WriteToSavegame(Shared::Stream *out) const;
|
||||
|
@ -90,8 +90,11 @@ const int LegacyRoomVolumeFactor = 30;
|
||||
#define CHANIM_REPEAT 2
|
||||
#define CHANIM_BACKWARDS 4
|
||||
#define ANIM_BACKWARDS 10
|
||||
// Animates once and stops at the *last* frame
|
||||
#define ANIM_ONCE 1
|
||||
// Animates infinitely until stopped by command
|
||||
#define ANIM_REPEAT 2
|
||||
// Animates once and stops, resetting to the very first frame
|
||||
#define ANIM_ONCERESET 3
|
||||
#define FONT_STATUSBAR 0
|
||||
#define FONT_NORMAL _GP(play).normal_font
|
||||
|
@ -19,9 +19,13 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// Description of a button animation; stored separately from the GUI button.
|
||||
//
|
||||
|
||||
#ifndef AGS_ENGINE_GUI_ANIMATING_GUI_BUTTON_H
|
||||
#define AGS_ENGINE_GUI_ANIMATING_GUI_BUTTON_H
|
||||
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/engine/ac/runtime_defines.h"
|
||||
|
||||
namespace AGS3 {
|
||||
@ -38,7 +42,7 @@ struct AnimatingGUIButton {
|
||||
// index into _GP(guibuts) array, GUI, button
|
||||
short buttonid = 0, ongui = 0, onguibut = 0;
|
||||
// current animation status
|
||||
short view = 0, loop = 0, frame = 0;
|
||||
uint16_t view = 0, loop = 0, frame = 0;
|
||||
short speed = 0, repeat = 0, blocking = 0,
|
||||
direction = 0, wait = 0;
|
||||
|
||||
|
@ -594,7 +594,7 @@ static void game_loop_update_animated_buttons() {
|
||||
// this bit isn't in update_stuff because it always needs to
|
||||
// happen, even when the game is paused
|
||||
for (size_t i = 0; i < GetAnimatingButtonCount(); ++i) {
|
||||
if (UpdateAnimatingButton(i)) {
|
||||
if (!UpdateAnimatingButton(i)) {
|
||||
StopButtonAnimation(i);
|
||||
i--;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user