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

Allow animated pictures in special dialogs #640

Merged
merged 7 commits into from
Mar 6, 2025
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
4 changes: 2 additions & 2 deletions rsrc/strings/specials-text-general.txt
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,10 @@ Picture number
Picture type
Unused
Unused
Animation Loops (-2 for infinite)
Unused
Unused
Unused
Unused
Animation FPS (-1 for default 2)
Special to Jump To

--------------------
Expand Down
12 changes: 6 additions & 6 deletions rsrc/strings/specials-text-once.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ Picture number
Picture type
Label of 2nd button (-1 - no button)
Special if button 2 pressed
Unused
Animation Loops (-2 for infinite)
Label of 3rd button (-1 - no button)
Special if button 3 pressed
Unused
Animation FPS (-1 for default 2)
Special if OK/Leave picked

--------------------
Expand Down Expand Up @@ -144,10 +144,10 @@ Picture number
Picture type
Item to give
Amount of gold to give
Unused
Animation Loops (-2 for infinite)
Amount of food to give
Special if item IS taken
Unused
Animation FPS (-1 for default 2)
Special to Jump To

--------------------
Expand Down Expand Up @@ -229,10 +229,10 @@ Picture number
Picture type
Type of trap
Trap severity (0 .. 3)
Unused
Animation Loops (-2 for infinite)
Penalty (0 .. 100, higher is harder)
(Custom only) Special node for effect
Unused
Animation FPS (-1 for default 2)
Special after trap finished

--------------------
12 changes: 6 additions & 6 deletions rsrc/strings/specials-text-town.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ Unused
First part of message
Second part of message
Unused
pic
pictype
Unused
Unused
X coordinate of space
Y coordinate of space
extra 1c
Expand Down Expand Up @@ -314,10 +314,10 @@ Picture number
Picture type
Unused
If Pulled, call this special ...
Animation Loops (-2 for infinite)
Unused
Unused
Unused
Unused
Animation FPS (-1 for default 2)
Special to Jump To

--------------------
Expand All @@ -331,10 +331,10 @@ Picture number
Picture type
X coordinate to telep. to
Y coordinate to telep. to
Animation Loops (-2 for infinite)
Unused
Unused
Unused
Unused
Animation FPS (-1 for default 2)
Special to Jump To

--------------------
Expand Down
9 changes: 5 additions & 4 deletions src/dialogxml/dialogs/dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ cKey cControl::parseKey(string what){
return key;
}

cDialog::cDialog(cDialog* p) : parent(p) {}
cDialog::cDialog(cDialog* p) : parent(p), doAnimations(defaultDoAnimations) {}

