Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_ANIMATIONEFFECT_H
#define CRAB_ANIMATIONEFFECT_H
#include "crab/loaders.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
// Types of fade effects
enum FadeType {
FADE_NONE,
FADE_IN,
FADE_OUT
};
// Sometimes we need to stop drawing the game for proper fade effects
// Use DRAW_STOP to stop drawing the game until DRAW_START is called. DRAW_SAME doesn't change anything
enum DrawType {
DRAW_SAME,
DRAW_STOP,
DRAW_START
};
struct AnimationEffect {
// What sort of effect do we apply to the image
FadeType _type;
// The duration of the effect relative to the start of this animation
uint32 _start, _finish;
// Warning: the only way to start drawing the game again is having another animation event with DRAW_START
DrawType _drawGame;
AnimationEffect() {
_type = FADE_NONE;
_drawGame = DRAW_SAME;
_start = 0;
_finish = 0;
}
AnimationEffect(rapidxml::xml_node<char> *node) : AnimationEffect() {
if (nodeValid("effect", node)) {
rapidxml::xml_node<char> *effnode = node->first_node("effect");
loadNum(_start, "start", effnode);
loadNum(_finish, "finish", effnode);
Common::String str;
loadStr(str, "type", effnode);
if (str == "fade_in")
_type = FADE_IN;
else if (str == "fade_out")
_type = FADE_OUT;
else
_type = FADE_NONE;
loadStr(str, "game_draw", effnode);
if (str == "start")
_drawGame = DRAW_START;
else if (str == "stop")
_drawGame = DRAW_STOP;
else
_drawGame = DRAW_SAME;
}
}
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_ANIMATIONEFFECT_H

View File

@@ -0,0 +1,106 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/crab.h"
#include "crab/animation/AnimationFrame.h"
namespace Crab {
using namespace pyrodactyl::image;
using namespace pyrodactyl::anim;
AnimationFrame::AnimationFrame(rapidxml::xml_node<char> *node) : AnimationFrame() {
_eff = AnimationEffect(node);
Vector2i::load(node);
loadImgKey(_img, "img", node);
loadNum(_start, "start", node);
loadNum(_finish, "finish", node);
loadColor(_col, node);
if (nodeValid("text", node, false))
_text.load(node->first_node("text"));
reset();
}
void AnimationFrame::reset() {
switch (_eff._type) {
case FADE_IN:
_col.a = 0;
break;
case FADE_OUT:
_col.a = 255;
break;
default:
_col.a = 255;
break;
}
}
void AnimationFrame::draw(const uint32 &timestamp) {
warning("STUB: AnimationFrame::draw()");
#if 0
// Only draw the frame in the specified duration
if (timestamp >= start && timestamp <= finish) {
// Fill the screen with the color indicated
SDL_SetRenderDrawBlendMode(gRenderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(gRenderer, col.r, col.g, col.b, col.a);
SDL_RenderFillRect(gRenderer, NULL);
g_engine->_imageManager->draw(x, y, img);
text.draw();
}
#endif
}
DrawType AnimationFrame::internalEvents(const uint32 &timestamp) {
// Vary alpha according to the effect values in the variation time frame
if (timestamp >= _eff._start && timestamp <= _eff._finish) {
// These equations courtesy of linear algebra
switch (_eff._type) {
case FADE_IN:
_col.a = (255 * (timestamp - _eff._start)) / (_eff._finish - _eff._start);
break;
case FADE_OUT:
_col.a = (255 * (_eff._finish - timestamp)) / (_eff._finish - _eff._start);
break;
default:
break;
}
return _eff._drawGame;
}
return DRAW_SAME;
}
} // End of namespace Crab

View File

@@ -0,0 +1,81 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_ANIMATIONFRAME_H
#define CRAB_ANIMATIONFRAME_H
#include "crab/animation/AnimationEffect.h"
#include "crab/image/ImageManager.h"
#include "crab/text/TextManager.h"
#include "crab/ui/HoverInfo.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
struct AnimationFrame : public Vector2i {
// The image drawn in this frame
ImageKey _img;
// This is the time in we draw the frame milliseconds relative to the start of the entire animation
uint32 _start, _finish;
// The effect applied to the image
AnimationEffect _eff;
// In case we want to display any words during the animation
pyrodactyl::ui::HoverInfo _text;
// The color drawn on the screen
Color _col;
AnimationFrame() {
_img = 0;
_start = 0;
_finish = 0;
_col.r = 0;
_col.g = 0;
_col.b = 0;
_col.a = 255;
}
AnimationFrame(rapidxml::xml_node<char> *node);
void reset();
void draw(const uint32 &timestamp);
DrawType internalEvents(const uint32 &timestamp);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_ANIMATIONFRAME_H

View File

@@ -0,0 +1,133 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/ScreenSettings.h"
#include "crab/animation/PopUp.h"
namespace Crab {
using namespace pyrodactyl::anim;
using namespace pyrodactyl::event;
//------------------------------------------------------------------------
// Purpose: Load from xml
//------------------------------------------------------------------------
void PopUp::load(rapidxml::xml_node<char> *node) {
_duration.load(node, "duration", false);
_delay.load(node, "delay");
loadStr(_text, "text", node);
loadNum(_next, "next", node);
bool end = false;
loadBool(end, "end", node, false);
if (end)
_next = -1;
_visible.load(node);
_effect.clear();
for (rapidxml::xml_node<char> *n = node->first_node("effect"); n != nullptr; n = n->next_sibling("effect")) {
Effect e;
e.load(n);
_effect.push_back(e);
}
}
void PopUpCollection::load(rapidxml::xml_node<char> *node) {
loadBool(_loop, "loop", node);
for (auto n = node->first_node("dialog"); n != nullptr; n = n->next_sibling("dialog"))
_element.push_back(n);
}
//------------------------------------------------------------------------
// Purpose: Internal events
//------------------------------------------------------------------------
bool PopUp::internalEvents(pyrodactyl::event::Info &info, const Common::String &playerId,
Common::Array<EventResult> &result, Common::Array<EventSeqInfo> &endSeq) {
if (_visible.evaluate(info) || _startedShow) {
if (_delay.targetReached()) {
if (_duration.targetReached(g_engine->_screenSettings->_textSpeed)) {
_show = false;
for (auto &i : _effect)
i.execute(info, playerId, result, endSeq);
return true;
} else {
_startedShow = true;
_show = true;
}
} else
_show = false;
} else
_show = false;
return false;
}
void PopUpCollection::internalEvents(pyrodactyl::event::Info &info, const Common::String &playerId,
Common::Array<EventResult> &result, Common::Array<EventSeqInfo> &endSeq) {
if (_cur >= 0 && (uint)_cur < _element.size()) {
if (_element[_cur].internalEvents(info, playerId, result, endSeq)) {
if (_element[_cur]._next <= 0 || (uint)_element[_cur]._next >= _element.size()) {
// This means that this popup is the "end" node, we must loop back to start or end this
if (_loop) {
_cur = 0;
_element[_cur].reset();
} else
_cur = -1;
} else {
_cur = _element[_cur]._next;
_element[_cur].reset();
}
}
}
}
//------------------------------------------------------------------------
// Purpose: Draw functions
//------------------------------------------------------------------------
void PopUp::draw(const int &x, const int &y, pyrodactyl::ui::ParagraphData &pop, const Rect &camera) {
if (_show) {
if (x + pop.x < camera.w / 3)
g_engine->_textManager->draw(x + pop.x, y + pop.y, _text, pop._col, pop._font, ALIGN_LEFT, pop._line.x, pop._line.y, true);
else if (x + pop.x > (2 * camera.w) / 3)
g_engine->_textManager->draw(x + pop.x, y + pop.y, _text, pop._col, pop._font, ALIGN_RIGHT, pop._line.x, pop._line.y, true);
else
g_engine->_textManager->draw(x + pop.x, y + pop.y, _text, pop._col, pop._font, ALIGN_CENTER, pop._line.x, pop._line.y, true);
}
}
void PopUpCollection::draw(const int &x, const int &y, pyrodactyl::ui::ParagraphData &pop, const Rect &camera) {
if (_cur >= 0 && (uint)_cur < _element.size())
_element[_cur].draw(x, y, pop, camera);
}
} // End of namespace Crab

View File

@@ -0,0 +1,127 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_POPUP_H
#define CRAB_POPUP_H
#include "crab/timer.h"
#include "crab/event/effect.h"
#include "crab/event/triggerset.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
struct PopUp {
// The total time the popup stays on the screen
Timer _duration;
// The time we wait before showing the trigger for the first time
Timer _delay;
// Should we draw this or not? (Decided by internal events)
bool _show;
// Popups with "talk key pressed" condition need to be shown once the key is pressed
bool _startedShow;
// Triggers for when you only want to display this in certain conditions
pyrodactyl::event::TriggerSet _visible;
// Effects for changing variables and other related stuff
Common::Array<pyrodactyl::event::Effect> _effect;
// The text displayed
Common::String _text;
// The next popup we should go to, negative values means the end
int _next;
PopUp() {
_next = -1;
reset();
}
PopUp(rapidxml::xml_node<char> *node) : PopUp() {
load(node);
}
void reset() {
_show = false;
_startedShow = false;
_delay.stop();
_duration.stop();
}
void load(rapidxml::xml_node<char> *node);
void draw(const int &x, const int &y, pyrodactyl::ui::ParagraphData &pop, const Rect &camera);
// return true if we should proceed to next event, false otherwise
bool internalEvents(pyrodactyl::event::Info &info, const Common::String &playerId,
Common::Array<pyrodactyl::event::EventResult> &result, Common::Array<pyrodactyl::event::EventSeqInfo> &endSeq);
};
struct PopUpCollection {
// Collection of environmental dialog
Common::Array<PopUp> _element;
// The current dialog being played
int _cur;
// true if dialog needs to loop, false otherwise
bool _loop;
PopUpCollection() {
_cur = 0;
_loop = true;
}
// Return true if any of the popup dialog is visible, false otherwise
bool show() {
for (auto &i : _element)
if (i._show)
return true;
return false;
}
void load(rapidxml::xml_node<char> *node);
void internalEvents(pyrodactyl::event::Info &info, const Common::String &playerId,
Common::Array<pyrodactyl::event::EventResult> &result, Common::Array<pyrodactyl::event::EventSeqInfo> &endSeq);
void draw(const int &x, const int &y, pyrodactyl::ui::ParagraphData &pop, const Rect &camera);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_POPUP_H

View File

@@ -0,0 +1,66 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/animation/animation.h"
namespace Crab {
using namespace pyrodactyl::image;
using namespace pyrodactyl::anim;
Animation::Animation(rapidxml::xml_node<char> *node) {
loadNum(_length, "length", node);
for (auto n = node->first_node("frame"); n != nullptr; n = n->next_sibling("frame"))
_frame.push_back(n);
}
void Animation::draw() {
uint32 timestamp = _timer.ticks();
for (auto &frame : _frame)
frame.draw(timestamp);
}
bool Animation::internalEvents(DrawType &gameDraw) {
uint32 timestamp = _timer.ticks();
for (auto &frame : _frame) {
DrawType result = frame.internalEvents(timestamp);
// if (result != DRAW_SAME)
gameDraw = result;
}
return _timer.ticks() >= _length;
}
void Animation::reset() {
for (auto &frame : _frame)
frame.reset();
}
} // End of namespace Crab

View File

@@ -0,0 +1,73 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_ANIMATION_H
#define CRAB_ANIMATION_H
#include "crab/timer.h"
#include "crab/animation/AnimationEffect.h"
#include "crab/animation/AnimationFrame.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
class Animation {
// All the frames are updated simultaneously rather than sequentially
Common::Array<AnimationFrame> _frame;
// Length of the entire animation in milliseconds
uint32 _length;
// Keep track of the time
Timer _timer;
public:
Animation() {
_length = 0;
}
Animation(rapidxml::xml_node<char> *node);
void draw();
void reset();
bool internalEvents(DrawType &gameDraw);
void start() {
reset();
_timer.start();
}
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB__ANIMATION_H

View File

@@ -0,0 +1,109 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/animation/animframe.h"
namespace Crab {
using namespace pyrodactyl::anim;
void AnimFrame::load(rapidxml::xml_node<char> *node, const Rect &VBOX, const uint32 &rep, const int &AX, const int &AY) {
_clip.load(node);
if (rep == 0)
loadNum(_repeat, "repeat", node);
else
_repeat = rep;
if (AX == 0.0f && AY == 0.0f) {
if (nodeValid("anchor", node, false))
_anchor.load(node->first_node("anchor"));
} else {
_anchor.x = AX;
_anchor.y = AY;
}
if (VBOX.w == 0 || VBOX.h == 0) {
if (nodeValid("box_v", node))
_boxV.load(node->first_node("box_v"));
} else
_boxV = VBOX;
}
void AnimationFrames::load(rapidxml::xml_node<char> *node) {
loadTextureFlipType(_flip, node);
if (!loadNum(_repeat, "repeat", node, false))
_repeat = 0;
loadBool(_random, "random", node, false);
if (nodeValid("anchor", node, false))
_anchor.load(node->first_node("anchor"));
if (nodeValid("box_v", node))
_boxV.load(node->first_node("box_v"));
if (nodeValid("shadow", node)) {
_shadow.load(node->first_node("shadow"));
_shadow._valid = true;
}
if (nodeValid("frames", node)) {
_frame.clear();
rapidxml::xml_node<char> *framenode = node->first_node("frames");
for (auto n = framenode->first_node("frame"); n != nullptr; n = n->next_sibling("frame")) {
AnimFrame af;
af.load(n, _boxV, _repeat, _anchor.x, _anchor.y);
_frame.push_back(af);
}
}
if (_random)
_currentClip = g_engine->getRandomNumber(_frame.size() - 1);
else
_currentClip = 0;
}
bool AnimationFrames::updateClip() {
if (_currentClip < _frame.size()) {
_currentClip = (_currentClip + 1) % _frame.size();
return true;
} else
_currentClip = 0;
return false;
}
const AnimFrame &AnimationFrames::currentFrame() {
return _frame[_currentClip];
}
} // End of namespace Crab

View File

@@ -0,0 +1,113 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_ANIMFRAME_H
#define CRAB_ANIMFRAME_H
#include "crab/Rectangle.h"
#include "crab/vectors.h"
#include "crab/animation/shadow.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
struct AnimFrame {
// Portion of sprite to show
Rect _clip;
// The duration for which the frame must be repeated on screen
uint32 _repeat;
// The anchor point of the frame
Vector2i _anchor;
// The vulnerable hit box for this frame
Rect _boxV;
AnimFrame() {
_repeat = 0;
}
void load(rapidxml::xml_node<char> *node, const Rect &VBOX,
const uint32 &REP = 0, const int &AX = 0, const int &AY = 0);
};
class AnimationFrames {
// The global vulnerable hit box for all the frames
// If the W or H of this is 0, then use individual frame values
Rect _boxV;
public:
// The frames for the animation
Common::Array<AnimFrame> _frame;
// The currentClip
uint _currentClip;
// Should we flip the images in the frame rectangle?
TextureFlipType _flip;
// The global repeat value for all the frames
// If this is 0, then use individual frame values
uint32 _repeat;
// The global anchor value for all the frames
// If this is 0, then use individual frame values
Vector2i _anchor;
// true if animation starts at a random frame
// used for idle animations so that every sprite doesn't animate in sync
bool _random;
// Does this set of animation frames need a specific shadow offset?
ShadowOffset _shadow;
AnimationFrames() {
reset();
_flip = FLIP_NONE;
_repeat = 0;
_random = false;
}
void reset() {
_currentClip = 0;
}
void load(rapidxml::xml_node<char> *node);
bool updateClip();
const AnimFrame &currentFrame();
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_ANIMFRAME_H

View File

@@ -0,0 +1,89 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/XMLDoc.h"
#include "crab/animation/animset.h"
namespace Crab {
using namespace pyrodactyl::anim;
void AnimSet::load(const Common::Path &filename) {
XMLDoc conf(filename);
if (conf.ready()) {
rapidxml::xml_node<char> *node = conf.doc()->first_node();
if (nodeValid(node)) {
_fight.load(node);
_walk.load(node);
if (nodeValid("bounds", node))
_bounds.load(node->first_node("bounds"));
if (nodeValid("shadow", node))
_shadow.load(node->first_node("shadow"));
if (nodeValid("focus", node))
_focus.load(node->first_node("focus"));
}
}
}
TextureFlipType AnimSet::flip(const Direction &dir) {
TextureFlipType ret;
if (_fight.flip(ret, dir))
return ret;
return _walk.flip(dir);
}
const ShadowOffset &AnimSet::shadow(const Direction &dir) {
if (_fight.validMove())
return _fight.shadow(dir);
return _walk.shadow(dir);
}
int AnimSet::anchorX(const Direction &dir) {
FightAnimFrame faf;
if (_fight.curFrame(faf, dir))
return faf._anchor.x;
return _walk.anchorX(dir);
}
int AnimSet::anchorY(const Direction &dir) {
FightAnimFrame faf;
if (_fight.curFrame(faf, dir))
return faf._anchor.y;
return _walk.anchorY(dir);
}
} // End of namespace Crab

View File

@@ -0,0 +1,74 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_ANIMSET_H
#define CRAB_ANIMSET_H
#include "crab/animation/fightmoves.h"
#include "crab/animation/shadow.h"
#include "crab/animation/walkframes.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
// Container for all the possible animations an object can have
struct AnimSet {
// The frames relevant to fighting moves
FightMoves _fight;
// The frames relevant to walking animations
WalkFrames _walk;
// The bounding box of the character used for level collision
Rect _bounds;
// The sprite shadow
ShadowData _shadow;
// The camera focus point
Vector2i _focus;
AnimSet() {}
void load(const Common::Path &filename);
TextureFlipType flip(const Direction &dir);
const ShadowOffset &shadow(const Direction &dir);
int anchorX(const Direction &dir);
int anchorY(const Direction &dir);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_ANIMSET_H

View File

@@ -0,0 +1,86 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/animation/fightanim.h"
namespace Crab {
using namespace pyrodactyl::anim;
//------------------------------------------------------------------------
// Purpose: Load a single frame of a fighting move
//------------------------------------------------------------------------
void FightAnimFrame::load(rapidxml::xml_node<char> *node, const Rect &VBOX, const uint32 &rep, const int &AX, const int &AY) {
AnimFrame::load(node, VBOX, rep, AX, AY);
if (nodeValid("box_d", node, false))
_boxD.load(node->first_node("box_d"));
if (nodeValid("shift", node, false))
_delta.load(node->first_node("shift"));
if (!loadNum(_state, "state", node, false))
_state = 0;
loadBool(_branch, "branch", node, false);
}
//------------------------------------------------------------------------
// Purpose: Load a fighting move
//------------------------------------------------------------------------
void FightAnimFrames::load(rapidxml::xml_node<char> *node) {
loadTextureFlipType(_flip, node);
if (!loadNum(_repeat, "repeat", node, false))
_repeat = 0;
if (nodeValid("anchor", node, false))
_anchor.load(node->first_node("anchor"));
if (nodeValid("box_v", node))
_boxV.load(node->first_node("box_v"));
if (nodeValid("shadow", node)) {
_shadow.load(node->first_node("shadow"));
_shadow._valid = true;
}
if (nodeValid("frames", node)) {
_frame.clear();
rapidxml::xml_node<char> *framenode = node->first_node("frames");
for (auto n = framenode->first_node("frame"); n != nullptr; n = n->next_sibling("frame")) {
FightAnimFrame faf;
faf.load(n, _boxV, _repeat, _anchor.x, _anchor.y);
_frame.push_back(faf);
}
}
}
} // End of namespace Crab

View File

@@ -0,0 +1,110 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_FIGHTANIM_H
#define CRAB_FIGHTANIM_H
#include "crab/ai/moveeffect.h"
#include "crab/animation/fm_ai_data.h"
#include "crab/input/fightinput.h"
#include "crab/event/triggerset.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
// A single frame of a fighting move
struct FightAnimFrame : public AnimFrame {
// The hit box of the player WITH RESPECT TO the sprite bounding box
//boxV is the vulnerable hit box, boxD is the damage hit box
Rect _boxD;
// The displacement in the position caused by the frame
Vector2i _delta;
// The sprite state for the duration of the frame
uint _state;
// Can we cancel/branch to another move from this frame?
bool _branch;
FightAnimFrame() {
_state = 0;
_branch = false;
}
void load(rapidxml::xml_node<char> *node, const Rect &VBOX,
const uint32 &REP = 0, const int &AX = 0, const int &AY = 0);
};
// All data related to a single fighting move in a single direction
class FightAnimFrames {
// The global vulnerable hit box for all the frames
// If the W or H of this is 0, then use individual frame values
Rect _boxV;
public:
// The individual frames for each direction
Common::Array<FightAnimFrame> _frame;
// The currentClip
uint _currentClip;
// Should we flip the images in the frame rectangle?
TextureFlipType _flip;
// The amount of time in milliseconds each animation frame needs to be on screen
// If this is zero then use the value in each individual frame
uint32 _repeat;
// The global anchor value for all the frames
// If this is 0, then use individual frame values
Vector2i _anchor;
// Does this set of animation frames need a specific shadow offset?
ShadowOffset _shadow;
FightAnimFrames() {
reset();
_flip = FLIP_NONE;
_repeat = 0;
}
void reset() {
_currentClip = 0;
}
void load(rapidxml::xml_node<char> *node);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_FIGHTANIM_H

View File

@@ -0,0 +1,56 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/animation/fightmove.h"
namespace Crab {
using namespace pyrodactyl::anim;
void FightMove::load(rapidxml::xml_node<char> *node) {
_frames[DIRECTION_DOWN].load(node->first_node("down"));
_frames[DIRECTION_UP].load(node->first_node("up"));
_frames[DIRECTION_LEFT].load(node->first_node("left"));
_frames[DIRECTION_RIGHT].load(node->first_node("right"));
if (nodeValid("input", node))
_input.load(node->first_node("input"));
if (nodeValid("unlock", node, false))
_unlock.load(node->first_node("unlock"));
if (nodeValid("effect", node))
_eff.load(node->first_node("effect"));
if (nodeValid("ai", node, false))
_ai.load(node->first_node("ai"));
}
} // End of namespace Crab

View File

@@ -0,0 +1,67 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_FIGHTMOVE_H
#define CRAB_FIGHTMOVE_H
#include "crab/animation/fightanim.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
// All info for a single fighting move in all four directions
struct FightMove {
// Frames for all four directions
FightAnimFrames _frames[DIRECTION_TOTAL];
// The input required
pyrodactyl::input::FightInput _input;
// The conditions to unlock this move for player use
pyrodactyl::event::TriggerSet _unlock;
// The effects of this move - hurt animation, sound effect and so on
FightMoveEffect _eff;
// The data needed by an AI sprite to execute this move
FightMoveAIData _ai;
FightMove() {}
~FightMove() {}
void load(rapidxml::xml_node<char> *node);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_FIGHTMOVE_H

View File

@@ -0,0 +1,201 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/animation/fightmoves.h"
namespace Crab {
using namespace pyrodactyl::anim;
//------------------------------------------------------------------------
// Purpose: Constructor
//------------------------------------------------------------------------
FightMoves::FightMoves() {
_cur = -1;
_next = -1;
_start = false;
_frameCur = 0;
_frameTotal = 0;
_move.clear();
_timer.start();
}
//------------------------------------------------------------------------
// Purpose: Load from file
//------------------------------------------------------------------------
void FightMoves::load(rapidxml::xml_node<char> *node) {
for (auto n = node->first_node("move"); n != nullptr; n = n->next_sibling("move")) {
FightMove fm;
fm.load(n);
_move.push_back(fm);
}
}
//------------------------------------------------------------------------
// Purpose: Return current or next move
//------------------------------------------------------------------------
bool FightMoves::curMove(FightMove &fm) {
if (_cur >= 0 && (uint)_cur < _move.size()) {
fm = _move[_cur];
return true;
}
return false;
}
bool FightMoves::nextMove(FightMove &fm) {
if (_next >= 0 && (uint)_next < _move.size()) {
fm = _move[_next];
return true;
}
return false;
}
//------------------------------------------------------------------------
// Purpose: Get the current frame of the sprite
//------------------------------------------------------------------------
bool FightMoves::curFrame(FightAnimFrame &faf, const Direction &d) {
// Check validity of current move
if (_cur >= 0 && (uint)_cur < _move.size()) {
// Check validity of current frame
if (_frameCur < _frameTotal && _frameCur < _move[_cur]._frames[d]._frame.size()) {
faf = _move[_cur]._frames[d]._frame[_frameCur];
return true;
}
}
return false;
}
//------------------------------------------------------------------------
// Purpose: Update frame
//------------------------------------------------------------------------
FrameUpdateResult FightMoves::updateFrame(const Direction &d) {
// Check validity of current move
if (_cur >= 0 && (uint)_cur < _move.size()) {
// Check validity of current frame
if (_frameCur < _frameTotal && _frameCur < _move[_cur]._frames[d]._frame.size()) {
// Has the current frame finished playing?
// OR Is this the first frame of the move?
if (_timer.ticks() >= _move[_cur]._frames[d]._frame[_frameCur]._repeat || _start) {
_frameCur++;
_timer.start();
_start = false;
return FUR_SUCCESS;
} else
return FUR_WAIT;
}
}
return FUR_FAIL;
}
//------------------------------------------------------------------------
// Purpose: Find a move corresponding to the input and sprite state
//------------------------------------------------------------------------
uint FightMoves::findMove(const pyrodactyl::input::FightAnimationType &type, const int &state) {
uint pos = 0;
for (auto i = _move.begin(); i != _move.end(); ++i, ++pos)
if (i->_input._type == type && i->_input._state == (uint)state)
return pos;
pos = 0;
for (auto i = _move.begin(); i != _move.end(); ++i, ++pos)
if (i->_input._type == type && i->_input._state == SPRITE_STATE_OVERRIDE)
return pos;
return SPRITE_STATE_OVERRIDE;
}
//------------------------------------------------------------------------
// Purpose: Function for AI
//------------------------------------------------------------------------
void FightMoves::listAttackMoves(Common::Array<uint> &list) {
list.clear();
uint pos = 0;
for (auto i = _move.begin(); i != _move.end(); ++i, ++pos)
if (i->_ai._type == MOVE_ATTACK)
list.push_back(pos);
}
//------------------------------------------------------------------------
// Purpose: Force update to a new move
//------------------------------------------------------------------------
bool FightMoves::forceUpdate(const uint &index, pyrodactyl::input::FightInput &input, const Direction &d) {
_frameCur = 0;
_cur = index;
if ((uint)_cur < _move.size()) {
if (_move[_cur]._unlock.result()) {
_frameTotal = _move[_cur]._frames[d]._frame.size();
if (_frameTotal > 0) {
input = _move[_cur]._input;
input._state = _move[_cur]._frames[d]._frame[0]._state;
} else
input.reset();
_timer.start();
_start = true;
g_engine->_musicManager->playEffect(_move[_cur]._eff._activate, 0);
return true;
}
}
_cur = 0;
_frameTotal = 0;
return false;
}
//------------------------------------------------------------------------
// Purpose: Set unlock status
//------------------------------------------------------------------------
void FightMoves::evaluate(pyrodactyl::event::Info &info) {
for (auto &i : _move)
i._unlock.evaluate(info);
}
//------------------------------------------------------------------------
// Purpose: Find which style to flip the texture in
//------------------------------------------------------------------------
bool FightMoves::flip(TextureFlipType &flip, Direction d) {
// Check validity of current move
if (validMove()) {
flip = _move[_cur]._frames[d]._flip;
return true;
}
return false;
}
} // End of namespace Crab

View File

@@ -0,0 +1,133 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_FIGHTMOVES_H
#define CRAB_FIGHTMOVES_H
#include "crab/timer.h"
#include "crab/animation/fightmove.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
enum FrameUpdateResult {
FUR_FAIL,
FUR_WAIT,
FUR_SUCCESS
};
// This state value indicates that the move should execute regardless of actual sprite state
const uint SPRITE_STATE_OVERRIDE = std::numeric_limits<uint>::max();
class FightMoves {
// The fighting moves of a sprite
Common::Array<FightMove> _move;
// The currently selected move
int _cur;
// For AI - the move about to be executed
int _next;
// The timer used for playing animations
Timer _timer;
// We need to instantly show the new frame for a move that has started
bool _start;
// The current frame and total frames
uint _frameCur, _frameTotal;
public:
FightMoves();
~FightMoves() {}
void reset() {
_cur = -1;
}
void load(rapidxml::xml_node<char> *node);
bool curMove(FightMove &fm);
bool nextMove(FightMove &fm);
FrameUpdateResult updateFrame(const Direction &d);
bool curFrame(FightAnimFrame &faf, const Direction &d);
uint findMove(const pyrodactyl::input::FightAnimationType &type, const int &state);
void listAttackMoves(Common::Array<uint> &list);
bool forceUpdate(const uint &index, pyrodactyl::input::FightInput &input, const Direction &d);
bool lastFrame() {
return _frameCur >= _frameTotal;
}
void frameIndex(uint val) {
_frameCur = val;
}
void curCombo(pyrodactyl::input::FightInput &input) {
input = _move[_cur]._input;
}
bool validMove() {
return _cur >= 0 && (uint)_cur < _move.size();
}
bool empty() {
return _move.empty();
}
bool flip(TextureFlipType &flip, Direction d);
const ShadowOffset &shadow(Direction d) {
return _move[_cur]._frames[d]._shadow;
}
void next(int val) {
_next = val;
}
int next() {
return _next;
}
void evaluate(pyrodactyl::event::Info &info);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_FIGHTMOVES_H

View File

@@ -0,0 +1,82 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_FM_AI_DATA_H
#define CRAB_FM_AI_DATA_H
#include "crab/animation/range.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
enum AIMoveType {
MOVE_NONE, // AI sprites do not use this move
MOVE_ATTACK, // AI sprites use this move to attack you
MOVE_DEFEND // AI sprites use this move to dodge or defend
};
struct FightMoveAIData {
// Can this move be used by AI to attack
AIMoveType _type;
// The range of the move
Range _range;
// The AI delays executing the move by this long
uint _delay;
FightMoveAIData() {
_type = MOVE_NONE;
_delay = 0;
}
void load(rapidxml::xml_node<char> *node) {
if (!loadNum(_delay, "delay", node, false))
_delay = 0;
_range.load(node->first_node("range"));
Common::String str;
loadStr(str, "type", node, false);
if (str == "attack")
_type = MOVE_ATTACK;
else if (str == "defend")
_type = MOVE_DEFEND;
else
_type = MOVE_NONE;
}
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_FM_AI_DATA_H

View File

@@ -0,0 +1,51 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/crab.h"
#include "crab/animation/imageeffect.h"
#include "crab/image/ImageManager.h"
namespace Crab {
using namespace pyrodactyl::anim;
void ImageEffect::load(rapidxml::xml_node<char> *node) {
if (nodeValid(node, false)) {
if (loadImgKey(_img, "img", node) && loadXY(x, y, node))
_visible = true;
}
}
void ImageEffect::draw(const int &xOffset, const int &yOffset) {
if (_visible)
g_engine->_imageManager->draw(x + xOffset, y + yOffset, _img);
}
} // End of namespace Crab

View File

@@ -0,0 +1,57 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_IMAGEEFFECT_H
#define CRAB_IMAGEEFFECT_H
#include "crab/image/ImageManager.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
struct ImageEffect : public Vector2i {
ImageKey _img;
bool _visible;
ImageEffect() {
_visible = false;
_img = 0;
}
void load(rapidxml::xml_node<char> *node);
void draw(const int &xOffset, const int &yOffset);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_IMAGEEFFECT_H

View File

@@ -0,0 +1,65 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_RANGE_H
#define CRAB_RANGE_H
#include "crab/animation/animframe.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
struct Range {
bool _valid;
Rect _val[DIRECTION_TOTAL];
Range() {
_valid = false;
}
void load(rapidxml::xml_node<char> *node) {
if (nodeValid(node, false)) {
_val[DIRECTION_DOWN].load(node->first_node("down"));
_val[DIRECTION_UP].load(node->first_node("up"));
_val[DIRECTION_LEFT].load(node->first_node("left"));
_val[DIRECTION_RIGHT].load(node->first_node("right"));
_valid = true;
} else
_valid = false;
}
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_RANGE_H

View File

@@ -0,0 +1,83 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_SHADOW_H
#define CRAB_SHADOW_H
#include "crab/crab.h"
#include "crab/vectors.h"
#include "crab/image/ImageManager.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
struct ShadowData {
// The image of the sprite's shadow
ImageKey _img;
// Size of image
Vector2i _size;
// The default shadow offset
Vector2i _offset;
ShadowData() : _size(1, 1) {
_img = 0;
}
void load(rapidxml::xml_node<char> *node) {
loadImgKey(_img, "img", node);
_offset.load(node);
using namespace pyrodactyl::image;
Image dat;
g_engine->_imageManager->getTexture(_img, dat);
_size.x = dat.w() / 2;
_size.y = dat.h() / 2;
}
};
// Used when a set of animation frames needs a specific shadow offset
class ShadowOffset : public Vector2i {
public:
// Only use this offset if this is true
bool _valid;
ShadowOffset() {
_valid = false;
}
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_SHADOW_H

View File

@@ -0,0 +1,668 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/animation/sprite.h"
#include "crab/input/cursor.h"
namespace Crab {
using namespace pyrodactyl::ai;
using namespace pyrodactyl::anim;
using namespace pyrodactyl::input;
using namespace pyrodactyl::event;
//------------------------------------------------------------------------
// Purpose: Constructor
//------------------------------------------------------------------------
Sprite::Sprite() : _imgSize(1, 1), _velMod(1.0f, 1.0f) {
_dir = DIRECTION_LEFT;
_layer = -1;
_image = 0;
visible(true);
_damageDone = false;
_hover = false;
// _pathing.SetSprite(this);
}
//------------------------------------------------------------------------
// Purpose: Load sprite from XML and animations from the index of all animation files
//------------------------------------------------------------------------
void Sprite::load(rapidxml::xml_node<char> *node, Common::Array<Common::Path> &animations) {
using namespace pyrodactyl::image;
if (nodeValid(node)) {
loadStr(_id, "id", node);
// The amount by which the sprite x,y should be multiplied
int multiply = 1;
loadNum(multiply, "multiply", node, false);
loadNum(_pos.x, "x", node);
loadNum(_pos.y, "y", node);
_pos.x *= multiply;
_pos.y *= multiply;
loadImgKey(_image, "img", node);
loadNum(_layer, "layer", node, false);
Image dat;
g_engine->_imageManager->getTexture(_image, dat);
_imgSize.x = dat.w();
_imgSize.y = dat.h();
uint index = 0;
loadNum(index, "moveset", node);
if (index < animations.size())
_animSet.load(animations[index]);
_animSet._fight.listAttackMoves(_aiData._fight._attack);
loadDirection(_dir, node);
_clip = _animSet._walk.clip(_dir);
_boxV = _animSet._walk.boxV(_dir);
if (nodeValid("visible", node, false))
_visible.load(node->first_node("visible"));
if (nodeValid("movement", node, false))
_aiData._walk.load(node->first_node("movement"));
if (nodeValid("popup", node, false))
_popup.load(node->first_node("popup"));
}
}
//------------------------------------------------------------------------
// Purpose: Move along x and y axis
//------------------------------------------------------------------------
void Sprite::move(const SpriteConstant &sc) {
if (_target.x == 0.0f && (_vel.x > -sc._tweening && _vel.x < sc._tweening))
_vel.x = 0.0f;
else {
_vel.x += (_target.x - _vel.x) * sc._tweening;
_pos.x += _vel.x;
}
if (_target.y == 0.0f && (_vel.y > -sc._tweening && _vel.y < sc._tweening))
_vel.y = 0.0f;
else {
_vel.y += (_target.y - _vel.y) * sc._tweening;
_pos.y += _vel.y;
}
}
//------------------------------------------------------------------------
// Purpose: Resolve collision with shapes excluding the level bounding rectangle
//------------------------------------------------------------------------
void Sprite::resolveCollide() {
// NOTE: we don't check i->intersect here because we do that in the level functions
for (const auto &i : _collideData) {
Rect bounds = boundRect();
if (i._type == SHAPE_POLYGON) {
_pos.x -= i._data.x;
_pos.y -= i._data.y;
} else {
Direction d = bounds.resolveY(i._data);
if (d == DIRECTION_UP)
_pos.y -= i._data.y + i._data.h - _animSet._bounds.y + _animSet.anchorY(_dir) + 1;
else if (d == DIRECTION_DOWN)
_pos.y -= i._data.y - bounds.h - _animSet._bounds.y + _animSet.anchorY(_dir) - 1;
d = bounds.resolveX(i._data);
if (d == DIRECTION_LEFT)
_pos.x -= i._data.x + i._data.w - _animSet._bounds.x + _animSet.anchorX(_dir) + 1;
else if (d == DIRECTION_RIGHT)
_pos.x -= i._data.x - bounds.w - _animSet._bounds.x + _animSet.anchorX(_dir) - 1;
}
}
// Clear the collision data
_collideData.clear();
}
//------------------------------------------------------------------------
// Purpose: Resolve collision with the level bounding rectangle
//------------------------------------------------------------------------
void Sprite::resolveInside(Rect collider) {
Rect bounds = boundRect();
Direction d = bounds.resolveX(collider);
if (d == DIRECTION_RIGHT)
_pos.x = collider.x - _animSet._bounds.x + _animSet.anchorX(_dir) + 1;
else if (d == DIRECTION_LEFT)
_pos.x = collider.x + collider.w - _animSet._bounds.x - bounds.w + _animSet.anchorX(_dir) - 1;
bounds = boundRect();
d = bounds.resolveY(collider);
if (d == DIRECTION_DOWN)
_pos.y = collider.y - _animSet._bounds.y + _animSet.anchorY(_dir) + 1;
else if (d == DIRECTION_UP)
_pos.y = collider.y + collider.h - _animSet._bounds.y - bounds.h + _animSet.anchorY(_dir) - 1;
}
//------------------------------------------------------------------------
// Purpose: Various rectangles of the sprite
// Note: Every sprite in the game uses bottom center coordinates:
// draw_x = x - clip.w/2, draw_y = y - clip.h
//------------------------------------------------------------------------
// Used for walking and level geometry collision
Rect Sprite::boundRect() {
Rect rect;
rect.x = _pos.x + _animSet._bounds.x - _animSet.anchorX(_dir);
rect.y = _pos.y + _animSet._bounds.y - _animSet.anchorY(_dir);
rect.w = _animSet._bounds.w;
rect.h = _animSet._bounds.h;
return rect;
}
// Used for fighting
Rect Sprite::boxV() {
Rect rect;
rect.x = _pos.x + _boxV.x;
rect.y = _pos.y + _boxV.y;
rect.w = _boxV.w;
rect.h = _boxV.h;
return rect;
}
// Used for fighting
Rect Sprite::boxD() {
Rect rect;
rect.x = _pos.x + _boxD.x;
rect.y = _pos.y + _boxD.y;
rect.w = _boxD.w;
rect.h = _boxD.h;
return rect;
}
// Used for drawing object notifications over stuff
Rect Sprite::posRect() {
Rect rect;
rect.x = _pos.x - _animSet.anchorX(_dir);
rect.y = _pos.y - _animSet.anchorY(_dir);
rect.w = _clip.w;
rect.h = _clip.h;
return rect;
}
// The range rectangle is relative to the bounding rectangle, and needs to be updated according to the actual position
// Used for enemy sprite to find their required spot to attack the player
Rect Sprite::rangeRect(const Rect &bounds, const Range &range) {
Rect rect;
rect.x = bounds.x + range._val[_dir].x;
rect.y = bounds.y + range._val[_dir].y;
rect.w = range._val[_dir].w;
rect.h = range._val[_dir].h;
return rect;
}
// Used for focusing the camera on the sprite
Vector2i Sprite::camFocus() {
Vector2i v;
v.x = _pos.x + _animSet._focus.x;
v.y = _pos.y + _animSet._focus.y;
return v;
}
//------------------------------------------------------------------------
// Purpose: Draw the sprite
//------------------------------------------------------------------------
void Sprite::draw(pyrodactyl::event::Info &info, const Rect &camera) {
using namespace pyrodactyl::image;
using namespace pyrodactyl::text;
int x = _pos.x - camera.x - _animSet.anchorX(_dir), y = _pos.y - camera.y - _animSet.anchorY(_dir);
// Draw the shadow image relative to the bottom center of the sprite
ShadowOffset sh = _animSet.shadow(_dir);
if (sh._valid) {
// Draw using custom offset
g_engine->_imageManager->draw(x + _clip.w / 2 - _animSet._shadow._size.x + sh.x,
y + _clip.h - _animSet._shadow._size.y + sh.y,
_animSet._shadow._img);
} else {
// Draw using default offset
g_engine->_imageManager->draw(x + _clip.w / 2 - _animSet._shadow._size.x + _animSet._shadow._offset.x,
y + _clip.h - _animSet._shadow._size.y + _animSet._shadow._offset.y,
_animSet._shadow._img);
}
g_engine->_imageManager->draw(x, y, _image, &_clip, _animSet.flip(_dir));
_imgEff.draw(x, y);
if (g_engine->_debugDraw & DRAW_SPRITE_BOUNDS) {
// Nice boxes for the frames and boxV, boxD
Rect bounds = boundRect(), vul = boxV(), dmg = boxD(), debugpos = posRect();
bounds.draw(-camera.x, -camera.y);
debugpos.draw(-camera.x, -camera.y, 255, 255, 255);
dmg.draw(-camera.x, -camera.y, 255, 0, 0);
vul.draw(-camera.x, -camera.y, 0, 0, 255);
FightMove fm;
if (_animSet._fight.nextMove(fm)) {
Rect actualRange;
actualRange.x = bounds.x + fm._ai._range._val[_dir].x;
actualRange.y = bounds.y + fm._ai._range._val[_dir].y;
actualRange.w = fm._ai._range._val[_dir].w;
actualRange.h = fm._ai._range._val[_dir].h;
actualRange.draw(-camera.x, -camera.y, 255, 0, 255);
}
}
if (g_engine->_debugDraw & DRAW_PATHING) {
for (const auto &iter : _pathing._vSolution) {
bool nextToWall = false;
for (const auto &neighbor : iter->_neighborNodes) {
if (neighbor->getMovementCost() < 0 || neighbor->getMovementCost() > 1) {
nextToWall = true;
break;
}
}
if (nextToWall)
iter->getRect().draw(-camera.x, -camera.y, 0, 0, 0, 254);
else
iter->getRect().draw(-camera.x, -camera.y, 200, 200, 0, 254);
}
if (_pathing._goalTile && _pathing._startTile) {
_pathing._goalTile->getRect().draw(-camera.x, -camera.y, 0, 0, 200, 254);
_pathing._startTile->getRect().draw(-camera.x, -camera.y, 0, 200, 0, 254);
}
Rect destinationRect = Rect((int)_pathing._destination.x - 5,
(int)_pathing._destination.y - 5,
10,
10);
destinationRect.draw(-camera.x, -camera.y, 0, 200, 0, 254);
}
}
void Sprite::drawPopup(pyrodactyl::ui::ParagraphData &pop, const Rect &camera) {
// This is different from draw because we draw the popup centered over the head
int x = _pos.x - camera.x - _animSet.anchorX(_dir) + (_animSet._bounds.w / 2);
int y = _pos.y - camera.y - _animSet.anchorY(_dir);
_popup.draw(x, y, pop, camera);
}
//------------------------------------------------------------------------
// Purpose: Handle the movement in a level for the player only
//------------------------------------------------------------------------
void Sprite::handleEvents(Info &info, const Rect &camera, const SpriteConstant &sc, const Common::Event &event) {
int num = 0;
info.statGet(_id, pyrodactyl::stat::STAT_SPEED, num);
++num;
float playerSpeed = static_cast<float>(num);
// This is for Diablo style hold-mouse-button-in-direction-of-movement
// This is only used if - point and click movement isn't being used, cursor is not inside the hud, the cursor is a normal cursor and the mouse is pressed
if (!_aiData._dest._active && !g_engine->_mouse->_insideHud && !g_engine->_mouse->_hover && g_engine->_mouse->pressed()) {
// To find where the click is w.r.t sprite, we need to see where it is being drawn
int x = _pos.x - camera.x - _animSet.anchorX(_dir), y = _pos.y - camera.y - _animSet.anchorY(_dir);
// Just use the bound rectangle dimensions
Rect b = boundRect();
int w = b.w, h = b.h;
// X axis
if (g_engine->_mouse->_motion.x > x + w)
xVel(playerSpeed * sc._walkVelMod.x);
else if (g_engine->_mouse->_motion.x < x)
xVel(-playerSpeed * sc._walkVelMod.x);
else
xVel(0.0f);
// Y axis
if (g_engine->_mouse->_motion.y > y + h)
yVel(playerSpeed * sc._walkVelMod.y);
else if (g_engine->_mouse->_motion.y < y)
yVel(-playerSpeed * sc._walkVelMod.y);
else
yVel(0.0f);
} else { // Keyboard movement
// Disable destination as soon as player presses a direction key
// X axis
if (g_engine->_inputManager->state(IG_LEFT)) {
_aiData._dest._active = false;
xVel(-playerSpeed * sc._walkVelMod.x);
} else if (g_engine->_inputManager->state(IG_RIGHT)) {
_aiData._dest._active = false;
xVel(playerSpeed * sc._walkVelMod.x);
} else if (!_aiData._dest._active)
xVel(0.0f);
// Y axis
if (g_engine->_inputManager->state(IG_UP)) {
_aiData._dest._active = false;
yVel(-playerSpeed * sc._walkVelMod.y);
} else if (g_engine->_inputManager->state(IG_DOWN)) {
_aiData._dest._active = false;
yVel(playerSpeed * sc._walkVelMod.y);
} else if (!_aiData._dest._active)
yVel(0.0f);
}
updateMove(_input.handleEvents(event));
// This is to prevent one frame of drawing with incorrect parameters
animate(info);
}
//------------------------------------------------------------------------
// Purpose: Set destination for sprite movement
//------------------------------------------------------------------------
void Sprite::setDestPathfinding(const Vector2i &dest, bool reachable) {
_aiData.dest(dest, true);
_pathing.setDestination(dest, reachable);
}
//------------------------------------------------------------------------
// Purpose: Walking animation
//------------------------------------------------------------------------
void Sprite::walk(const pyrodactyl::people::PersonState &pst) {
_imgEff._visible = false;
bool firstX = true;
if (_aiData._dest._active) {
Rect b = boundRect();
if (_pos.x - _aiData._dest.x > -b.w && _pos.x - _aiData._dest.x < b.w)
firstX = false;
}
bool reset = _animSet._walk.type(_vel, _dir, pst, firstX);
if (reset)
_animSet._walk.resetClip(_dir);
walk(reset);
}
void Sprite::walk(const bool &reset) {
if (_animSet._walk.updateClip(_dir, reset)) {
_clip = _animSet._walk.clip(_dir);
_boxV = _animSet._walk.boxV(_dir);
}
}
//------------------------------------------------------------------------
// Purpose: Decide which animation to play
//------------------------------------------------------------------------
void Sprite::animate(Info &info) {
if (_input.idle())
walk(info.state(_id));
else
updateFrame(info.state(_id));
}
void Sprite::animate(const pyrodactyl::people::PersonState &pst) {
walk(pst);
}
//------------------------------------------------------------------------
// Purpose: We need to find if the vulnerable area of this sprite collides
// with hitbox (usually the damage area of another sprite)
//------------------------------------------------------------------------
bool Sprite::fightCollide(Rect hitbox, Rect enemyBounds, Range &range, const SpriteConstant &sc) {
Rect bounds = boundRect();
if (range._valid) {
Rect actualRange = rangeRect(bounds, range);
// The second part is a sanity check so the stray hitbox of a sprite 1000 pixels below does not cause damage
if (hitbox.collide(actualRange) && abs(bounds.y + bounds.h - enemyBounds.y - enemyBounds.h) < sc._planeW)
return true;
} else {
if (hitbox.collide(bounds) && abs(bounds.y + bounds.h - enemyBounds.y - enemyBounds.h) < sc._planeW)
return true;
}
return false;
}
//------------------------------------------------------------------------
// Purpose: Update the frame info of the sprite
//------------------------------------------------------------------------
void Sprite::updateFrame(const pyrodactyl::people::PersonState &pst, const bool &repeat) {
FrameUpdateResult res = _animSet._fight.updateFrame(_dir);
if (res == FUR_SUCCESS) {
assignFrame();
} else if (res == FUR_FAIL) {
_damageDone = false;
stop();
if (repeat == false)
resetFrame(pst);
else
_animSet._fight.frameIndex(0);
}
}
void Sprite::assignFrame() {
FightAnimFrame faf;
if (_animSet._fight.curFrame(faf, _dir)) {
_clip = faf._clip;
boxV(faf._boxV);
boxD(faf._boxD);
_pos.x += faf._delta.x;
_pos.y += faf._delta.y;
_input._state = faf._state;
}
}
//------------------------------------------------------------------------
// Purpose: Update the move info of the player sprite
//------------------------------------------------------------------------
void Sprite::updateMove(const FightAnimationType &combo) {
if (combo != FA_IDLE) {
if (_input.idle())
forceUpdateMove(combo);
else {
FightAnimFrame faf;
if (_animSet._fight.curFrame(faf, _dir))
if (faf._branch)
forceUpdateMove(combo);
}
}
}
void Sprite::forceUpdateMove(const FightAnimationType &combo) {
uint index = _animSet._fight.findMove(combo, _input._state);
forceUpdateMove(index);
}
//------------------------------------------------------------------------
// Purpose: Update the move info of the AI or player sprite
//------------------------------------------------------------------------
void Sprite::updateMove(const uint &index) {
if (_input.idle())
forceUpdateMove(index);
}
void Sprite::forceUpdateMove(const uint &index) {
if (_animSet._fight.forceUpdate(index, _input, _dir)) {
// This sets the sprite input to the current move input
_animSet._fight.curCombo(_input);
stop();
assignFrame();
} else
_input.reset();
}
//------------------------------------------------------------------------
// Purpose: Reset the frame info of the sprite
//------------------------------------------------------------------------
void Sprite::resetFrame(const pyrodactyl::people::PersonState &pst) {
_input.reset();
walk(true);
_animSet._fight.reset();
_boxD.w = 0;
_boxD.h = 0;
}
//------------------------------------------------------------------------
// Purpose: Check if both sprites in the same plane
//------------------------------------------------------------------------
bool Sprite::damageValid(Sprite &s, const SpriteConstant &sc) {
// Get the y coordinates where these sprites are standing
float Y = _pos.y + _clip.h, SY = s._pos.y + s._clip.h;
if (abs(Y - SY) < sc._planeW)
return true;
return false;
}
//------------------------------------------------------------------------
// Purpose: Checks about dealing damage to sprite
//------------------------------------------------------------------------
void Sprite::calcProperties(Info &info) {
_visible.evaluate(info);
_animSet._fight.evaluate(info);
}
//------------------------------------------------------------------------
// Purpose: Checks about dealing damage to sprite
//------------------------------------------------------------------------
bool Sprite::takingDamage(Sprite &sp, const SpriteConstant &sc) {
if (damageValid(sp, sc))
if (boxV().w > 0 && boxV().h > 0 && sp.boxD().w > 0 && sp.boxD().h > 0)
if (boxV().collide(sp.boxD()))
return true;
/*Common::String words = NumberToString(BoxV().x) + " " + NumberToString(BoxV().y)+ " " + NumberToString(BoxV().w)
+ " " + NumberToString(BoxV().h) + "\n" + NumberToString(sp.BoxD().x) + " " + NumberToString(sp.BoxD().y)
+ " " + NumberToString(sp.BoxD().w) + " " + NumberToString(sp.BoxD().h) + "\n";
fprintf(stdout,words.c_str());*/
return false;
}
//------------------------------------------------------------------------
// Purpose: We know we are taking damage, now is the time to update stats
//------------------------------------------------------------------------
void Sprite::takeDamage(Info &info, Sprite &s) {
using namespace pyrodactyl::stat;
using namespace pyrodactyl::music;
FightMove f;
if (s._animSet._fight.curMove(f) && info.personValid(s.id()) && info.personValid(_id)) {
int dmg = -1 * (f._eff._dmg + info.personGet(s.id())._stat._val[STAT_ATTACK]._cur - info.personGet(_id)._stat._val[STAT_DEFENSE]._cur);
if (dmg >= 0)
dmg = -1;
info.statChange(_id, STAT_HEALTH, dmg);
int health = 1;
info.statGet(_id, STAT_HEALTH, health);
// Play death animation if dead, hurt animation otherwise
if (health <= 0 && f._eff._death != -1)
forceUpdateMove(f._eff._death);
else if (f._eff._hurt != -1)
forceUpdateMove(f._eff._hurt);
g_engine->_musicManager->playEffect(f._eff._hit, 0);
_imgEff = f._eff._img;
}
stop();
s._damageDone = true;
}
//------------------------------------------------------------------------
// Purpose: We have 2 sprites, *this and s.
// Check damage between s.boxV and this->boxD and vice versa
//------------------------------------------------------------------------
void Sprite::exchangeDamage(Info &info, Sprite &s, const SpriteConstant &sc) {
using namespace pyrodactyl::people;
using namespace pyrodactyl::stat;
// This object is taking damage from s
if (!s._damageDone && takingDamage(s, sc))
takeDamage(info, s);
// Is the other sprite taking damage from this sprite?
if (!_damageDone && s.takingDamage(*this, sc))
s.takeDamage(info, *this);
// We change the animation to dying in order to give time to the death animation to play out
int num = 0;
info.statGet(s.id(), STAT_HEALTH, num);
if (num <= 0) {
info.state(s.id(), PST_DYING);
info.statChange(s.id(), STAT_HEALTH, 1);
}
info.statGet(_id, STAT_HEALTH, num);
if (num <= 0) {
info.state(_id, PST_DYING);
info.statChange(_id, STAT_HEALTH, 1);
}
}
//------------------------------------------------------------------------
// Purpose: Update status of ambient dialog via popup object
//------------------------------------------------------------------------
void Sprite::internalEvents(Info &info, const Common::String &player_id, Common::Array<EventResult> &result, Common::Array<EventSeqInfo> &end_seq) {
_popup.internalEvents(info, player_id, result, end_seq);
}
//------------------------------------------------------------------------
// Purpose: Save all sprite positions to save file
//------------------------------------------------------------------------
void Sprite::saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root) {
root->append_attribute(doc.allocate_attribute("id", _id.c_str()));
root->append_attribute(doc.allocate_attribute("x", g_engine->_stringPool->get(_pos.x)));
root->append_attribute(doc.allocate_attribute("y", g_engine->_stringPool->get(_pos.y)));
}
//------------------------------------------------------------------------
// Purpose: Load all sprite positions from save file
//------------------------------------------------------------------------
void Sprite::loadState(rapidxml::xml_node<char> *node) {
loadNum(_pos.x, "x", node);
loadNum(_pos.y, "y", node);
}
} // End of namespace Crab

View File

@@ -0,0 +1,295 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_SPRITE_H
#define CRAB_SPRITE_H
#include "crab/collision.h"
#include "crab/timer.h"
#include "crab/ai/spriteai.h"
#include "crab/ai/SpriteConstant.h"
#include "crab/animation/animset.h"
#include "crab/animation/PopUp.h"
#include "crab/level/LevelExit.h"
namespace Crab {
class PathfindingAgent;
namespace pyrodactyl {
namespace anim {
class Sprite {
protected:
// Used to sync sprite to character
Common::String _id;
// The position of the sprite
Vector2i _pos;
// The velocity of the sprite, target velocity is our maximum velocity
Vector2f _vel, _target;
// The image of the sprite and it's dimensions
ImageKey _image;
Vector2i _imgSize;
// Clip is the portion of the sprite map to be drawn
Rect _clip;
// The hit boxes of the character - v is vulnerable hit box, d is damage hit box
Rect _boxV, _boxD;
// The direction the sprite is facing
Direction _dir;
// The currently playing image effect
ImageEffect _imgEff;
// The complete animation set for the sprite
AnimSet _animSet;
// The conditions for sprite visibility
pyrodactyl::event::TriggerSet _visible;
// Current sprite combo and input for the sprite
pyrodactyl::input::FightInput _input;
// Have we done damage for this frame - used to avoid repeated damage for the same frame
bool _damageDone;
// Dialog shown without events
PopUpCollection _popup;
protected:
void resetFrame(const pyrodactyl::people::PersonState &pst);
bool fightCollide(Rect hitbox, Rect enemy_bounds, Range &range, const pyrodactyl::ai::SpriteConstant &sc);
bool damageValid(Sprite &s, const pyrodactyl::ai::SpriteConstant &sc);
void clip(const Rect &rect) { _clip = rect; }
void boxV(const Rect &rect) { _boxV = rect; }
void boxD(const Rect &rect) { _boxD = rect; }
public:
// The AI data for the sprite
pyrodactyl::ai::SpriteAIData _aiData;
PathfindingAgent _pathing;
// The modifier applied to the sprite velocity
Vector2f _velMod;
// The layer associated with the sprite (used to show/hide sprite according to auto hide layers)
int _layer;
// Is the mouse hovering over this sprite?
bool _hover;
// The list of collisions currently taking place with the sprite
Common::List<CollisionData> _collideData;
Sprite();
~Sprite() {
_pathing.reset();
}
void visible(bool val) {
_visible.result(val);
}
bool visible() {
return _visible.result();
}
void calcProperties(pyrodactyl::event::Info &info);
void x(int X) {
_pos.x = X;
}
void y(int Y) {
_pos.y = Y;
}
int x() {
return _pos.x;
}
int y() {
return _pos.y;
}
void walkPattern(const pyrodactyl::ai::MovementSet &set) {
_aiData._walk = set;
}
void move(const pyrodactyl::ai::SpriteConstant &sc);
// Resolve collisions for polygons we want to be outside of
void resolveCollide();
// Resolve collisions for the walk rectangle
void resolveInside(Rect collider);
void stop() {
_vel.Set();
_target.Set();
_aiData._dest._active = false;
}
void inputStop() {
_input.reset();
}
void xVel(const float &val) {
_target.x = val * _velMod.x;
}
void yVel(const float &val) {
_target.y = val * _velMod.y;
}
float xVel() {
return _vel.x;
}
float yVel() {
return _vel.y;
}
Vector2f vel() {
return _vel;
}
const Common::String &id() {
return _id;
}
int w() {
return _clip.w;
}
int h() {
return _clip.h;
}
const ImageKey &img() {
return _image;
}
Rect dialogClip(const pyrodactyl::people::PersonState &state) {
return _animSet._walk.dialogClip(state);
}
void dialogUpdateClip(const pyrodactyl::people::PersonState &state) {
_animSet._walk.updateClip(state);
}
bool popupShow() {
return _popup.show();
}
Rect boundRect();
Rect boxV();
Rect boxD();
Rect posRect();
Rect rangeRect(const Rect &bounds, const Range &range);
Vector2i camFocus();
double distSq(const Sprite &s);
void effectImg(bool vis) {
_imgEff._visible = vis;
}
bool lastFrame() {
return _animSet._fight.lastFrame();
}
bool takingDamage(Sprite &sp, const pyrodactyl::ai::SpriteConstant &sc);
void takeDamage(pyrodactyl::event::Info &info, Sprite &s);
void exchangeDamage(pyrodactyl::event::Info &info, Sprite &s, const pyrodactyl::ai::SpriteConstant &sc);
void load(rapidxml::xml_node<char> *node, Common::Array<Common::Path> &animations);
void internalEvents(pyrodactyl::event::Info &info, const Common::String &player_id,
Common::Array<pyrodactyl::event::EventResult> &result, Common::Array<pyrodactyl::event::EventSeqInfo> &end_seq);
void draw(pyrodactyl::event::Info &info, const Rect &camera);
void drawPopup(pyrodactyl::ui::ParagraphData &pop, const Rect &camera);
void walk(const bool &reset);
void walk(const pyrodactyl::people::PersonState &pst);
void updateFrame(const pyrodactyl::people::PersonState &pst, const bool &repeat = false);
void assignFrame();
void updateMove(const pyrodactyl::input::FightAnimationType &combo);
void forceUpdateMove(const pyrodactyl::input::FightAnimationType &combo);
void updateMove(const uint &index);
void forceUpdateMove(const uint &index);
// Set sprite destination
void setDestPathfinding(const Vector2i &dest, bool reachable = true);
// Used for sprite movement controlled by player input (usually the player sprite)
void handleEvents(pyrodactyl::event::Info &info, const Rect &camera, const pyrodactyl::ai::SpriteConstant &sc, const Common::Event &event);
// This is for sprites with valid object ids
void animate(pyrodactyl::event::Info &info);
// This is for objects without valid ids - like <background> and <fly> sprites
void animate(const pyrodactyl::people::PersonState &pst);
// AI behavior routine for sprites attacking the player
void attack(pyrodactyl::event::Info &info, Sprite &targetSp, const pyrodactyl::ai::SpriteConstant &sc);
// AI behavior routine for sprites running away from the player
// Requires every exit in the level be accessible
void flee(pyrodactyl::event::Info &info, Common::Array<pyrodactyl::level::Exit> &areaExit, const pyrodactyl::ai::SpriteConstant &sc);
// Used for sprites that fly across semi randomly on the screen
void flyAround(const Rect &camera, const pyrodactyl::ai::SpriteConstant &sc);
// Used for the player destination movement
void moveToDest(pyrodactyl::event::Info &info, const pyrodactyl::ai::SpriteConstant &sc);
void moveToDestPathfinding(pyrodactyl::event::Info &info, const pyrodactyl::ai::SpriteConstant &sc);
// Used for AI movement - returns true if at the destination, false otherwise
bool moveToLoc(Vector2i &dest, const float &vel, const pyrodactyl::ai::SpriteConstant &sc);
bool moveToLocPathfinding(Vector2i &dest, const float &vel, const pyrodactyl::ai::SpriteConstant &sc);
void saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root);
void loadState(rapidxml::xml_node<char> *node);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_SPRITE_H

View File

@@ -0,0 +1,155 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#include "crab/animation/walkframes.h"
namespace Crab {
using namespace pyrodactyl::anim;
using namespace pyrodactyl::people;
//------------------------------------------------------------------------
// Purpose: Loader Function
//------------------------------------------------------------------------
void WalkFrames::load(rapidxml::xml_node<char> *node) {
if (nodeValid("stand", node))
_set[WT_STAND].load(node->first_node("stand"));
if (nodeValid("walk", node))
_set[WT_WALK].load(node->first_node("walk"));
if (nodeValid("fight", node))
_set[WT_FIGHT].load(node->first_node("fight"));
if (nodeValid("ko", node))
_set[WT_KO].load(node->first_node("ko"));
}
//------------------------------------------------------------------------
// Purpose: Used for walking inside levels
//------------------------------------------------------------------------
bool WalkFrames::updateClip(Direction d, bool reset) {
if (_timer.ticks() > _set[_cur].frames[d].currentFrame()._repeat || reset) {
_timer.start();
return _set[_cur].frames[d].updateClip();
}
return false;
}
void WalkFrames::resetClip(Direction d) {
_set[_cur].frames[d].reset();
_timer.start();
}
//------------------------------------------------------------------------
// Purpose: Used inside dialog box
//------------------------------------------------------------------------
void WalkFrames::updateClip(WalkAnimType type, Direction d) {
if (!_timer.started())
_timer.start();
if (_timer.ticks() > _set[type].frames[d].currentFrame()._repeat) {
_set[type].frames[d].updateClip();
_timer.start();
}
}
Rect WalkFrames::dialogClip(const PersonState &state) {
if (state == PST_FIGHT)
return _set[WT_FIGHT].frames[DIRECTION_DOWN].currentFrame()._clip;
else if (state == PST_KO)
return _set[WT_KO].frames[DIRECTION_DOWN].currentFrame()._clip;
return _set[WT_STAND].frames[DIRECTION_DOWN].currentFrame()._clip;
}
void WalkFrames::updateClip(const PersonState &state) {
if (state == PST_FIGHT)
updateClip(WT_FIGHT, DIRECTION_DOWN);
else if (state == PST_KO)
updateClip(WT_KO, DIRECTION_DOWN);
else
updateClip(WT_STAND, DIRECTION_DOWN);
}
//------------------------------------------------------------------------
// Purpose: Decide direction and type of animation, return whether it has changed
//------------------------------------------------------------------------
bool WalkFrames::type(const Vector2f &vel, Direction &dir, const pyrodactyl::people::PersonState &pst, const bool &firstX) {
Direction prevDir = dir;
WalkAnimType prevType = _cur;
if (pst == PST_KO) {
_cur = WT_KO;
} else if (firstX) {
// If we prioritize the X direction, X velocity is checked first for direction and then Y velocity
if (vel.x > 0) {
dir = DIRECTION_RIGHT;
_cur = WT_WALK;
} else if (vel.x < 0) {
dir = DIRECTION_LEFT;
_cur = WT_WALK;
} else if (vel.y > 0) {
dir = DIRECTION_DOWN;
_cur = WT_WALK;
} else if (vel.y < 0) {
dir = DIRECTION_UP;
_cur = WT_WALK;
} else {
_cur = WT_STAND;
}
} else {
// If we prioritize the Y direction, Y velocity is checked first for direction and then Y velocity
if (vel.y > 0) {
dir = DIRECTION_DOWN;
_cur = WT_WALK;
} else if (vel.y < 0) {
dir = DIRECTION_UP;
_cur = WT_WALK;
} else if (vel.x > 0) {
dir = DIRECTION_RIGHT;
_cur = WT_WALK;
} else if (vel.x < 0) {
dir = DIRECTION_LEFT;
_cur = WT_WALK;
} else {
_cur = WT_STAND;
}
}
if (prevDir != dir || prevType != _cur)
return true;
return false;
}
} // End of namespace Crab

View File

@@ -0,0 +1,130 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This code is based on the CRAB engine
*
* Copyright (c) Arvind Raja Yadav
*
* Licensed under MIT
*
*/
#ifndef CRAB_WALKFRAMES_H
#define CRAB_WALKFRAMES_H
#include "crab/timer.h"
#include "crab/ai/movement.h"
#include "crab/animation/animframe.h"
#include "crab/people/personbase.h"
namespace Crab {
namespace pyrodactyl {
namespace anim {
enum WalkAnimType {
WT_STAND,
WT_WALK,
WT_FIGHT,
WT_KO,
WT_TOTAL
};
class WalkFrames {
struct WalkFrameSet {
AnimationFrames frames[DIRECTION_TOTAL];
void load(rapidxml::xml_node<char> *node) {
frames[DIRECTION_DOWN].load(node->first_node("down"));
frames[DIRECTION_UP].load(node->first_node("up"));
frames[DIRECTION_LEFT].load(node->first_node("left"));
frames[DIRECTION_RIGHT].load(node->first_node("right"));
}
};
// The walking animations of the sprite
WalkFrameSet _set[WT_TOTAL];
// The current walking animation
WalkAnimType _cur;
// The timers used for animation playing
Timer _timer;
// Dialog box related
void updateClip(WalkAnimType type, Direction d);
public:
WalkFrames() {
_cur = WT_STAND;
_timer.start();
}
~WalkFrames() {}
void load(rapidxml::xml_node<char> *node);
bool updateClip(Direction d, bool reset);
void resetClip(Direction d);
void type(WalkAnimType type) {
_cur = type;
}
WalkAnimType type() {
return _cur;
}
bool type(const Vector2f &vel, Direction &dir, const pyrodactyl::people::PersonState &pst, const bool &first_x);
const Rect &clip(Direction d) {
return _set[_cur].frames[d].currentFrame()._clip;
}
const Rect &boxV(Direction d) {
return _set[_cur].frames[d].currentFrame()._boxV;
}
const TextureFlipType &flip(Direction d) {
return _set[_cur].frames[d]._flip;
}
const ShadowOffset &shadow(Direction d) {
return _set[_cur].frames[d]._shadow;
}
int anchorX(Direction d) {
return _set[_cur].frames[d].currentFrame()._anchor.x;
}
int anchorY(Direction d) {
return _set[_cur].frames[d].currentFrame()._anchor.y;
}
// Dialog box related
Rect dialogClip(const pyrodactyl::people::PersonState &state);
void updateClip(const pyrodactyl::people::PersonState &state);
};
} // End of namespace anim
} // End of namespace pyrodactyl
} // End of namespace Crab
#endif // CRAB_WALKFRAMES_H