Initial commit
This commit is contained in:
96
engines/crab/GameClock.h
Normal file
96
engines/crab/GameClock.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* 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_GAMECLOCK_H
|
||||
#define CRAB_GAMECLOCK_H
|
||||
|
||||
#include "crab/numstr.h"
|
||||
#include "crab/timer.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
class GameClock {
|
||||
Timer _timer;
|
||||
uint32 _start;
|
||||
Common::String _seperator;
|
||||
|
||||
public:
|
||||
GameClock() : _seperator(" : ") { _start = 0; }
|
||||
|
||||
void start(uint32 initialTime = 0) {
|
||||
_start = initialTime;
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
void start(const Common::String &str) {
|
||||
uint32 ms = 0, hr = 0, min = 0, sec = 0;
|
||||
Common::String strHrs, strMin, strSec;
|
||||
|
||||
size_t found1 = str.findFirstOf(_seperator);
|
||||
if (found1 > 0 && found1 != Common::String::npos) {
|
||||
strHrs = str.substr(0, found1);
|
||||
hr = stringToNumber<uint32>(strHrs);
|
||||
|
||||
size_t found2 = str.findFirstOf(_seperator);
|
||||
if (found2 > 0 && found2 != Common::String::npos) {
|
||||
strSec = str.substr(found2 + 1, Common::String::npos);
|
||||
sec = stringToNumber<uint32>(strSec);
|
||||
|
||||
strMin = str.substr(found1 + _seperator.size(), found2 - (2 * _seperator.size()));
|
||||
min = stringToNumber<uint32>(strMin);
|
||||
}
|
||||
}
|
||||
|
||||
ms = 3600000 * hr + 60000 * min + 1000 * sec;
|
||||
start(ms);
|
||||
}
|
||||
|
||||
Common::String getTime() {
|
||||
uint32 ms = _start + _timer.ticks();
|
||||
|
||||
uint32 x = ms / 1000;
|
||||
uint32 seconds = x % 60;
|
||||
x /= 60;
|
||||
uint32 minutes = x % 60;
|
||||
uint32 hours = x / 60;
|
||||
|
||||
Common::String timeStr = numberToString(hours);
|
||||
timeStr += _seperator;
|
||||
timeStr += numberToString(minutes);
|
||||
timeStr += _seperator;
|
||||
timeStr += numberToString(seconds);
|
||||
|
||||
return timeStr;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_GAMECLOCK_H
|
||||
145
engines/crab/GameParam.cpp
Normal file
145
engines/crab/GameParam.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/* 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/GameParam.h"
|
||||
#include "crab/XMLDoc.h"
|
||||
|
||||
namespace Crab {
|
||||
// Are we in debug mode or not?
|
||||
bool GameDebug = false;
|
||||
|
||||
FilePaths::FilePaths() : _common("res/levels/common.xml"),
|
||||
_modPath("mods/"),
|
||||
_modExt(".unrmod"),
|
||||
_modCur("res/default.xml"),
|
||||
_mainmenuL("res/layout/main_menu_l.xml"),
|
||||
_mainmenuR("res/layout/main_menu_r.xml"),
|
||||
_soundEffect("res/sounds/effects.xml"),
|
||||
_soundMusic("res/sounds/music.xml"),
|
||||
_font("res/fonts/fonts.xml"),
|
||||
_icon("res/gfx/icon.bmp"),
|
||||
_saveDir("save/"),
|
||||
_saveExt(".unr"),
|
||||
_shaders("res/shaders/list.xml"),
|
||||
_colors("res/gfx/colors.xml"),
|
||||
_currentR("res/layout/main_menu_r.xml") {
|
||||
_level.clear();
|
||||
_loaded = false;
|
||||
|
||||
warning("FilePaths::FilePaths() setting appdata directory to game dir");
|
||||
_appdata = "./";
|
||||
}
|
||||
|
||||
void FilePaths::loadLevel(const Common::Path &filename) {
|
||||
_level.clear();
|
||||
XMLDoc lev_list(filename);
|
||||
if (lev_list.ready()) {
|
||||
rapidxml::xml_node<char> *node = lev_list.doc()->first_node("world");
|
||||
|
||||
for (rapidxml::xml_node<char> *n = node->first_node("loc"); n != nullptr; n = n->next_sibling("loc")) {
|
||||
LevelPath l;
|
||||
l.load(n);
|
||||
|
||||
Common::String id;
|
||||
loadStr(id, "id", n);
|
||||
|
||||
_level[id] = Common::move(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FilePaths::load(const Common::Path &filename) {
|
||||
XMLDoc settings(filename);
|
||||
if (settings.ready()) {
|
||||
rapidxml::xml_node<char> *node = settings.doc()->first_node("paths");
|
||||
|
||||
if (nodeValid(node) && !_loaded) {
|
||||
if (nodeValid("icon", node)) {
|
||||
rapidxml::xml_node<char> *iconode = node->first_node("icon");
|
||||
_icon = iconode->value();
|
||||
}
|
||||
|
||||
if (nodeValid("common", node)) {
|
||||
rapidxml::xml_node<char> *commonnode = node->first_node("common");
|
||||
_common = commonnode->value();
|
||||
}
|
||||
|
||||
if (nodeValid("font", node)) {
|
||||
rapidxml::xml_node<char> *fontnode = node->first_node("font");
|
||||
_font = fontnode->value();
|
||||
}
|
||||
|
||||
if (nodeValid("shader", node)) {
|
||||
rapidxml::xml_node<char> *shadnode = node->first_node("shader");
|
||||
_shaders = shadnode->value();
|
||||
}
|
||||
|
||||
if (nodeValid("color", node)) {
|
||||
rapidxml::xml_node<char> *colnode = node->first_node("color");
|
||||
_colors = colnode->value();
|
||||
}
|
||||
|
||||
if (nodeValid("mod", node)) {
|
||||
rapidxml::xml_node<char> *modnode = node->first_node("mod");
|
||||
loadPath(_modPath, "path", modnode);
|
||||
loadPath(_modCur, "cur", modnode);
|
||||
loadStr(_modExt, "ext", modnode);
|
||||
}
|
||||
|
||||
if (nodeValid("main_menu", node)) {
|
||||
rapidxml::xml_node<char> *menunode = node->first_node("main_menu");
|
||||
loadPath(_mainmenuL, "l", menunode);
|
||||
loadPath(_mainmenuR, "r", menunode);
|
||||
_currentR = _mainmenuR;
|
||||
}
|
||||
|
||||
if (nodeValid("sound", node)) {
|
||||
rapidxml::xml_node<char> *soundnode = node->first_node("sound");
|
||||
loadPath(_soundEffect, "effect", soundnode);
|
||||
loadPath(_soundMusic, "music", soundnode);
|
||||
}
|
||||
|
||||
if (nodeValid("save", node)) {
|
||||
rapidxml::xml_node<char> *savenode = node->first_node("save");
|
||||
loadPath(_saveDir, "dir", savenode);
|
||||
loadStr(_saveExt, "ext", savenode);
|
||||
|
||||
Common::String custom_path;
|
||||
if (loadStr(custom_path, "custom", savenode)) {
|
||||
warning("In FilePaths::load(), customPath : %s", custom_path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
_loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
180
engines/crab/GameParam.h
Normal file
180
engines/crab/GameParam.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/* 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_GAMEPARAM_H
|
||||
#define CRAB_GAMEPARAM_H
|
||||
|
||||
#include "common/hashmap.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/list.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
#include "crab/loaders.h"
|
||||
#include "crab/rapidxml/rapidxml.hpp"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// The index for all levels in the game
|
||||
struct LevelPath {
|
||||
// The file paths
|
||||
Common::Path _layout, _asset;
|
||||
|
||||
// The name of the level
|
||||
Common::String _name;
|
||||
|
||||
LevelPath() {}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node) {
|
||||
loadStr(_name, "name", node);
|
||||
loadPath(_layout, "layout", node);
|
||||
loadPath(_asset, "res", node);
|
||||
}
|
||||
};
|
||||
|
||||
// Stores all layout paths for the game
|
||||
struct FilePaths {
|
||||
// Resources common to all levels and states
|
||||
Common::Path _common;
|
||||
|
||||
// Mod file location, current mod and their extension
|
||||
Common::Path _modPath, _modCur;
|
||||
Common::String _modExt;
|
||||
|
||||
// Main menu resources
|
||||
Common::Path _mainmenuL, _mainmenuR;
|
||||
|
||||
// Sounds
|
||||
Common::Path _soundEffect, _soundMusic;
|
||||
|
||||
// Fonts and window icon file
|
||||
Common::Path _font, _icon;
|
||||
|
||||
// Save directory and extension
|
||||
Common::Path _saveDir;
|
||||
Common::String _saveExt;
|
||||
|
||||
// The location of the shader index file
|
||||
Common::Path _shaders;
|
||||
|
||||
// The location of the color index file
|
||||
Common::Path _colors;
|
||||
|
||||
// The list of levels in the game
|
||||
Common::HashMap<Common::String, LevelPath> _level;
|
||||
|
||||
// The file path of the current resource file
|
||||
Common::Path _currentR;
|
||||
|
||||
// The application data path (where saves and settings are stored)
|
||||
Common::Path _appdata;
|
||||
|
||||
// Has this been loaded?
|
||||
bool _loaded;
|
||||
|
||||
FilePaths();
|
||||
void load(const Common::Path &filename);
|
||||
void loadLevel(const Common::Path &filename);
|
||||
};
|
||||
|
||||
// Storage pool used for saving numbers as strings
|
||||
class StringPool {
|
||||
// Store integer strings here
|
||||
// std::unordered_map<int, Common::String> pool_i;
|
||||
Common::HashMap<int, Common::String> poolI;
|
||||
|
||||
// Store floating point strings here
|
||||
struct FloatString {
|
||||
float _val;
|
||||
Common::String _str;
|
||||
|
||||
FloatString() {
|
||||
_val = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
// std::list<FloatString> pool_f;
|
||||
Common::List<FloatString> poolF;
|
||||
|
||||
public:
|
||||
StringPool() {
|
||||
poolI.clear();
|
||||
poolF.clear();
|
||||
}
|
||||
|
||||
const char *get(const int &num) {
|
||||
if (poolI.contains(num) == false)
|
||||
poolI[num] = numberToString<int>(num);
|
||||
|
||||
return poolI.getVal(num).c_str();
|
||||
}
|
||||
|
||||
const char *fGet(const float &num) {
|
||||
for (auto &i : poolF)
|
||||
if (i._val == num)
|
||||
return i._str.c_str();
|
||||
|
||||
FloatString fs;
|
||||
fs._val = num;
|
||||
fs._str = numberToString<float>(num);
|
||||
poolF.push_back(fs);
|
||||
|
||||
auto ret = poolF.back();
|
||||
return ret._str.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
struct TempValue {
|
||||
// Differences between normal mode and iron man mode
|
||||
// save button - iron man saves in existing file
|
||||
// load button - hidden in iron man
|
||||
// exit - saves and exits in iron man
|
||||
// quick save and quick load - operate on the iron man file in iron man mode
|
||||
bool _ironman;
|
||||
|
||||
// This is the filename a player chose when selecting "new game" + iron man mode
|
||||
Common::String _filename;
|
||||
|
||||
// We use this to see whether the player is exiting to main menu or to credits
|
||||
bool _credits;
|
||||
|
||||
TempValue() : _filename("No IronMan") {
|
||||
_ironman = false;
|
||||
_credits = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Our global objects
|
||||
|
||||
// Whether to draw debug outlines on polygons
|
||||
extern bool GameDebug;
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_GAMEPARAM_H
|
||||
58
engines/crab/LevelResult.h
Normal file
58
engines/crab/LevelResult.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* 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_LEVELRESULT_H
|
||||
#define CRAB_LEVELRESULT_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
enum LevelResultType {
|
||||
LR_NONE,
|
||||
LR_LEVEL,
|
||||
LR_GAMEOVER
|
||||
};
|
||||
|
||||
struct LevelResult {
|
||||
LevelResultType _type;
|
||||
Common::String _val;
|
||||
int _x, _y;
|
||||
|
||||
LevelResult() {
|
||||
_type = LR_NONE;
|
||||
_x = -1;
|
||||
_y = -1;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_LEVELRESULT_H
|
||||
72
engines/crab/Line.h
Normal file
72
engines/crab/Line.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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_LINE_H
|
||||
#define CRAB_LINE_H
|
||||
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// Find if 2 lines intersect and store the point of intersection
|
||||
template<typename T>
|
||||
bool collideLine(const T &p0X, const T &p0Y, const T &p1X, const T &p1Y,
|
||||
const T &p2X, const T &p2Y, const T &p3X, const T &p3Y,
|
||||
T *x = nullptr, T *y = nullptr) {
|
||||
Vector2D<T> s1, s2;
|
||||
s1.x = p1X - p0X;
|
||||
s1.y = p1Y - p0Y;
|
||||
s2.x = p3X - p2X;
|
||||
s2.y = p3Y - p2Y;
|
||||
|
||||
float d = (-s2.x * s1.y + s1.x * s2.y);
|
||||
|
||||
if (d != 0) {
|
||||
float s, t;
|
||||
s = (-s1.y * (p0X - p2X) + s1.x * (p0Y - p2Y)) / d;
|
||||
t = (s2.x * (p0Y - p2Y) - s2.y * (p0X - p2X)) / d;
|
||||
|
||||
if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
|
||||
// Collision detected
|
||||
if (x != nullptr)
|
||||
*x = p0X + (t * s1.x);
|
||||
if (y != nullptr)
|
||||
*y = p0Y + (t * s1.y);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // No collision
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_LINE_H
|
||||
93
engines/crab/LoadingScreen.cpp
Normal file
93
engines/crab/LoadingScreen.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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 "graphics/screen.h"
|
||||
#include "crab/crab.h"
|
||||
#include "crab/LoadingScreen.h"
|
||||
#include "crab/XMLDoc.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
void LoadingScreen::load() {
|
||||
Common::Path filename("res/layout/loading.xml");
|
||||
XMLDoc doc(filename);
|
||||
if (doc.ready()) {
|
||||
rapidxml::xml_node<char> *node = doc.doc()->first_node("loading");
|
||||
if (nodeValid(node)) {
|
||||
if (nodeValid("screens", node)) {
|
||||
rapidxml::xml_node<char> *scrnode = node->first_node("screens");
|
||||
for (auto n = scrnode->first_node("screen"); n != nullptr; n = n->next_sibling("screen"))
|
||||
_screen.push_back(n);
|
||||
}
|
||||
|
||||
if (nodeValid("text", node))
|
||||
_text.load(node->first_node("text"), "img");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoadingScreen::draw() {
|
||||
// Change to a random screen
|
||||
change();
|
||||
|
||||
// Draw the current screen
|
||||
if (_cur < _screen.size())
|
||||
_screen[_cur].draw();
|
||||
|
||||
// Draw the loading text
|
||||
_text.draw((g_engine->_screenSettings->_cur.w - _text.w()) / 2, (g_engine->_screenSettings->_cur.h - _text.h()) / 2);
|
||||
|
||||
// Update the screen
|
||||
g_engine->_screen->update();
|
||||
}
|
||||
|
||||
void LoadingScreen::dim() {
|
||||
warning("STUB: LoadingScreen::dim()");
|
||||
|
||||
#if 0
|
||||
// This is used when starting or loading a game from the main menu in order to dim the screen
|
||||
// until an actual loading screen is drawn
|
||||
SDL_SetRenderDrawBlendMode(gRenderer, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderDrawColor(gRenderer, 0, 0, 0, 200);
|
||||
SDL_RenderFillRect(gRenderer, NULL);
|
||||
|
||||
// Update the screen
|
||||
SDL_RenderPresent(gRenderer);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LoadingScreen::quit() {
|
||||
_text.deleteImage();
|
||||
|
||||
for (auto &i : _screen)
|
||||
i.clear();
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
84
engines/crab/LoadingScreen.h
Normal file
84
engines/crab/LoadingScreen.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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_LOADINGSCREEN_H
|
||||
#define CRAB_LOADINGSCREEN_H
|
||||
|
||||
#include "crab/image/Image.h"
|
||||
#include "crab/ScreenSettings.h"
|
||||
#include "crab/timer.h"
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
class LoadingScreen {
|
||||
struct Screen {
|
||||
// The background image
|
||||
pyrodactyl::image::Image _bg;
|
||||
|
||||
Screen(rapidxml::xml_node<char> *node) {
|
||||
_bg.load(node, "bg");
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_bg.deleteImage();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
_bg.draw((g_engine->_screenSettings->_cur.w - _bg.w()) / 2, (g_engine->_screenSettings->_cur.h - _bg.h()) / 2);
|
||||
}
|
||||
};
|
||||
|
||||
// The different loading screens
|
||||
Common::Array<Screen> _screen;
|
||||
|
||||
// The current loading screen
|
||||
uint _cur;
|
||||
|
||||
// The text image (says loading)
|
||||
pyrodactyl::image::Image _text;
|
||||
|
||||
public:
|
||||
LoadingScreen() { _cur = 0; };
|
||||
~LoadingScreen(){};
|
||||
|
||||
void change() {
|
||||
_cur = g_engine->getRandomNumber(_screen.size() - 1);
|
||||
}
|
||||
|
||||
void load();
|
||||
void draw();
|
||||
void dim();
|
||||
void quit();
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_LOADINGSCREEN_H
|
||||
2
engines/crab/POTFILES
Normal file
2
engines/crab/POTFILES
Normal file
@@ -0,0 +1,2 @@
|
||||
engines/crab/metaengine.cpp
|
||||
engines/crab/input/input.cpp
|
||||
312
engines/crab/PathfindingAgent.cpp
Normal file
312
engines/crab/PathfindingAgent.cpp
Normal file
@@ -0,0 +1,312 @@
|
||||
/* 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 "common/system.h"
|
||||
#include "crab/crab.h"
|
||||
#include "crab/PathfindingAgent.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// This keeps the PriorityQueue organized based on the cost of the paths.
|
||||
static bool compareNodes(PlannerNode const *nodeA, PlannerNode const *nodeB) {
|
||||
return nodeA->getFinalCost() > nodeB->getFinalCost();
|
||||
}
|
||||
|
||||
PathfindingAgent::PathfindingAgent() : _nodeQueue(compareNodes) {
|
||||
_grid = nullptr;
|
||||
|
||||
_destinationSet = false;
|
||||
_destinationReachable = false;
|
||||
_nodeBufferDistance = 1.0f;
|
||||
_solutionFound = _noSolution = false;
|
||||
|
||||
_startTile = nullptr;
|
||||
_goalTile = nullptr;
|
||||
_clickedTile = nullptr;
|
||||
}
|
||||
|
||||
PathfindingAgent::~PathfindingAgent() {
|
||||
}
|
||||
|
||||
void PathfindingAgent::initialize(PathfindingGrid *g) {
|
||||
_grid = g;
|
||||
|
||||
_nodeBufferDistance = _grid->getCellSize().x / 2.0f;
|
||||
|
||||
_nodeBufferDistance *= _nodeBufferDistance;
|
||||
}
|
||||
|
||||
void PathfindingAgent::setDestination(Vector2i d, bool r) {
|
||||
Vector2f iVec = Vector2f((float)d.x, (float)d.y);
|
||||
|
||||
setDestination(iVec, r);
|
||||
}
|
||||
|
||||
void PathfindingAgent::setDestination(Vector2i d) {
|
||||
setDestination(d, true);
|
||||
}
|
||||
|
||||
void PathfindingAgent::setDestination(Vector2f d) {
|
||||
setDestination(d, true);
|
||||
}
|
||||
|
||||
void PathfindingAgent::setDestination(Vector2f d, bool r) {
|
||||
if (_grid == nullptr)
|
||||
return;
|
||||
|
||||
_destination = d;
|
||||
|
||||
// TODO: This could be optimized to cache the route somehow... (SZ)
|
||||
reset();
|
||||
|
||||
_startTile = _grid->getNodeAtPoint(_position);
|
||||
// m_pGoalTile = grid->GetNodeAtPoint(d);
|
||||
|
||||
// I am now tracking the goal node and the clicked tile separately to solve problems
|
||||
// with hangups and trying to reach un-reachable destinations.
|
||||
_clickedTile = _grid->getNodeAtPoint(d);
|
||||
_goalTile = _grid->getNearestOpenNode(d, _position);
|
||||
|
||||
PlannerNode *startingNode = new PlannerNode();
|
||||
startingNode->setLocation(_startTile);
|
||||
startingNode->setHCost((_position - _destination).magnitude());
|
||||
startingNode->setFinalCost((_position - _destination).magnitude());
|
||||
startingNode->setGivenCost(0.0);
|
||||
|
||||
_nodeQueue.push(startingNode);
|
||||
_createdList[_startTile] = (startingNode);
|
||||
|
||||
_destinationSet = true;
|
||||
_solutionFound = _noSolution = false;
|
||||
|
||||
_destinationReachable = r;
|
||||
}
|
||||
|
||||
void PathfindingAgent::update(uint32 timeslice) {
|
||||
|
||||
uint32 prevTime = g_system->getMillis();
|
||||
uint32 timeLeft = timeslice;
|
||||
|
||||
double dTempCost;
|
||||
|
||||
if (_solutionFound) {
|
||||
if (_vSolution.size() > 0) {
|
||||
float distSqr = (_position - _vSolution.back()->getPosition()).magSqr();
|
||||
if (distSqr < _nodeBufferDistance) { // Have to find the right deadzone buffer
|
||||
_vSolution.pop_back();
|
||||
}
|
||||
}
|
||||
if (_vSolution.size() > 0) {
|
||||
_immediateDest = Vector2i(_vSolution.back()->getPosition().x, _vSolution.back()->getPosition().y);
|
||||
} else {
|
||||
if (_destinationReachable)
|
||||
_immediateDest = Vector2i((int)_destination.x, (int)_destination.y);
|
||||
else
|
||||
_immediateDest = Vector2i((int)_position.x, (int)_position.y);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// No nodes, no pathing.
|
||||
if (_nodeQueue.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common::StableMap<PathfindingGraphNode *, PlannerNode *>::iterator currentIter;
|
||||
|
||||
do {
|
||||
PlannerNode *current = _nodeQueue.front();
|
||||
_nodeQueue.pop();
|
||||
|
||||
if (current->getLocation() == _goalTile) { // We're done.
|
||||
// m_vSolution = getSolution();
|
||||
_vSolution = getPrunedSolution(nullptr);
|
||||
_solutionFound = true;
|
||||
return;
|
||||
} else if (current->getLocation()->getMovementCost() > 0 && current->getLocation()->adjacentToNode(_clickedTile) && _clickedTile->getMovementCost() < 0) {
|
||||
_vSolution = getPrunedSolution(current->getLocation());
|
||||
_solutionFound = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &i : current->_location->_neighborNodes) {
|
||||
if (i->getMovementCost() > 0) {
|
||||
// Compute the temp given cost
|
||||
dTempCost = current->getGivenCost() + i->getMovementCost() * distExact(i, current->getLocation());
|
||||
|
||||
// If it's a duplicate...
|
||||
currentIter = _createdList.find(i);
|
||||
if (currentIter != _createdList.end()) {
|
||||
if (dTempCost < currentIter->second->getGivenCost()) {
|
||||
// If the current planner node has already been added, but the current path is cheaper,
|
||||
// replace it.
|
||||
|
||||
_nodeQueue.remove(currentIter->second);
|
||||
|
||||
currentIter->second->setGivenCost(dTempCost);
|
||||
currentIter->second->setFinalCost(
|
||||
currentIter->second->getHCost() * 1.1 +
|
||||
currentIter->second->getGivenCost());
|
||||
|
||||
currentIter->second->setParent(current);
|
||||
|
||||
_nodeQueue.push(currentIter->second);
|
||||
}
|
||||
} else { // Otherwise...
|
||||
PlannerNode *successor = new PlannerNode();
|
||||
successor->setLocation(i);
|
||||
|
||||
// Set the new heuristic (distance from node to the goal)
|
||||
successor->setHCost(distExact(i, _goalTile));
|
||||
successor->setGivenCost(dTempCost);
|
||||
// Final cost is the distance to goal (scaled by 10%) plus the distance of the path.
|
||||
successor->setFinalCost(successor->getHCost() * 1.1 + successor->getGivenCost());
|
||||
|
||||
successor->setParent(current);
|
||||
|
||||
_createdList[i] = (successor);
|
||||
_nodeQueue.push(successor); // When the node is pushed onto the PriorityQueue it ends up beings sorted cheapest -> most expensive
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the time
|
||||
if (timeslice != 0) {
|
||||
timeLeft -= (g_system->getMillis() - prevTime);
|
||||
prevTime = g_system->getMillis();
|
||||
}
|
||||
|
||||
} while (!isDone() && ((int32)timeLeft >= 0 || timeslice == 0));
|
||||
_noSolution = true; // You can't get there from here (SZ)
|
||||
}
|
||||
|
||||
bool PathfindingAgent::isDone() const {
|
||||
if (_nodeQueue.empty())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear everything.
|
||||
void PathfindingAgent::reset() {
|
||||
for (auto &iter : _createdList)
|
||||
delete iter.second;
|
||||
|
||||
_nodeQueue.clear();
|
||||
_createdList.clear();
|
||||
_vSolution.clear();
|
||||
|
||||
_solutionFound = false;
|
||||
|
||||
_goalTile = nullptr;
|
||||
_startTile = nullptr;
|
||||
}
|
||||
|
||||
void PathfindingAgent::shutdown() {
|
||||
reset();
|
||||
|
||||
_grid = nullptr;
|
||||
}
|
||||
|
||||
Common::Array<PathfindingGraphNode const *> const PathfindingAgent::getSolution(PathfindingGraphNode *destNode) const {
|
||||
Common::Array<PathfindingGraphNode const *> temp;
|
||||
|
||||
PlannerNode *current = nullptr;
|
||||
|
||||
if (_createdList.find(_goalTile) != _createdList.end()) {
|
||||
current = _createdList.find(_goalTile)->second;
|
||||
} else if (destNode != nullptr) {
|
||||
// If the dest node passed in is not null, that means we did not reach the goal but came close
|
||||
// so we should start with that node instead when we are constructing our path
|
||||
current = _createdList.find(destNode)->second;
|
||||
}
|
||||
|
||||
// Iterate through the planner nodes to create a vector to return.
|
||||
while (current) {
|
||||
if (current->getLocation() != _startTile) {
|
||||
// You don't have to path to the start
|
||||
if (current->getLocation() != _startTile)
|
||||
temp.push_back(current->getLocation());
|
||||
}
|
||||
|
||||
current = current->getParent();
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
Common::Array<PathfindingGraphNode const *> const PathfindingAgent::getPrunedSolution(PathfindingGraphNode *destNode) {
|
||||
Common::Array<PathfindingGraphNode const *> temp = getSolution(destNode);
|
||||
|
||||
Common::Array<PathfindingGraphNode const *> returnVec = temp;
|
||||
|
||||
// Any node that is not adjacent to an obstacle or an obstacle corner can be removed.
|
||||
for (int i = 0; (uint)i < temp.size(); ++i) {
|
||||
if (!temp[i]->adjacentToObstacle()) {
|
||||
if (i > 0 && (uint)i < temp.size() - 1) {
|
||||
// This check to see if the node is a "corner" to an obstacle that should not be pruned
|
||||
// to prevent hanging on corners.
|
||||
Common::Array<PathfindingGraphNode *> corners = _grid->cornerCheck(temp[i - 1], temp[i + 1]);
|
||||
|
||||
if (corners.size() == 0) {
|
||||
Common::Array<PathfindingGraphNode const *>::iterator theEnd = Common::remove(returnVec.begin(), returnVec.end(), temp[i]);
|
||||
returnVec.erase(theEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnVec;
|
||||
}
|
||||
|
||||
double PathfindingAgent::distSquared(PathfindingGraphNode *tileA, PathfindingGraphNode *tileB) {
|
||||
Vector2f vecTo = tileA->getPosition() - tileB->getPosition();
|
||||
|
||||
return vecTo.magSqr();
|
||||
}
|
||||
|
||||
double PathfindingAgent::distExact(PathfindingGraphNode *tileA, PathfindingGraphNode *tileB) {
|
||||
Vector2f vecTo = tileA->getPosition() - tileB->getPosition();
|
||||
|
||||
return vecTo.magnitude();
|
||||
}
|
||||
|
||||
bool PathfindingAgent::adjacentToGoal(PathfindingGraphNode *node) {
|
||||
for (const auto &iter : node->_neighborNodes) {
|
||||
if (iter == _goalTile) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
220
engines/crab/PathfindingAgent.h
Normal file
220
engines/crab/PathfindingAgent.h
Normal file
@@ -0,0 +1,220 @@
|
||||
/* 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_PATHFINDINGAGENT_H
|
||||
#define CRAB_PATHFINDINGAGENT_H
|
||||
|
||||
#include "common/stablemap.h"
|
||||
#include "crab/PathfindingGrid.h"
|
||||
#include "crab/PriorityQueue.h"
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// This class represents the actual pathfinding and following agent that utilizes
|
||||
// the pathfinding grid
|
||||
class PlannerNode {
|
||||
PlannerNode *_parent;
|
||||
PlannerNode *_child;
|
||||
|
||||
double _cost; // Heuristic cost equivalent to cost to reach goal from planner node's position.
|
||||
double _finalCost; // Final cost of route through the planner node. Used to determine optimal path.
|
||||
double _givenCost; // The current distance of the route.
|
||||
|
||||
public:
|
||||
PathfindingGraphNode *_location;
|
||||
|
||||
PlannerNode() {
|
||||
_location = nullptr;
|
||||
_parent = nullptr;
|
||||
_child = nullptr;
|
||||
_cost = 0;
|
||||
_finalCost = 0;
|
||||
_givenCost = 0;
|
||||
}
|
||||
~PlannerNode() {}
|
||||
|
||||
PathfindingGraphNode *getLocation() {
|
||||
return _location;
|
||||
}
|
||||
|
||||
PlannerNode *getParent() {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
PlannerNode *getChild() {
|
||||
return _child;
|
||||
}
|
||||
|
||||
double getHCost() const {
|
||||
return _cost;
|
||||
}
|
||||
|
||||
double getFinalCost() const {
|
||||
return _finalCost;
|
||||
}
|
||||
|
||||
double getGivenCost() const {
|
||||
return _givenCost;
|
||||
}
|
||||
|
||||
void setLocation(PathfindingGraphNode *loc) {
|
||||
_location = loc;
|
||||
}
|
||||
|
||||
void setParent(PlannerNode *p) {
|
||||
_parent = p;
|
||||
}
|
||||
|
||||
void setChild(PlannerNode *c) {
|
||||
_child = c;
|
||||
}
|
||||
|
||||
void setHCost(double c) {
|
||||
_cost = c;
|
||||
}
|
||||
|
||||
void setFinalCost(double c) {
|
||||
_finalCost = c;
|
||||
}
|
||||
|
||||
void setGivenCost(double c) {
|
||||
_givenCost = c;
|
||||
}
|
||||
};
|
||||
|
||||
class PathfindingAgent {
|
||||
Vector2f _position;
|
||||
Vector2f _prevPosition; // Used to determine that we are making progress toward the goal
|
||||
Vector2i _immediateDest; // The next stop on the AI's path
|
||||
|
||||
bool _destinationSet; // Was a destination specified.
|
||||
bool _destinationReachable; // Can the agent actually get to the destination?
|
||||
|
||||
float _nodeBufferDistance; // How much leeway is there for reaching the destination
|
||||
|
||||
public:
|
||||
PathfindingAgent();
|
||||
~PathfindingAgent();
|
||||
|
||||
PathfindingGrid *_grid;
|
||||
|
||||
Vector2f _destination;
|
||||
|
||||
PathfindingGraphNode *_startTile; // The system originally used tiles, but this one uses discreet points.
|
||||
PathfindingGraphNode *_goalTile; // The tile we are trying to reach. May not be the tile that was clicked if the clicked tile is blocked.
|
||||
PathfindingGraphNode *_clickedTile; // The tile that was clicked. If it is open, it will be the goal node.
|
||||
|
||||
bool _solutionFound;
|
||||
bool _noSolution;
|
||||
|
||||
Common::Array<PathfindingGraphNode const *> _vSolution;
|
||||
|
||||
void setNodeBufferDistance(float w) {
|
||||
_nodeBufferDistance = w;
|
||||
}
|
||||
|
||||
float getNodeBufferDistance() {
|
||||
return _nodeBufferDistance;
|
||||
}
|
||||
|
||||
// Added for Greedy search
|
||||
double distSquared(PathfindingGraphNode *tileA, PathfindingGraphNode *tileB);
|
||||
// Added for A* search
|
||||
double distExact(PathfindingGraphNode *tileA, PathfindingGraphNode *tileB);
|
||||
|
||||
PriorityQueue<PlannerNode> _nodeQueue;
|
||||
|
||||
Common::StableMap<PathfindingGraphNode *, PlannerNode *> _createdList;
|
||||
|
||||
// void SetSprite(pyrodactyl::anim::Sprite* s){entitySprite = s;}
|
||||
|
||||
//! \brief Sets the tile map.
|
||||
//!
|
||||
//! Invoked when the user opens a tile map file.
|
||||
//!
|
||||
//! \param _tileMap the data structure that this algorithm will use
|
||||
//! to access each tile's location and weight data.
|
||||
void initialize(PathfindingGrid *g);
|
||||
|
||||
void setDestination(Vector2f d);
|
||||
void setDestination(Vector2f d, bool r);
|
||||
void setDestination(Vector2i d);
|
||||
void setDestination(Vector2i d, bool r);
|
||||
|
||||
void setPosition(Vector2f p) {
|
||||
_position = p;
|
||||
}
|
||||
|
||||
void setPrevPosition(Vector2f p) {
|
||||
_prevPosition = p;
|
||||
}
|
||||
|
||||
Vector2f getPosition() {
|
||||
return _position;
|
||||
}
|
||||
|
||||
bool positionChanged() {
|
||||
return _position != _prevPosition;
|
||||
}
|
||||
|
||||
Vector2i getImmediateDest() {
|
||||
return _immediateDest;
|
||||
}
|
||||
|
||||
//! \brief Performs the main part of the algorithm until the specified time has elapsed or
|
||||
//! no nodes are left open.
|
||||
void update(uint32 timeslice);
|
||||
|
||||
//! \brief Returns <code>true</code> if and only if no nodes are left open.
|
||||
//!
|
||||
//! \return <code>true</code> if no nodes are left open, <code>false</code> otherwise.
|
||||
bool isDone() const;
|
||||
|
||||
//! \brief Returns an unmodifiable view of the solution path found by this algorithm.
|
||||
Common::Array<PathfindingGraphNode const *> const getSolution(PathfindingGraphNode *destNode) const;
|
||||
|
||||
// Get the solution removing any nodes that are completely surrounded by open space.
|
||||
// This will result in a more linear path to the goal.
|
||||
Common::Array<PathfindingGraphNode const *> const getPrunedSolution(PathfindingGraphNode *destNode);
|
||||
|
||||
//! \brief Resets the algorithm.
|
||||
void reset();
|
||||
|
||||
//! \brief Uninitializes the algorithm before the tile map is unloaded.
|
||||
void shutdown();
|
||||
|
||||
// Returns true if the node connects to the goal node
|
||||
bool adjacentToGoal(PathfindingGraphNode *node);
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_PATHFINDINGAGENT_H
|
||||
94
engines/crab/PathfindingGraphNode.cpp
Normal file
94
engines/crab/PathfindingGraphNode.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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/PathfindingGraphNode.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
PathfindingGraphNode::PathfindingGraphNode() {
|
||||
_id = -1;
|
||||
_movementCost = -1.0f;
|
||||
}
|
||||
|
||||
PathfindingGraphNode::PathfindingGraphNode(Vector2f pos, int i) : _position(pos) {
|
||||
_id = i;
|
||||
_movementCost = -1.0f;
|
||||
}
|
||||
|
||||
PathfindingGraphNode::~PathfindingGraphNode() {
|
||||
}
|
||||
|
||||
void PathfindingGraphNode::addNeighbor(PathfindingGraphNode *node) {
|
||||
addNeighbor(node, false);
|
||||
}
|
||||
|
||||
void PathfindingGraphNode::addNeighbor(PathfindingGraphNode *node, bool ignoreDistance) {
|
||||
// You can't be your own neighbor. Sorry.
|
||||
if (node->_id == this->_id)
|
||||
return;
|
||||
|
||||
// Make sure that the node is not already a neighbor (SZ)
|
||||
for (uint i = 0; i < _neighborNodes.size(); ++i) {
|
||||
if (_neighborNodes[i]->_id == node->_id) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_neighborNodes.push_back(node);
|
||||
|
||||
// Determine the cost.
|
||||
if (ignoreDistance) {
|
||||
_neighborCosts.push_back(node->_movementCost);
|
||||
} else {
|
||||
Vector2f distVec = node->_position - this->_position;
|
||||
|
||||
_neighborCosts.push_back(distVec.magnitude() * node->_movementCost);
|
||||
}
|
||||
}
|
||||
|
||||
bool PathfindingGraphNode::adjacentToObstacle() const {
|
||||
for (const auto &iter : _neighborNodes) {
|
||||
if (iter->getMovementCost() < 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PathfindingGraphNode::adjacentToNode(PathfindingGraphNode *otherNode) {
|
||||
for (uint i = 0; i < _neighborNodes.size(); ++i) {
|
||||
if (_neighborNodes[i] == otherNode)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
92
engines/crab/PathfindingGraphNode.h
Normal file
92
engines/crab/PathfindingGraphNode.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/* 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_PATHFINDINGGRAPHNODE_H
|
||||
#define CRAB_PATHFINDINGGRAPHNODE_H
|
||||
|
||||
#include "crab/Rectangle.h"
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// This is the basic pathfinding node that will construct the pathfinding graph. (SZ)
|
||||
// Although Unrest is using a square grid based pathfinding map, this is made to be a general use pathfinding node.
|
||||
class PathfindingGraphNode {
|
||||
friend class PathfindingGrid;
|
||||
|
||||
int _id; // Each ID will be assigned when the pathfinding graph is generated and will identify each node.
|
||||
|
||||
float _movementCost; // 1 is open terrain, >1 is impeding terrain, <0 is completely obstructed
|
||||
|
||||
Vector2f _position; // Position of the node
|
||||
|
||||
Rect _collisionRect; // Represents spaced covered by the node.
|
||||
|
||||
public:
|
||||
Common::Array<PathfindingGraphNode *> _neighborNodes;
|
||||
Common::Array<float> _neighborCosts; // The movement cost for the neighbor nodes (distance to the node X the nodes movement cost)
|
||||
// This is stored to prevent having to recalculate each frame.
|
||||
|
||||
PathfindingGraphNode();
|
||||
PathfindingGraphNode(Vector2f pos, int i);
|
||||
|
||||
~PathfindingGraphNode();
|
||||
|
||||
float getMovementCost() {
|
||||
return _movementCost;
|
||||
}
|
||||
|
||||
Vector2f getPosition() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
// Adds node to neighbor vector and cost to neighbor costs
|
||||
void addNeighbor(PathfindingGraphNode *node);
|
||||
|
||||
// Same as above, but does not calculate distance. Used when all nodes
|
||||
// are equidistant
|
||||
void addNeighbor(PathfindingGraphNode *node, bool ignoreDistance);
|
||||
|
||||
// const Common::Array< PathfindingGraphNode*>& GetNeighbors() const;
|
||||
|
||||
Rect getRect() const {
|
||||
return _collisionRect;
|
||||
}
|
||||
|
||||
// Return true if the node is adjacent to a blocked node
|
||||
bool adjacentToObstacle() const;
|
||||
|
||||
// Return true if the node is adjacent to the otherNode
|
||||
bool adjacentToNode(PathfindingGraphNode *otherNode);
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_PATHFINDINGGRAPHNODE_H
|
||||
279
engines/crab/PathfindingGrid.cpp
Normal file
279
engines/crab/PathfindingGrid.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
/* 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/PathfindingGrid.h"
|
||||
#include "crab/TMX/TMXMap.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace TMX;
|
||||
|
||||
PathfindingGrid::PathfindingGrid() {
|
||||
_blockedCost = BLOCKED;
|
||||
_openCost = OPEN;
|
||||
_stairsCost = STAIRS;
|
||||
_nodes = nullptr;
|
||||
|
||||
_dimensions.x = 0;
|
||||
_dimensions.y = 0;
|
||||
|
||||
_cellSize.x = 0.0;
|
||||
_cellSize.y = 0.0;
|
||||
}
|
||||
|
||||
PathfindingGrid::~PathfindingGrid() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void PathfindingGrid::reset() {
|
||||
for (int x = 0; x < _dimensions.x; ++x) {
|
||||
delete[] _nodes[x];
|
||||
}
|
||||
|
||||
delete[] _nodes;
|
||||
_nodes = nullptr;
|
||||
|
||||
_dimensions.x = 0;
|
||||
_dimensions.y = 0;
|
||||
|
||||
_cellSize.x = 0.0;
|
||||
_cellSize.y = 0.0;
|
||||
}
|
||||
|
||||
void PathfindingGrid::setupNodes(const TMX::TMXMap &map) {
|
||||
// delete nodes if they exist
|
||||
reset();
|
||||
|
||||
_dimensions.x = map._pathRows; // Logically, this is incorrect but it matches the format of cols and rows used elsewhere (SZ)
|
||||
_dimensions.y = map._pathCols;
|
||||
|
||||
_cellSize.x = (float)map._pathSize.x;
|
||||
_cellSize.y = (float)map._pathSize.y;
|
||||
|
||||
// Check to see if the costs have been loaded from the level file.
|
||||
// If not, assign to defaults.
|
||||
if (map._movementCosts._noWalk != 0) {
|
||||
_blockedCost = map._movementCosts._noWalk;
|
||||
}
|
||||
if (map._movementCosts._open != 0) {
|
||||
_openCost = map._movementCosts._open;
|
||||
}
|
||||
if (map._movementCosts._stairs != 0) {
|
||||
_stairsCost = map._movementCosts._stairs;
|
||||
}
|
||||
|
||||
_nodes = new PathfindingGraphNode *[_dimensions.x];
|
||||
|
||||
// Allocate some nodes!
|
||||
// TODO: probably want to change this to a one chunk allocation...
|
||||
for (int i = 0; i < _dimensions.x; ++i) {
|
||||
_nodes[i] = new PathfindingGraphNode[_dimensions.y];
|
||||
}
|
||||
|
||||
// Fill up those nodes!
|
||||
int idCounter = 0;
|
||||
|
||||
Vector2f pos = Vector2f(0.0f, 0.0f);
|
||||
Vector2f topLeftPos = pos;
|
||||
|
||||
// Initialize the nodes
|
||||
for (int x = 0; x < _dimensions.x; ++x) {
|
||||
for (int y = 0; y < _dimensions.y; ++y) {
|
||||
// PathfindingGraphNode* newNode = new PathfindingGraphNode(pos, idCounter++);
|
||||
|
||||
// nodes[x][y] = *newNode;
|
||||
_nodes[x][y]._collisionRect = Rect(pos.x, pos.y, _cellSize.x, _cellSize.y);
|
||||
|
||||
_nodes[x][y]._position.x = pos.x + _cellSize.x / 2.0f;
|
||||
_nodes[x][y]._position.y = pos.y + _cellSize.y / 2.0f;
|
||||
_nodes[x][y]._id = idCounter++;
|
||||
|
||||
_nodes[x][y]._movementCost = _openCost;
|
||||
_nodes[x][y]._neighborCosts.reserve(4); // since its a square based grid, 4 is the greatest number of costs and nodes possible.
|
||||
_nodes[x][y]._neighborNodes.reserve(4);
|
||||
|
||||
pos.y += _cellSize.y;
|
||||
|
||||
const Common::Array<Shape> &noWalk = map.areaNoWalk();
|
||||
|
||||
// Check if the square should count as blocked
|
||||
for (const auto &i : noWalk) {
|
||||
if (i.collide(_nodes[x][y]._collisionRect)._intersect) {
|
||||
_nodes[x][y]._movementCost = (float)_blockedCost;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for stairs if the cell isn't blocked
|
||||
if (_nodes[x][y]._movementCost >= 0.0f) {
|
||||
const Common::Array<pyrodactyl::level::Stairs> &stairs = map.areaStairs();
|
||||
|
||||
for (const auto &i : stairs) {
|
||||
if (i.collide(_nodes[x][y]._collisionRect)._intersect) {
|
||||
_nodes[x][y]._movementCost = (float)_stairsCost;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// More collision checks can be added for the node as long as it checks for the high cost objects first
|
||||
// since the highest cost collider in any given tile would be used for the path cost. (SZ)
|
||||
}
|
||||
|
||||
pos.x += _cellSize.x;
|
||||
pos.y = topLeftPos.y;
|
||||
}
|
||||
|
||||
// Connect the nodes
|
||||
for (int x = 0; x < _dimensions.x; ++x) {
|
||||
for (int y = 0; y < _dimensions.y; ++y) {
|
||||
// Check horizontal
|
||||
if (x < _dimensions.x - 1) {
|
||||
connectNodes(&_nodes[x][y], &_nodes[x + 1][y]);
|
||||
|
||||
// Check diagonals
|
||||
// This causes hangups since the collider has a greater width to take into account when traveling
|
||||
// diagonally compared to horizontal or vertical. (SZ)
|
||||
/*if( y < dimensions.y - 2)
|
||||
{
|
||||
ConnectNodes(&nodes[x][y], &nodes[x + 1][y + 1]);
|
||||
|
||||
nodes[x][y].neighborCosts[nodes[x][y].neighborCosts.size() - 1] *= 1.41f;
|
||||
nodes[x + 1][y + 1].movementCost *= 1.41f;
|
||||
}
|
||||
|
||||
if(y > 0)
|
||||
{
|
||||
ConnectNodes(&nodes[x][y], &nodes[x + 1][y - 1]);
|
||||
|
||||
nodes[x][y].neighborCosts[nodes[x][y].neighborCosts.size() - 1] *= 1.41f;
|
||||
nodes[x + 1][y - 1].movementCost *= 1.41f;
|
||||
}*/
|
||||
}
|
||||
// Check vertical
|
||||
if (y < _dimensions.y - 1) {
|
||||
connectNodes(&_nodes[x][y], &_nodes[x][y + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////Check for adjacencies
|
||||
////This could be used if additional weight should be applied to nodes adjacent to blocked nodes.
|
||||
// for(int x = 0; x < dimensions.x; ++x)
|
||||
//{
|
||||
// for(int y = 0; y < dimensions.y; ++y)
|
||||
// {
|
||||
// for(int i = 0; i < nodes[x][y].neighborNodes.size(); ++i)
|
||||
// {
|
||||
// if(nodes[x][y].neighborNodes[i]->movementCost == blockedCost)
|
||||
// {
|
||||
// nodes[x][y].movementCost *= 2.0f;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void PathfindingGrid::connectNodes(PathfindingGraphNode *node1, PathfindingGraphNode *node2) {
|
||||
node1->addNeighbor(node2, true);
|
||||
node2->addNeighbor(node1, true);
|
||||
}
|
||||
|
||||
PathfindingGraphNode *PathfindingGrid::getNodeAtPoint(Vector2f point) {
|
||||
int x = (int)floor(point.x / _cellSize.x);
|
||||
int y = (int)floor(point.y / _cellSize.y);
|
||||
|
||||
return &_nodes[x][y];
|
||||
}
|
||||
|
||||
Common::Array<PathfindingGraphNode *> PathfindingGrid::cornerCheck(const PathfindingGraphNode *node1, const PathfindingGraphNode *node2) {
|
||||
Common::Array<PathfindingGraphNode *> returnNodes;
|
||||
|
||||
// Iterat through both nodes neighbors. If a blocked neighbor is found that is shared between the two,
|
||||
// It is a corner to them.
|
||||
for (auto iter : node1->_neighborNodes) {
|
||||
for (auto iter2 : node2->_neighborNodes) {
|
||||
if (iter == iter2 && iter->_movementCost < 0) {
|
||||
if (returnNodes.size() == 0 || (*(Common::find(returnNodes.begin(), returnNodes.end(), iter))) == nullptr)
|
||||
returnNodes.push_back(iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return returnNodes;
|
||||
}
|
||||
|
||||
PathfindingGraphNode *PathfindingGrid::getNearestOpenNode(Vector2f nodePos, Vector2f comparePos) {
|
||||
PathfindingGraphNode *startNode = getNodeAtPoint(nodePos);
|
||||
|
||||
if (startNode->getMovementCost() > 0) // If the clicked node is open, we're done!
|
||||
return startNode;
|
||||
|
||||
PathfindingGraphNode *returnNode = nullptr;
|
||||
|
||||
float shortestDistance = 0.0f;
|
||||
|
||||
Common::List<PathfindingGraphNode *> checkNodes;
|
||||
checkNodes.push_back(startNode);
|
||||
|
||||
Common::Array<PathfindingGraphNode *> allUsedNodes;
|
||||
allUsedNodes.push_back(startNode);
|
||||
|
||||
// Iterate through the nodes, check if they are open then check their distance from the compare point.
|
||||
while (!checkNodes.empty()) {
|
||||
if (checkNodes.front()->getMovementCost() > 0) {
|
||||
float distance = (comparePos - checkNodes.front()->getPosition()).magSqr();
|
||||
|
||||
if (shortestDistance == 0.0f || distance) { // If this is the new shortest distance, this becomes the new return.
|
||||
shortestDistance = distance;
|
||||
|
||||
returnNode = checkNodes.front();
|
||||
}
|
||||
} else {
|
||||
for (uint i = 0; i < checkNodes.front()->_neighborNodes.size(); ++i) {
|
||||
// If the neighbor hasn't been checked yet, add it to the list to check.
|
||||
if (Common::find(allUsedNodes.begin(), allUsedNodes.end(), checkNodes.front()->_neighborNodes[i]) == allUsedNodes.end()) {
|
||||
allUsedNodes.push_back(checkNodes.front()->_neighborNodes[i]);
|
||||
checkNodes.push_back(checkNodes.front()->_neighborNodes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (returnNode != nullptr) // If a node has been found, we are done. We don't want to continue iterating through neighbors since it would take us further from the clicked node.
|
||||
return returnNode;
|
||||
|
||||
checkNodes.pop_front();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
99
engines/crab/PathfindingGrid.h
Normal file
99
engines/crab/PathfindingGrid.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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_PATHFINDINGGRID_H
|
||||
#define CRAB_PATHFINDINGGRID_H
|
||||
|
||||
#include "crab/PathfindingGraphNode.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace TMX {
|
||||
class TMXMap;
|
||||
}
|
||||
|
||||
// This is the grid of pathfinding nodes that is formed for the level (SZ)
|
||||
class PathfindingGrid {
|
||||
friend class PathfindingGraphNode;
|
||||
|
||||
PathfindingGraphNode **_nodes; // 2D array of nodes (size is [dimensions.x][dimensions.y]
|
||||
|
||||
Vector2i _dimensions; // rows and columns of nodes.
|
||||
Vector2f _cellSize; // size of a cell in width and height
|
||||
|
||||
// Neighbor node1 to node2.
|
||||
void connectNodes(PathfindingGraphNode *node1, PathfindingGraphNode *node2);
|
||||
|
||||
public:
|
||||
// these are the default graph node costs.
|
||||
// they can be overwritten by values stored in the level's file.(SZ)
|
||||
static const int BLOCKED = -1;
|
||||
static const int OPEN = 1;
|
||||
static const int STAIRS = 5;
|
||||
|
||||
// These are the actual data members used to assign costs. (SZ)
|
||||
int _blockedCost;
|
||||
int _openCost;
|
||||
int _stairsCost;
|
||||
|
||||
PathfindingGrid();
|
||||
~PathfindingGrid();
|
||||
|
||||
void reset();
|
||||
|
||||
void setupNodes(const TMX::TMXMap &map);
|
||||
|
||||
// Return the node at the given point (SZ)
|
||||
PathfindingGraphNode *getNodeAtPoint(Vector2f point);
|
||||
// Return the node at the given coordinates (SZ)
|
||||
PathfindingGraphNode *getNodeAtCoords(int x, int y) {
|
||||
return &_nodes[x][y];
|
||||
}
|
||||
|
||||
Vector2i getDimensions() {
|
||||
return _dimensions;
|
||||
}
|
||||
|
||||
Vector2f getCellSize() {
|
||||
return _cellSize;
|
||||
}
|
||||
|
||||
// Returns the nearest open node to the compare spot, starting with the given nodePos
|
||||
// and iterating through its neighbors. (SZ)
|
||||
PathfindingGraphNode *getNearestOpenNode(Vector2f nodePos, Vector2f comparePos);
|
||||
|
||||
// Return true if two nodes share and adjacency to the same blocked node.
|
||||
// Can be used to find corners that shouldn't be cut.
|
||||
Common::Array<PathfindingGraphNode *> cornerCheck(const PathfindingGraphNode *node1, const PathfindingGraphNode *node2);
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_PATHFINDINGGRID_H
|
||||
275
engines/crab/Polygon.cpp
Normal file
275
engines/crab/Polygon.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/* 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 "graphics/screen.h"
|
||||
#include "crab/crab.h"
|
||||
#include "crab/Polygon.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// Calculate the distance between [minA, maxA] and [minB, maxB]
|
||||
// The distance will be negative if the intervals overlap
|
||||
float IntervalDistance(float minA, float maxA, float minB, float maxB) {
|
||||
if (minA < minB)
|
||||
return minB - maxA;
|
||||
return minA - maxB;
|
||||
}
|
||||
|
||||
void Polygon2D::addPoint(const Vector2f &ref, const Common::String &x, const Common::String &y, Vector2f &min, Vector2f &max) {
|
||||
Vector2f p;
|
||||
p.x = ref.x + stringToNumber<float>(x);
|
||||
p.y = ref.y + stringToNumber<float>(y);
|
||||
|
||||
if (p.x < min.x)
|
||||
min.x = p.x;
|
||||
if (p.x > max.x)
|
||||
max.x = p.x;
|
||||
|
||||
if (p.y < min.y)
|
||||
min.y = p.y;
|
||||
if (p.y > max.y)
|
||||
max.y = p.y;
|
||||
|
||||
_point.push_back(p);
|
||||
}
|
||||
|
||||
void Polygon2D::load(rapidxml::xml_node<char> *node, Rect &bounds) {
|
||||
Vector2f ref;
|
||||
ref.load(node);
|
||||
|
||||
// Converting a polygon to an axis aligned bounding box is easy - just record the minimum and maximum values of x and y
|
||||
// for the vertices of the polygon, then minimum = top left corner, max - min = dimensions
|
||||
Vector2f min(std::numeric_limits<float>::max(), std::numeric_limits<float>::max());
|
||||
Vector2f max(-std::numeric_limits<float>::max(), -std::numeric_limits<float>::max());
|
||||
|
||||
_point.clear();
|
||||
rapidxml::xml_node<char> *polynode = node->first_node("polygon");
|
||||
if (polynode != nullptr) {
|
||||
Common::String points, x, y;
|
||||
loadStr(points, "points", polynode);
|
||||
|
||||
bool comma = false;
|
||||
for (const auto &i : points) {
|
||||
if (i == ',')
|
||||
comma = true;
|
||||
else if (i == ' ') {
|
||||
addPoint(ref, x, y, min, max);
|
||||
comma = false;
|
||||
x.clear();
|
||||
y.clear();
|
||||
} else if (comma)
|
||||
y += i;
|
||||
else
|
||||
x += i;
|
||||
}
|
||||
|
||||
addPoint(ref, x, y, min, max);
|
||||
|
||||
bounds.x = min.x;
|
||||
bounds.y = min.y;
|
||||
bounds.w = max.x - min.x;
|
||||
bounds.h = max.y - min.y;
|
||||
}
|
||||
|
||||
setEdge();
|
||||
}
|
||||
|
||||
void Polygon2D::setEdge() {
|
||||
_edge.clear();
|
||||
Vector2f p1, p2, res;
|
||||
for (uint i = 0; i < _point.size(); i++) {
|
||||
p1 = _point[i];
|
||||
if (i + 1 >= _point.size())
|
||||
p2 = _point[0];
|
||||
else
|
||||
p2 = _point[i + 1];
|
||||
|
||||
res.x = p2.x - p1.x;
|
||||
res.y = p2.y - p1.y;
|
||||
_edge.push_back(res);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2f Polygon2D::center() const {
|
||||
Vector2f total;
|
||||
for (uint i = 0; i < _point.size(); i++) {
|
||||
total.x += _point[i].x;
|
||||
total.y += _point[i].y;
|
||||
}
|
||||
|
||||
Vector2f ret;
|
||||
if (_point.size() > 0) {
|
||||
ret.x = total.x / _point.size();
|
||||
ret.y = total.y / _point.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Polygon2D::offset(const float &x, const float &y) {
|
||||
for (auto &i : _point) {
|
||||
i.x += x;
|
||||
i.y += y;
|
||||
}
|
||||
}
|
||||
|
||||
void Polygon2D::project(const Vector2f &axis, float &min, float &max) const {
|
||||
// To project a point on an axis use the dot product
|
||||
float d = axis.dotProduct(_point[0]);
|
||||
min = d;
|
||||
max = d;
|
||||
|
||||
for (auto i = _point.begin(); i != _point.end(); ++i) {
|
||||
d = i->dotProduct(axis);
|
||||
|
||||
if (d < min)
|
||||
min = d;
|
||||
else if (d > max)
|
||||
max = d;
|
||||
}
|
||||
}
|
||||
|
||||
PolygonCollisionResult Polygon2D::collide(const Rect &rect) const {
|
||||
Polygon2D polyB;
|
||||
Vector2f p;
|
||||
p.x = rect.x;
|
||||
p.y = rect.y;
|
||||
polyB._point.push_back(p);
|
||||
p.x = rect.x + rect.w;
|
||||
p.y = rect.y;
|
||||
polyB._point.push_back(p);
|
||||
p.x = rect.x + rect.w;
|
||||
p.y = rect.y + rect.h;
|
||||
polyB._point.push_back(p);
|
||||
p.x = rect.x;
|
||||
p.y = rect.y + rect.h;
|
||||
polyB._point.push_back(p);
|
||||
polyB.setEdge();
|
||||
|
||||
return collide(polyB);
|
||||
}
|
||||
|
||||
PolygonCollisionResult Polygon2D::collide(const Polygon2D &polyB) const {
|
||||
PolygonCollisionResult result;
|
||||
result._intersect = true;
|
||||
|
||||
int edgeCountA = _edge.size();
|
||||
int edgeCountB = polyB._edge.size();
|
||||
float minIntervalDistance = std::numeric_limits<float>::max();
|
||||
Vector2f translationAxis;
|
||||
Vector2f e;
|
||||
|
||||
// Loop through all the edges of both polygons
|
||||
for (int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++) {
|
||||
if (edgeIndex < edgeCountA)
|
||||
e = _edge[edgeIndex];
|
||||
else
|
||||
e = polyB._edge[edgeIndex - edgeCountA];
|
||||
|
||||
// ===== 1. Find if the Polygon2Ds are currently intersecting =====
|
||||
|
||||
// Find the axis perpendicular to the current edge
|
||||
Vector2f axis(-e.y, e.x);
|
||||
axis.normalize();
|
||||
|
||||
// Find the projection of the Polygon2D on the current axis
|
||||
float minA = 0;
|
||||
float minB = 0;
|
||||
float maxA = 0;
|
||||
float maxB = 0;
|
||||
project(axis, minA, maxA);
|
||||
polyB.project(axis, minB, maxB);
|
||||
|
||||
// Check if the Polygon2D projections are currently intersecting
|
||||
float intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
|
||||
if (intervalDistance > 0) {
|
||||
// If the Polygon2Ds are not intersecting and won't intersect, exit the loop
|
||||
result._intersect = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the current interval distance is the minimum one. If so store
|
||||
// the interval distance and the current distance.
|
||||
// This will be used to calculate the minimum translation vector
|
||||
intervalDistance = abs(intervalDistance);
|
||||
if (intervalDistance < minIntervalDistance) {
|
||||
minIntervalDistance = intervalDistance;
|
||||
translationAxis = axis;
|
||||
|
||||
Vector2f d, ca, cb;
|
||||
ca = center();
|
||||
cb = polyB.center();
|
||||
|
||||
d.x = ca.x - cb.x;
|
||||
d.y = ca.y - cb.y;
|
||||
|
||||
if (d.dotProduct(translationAxis) < 0) {
|
||||
translationAxis.x = -translationAxis.x;
|
||||
translationAxis.y = -translationAxis.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The minimum translation vector can be used to push the Polygon2Ds apart.
|
||||
// First moves the Polygon2Ds by their velocity
|
||||
// then move polyA by MinimumTranslationVector.
|
||||
if (result._intersect) {
|
||||
result._mtv.x = translationAxis.x * minIntervalDistance;
|
||||
result._mtv.y = translationAxis.y * minIntervalDistance;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Polygon2D::contains(const float &x, const float &y) {
|
||||
bool result = false;
|
||||
|
||||
for (uint i = 0, j = _point.size() - 1; i < _point.size(); j = i++) {
|
||||
if (((_point[i].y > y) != (_point[j].y > y)) &&
|
||||
(x < (_point[j].x - _point[i].x) * (y - _point[i].y) / (_point[j].y - _point[i].y) + _point[i].x))
|
||||
result = !result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Polygon2D::draw(const int &xOffset, const int &yOffset, const uint8 &r, const uint8 &g, const uint8 &b, const uint8 &a) {
|
||||
Vector2f p1, p2;
|
||||
for (uint i = 0; i < _point.size(); i++) {
|
||||
p1 = _point[i];
|
||||
if (i + 1 >= _point.size())
|
||||
p2 = _point[0];
|
||||
else
|
||||
p2 = _point[i + 1];
|
||||
|
||||
g_engine->_screen->drawLine(p1.x + xOffset, p1.y + yOffset, p2.x + xOffset, p2.y + yOffset, g_engine->_format.ARGBToColor(a, r, g, b));
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
103
engines/crab/Polygon.h
Normal file
103
engines/crab/Polygon.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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_POLYGON_H
|
||||
#define CRAB_POLYGON_H
|
||||
|
||||
#include "crab/Rectangle.h"
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: The result of a collision
|
||||
//------------------------------------------------------------------------
|
||||
struct PolygonCollisionResult {
|
||||
// Are the Polygons currently intersecting?
|
||||
bool _intersect;
|
||||
|
||||
// The translation to apply to polygon A to push the polygons apart
|
||||
// Also known as the minimum translation vector
|
||||
Vector2f _mtv;
|
||||
|
||||
PolygonCollisionResult() {
|
||||
_intersect = false;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: A simple 2D Polygon class
|
||||
//------------------------------------------------------------------------
|
||||
class Polygon2D {
|
||||
void addPoint(const Vector2f &ref, const Common::String &x, const Common::String &y, Vector2f &min, Vector2f &max);
|
||||
|
||||
public:
|
||||
// A list of all points
|
||||
Common::Array<Vector2f> _point;
|
||||
|
||||
// A list of all edges
|
||||
Common::Array<Vector2f> _edge;
|
||||
|
||||
Polygon2D() {}
|
||||
Polygon2D(rapidxml::xml_node<char> *node, Rect &bounds) {
|
||||
load(node, bounds);
|
||||
}
|
||||
|
||||
// Returns the approximate axis aligned bounding box of the polygon
|
||||
void load(rapidxml::xml_node<char> *node, Rect &bounds);
|
||||
|
||||
void setEdge();
|
||||
|
||||
Vector2f center() const;
|
||||
void offset(const float &x, const float &y);
|
||||
void offset(const Vector2f &v) {
|
||||
offset(v.x, v.y);
|
||||
}
|
||||
|
||||
// Check if Polygon2D A is going to collide with Polygon2D B for the given velocity
|
||||
// PolyA is this polygon
|
||||
PolygonCollisionResult collide(const Polygon2D &polyB) const;
|
||||
|
||||
// Code for collision with a rectangle
|
||||
PolygonCollisionResult collide(const Rect &rect) const;
|
||||
|
||||
// Find if a point is inside this polygon
|
||||
bool contains(const float &x, const float &y);
|
||||
|
||||
// Calculate the projection of a polygon on an axis and returns it as a [min, max] interval
|
||||
void project(const Vector2f &axis, float &min, float &max) const;
|
||||
|
||||
void draw(const int &xOffset = 0, const int &yOffset = 0,
|
||||
const uint8 &r = 0, const uint8 &g = 0, const uint8 &b = 0.0f, const uint8 &a = 255);
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_POLYGON_H
|
||||
147
engines/crab/PriorityQueue.h
Normal file
147
engines/crab/PriorityQueue.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/* 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_PRIORITYQUEUE_H
|
||||
#define CRAB_PRIORITYQUEUE_H
|
||||
|
||||
|
||||
namespace Crab {
|
||||
|
||||
//! \brief The open heap used by all cost-based search algorithms.
|
||||
//!
|
||||
//! This class template is basically a thin wrapper on top of both the <code>std::deque</code>
|
||||
//! class template and the <a href="http://www.sgi.com/tech/stl/">STL</a> heap operations.
|
||||
template<typename Node>
|
||||
class PriorityQueue {
|
||||
Common::Array<Node *> _open;
|
||||
bool (*compare)(Node const *, Node const *);
|
||||
|
||||
public:
|
||||
//! \brief Constructs a new <code>%PriorityQueue</code> that heap-sorts nodes
|
||||
//! using the specified comparator.
|
||||
explicit PriorityQueue(bool (*)(Node const *, Node const *));
|
||||
|
||||
//! \brief Returns <code>true</code> if the heap contains no nodes,
|
||||
//! <code>false</code> otherwise.
|
||||
bool empty() const;
|
||||
|
||||
//! \brief Removes all nodes from the heap.
|
||||
//!
|
||||
//! \post
|
||||
//! - <code>empty()</code>
|
||||
void clear();
|
||||
|
||||
//! \brief Returns the number of nodes currently in the heap.
|
||||
size_t size() const;
|
||||
|
||||
//! \brief Pushes the specified node onto the heap.
|
||||
//!
|
||||
//! The heap will maintain the ordering of its nodes during this operation.
|
||||
//!
|
||||
//! \post
|
||||
//! - <code>! empty()</code>
|
||||
void push(Node *node);
|
||||
|
||||
//! \brief Returns the least costly node in the heap.
|
||||
//!
|
||||
//! \pre
|
||||
//! - <code>! empty()</code>
|
||||
Node *front() const;
|
||||
|
||||
//! \brief Removes the least costly node from the heap.
|
||||
//!
|
||||
//! The heap will maintain the ordering of its nodes during this operation.
|
||||
//!
|
||||
//! \pre
|
||||
//! - <code>! empty()</code>
|
||||
void pop();
|
||||
|
||||
//! \brief Removes all instances of the specified node from the heap.
|
||||
void remove(Node const *node);
|
||||
|
||||
//! \brief Enumerates all nodes in the heap so far.
|
||||
//!
|
||||
//! \param sorted the container to which each node will be added.
|
||||
//!
|
||||
//! \pre
|
||||
//! - There must be no <code>NULL</code> pointers in the heap.
|
||||
//! \post
|
||||
//! - All nodes should be sorted by this heap's comparator.
|
||||
void enumerate(Common::Array<Node const *> &sorted) const;
|
||||
};
|
||||
|
||||
template<typename Node>
|
||||
PriorityQueue<Node>::PriorityQueue(bool (*c)(Node const *, Node const *)) : _open(), compare(c) {
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
bool PriorityQueue<Node>::empty() const {
|
||||
return _open.empty();
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
void PriorityQueue<Node>::clear() {
|
||||
_open.clear();
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
size_t PriorityQueue<Node>::size() const {
|
||||
return _open.size();
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
void PriorityQueue<Node>::push(Node *node) {
|
||||
_open.insert(Common::upperBound(_open.begin(), _open.end(), node, compare), node);
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
Node *PriorityQueue<Node>::front() const {
|
||||
return _open.back();
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
void PriorityQueue<Node>::pop() {
|
||||
_open.pop_back();
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
void PriorityQueue<Node>::remove(Node const *node) {
|
||||
_open.erase(Common::remove(_open.begin(), _open.end(), node), _open.end());
|
||||
}
|
||||
|
||||
template<typename Node>
|
||||
void PriorityQueue<Node>::enumerate(Common::Array<Node const *> &sorted) const {
|
||||
sorted.resize(_open.size());
|
||||
Common::copy(_open.begin(), _open.end(), sorted.begin());
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_PRIORITYQUEUE_H
|
||||
132
engines/crab/Rectangle.cpp
Normal file
132
engines/crab/Rectangle.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/* 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 "graphics/screen.h"
|
||||
#include "crab/crab.h"
|
||||
#include "crab/GameParam.h"
|
||||
#include "crab/Rectangle.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
bool Rect::load(rapidxml::xml_node<char> *node, const bool &echo, const Common::String &x_name, const Common::String &y_name,
|
||||
const Common::String &w_name, const Common::String &h_name) {
|
||||
return loadNum(x, x_name, node, echo) && loadNum(y, y_name, node, echo) && loadNum(w, w_name, node, echo) && loadNum(h, h_name, node, echo);
|
||||
}
|
||||
|
||||
bool Rect::collide(Rect box) const {
|
||||
if (box.x + box.w < x)
|
||||
return false; // just checking if their
|
||||
if (box.x > x + w)
|
||||
return false; // bounding boxes even touch
|
||||
if (box.y + box.h < y)
|
||||
return false;
|
||||
if (box.y > y + h)
|
||||
return false;
|
||||
|
||||
return true; // bounding boxes intersect
|
||||
}
|
||||
|
||||
void Rect::extend(Rect box) {
|
||||
int left1 = x;
|
||||
int right1 = x + w;
|
||||
int top1 = y;
|
||||
int bottom1 = y + h;
|
||||
|
||||
const int left2 = box.x;
|
||||
const int right2 = box.x + box.w;
|
||||
const int top2 = box.y;
|
||||
const int bottom2 = box.y + box.h;
|
||||
|
||||
left1 = MIN(left1, left2);
|
||||
right1 = MAX(right1, right2);
|
||||
top1 = MIN(top1, top2);
|
||||
bottom1 = MAX(bottom1, bottom2);
|
||||
|
||||
x = left1;
|
||||
y = top1;
|
||||
w = right1 - left1;
|
||||
h = bottom1 - top1;
|
||||
}
|
||||
|
||||
Direction Rect::resolveX(Rect collider) {
|
||||
// Check left edge of collider
|
||||
if (x < collider.x && collider.x < x + w)
|
||||
return DIRECTION_RIGHT;
|
||||
|
||||
// Check right edge of collider
|
||||
if (x < collider.x + collider.w && collider.x + collider.w < x + w)
|
||||
return DIRECTION_LEFT;
|
||||
|
||||
return DIRECTION_NONE;
|
||||
}
|
||||
|
||||
Direction Rect::resolveY(Rect collider) {
|
||||
// Check top edge of collider
|
||||
if (y < collider.y && collider.y < y + h)
|
||||
return DIRECTION_DOWN;
|
||||
|
||||
// Check bottom edge of collider
|
||||
if (y < collider.y + collider.h && collider.y + collider.h < y + h)
|
||||
return DIRECTION_UP;
|
||||
|
||||
return DIRECTION_NONE;
|
||||
}
|
||||
|
||||
void Rect::flip(const TextureFlipType &flip, const Vector2i &axis) {
|
||||
if (flip == FLIP_NONE)
|
||||
return;
|
||||
|
||||
if (flip == FLIP_X || flip == FLIP_XY)
|
||||
x = 2 * axis.x - x - w;
|
||||
|
||||
if (flip == FLIP_Y || flip == FLIP_XY)
|
||||
y = 2 * axis.y - y - h;
|
||||
}
|
||||
|
||||
void Rect::draw(const int &xOffset, const int &yOffset, const uint8 &r, const uint8 &g, const uint8 &b, const uint8 &a) {
|
||||
int X = x + xOffset, Y = y + yOffset;
|
||||
uint32 col = g_engine->_format.ARGBToColor(a, r, g, b);
|
||||
|
||||
g_engine->_screen->drawLine(X, Y, X + w, Y, col);
|
||||
g_engine->_screen->drawLine(X, Y, X, Y + h, col);
|
||||
g_engine->_screen->drawLine(X + w, Y, X + w, Y + h, col);
|
||||
g_engine->_screen->drawLine(X, Y + h, X + w, Y + h, col);
|
||||
}
|
||||
|
||||
void Rect::saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root, const char *name) {
|
||||
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, name);
|
||||
child->append_attribute(doc.allocate_attribute("x", g_engine->_stringPool->get(x)));
|
||||
child->append_attribute(doc.allocate_attribute("y", g_engine->_stringPool->get(y)));
|
||||
child->append_attribute(doc.allocate_attribute("w", g_engine->_stringPool->get(w)));
|
||||
child->append_attribute(doc.allocate_attribute("h", g_engine->_stringPool->get(h)));
|
||||
root->append_node(child);
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
103
engines/crab/Rectangle.h
Normal file
103
engines/crab/Rectangle.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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_RECTANGLE_H
|
||||
#define CRAB_RECTANGLE_H
|
||||
|
||||
#include "crab/Line.h"
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: A simple rectangle class
|
||||
//------------------------------------------------------------------------
|
||||
struct Rect {
|
||||
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
|
||||
Rect(int X = 0, int Y = 0, int W = 0, int H = 0) {
|
||||
x = X;
|
||||
y = Y;
|
||||
w = W;
|
||||
h = H;
|
||||
}
|
||||
|
||||
bool load(rapidxml::xml_node<char> *node, const bool &echo = true, const Common::String &x_name = "x",
|
||||
const Common::String &y_name = "y", const Common::String &w_name = "w", const Common::String &h_name = "h");
|
||||
|
||||
// Is this rectangle colliding with another rectangle?
|
||||
bool collide(Rect box) const;
|
||||
|
||||
// Extend this rectangle to fully contain another rectangle
|
||||
void extend(Rect box);
|
||||
|
||||
// Resolving a collision means we need to correct the position of the target rectangle to just outside of the reference rectangle
|
||||
// To do this, first we need to determine which edges of the rectangles are colliding
|
||||
|
||||
// Resolve a collision in the X plane
|
||||
Direction resolveX(Rect collider);
|
||||
|
||||
// Resolve a collision in the Y plane
|
||||
Direction resolveY(Rect collider);
|
||||
|
||||
// Does this rectangle contain a point?
|
||||
bool contains(int x1, int y1) {
|
||||
return (x1 > x && x1 < x + w && y1 > y && y1 < y + h);
|
||||
}
|
||||
|
||||
bool contains(Vector2i v) {
|
||||
return contains(v.x, v.y);
|
||||
}
|
||||
|
||||
// Does this rectangle contain another rectangle?
|
||||
bool contains(Rect box) {
|
||||
return (x < box.x && x + w > box.x + box.w && y < box.y && y + h > box.y + box.h);
|
||||
}
|
||||
|
||||
// Flip a rectangle with respect to an axis
|
||||
void flip(const TextureFlipType &flip, const Vector2i &axis);
|
||||
|
||||
// Draw the borders of the rectangle
|
||||
void draw(const int &xOffset = 0, const int &yOffset = 0, const uint8 &r = 0, const uint8 &g = 0, const uint8 &b = 0, const uint8 &a = 255);
|
||||
|
||||
// Check if a rectangle is the same as another
|
||||
bool operator==(const Rect &r) { return r.x == x && r.y == y && r.w == w && r.h == h; }
|
||||
|
||||
// Save to file
|
||||
void saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root, const char *name);
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_RECTANGLE_H
|
||||
118
engines/crab/ScreenSettings.cpp
Normal file
118
engines/crab/ScreenSettings.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/* 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 "common/config-manager.h"
|
||||
#include "common/system.h"
|
||||
#include "crab/crab.h"
|
||||
#include "crab/GameParam.h"
|
||||
#include "crab/loaders.h"
|
||||
#include "crab/ScreenSettings.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
void ScreenSettings::load(rapidxml::xml_node<char> *node) {
|
||||
loadNum(_cur.w, "w", node);
|
||||
loadNum(_cur.h, "h", node);
|
||||
loadNum(_fps, "fps", node);
|
||||
loadNum(_gamma, "gamma", node);
|
||||
loadNum(_textSpeed, "text_speed", node);
|
||||
|
||||
// The following values are read from ConfMan instead of the XML
|
||||
//loadBool(_vsync, "vsync", node);
|
||||
//loadBool(_fullscreen, "fullscreen", node);
|
||||
loadBool(_border, "border", node);
|
||||
loadBool(_saveOnExit, "save_on_exit", node);
|
||||
//loadBool(_mouseTrap, "mouse_trap", node);
|
||||
loadBool(_quality, "quality", node);
|
||||
|
||||
if (ConfMan.hasKey("mousetrap"))
|
||||
_mouseTrap = ConfMan.getBool("mousetrap");
|
||||
|
||||
if (ConfMan.hasKey("fullscreen"))
|
||||
_fullscreen = ConfMan.getBool("fullscreen");
|
||||
|
||||
if (ConfMan.hasKey("vsync"))
|
||||
_vsync = ConfMan.getBool("vsync");
|
||||
}
|
||||
|
||||
void ScreenSettings::internalEvents() {
|
||||
if (g_system->hasFeature(OSystem::kFeatureFullscreenMode))
|
||||
_fullscreen = g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
|
||||
|
||||
if (g_system->hasFeature(OSystem::kFeatureVSync))
|
||||
_vsync = g_system->getFeatureState(OSystem::kFeatureVSync);
|
||||
}
|
||||
|
||||
void ScreenSettings::toggleFullScreen() {
|
||||
if (g_system->hasFeature(OSystem::kFeatureFullscreenMode)) {
|
||||
_fullscreen = !_fullscreen;
|
||||
g_system->beginGFXTransaction();
|
||||
g_system->setFeatureState(OSystem::kFeatureFullscreenMode, _fullscreen);
|
||||
g_system->endGFXTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSettings::toggleVsync() {
|
||||
if (g_system->hasFeature(OSystem::kFeatureVSync)) {
|
||||
_vsync = !_vsync;
|
||||
g_system->beginGFXTransaction();
|
||||
g_system->setFeatureState(OSystem::kFeatureVSync, _vsync);
|
||||
g_system->endGFXTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenSettings::saveState() {
|
||||
ConfMan.setBool("fullscreen", _fullscreen);
|
||||
ConfMan.setBool("vsync", _vsync);
|
||||
ConfMan.setBool("mousetrap", _mouseTrap);
|
||||
|
||||
#if 0
|
||||
root->append_attribute(doc.allocate_attribute("version", g_engine->_stringPool->get(_version)));
|
||||
|
||||
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, "screen");
|
||||
child->append_attribute(doc.allocate_attribute("w", g_engine->_stringPool->get(_cur.w)));
|
||||
child->append_attribute(doc.allocate_attribute("h", g_engine->_stringPool->get(_cur.h)));
|
||||
child->append_attribute(doc.allocate_attribute("fps", g_engine->_stringPool->get(_fps)));
|
||||
|
||||
child->append_attribute(doc.allocate_attribute("gamma", g_engine->_stringPool->fGet(_gamma)));
|
||||
child->append_attribute(doc.allocate_attribute("text_speed", g_engine->_stringPool->fGet(_textSpeed)));
|
||||
|
||||
saveBool(_vsync, "vsync", doc, child);
|
||||
saveBool(_border, "border", doc, child);
|
||||
saveBool(_fullscreen, "fullscreen", doc, child);
|
||||
saveBool(_saveOnExit, "save_on_exit", doc, child);
|
||||
saveBool(_quality, "quality", doc, child);
|
||||
saveBool(_mouseTrap, "mouse_trap", doc, child);
|
||||
|
||||
root->append_node(child);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
140
engines/crab/ScreenSettings.h
Normal file
140
engines/crab/ScreenSettings.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/* 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_SCREENSETTINGS_H
|
||||
#define CRAB_SCREENSETTINGS_H
|
||||
|
||||
#include "crab/rapidxml/rapidxml.hpp"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
struct Dimension {
|
||||
int w, h;
|
||||
Dimension() {
|
||||
w = 1280;
|
||||
h = 720;
|
||||
}
|
||||
|
||||
bool operator<(const Dimension &d) { return (w < d.w && h < d.h); }
|
||||
};
|
||||
|
||||
class ScreenAttributes {
|
||||
public:
|
||||
// Frames per second
|
||||
int _fps;
|
||||
|
||||
// The current screen dimensions
|
||||
Dimension _cur;
|
||||
|
||||
// The minimum dimension where we draw the image without scaling
|
||||
// Any lower than this and we draw at the minimum resolution, then scale it down
|
||||
// Dimension min;
|
||||
|
||||
// Is the window full-screen?
|
||||
bool _fullscreen;
|
||||
|
||||
// Does the window have a border?
|
||||
bool _border;
|
||||
|
||||
// Is vertical sync enabled?
|
||||
bool _vsync;
|
||||
|
||||
// The brightness of a window
|
||||
float _gamma;
|
||||
|
||||
// The video flags
|
||||
uint32 _videoflags;
|
||||
|
||||
// should we save on exit?
|
||||
bool _saveOnExit;
|
||||
|
||||
// This flag is true if we want to load high quality images, false otherwise
|
||||
bool _quality;
|
||||
|
||||
// Is the mouse trapped within the window
|
||||
bool _mouseTrap;
|
||||
|
||||
// The text speed (used only for popup text)
|
||||
float _textSpeed;
|
||||
|
||||
ScreenAttributes() {
|
||||
_fps = 60;
|
||||
_fullscreen = false;
|
||||
_border = true;
|
||||
_vsync = true;
|
||||
_saveOnExit = true;
|
||||
_quality = true;
|
||||
_mouseTrap = false;
|
||||
_gamma = 1.0f;
|
||||
_textSpeed = 1.0f;
|
||||
_videoflags = 0; //SDL_WINDOW_SHOWN;
|
||||
}
|
||||
};
|
||||
|
||||
// Screen attributes
|
||||
class ScreenSettings : public ScreenAttributes {
|
||||
|
||||
public:
|
||||
// The desktop dimensions
|
||||
Dimension _desktop;
|
||||
|
||||
// True if we are in game, false otherwise
|
||||
bool _inGame;
|
||||
|
||||
// Set to true when we have to call setUI() for rearranging UI after a resolution change
|
||||
bool _changeInterface;
|
||||
|
||||
// The version of the settings
|
||||
uint _version;
|
||||
|
||||
ScreenSettings() {
|
||||
_inGame = false;
|
||||
_version = 0;
|
||||
_changeInterface = false;
|
||||
}
|
||||
~ScreenSettings() {}
|
||||
|
||||
bool validDimension(Dimension d) {
|
||||
return d.w <= _desktop.w && d.h <= _desktop.h;
|
||||
}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
|
||||
void internalEvents();
|
||||
|
||||
void toggleFullScreen();
|
||||
void toggleVsync();
|
||||
|
||||
void saveState();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CRAB_SCREENSETTINGS_H
|
||||
85
engines/crab/Shape.cpp
Normal file
85
engines/crab/Shape.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/* 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/Shape.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
void Shape::load(rapidxml::xml_node<char> *node, const bool &echo) {
|
||||
if (nodeValid("polygon", node, echo)) {
|
||||
_type = SHAPE_POLYGON;
|
||||
_poly.load(node, _rect);
|
||||
} else {
|
||||
_rect.load(node, echo, "x", "y", "width", "height");
|
||||
if (nodeValid("ellipse", node, echo))
|
||||
_type = SHAPE_ELLIPSE;
|
||||
else
|
||||
_type = SHAPE_RECT;
|
||||
}
|
||||
}
|
||||
|
||||
CollisionData Shape::collide(Rect box) const {
|
||||
CollisionData res;
|
||||
res._intersect = _rect.collide(box);
|
||||
|
||||
if (res._intersect) {
|
||||
res._type = _type;
|
||||
if (_type == SHAPE_POLYGON) {
|
||||
PolygonCollisionResult pcr = _poly.collide(box);
|
||||
res._intersect = pcr._intersect;
|
||||
res._data.x = pcr._mtv.x;
|
||||
res._data.y = pcr._mtv.y;
|
||||
return res;
|
||||
} else
|
||||
res._data = _rect;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Shape::contains(const Vector2i &pos) {
|
||||
if (_rect.contains(pos)) {
|
||||
if (_type == SHAPE_POLYGON)
|
||||
return _poly.contains(pos.x, pos.y);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Shape::draw(const int &xOffset, const int &yOffset, const uint8 &r, const uint8 &g, const uint8 &b, const uint8 &a) {
|
||||
if (_type == SHAPE_POLYGON)
|
||||
_poly.draw(xOffset, yOffset, r, g, b, a);
|
||||
else
|
||||
_rect.draw(xOffset, yOffset, r, g, b, a);
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
91
engines/crab/Shape.h
Normal file
91
engines/crab/Shape.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* 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_SHAPE_H
|
||||
#define CRAB_SHAPE_H
|
||||
|
||||
#include "crab/Polygon.h"
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// The kind of shape
|
||||
enum ShapeType {
|
||||
SHAPE_RECT,
|
||||
SHAPE_POLYGON,
|
||||
SHAPE_ELLIPSE
|
||||
};
|
||||
|
||||
struct CollisionData {
|
||||
// Store the type of shape
|
||||
ShapeType _type;
|
||||
|
||||
// Do the two shapes intersect?
|
||||
bool _intersect;
|
||||
|
||||
// If Shape is Polygon, the .x and .y of this rectangle contain the minimum translation vector
|
||||
// If Shape is Rectangle, this contains the colliding rectangle
|
||||
Rect _data;
|
||||
|
||||
CollisionData() {
|
||||
_type = SHAPE_RECT;
|
||||
_intersect = false;
|
||||
}
|
||||
};
|
||||
|
||||
class Shape {
|
||||
public:
|
||||
// The type of shape
|
||||
ShapeType _type;
|
||||
|
||||
// This stores both the ellipse and rectangle data
|
||||
Rect _rect;
|
||||
|
||||
// This stores the polygon data
|
||||
Polygon2D _poly;
|
||||
|
||||
Shape() {
|
||||
_type = SHAPE_RECT;
|
||||
}
|
||||
|
||||
~Shape() {}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node, const bool &echo = true);
|
||||
CollisionData collide(Rect box) const;
|
||||
|
||||
bool contains(const Vector2i &pos);
|
||||
|
||||
void draw(const int &xOffset = 0, const int &yOffset = 0,
|
||||
const uint8 &r = 0, const uint8 &g = 0, const uint8 &b = 0, const uint8 &a = 255);
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_SHAPE_H
|
||||
107
engines/crab/TMX/TMXLayer.cpp
Normal file
107
engines/crab/TMX/TMXLayer.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/* 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/TMX/TMXLayer.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace TMX;
|
||||
|
||||
bool Layer::load(rapidxml::xml_node<char> *node) {
|
||||
if (nodeValid(node))
|
||||
return loadStr(_name, "name", node) && loadNum(_w, "width", node) && loadNum(_h, "height", node);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MapLayer::load(const Common::Path &path, rapidxml::xml_node<char> *node) {
|
||||
if (Layer::load(node)) {
|
||||
if (nodeValid("image", node, false)) {
|
||||
_type = LAYER_IMAGE;
|
||||
rapidxml::xml_node<char> *imgnode = node->first_node("image");
|
||||
|
||||
if (imgnode->first_attribute("source") != nullptr)
|
||||
_img.load(path.append(imgnode->first_attribute("source")->value()));
|
||||
} else {
|
||||
_type = LAYER_NORMAL;
|
||||
int i = 0;
|
||||
Common::Array<TileInfo> t;
|
||||
|
||||
//.tmx stores tiles row-first
|
||||
for (auto n = node->first_node("data")->first_node("tile"); n != nullptr; n = n->next_sibling("tile")) {
|
||||
t.push_back(n);
|
||||
|
||||
if (++i >= _w) {
|
||||
_tile.push_back(t);
|
||||
t.clear();
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load properties associated with the layer, such as:
|
||||
// Is it a prop layer or not? If yes, the prop dimensions
|
||||
// The rate of scrolling of the layer, used for parallax scrolling
|
||||
if (nodeValid("properties", node, false)) {
|
||||
Common::String n, v;
|
||||
for (auto p = node->first_node("properties")->first_node("property"); p != nullptr; p = p->next_sibling("property")) {
|
||||
if (loadStr(n, "name", p) && loadStr(v, "value", p)) {
|
||||
if (n == "prop" && v == "true")
|
||||
_type = LAYER_PROP;
|
||||
else if (n == "autohide" && v == "true")
|
||||
_type = LAYER_AUTOHIDE;
|
||||
else if (n == "autoshow" && v == "true")
|
||||
_type = LAYER_AUTOSHOW;
|
||||
else if (n == "x") {
|
||||
_pos.x = stringToNumber<int>(v);
|
||||
} else if (n == "y") {
|
||||
_pos.y = stringToNumber<int>(v);
|
||||
} else if (n == "w") {
|
||||
_pos.w = stringToNumber<int>(v);
|
||||
} else if (n == "h") {
|
||||
_pos.h = stringToNumber<int>(v);
|
||||
} else if (n == "scroll_rate_x") {
|
||||
_rate.x = stringToNumber<float>(v);
|
||||
_type = LAYER_PARALLAX;
|
||||
} else if (n == "scroll_rate_y") {
|
||||
_rate.y = stringToNumber<float>(v);
|
||||
_type = LAYER_PARALLAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
115
engines/crab/TMX/TMXLayer.h
Normal file
115
engines/crab/TMX/TMXLayer.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/* 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_TMXLAYER_H
|
||||
#define CRAB_TMXLAYER_H
|
||||
|
||||
#include "crab/Rectangle.h"
|
||||
#include "crab/image/Image.h"
|
||||
#include "crab/TMX/TileInfo.h"
|
||||
|
||||
#include "common/list.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace TMX {
|
||||
enum LayerType {
|
||||
// Run of the mill layer full of tiles
|
||||
LAYER_NORMAL,
|
||||
|
||||
// Layer containing a simple image instead of tiles
|
||||
LAYER_IMAGE,
|
||||
|
||||
// We do not draw prop layers along with the non-prop layers,
|
||||
// because their draw order depends on the positions of the sprites
|
||||
LAYER_PROP,
|
||||
|
||||
// Parallax layers are drawn differently, but are still composed of tiles
|
||||
LAYER_PARALLAX,
|
||||
|
||||
// Auto-hide layers are primarily used for interiors
|
||||
// These are only visible if the player is colliding with them
|
||||
LAYER_AUTOHIDE,
|
||||
|
||||
// Auto-show layers are the reverse of auto-hide layers
|
||||
// These are only visible if the player is not colliding with them
|
||||
LAYER_AUTOSHOW
|
||||
};
|
||||
|
||||
class Layer {
|
||||
public:
|
||||
// Name of the layer
|
||||
Common::String _name;
|
||||
|
||||
// Dimensions of the layer in terms of tiles
|
||||
int _w, _h;
|
||||
|
||||
Layer() {
|
||||
_w = 0;
|
||||
_h = 0;
|
||||
}
|
||||
bool load(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
|
||||
// Currently we just use one general purpose layer object instead of multiple inherited classes and stuff
|
||||
class MapLayer : public Layer {
|
||||
public:
|
||||
// The tiles in the layer
|
||||
Common::Array<Common::Array<TileInfo>> _tile;
|
||||
|
||||
// The type of layer
|
||||
LayerType _type;
|
||||
|
||||
// The image in the layer
|
||||
pyrodactyl::image::Image _img;
|
||||
|
||||
// The coordinates to draw the prop in(x,y) and dimensions of the area(w,h) in terms of tiles
|
||||
// This is also the collision rectangle of the prop and auto hide layer
|
||||
Rect _pos;
|
||||
|
||||
Common::List<Rect> _boundRect;
|
||||
|
||||
// The rate of scrolling of image, used for parallax
|
||||
Vector2f _rate;
|
||||
|
||||
// Is the player colliding with the layer? (used for auto hide layer)
|
||||
bool _collide;
|
||||
|
||||
MapLayer() : _rate(1, 1) {
|
||||
_type = LAYER_NORMAL;
|
||||
_collide = false;
|
||||
}
|
||||
bool load(const Common::Path &path, rapidxml::xml_node<char> *node);
|
||||
};
|
||||
} // End of namespace TMX
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_TMXLAYER_H
|
||||
374
engines/crab/TMX/TMXMap.cpp
Normal file
374
engines/crab/TMX/TMXMap.cpp
Normal file
@@ -0,0 +1,374 @@
|
||||
/* 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/image/ImageManager.h"
|
||||
#include "crab/text/TextManager.h"
|
||||
#include "crab/TMX/TMXMap.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace TMX;
|
||||
using namespace pyrodactyl::image;
|
||||
|
||||
static bool propCompare(const MapLayer &l1, const MapLayer &l2) {
|
||||
return l1._pos.y + l1._pos.h < l2._pos.y + l2._pos.h;
|
||||
}
|
||||
|
||||
TMXMap::TMXMap() {
|
||||
_tileRows = 0;
|
||||
_tileCols = 0;
|
||||
_pathRows = 0;
|
||||
_pathCols = 0;
|
||||
|
||||
_w = 0;
|
||||
_h = 0;
|
||||
_spriteLayer = 0;
|
||||
_grid = nullptr;
|
||||
|
||||
_movementCosts._noWalk = 0;
|
||||
_movementCosts._open = 0;
|
||||
_movementCosts._stairs = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Load stuff via a .tmx file set to xml storage (no compression)
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
void TMXMap::load(const Common::Path &path, const Common::String &filename) {
|
||||
XMLDoc conf(path.appendComponent(filename));
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *node = conf.doc()->first_node("map");
|
||||
if (nodeValid(node)) {
|
||||
loadNum(_tileRows, "width", node);
|
||||
loadNum(_tileCols, "height", node);
|
||||
loadNum(_tileSize.x, "tilewidth", node);
|
||||
loadNum(_tileSize.y, "tileheight", node);
|
||||
|
||||
// Pathfinding info load
|
||||
_pathSize.x = 0;
|
||||
_pathSize.y = 0;
|
||||
|
||||
loadNum(_pathSize.x, "pathwidth", node);
|
||||
loadNum(_pathSize.y, "pathheight", node);
|
||||
|
||||
// Load costs...Not sure if this is right. (SZ)
|
||||
loadNum(_movementCosts._open, "opencost", node);
|
||||
loadNum(_movementCosts._noWalk, "nowalkcost", node);
|
||||
loadNum(_movementCosts._stairs, "stairscost", node);
|
||||
|
||||
// if(path_size.x == 0)
|
||||
// path_size.x = tile_size.x;
|
||||
// if(path_size.y == 0)
|
||||
// path_size.y = tile_size.y;
|
||||
// Testing
|
||||
if (_pathSize.x == 0)
|
||||
_pathSize.x = 40;
|
||||
if (_pathSize.y == 0)
|
||||
_pathSize.y = 40;
|
||||
|
||||
_w = _tileRows * _tileSize.x;
|
||||
_h = _tileCols * _tileSize.y;
|
||||
|
||||
_pathRows = (int)ceil((float)_w / (float)_pathSize.x + .5f); // Adding .5 before casting in order to round up (SZ)
|
||||
_pathCols = (int)ceil((float)_h / (float)_pathSize.y + .5f);
|
||||
|
||||
g_engine->_imageManager->_tileset.load(path, node);
|
||||
|
||||
// Reset the layer at which sprites are drawn
|
||||
_spriteLayer = 0;
|
||||
uint layerCount = 0;
|
||||
|
||||
// We need to cycle through all tile and object layers in order to
|
||||
// see the level at which the sprites will be drawn
|
||||
for (auto groupnode = node->first_node(); groupnode != nullptr; groupnode = groupnode->next_sibling()) {
|
||||
// Store the name for easy comparison
|
||||
Common::String name = groupnode->name();
|
||||
|
||||
if (name == "layer" || name == "imagelayer") { // Is this a tile or an image layer
|
||||
MapLayer l;
|
||||
l.load(path, groupnode);
|
||||
l._pos.x *= _tileSize.x;
|
||||
l._pos.y *= _tileSize.y;
|
||||
l._pos.w *= _tileSize.x;
|
||||
l._pos.h *= _tileSize.y;
|
||||
|
||||
if (l._type == LAYER_PROP)
|
||||
_prop.push_back(l);
|
||||
else
|
||||
_layer.push_back(l);
|
||||
|
||||
layerCount++;
|
||||
} else if (name == "objectgroup") { // Is this an object layer
|
||||
Common::String groupName;
|
||||
loadStr(groupName, "name", groupnode);
|
||||
if (groupName == "exit") {
|
||||
for (auto n = groupnode->first_node("object"); n != nullptr; n = n->next_sibling("object")) {
|
||||
pyrodactyl::level::Exit le(n);
|
||||
_areaExit.push_back(le);
|
||||
}
|
||||
} else if (groupName == "walk") {
|
||||
auto n = groupnode->first_node("object");
|
||||
if (n != nullptr)
|
||||
_areaWalk.load(n, true, "x", "y", "width", "height");
|
||||
} else if (groupName == "no_walk") {
|
||||
for (auto n = groupnode->first_node("object"); n != nullptr; n = n->next_sibling("object")) {
|
||||
Shape s;
|
||||
s.load(n);
|
||||
_areaNowalk.push_back(s);
|
||||
}
|
||||
} else if (groupName == "trigger") {
|
||||
for (auto n = groupnode->first_node("object"); n != nullptr; n = n->next_sibling("object")) {
|
||||
Shape s;
|
||||
s.load(n);
|
||||
|
||||
uint pos = _areaTrig.size();
|
||||
loadNum(pos, "name", n);
|
||||
|
||||
if (_areaTrig.size() <= pos)
|
||||
_areaTrig.resize(pos + 1);
|
||||
|
||||
_areaTrig[pos] = s;
|
||||
}
|
||||
} else if (groupName == "stairs") {
|
||||
for (auto n = groupnode->first_node("object"); n != nullptr; n = n->next_sibling("object")) {
|
||||
pyrodactyl::level::Stairs s;
|
||||
s.load(n);
|
||||
_areaStairs.push_back(s);
|
||||
}
|
||||
} else if (groupName == "music") {
|
||||
for (auto n = groupnode->first_node("object"); n != nullptr; n = n->next_sibling("object")) {
|
||||
pyrodactyl::level::MusicArea ma;
|
||||
ma.load(n);
|
||||
_areaMusic.push_back(ma);
|
||||
}
|
||||
} else if (groupName == "sprites")
|
||||
_spriteLayer = layerCount;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the props in the level according to y axis
|
||||
Common::sort(_prop.begin(), _prop.end(), propCompare);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Use this if you want to load a poly line from tmx
|
||||
//------------------------------------------------------------------------
|
||||
// void TMXMap::LoadPath(rapidxml::xml_node<char> *node)
|
||||
//{
|
||||
// int pos = 0;
|
||||
// for (auto n = node->first_node("object"); n != nullptr; n = n->next_sibling("object"), ++pos)
|
||||
// {
|
||||
// Vector2i start;
|
||||
// start.load(n);
|
||||
//
|
||||
// rapidxml::xml_node<char> *linenode = n->first_node("polyline");
|
||||
// if (linenode != nullptr)
|
||||
// {
|
||||
// Common::String points, x, y;
|
||||
// loadStr(points, "points", linenode);
|
||||
//
|
||||
// path.resize(pos + 1);
|
||||
// bool comma = false;
|
||||
// for (auto i = points.begin(); i != points.end(); ++i)
|
||||
// {
|
||||
// if (*i == ',') comma = true;
|
||||
// else if (*i == ' ')
|
||||
// {
|
||||
// path[pos].push_back(GetPoint(start, x, y));
|
||||
// comma = false;
|
||||
// x.clear();
|
||||
// y.clear();
|
||||
// }
|
||||
// else if (comma) y.push_back(*i);
|
||||
// else x.push_back(*i);
|
||||
// }
|
||||
// path[pos].push_back(GetPoint(start, x, y));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Convert point from string to vector
|
||||
//------------------------------------------------------------------------
|
||||
// const Vector2i TMXMap::GetPoint(const Vector2i &ref, Common::String &x, Common::String &y)
|
||||
//{
|
||||
// Vector2i v;
|
||||
// v.x = ref.x + StringToNumber<int>(x);
|
||||
// v.y = ref.y + StringToNumber<int>(y);
|
||||
// return v;
|
||||
//}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Clear all data from the level
|
||||
//------------------------------------------------------------------------
|
||||
void TMXMap::reset() {
|
||||
g_engine->_imageManager->_tileset.reset();
|
||||
_layer.clear();
|
||||
|
||||
_areaNowalk.clear();
|
||||
_areaExit.clear();
|
||||
_areaTrig.clear();
|
||||
_areaStairs.clear();
|
||||
_areaMusic.clear();
|
||||
|
||||
_prop.clear();
|
||||
_spriteLayer = 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Draw functions
|
||||
//------------------------------------------------------------------------
|
||||
void TMXMap::drawDebug(const Rect &camera) {
|
||||
using namespace pyrodactyl::text;
|
||||
|
||||
for (auto &i : _areaTrig)
|
||||
i.draw(-camera.x, -camera.y, 0, 0, 254, 254);
|
||||
|
||||
for (auto &i : _areaExit)
|
||||
i._dim.draw(-camera.x, -camera.y, 0, 254, 254, 254);
|
||||
|
||||
for (auto &i : _prop)
|
||||
i._pos.draw(-camera.x, -camera.y, 254, 0, 254, 254);
|
||||
|
||||
for (auto &i : _areaNowalk)
|
||||
i.draw(-camera.x, -camera.y, 254, 0, 0, 254);
|
||||
|
||||
for (auto &i : _areaMusic)
|
||||
i.draw(-camera.x, -camera.y, 254, 254, 0, 254);
|
||||
|
||||
for (auto &i : _areaStairs) {
|
||||
i.draw(-camera.x, -camera.y, 0, 254, 0, 254);
|
||||
}
|
||||
|
||||
// Draw the pathfinding grid (SZ)
|
||||
for (int x = 0; x < _grid->getDimensions().x; ++x) {
|
||||
for (int y = 0; y < _grid->getDimensions().y; ++y) {
|
||||
if (_grid->getNodeAtCoords(x, y)->getMovementCost() < 0.0f)
|
||||
_grid->getNodeAtCoords(x, y)->getRect().draw(-camera.x, -camera.y, 0, 0, 0, 254);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &i : _layer)
|
||||
i._pos.draw(-camera.x, -camera.y, 254, 216, 0);
|
||||
|
||||
_areaWalk.draw(-camera.x, -camera.y, 254, 254, 254, 254);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Collision functions
|
||||
//------------------------------------------------------------------------
|
||||
void TMXMap::collideWithNoWalk(const Rect boundingBox, Common::List<CollisionData> &colliders) {
|
||||
CollisionData res;
|
||||
for (auto &i : _areaNowalk) {
|
||||
res = i.collide(boundingBox);
|
||||
if (res._intersect)
|
||||
colliders.push_back(res);
|
||||
}
|
||||
}
|
||||
|
||||
bool TMXMap::insideNoWalk(const Vector2i &pos) {
|
||||
for (auto &i : _areaNowalk)
|
||||
if (i.contains(pos))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TMXMap::insideWalk(const Rect &boundingBox) {
|
||||
if (_areaWalk.contains(boundingBox))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TMXMap::insideWalk(const Vector2i &pos) {
|
||||
if (_areaWalk.contains(pos))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TMXMap::collideWithTrigger(const Rect rect, int index) {
|
||||
if (_areaTrig.size() > (uint)index)
|
||||
return _areaTrig[index].collide(rect)._intersect;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TMXMap::collideWithTrigger(const Rect rect, Common::Array<int> &collisionTable) {
|
||||
int index = 0;
|
||||
collisionTable.clear();
|
||||
|
||||
for (auto i = _areaTrig.begin(); i != _areaTrig.end(); ++i, ++index)
|
||||
if (i->collide(rect)._intersect)
|
||||
collisionTable.push_back(index);
|
||||
}
|
||||
|
||||
bool TMXMap::collideWithExit(const Rect rect, LevelResult &res) {
|
||||
for (const auto &i : _areaExit)
|
||||
if (i._dim.collide(rect)._intersect) {
|
||||
res._val = i._name;
|
||||
res._x = i._entry.x;
|
||||
res._y = i._entry.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TMXMap::collideWithStairs(const Rect rect, Vector2f &velMod) {
|
||||
for (const auto &i : _areaStairs) {
|
||||
if (i.collide(rect)._intersect) {
|
||||
velMod = i._modifier;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// We are not colliding with any stairs, reset the modifier
|
||||
velMod.x = 1.0f;
|
||||
velMod.y = 1.0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TMXMap::collideWithMusic(const Rect rect, pyrodactyl::level::MusicInfo &music) {
|
||||
for (const auto &i : _areaMusic) {
|
||||
if (i.collide(rect)._intersect) {
|
||||
music._id = i._id;
|
||||
music._track = i._track;
|
||||
music._loops = i._loops;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
148
engines/crab/TMX/TMXMap.h
Normal file
148
engines/crab/TMX/TMXMap.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/* 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_TMXMAP_H
|
||||
#define CRAB_TMXMAP_H
|
||||
|
||||
#include "crab/LevelResult.h"
|
||||
#include "crab/Shape.h"
|
||||
#include "crab/XMLDoc.h"
|
||||
#include "crab/ai/spriteai.h"
|
||||
#include "crab/level/LevelExit.h"
|
||||
#include "crab/level/MusicArea.h"
|
||||
#include "crab/level/Stairs.h"
|
||||
#include "crab/TMX/TMXTileSet.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace TMX {
|
||||
// For TMX version 1.0, orthogonal maps only
|
||||
class TMXMap {
|
||||
protected:
|
||||
// The actual dimensions of the level
|
||||
int _w, _h;
|
||||
|
||||
// The area you can move in
|
||||
Rect _areaWalk;
|
||||
|
||||
// The non-walk able areas in the level
|
||||
Common::Array<Shape> _areaNowalk;
|
||||
|
||||
// The trigger rectangles in the level
|
||||
Common::Array<Shape> _areaTrig;
|
||||
|
||||
// Stairs modify the player walking speed
|
||||
Common::Array<pyrodactyl::level::Stairs> _areaStairs;
|
||||
|
||||
// Music areas change the music if player collides with them
|
||||
Common::Array<pyrodactyl::level::MusicArea> _areaMusic;
|
||||
|
||||
// Archived methods for loading poly lines in tiled
|
||||
// void LoadPath(rapidxml::xml_node<char> *node);
|
||||
// const Vector2i GetPoint(const Vector2i &ref, Common::String &x, Common::String &y);
|
||||
|
||||
public:
|
||||
// The exits to different levels
|
||||
Common::Array<pyrodactyl::level::Exit> _areaExit;
|
||||
|
||||
// The layer on top of which objects walk
|
||||
uint _spriteLayer;
|
||||
|
||||
// Dimensions of the level in terms of tiles
|
||||
int _tileRows, _tileCols;
|
||||
|
||||
// Dimensions of the level in terms of pathfinding grid cells (SZ)
|
||||
int _pathRows, _pathCols;
|
||||
|
||||
// The width and height of tiles
|
||||
Vector2i _tileSize;
|
||||
|
||||
// The width and height of pathfinding grid cells (SZ)
|
||||
Vector2i _pathSize;
|
||||
|
||||
// The layers of tiles in the level
|
||||
Common::Array<MapLayer> _layer;
|
||||
|
||||
// The props in the level
|
||||
Common::Array<MapLayer> _prop;
|
||||
|
||||
PathfindingGrid *_grid; // The grid of graph nodes used for navigating.
|
||||
|
||||
// Movement costs
|
||||
struct {
|
||||
int _open, _noWalk, _stairs;
|
||||
} _movementCosts;
|
||||
|
||||
TMXMap();
|
||||
~TMXMap() {}
|
||||
|
||||
void reset();
|
||||
void load(const Common::Path &path, const Common::String &filename);
|
||||
|
||||
void drawDebug(const Rect &camera);
|
||||
|
||||
bool insideWalk(const Rect &boundingBox);
|
||||
bool insideWalk(const Vector2i &pos);
|
||||
|
||||
bool insideNoWalk(const Vector2i &pos);
|
||||
void collideWithNoWalk(const Rect boundingBox, Common::List<CollisionData> &colliders);
|
||||
|
||||
bool collideWithExit(const Rect rect, LevelResult &res);
|
||||
bool collideWithStairs(const Rect rect, Vector2f &velMod);
|
||||
bool collideWithMusic(const Rect rect, pyrodactyl::level::MusicInfo &music);
|
||||
|
||||
bool collideWithTrigger(const Rect rect, int index);
|
||||
void collideWithTrigger(const Rect rect, Common::Array<int> &collisionTable);
|
||||
|
||||
int w() {
|
||||
return _w;
|
||||
}
|
||||
|
||||
int h() {
|
||||
return _h;
|
||||
}
|
||||
|
||||
const Rect &areaWalk() const {
|
||||
return _areaWalk;
|
||||
}
|
||||
|
||||
const Common::Array<Shape> &areaNoWalk() const {
|
||||
return _areaNowalk;
|
||||
}
|
||||
|
||||
const Common::Array<pyrodactyl::level::Stairs> &areaStairs() const {
|
||||
return _areaStairs;
|
||||
}
|
||||
};
|
||||
} // End of namespace TMX
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_TMXMAP_H
|
||||
270
engines/crab/TMX/TMXTileSet.cpp
Normal file
270
engines/crab/TMX/TMXTileSet.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/* 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 "graphics/screen.h"
|
||||
#include "crab/crab.h"
|
||||
#include "crab/text/TextManager.h"
|
||||
#include "crab/TMX/TMXTileSet.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace TMX;
|
||||
|
||||
void TileSet::load(const Common::Path &path, rapidxml::xml_node<char> *node) {
|
||||
if (nodeValid(node)) {
|
||||
loadNum(_firstGid, "firstgid", node);
|
||||
loadStr(_name, "name", node);
|
||||
loadNum(_tileW, "tilewidth", node);
|
||||
loadNum(_tileH, "tileheight", node);
|
||||
|
||||
_clip.w = _tileW;
|
||||
_clip.h = _tileH;
|
||||
|
||||
if (nodeValid("image", node)) {
|
||||
rapidxml::xml_node<char> *imgnode = node->first_node("image");
|
||||
Common::String filename;
|
||||
loadStr(filename, "source", imgnode);
|
||||
_loc = path.appendComponent(filename);
|
||||
|
||||
_img.load(_loc);
|
||||
_totalRows = _img.h() / _tileH;
|
||||
_totalCols = _img.w() / _tileW;
|
||||
debugC(kDebugGraphics, "Total rows : %d Total cols: %d gid: %d", _totalRows, _totalCols, _firstGid);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent divide by zero errors later
|
||||
if (_totalCols == 0)
|
||||
_totalCols = 1;
|
||||
}
|
||||
|
||||
void TileSetGroup::reset() {
|
||||
for (auto &i : _tileset)
|
||||
i._img.deleteImage();
|
||||
|
||||
_tileset.clear();
|
||||
}
|
||||
|
||||
void TileSetGroup::load(const Common::Path &path, rapidxml::xml_node<char> *node) {
|
||||
reset();
|
||||
for (auto n = node->first_node("tileset"); n != nullptr; n = n->next_sibling("tileset")) {
|
||||
TileSet t;
|
||||
t.load(path, n);
|
||||
_tileset.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
void TileSet::draw(const Vector2i &pos, const TileInfo &tile) {
|
||||
if (tile._gid != 0) {
|
||||
_clip.x = ((tile._gid - _firstGid) % _totalCols) * _tileW;
|
||||
_clip.y = ((tile._gid - _firstGid) / _totalCols) * _tileH;
|
||||
|
||||
_img.draw(pos.x, pos.y, &_clip, tile._flip);
|
||||
}
|
||||
}
|
||||
|
||||
void TileSet::preDraw(const Vector2i &pos, const TileInfo &tile, Graphics::ManagedSurface *surf) {
|
||||
if (tile._gid != 0) {
|
||||
_clip.x = ((tile._gid - _firstGid) % _totalCols) * _tileW;
|
||||
_clip.y = ((tile._gid - _firstGid) / _totalCols) * _tileH;
|
||||
|
||||
_img.draw(pos.x, pos.y, &_clip, tile._flip, surf);
|
||||
}
|
||||
}
|
||||
|
||||
void TileSetGroup::preDraw(MapLayer &layer, const Vector2i &tileSize, Graphics::ManagedSurface *surf) {
|
||||
if (layer._type == LAYER_IMAGE || layer._type == LAYER_AUTOSHOW)
|
||||
return;
|
||||
|
||||
_start.x = 0;
|
||||
_start.y = 0;
|
||||
|
||||
_finish.x = layer._tile.size();
|
||||
_finish.y = layer._tile[0].size();
|
||||
|
||||
_v.x = _start.y * tileSize.x;
|
||||
_v.y = _start.x * tileSize.y;
|
||||
|
||||
for (int x = _start.x; x < _finish.x; ++x) {
|
||||
for (int y = _start.y; y < _finish.y; ++y) {
|
||||
for (int i = _tileset.size() - 1; i >= 0; --i)
|
||||
if (layer._tile[x][y]._gid >= _tileset[i]._firstGid) {
|
||||
_tileset[i].preDraw(_v, layer._tile[x][y], surf);
|
||||
layer._boundRect.push_back(Rect(_v.x, _v.y, tileSize.x, tileSize.y));
|
||||
break;
|
||||
}
|
||||
|
||||
_v.x += tileSize.x;
|
||||
}
|
||||
|
||||
_v.x = _start.y * tileSize.x;
|
||||
_v.y += tileSize.y;
|
||||
}
|
||||
|
||||
Common::List<Rect>::iterator rOuter, rInner;
|
||||
|
||||
// Process the bound rect list to find any rects to merge
|
||||
for (rOuter = layer._boundRect.begin(); rOuter != layer._boundRect.end(); ++rOuter) {
|
||||
rInner = rOuter;
|
||||
while (++rInner != layer._boundRect.end()) {
|
||||
if ((*rOuter).collide(*rInner)) {
|
||||
rOuter->extend(*rInner);
|
||||
layer._boundRect.erase(rInner);
|
||||
rInner = rOuter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TileSetGroup::forceDraw(MapLayer &layer, const Rect &camera, const Vector2i &tileSize, const Rect &playerPos) {
|
||||
|
||||
if (layer._type == LAYER_IMAGE)
|
||||
return;
|
||||
|
||||
layer._collide = layer._pos.collide(playerPos);
|
||||
|
||||
// Normal and prop layers are drawn this way
|
||||
// The row and column we start drawing at
|
||||
_start.x = playerPos.y / tileSize.y;
|
||||
_start.y = playerPos.x / tileSize.x;
|
||||
|
||||
if (_start.x < 0 || _start.y < 0)
|
||||
return;
|
||||
|
||||
// The row and column we end drawing at
|
||||
_finish.x = (playerPos.y + playerPos.h) / tileSize.y + 1;
|
||||
_finish.y = (playerPos.x + playerPos.w) / tileSize.x + 1;
|
||||
|
||||
if (layer._type == LAYER_AUTOSHOW) {
|
||||
if (layer._collide)
|
||||
return;
|
||||
|
||||
_start.x = camera.y / tileSize.y;
|
||||
_start.y = camera.x / tileSize.x;
|
||||
|
||||
//The row and column we end drawing at
|
||||
_finish.x = (camera.y + camera.h) / tileSize.y + 1;
|
||||
_finish.y = (camera.x + camera.w) / tileSize.x + 1;
|
||||
}
|
||||
|
||||
if (_finish.x > (int)layer._tile.size())
|
||||
_finish.x = layer._tile.size();
|
||||
if (_finish.y > (int)layer._tile[0].size())
|
||||
_finish.y = layer._tile[0].size();
|
||||
|
||||
_v.x = _start.y * tileSize.x - camera.x;
|
||||
_v.y = _start.x * tileSize.y - camera.y;
|
||||
|
||||
for (int x = _start.x; x < _finish.x; ++x) {
|
||||
for (int y = _start.y; y < _finish.y; ++y) {
|
||||
for (int i = _tileset.size() - 1; i >= 0; --i)
|
||||
if (layer._tile[x][y]._gid >= _tileset[i]._firstGid) {
|
||||
_tileset[i].draw(_v, layer._tile[x][y]);
|
||||
break;
|
||||
}
|
||||
|
||||
_v.x += tileSize.x;
|
||||
}
|
||||
|
||||
_v.x = _start.y * tileSize.x - camera.x;
|
||||
_v.y += tileSize.y;
|
||||
}
|
||||
}
|
||||
|
||||
void TileSetGroup::draw(MapLayer &layer, const Rect &camera, const Vector2i &tileSize, const Rect &playerPos, pyrodactyl::image::Image &img) {
|
||||
if (layer._type == LAYER_IMAGE)
|
||||
layer._img.draw(-1.0f * camera.x * layer._rate.x, -1.0f * camera.y * layer._rate.y);
|
||||
else if (layer._type == LAYER_PARALLAX) {
|
||||
// The row and column we start drawing at
|
||||
_start.x = 0;
|
||||
_start.y = 0;
|
||||
|
||||
// The row and column we end drawing at
|
||||
_finish.x = layer._tile.size() - 1;
|
||||
_finish.y = layer._tile[0].size() - 1;
|
||||
|
||||
_v.x = (_start.y * tileSize.x - camera.x) * layer._rate.x;
|
||||
_v.y = (_start.x * tileSize.y - camera.y) * layer._rate.y;
|
||||
|
||||
for (int x = _start.x; x < _finish.x; ++x) {
|
||||
for (int y = _start.y; y < _finish.y; ++y) {
|
||||
for (int i = _tileset.size() - 1; i >= 0; --i)
|
||||
if (layer._tile[x][y]._gid >= _tileset[i]._firstGid) {
|
||||
_tileset[i].draw(_v, layer._tile[x][y]);
|
||||
break;
|
||||
}
|
||||
|
||||
_v.x += tileSize.x;
|
||||
}
|
||||
|
||||
_v.x = (_start.y * tileSize.x - camera.x) * layer._rate.x;
|
||||
_v.y += tileSize.y;
|
||||
}
|
||||
} else {
|
||||
layer._collide = layer._pos.collide(playerPos);
|
||||
|
||||
// If player is inside the layer bounds, draw normally - else skip drawing
|
||||
if (layer._type == LAYER_AUTOHIDE && !layer._collide)
|
||||
return;
|
||||
|
||||
// If the player is outside the layer bounds, draw normally - else skip drawing
|
||||
if (layer._type == LAYER_AUTOSHOW && layer._collide)
|
||||
return;
|
||||
|
||||
// Normal and prop layers are drawn this way
|
||||
|
||||
// The row and column we start drawing at
|
||||
_start.x = camera.y / tileSize.y;
|
||||
_start.y = camera.x / tileSize.x;
|
||||
|
||||
// The row and column we end drawing at
|
||||
_finish.x = (camera.y + camera.h) / tileSize.y + 1;
|
||||
_finish.y = (camera.x + camera.w) / tileSize.x + 1;
|
||||
|
||||
if (_finish.x > (int)layer._tile.size())
|
||||
_finish.x = layer._tile.size();
|
||||
if (_finish.y > (int)layer._tile[0].size())
|
||||
_finish.y = layer._tile[0].size();
|
||||
|
||||
_v.x = camera.x;
|
||||
_v.y = camera.y;
|
||||
|
||||
Vector2i end;
|
||||
|
||||
end.x = camera.x + g_engine->_screen->w;
|
||||
end.y = camera.y + g_engine->_screen->h;
|
||||
|
||||
Rect clip(_v.x, _v.y, end.x - _v.x, end.y - _v.y);
|
||||
img.fastDraw(0, 0, &clip);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
109
engines/crab/TMX/TMXTileSet.h
Normal file
109
engines/crab/TMX/TMXTileSet.h
Normal 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRAB_TMXTILESET_H
|
||||
#define CRAB_TMXTILESET_H
|
||||
|
||||
#include "crab/image/Image.h"
|
||||
#include "crab/TMX/TMXLayer.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace TMX {
|
||||
struct TileSet {
|
||||
// The name of the tileset
|
||||
Common::String _name;
|
||||
|
||||
// The location of the tileset image on the disk
|
||||
Common::Path _loc;
|
||||
|
||||
// The first gid of the tileset
|
||||
GidFormat _firstGid;
|
||||
|
||||
// Dimensions of tiles
|
||||
int _tileW, _tileH;
|
||||
|
||||
// Number of rows and columns of tiles
|
||||
int _totalRows, _totalCols;
|
||||
|
||||
// The image used by the tileset
|
||||
pyrodactyl::image::Image _img;
|
||||
|
||||
// Stuff used to store temporary data
|
||||
|
||||
// The rectangle used to store clip info
|
||||
Rect _clip;
|
||||
|
||||
void init() {
|
||||
_firstGid = 1;
|
||||
_tileW = 1;
|
||||
_tileH = 1;
|
||||
_totalRows = 1;
|
||||
_totalCols = 1;
|
||||
}
|
||||
|
||||
TileSet() {
|
||||
init();
|
||||
}
|
||||
|
||||
TileSet(const Common::Path &path, rapidxml::xml_node<char> *node) {
|
||||
init();
|
||||
load(path, node);
|
||||
}
|
||||
|
||||
void load(const Common::Path &path, rapidxml::xml_node<char> *node);
|
||||
void draw(const Vector2i &pos, const TileInfo &tile);
|
||||
void preDraw(const Vector2i &pos, const TileInfo &tile, Graphics::ManagedSurface *surf);
|
||||
};
|
||||
|
||||
class TileSetGroup {
|
||||
Common::Array<TileSet> _tileset;
|
||||
|
||||
// The latest tile position
|
||||
Vector2i _v;
|
||||
|
||||
// The area that we have to draw
|
||||
Vector2i _start, _finish;
|
||||
|
||||
public:
|
||||
TileSetGroup() {}
|
||||
|
||||
void reset();
|
||||
|
||||
void load(const Common::Path &path, rapidxml::xml_node<char> *node);
|
||||
void draw(MapLayer &layer, const Rect &camera, const Vector2i &tileSize, const Rect &playerPos, pyrodactyl::image::Image &img);
|
||||
void preDraw(MapLayer &layer, const Vector2i &tileSize, Graphics::ManagedSurface *surf);
|
||||
void forceDraw(MapLayer &layer, const Rect &camera, const Vector2i &tileSize, const Rect &playerPos);
|
||||
};
|
||||
} // End of namespace TMX
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_TMXTILESET_H
|
||||
100
engines/crab/TMX/TileInfo.h
Normal file
100
engines/crab/TMX/TileInfo.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/* 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_TILEINFO_H
|
||||
#define CRAB_TILEINFO_H
|
||||
|
||||
#include "crab/loaders.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace TMX {
|
||||
typedef uint GidFormat;
|
||||
|
||||
// Bits on the far end of the 32-bit global tile ID are used for tile flags
|
||||
const static GidFormat FlippedHorizontallyFlag = 0x80000000;
|
||||
const static GidFormat FlippedVerticallyFlag = 0x40000000;
|
||||
const static GidFormat FlippedAntiDiagonallyFlag = 0x20000000;
|
||||
|
||||
struct TileInfo {
|
||||
// The gid of the tile
|
||||
GidFormat _gid;
|
||||
|
||||
// Do we need to flip this tile?
|
||||
TextureFlipType _flip;
|
||||
|
||||
TileInfo() {
|
||||
_gid = 0;
|
||||
_flip = FLIP_NONE;
|
||||
}
|
||||
|
||||
TileInfo(rapidxml::xml_node<char> *node) {
|
||||
// Load the gid of the tile
|
||||
if (!loadNum(_gid, "gid", node))
|
||||
_gid = 0;
|
||||
|
||||
bool horizontal = (_gid & FlippedHorizontallyFlag) != 0;
|
||||
bool vertical = (_gid & FlippedVerticallyFlag) != 0;
|
||||
bool antidiagonal = (_gid & FlippedAntiDiagonallyFlag) != 0;
|
||||
|
||||
// Find how the tile is flipped
|
||||
if (horizontal) {
|
||||
if (vertical) {
|
||||
if (antidiagonal)
|
||||
_flip = FLIP_XYD;
|
||||
else
|
||||
_flip = FLIP_XY;
|
||||
} else if (antidiagonal)
|
||||
_flip = FLIP_DX;
|
||||
else
|
||||
_flip = FLIP_X;
|
||||
} else if (vertical) {
|
||||
if (antidiagonal)
|
||||
_flip = FLIP_DY;
|
||||
else
|
||||
_flip = FLIP_Y;
|
||||
} else if (antidiagonal)
|
||||
_flip = FLIP_D;
|
||||
else
|
||||
_flip = FLIP_NONE;
|
||||
|
||||
// Clear the flags
|
||||
_gid &= ~(FlippedHorizontallyFlag | FlippedVerticallyFlag | FlippedAntiDiagonallyFlag);
|
||||
}
|
||||
|
||||
bool operator==(const TileInfo& other) const {
|
||||
return (_gid == other._gid) && (_flip == other._flip);
|
||||
}
|
||||
};
|
||||
} // End of namespace TMX
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_TILEINFO_H
|
||||
47
engines/crab/TTSHandler.cpp
Normal file
47
engines/crab/TTSHandler.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crab/TTSHandler.h"
|
||||
#include "common/system.h"
|
||||
|
||||
namespace Crab {
|
||||
void TTSHandler::onEntry(const Common::String &dialog) const {
|
||||
Common::TextToSpeechManager *_ttsMan = g_system->getTextToSpeechManager();
|
||||
|
||||
if (_ttsMan) {
|
||||
_ttsMan->enable(true);
|
||||
_ttsMan->setPitch(50);
|
||||
_ttsMan->setVolume(100);
|
||||
_ttsMan->setRate(20);
|
||||
_ttsMan->setVoice(1);
|
||||
_ttsMan->say(dialog);
|
||||
}
|
||||
}
|
||||
|
||||
void TTSHandler::onExit() const {
|
||||
Common::TextToSpeechManager *_ttsMan = g_system->getTextToSpeechManager();
|
||||
|
||||
if(_ttsMan) {
|
||||
_ttsMan->stop();
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
37
engines/crab/TTSHandler.h
Normal file
37
engines/crab/TTSHandler.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRAB_TTSHANDLER_H
|
||||
#define CRAB_TTSHANDLER_H
|
||||
|
||||
#include "common/text-to-speech.h"
|
||||
|
||||
namespace Crab {
|
||||
class TTSHandler {
|
||||
public:
|
||||
void onEntry(const Common::String &dialog) const;
|
||||
|
||||
void onExit() const;
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_TTSHANDLER_H
|
||||
56
engines/crab/XMLDoc.cpp
Normal file
56
engines/crab/XMLDoc.cpp
Normal 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/XMLDoc.h"
|
||||
|
||||
namespace rapidxml {
|
||||
void parse_error_handler(char const* what, void* where) {
|
||||
warning("RapidXML error handler: %s", what);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Crab {
|
||||
|
||||
void XMLDoc::load(const Common::Path &filename) {
|
||||
if (ready())
|
||||
_doc.clear();
|
||||
|
||||
if (fileOpen(filename, _text) && _text)
|
||||
_doc.parse<0>(_text);
|
||||
}
|
||||
|
||||
const rapidxml::xml_document<> *XMLDoc::doc() const {
|
||||
if (_text != nullptr)
|
||||
return &_doc;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
76
engines/crab/XMLDoc.h
Normal file
76
engines/crab/XMLDoc.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* 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_XMLDOC_H
|
||||
#define CRAB_XMLDOC_H
|
||||
|
||||
#include "crab/filesystem.h"
|
||||
#include "crab/rapidxml/rapidxml.hpp"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
class XMLDoc {
|
||||
rapidxml::xml_document<char> _doc;
|
||||
char *_text;
|
||||
|
||||
public:
|
||||
XMLDoc() {
|
||||
_text = nullptr;
|
||||
}
|
||||
|
||||
XMLDoc(const Common::Path &filename) {
|
||||
_text = nullptr;
|
||||
load(filename);
|
||||
}
|
||||
|
||||
XMLDoc(uint8 *data) {
|
||||
_text = (char*)data;
|
||||
_doc.parse<0>(_text);
|
||||
}
|
||||
|
||||
~XMLDoc() {
|
||||
delete[] _text;
|
||||
}
|
||||
|
||||
// Load the text from the specified file into the rapidxml format
|
||||
// Each function that references it must parse it there
|
||||
void load(const Common::Path &filename);
|
||||
|
||||
// Check if document is ready for parsing
|
||||
bool ready() const {
|
||||
return _text != nullptr;
|
||||
}
|
||||
|
||||
const rapidxml::xml_document<> *doc() const;
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_XMLDOC_H
|
||||
72
engines/crab/ai/SpriteConstant.cpp
Normal file
72
engines/crab/ai/SpriteConstant.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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/ai/SpriteConstant.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::ai;
|
||||
|
||||
FlyerConstant::FlyerConstant() : _start(10, 40), _vel(8.0f, 0.0f) {
|
||||
_delayMin = 5000;
|
||||
_delayMax = 20000;
|
||||
}
|
||||
|
||||
void FlyerConstant::load(rapidxml::xml_node<char> *node) {
|
||||
if (nodeValid("start", node))
|
||||
_start.load(node->first_node("start"));
|
||||
|
||||
if (nodeValid("vel", node))
|
||||
_vel.load(node->first_node("vel"));
|
||||
|
||||
if (nodeValid("delay", node)) {
|
||||
auto n = node->first_node("delay");
|
||||
loadNum(_delayMin, "min", n);
|
||||
loadNum(_delayMax, "max", n);
|
||||
}
|
||||
}
|
||||
|
||||
SpriteConstant::SpriteConstant() : _walkVelMod(0.9f, 0.63f) {
|
||||
_planeW = 20;
|
||||
_tweening = 0.2f;
|
||||
}
|
||||
|
||||
void SpriteConstant::load(rapidxml::xml_node<char> *node) {
|
||||
loadNum(_planeW, "plane_width", node);
|
||||
loadNum(_tweening, "tweening", node);
|
||||
|
||||
if (nodeValid("_walkVelMod", node))
|
||||
_walkVelMod.load(node->first_node("_walkVelMod"));
|
||||
|
||||
if (nodeValid("fly", node))
|
||||
_fly.load(node->first_node("fly"));
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
79
engines/crab/ai/SpriteConstant.h
Normal file
79
engines/crab/ai/SpriteConstant.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* 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_SPRITECONSTANT_H
|
||||
#define CRAB_SPRITECONSTANT_H
|
||||
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace ai {
|
||||
// These parameters control aspects of sprites flying across the screen
|
||||
struct FlyerConstant {
|
||||
// How far does a flier sprite start from the camera (an offset, not the whole value)
|
||||
Vector2i _start;
|
||||
|
||||
// The value of the delay for fliers
|
||||
uint32 _delayMin, _delayMax;
|
||||
|
||||
// The velocity of fliers
|
||||
Vector2f _vel;
|
||||
|
||||
FlyerConstant();
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
|
||||
// These values are used in various sprite related tasks
|
||||
struct SpriteConstant {
|
||||
// Plane width decides the maximum difference in sprite Y values that is considered on the same plane
|
||||
int _planeW;
|
||||
|
||||
// Tweening constant controls the acceleration curve of every sprite
|
||||
float _tweening;
|
||||
|
||||
// The modifiers of x and y movement speeds
|
||||
Vector2f _walkVelMod;
|
||||
|
||||
// Data for flying sprites
|
||||
FlyerConstant _fly;
|
||||
|
||||
SpriteConstant();
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
} // End of namespace ai
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_SPRITECONSTANT_H
|
||||
66
engines/crab/ai/moveeffect.cpp
Normal file
66
engines/crab/ai/moveeffect.cpp
Normal 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/ai/moveeffect.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::anim;
|
||||
|
||||
FightMoveEffect::FightMoveEffect() {
|
||||
_activate = -1;
|
||||
_hit = -1;
|
||||
_dmg = 0;
|
||||
_stun = 0;
|
||||
_hurt = -1;
|
||||
_death = -1;
|
||||
}
|
||||
|
||||
void FightMoveEffect::load(rapidxml::xml_node<char> *node) {
|
||||
loadNum(_stun, "stun", node);
|
||||
loadNum(_dmg, "damage", node);
|
||||
loadNum(_hurt, "hurt", node);
|
||||
loadNum(_death, "death", node);
|
||||
|
||||
if (nodeValid("image", node, false))
|
||||
_img.load(node->first_node("image"));
|
||||
|
||||
if (nodeValid("sound", node)) {
|
||||
rapidxml::xml_node<char> *soundnode = node->first_node("sound");
|
||||
|
||||
if (!loadNum(_activate, "activate", soundnode, false))
|
||||
_activate = -1;
|
||||
|
||||
if (!loadNum(_activate, "hit", soundnode, false))
|
||||
_activate = -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
72
engines/crab/ai/moveeffect.h
Normal file
72
engines/crab/ai/moveeffect.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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_MOVEEFFECT_H
|
||||
#define CRAB_MOVEEFFECT_H
|
||||
|
||||
#include "crab/animation/imageeffect.h"
|
||||
#include "crab/music/musicparam.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace anim {
|
||||
struct FightMoveEffect {
|
||||
// The image displayed on being hit
|
||||
ImageEffect _img;
|
||||
|
||||
// The sound played by this move when it's activated
|
||||
pyrodactyl::music::ChunkKey _activate;
|
||||
|
||||
// The sound played by this move when it hits opponent
|
||||
pyrodactyl::music::ChunkKey _hit;
|
||||
|
||||
// The move the sprite hit by our current move performs - if living (hurt animation)
|
||||
int _hurt;
|
||||
|
||||
// The move the sprite hit by our current move performs - if it dies as a result (dying animation)
|
||||
int _death;
|
||||
|
||||
// The stun time for the enemy if this move hits a sprite
|
||||
uint _stun;
|
||||
|
||||
// The base damage of the move if it hits a sprite
|
||||
int _dmg;
|
||||
|
||||
FightMoveEffect();
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
} // End of namespace anim
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_MOVEEFFECT_H
|
||||
66
engines/crab/ai/movement.cpp
Normal file
66
engines/crab/ai/movement.cpp
Normal 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/ai/movement.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::ai;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Walk in preset paths
|
||||
//------------------------------------------------------------------------
|
||||
void MovementSet::load(rapidxml::xml_node<char> *node) {
|
||||
_enabled = true;
|
||||
loadBool(_repeat, "repeat", node);
|
||||
for (auto n = node->first_node("walk"); n != nullptr; n = n->next_sibling("walk"))
|
||||
_path.push_back(n);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: To make the AI patrol/wait along certain points
|
||||
//------------------------------------------------------------------------
|
||||
bool MovementSet::internalEvents(const Rect rect) {
|
||||
if (_enabled) {
|
||||
// If we are at the current waypoint, get to the next waypoint
|
||||
if (_path[_cur]._target.collide(rect)) {
|
||||
_cur = (_cur + 1) % _path.size();
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
// Wait according to the delay value in the node
|
||||
if (_timer.ticks() >= _path[_cur]._delay)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
92
engines/crab/ai/movement.h
Normal file
92
engines/crab/ai/movement.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/* 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_MOVEMENT_H
|
||||
#define CRAB_MOVEMENT_H
|
||||
|
||||
#include "crab/Rectangle.h"
|
||||
#include "crab/timer.h"
|
||||
#include "crab/vectors.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace ai {
|
||||
struct MovementSet {
|
||||
struct Movement {
|
||||
// The position this sprite has to move to
|
||||
Rect _target;
|
||||
|
||||
// The time the sprite waits before it starts moving to pos
|
||||
uint32 _delay;
|
||||
|
||||
Movement(rapidxml::xml_node<char> *node) {
|
||||
_target.load(node);
|
||||
_delay = 0;
|
||||
loadNum(_delay, "delay", node);
|
||||
}
|
||||
};
|
||||
|
||||
// The path followed by the sprite
|
||||
Common::Array<Movement> _path;
|
||||
|
||||
// If true, sprite repeats the path pattern after reaching the last co-ordinate
|
||||
bool _repeat;
|
||||
|
||||
// The current path node we are traveling to
|
||||
uint _cur;
|
||||
|
||||
// The time the sprite has spent waiting is calculated here
|
||||
Timer _timer;
|
||||
|
||||
// Is this set enabled?
|
||||
bool _enabled;
|
||||
|
||||
MovementSet() {
|
||||
_cur = 0;
|
||||
_repeat = false;
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
MovementSet(rapidxml::xml_node<char> *node) : MovementSet() {
|
||||
load(node);
|
||||
}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
|
||||
bool internalEvents(const Rect rect);
|
||||
Rect target() { return _path[_cur]._target; }
|
||||
};
|
||||
} // End of namespace ai
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_MOVEMENT_H
|
||||
315
engines/crab/ai/spriteai.cpp
Normal file
315
engines/crab/ai/spriteai.cpp
Normal file
@@ -0,0 +1,315 @@
|
||||
/* 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/ScreenSettings.h"
|
||||
#include "crab/animation/sprite.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::anim;
|
||||
using namespace pyrodactyl::ai;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Calculate distance between two sprites
|
||||
//------------------------------------------------------------------------
|
||||
double Sprite::distSq(const Sprite &s) {
|
||||
double result = (_pos.x - s._pos.x) * (_pos.x - s._pos.x) + (_pos.y - s._pos.y) * (_pos.y - s._pos.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Used for player movement
|
||||
//------------------------------------------------------------------------
|
||||
void Sprite::moveToDest(pyrodactyl::event::Info &info, const SpriteConstant &sc) {
|
||||
if (_aiData._dest._active) {
|
||||
int num = 0;
|
||||
info.statGet(_id, pyrodactyl::stat::STAT_SPEED, num);
|
||||
++num;
|
||||
float playerSpeed = static_cast<float>(num);
|
||||
|
||||
if (moveToLoc(_aiData._dest, playerSpeed, sc)) {
|
||||
_aiData._dest._active = false;
|
||||
xVel(0.0f);
|
||||
yVel(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::moveToDestPathfinding(pyrodactyl::event::Info &info, const SpriteConstant &sc) {
|
||||
if (_aiData._dest._active) {
|
||||
int num = 0;
|
||||
info.statGet(_id, pyrodactyl::stat::STAT_SPEED, num);
|
||||
++num;
|
||||
float playerSpeed = static_cast<float>(num);
|
||||
|
||||
Rect b = boundRect();
|
||||
|
||||
// Use to provide a bit of leeway with reaching the goal.
|
||||
_pathing.setNodeBufferDistance((b.w * b.w) / 2.0f);
|
||||
|
||||
// IF we either have a solution, have reached our destination, and it was our final destination OR
|
||||
// IF there is no solution OR
|
||||
// IF we haven't yet found a solution
|
||||
// THEN stop.
|
||||
if ((moveToLocPathfinding(_aiData._dest, playerSpeed, sc) && _pathing._solutionFound &&
|
||||
_pathing.getImmediateDest() == Vector2i(_pathing._destination.x, _pathing._destination.y)) ||
|
||||
_pathing._noSolution || !_pathing._solutionFound) {
|
||||
_aiData._dest._active = false;
|
||||
xVel(0.0f);
|
||||
yVel(0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Move towards a location without any path finding
|
||||
//------------------------------------------------------------------------
|
||||
bool Sprite::moveToLoc(Vector2i &dest, const float &velocity, const SpriteConstant &sc) {
|
||||
// Use the bound rectangle dimensions
|
||||
Rect b = boundRect();
|
||||
|
||||
// X axis
|
||||
if (b.x + b.w < dest.x)
|
||||
xVel(velocity * sc._walkVelMod.x);
|
||||
else if (b.x > dest.x)
|
||||
xVel(-velocity * sc._walkVelMod.x);
|
||||
else
|
||||
xVel(0.0f);
|
||||
|
||||
// Y axis
|
||||
if (b.y + b.h < dest.y)
|
||||
yVel(velocity * sc._walkVelMod.y);
|
||||
else if (b.y > dest.y)
|
||||
yVel(-velocity * sc._walkVelMod.y);
|
||||
else
|
||||
yVel(0.0f);
|
||||
|
||||
return b.contains(dest);
|
||||
}
|
||||
|
||||
// Move toward the location using pathfinding.
|
||||
bool Sprite::moveToLocPathfinding(Vector2i &dest, const float &velocity, const SpriteConstant &sc) {
|
||||
// Rect b = BoundRect();
|
||||
|
||||
Vector2i immediateDest = _pathing.getImmediateDest();
|
||||
|
||||
Vector2f vecTo = Vector2f((float)immediateDest.x, (float)immediateDest.y) - _pathing.getPosition();
|
||||
|
||||
// If the destination is not the pathing goal, we must reach it exactly before moving on.
|
||||
if (immediateDest != Vector2i(_pathing._destination.x, _pathing._destination.y)) {
|
||||
Timer fps;
|
||||
float deltaTime = 1.0f / (float)g_engine->_screenSettings->_fps;
|
||||
|
||||
// Project how far we will travel next frame.
|
||||
Vector2f velVec = Vector2f(sc._walkVelMod.x * velocity * deltaTime, sc._walkVelMod.y * velocity * deltaTime);
|
||||
|
||||
if (vecTo.magnitude() > velVec.magnitude()) {
|
||||
vecTo.normalize();
|
||||
|
||||
xVel(vecTo.x * sc._walkVelMod.x * velocity);
|
||||
yVel(vecTo.y * sc._walkVelMod.y * velocity);
|
||||
} else {
|
||||
xVel(0.0f);
|
||||
yVel(0.0f);
|
||||
}
|
||||
} else {
|
||||
Vector2i loc = _pathing.getImmediateDest();
|
||||
moveToLoc(loc, velocity, sc);
|
||||
}
|
||||
|
||||
// return(MoveToLoc(pathing.GetImmediateDest(), vel, sc) || (xVel() == 0.0f && yVel() == 0.0f));
|
||||
|
||||
return (xVel() == 0.0f && yVel() == 0.0f);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: AI routine for running to the nearest exit, then disappearing
|
||||
//------------------------------------------------------------------------
|
||||
void Sprite::flee(pyrodactyl::event::Info &info, Common::Array<pyrodactyl::level::Exit> &areaExit, const SpriteConstant &sc) {
|
||||
switch (_aiData._flee._state) {
|
||||
case FLEESTATE_GETNEARESTEXIT: {
|
||||
if (areaExit.empty()) {
|
||||
// No valid exits in the level
|
||||
_aiData._flee._state = FLEESTATE_CANTFLEE;
|
||||
break;
|
||||
} else {
|
||||
_aiData._flee._state = FLEESTATE_GETNEARESTEXIT;
|
||||
|
||||
// Standard way to find nearest exit
|
||||
int min_dist = INT_MAX;
|
||||
|
||||
// Find the nearest exit
|
||||
for (auto &i : areaExit) {
|
||||
// Compare distance to the rough center of each exit
|
||||
int dist = distance2D(_pos.x, _pos.y, i._dim._rect.x + i._dim._rect.w / 2, i._dim._rect.y + i._dim._rect.h / 2);
|
||||
if (dist < min_dist) {
|
||||
min_dist = dist;
|
||||
|
||||
// Set the destination of sprite to this exit
|
||||
_aiData.dest(i._dim._rect.x + i._dim._rect.w / 2, i._dim._rect.y + i._dim._rect.h / 2);
|
||||
|
||||
_pathing.setDestination(Vector2f((float)_aiData._dest.x, (float)_aiData._dest.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case FLEESTATE_RUNTOEXIT: {
|
||||
Rect b = boundRect();
|
||||
if (b.contains(_aiData._dest)) {
|
||||
// We have reached the exit, time to make the sprite disappear
|
||||
_aiData._flee._state = FLEESTATE_DISAPPEAR;
|
||||
break;
|
||||
} else {
|
||||
int num = 0;
|
||||
info.statGet(_id, pyrodactyl::stat::STAT_SPEED, num);
|
||||
++num;
|
||||
float velocity = static_cast<float>(num);
|
||||
|
||||
// MoveToLoc(_aiData.dest, vel, sc);
|
||||
moveToLocPathfinding(_aiData._dest, velocity, sc);
|
||||
}
|
||||
} break;
|
||||
case FLEESTATE_DISAPPEAR:
|
||||
_visible.result(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: AI routine for fighting the player
|
||||
//------------------------------------------------------------------------
|
||||
void Sprite::attack(pyrodactyl::event::Info &info, Sprite &targetSp, const SpriteConstant &sc) {
|
||||
switch (_aiData._fight._state) {
|
||||
case FIGHTSTATE_GETNEXTMOVE: {
|
||||
_aiData._fight._state = FIGHTSTATE_GETINRANGE;
|
||||
_aiData._fight._delay.start();
|
||||
|
||||
uint size = _aiData._fight._attack.size();
|
||||
if (size > 1)
|
||||
_animSet._fight.next(_aiData._fight._attack[g_engine->getRandomNumber(_aiData._fight._attack.size())]);
|
||||
else if (size <= 0)
|
||||
_aiData._fight._state = FIGHTSTATE_CANTFIGHT;
|
||||
else
|
||||
_animSet._fight.next(_aiData._fight._attack[0]);
|
||||
}
|
||||
break;
|
||||
case FIGHTSTATE_GETINRANGE: {
|
||||
// Set destination path to the player location
|
||||
Rect b = targetSp.boundRect();
|
||||
Vector2i dest(b.x + b.w / 2, b.y + b.h / 2);
|
||||
setDestPathfinding(dest);
|
||||
|
||||
Rect p = boundRect();
|
||||
_pathing.setPosition(Vector2f((float)(p.x + p.w / 2), (float)p.y + p.h / 2));
|
||||
_pathing.update(0);
|
||||
|
||||
FightMove f;
|
||||
if (_animSet._fight.nextMove(f) && fightCollide(targetSp.boxV(), targetSp.boundRect(), f._ai._range, sc)) {
|
||||
if (_aiData._fight._delay.ticks() > f._ai._delay)
|
||||
_aiData._fight._state = FIGHTSTATE_EXECUTEMOVE;
|
||||
} else if (_input.idle())
|
||||
moveToDestPathfinding(info, sc);
|
||||
}
|
||||
break;
|
||||
case FIGHTSTATE_EXECUTEMOVE:
|
||||
updateMove(_animSet._fight.next());
|
||||
_aiData._fight._state = FIGHTSTATE_GETNEXTMOVE;
|
||||
_aiData._fight._delay.stop();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::flyAround(const Rect &camera, const SpriteConstant &sc) {
|
||||
// Is this sprite flying right now?
|
||||
if (_aiData._walk._enabled) {
|
||||
// We're flying towards the left edge
|
||||
if (xVel() < 0) {
|
||||
// Are we completely out of the left edge of the camera?
|
||||
if (x() < camera.x - w()) {
|
||||
_aiData._walk._enabled = false;
|
||||
|
||||
// Start the timer, set a semi-random time
|
||||
_aiData._walk._timer.target(sc._fly._delayMin + (g_engine->getRandomNumber(sc._fly._delayMax)));
|
||||
_aiData._walk._timer.start();
|
||||
}
|
||||
} else if (xVel() > 0) { // Flying towards the right edge
|
||||
// Are we completely out of the left edge of the camera?
|
||||
if (x() > camera.x + camera.w + w()) {
|
||||
_aiData._walk._enabled = false;
|
||||
|
||||
// Start the timer, set a semi-random time
|
||||
_aiData._walk._timer.target(sc._fly._delayMin + (g_engine->getRandomNumber(sc._fly._delayMax)));
|
||||
_aiData._walk._timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
move(sc);
|
||||
} else {
|
||||
// Safety condition in case timer isn't running
|
||||
if (!_aiData._walk._timer.started())
|
||||
_aiData._walk._timer.start();
|
||||
|
||||
// Is it time to start flying?
|
||||
if (_aiData._walk._timer.targetReached()) {
|
||||
// Stop the timer
|
||||
_aiData._walk._timer.stop();
|
||||
|
||||
// Decide if the sprite flies from the left or right of the camera
|
||||
if (g_engine->getRandomNumber(1)) {
|
||||
// Fly in from the right
|
||||
x(camera.x + camera.w + sc._fly._start.x);
|
||||
xVel(-1.0f * sc._fly._vel.x);
|
||||
|
||||
// Sprite needs to face left
|
||||
_dir = DIRECTION_LEFT;
|
||||
} else {
|
||||
// Fly in from the left
|
||||
x(camera.x - w() - sc._fly._start.x);
|
||||
xVel(sc._fly._vel.x);
|
||||
|
||||
// Sprite needs to face right
|
||||
_dir = DIRECTION_RIGHT;
|
||||
}
|
||||
|
||||
y(camera.y + sc._fly._start.y + (g_engine->getRandomNumber(camera.h - (2 * sc._fly._start.y))));
|
||||
yVel(sc._fly._vel.y);
|
||||
|
||||
// Set state to flying
|
||||
_aiData._walk._enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
118
engines/crab/ai/spriteai.h
Normal file
118
engines/crab/ai/spriteai.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/* 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_SPRITEAI_H
|
||||
#define CRAB_SPRITEAI_H
|
||||
|
||||
#include "crab/ai/movement.h"
|
||||
#include "crab/PathfindingAgent.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// class PathfindingAgent;
|
||||
namespace pyrodactyl {
|
||||
namespace ai {
|
||||
|
||||
// States of a fighting sprite
|
||||
enum AIFightState {
|
||||
FIGHTSTATE_GETNEXTMOVE,
|
||||
FIGHTSTATE_GETINRANGE,
|
||||
FIGHTSTATE_EXECUTEMOVE,
|
||||
FIGHTSTATE_CANTFIGHT
|
||||
};
|
||||
|
||||
// States of a fleeing sprite
|
||||
enum AIFleeState {
|
||||
FLEESTATE_GETNEARESTEXIT,
|
||||
FLEESTATE_RUNTOEXIT,
|
||||
FLEESTATE_DISAPPEAR,
|
||||
FLEESTATE_CANTFLEE
|
||||
};
|
||||
|
||||
struct SpriteAIData {
|
||||
// Data required for fighting
|
||||
struct FightData {
|
||||
// The state of the sprite
|
||||
AIFightState _state;
|
||||
|
||||
// Used to count down the time NPCs wait before their next move
|
||||
// Usually varies per move which is why we don't load target for it
|
||||
Timer _delay;
|
||||
|
||||
// The list of moves that can be performed while attacking
|
||||
Common::Array<uint> _attack;
|
||||
|
||||
FightData() {
|
||||
_state = FIGHTSTATE_GETNEXTMOVE;
|
||||
}
|
||||
} _fight;
|
||||
|
||||
// The pattern a peaceful sprite walks in
|
||||
MovementSet _walk;
|
||||
|
||||
// Data required to flee
|
||||
struct FleeData {
|
||||
AIFleeState _state;
|
||||
|
||||
FleeData() {
|
||||
_state = FLEESTATE_GETNEARESTEXIT;
|
||||
}
|
||||
} _flee;
|
||||
|
||||
// The next location the sprite has to reach
|
||||
// PLAYER: Used for adventure game style point-n-click movement
|
||||
// AI: Used for path-finding (usually to the player's location)
|
||||
struct Destination : public Vector2i {
|
||||
// Are we trying to reach the destination?
|
||||
bool _active;
|
||||
|
||||
Destination() {
|
||||
_active = false;
|
||||
}
|
||||
} _dest;
|
||||
|
||||
SpriteAIData() {}
|
||||
|
||||
void dest(const int &x, const int &y, const bool &active = true) {
|
||||
_dest.x = x;
|
||||
_dest.y = y;
|
||||
_dest._active = active;
|
||||
}
|
||||
|
||||
void dest(const Vector2i &v, const bool &active = true) {
|
||||
dest(v.x, v.y, active);
|
||||
}
|
||||
};
|
||||
} // End of namespace ai
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_SPRITEAI_H
|
||||
102
engines/crab/animation/AnimationEffect.h
Normal file
102
engines/crab/animation/AnimationEffect.h
Normal 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
|
||||
106
engines/crab/animation/AnimationFrame.cpp
Normal file
106
engines/crab/animation/AnimationFrame.cpp
Normal 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 ×tamp) {
|
||||
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 ×tamp) {
|
||||
|
||||
// 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
|
||||
81
engines/crab/animation/AnimationFrame.h
Normal file
81
engines/crab/animation/AnimationFrame.h
Normal 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 ×tamp);
|
||||
DrawType internalEvents(const uint32 ×tamp);
|
||||
};
|
||||
} // End of namespace anim
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_ANIMATIONFRAME_H
|
||||
133
engines/crab/animation/PopUp.cpp
Normal file
133
engines/crab/animation/PopUp.cpp
Normal 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
|
||||
127
engines/crab/animation/PopUp.h
Normal file
127
engines/crab/animation/PopUp.h
Normal 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
|
||||
66
engines/crab/animation/animation.cpp
Normal file
66
engines/crab/animation/animation.cpp
Normal 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
|
||||
73
engines/crab/animation/animation.h
Normal file
73
engines/crab/animation/animation.h
Normal 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
|
||||
109
engines/crab/animation/animframe.cpp
Normal file
109
engines/crab/animation/animframe.cpp
Normal 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
|
||||
113
engines/crab/animation/animframe.h
Normal file
113
engines/crab/animation/animframe.h
Normal 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 ¤tFrame();
|
||||
};
|
||||
} // End of namespace anim
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_ANIMFRAME_H
|
||||
89
engines/crab/animation/animset.cpp
Normal file
89
engines/crab/animation/animset.cpp
Normal 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
|
||||
74
engines/crab/animation/animset.h
Normal file
74
engines/crab/animation/animset.h
Normal 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
|
||||
86
engines/crab/animation/fightanim.cpp
Normal file
86
engines/crab/animation/fightanim.cpp
Normal 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
|
||||
110
engines/crab/animation/fightanim.h
Normal file
110
engines/crab/animation/fightanim.h
Normal 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
|
||||
56
engines/crab/animation/fightmove.cpp
Normal file
56
engines/crab/animation/fightmove.cpp
Normal 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
|
||||
67
engines/crab/animation/fightmove.h
Normal file
67
engines/crab/animation/fightmove.h
Normal 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
|
||||
201
engines/crab/animation/fightmoves.cpp
Normal file
201
engines/crab/animation/fightmoves.cpp
Normal 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
|
||||
133
engines/crab/animation/fightmoves.h
Normal file
133
engines/crab/animation/fightmoves.h
Normal 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
|
||||
82
engines/crab/animation/fm_ai_data.h
Normal file
82
engines/crab/animation/fm_ai_data.h
Normal 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
|
||||
51
engines/crab/animation/imageeffect.cpp
Normal file
51
engines/crab/animation/imageeffect.cpp
Normal 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
|
||||
57
engines/crab/animation/imageeffect.h
Normal file
57
engines/crab/animation/imageeffect.h
Normal 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
|
||||
65
engines/crab/animation/range.h
Normal file
65
engines/crab/animation/range.h
Normal 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
|
||||
83
engines/crab/animation/shadow.h
Normal file
83
engines/crab/animation/shadow.h
Normal 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
|
||||
668
engines/crab/animation/sprite.cpp
Normal file
668
engines/crab/animation/sprite.cpp
Normal 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
|
||||
295
engines/crab/animation/sprite.h
Normal file
295
engines/crab/animation/sprite.h
Normal 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
|
||||
155
engines/crab/animation/walkframes.cpp
Normal file
155
engines/crab/animation/walkframes.cpp
Normal 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
|
||||
130
engines/crab/animation/walkframes.h
Normal file
130
engines/crab/animation/walkframes.h
Normal 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
|
||||
201
engines/crab/app.cpp
Normal file
201
engines/crab/app.cpp
Normal 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/app.h"
|
||||
#include "common/events.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "crab/crab.h"
|
||||
#include "crab/game.h"
|
||||
#include "crab/mainmenu.h"
|
||||
#include "crab/splash.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
void App::run() {
|
||||
// State IDs
|
||||
GameStateID currentStateId = GAMESTATE_NULL, nextStateId = GAMESTATE_TITLE;
|
||||
bool shouldChangeState = true;
|
||||
|
||||
// Set the current game state object
|
||||
GameState *currentState = nullptr;
|
||||
Timer fps;
|
||||
Common::Event e;
|
||||
int fpscount = 0, fpsval = 1, lasts = 0;
|
||||
|
||||
_game = new Game();
|
||||
|
||||
g_engine->_filePath->load("res/paths.xml");
|
||||
|
||||
loadSettings("res/settings.xml");
|
||||
g_engine->_screenSettings->_inGame = false;
|
||||
|
||||
// While the user hasn't quit - This is the main game loop
|
||||
while (currentStateId != GAMESTATE_EXIT && !g_engine->shouldQuit()) {
|
||||
// Start the frame timer
|
||||
fps.start();
|
||||
|
||||
// Change state if needed
|
||||
if (shouldChangeState) {
|
||||
// Delete the current state
|
||||
if (currentState != _game) {
|
||||
delete currentState;
|
||||
currentState = nullptr;
|
||||
}
|
||||
|
||||
if (nextStateId == GAMESTATE_EXIT)
|
||||
break;
|
||||
|
||||
// Change the state
|
||||
switch (nextStateId) {
|
||||
case GAMESTATE_TITLE:
|
||||
currentState = new Splash();
|
||||
g_engine->_screenSettings->_inGame = false;
|
||||
break;
|
||||
|
||||
case GAMESTATE_MAIN_MENU:
|
||||
currentState = new MainMenu();
|
||||
g_engine->_screenSettings->_inGame = false;
|
||||
break;
|
||||
|
||||
case GAMESTATE_NEW_GAME:
|
||||
_game->startNewGame();
|
||||
currentState = _game;
|
||||
g_engine->_screenSettings->_inGame = true;
|
||||
break;
|
||||
|
||||
case GAMESTATE_LOAD_GAME:
|
||||
currentState = _game;
|
||||
g_engine->_screenSettings->_inGame = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Encountering an undefined state, exit with an error code
|
||||
return;
|
||||
}
|
||||
|
||||
// Change the current state ID
|
||||
currentStateId = nextStateId;
|
||||
|
||||
// NULL the next state ID
|
||||
nextStateId = GAMESTATE_NULL;
|
||||
|
||||
// No need to change state until further notice
|
||||
shouldChangeState = false;
|
||||
}
|
||||
|
||||
// Do state InternalEvents
|
||||
currentState->internalEvents(shouldChangeState, nextStateId);
|
||||
|
||||
while (g_system->getEventManager()->pollEvent(e)) {
|
||||
|
||||
switch (e.type) {
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
g_engine->_inputManager->_ivState[e.customType] = true;
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
|
||||
g_engine->_inputManager->_ivState[e.customType] = false;
|
||||
break;
|
||||
|
||||
// explicitly specify the default block to turn off unhandled case warnings
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Do state Event handling
|
||||
currentState->handleEvents(e, shouldChangeState, nextStateId);
|
||||
}
|
||||
|
||||
|
||||
// Do we have to reposition our interface?
|
||||
if (g_engine->_screenSettings->_changeInterface) {
|
||||
currentState->setUI();
|
||||
g_engine->_screenSettings->_changeInterface = false;
|
||||
}
|
||||
|
||||
// Do state Drawing
|
||||
currentState->draw();
|
||||
|
||||
if (g_system->getMillis() - lasts > 1000) {
|
||||
lasts = g_system->getMillis();
|
||||
fpsval = fpscount;
|
||||
fpscount = 1;
|
||||
} else
|
||||
++fpscount;
|
||||
|
||||
if ((g_engine->_debugDraw & DRAW_FPS) && currentStateId >= 0)
|
||||
g_engine->_textManager->draw(0, 0, numberToString(fpsval).c_str(), 0);
|
||||
|
||||
g_engine->_screen->update();
|
||||
|
||||
// Cap the frame rate
|
||||
if (fps.ticks() < 1000u / g_engine->_screenSettings->_fps) {
|
||||
uint32 delay = (1000u / g_engine->_screenSettings->_fps) - fps.ticks();
|
||||
g_system->delayMillis(delay);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentState != _game)
|
||||
delete currentState;
|
||||
delete _game;
|
||||
}
|
||||
|
||||
void App::loadSettings(const Common::Path &filename) {
|
||||
XMLDoc settings(filename);
|
||||
if (settings.ready()) {
|
||||
rapidxml::xml_node<char> *node = settings.doc()->first_node("settings");
|
||||
if (nodeValid(node)) {
|
||||
// Load the version
|
||||
loadNum(g_engine->_screenSettings->_version, "version", node);
|
||||
|
||||
// Load screen settings
|
||||
if (nodeValid("screen", node))
|
||||
g_engine->_screenSettings->load(node->first_node("screen"));
|
||||
|
||||
// Start the sound subsystem
|
||||
g_engine->_musicManager->load(node);
|
||||
|
||||
g_system->lockMouse(g_engine->_screenSettings->_mouseTrap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
App::~App() {
|
||||
// Return setting to default when game exits
|
||||
g_system->lockMouse(false);
|
||||
|
||||
g_engine->_imageManager->quit();
|
||||
g_engine->_musicManager->quit();
|
||||
g_engine->_textManager->quit();
|
||||
g_engine->_loadingScreen->quit();
|
||||
g_engine->_mouse->quit();
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
54
engines/crab/app.h
Normal file
54
engines/crab/app.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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_APP_H
|
||||
#define CRAB_APP_H
|
||||
|
||||
#include "common/path.h"
|
||||
|
||||
namespace Crab {
|
||||
class Game;
|
||||
|
||||
class App {
|
||||
private:
|
||||
Game *_game;
|
||||
void loadSettings(const Common::Path &filename);
|
||||
public:
|
||||
~App();
|
||||
|
||||
void run();
|
||||
Game *getGame() const {
|
||||
return _game;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_APP_H
|
||||
60
engines/crab/backInserter.h
Normal file
60
engines/crab/backInserter.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRAB_BACKINSERTER_H
|
||||
#define CRAB_BACKINSERTER_H
|
||||
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
template<class Container>
|
||||
class backInserterIterator {
|
||||
protected:
|
||||
Container *_container;
|
||||
|
||||
public:
|
||||
explicit backInserterIterator(Container &x) : _container(&x) {}
|
||||
|
||||
backInserterIterator &operator=(const typename Container::value_type &value) {
|
||||
*_container += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
backInserterIterator &operator=(const typename Container::value_type &&value) {
|
||||
*_container += Common::move(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
backInserterIterator &operator*() { return *this; }
|
||||
backInserterIterator &operator++() { return *this; }
|
||||
backInserterIterator &operator++(int) { return *this; }
|
||||
};
|
||||
|
||||
template<class Container>
|
||||
backInserterIterator<Container>
|
||||
backInserter(Container &x) {
|
||||
return backInserterIterator<Container>(x);
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif
|
||||
223
engines/crab/collision.cpp
Normal file
223
engines/crab/collision.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/* 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/collision.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// Find if a line and a rectangle intersect
|
||||
bool collideLineRect(int p0X, int p0Y, int p1X, int p1Y, const Rect &rect) {
|
||||
int q0_x = rect.x;
|
||||
int q0_y = rect.y;
|
||||
int q1_x = rect.x + rect.w;
|
||||
int q1_y = rect.y;
|
||||
|
||||
if (collideLine<int>(p0X, p0Y, p1X, p1Y, q0_x, q0_y, q1_x, q1_y))
|
||||
return true;
|
||||
|
||||
q0_x = rect.x;
|
||||
q0_y = rect.y;
|
||||
q1_x = rect.x;
|
||||
q1_y = rect.y + rect.h;
|
||||
|
||||
if (collideLine<int>(p0X, p0Y, p1X, p1Y, q0_x, q0_y, q1_x, q1_y))
|
||||
return true;
|
||||
|
||||
q0_x = rect.x + rect.w;
|
||||
q0_y = rect.y;
|
||||
q1_x = rect.x + rect.w;
|
||||
q1_y = rect.y + rect.h;
|
||||
|
||||
if (collideLine<int>(p0X, p0Y, p1X, p1Y, q0_x, q0_y, q1_x, q1_y))
|
||||
return true;
|
||||
|
||||
q0_x = rect.x;
|
||||
q0_y = rect.y + rect.h;
|
||||
q1_x = rect.x + rect.w;
|
||||
q1_y = rect.y + rect.h;
|
||||
|
||||
if (collideLine<int>(p0X, p0Y, p1X, p1Y, q0_x, q0_y, q1_x, q1_y))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find if there is a clear line of sight between two rectangles
|
||||
bool lineOfSight(const Rect &a, const Rect &b, const Rect &obstacle) {
|
||||
int p0_x = a.x;
|
||||
int p0_y = a.y;
|
||||
int p1_x = b.x;
|
||||
int p1_y = b.y;
|
||||
|
||||
if (collideLineRect(p0_x, p0_y, p1_x, p1_y, obstacle))
|
||||
return false;
|
||||
|
||||
p0_x = a.x + a.w;
|
||||
p0_y = a.y;
|
||||
p1_x = b.x + b.w;
|
||||
p1_y = b.y;
|
||||
|
||||
if (collideLineRect(p0_x, p0_y, p1_x, p1_y, obstacle))
|
||||
return false;
|
||||
|
||||
p0_x = a.x;
|
||||
p0_y = a.y + a.h;
|
||||
p1_x = b.x;
|
||||
p1_y = b.y + b.h;
|
||||
|
||||
if (collideLineRect(p0_x, p0_y, p1_x, p1_y, obstacle))
|
||||
return false;
|
||||
|
||||
p0_x = a.x + a.w;
|
||||
p0_y = a.y + a.h;
|
||||
p1_x = b.x + b.w;
|
||||
p1_y = b.y + b.h;
|
||||
|
||||
if (collideLineRect(p0_x, p0_y, p1_x, p1_y, obstacle))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// float IntervalDistance(float minA, float maxA, float minB, float maxB)
|
||||
//{
|
||||
// if (minA < minB)
|
||||
// return minB - maxA;
|
||||
//
|
||||
// return minA - maxB;
|
||||
// }
|
||||
//
|
||||
//// Calculate the projection of a polygon on an axis and returns it as a [min, max] interval
|
||||
// void ProjectPolygon(const Vector2i &axis, const Polygon2D &poly, float &min, float &max)
|
||||
//{
|
||||
// // To project a point on an axis use the dot product
|
||||
// float d = axis.DotProduct(poly.point[0]);
|
||||
// min = d;
|
||||
// max = d;
|
||||
//
|
||||
// for(auto i = poly.point.begin(); i != poly.point.end(); ++i)
|
||||
// {
|
||||
// d = i->DotProduct(axis);
|
||||
//
|
||||
// if (d < min) min = d;
|
||||
// else if (d > max) max = d;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// PolygonCollisionResult Collide(const Polygon2D &polyA, const Polygon2D &polyB, const Vector2i &velocity)
|
||||
//{
|
||||
// PolygonCollisionResult result;
|
||||
//
|
||||
// int edgeCountA = polyA.edge.size();
|
||||
// int edgeCountB = polyB.edge.size();
|
||||
// float minIntervalDistance = std::numeric_limits<float>::max();
|
||||
// Vector2i translationAxis;
|
||||
// Vector2i edge;
|
||||
//
|
||||
// // Loop through all the edges of both polygons
|
||||
// for(int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++)
|
||||
// {
|
||||
// if (edgeIndex < edgeCountA)
|
||||
// edge = polyA.edge[edgeIndex];
|
||||
// else
|
||||
// edge = polyB.edge[edgeIndex - edgeCountA];
|
||||
//
|
||||
// // ===== 1. Find if the Polygon2Ds are currently intersecting =====
|
||||
//
|
||||
// // Find the axis perpendicular to the current edge
|
||||
// Vector2i axis(-edge.y, edge.x);
|
||||
// axis.Normalize();
|
||||
//
|
||||
// // Find the projection of the Polygon2D on the current axis
|
||||
// float minA = 0; float minB = 0; float maxA = 0; float maxB = 0;
|
||||
// ProjectPolygon(axis, polyA, minA, maxA);
|
||||
// ProjectPolygon(axis, polyB, minB, maxB);
|
||||
//
|
||||
// // Check if the Polygon2D projections are currently intersecting
|
||||
// if (IntervalDistance(minA, maxA, minB, maxB) > 0)
|
||||
// result.intersect = false;
|
||||
//
|
||||
// // ===== 2. Now find if the Polygon2Ds *will* intersect =====
|
||||
//
|
||||
// // Project the velocity on the current axis
|
||||
// float velocityProjection = axis.DotProduct(velocity);
|
||||
//
|
||||
// // Get the projection of Polygon2D A during the movement
|
||||
// if (velocityProjection < 0)
|
||||
// minA += velocityProjection;
|
||||
// else
|
||||
// maxA += velocityProjection;
|
||||
//
|
||||
// // Do the same test as above for the new projection
|
||||
// float intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
|
||||
// if (intervalDistance > 0)
|
||||
// result.will_intersect = false;
|
||||
//
|
||||
// // If the Polygon2Ds are not intersecting and won't intersect, exit the loop
|
||||
// if (!result.intersect && !result.will_intersect)
|
||||
// break;
|
||||
//
|
||||
// // Check if the current interval distance is the minimum one. If so store
|
||||
// // the interval distance and the current distance.
|
||||
// // This will be used to calculate the minimum translation vector
|
||||
// intervalDistance = abs(intervalDistance);
|
||||
// if (intervalDistance < minIntervalDistance)
|
||||
// {
|
||||
// minIntervalDistance = intervalDistance;
|
||||
// translationAxis = axis;
|
||||
//
|
||||
// Vector2i d, ca, cb;
|
||||
// ca = polyA.Center();
|
||||
// cb = polyB.Center();
|
||||
//
|
||||
// d.x = ca.x - cb.x;
|
||||
// d.y = ca.y - cb.y;
|
||||
//
|
||||
// if (d.DotProduct(translationAxis) < 0)
|
||||
// {
|
||||
// translationAxis.x = -translationAxis.x;
|
||||
// translationAxis.y = -translationAxis.y;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // The minimum translation vector can be used to push the Polygon2Ds apart.
|
||||
// // First moves the Polygon2Ds by their velocity
|
||||
// // then move polyA by MinimumTranslationVector.
|
||||
// if (result.will_intersect)
|
||||
// {
|
||||
// result.mtv.x = translationAxis.x * minIntervalDistance;
|
||||
// result.mtv.y = translationAxis.y * minIntervalDistance;
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
|
||||
} // End of namespace Crab
|
||||
53
engines/crab/collision.h
Normal file
53
engines/crab/collision.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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_COLLISION_H
|
||||
#define CRAB_COLLISION_H
|
||||
|
||||
#include "crab/Polygon.h"
|
||||
#include "crab/Rectangle.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// Find if a line and a rectangle intersect
|
||||
bool collideLineRect(int p0X, int p0Y, int p1X, int p1Y, const Rect &rect);
|
||||
|
||||
// Find if there is a clear line of sight between two rectangles
|
||||
bool lineOfSight(const Rect &a, const Rect &b, const Rect &obstacle);
|
||||
|
||||
// Find the distance between two points
|
||||
template<typename T>
|
||||
double distance2D(const T &p0X, const T &p0Y, const T &p1X, const T &p1Y) {
|
||||
return sqrt((p0X - p1X) * (p0X - p1X) + (p0Y - p1Y) * (p0Y - p1Y));
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_COLLISION_H
|
||||
35
engines/crab/color.h
Normal file
35
engines/crab/color.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRAB_COLOR_H
|
||||
#define CRAB_COLOR_H
|
||||
|
||||
namespace Crab {
|
||||
struct Color {
|
||||
uint8 r;
|
||||
uint8 g;
|
||||
uint8 b;
|
||||
uint8 a;
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_COLOR_H
|
||||
3
engines/crab/configure.engine
Normal file
3
engines/crab/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine crab "CRAB" yes "" "" "16bit highres png freetype2 vorbis"
|
||||
90
engines/crab/console.cpp
Normal file
90
engines/crab/console.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crab/crab.h"
|
||||
#include "crab/console.h"
|
||||
#include "crab/input/input.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::input;
|
||||
|
||||
Console::Console() : GUI::Debugger() {
|
||||
registerCmd("draw", WRAP_METHOD(Console, cmdDraw));
|
||||
registerCmd("what", WRAP_METHOD(Console, cmdWhat));
|
||||
}
|
||||
|
||||
Console::~Console() {
|
||||
}
|
||||
|
||||
bool Console::cmdDraw(int argc, const char **argv) {
|
||||
if (argc > 1) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!scumm_stricmp(argv[i], "OFF"))
|
||||
g_engine->_debugDraw = 0;
|
||||
else if (!scumm_stricmp(argv[i], "TMX"))
|
||||
g_engine->_debugDraw |= DRAW_TMX;
|
||||
else if (!scumm_stricmp(argv[i], "PROPS"))
|
||||
g_engine->_debugDraw |= DRAW_PROP_BOUNDS;
|
||||
else if (!scumm_stricmp(argv[i], "SPRITE"))
|
||||
g_engine->_debugDraw |= DRAW_SPRITE_BOUNDS;
|
||||
else if (!scumm_stricmp(argv[i], "PATHING"))
|
||||
g_engine->_debugDraw |= DRAW_PATHING;
|
||||
else if (!scumm_stricmp(argv[i], "FPS"))
|
||||
g_engine->_debugDraw |= DRAW_FPS;
|
||||
else if (!scumm_stricmp(argv[i], "ALL"))
|
||||
g_engine->_debugDraw = DRAW_TMX | DRAW_PROP_BOUNDS | DRAW_SPRITE_BOUNDS | DRAW_PATHING | DRAW_FPS;
|
||||
else
|
||||
debugPrintf("Valid parameters are 'TMX', 'PROPS', 'SPRITE', 'PATHING', 'FPS', 'ALL' or 'OFF'\n");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::cmdWhat(int argc, const char **argv) {
|
||||
if (argc > 1) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!scumm_stricmp(argv[i], "keymap")) {
|
||||
switch (g_engine->_inputManager->getKeyBindingMode()) {
|
||||
case KBM_NONE:
|
||||
debugPrintf("KBM_NONE\n");
|
||||
break;
|
||||
|
||||
case KBM_GAME:
|
||||
debugPrintf("KBM_GAME\n");
|
||||
break;
|
||||
|
||||
case KBM_UI:
|
||||
debugPrintf("KBM_UI\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
debugPrintf("Unknown KBM\n");
|
||||
break;
|
||||
}
|
||||
} else
|
||||
debugPrintf("Valid parameters are 'keymap'\n");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
41
engines/crab/console.h
Normal file
41
engines/crab/console.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRAB_CONSOLE_H
|
||||
#define CRAB_CONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
class Console : public GUI::Debugger {
|
||||
private:
|
||||
bool cmdDraw(int argc, const char **argv);
|
||||
bool cmdWhat(int argc, const char **argv);
|
||||
|
||||
public:
|
||||
Console();
|
||||
~Console() override;
|
||||
};
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_CONSOLE_H
|
||||
214
engines/crab/crab.cpp
Normal file
214
engines/crab/crab.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "engines/util.h"
|
||||
#include "graphics/cursorman.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
#include "graphics/screen.h"
|
||||
#include "crab/crab.h"
|
||||
#include "crab/app.h"
|
||||
#include "crab/console.h"
|
||||
#include "crab/game.h"
|
||||
#include "crab/GameParam.h"
|
||||
#include "crab/LoadingScreen.h"
|
||||
#include "crab/input/cursor.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
CrabEngine *g_engine;
|
||||
|
||||
CrabEngine::CrabEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst),
|
||||
_gameDescription(gameDesc), _randomSource("Crab") {
|
||||
_app = nullptr;
|
||||
_thumbnail = nullptr;
|
||||
_debugDraw = 0;
|
||||
|
||||
g_engine = this;
|
||||
}
|
||||
|
||||
CrabEngine::~CrabEngine() {
|
||||
delete _app;
|
||||
|
||||
delete _screenSettings;
|
||||
delete _stringPool;
|
||||
delete _tempData;
|
||||
delete _filePath;
|
||||
|
||||
delete _loadMenu;
|
||||
delete _optionMenu;
|
||||
|
||||
delete _helpScreen;
|
||||
delete _loadingScreen;
|
||||
|
||||
delete _eventStore;
|
||||
delete _mouse;
|
||||
|
||||
delete _musicManager;
|
||||
delete _inputManager;
|
||||
delete _textManager;
|
||||
delete _imageManager;
|
||||
|
||||
delete _thumbnail;
|
||||
delete _screen;
|
||||
}
|
||||
|
||||
uint32 CrabEngine::getFeatures() const {
|
||||
return _gameDescription->flags;
|
||||
}
|
||||
|
||||
Common::String CrabEngine::getGameId() const {
|
||||
return _gameDescription->gameId;
|
||||
}
|
||||
|
||||
Common::Error CrabEngine::run() {
|
||||
// Prefer this format to avoid converting PNG files.
|
||||
const Graphics::PixelFormat bestFormat = Graphics::PixelFormat::createFormatRGBA32();
|
||||
|
||||
// Find a suitable 32-bit format with alpha, currently we don't support other color depths
|
||||
Common::List<Graphics::PixelFormat> formats = g_system->getSupportedFormats();
|
||||
for (Common::List<Graphics::PixelFormat>::iterator it = formats.begin(); it != formats.end(); ++it) {
|
||||
if (it->bytesPerPixel != 4 || it->aBits() == 0) {
|
||||
it = formats.reverse_erase(it);
|
||||
} else if (*it == bestFormat) {
|
||||
formats.clear();
|
||||
formats.push_back(bestFormat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Even if no formats are found, it's possible that the backend
|
||||
// can handle software conversion.
|
||||
if (formats.empty())
|
||||
formats.push_back(bestFormat);
|
||||
|
||||
initGraphics(1280, 720, formats);
|
||||
|
||||
_format = g_system->getScreenFormat();
|
||||
if (_format.bytesPerPixel != 4)
|
||||
return Common::kUnsupportedColorMode;
|
||||
|
||||
_screen = new Graphics::Screen(1280, 720, _format);
|
||||
_thumbnail = new Graphics::ManagedSurface(1280, 720, _format);
|
||||
|
||||
_imageManager = new pyrodactyl::image::ImageManager();
|
||||
_textManager = new pyrodactyl::text::TextManager();
|
||||
_inputManager = new pyrodactyl::input::InputManager();
|
||||
_musicManager = new pyrodactyl::music::MusicManager();
|
||||
|
||||
_mouse = new pyrodactyl::input::Cursor();
|
||||
_eventStore = new pyrodactyl::event::GameEventStore();
|
||||
|
||||
_loadingScreen = new LoadingScreen();
|
||||
_helpScreen = new pyrodactyl::ui::SlideShow();
|
||||
|
||||
_optionMenu = new pyrodactyl::ui::OptionMenu();
|
||||
_loadMenu = new pyrodactyl::ui::FileMenu<pyrodactyl::ui::SaveFileData>();
|
||||
|
||||
_filePath = new FilePaths();
|
||||
_tempData = new TempValue();
|
||||
_stringPool = new StringPool();
|
||||
_screenSettings = new ScreenSettings();
|
||||
|
||||
_debugDraw = 0;
|
||||
|
||||
CursorMan.showMouse(true);
|
||||
_mouse->reset();
|
||||
|
||||
_inputManager->populateKeyTable();
|
||||
_inputManager->setKeyBindingMode(pyrodactyl::input::KBM_GAME);
|
||||
|
||||
// Set the engine's debugger console
|
||||
setDebugger(new Console());
|
||||
|
||||
// If a savegame was selected from the launcher, load it
|
||||
int saveSlot = ConfMan.getInt("save_slot");
|
||||
if (saveSlot != -1)
|
||||
(void)loadGameState(saveSlot);
|
||||
|
||||
_app = new App();
|
||||
|
||||
_app->run();
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void CrabEngine::initializePath(const Common::FSNode &gamePath) {
|
||||
SearchMan.addDirectory(gamePath, 0, 5);
|
||||
}
|
||||
|
||||
Common::Error CrabEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
|
||||
Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(getSaveStateName(slot));
|
||||
|
||||
if (!saveFile)
|
||||
return Common::kWritingFailed;
|
||||
|
||||
_app->getGame()->saveState(saveFile);
|
||||
getMetaEngine()->appendExtendedSave(saveFile, getTotalPlayTime(), desc, isAutosave);
|
||||
|
||||
saveFile->finalize();
|
||||
|
||||
delete saveFile;
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error CrabEngine::loadGameState(int slot) {
|
||||
Common::Error res = Common::kReadingFailed;
|
||||
saveAutosaveIfEnabled();
|
||||
|
||||
Common::InSaveFile *saveFile = _saveFileMan->openForLoading(getSaveStateName(slot));
|
||||
|
||||
if (!saveFile)
|
||||
return res;
|
||||
|
||||
if (_app->getGame()->loadState(saveFile)) {
|
||||
ExtendedSavegameHeader header;
|
||||
if (MetaEngine::readSavegameHeader(saveFile, &header))
|
||||
setTotalPlayTime(header.playtime);
|
||||
res = Common::kNoError;
|
||||
}
|
||||
|
||||
delete saveFile;
|
||||
return res;
|
||||
}
|
||||
|
||||
Common::Error CrabEngine::syncGame(Common::Serializer &s) {
|
||||
// The Serializer has methods isLoading() and isSaving()
|
||||
// if you need to specific steps; for example setting
|
||||
// an array size after reading it's length, whereas
|
||||
// for saving it would write the existing array's length
|
||||
int dummy = 0;
|
||||
s.syncAsUint32LE(dummy);
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool CrabEngine::canSaveGameStateCurrently(Common::U32String *msg) {
|
||||
return _screenSettings->_inGame;
|
||||
}
|
||||
|
||||
void CrabEngine::syncSoundSettings() {
|
||||
Engine::syncSoundSettings();
|
||||
|
||||
_musicManager->syncSettings();
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
179
engines/crab/crab.h
Normal file
179
engines/crab/crab.h
Normal file
@@ -0,0 +1,179 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRAB_H
|
||||
#define CRAB_H
|
||||
|
||||
#include "common/random.h"
|
||||
#include "common/serializer.h"
|
||||
#include "graphics/pixelformat.h"
|
||||
|
||||
#include "crab/detection.h"
|
||||
|
||||
namespace Graphics {
|
||||
class ManagedSurface;
|
||||
class Screen;
|
||||
} // End of namespace Graphics
|
||||
|
||||
namespace Crab {
|
||||
|
||||
class App;
|
||||
struct CrabGameDescription;
|
||||
|
||||
class LoadingScreen;
|
||||
|
||||
struct FilePaths;
|
||||
struct TempValue;
|
||||
class StringPool;
|
||||
class ScreenSettings;
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
struct GameEventStore;
|
||||
} // End of namespace event
|
||||
|
||||
namespace ui {
|
||||
class SlideShow;
|
||||
class OptionMenu;
|
||||
|
||||
template<typename FileType>
|
||||
class FileMenu;
|
||||
|
||||
class SaveFileData;
|
||||
} // End of namespace ui
|
||||
|
||||
namespace image {
|
||||
class ImageManager;
|
||||
} // End of namespace image
|
||||
|
||||
namespace input {
|
||||
class Cursor;
|
||||
class InputManager;
|
||||
} // End of namespace input
|
||||
|
||||
namespace music {
|
||||
class MusicManager;
|
||||
} // End of namespace music
|
||||
|
||||
namespace text {
|
||||
class TextManager;
|
||||
} // End of namespace text
|
||||
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
enum DebugDraw {
|
||||
DRAW_TMX = 1 << 0,
|
||||
DRAW_PROP_BOUNDS = 1 << 1,
|
||||
DRAW_SPRITE_BOUNDS = 1 << 2,
|
||||
DRAW_PATHING = 1 << 3,
|
||||
DRAW_FPS = 1 << 4
|
||||
};
|
||||
|
||||
class CrabEngine : public Engine {
|
||||
private:
|
||||
const ADGameDescription *_gameDescription;
|
||||
Common::RandomSource _randomSource;
|
||||
App *_app;
|
||||
|
||||
protected:
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
|
||||
public:
|
||||
Graphics::Screen *_screen = nullptr;
|
||||
Graphics::PixelFormat _format;
|
||||
|
||||
pyrodactyl::image::ImageManager *_imageManager = nullptr;
|
||||
pyrodactyl::text::TextManager *_textManager = nullptr;
|
||||
pyrodactyl::input::InputManager *_inputManager = nullptr;
|
||||
pyrodactyl::music::MusicManager *_musicManager = nullptr;
|
||||
|
||||
pyrodactyl::input::Cursor *_mouse = nullptr;
|
||||
pyrodactyl::event::GameEventStore *_eventStore = nullptr;
|
||||
|
||||
// Should these really be inside the Engine class?
|
||||
LoadingScreen *_loadingScreen = nullptr;
|
||||
pyrodactyl::ui::SlideShow *_helpScreen = nullptr;
|
||||
pyrodactyl::ui::OptionMenu *_optionMenu = nullptr;
|
||||
pyrodactyl::ui::FileMenu<pyrodactyl::ui::SaveFileData> *_loadMenu = nullptr;
|
||||
|
||||
FilePaths *_filePath = nullptr;
|
||||
TempValue *_tempData = nullptr;
|
||||
StringPool *_stringPool = nullptr;
|
||||
ScreenSettings *_screenSettings = nullptr;
|
||||
|
||||
// Keeps a copy of latest screen for thumbnail
|
||||
Graphics::ManagedSurface *_thumbnail;
|
||||
|
||||
// What components to draw lines for (if any)
|
||||
uint32 _debugDraw;
|
||||
|
||||
Common::FSNode _gameDataDir;
|
||||
|
||||
CrabEngine(OSystem *syst, const ADGameDescription *gameDesc);
|
||||
~CrabEngine() override;
|
||||
void initializePath(const Common::FSNode &gamePath) override;
|
||||
|
||||
uint32 getFeatures() const;
|
||||
|
||||
/**
|
||||
* Returns the game Id
|
||||
*/
|
||||
Common::String getGameId() const;
|
||||
|
||||
/**
|
||||
* Gets a random number
|
||||
*/
|
||||
uint32 getRandomNumber(uint maxNum) {
|
||||
return _randomSource.getRandomNumber(maxNum);
|
||||
}
|
||||
|
||||
bool hasFeature(EngineFeature f) const override {
|
||||
return (f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime) ||
|
||||
(f == kSupportsReturnToLauncher);
|
||||
};
|
||||
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
|
||||
|
||||
/**
|
||||
* Uses a serializer to allow implementing savegame
|
||||
* loading and saving using a single method
|
||||
*/
|
||||
Common::Error syncGame(Common::Serializer &s);
|
||||
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave) override;
|
||||
Common::Error loadGameState(int slot) override;
|
||||
|
||||
void syncSoundSettings() override;
|
||||
|
||||
|
||||
};
|
||||
|
||||
extern CrabEngine *g_engine;
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_H
|
||||
3
engines/crab/credits.pl
Normal file
3
engines/crab/credits.pl
Normal file
@@ -0,0 +1,3 @@
|
||||
begin_section("CRAB");
|
||||
add_person("Kartik Agarwala", "hax0kartik", "");
|
||||
end_section();
|
||||
71
engines/crab/detection.cpp
Normal file
71
engines/crab/detection.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/plugins.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "crab/detection.h"
|
||||
|
||||
const DebugChannelDef CrabMetaEngineDetection::debugFlagList[] = {
|
||||
{Crab::kDebugGraphics, "Graphics", "Graphics debug level"},
|
||||
{Crab::kDebugPath, "Path", "Pathfinding debug level"},
|
||||
{Crab::kDebugFilePath, "FilePath", "File path debug level"},
|
||||
{Crab::kDebugScan, "Scan", "Scan for unrecognised games"},
|
||||
{Crab::kDebugScript, "Script", "Enable debug script dump"},
|
||||
DEBUG_CHANNEL_END};
|
||||
|
||||
static const PlainGameDescriptor crabGames[] = {
|
||||
{"unrest", "Unrest"},
|
||||
{nullptr, nullptr}};
|
||||
|
||||
namespace Crab {
|
||||
|
||||
static const ADGameDescription gameDescriptions[] = {
|
||||
{
|
||||
"unrest",
|
||||
"",
|
||||
AD_ENTRY2s("characters/backer_chars.xml", "d9028280f75836192d93e56df7313d8c", 2517,
|
||||
"traits/tanya_intelligent.png", "441221becc2b70e7c9d7838d6a8bd990", 12593),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformUnknown, // These files are same on Windows, Linux and MacOS. Therefore, do not specify platform.
|
||||
ADGF_DROPLANGUAGE | ADGF_DROPPLATFORM,
|
||||
GUIO3(GUIO_NOSPEECH, GUIO_NOLAUNCHLOAD, GUIO_NOMIDI),
|
||||
},
|
||||
{
|
||||
"unrest",
|
||||
"Demo",
|
||||
AD_ENTRY2s("characters/backer_chars.xml", "5ba20126349bc57b3774623a1ec89627", 2127,
|
||||
"traits/tanya_intelligent.png", "441221becc2b70e7c9d7838d6a8bd990", 12593),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformUnknown, // These files are same on Windows, Linux and MacOS. Therefore, do not specify platform.
|
||||
ADGF_DROPPLATFORM | ADGF_DEMO,
|
||||
GUIO3(GUIO_NOSPEECH, GUIO_NOLAUNCHLOAD, GUIO_NOMIDI),
|
||||
},
|
||||
AD_TABLE_END_MARKER};
|
||||
|
||||
}
|
||||
|
||||
CrabMetaEngineDetection::CrabMetaEngineDetection() : AdvancedMetaEngineDetection(Crab::gameDescriptions,
|
||||
crabGames) {
|
||||
_flags = kADFlagMatchFullPaths;
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(CRAB_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, CrabMetaEngineDetection);
|
||||
65
engines/crab/detection.h
Normal file
65
engines/crab/detection.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRAB_DETECTION_H
|
||||
#define CRAB_DETECTION_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
enum CrabDebugChannels {
|
||||
kDebugGraphics = 1,
|
||||
kDebugPath,
|
||||
kDebugScan,
|
||||
kDebugFilePath,
|
||||
kDebugScript,
|
||||
};
|
||||
|
||||
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
class CrabMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
static const DebugChannelDef debugFlagList[];
|
||||
|
||||
public:
|
||||
CrabMetaEngineDetection();
|
||||
~CrabMetaEngineDetection() override {}
|
||||
|
||||
const char *getName() const override {
|
||||
return "crab";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Crab";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Unrest (c) Pyrodactyl Games 2009-2023";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CRAB_DETECTION_H
|
||||
100
engines/crab/event/EventSeqGroup.cpp
Normal file
100
engines/crab/event/EventSeqGroup.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/* 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/event/EventSeqGroup.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::event;
|
||||
|
||||
void EventSeqGroup::endSeq(const uint &id) {
|
||||
_seq.erase(id);
|
||||
_end.push_back(id);
|
||||
}
|
||||
|
||||
void EventSeqGroup::addSeq(const uint &id, const Common::Path &path) {
|
||||
_seq[id].load(path);
|
||||
}
|
||||
|
||||
bool EventSeqGroup::eventInProgress(const uint &id) {
|
||||
return _seq.contains(id) && _seq[id].eventInProgress();
|
||||
}
|
||||
|
||||
GameEvent *EventSeqGroup::curEvent(const uint &id) {
|
||||
return _seq[id].currentEvent();
|
||||
}
|
||||
|
||||
void EventSeqGroup::nextEvent(const uint &id, Info &info, const Common::String &playerId,
|
||||
Common::Array<EventResult> &result, Common::Array<EventSeqInfo> &endSeq, const int choice) {
|
||||
return _seq[id].nextEvent(info, playerId, result, endSeq, choice);
|
||||
}
|
||||
|
||||
void EventSeqGroup::internalEvents(Info &info) {
|
||||
for (auto &it : _seq)
|
||||
it._value.internalEvents(info);
|
||||
}
|
||||
|
||||
bool EventSeqGroup::activeSeq(uint &activeSeq) {
|
||||
for (auto &i : _seq) {
|
||||
if (i._value.eventInProgress()) {
|
||||
activeSeq = i._key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
activeSeq = UINT_MAX;
|
||||
return false;
|
||||
}
|
||||
|
||||
void EventSeqGroup::saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root) {
|
||||
for (const auto &i : _end) {
|
||||
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, "end");
|
||||
child->value(g_engine->_stringPool->get(i));
|
||||
root->append_node(child);
|
||||
}
|
||||
|
||||
for (auto &i : _seq)
|
||||
i._value.saveState(doc, root, g_engine->_stringPool->get(i._key));
|
||||
}
|
||||
|
||||
void EventSeqGroup::loadState(rapidxml::xml_node<char> *node) {
|
||||
for (rapidxml::xml_node<char> *i = node->first_node("end"); i != nullptr; i = i->next_sibling("end"))
|
||||
endSeq(stringToNumber<uint>(i->value()));
|
||||
|
||||
for (auto n = node->first_node("set"); n != nullptr; n = n->next_sibling("set"))
|
||||
if (n->first_attribute("name") != nullptr) {
|
||||
uint id = stringToNumber<uint>(n->first_attribute("name")->value());
|
||||
if (_seq.contains(id))
|
||||
_seq[id].loadState(n);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
72
engines/crab/event/EventSeqGroup.h
Normal file
72
engines/crab/event/EventSeqGroup.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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_EVENTSEQGROUP_H
|
||||
#define CRAB_EVENTSEQGROUP_H
|
||||
|
||||
#include "crab/event/EventSequence.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
class EventSeqGroup {
|
||||
typedef Common::HashMap<uint, EventSequence> SeqMap;
|
||||
|
||||
// The event sequences in this group
|
||||
SeqMap _seq;
|
||||
|
||||
// The sequences that have ended in this group
|
||||
Common::Array<uint> _end;
|
||||
|
||||
public:
|
||||
EventSeqGroup() {}
|
||||
~EventSeqGroup() {}
|
||||
|
||||
void addSeq(const uint &id, const Common::Path &path);
|
||||
void endSeq(const uint &id);
|
||||
bool eventInProgress(const uint &id);
|
||||
bool activeSeq(uint &activeSeq);
|
||||
|
||||
GameEvent *curEvent(const uint &id);
|
||||
void nextEvent(const uint &id, Info &info, const Common::String &playerId, Common::Array<EventResult> &result,
|
||||
Common::Array<EventSeqInfo> &endSeq, const int choice = -1);
|
||||
|
||||
void internalEvents(Info &info);
|
||||
|
||||
void saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root);
|
||||
void loadState(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_EVENTSEQGROUP_H
|
||||
148
engines/crab/event/EventSequence.cpp
Normal file
148
engines/crab/event/EventSequence.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
/* 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/event/EventSequence.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::event;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Load
|
||||
//------------------------------------------------------------------------
|
||||
void EventSequence::load(const Common::Path &filename) {
|
||||
XMLDoc conf(filename);
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *node = conf.doc()->first_node("events");
|
||||
for (auto n = node->first_node("event"); n != nullptr; n = n->next_sibling("event")) {
|
||||
GameEvent e(n);
|
||||
_events.push_back(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Check for events happening
|
||||
//------------------------------------------------------------------------
|
||||
void EventSequence::internalEvents(pyrodactyl::event::Info &info) {
|
||||
for (const auto &nxe : _next) {
|
||||
if (nxe < _events.size()) {
|
||||
if (_events[nxe]._trig.evaluate(info)) {
|
||||
_eventInProgress = true;
|
||||
_cur = nxe;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Go to next event
|
||||
//------------------------------------------------------------------------
|
||||
void EventSequence::nextEvent(pyrodactyl::event::Info &info, const Common::String &player_id, Common::Array<EventResult> &result,
|
||||
Common::Array<EventSeqInfo> &end_seq, int NextEventChoice) {
|
||||
bool sync = false;
|
||||
_eventInProgress = false;
|
||||
|
||||
// Execute all effects associated with the event
|
||||
for (auto &i : _events[_cur]._effect)
|
||||
if (i.execute(info, player_id, result, end_seq))
|
||||
sync = true;
|
||||
|
||||
// Play a notification sound
|
||||
using namespace pyrodactyl::music;
|
||||
|
||||
if (info._sound._repDec)
|
||||
g_engine->_musicManager->playEffect(g_engine->_musicManager->_repDec, 0);
|
||||
else if (info._sound._repInc)
|
||||
g_engine->_musicManager->playEffect(g_engine->_musicManager->_repInc, 0);
|
||||
else if (info._sound._notify)
|
||||
g_engine->_musicManager->playEffect(g_engine->_musicManager->_notify, 0);
|
||||
|
||||
info._sound._notify = false;
|
||||
info._sound._repDec = false;
|
||||
info._sound._repInc = false;
|
||||
|
||||
if (!result.empty() || sync) {
|
||||
EventResult r;
|
||||
r._type = ER_SYNC;
|
||||
result.push_back(r);
|
||||
}
|
||||
|
||||
// Clear the next event list
|
||||
_next.clear();
|
||||
|
||||
// Add the next event to the event list
|
||||
if (NextEventChoice != -1)
|
||||
_next.push_back(NextEventChoice);
|
||||
else {
|
||||
for (const auto &i : _events[_cur]._next)
|
||||
_next.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Save the state of the object
|
||||
//------------------------------------------------------------------------
|
||||
void EventSequence::saveState(rapidxml::xml_document<char> &doc, rapidxml::xml_node<char> *root, const char *name) {
|
||||
rapidxml::xml_node<char> *seqnode = doc.allocate_node(rapidxml::node_element, "set");
|
||||
|
||||
// Write current event id and name to node
|
||||
seqnode->append_attribute(doc.allocate_attribute("name", name));
|
||||
seqnode->append_attribute(doc.allocate_attribute("current", g_engine->_stringPool->get(_cur)));
|
||||
|
||||
// Prepare strings of next events and write them
|
||||
for (uint i = 0; i < _next.size(); i++) {
|
||||
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, "next");
|
||||
child->value(g_engine->_stringPool->get(_next[i]));
|
||||
seqnode->append_node(child);
|
||||
}
|
||||
|
||||
root->append_node(seqnode);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Load the state of the object
|
||||
//------------------------------------------------------------------------
|
||||
void EventSequence::loadState(rapidxml::xml_node<char> *node) {
|
||||
rapidxml::xml_attribute<char> *curid = node->first_attribute("current");
|
||||
if (curid != nullptr)
|
||||
_cur = stringToNumber<uint>(curid->value());
|
||||
|
||||
_next.clear();
|
||||
for (auto n = node->first_node("next"); n != nullptr; n = n->next_sibling("next"))
|
||||
_next.push_back(stringToNumber<uint>(n->value()));
|
||||
|
||||
if (_next.empty())
|
||||
_next.push_back(0);
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
89
engines/crab/event/EventSequence.h
Normal file
89
engines/crab/event/EventSequence.h
Normal 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CRAB_EVENTSEQUENCE_H
|
||||
#define CRAB_EVENTSEQUENCE_H
|
||||
|
||||
#include "crab/event/gameevent.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
class EventSequence {
|
||||
Common::Array<GameEvent> _events;
|
||||
bool _eventInProgress;
|
||||
|
||||
// The event currently in execution - updated only when all trigger conditions are met in InternalEvents
|
||||
uint _cur;
|
||||
|
||||
// The events that can happen next - these are updated when the cur event is over
|
||||
// This means cur and next operate in an alternating way
|
||||
// scan next until find event, make it cur, end cur and update next, repeat
|
||||
Common::Array<uint> _next;
|
||||
|
||||
public:
|
||||
EventSequence() {
|
||||
_eventInProgress = false;
|
||||
_next.push_back(0);
|
||||
_cur = 0;
|
||||
}
|
||||
|
||||
~EventSequence() {}
|
||||
|
||||
GameEvent *currentEvent() {
|
||||
return &_events[_cur];
|
||||
}
|
||||
|
||||
// See if we should trigger any event
|
||||
void internalEvents(pyrodactyl::event::Info &info);
|
||||
void nextEvent(Info &info, const Common::String &playerId, Common::Array<EventResult> &result,
|
||||
Common::Array<EventSeqInfo> &endSeq, int nextEventChoice = -1);
|
||||
|
||||
bool eventInProgress() {
|
||||
return _eventInProgress;
|
||||
}
|
||||
|
||||
void eventInProgress(bool val) {
|
||||
_eventInProgress = val;
|
||||
}
|
||||
|
||||
// Load and save
|
||||
void load(const Common::Path &filename);
|
||||
|
||||
void saveState(rapidxml::xml_document<char> &doc, rapidxml::xml_node<char> *root, const char *name);
|
||||
void loadState(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_EVENTSEQUENCE_H
|
||||
398
engines/crab/event/GameEventInfo.cpp
Normal file
398
engines/crab/event/GameEventInfo.cpp
Normal file
@@ -0,0 +1,398 @@
|
||||
/* 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/event/eventstore.h"
|
||||
#include "crab/event/GameEventInfo.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
bool isChar(char c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
using namespace pyrodactyl::people;
|
||||
using namespace pyrodactyl::event;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Load from xml
|
||||
//------------------------------------------------------------------------
|
||||
void Info::load(rapidxml::xml_node<char> *node) {
|
||||
if (nodeValid("people", node)) {
|
||||
rapidxml::xml_node<char> *pnode = node->first_node("people");
|
||||
|
||||
_stem.load(pnode->first_attribute("templates")->value());
|
||||
|
||||
XMLDoc conf(pnode->first_attribute("list")->value());
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *cnode = conf.doc()->first_node("characters");
|
||||
if (nodeValid(cnode)) {
|
||||
loadNum(OPINION_MIN, "op_min", cnode);
|
||||
loadNum(OPINION_MAX, "op_max", cnode);
|
||||
|
||||
for (auto n = cnode->first_node("group"); n != nullptr; n = n->next_sibling("group"))
|
||||
loadPeople(n->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeValid("objective", node))
|
||||
_journal.load(node->first_node("objective")->first_attribute("layout")->value());
|
||||
|
||||
if (nodeValid("inventory", node)) {
|
||||
rapidxml::xml_node<char> *inode = node->first_node("inventory");
|
||||
_inv.load(inode->first_attribute("layout")->value());
|
||||
}
|
||||
|
||||
curLocID(node->first_node("level")->first_attribute("start")->value());
|
||||
_inv.itemFile(node->first_node("item")->first_attribute("list")->value());
|
||||
}
|
||||
|
||||
void Info::loadPeople(const Common::Path &filename) {
|
||||
XMLDoc conf(filename);
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *node = conf.doc()->first_node("people");
|
||||
if (nodeValid(node)) {
|
||||
for (auto n = node->first_node(); n != nullptr; n = n->next_sibling()) {
|
||||
Common::String str;
|
||||
loadStr(str, "id", n);
|
||||
_people[str].load(n, _stem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get/Set information about object type
|
||||
//------------------------------------------------------------------------
|
||||
void Info::type(const Common::String &id, const PersonType &val) {
|
||||
if (_people.contains(id))
|
||||
_people[id]._type = val;
|
||||
}
|
||||
|
||||
PersonType Info::type(const Common::String &id) {
|
||||
if (_people.contains(id))
|
||||
return _people[id]._type;
|
||||
|
||||
return PE_NEUTRAL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get/Set information about object state
|
||||
//------------------------------------------------------------------------
|
||||
void Info::state(const Common::String &id, const PersonState &val) {
|
||||
if (_people.contains(id))
|
||||
_people[id]._state = val;
|
||||
}
|
||||
|
||||
PersonState Info::state(const Common::String &id) {
|
||||
if (_people.contains(id))
|
||||
return _people[id]._state;
|
||||
|
||||
return PST_NORMAL;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get/Set information about variables
|
||||
//------------------------------------------------------------------------
|
||||
bool Info::varGet(const Common::String &name, int &val) {
|
||||
if (!_var.contains(name))
|
||||
return false;
|
||||
else
|
||||
val = _var[name];
|
||||
return true;
|
||||
}
|
||||
|
||||
void Info::varSet(const Common::String &name, const Common::String &val) {
|
||||
int varVal = 0;
|
||||
bool assignToVar = Common::find_if(val.begin(), val.end(), isChar) != val.end();
|
||||
|
||||
if (assignToVar)
|
||||
varGet(val, varVal);
|
||||
else
|
||||
varVal = stringToNumber<int>(val);
|
||||
|
||||
_var[name] = varVal;
|
||||
}
|
||||
|
||||
void Info::varAdd(const Common::String &name, const int &val) {
|
||||
if (!_var.contains(name))
|
||||
varSet(name, 0);
|
||||
|
||||
_var[name] += val;
|
||||
}
|
||||
|
||||
void Info::varSub(const Common::String &name, const int &val) {
|
||||
if (!_var.contains(name))
|
||||
varSet(name, 0);
|
||||
|
||||
_var[name] -= val;
|
||||
}
|
||||
|
||||
void Info::varMul(const Common::String &name, const int &val) {
|
||||
if (!_var.contains(name))
|
||||
varSet(name, 0);
|
||||
|
||||
_var[name] *= val;
|
||||
}
|
||||
|
||||
void Info::varDiv(const Common::String &name, const int &val) {
|
||||
if (!_var.contains(name))
|
||||
varSet(name, 0);
|
||||
|
||||
_var[name] /= val;
|
||||
}
|
||||
|
||||
void Info::varDel(const Common::String &name) {
|
||||
_var.erase(name);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get/Set person traits
|
||||
//------------------------------------------------------------------------
|
||||
void Info::traitAdd(const Common::String &perId, const int &traitId) {
|
||||
if (personValid(perId)) { // Valid person id
|
||||
if (traitId >= 0 && (uint)traitId < g_engine->_eventStore->_trait.size()) { // Valid trait id
|
||||
// Check for duplicate traits, DONT award anything if duplicate found
|
||||
Person *p = &personGet(perId);
|
||||
|
||||
for (const auto &i : p->_trait)
|
||||
if (i._id == traitId)
|
||||
return;
|
||||
|
||||
p->_trait.push_back(g_engine->_eventStore->_trait[traitId]);
|
||||
|
||||
g_engine->_eventStore->setAchievement(g_engine->_eventStore->_trait[traitId]._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Info::traitDel(const Common::String &perId, const int &traitId) {
|
||||
if (personValid(perId)) { // Valid person id
|
||||
if (traitId > 0 && (uint)traitId < g_engine->_eventStore->_trait.size()) { // Valid trait id
|
||||
Person *p = &personGet(perId);
|
||||
|
||||
for (auto j = p->_trait.begin(); j != p->_trait.end(); ++j) {
|
||||
if (j->_id == traitId) {
|
||||
p->_trait.erase(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get/Set information about object opinion
|
||||
//------------------------------------------------------------------------
|
||||
bool Info::opinionGet(const Common::String &name, const pyrodactyl::people::OpinionType &type, int &val) {
|
||||
if (!_people.contains(name))
|
||||
return false;
|
||||
|
||||
val = _people[name]._opinion._val[type];
|
||||
return true;
|
||||
}
|
||||
|
||||
void Info::opinionChange(const Common::String &name, const pyrodactyl::people::OpinionType &type, int val) {
|
||||
if (_people.contains(name))
|
||||
_people[name]._opinion.change(type, val);
|
||||
}
|
||||
|
||||
void Info::opinionSet(const Common::String &name, const pyrodactyl::people::OpinionType &type, int val) {
|
||||
if (_people.contains(name))
|
||||
_people[name]._opinion.set(type, val);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get/Set information about object stats
|
||||
//------------------------------------------------------------------------
|
||||
bool Info::statGet(const Common::String &name, const pyrodactyl::stat::StatType &type, int &num) {
|
||||
if (!_people.contains(name))
|
||||
return false;
|
||||
|
||||
num = _people[name]._stat._val[type]._cur;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Info::statSet(const Common::String &name, const pyrodactyl::stat::StatType &type, const int &num) {
|
||||
if (_people.contains(name))
|
||||
_people[name]._stat.set(type, num);
|
||||
}
|
||||
|
||||
void Info::statChange(const Common::String &name, const pyrodactyl::stat::StatType &type, const int &num) {
|
||||
if (_people.contains(name))
|
||||
_people[name]._stat.change(type, num);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get person object
|
||||
//------------------------------------------------------------------------
|
||||
bool Info::personGet(const Common::String &id, pyrodactyl::people::Person &p) {
|
||||
if (!_people.contains(id))
|
||||
return false;
|
||||
|
||||
p = _people[id];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Info::personValid(const Common::String &id) {
|
||||
return _people.contains(id);
|
||||
}
|
||||
|
||||
pyrodactyl::people::Person &Info::personGet(const Common::String &id) {
|
||||
// Make sure to check PersonValid before doing this!
|
||||
// Only use this to change parts of an object
|
||||
return _people[id];
|
||||
}
|
||||
|
||||
bool Info::collideWithTrigger(const Common::String &id, int rectIndex) {
|
||||
if (_people.contains(id)) {
|
||||
for (const auto &i : _people[id]._trig)
|
||||
if (i == rectIndex)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Replace all #values with their appropriate names in a string
|
||||
//------------------------------------------------------------------------
|
||||
void Info::insertName(Common::String &msg) {
|
||||
// We scan the dialog for #id values, which we convert to actual NPC names
|
||||
for (uint i = 0; i < msg.size(); ++i) {
|
||||
// The # symbol indicates that the next string until an end character needs to be replaced by the name
|
||||
if (msg[i] == '#') {
|
||||
// The position we want to start from, and the length of the substring
|
||||
uint start = i, end = i + 1, len = 0;
|
||||
|
||||
// First make sure # wasn't the end of the string
|
||||
for (; end < msg.size(); ++end, ++len)
|
||||
if (msg[end] == ',' || msg[end] == '.' || msg[end] == '!' || msg[end] == ' ' ||
|
||||
msg[end] == '?' || msg[end] == '-' || msg[end] == '\'' || msg[end] == '\"')
|
||||
break;
|
||||
|
||||
if (end < msg.size()) {
|
||||
// We use start+1 here because # isn't part of the id
|
||||
Common::String s = msg.substr(start + 1, len);
|
||||
|
||||
// We use length+1 here because otherwise it lets the last character stay in dialog
|
||||
if (personValid(s))
|
||||
msg.replace(start, len + 1, personGet(s)._name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::String Info::getName(const Common::String &id) {
|
||||
if (personValid(id))
|
||||
return personGet(id)._name;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Save and load object state
|
||||
//------------------------------------------------------------------------
|
||||
void Info::saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root) {
|
||||
for (const auto &v : _var) {
|
||||
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, "var");
|
||||
child->append_attribute(doc.allocate_attribute("id", v._key.c_str()));
|
||||
child->append_attribute(doc.allocate_attribute("val", g_engine->_stringPool->get(v._value)));
|
||||
root->append_node(child);
|
||||
}
|
||||
|
||||
for (auto &p : _people)
|
||||
p._value.saveState(doc, root);
|
||||
|
||||
rapidxml::xml_node<char> *childUnr = doc.allocate_node(rapidxml::node_element, "unread");
|
||||
|
||||
saveBool(_unread._inventory, "inventory", doc, childUnr);
|
||||
saveBool(_unread._journal, "journal", doc, childUnr);
|
||||
saveBool(_unread._trait, "trait", doc, childUnr);
|
||||
saveBool(_unread._map, "map", doc, childUnr);
|
||||
|
||||
root->append_node(childUnr);
|
||||
|
||||
rapidxml::xml_node<char> *child_img = doc.allocate_node(rapidxml::node_element, "img");
|
||||
child_img->append_attribute(doc.allocate_attribute("index", g_engine->_stringPool->get(_playerImg)));
|
||||
root->append_node(child_img);
|
||||
|
||||
rapidxml::xml_node<char> *child_money = doc.allocate_node(rapidxml::node_element, "money");
|
||||
child_money->append_attribute(doc.allocate_attribute("var", _moneyVar.c_str()));
|
||||
root->append_node(child_money);
|
||||
|
||||
_journal.saveState(doc, root);
|
||||
_inv.saveState(doc, root);
|
||||
}
|
||||
|
||||
void Info::loadState(rapidxml::xml_node<char> *node) {
|
||||
for (rapidxml::xml_node<char> *v = node->first_node("var"); v != nullptr; v = v->next_sibling("var"))
|
||||
_var[v->first_attribute("id")->value()] = stringToNumber<int>(v->first_attribute("val")->value());
|
||||
|
||||
for (rapidxml::xml_node<char> *p = node->first_node("object"); p != nullptr; p = p->next_sibling("object")) {
|
||||
Common::String id;
|
||||
loadStr(id, "id", p);
|
||||
_people[id].loadState(p);
|
||||
}
|
||||
|
||||
if (nodeValid("unread", node)) {
|
||||
rapidxml::xml_node<char> *unrnode = node->first_node("unread");
|
||||
loadBool(_unread._inventory, "inventory", unrnode);
|
||||
loadBool(_unread._journal, "journal", unrnode);
|
||||
loadBool(_unread._trait, "trait", unrnode);
|
||||
loadBool(_unread._map, "map", unrnode);
|
||||
}
|
||||
|
||||
if (nodeValid("img", node))
|
||||
loadNum(_playerImg, "index", node->first_node("img"));
|
||||
|
||||
if (nodeValid("money", node))
|
||||
loadStr(_moneyVar, "var", node->first_node("money"));
|
||||
|
||||
_journal.loadState(node);
|
||||
_inv.loadState(node);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Calculate UI positions after change in screen size
|
||||
//------------------------------------------------------------------------
|
||||
void Info::setUI() {
|
||||
_journal.setUI();
|
||||
_inv.setUI();
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
243
engines/crab/event/GameEventInfo.h
Normal file
243
engines/crab/event/GameEventInfo.h
Normal file
@@ -0,0 +1,243 @@
|
||||
/* 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_GAMEEVENTINFO_H
|
||||
#define CRAB_GAMEEVENTINFO_H
|
||||
|
||||
#include "crab/stat/StatTemplate.h"
|
||||
#include "crab/ui/Inventory.h"
|
||||
#include "crab/ui/journal.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
bool isChar(char c);
|
||||
|
||||
class Info {
|
||||
// The characters in the game
|
||||
pyrodactyl::people::PersonMap _people;
|
||||
|
||||
// The stat templates used in declaring person objects
|
||||
pyrodactyl::stat::StatTemplates _stem;
|
||||
|
||||
// The variables set by the events so far
|
||||
typedef Common::HashMap<Common::String, int> VarMap;
|
||||
VarMap _var;
|
||||
|
||||
// The last object player interacted with
|
||||
Common::String _lastobj;
|
||||
|
||||
// Is the game Iron Man or not?
|
||||
// Iron man means only one save - no reloading
|
||||
bool _ironman;
|
||||
|
||||
// The player's current location
|
||||
struct PlayerLoc {
|
||||
// id of the player's current location
|
||||
Common::String _id;
|
||||
|
||||
// The name of the player's current location
|
||||
Common::String _name;
|
||||
|
||||
PlayerLoc() {}
|
||||
} _loc;
|
||||
|
||||
// This image changes to reflect the playable character
|
||||
int _playerImg;
|
||||
|
||||
void loadPeople(const Common::Path &filename);
|
||||
|
||||
public:
|
||||
// The player's one stop shop for objectives and lore
|
||||
pyrodactyl::ui::Journal _journal;
|
||||
|
||||
// The current player inventory
|
||||
pyrodactyl::ui::Inventory _inv;
|
||||
|
||||
// This structure keeps track of unread indicators
|
||||
struct UnreadData {
|
||||
bool _inventory, _journal, _trait, _map;
|
||||
|
||||
UnreadData() {
|
||||
_inventory = false;
|
||||
_journal = false;
|
||||
_trait = true;
|
||||
_map = false;
|
||||
}
|
||||
} _unread;
|
||||
|
||||
// This is the variable corresponding to money that is drawn
|
||||
Common::String _moneyVar;
|
||||
|
||||
// Has the player pressed the talk key
|
||||
bool _talkKeyDown;
|
||||
|
||||
// Used so we only play one sound per event
|
||||
struct NotifySounds {
|
||||
bool _notify, _repInc, _repDec;
|
||||
|
||||
NotifySounds() {
|
||||
_notify = false;
|
||||
_repInc = false;
|
||||
_repDec = false;
|
||||
}
|
||||
} _sound;
|
||||
|
||||
Info() {
|
||||
Init();
|
||||
}
|
||||
|
||||
~Info() {}
|
||||
|
||||
void Init() {
|
||||
_lastobj = "";
|
||||
_ironman = false;
|
||||
_playerImg = 0;
|
||||
_talkKeyDown = false;
|
||||
}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
|
||||
// Person related stuff
|
||||
void type(const Common::String &id, const pyrodactyl::people::PersonType &val);
|
||||
pyrodactyl::people::PersonType type(const Common::String &id);
|
||||
|
||||
void state(const Common::String &id, const pyrodactyl::people::PersonState &val);
|
||||
pyrodactyl::people::PersonState state(const Common::String &id);
|
||||
|
||||
// Opinion
|
||||
bool opinionGet(const Common::String &name, const pyrodactyl::people::OpinionType &type, int &val);
|
||||
void opinionSet(const Common::String &name, const pyrodactyl::people::OpinionType &type, int val);
|
||||
void opinionChange(const Common::String &name, const pyrodactyl::people::OpinionType &type, int val);
|
||||
|
||||
// Stats
|
||||
bool statGet(const Common::String &name, const pyrodactyl::stat::StatType &type, int &num);
|
||||
void statSet(const Common::String &name, const pyrodactyl::stat::StatType &type, const int &num);
|
||||
void statChange(const Common::String &name, const pyrodactyl::stat::StatType &type, const int &num);
|
||||
|
||||
// Variables
|
||||
bool varGet(const Common::String &name, int &val);
|
||||
void varSet(const Common::String &name, const Common::String &val);
|
||||
void varAdd(const Common::String &name, const int &val);
|
||||
void varSub(const Common::String &name, const int &val);
|
||||
void varMul(const Common::String &name, const int &val);
|
||||
void varDiv(const Common::String &name, const int &val);
|
||||
void varDel(const Common::String &name);
|
||||
|
||||
// The trait functions
|
||||
void traitAdd(const Common::String &perId, const int &traitId);
|
||||
void traitDel(const Common::String &perId, const int &traitId);
|
||||
|
||||
// Player character button
|
||||
void playerImg(const int &val) {
|
||||
_playerImg = val;
|
||||
}
|
||||
|
||||
int playerImg() {
|
||||
return _playerImg;
|
||||
}
|
||||
|
||||
Common::String curLocID() {
|
||||
return _loc._id;
|
||||
}
|
||||
|
||||
void curLocID(const Common::String &id) {
|
||||
_loc._id = id;
|
||||
}
|
||||
|
||||
Common::String curLocName() {
|
||||
return _loc._name;
|
||||
}
|
||||
|
||||
void curLocName(const Common::String &name) {
|
||||
_loc._name = name;
|
||||
}
|
||||
|
||||
// Player stuff
|
||||
Common::String lastPerson() {
|
||||
return _lastobj;
|
||||
}
|
||||
|
||||
void lastPerson(const Common::String &name) {
|
||||
_lastobj = name;
|
||||
}
|
||||
|
||||
// Return the variable map for stuff like visibility checks
|
||||
VarMap &mapGet() {
|
||||
return _var;
|
||||
}
|
||||
|
||||
bool personGet(const Common::String &id, pyrodactyl::people::Person &p);
|
||||
|
||||
bool personValid(const Common::String &id);
|
||||
pyrodactyl::people::Person &personGet(const Common::String &id);
|
||||
|
||||
// Is an object colliding with a trigger area
|
||||
bool collideWithTrigger(const Common::String &id, int rectIndex);
|
||||
|
||||
// Replace all #values with their appropriate names in a string
|
||||
void insertName(Common::String &msg);
|
||||
Common::String getName(const Common::String &id);
|
||||
|
||||
// Draw the inventory
|
||||
void invDraw(const Common::String &id) {
|
||||
if (_var.contains(_moneyVar))
|
||||
_inv.draw(_people[id], _var[_moneyVar]);
|
||||
else
|
||||
_inv.draw(_people[id], 0);
|
||||
}
|
||||
|
||||
// Get whether game is iron man or not
|
||||
bool ironMan() {
|
||||
return _ironman;
|
||||
}
|
||||
|
||||
void ironMan(const bool &val) {
|
||||
_ironman = val;
|
||||
}
|
||||
|
||||
void loadIronMan(rapidxml::xml_node<char> *node) {
|
||||
Common::String str;
|
||||
loadStr(str, "diff", node);
|
||||
_ironman = (str == "Iron Man");
|
||||
}
|
||||
|
||||
void saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root);
|
||||
void loadState(rapidxml::xml_node<char> *node);
|
||||
|
||||
void setUI();
|
||||
};
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_GAMEEVENTINFO_H
|
||||
73
engines/crab/event/changeval.h
Normal file
73
engines/crab/event/changeval.h
Normal 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_CHANGEVAL_H
|
||||
#define CRAB_CHANGEVAL_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "crab/loaders.h"
|
||||
#include "crab/people/opinion.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::people;
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
struct ChangeVal {
|
||||
// The person whose opinion is changed
|
||||
Common::String _id;
|
||||
|
||||
// How much does opinion change?
|
||||
int _val[pyrodactyl::people::OPI_TOTAL];
|
||||
|
||||
ChangeVal() {
|
||||
_val[OPI_LIKE] = 0;
|
||||
_val[OPI_RESPECT] = 0;
|
||||
_val[OPI_FEAR] = 0;
|
||||
}
|
||||
|
||||
ChangeVal(rapidxml::xml_node<char> *node) : ChangeVal() {
|
||||
load(node);
|
||||
}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node) {
|
||||
loadStr(_id, "id", node);
|
||||
loadNum(_val[OPI_LIKE], "like", node);
|
||||
loadNum(_val[OPI_RESPECT], "respect", node);
|
||||
loadNum(_val[OPI_FEAR], "fear", node);
|
||||
}
|
||||
};
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_CHANGEVAL_H
|
||||
55
engines/crab/event/conversationdata.cpp
Normal file
55
engines/crab/event/conversationdata.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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/event/conversationdata.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::event;
|
||||
|
||||
void ReplyChoice::load(rapidxml::xml_node<char> *node) {
|
||||
loadStr(_text, "text", node);
|
||||
loadNum(_tone, "tone", node);
|
||||
loadNum(_nextid, "next", node);
|
||||
|
||||
if (nodeValid("unlock", node, false))
|
||||
_unlock.load(node->first_node("unlock"));
|
||||
|
||||
if (nodeValid("change", node, false))
|
||||
for (auto n = node->first_node("change"); n != nullptr; n = n->next_sibling("change"))
|
||||
_change.push_back(n);
|
||||
}
|
||||
|
||||
void ConversationData::load(rapidxml::xml_node<char> *node) {
|
||||
for (auto n = node->first_node("reply"); n != nullptr; n = n->next_sibling("reply"))
|
||||
_reply.push_back(n);
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
83
engines/crab/event/conversationdata.h
Normal file
83
engines/crab/event/conversationdata.h
Normal 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_CONVERSATIONDATA_H
|
||||
#define CRAB_CONVERSATIONDATA_H
|
||||
|
||||
#include "crab/event/changeval.h"
|
||||
#include "crab/event/triggerset.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
struct ReplyChoice {
|
||||
// The text for the reply
|
||||
Common::String _text;
|
||||
|
||||
// The tone of the response
|
||||
uint _tone;
|
||||
|
||||
// The next event id
|
||||
uint _nextid;
|
||||
|
||||
// The conditions to unlock this choice
|
||||
TriggerSet _unlock;
|
||||
|
||||
// The changes to opinion that are possible for this reply
|
||||
// All NPCs affected by this conversation
|
||||
Common::Array<ChangeVal> _change;
|
||||
|
||||
ReplyChoice() {
|
||||
_tone = 0;
|
||||
_nextid = 0;
|
||||
}
|
||||
|
||||
ReplyChoice(rapidxml::xml_node<char> *node) : ReplyChoice() {
|
||||
load(node);
|
||||
}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
|
||||
struct ConversationData {
|
||||
// The set of replies
|
||||
Common::Array<ReplyChoice> _reply;
|
||||
|
||||
ConversationData() {}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_CONVERSATIONDATA_H
|
||||
289
engines/crab/event/effect.cpp
Normal file
289
engines/crab/event/effect.cpp
Normal file
@@ -0,0 +1,289 @@
|
||||
/* 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/event/effect.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::event;
|
||||
using namespace pyrodactyl::music;
|
||||
|
||||
void Effect::load(rapidxml::xml_node<char> *node) {
|
||||
Common::String ty;
|
||||
loadStr(ty, "type", node);
|
||||
|
||||
// Should we throw a warning about missing fields? Depends on the type of effect
|
||||
bool echoOp = true, echoSub = true, echoVal = true;
|
||||
|
||||
if (ty == "var")
|
||||
_type = EFF_VAR;
|
||||
else if (ty == "journal")
|
||||
_type = EFF_JOURNAL;
|
||||
else if (ty == "person")
|
||||
_type = EFF_OBJ;
|
||||
else if (ty == "item")
|
||||
_type = EFF_ITEM;
|
||||
else if (ty == "like")
|
||||
_type = EFF_LIKE;
|
||||
else if (ty == "fear")
|
||||
_type = EFF_FEAR;
|
||||
else if (ty == "respect")
|
||||
_type = EFF_RESPECT;
|
||||
else if (ty == STATNAME_HEALTH)
|
||||
_type = EFF_HEALTH;
|
||||
else if (ty == "sound")
|
||||
_type = EFF_SOUND;
|
||||
else if (ty == "money")
|
||||
_type = EFF_MONEY;
|
||||
else if (ty == "end") {
|
||||
_type = EFF_END;
|
||||
echoSub = false;
|
||||
echoVal = false;
|
||||
} else if (ty == "map")
|
||||
_type = EFF_MAP;
|
||||
else if (ty == "dest")
|
||||
_type = EFF_DEST;
|
||||
else if (ty == "img") {
|
||||
_type = EFF_IMG;
|
||||
echoOp = false;
|
||||
echoSub = false;
|
||||
} else if (ty == "trait") {
|
||||
_type = EFF_TRAIT;
|
||||
echoOp = false;
|
||||
} else if (ty == "move") {
|
||||
_type = EFF_MOVE;
|
||||
echoOp = false;
|
||||
} else if (ty == "level")
|
||||
_type = EFF_LEVEL;
|
||||
else if (ty == "player") {
|
||||
_type = EFF_PLAYER;
|
||||
echoOp = false;
|
||||
echoSub = false;
|
||||
} else if (ty == "save") {
|
||||
_type = EFF_SAVE;
|
||||
echoOp = false;
|
||||
echoSub = false;
|
||||
echoVal = false;
|
||||
} else if (ty == "quit") {
|
||||
_type = EFF_QUIT;
|
||||
echoOp = false;
|
||||
echoSub = false;
|
||||
echoVal = false;
|
||||
} else
|
||||
_type = EFF_VAR;
|
||||
|
||||
loadStr(_subject, "subject", node, echoSub);
|
||||
loadStr(_operation, "operation", node, echoOp);
|
||||
loadStr(_val, "val", node, echoVal);
|
||||
}
|
||||
|
||||
void Effect::changeOpinion(pyrodactyl::event::Info &info, pyrodactyl::people::OpinionType opType) {
|
||||
int oldOp = 0;
|
||||
|
||||
// Only bother if the person exists and has a valid opinion
|
||||
if (info.opinionGet(_subject, opType, oldOp)) {
|
||||
if (_operation == "=")
|
||||
info.opinionSet(_subject, opType, stringToNumber<int>(_val));
|
||||
else if (_operation == "+")
|
||||
info.opinionChange(_subject, opType, stringToNumber<int>(_val));
|
||||
else if (_operation == "-")
|
||||
info.opinionChange(_subject, opType, -1 * stringToNumber<int>(_val));
|
||||
|
||||
int newOp = 0;
|
||||
info.opinionGet(_subject, opType, newOp);
|
||||
|
||||
if (newOp > oldOp)
|
||||
info._sound._repInc = true;
|
||||
else if (newOp < oldOp)
|
||||
info._sound._repDec = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Effect::execute(pyrodactyl::event::Info &info, const Common::String &playerId,
|
||||
Common::Array<EventResult> &result, Common::Array<EventSeqInfo> &endSeq) {
|
||||
if (_type < EFF_MOVE) {
|
||||
switch (_type) {
|
||||
case EFF_VAR:
|
||||
if (_operation == "=")
|
||||
info.varSet(_subject, _val);
|
||||
else if (_operation == "del")
|
||||
info.varDel(_subject);
|
||||
else if (_operation == "+")
|
||||
info.varAdd(_subject, stringToNumber<int>(_val));
|
||||
else if (_operation == "-")
|
||||
info.varSub(_subject, stringToNumber<int>(_val));
|
||||
else if (_operation == "*")
|
||||
info.varMul(_subject, stringToNumber<int>(_val));
|
||||
else if (_operation == "/")
|
||||
info.varDiv(_subject, stringToNumber<int>(_val));
|
||||
break;
|
||||
|
||||
case EFF_JOURNAL:
|
||||
if (_subject == "finish")
|
||||
info._journal.move(playerId, _operation, true);
|
||||
else if (_subject == "start")
|
||||
info._journal.move(playerId, _operation, false);
|
||||
else
|
||||
info._journal.add(playerId, _subject, _operation, _val);
|
||||
|
||||
// Update unread status of journal
|
||||
info._unread._journal = true;
|
||||
|
||||
// used so we only play one notify sound per event
|
||||
info._sound._notify = true;
|
||||
break;
|
||||
|
||||
case EFF_OBJ:
|
||||
if (_operation == "type")
|
||||
info.type(_subject, pyrodactyl::people::stringToPersonType(_val));
|
||||
else if (_operation == "state")
|
||||
info.state(_subject, pyrodactyl::people::stringToPersonState(_val));
|
||||
break;
|
||||
|
||||
case EFF_ITEM:
|
||||
if (_operation == "del")
|
||||
info._inv.delItem(_subject, _val);
|
||||
else
|
||||
info._inv.loadItem(_subject, _val);
|
||||
|
||||
// Update unread status of inventory
|
||||
info._unread._inventory = true;
|
||||
|
||||
// used so we only play one notify sound per event
|
||||
info._sound._notify = true;
|
||||
break;
|
||||
|
||||
case EFF_LIKE:
|
||||
changeOpinion(info, pyrodactyl::people::OPI_LIKE);
|
||||
break;
|
||||
|
||||
case EFF_FEAR:
|
||||
changeOpinion(info, pyrodactyl::people::OPI_FEAR);
|
||||
break;
|
||||
|
||||
case EFF_RESPECT:
|
||||
changeOpinion(info, pyrodactyl::people::OPI_RESPECT);
|
||||
break;
|
||||
|
||||
case EFF_HEALTH: {
|
||||
using namespace pyrodactyl::stat;
|
||||
int num = stringToNumber<int>(_val);
|
||||
|
||||
if (_operation == "=")
|
||||
info.statSet(_subject, STAT_HEALTH, num);
|
||||
else if (_operation == "+")
|
||||
info.statChange(_subject, STAT_HEALTH, num);
|
||||
else if (_operation == "-")
|
||||
info.statChange(_subject, STAT_HEALTH, -1 * num);
|
||||
} break;
|
||||
|
||||
case EFF_SOUND:
|
||||
if (_subject == "music") {
|
||||
if (_operation == "play") {
|
||||
MusicKey m = stringToNumber<MusicKey>(_val);
|
||||
g_engine->_musicManager->playMusic(m);
|
||||
} else if (_operation == "stop")
|
||||
g_engine->_musicManager->stop();
|
||||
else if (_operation == "pause")
|
||||
g_engine->_musicManager->pause();
|
||||
else if (_operation == "resume")
|
||||
g_engine->_musicManager->resume();
|
||||
} else
|
||||
g_engine->_musicManager->playEffect(stringToNumber<ChunkKey>(_val), 0);
|
||||
break;
|
||||
|
||||
case EFF_MONEY:
|
||||
info._moneyVar = _val;
|
||||
break;
|
||||
|
||||
case EFF_END:
|
||||
if (_operation == "cur")
|
||||
endSeq.push_back(true);
|
||||
else {
|
||||
EventSeqInfo seqinfo;
|
||||
seqinfo._loc = _subject;
|
||||
seqinfo._val = _val;
|
||||
endSeq.push_back(seqinfo);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
EventResult r;
|
||||
r._val = _subject;
|
||||
r._x = stringToNumber<int>(_operation);
|
||||
r._y = stringToNumber<int>(_val);
|
||||
|
||||
switch (_type) {
|
||||
case EFF_MOVE:
|
||||
r._type = ER_MOVE;
|
||||
break;
|
||||
case EFF_MAP:
|
||||
r._type = ER_MAP;
|
||||
break;
|
||||
case EFF_DEST:
|
||||
r._type = ER_DEST;
|
||||
break;
|
||||
case EFF_IMG:
|
||||
r._type = ER_IMG;
|
||||
info.playerImg(stringToNumber<int>(_val));
|
||||
break;
|
||||
case EFF_TRAIT:
|
||||
r._type = ER_TRAIT;
|
||||
info._unread._trait = true;
|
||||
info._sound._notify = true;
|
||||
break;
|
||||
case EFF_LEVEL:
|
||||
r._type = ER_LEVEL;
|
||||
break;
|
||||
case EFF_PLAYER:
|
||||
r._type = ER_PLAYER;
|
||||
break;
|
||||
case EFF_SAVE:
|
||||
r._type = ER_SAVE;
|
||||
break;
|
||||
case EFF_QUIT:
|
||||
r._type = ER_QUIT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
result.push_back(r);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
127
engines/crab/event/effect.h
Normal file
127
engines/crab/event/effect.h
Normal 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_EFFECT_H
|
||||
#define CRAB_EFFECT_H
|
||||
|
||||
#include "crab/loaders.h"
|
||||
#include "crab/event/GameEventInfo.h"
|
||||
#include "crab/people/person.h"
|
||||
#include "crab/rapidxml/rapidxml.hpp"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
enum EventResultType {
|
||||
ER_NONE, // Do nothing
|
||||
ER_MAP, // Change the map visible to player
|
||||
ER_DEST, // Add or remove a destination on world map
|
||||
ER_IMG, // Change the character button image
|
||||
ER_TRAIT, // Add or remove a trait from a character
|
||||
ER_LEVEL, // Change level
|
||||
ER_MOVE, // Move sprite
|
||||
ER_PLAYER, // Switch the player sprite
|
||||
ER_SAVE, // Save game
|
||||
ER_SYNC, // Sync the level
|
||||
ER_QUIT // Quit to main menu
|
||||
};
|
||||
|
||||
struct EventResult {
|
||||
EventResultType _type;
|
||||
Common::String _val;
|
||||
int _x, _y;
|
||||
|
||||
EventResult() {
|
||||
_type = ER_NONE;
|
||||
_x = -1;
|
||||
_y = -1;
|
||||
}
|
||||
};
|
||||
|
||||
struct EventSeqInfo {
|
||||
bool _cur;
|
||||
Common::String _loc, _val;
|
||||
|
||||
EventSeqInfo() {
|
||||
_cur = false;
|
||||
}
|
||||
|
||||
EventSeqInfo(const bool &cur) {
|
||||
_cur = cur;
|
||||
}
|
||||
};
|
||||
|
||||
enum EffectType {
|
||||
EFF_VAR, // variable operations like adding, removing etc
|
||||
EFF_JOURNAL, // Add an objective to the player quest book
|
||||
EFF_OBJ, // Change status (hostile, coward etc), state (stand, fight, flee, KO etc) of a character
|
||||
EFF_ITEM, // Add/remove an item in the player's inventory
|
||||
EFF_LIKE, // Change opinion of a character (charm)
|
||||
EFF_FEAR, // Change opinion of a character (intimidate)
|
||||
EFF_RESPECT, // Change opinion of a character (respect)
|
||||
EFF_HEALTH, // Change health of a character
|
||||
EFF_SOUND, // Manipulate the game music
|
||||
EFF_MONEY, // Set the money variable (not its value, just that which variable is the current money variable)
|
||||
EFF_END, // End of the event sequence, remove it from active sequences
|
||||
// EFFECT DIVISION HERE
|
||||
EFF_MOVE, // Make a character move
|
||||
EFF_MAP, // Change the world map
|
||||
EFF_DEST, // Add a destination to the world map
|
||||
EFF_IMG, // Change the player button image
|
||||
EFF_TRAIT, // Add or remove a trait from a character
|
||||
EFF_LEVEL, // Load a new level
|
||||
EFF_PLAYER, // Swap the player sprite
|
||||
EFF_SAVE, // Auto save the game
|
||||
EFF_QUIT // Quit to main menu
|
||||
};
|
||||
|
||||
struct Effect {
|
||||
EffectType _type;
|
||||
Common::String _subject, _operation, _val;
|
||||
|
||||
Effect() {
|
||||
_type = EFF_VAR;
|
||||
}
|
||||
|
||||
~Effect() {}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
bool execute(pyrodactyl::event::Info &info, const Common::String &playerId,
|
||||
Common::Array<EventResult> &result, Common::Array<EventSeqInfo> &endSeq);
|
||||
|
||||
void changeOpinion(pyrodactyl::event::Info &info, pyrodactyl::people::OpinionType type);
|
||||
};
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_EFFECT_H
|
||||
102
engines/crab/event/eventstore.cpp
Normal file
102
engines/crab/event/eventstore.cpp
Normal 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "crab/XMLDoc.h"
|
||||
#include "crab/event/eventstore.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::event;
|
||||
|
||||
void GameEventStore::addConv(rapidxml::xml_node<char> *node, uint &index) {
|
||||
ConversationData c;
|
||||
if (nodeValid("talk", node))
|
||||
c.load(node->first_node("talk"));
|
||||
|
||||
index = _con.size();
|
||||
_con.push_back(c);
|
||||
}
|
||||
|
||||
void GameEventStore::load(const Common::Path &filename) {
|
||||
|
||||
// Request current user stats from Steam
|
||||
// m_pSteamUserStats = SteamUserStats();
|
||||
|
||||
// if (m_pSteamUserStats != nullptr)
|
||||
// m_pSteamUserStats->RequestCurrentStats();
|
||||
|
||||
XMLDoc conf(filename);
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *node = conf.doc()->first_node("store");
|
||||
|
||||
if (nodeValid("animations", node)) {
|
||||
rapidxml::xml_node<char> *animnode = node->first_node("animations");
|
||||
for (auto n = animnode->first_node("anim"); n != nullptr; n = n->next_sibling("anim"))
|
||||
_anim.push_back(n);
|
||||
}
|
||||
|
||||
if (nodeValid("tones", node)) {
|
||||
rapidxml::xml_node<char> *tonenode = node->first_node("tones");
|
||||
for (auto n = tonenode->first_node("tone"); n != nullptr; n = n->next_sibling("tone")) {
|
||||
ToneData dat;
|
||||
loadStr(dat._text, "text", n);
|
||||
_tone.push_back(dat);
|
||||
}
|
||||
}
|
||||
|
||||
if (nodeValid("images", node)) {
|
||||
rapidxml::xml_node<char> *imgnode = node->first_node("images");
|
||||
for (auto n = imgnode->first_node("img"); n != nullptr; n = n->next_sibling("img"))
|
||||
_img.push_back(n);
|
||||
}
|
||||
|
||||
if (nodeValid("traits", node)) {
|
||||
rapidxml::xml_node<char> *traitnode = node->first_node("traits");
|
||||
for (auto n = traitnode->first_node("trait"); n != nullptr; n = n->next_sibling("trait"))
|
||||
_trait.push_back(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameEventStore::setAchievement(const int &id) {
|
||||
/*
|
||||
if (m_pSteamUserStats != nullptr)
|
||||
{
|
||||
if (id == 0)
|
||||
m_pSteamUserStats->SetAchievement("a0");
|
||||
else
|
||||
m_pSteamUserStats->SetAchievement(trait[id].id_str.c_str());
|
||||
|
||||
m_pSteamUserStats->StoreStats();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
91
engines/crab/event/eventstore.h
Normal file
91
engines/crab/event/eventstore.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* 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_EVENTSTORE_H
|
||||
#define CRAB_EVENTSTORE_H
|
||||
|
||||
#include "crab/animation/animation.h"
|
||||
#include "crab/event/conversationdata.h"
|
||||
#include "crab/ui/StateButton.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
// This structure is responsible for storing the special data structures for events like replies, conversations
|
||||
struct GameEventStore {
|
||||
// Data related to conversation events
|
||||
Common::Array<ConversationData> _con;
|
||||
|
||||
// Data related to animations
|
||||
Common::Array<pyrodactyl::anim::Animation> _anim;
|
||||
|
||||
// Data related to the tones of a character
|
||||
struct ToneData {
|
||||
Common::String _text;
|
||||
};
|
||||
|
||||
// This sets the text the player sees as "tone" during the reply menu
|
||||
Common::Array<ToneData> _tone;
|
||||
|
||||
// We need to change player character images when switching between characters
|
||||
Common::Array<pyrodactyl::ui::StateButtonImage> _img;
|
||||
|
||||
// The set of traits for various characters
|
||||
Common::Array<pyrodactyl::people::Trait> _trait;
|
||||
|
||||
// Steam UserStats interface
|
||||
// ISteamUserStats *m_pSteamUserStats;
|
||||
|
||||
GameEventStore() {
|
||||
// Huge number to prevent lots of resizing and stuff
|
||||
_con.reserve(9999);
|
||||
|
||||
_trait.reserve(120);
|
||||
_tone.reserve(120);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
_con.clear();
|
||||
_anim.clear();
|
||||
}
|
||||
|
||||
void load(const Common::Path &filename);
|
||||
|
||||
void addConv(rapidxml::xml_node<char> *node, uint &index);
|
||||
void setAchievement(const int &id);
|
||||
};
|
||||
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_EVENTSTORE_H
|
||||
91
engines/crab/event/gameevent.cpp
Normal file
91
engines/crab/event/gameevent.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/* 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/event/gameevent.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::event;
|
||||
using namespace pyrodactyl::people;
|
||||
|
||||
GameEvent::GameEvent() {
|
||||
_id = 0;
|
||||
_type = EVENT_DIALOG;
|
||||
_special = 0;
|
||||
_state = PST_NORMAL;
|
||||
}
|
||||
|
||||
void GameEvent::load(rapidxml::xml_node<char> *node) {
|
||||
if (!LoadEventID(_id, "id", node))
|
||||
_id = 0;
|
||||
|
||||
loadStr(_title, "title", node);
|
||||
loadStr(_dialog, "dialog", node);
|
||||
loadEnum(_state, "state", node, false);
|
||||
|
||||
Common::String type;
|
||||
loadStr(type, "type", node);
|
||||
|
||||
if (type == "dlg") {
|
||||
_type = EVENT_DIALOG;
|
||||
_special = 0;
|
||||
} else if (type == "reply") {
|
||||
_type = EVENT_REPLY;
|
||||
g_engine->_eventStore->addConv(node, _special);
|
||||
} else if (type == "animation") {
|
||||
_type = EVENT_ANIM;
|
||||
loadNum(_special, "anim", node);
|
||||
} else if (type == "silent") {
|
||||
_type = EVENT_SILENT;
|
||||
_special = 0;
|
||||
} else if (type == "text") {
|
||||
_type = EVENT_TEXT;
|
||||
_special = 0;
|
||||
} else {
|
||||
_type = EVENT_SPLASH;
|
||||
_special = 0;
|
||||
}
|
||||
|
||||
_trig.load(node);
|
||||
|
||||
_next.clear();
|
||||
for (rapidxml::xml_node<char> *i = node->first_node("next"); i != nullptr; i = i->next_sibling("next"))
|
||||
if (i->first_attribute("id") != nullptr)
|
||||
_next.push_back(stringToNumber<EventID>(i->first_attribute("id")->value()));
|
||||
|
||||
_effect.clear();
|
||||
for (rapidxml::xml_node<char> *it = node->first_node("effect"); it != nullptr; it = it->next_sibling("effect")) {
|
||||
Effect e;
|
||||
e.load(it);
|
||||
_effect.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
99
engines/crab/event/gameevent.h
Normal file
99
engines/crab/event/gameevent.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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_GAMEEVENT_H
|
||||
#define CRAB_GAMEEVENT_H
|
||||
|
||||
#include "crab/event/effect.h"
|
||||
#include "crab/event/eventstore.h"
|
||||
#include "crab/people/person.h"
|
||||
#include "crab/event/triggerset.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
// An uinteger is our event id format
|
||||
typedef uint EventID;
|
||||
|
||||
// Just map loading function to number load
|
||||
#define LoadEventID loadNum
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
enum EventType {
|
||||
EVENT_DIALOG,
|
||||
EVENT_REPLY,
|
||||
EVENT_TEXT,
|
||||
EVENT_ANIM,
|
||||
EVENT_SILENT,
|
||||
EVENT_SPLASH
|
||||
};
|
||||
|
||||
struct GameEvent {
|
||||
// The event identifier
|
||||
EventID _id;
|
||||
|
||||
// The heading for the dialog spoken
|
||||
Common::String _title;
|
||||
|
||||
// The dialog spoken in the event
|
||||
Common::String _dialog;
|
||||
|
||||
// The state decides which animation is drawn in the dialog box
|
||||
pyrodactyl::people::PersonState _state;
|
||||
|
||||
// Event type and related data index
|
||||
EventType _type;
|
||||
uint _special;
|
||||
|
||||
// The variables changed/added in the event
|
||||
Common::Array<Effect> _effect;
|
||||
|
||||
// The triggers for the event
|
||||
TriggerSet _trig;
|
||||
|
||||
// The id of the next event
|
||||
Common::Array<EventID> _next;
|
||||
|
||||
GameEvent();
|
||||
|
||||
GameEvent(rapidxml::xml_node<char> *node) : GameEvent() {
|
||||
load(node);
|
||||
}
|
||||
|
||||
~GameEvent() {}
|
||||
|
||||
void load(rapidxml::xml_node<char> *node);
|
||||
};
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_GAMEEVENT_H
|
||||
371
engines/crab/event/gameeventmanager.cpp
Normal file
371
engines/crab/event/gameeventmanager.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
/* 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/event/gameeventmanager.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::people;
|
||||
using namespace pyrodactyl::event;
|
||||
using namespace pyrodactyl::level;
|
||||
using namespace pyrodactyl::image;
|
||||
using namespace pyrodactyl::ui;
|
||||
|
||||
void Manager::init() {
|
||||
_eventMap.clear();
|
||||
_activeSeq = UINT_MAX;
|
||||
_curSp = nullptr;
|
||||
_player = false;
|
||||
_curEvent = nullptr;
|
||||
_drawGame = true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Load this
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::load(rapidxml::xml_node<char> *node, ParagraphData &popup) {
|
||||
if (nodeValid(node)) {
|
||||
XMLDoc conf(node->first_attribute("list")->value());
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *lnode = conf.doc()->first_node("event_list");
|
||||
for (rapidxml::xml_node<char> *loc = lnode->first_node("loc"); loc != nullptr; loc = loc->next_sibling("loc")) {
|
||||
Common::String locName;
|
||||
loadStr(locName, "name", loc);
|
||||
|
||||
for (auto n = loc->first_node("file"); n != nullptr; n = n->next_sibling("file")) {
|
||||
uint id;
|
||||
Common::Path path;
|
||||
loadNum(id, "name", n);
|
||||
loadPath(path, "path", n);
|
||||
_eventMap[locName].addSeq(id, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_activeSeq = UINT_MAX;
|
||||
|
||||
conf.load(node->first_attribute("layout")->value());
|
||||
if (conf.ready()) {
|
||||
rapidxml::xml_node<char> *layout = conf.doc()->first_node("layout");
|
||||
if (nodeValid(layout)) {
|
||||
if (nodeValid("character", layout))
|
||||
_oh.load(layout->first_node("character"));
|
||||
|
||||
if (nodeValid("popup", layout))
|
||||
popup.load(layout->first_node("popup"));
|
||||
|
||||
if (nodeValid("intro", layout))
|
||||
_intro.load(layout->first_node("intro"));
|
||||
}
|
||||
}
|
||||
|
||||
_reply.load(node->first_attribute("conversation")->value());
|
||||
|
||||
_per.load(node->first_attribute("char")->value());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Handle events
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::handleEvents(Info &info, const Common::String &playerId, Common::Event &event, HUD &hud, Level &level, Common::Array<EventResult> &result) {
|
||||
// If an event is already being performed
|
||||
if (_eventMap.contains(info.curLocID()) && _eventMap[info.curLocID()].eventInProgress(_activeSeq)) {
|
||||
switch (_curEvent->_type) {
|
||||
case EVENT_DIALOG:
|
||||
if (_oh._showJournal) {
|
||||
info._journal.handleEvents(playerId, event);
|
||||
|
||||
if (hud._back.handleEvents(event) == BUAC_LCLICK || hud._pausekey.handleEvents(event))
|
||||
_oh._showJournal = false;
|
||||
} else {
|
||||
// If journal button is select from within an event, go to the entry corresponding to that person's name
|
||||
if (_oh.handleCommonEvents(event)) {
|
||||
if (info.personValid(_curEvent->_title)) {
|
||||
Person &p = info.personGet(_curEvent->_title);
|
||||
if (p._altJournalName)
|
||||
info._journal.open(playerId, JE_PEOPLE, p._journalName);
|
||||
else
|
||||
info._journal.open(playerId, JE_PEOPLE, p._name);
|
||||
}
|
||||
}
|
||||
|
||||
if (_oh.handleDlboxEvents(event)) {
|
||||
_oh.onExit();
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq);
|
||||
_oh._showJournal = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_ANIM:
|
||||
// Skip animation if key pressed or mouse pressed
|
||||
if (event.type == Common::EVENT_LBUTTONUP || event.type == Common::EVENT_RBUTTONUP)
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq);
|
||||
break;
|
||||
case EVENT_REPLY:
|
||||
if (_oh._showJournal) {
|
||||
info._journal.handleEvents(playerId, event);
|
||||
|
||||
if (hud._back.handleEvents(event) == BUAC_LCLICK || hud._pausekey.handleEvents(event))
|
||||
_oh._showJournal = false;
|
||||
} else {
|
||||
// If journal button is select from within an event, go to the entry corresponding to that person's name
|
||||
if (_oh.handleCommonEvents(event))
|
||||
if (info.personValid(_curEvent->_title))
|
||||
info._journal.open(playerId, JE_PEOPLE, info.personGet(_curEvent->_title)._name);
|
||||
|
||||
unsigned int option = static_cast<unsigned int>(_reply.hoverIndex());
|
||||
const auto &replyChoice = g_engine->_eventStore->_con[_curEvent->_special]._reply;
|
||||
if (option < replyChoice.size()) {
|
||||
_intro.onEntry(replyChoice[option]._text);
|
||||
}
|
||||
|
||||
int choice = _reply.handleEvents(info, g_engine->_eventStore->_con[_curEvent->_special], _curEvent->_title, _oh, event);
|
||||
if (choice >= 0) {
|
||||
_reply.onExit();
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq, choice);
|
||||
_oh._showJournal = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_TEXT:
|
||||
// If journal button is select from within an event, go to the entry corresponding to that person's name
|
||||
if (_oh.handleCommonEvents(event))
|
||||
if (info.personValid(_curEvent->_title))
|
||||
info._journal.open(playerId, JE_PEOPLE, info.personGet(_curEvent->_title)._name);
|
||||
|
||||
if (_textin.handleEvents(event))
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq);
|
||||
break;
|
||||
case EVENT_SPLASH:
|
||||
if (_intro._showTraits) {
|
||||
_per.handleEvents(info, _curEvent->_title, event);
|
||||
|
||||
if (hud._back.handleEvents(event) == BUAC_LCLICK || hud._pausekey.handleEvents(event))
|
||||
_intro._showTraits = false;
|
||||
} else {
|
||||
if (_intro.handleEvents(event)) {
|
||||
_intro.onExit();
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, playerId, result, _endSeq);
|
||||
}
|
||||
if (_intro._showTraits)
|
||||
_per.Cache(info, level.playerId(), level);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
endSequence(info.curLocID());
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Internal Events
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::internalEvents(Info &info, Level &level, Common::Array<EventResult> &result) {
|
||||
if (_eventMap.contains(info.curLocID())) {
|
||||
if (_eventMap[info.curLocID()].eventInProgress(_activeSeq)) {
|
||||
switch (_curEvent->_type) {
|
||||
case EVENT_DIALOG:
|
||||
// fallthrough intended
|
||||
case EVENT_REPLY:
|
||||
// fallthrough intended
|
||||
case EVENT_SPLASH:
|
||||
updateDialogBox(info, level);
|
||||
break;
|
||||
case EVENT_ANIM: {
|
||||
using namespace pyrodactyl::anim;
|
||||
|
||||
DrawType drawVal = DRAW_SAME;
|
||||
if (g_engine->_eventStore->_anim[_curEvent->_special].internalEvents(drawVal))
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, level.playerId(), result, _endSeq);
|
||||
|
||||
if (drawVal == DRAW_STOP)
|
||||
_drawGame = false;
|
||||
else if (drawVal == DRAW_START)
|
||||
_drawGame = true;
|
||||
} break;
|
||||
case EVENT_SILENT:
|
||||
_eventMap[info.curLocID()].nextEvent(_activeSeq, info, level.playerId(), result, _endSeq);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
endSequence(info.curLocID());
|
||||
} else {
|
||||
_eventMap[info.curLocID()].internalEvents(info);
|
||||
calcActiveSeq(info, level, level.camera());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::updateDialogBox(Info &info, pyrodactyl::level::Level &level) {
|
||||
_oh.internalEvents(_curEvent->_state, _curSp);
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Draw
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::draw(Info &info, HUD &hud, Level &level) {
|
||||
if (_eventMap.contains(info.curLocID()) && _eventMap[info.curLocID()].eventInProgress(_activeSeq)) {
|
||||
switch (_curEvent->_type) {
|
||||
case EVENT_ANIM:
|
||||
g_engine->_eventStore->_anim[_curEvent->_special].draw();
|
||||
break;
|
||||
case EVENT_DIALOG:
|
||||
g_engine->_imageManager->dimScreen();
|
||||
if (_oh._showJournal) {
|
||||
info._journal.draw(level.playerId());
|
||||
hud._back.draw();
|
||||
} else
|
||||
_oh.draw(info, _curEvent, _curEvent->_title, _player, _curSp);
|
||||
break;
|
||||
case EVENT_REPLY:
|
||||
g_engine->_imageManager->dimScreen();
|
||||
if (_oh._showJournal) {
|
||||
info._journal.draw(level.playerId());
|
||||
hud._back.draw();
|
||||
} else {
|
||||
_oh.draw(info, _curEvent, _curEvent->_title, _player, _curSp);
|
||||
_reply.draw();
|
||||
}
|
||||
break;
|
||||
case EVENT_TEXT:
|
||||
_oh.draw(info, _curEvent, _curEvent->_title, _player, _curSp);
|
||||
_textin.draw();
|
||||
break;
|
||||
case EVENT_SPLASH:
|
||||
g_engine->_imageManager->dimScreen();
|
||||
if (_intro._showTraits) {
|
||||
_per.draw(info, _curEvent->_title);
|
||||
hud._back.draw();
|
||||
} else
|
||||
_intro.draw(info, _curEvent->_dialog, _curSp, _curEvent->_state);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Calculate the current sequence in progress
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::calcActiveSeq(Info &info, pyrodactyl::level::Level &level, const Rect &camera) {
|
||||
if (_eventMap[info.curLocID()].activeSeq(_activeSeq)) {
|
||||
// Set all the pointers to the new values
|
||||
_curEvent = _eventMap[info.curLocID()].curEvent(_activeSeq);
|
||||
_oh.reset(_curEvent->_title);
|
||||
_curSp = level.getSprite(_curEvent->_title);
|
||||
|
||||
// The player character's dialog is drawn a bit differently compared to others
|
||||
_player = (_curEvent->_title == level.playerId());
|
||||
|
||||
switch (_curEvent->_type) {
|
||||
case EVENT_DIALOG:
|
||||
_oh.onEntry(_curEvent->_dialog);
|
||||
break;
|
||||
case EVENT_ANIM:
|
||||
g_engine->_eventStore->_anim[_curEvent->_special].start();
|
||||
break;
|
||||
case EVENT_REPLY:
|
||||
_reply.onEntry(_curEvent->_dialog);
|
||||
_reply.cache(info, g_engine->_eventStore->_con[_curEvent->_special]);
|
||||
break;
|
||||
case EVENT_SPLASH:
|
||||
_intro.onEntry(_curEvent->_dialog);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Get/set info
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::endSequence(const Common::String &curloc) {
|
||||
if (_endSeq.empty())
|
||||
return;
|
||||
|
||||
for (const auto &i : _endSeq)
|
||||
if (i._cur)
|
||||
_eventMap[curloc].endSeq(_activeSeq);
|
||||
else if (_eventMap.contains(i._loc))
|
||||
_eventMap[i._loc].endSeq(stringToNumber<uint>(i._val));
|
||||
|
||||
_activeSeq = UINT_MAX;
|
||||
_endSeq.clear();
|
||||
}
|
||||
|
||||
bool Manager::eventInProgress() {
|
||||
if (_activeSeq == UINT_MAX)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Save the state of the object
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root) {
|
||||
for (auto &i : _eventMap) {
|
||||
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, "loc");
|
||||
child->append_attribute(doc.allocate_attribute("name", i._key.c_str()));
|
||||
i._value.saveState(doc, child);
|
||||
root->append_node(child);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Load the state of the object
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::loadState(rapidxml::xml_node<char> *node) {
|
||||
for (auto n = node->first_node("loc"); n != nullptr; n = n->next_sibling("loc")) {
|
||||
if (n->first_attribute("name") != nullptr) {
|
||||
Common::String name = n->first_attribute("name")->value();
|
||||
if (_eventMap.contains(name))
|
||||
_eventMap[name].loadState(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Purpose: Function called when window size is changed to adjust UI
|
||||
//------------------------------------------------------------------------
|
||||
void Manager::setUI() {
|
||||
_oh.setUI();
|
||||
_reply.setUI();
|
||||
_textin.setUI();
|
||||
_per.setUI();
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
117
engines/crab/event/gameeventmanager.h
Normal file
117
engines/crab/event/gameeventmanager.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/* 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_GAMEEVENTMANAGER_H
|
||||
#define CRAB_GAMEEVENTMANAGER_H
|
||||
|
||||
#include "crab/event/EventSeqGroup.h"
|
||||
#include "crab/ui/ChapterIntro.h"
|
||||
#include "crab/ui/hud.h"
|
||||
#include "crab/ui/journal.h"
|
||||
#include "crab/ui/PersonHandler.h"
|
||||
#include "crab/ui/PersonScreen.h"
|
||||
#include "crab/ui/ReplyMenu.h"
|
||||
#include "crab/ui/textarea.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
namespace pyrodactyl {
|
||||
namespace event {
|
||||
class Manager {
|
||||
protected:
|
||||
// All the events in the game
|
||||
Common::HashMap<Common::String, EventSeqGroup> _eventMap;
|
||||
|
||||
// The currently happening or active sequence
|
||||
uint _activeSeq;
|
||||
|
||||
// THIS IS NOT THE DEFINITIVE LIST OF ENDED SEQUENCES
|
||||
// JUST A TEMPORARY LIST OF EVENT SEQUENCES TO PASS AROUND
|
||||
Common::Array<EventSeqInfo> _endSeq;
|
||||
|
||||
// The objects used to draw the dialog box and opinion bars
|
||||
pyrodactyl::ui::PersonHandler _oh;
|
||||
|
||||
// The _reply menu and the colors and font of the text
|
||||
pyrodactyl::ui::ReplyMenu _reply;
|
||||
|
||||
// The field for text input
|
||||
pyrodactyl::ui::TextArea _textin;
|
||||
|
||||
// The info for intro events
|
||||
pyrodactyl::ui::ChapterIntro _intro;
|
||||
|
||||
// Store the current event data temporarily
|
||||
GameEvent *_curEvent;
|
||||
bool _player;
|
||||
pyrodactyl::anim::Sprite *_curSp;
|
||||
|
||||
void updateDialogBox(Info &info, pyrodactyl::level::Level &level);
|
||||
|
||||
public:
|
||||
// The object used to draw the character screen
|
||||
pyrodactyl::ui::PersonScreen _per;
|
||||
|
||||
// A flag used to stop drawing the game for a better fade in/fade out experience
|
||||
bool _drawGame;
|
||||
|
||||
Manager() {
|
||||
init();
|
||||
}
|
||||
|
||||
~Manager() {}
|
||||
|
||||
void init();
|
||||
void load(rapidxml::xml_node<char> *node, pyrodactyl::ui::ParagraphData &popup);
|
||||
|
||||
void draw(Info &info, pyrodactyl::ui::HUD &hud, pyrodactyl::level::Level &level);
|
||||
|
||||
// cur_per is also updated here
|
||||
void internalEvents(Info &info, pyrodactyl::level::Level &level, Common::Array<EventResult> &result);
|
||||
|
||||
void handleEvents(Info &info, const Common::String &playerId, Common::Event &event,
|
||||
pyrodactyl::ui::HUD &hud, pyrodactyl::level::Level &level, Common::Array<EventResult> &result);
|
||||
|
||||
void calcActiveSeq(Info &info, pyrodactyl::level::Level &level, const Rect &camera);
|
||||
|
||||
void endSequence(const Common::String &curloc);
|
||||
bool eventInProgress();
|
||||
|
||||
void saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root);
|
||||
void loadState(rapidxml::xml_node<char> *node);
|
||||
|
||||
void setUI();
|
||||
};
|
||||
} // End of namespace event
|
||||
} // End of namespace pyrodactyl
|
||||
|
||||
} // End of namespace Crab
|
||||
|
||||
#endif // CRAB_GAMEEVENTMANAGER_H
|
||||
68
engines/crab/event/quest.cpp
Normal file
68
engines/crab/event/quest.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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/event/quest.h"
|
||||
|
||||
namespace Crab {
|
||||
|
||||
using namespace pyrodactyl::event;
|
||||
|
||||
Quest::Quest(const Common::String &title, const Common::String &text, const bool &unread, const bool &marker) : _title(title) {
|
||||
_text.insert_at(0, text);
|
||||
_unread = unread;
|
||||
_marker = marker;
|
||||
}
|
||||
|
||||
void Quest::loadState(rapidxml::xml_node<char> *node) {
|
||||
loadStr(_title, "title", node);
|
||||
loadBool(_unread, "unread", node);
|
||||
loadBool(_marker, "marker", node);
|
||||
|
||||
for (rapidxml::xml_node<char> *n = node->first_node("info"); n != nullptr; n = n->next_sibling("info"))
|
||||
_text.push_back(n->value());
|
||||
}
|
||||
|
||||
void Quest::saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root) {
|
||||
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, "quest");
|
||||
child->append_attribute(doc.allocate_attribute("title", _title.c_str()));
|
||||
|
||||
saveBool(_unread, "unread", doc, child);
|
||||
saveBool(_marker, "marker", doc, child);
|
||||
|
||||
for (const auto &i : _text) {
|
||||
rapidxml::xml_node<char> *grandchild = doc.allocate_node(rapidxml::node_element, "info");
|
||||
grandchild->value(i.c_str());
|
||||
child->append_node(grandchild);
|
||||
}
|
||||
|
||||
root->append_node(child);
|
||||
}
|
||||
|
||||
} // End of namespace Crab
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user