cDialog::cDialog(const DialogDefn& file, cDialog* p) : parent(p) {
cDialog::cDialog(const DialogDefn& file, cDialog* p) : parent(p), doAnimations(defaultDoAnimations) {
loadFromFile(file);
}

Expand Down Expand Up @@ -494,6 +494,7 @@ bool cDialog::sendInput(cKey key) {
}

void cDialog::run(std::function<void(cDialog&)> onopen){
cPict::resetAnim();
cDialog* formerTop = topWindow;
// TODO: The introduction of the static topWindow means I may be able to use this instead of parent->win; do I still need parent?
sf::RenderWindow* parentWin = &(parent ? parent->win : mainPtr);
Expand Down Expand Up @@ -1074,12 +1075,12 @@ xBadVal::~xBadVal() throw(){
if(msg != nullptr) delete[] msg;
}

bool cDialog::doAnimations = false;
bool cDialog::defaultDoAnimations = false;

void cDialog::draw(){
win.setActive(false);
tileImage(win,winRect,::bg[bg]);
if(doAnimations && animTimer.getElapsedTime().asMilliseconds() >= 500) {
if(doAnimations && animTimer.getElapsedTime().asMilliseconds() >= (1000 / anim_pict_fps)) {
cPict::advanceAnim();
animTimer.restart();
}
Expand Down
6 changes: 5 additions & 1 deletion src/dialogxml/dialogs/dialog.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class cDialog : public iComponent, public iNameGiver {
std::vector<std::pair<std::string,cTextField*>> tabOrder;
static cDialog* topWindow; // Tracks the frontmost dialog.
static bool initCalled;
int anim_pict_fps = 2;
bool doAnimations;
public:
static void (*redraw_everything)();
/// Performs essential startup initialization. Generally should not be called directly.
Expand Down Expand Up @@ -239,7 +241,7 @@ class cDialog : public iComponent, public iNameGiver {
/// @return true if there was a dialog opened to send to.
static bool sendInput(cKey key);
/// Sets whether to animate graphics in dialogs.
static bool doAnimations;
static bool defaultDoAnimations;
/// Adds a new control described by the passed XML element.
/// @tparam Ctrl The type of control to add.
/// @param who The XML element describing the control.
Expand All @@ -261,6 +263,8 @@ class cDialog : public iComponent, public iNameGiver {
}
cDialog& operator=(cDialog& other) = delete;
cDialog(cDialog& other) = delete;
inline void setAnimPictFPS(int fps) { if(fps == -1) fps = 2; anim_pict_fps = fps; }
inline void setDoAnimations(bool value) { doAnimations = value; }
private:
void draw();
void handle_events();
Expand Down
84 changes: 61 additions & 23 deletions src/dialogxml/widgets/pict.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,7 +726,7 @@ void cPict::drawPresetTer(short num, rectangle to_rect){
}

void cPict::drawPresetTerAnim(short num, rectangle to_rect){
rectangle from_rect = calc_rect(4 * (num / 5) + animFrame % 4, num % 5);
rectangle from_rect = calc_rect(4 * (num / 5) + (animLoops != 0 ? animFrame % 4 : 0), num % 5);
auto from_gw = getSheet(SHEET_TER_ANIM);
if(!from_gw) return;
if(to_rect.right - to_rect.left > 28) {
Expand All @@ -736,8 +736,9 @@ void cPict::drawPresetTerAnim(short num, rectangle to_rect){
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect);
}

static rectangle calcDefMonstRect(short i, short animFrame){
static rectangle calcDefMonstRect(short i, short animFrame, short animLoops){
rectangle r = calc_rect(2 * (i / 10), i % 10);
if(animLoops == 0) animFrame = 0;
switch(animFrame % 4){ // Sequence is right-facing, attack, left-facing, attack
case 1:
r.offset(112,0);
Expand All @@ -757,7 +758,8 @@ void cPict::drawPresetMonstSm(short num, rectangle to_rect){
auto from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
m_start_pic = m_start_pic % 20;
rectangle from_rect = calcDefMonstRect(m_start_pic, animFrame);
updateAnim(4);
rectangle from_rect = calcDefMonstRect(m_start_pic, animFrame, animLoops);
to_rect.right = to_rect.left + 28;
to_rect.bottom = to_rect.top + 36;
if(filled) fill_rect(getWindow(), to_rect, sf::Color::Black);
Expand All @@ -772,14 +774,15 @@ void cPict::drawPresetMonstWide(short num, rectangle to_rect){
short m_start_pic = m_pic_index[num].i;
auto from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
rectangle from_rect = calcDefMonstRect(m_start_pic % 20, animFrame);
updateAnim(4);
rectangle from_rect = calcDefMonstRect(m_start_pic % 20, animFrame, animLoops);
small_monst_rect.offset(to_rect.left,to_rect.top + 7);
rect_draw_some_item(*from_gw, from_rect, getWindow(), small_monst_rect, sf::BlendAlpha);

m_start_pic = m_pic_index[num].i + 1;
from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame);
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame, animLoops);
small_monst_rect.offset(14,0);
rect_draw_some_item(*from_gw, from_rect, getWindow(), small_monst_rect, sf::BlendAlpha);
}
Expand All @@ -793,14 +796,15 @@ void cPict::drawPresetMonstTall(short num, rectangle to_rect){
short m_start_pic = m_pic_index[num].i;
auto from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
rectangle from_rect = calcDefMonstRect(m_start_pic % 20, animFrame);
updateAnim(4);
rectangle from_rect = calcDefMonstRect(m_start_pic % 20, animFrame, animLoops);
small_monst_rect.offset(to_rect.left + 7,to_rect.top);
rect_draw_some_item(*from_gw, from_rect, getWindow(), small_monst_rect, sf::BlendAlpha);

m_start_pic = m_pic_index[num].i + 1;
from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame);
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame, animLoops);
small_monst_rect.offset(0,18);
rect_draw_some_item(*from_gw, from_rect, getWindow(), small_monst_rect, sf::BlendAlpha);
}
Expand All @@ -814,28 +818,29 @@ void cPict::drawPresetMonstLg(short num, rectangle to_rect){
short m_start_pic = m_pic_index[num].i;
auto from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
rectangle from_rect = calcDefMonstRect(m_start_pic % 20, animFrame);
updateAnim(4);
rectangle from_rect = calcDefMonstRect(m_start_pic % 20, animFrame, animLoops);
small_monst_rect.offset(to_rect.left,to_rect.top);
rect_draw_some_item(*from_gw, from_rect, getWindow(), small_monst_rect, sf::BlendAlpha);

m_start_pic = m_pic_index[num].i + 1;
from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame);
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame, animLoops);
small_monst_rect.offset(14,0);
rect_draw_some_item(*from_gw, from_rect, getWindow(), small_monst_rect, sf::BlendAlpha);

m_start_pic = m_pic_index[num].i + 2;
from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame);
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame, animLoops);
small_monst_rect.offset(-14,18);
rect_draw_some_item(*from_gw, from_rect, getWindow(), small_monst_rect, sf::BlendAlpha);

m_start_pic = m_pic_index[num].i + 3;
from_gw = getSheet(SHEET_MONST, m_start_pic / 20);
if(!from_gw) return;
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame);
from_rect = calcDefMonstRect(m_start_pic % 20, animFrame, animLoops);
small_monst_rect.offset(14,0);
rect_draw_some_item(*from_gw, from_rect, getWindow(), small_monst_rect, sf::BlendAlpha);
}
Expand Down Expand Up @@ -930,16 +935,34 @@ void cPict::drawPresetField(short num, rectangle to_rect){
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
}

void cPict::setAnimLoops(short value) {
// -2 is infinite loops. Anything else <= 0 is no animation.
if(value >= 0 || value == -2) animLoops = value;
else animLoops = 0;
}

void cPict::updateAnim(short loop_frames) {
if(prevAnimFrame != animFrame){
if(animFrame % loop_frames == 0 && animLoops > 0)
--animLoops;
prevAnimFrame = animFrame;
}
}

void cPict::drawPresetBoom(short num, rectangle to_rect){
auto from_gw = getSheet(SHEET_BOOM);
if(num >= 8)
if(num >= 8){
num = 8 * (num - 7) + animFrame % 8;
updateAnim(8);
}
rectangle from_rect = calc_rect(num % 8, num / 8);
// TODO: Be smarter about this - we know the first row is static booms and subsequent rows are animated booms.
to_rect.right = to_rect.left + 28;
to_rect.bottom = to_rect.top + 36;
if(filled) fill_rect(getWindow(), to_rect, sf::Color::Black);
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
// When missile loops are over, draw nothing
if(animLoops != 0)
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
}

void cPict::drawFullSheet(short num, rectangle to_rect){
Expand All @@ -959,9 +982,13 @@ void cPict::drawPresetMissile(short num, rectangle to_rect){
to_rect.right = to_rect.left + 18;
to_rect.bottom = to_rect.top + 18;
if(filled) fill_rect(getWindow(), to_rect, sf::Color::Black);
short i = animFrame % 8;
from_rect.offset(18 * i, 18 * num);
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
updateAnim(8);
// When missile loops are over, draw nothing
if(animLoops != 0){
short i = animFrame % 8;
from_rect.offset(18 * i, 18 * num);
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
}
}

void cPict::drawPresetTerMap(short num, rectangle to_rect){
Expand Down Expand Up @@ -1002,7 +1029,8 @@ void cPict::drawCustomTer(short num, rectangle to_rect){
void cPict::drawCustomTerAnim(short num, rectangle to_rect){
to_rect.right = to_rect.left + 28;
to_rect.bottom = to_rect.top + 36;
num += animFrame % 4;
updateAnim(4);
num += (animLoops != 0 ? animFrame % 4 : 0);
rectangle from_rect;
std::shared_ptr<const sf::Texture> from_gw;
graf_pos_ref(from_gw, from_rect) = spec_scen_g.find_graphic(num);
Expand All @@ -1011,7 +1039,8 @@ void cPict::drawCustomTerAnim(short num, rectangle to_rect){

void cPict::drawCustomMonstSm(short num, rectangle to_rect){
static const short adj[4] = {0, 2, 1, 3};
num += adj[animFrame % 4];
updateAnim(4);
num += adj[(animLoops != 0 ? animFrame % 4 : 0)];
to_rect.right = to_rect.left + 28;
to_rect.bottom = to_rect.top + 36;
if(filled) fill_rect(getWindow(), to_rect, sf::Color::Black);
Expand All @@ -1024,7 +1053,8 @@ void cPict::drawCustomMonstSm(short num, rectangle to_rect){

void cPict::drawCustomMonstWide(short num, rectangle to_rect){
static const short adj[4] = {0, 4, 2, 6};
num += adj[animFrame % 4];
updateAnim(4);
num += adj[(animLoops != 0 ? animFrame % 4 : 0)];
rectangle small_monst_rect = {0,0,18,14};
to_rect.right = to_rect.left + 28;
to_rect.bottom = to_rect.top + 36;
Expand All @@ -1043,7 +1073,8 @@ void cPict::drawCustomMonstWide(short num, rectangle to_rect){

void cPict::drawCustomMonstTall(short num, rectangle to_rect){
static const short adj[4] = {0, 4, 2, 6};
num += adj[animFrame % 4];
updateAnim(4);
num += adj[(animLoops != 0 ? animFrame % 4 : 0)];
rectangle small_monst_rect = {0,0,18,14};
to_rect.right = to_rect.left + 28;
to_rect.bottom = to_rect.top + 36;
Expand All @@ -1062,7 +1093,8 @@ void cPict::drawCustomMonstTall(short num, rectangle to_rect){

void cPict::drawCustomMonstLg(short num, rectangle to_rect){
static const short adj[4] = {0, 8, 4, 12};
num += adj[animFrame % 4];
updateAnim(4);
num += adj[(animLoops != 0 ? animFrame % 4 : 0)];
rectangle small_monst_rect = {0,0,18,14};
to_rect.right = to_rect.left + 28;
to_rect.bottom = to_rect.top + 36;
Expand Down Expand Up @@ -1163,16 +1195,20 @@ void cPict::drawCustomTinyItem(short num, rectangle to_rect){
}

void cPict::drawCustomBoom(short num, rectangle to_rect){
updateAnim(8);
to_rect.right = to_rect.left + 28;
to_rect.bottom = to_rect.top + 36;
rectangle from_rect;
std::shared_ptr<const sf::Texture> from_gw;
graf_pos_ref(from_gw, from_rect) = spec_scen_g.find_graphic(num + animFrame % 8);
if(filled) fill_rect(getWindow(), to_rect, sf::Color::Black);
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
// When boom loops are over, draw nothing
if(animLoops != 0)
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
}

void cPict::drawCustomMissile(short num, rectangle to_rect){
updateAnim(8);
num += animFrame % 8;
rectangle from_rect;
std::shared_ptr<const sf::Texture> from_gw;
Expand All @@ -1182,7 +1218,9 @@ void cPict::drawCustomMissile(short num, rectangle to_rect){
if(animFrame >= 4) from_rect.offset(0, 18);
if(filled) fill_rect(getWindow(), to_rect, sf::Color::Black);
to_rect.inset(5,9);
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
// When missile loops are over, draw nothing
if(animLoops != 0)
rect_draw_some_item(*from_gw, from_rect, getWindow(), to_rect, sf::BlendAlpha);
}

void cPict::drawCustomTerMap(short num, rectangle to_rect){
Expand Down
Loading
Loading