239 lines
7.6 KiB
C++
239 lines
7.6 KiB
C++
/* 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/ScreenSettings.h"
|
|
#include "crab/level/level.h"
|
|
|
|
namespace Crab {
|
|
|
|
using namespace TMX;
|
|
using namespace pyrodactyl::stat;
|
|
using namespace pyrodactyl::anim;
|
|
using namespace pyrodactyl::level;
|
|
using namespace pyrodactyl::image;
|
|
using namespace pyrodactyl::people;
|
|
using namespace pyrodactyl::input;
|
|
|
|
//------------------------------------------------------------------------
|
|
// Purpose: Used to sort background sprites
|
|
//------------------------------------------------------------------------
|
|
static bool compSpriteLayer(const Sprite &a, const Sprite &b) {
|
|
return (a._layer < b._layer);
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Purpose: Load the level
|
|
//------------------------------------------------------------------------
|
|
void Level::load(const Common::Path &filename, pyrodactyl::event::Info &info,
|
|
pyrodactyl::event::TriggerSet &gameOver, const int &playerX, const int &playerY) {
|
|
reset();
|
|
XMLDoc conf(filename);
|
|
if (conf.ready()) {
|
|
rapidxml::xml_node<char> *node = conf.doc()->first_node("level");
|
|
if (nodeValid(node)) {
|
|
Common::String vis;
|
|
loadStr(vis, "map", node, false);
|
|
if (vis == "false")
|
|
_showmap.set(false);
|
|
else
|
|
_showmap.set(true);
|
|
|
|
if (nodeValid("preview", node))
|
|
loadPath(_previewPath, "path", node->first_node("preview"));
|
|
|
|
if (nodeValid("music", node)) {
|
|
loadNum(_music._id, "id", node->first_node("music"));
|
|
g_engine->_musicManager->playMusic(_music._id);
|
|
}
|
|
|
|
if (nodeValid("map", node)) {
|
|
rapidxml::xml_node<char> *mapnode = node->first_node("map");
|
|
Common::Path path;
|
|
Common::String tmxfile;
|
|
loadPath(path, "path", mapnode);
|
|
loadStr(tmxfile, "file", mapnode);
|
|
|
|
_terrain.load(path, tmxfile);
|
|
|
|
// Remember to load the terrain data before constructing the pathfinding grid
|
|
_pathfindingGrid.setupNodes(_terrain);
|
|
|
|
_terrain._grid = &_pathfindingGrid;
|
|
|
|
if (nodeValid("loc", mapnode))
|
|
_mapLoc.load(mapnode->first_node("loc"));
|
|
|
|
if (nodeValid("clip", mapnode)) {
|
|
rapidxml::xml_node<char> *clipnode = mapnode->first_node("clip");
|
|
loadNum(_mapClip._id, "id", clipnode);
|
|
_mapClip._rect.load(clipnode);
|
|
}
|
|
}
|
|
|
|
if (nodeValid("sprites", node)) {
|
|
rapidxml::xml_node<char> *spritenode = node->first_node("sprites");
|
|
int count = 0;
|
|
for (auto n = spritenode->first_node(); n != nullptr; n = n->next_sibling(), ++count) {
|
|
Sprite s;
|
|
s.load(n, _animSet);
|
|
|
|
Common::String str = n->name();
|
|
if (str == "player") {
|
|
_playerIndex = _objects.size();
|
|
if (playerX != -1 && playerY != -1) {
|
|
s.x(playerX);
|
|
s.y(playerY);
|
|
}
|
|
}
|
|
|
|
_objects.push_back(s);
|
|
}
|
|
}
|
|
|
|
if (nodeValid("background", node)) {
|
|
rapidxml::xml_node<char> *spritenode = node->first_node("background");
|
|
for (auto n = spritenode->first_node(); n != nullptr; n = n->next_sibling()) {
|
|
Sprite s;
|
|
s.load(n, _animSet);
|
|
_background.push_back(s);
|
|
}
|
|
|
|
Common::sort(_background.begin(), _background.end(), compSpriteLayer);
|
|
}
|
|
|
|
if (nodeValid("fly", node)) {
|
|
rapidxml::xml_node<char> *spritenode = node->first_node("fly");
|
|
for (auto n = spritenode->first_node(); n != nullptr; n = n->next_sibling()) {
|
|
Sprite s;
|
|
s.load(n, _animSet);
|
|
|
|
// Set the timer target for the first time
|
|
//s.ai_data.walk.timer.Target(sc_default.fly.delay_min + (gRandom.Num() % sc_default.fly.delay_max));
|
|
s._aiData._walk._timer.target(_scDefault._fly._delayMax);
|
|
|
|
_fly.push_back(s);
|
|
}
|
|
}
|
|
|
|
if (nodeValid("movement", node)) {
|
|
rapidxml::xml_node<char> *movnode = node->first_node("movement");
|
|
for (auto n = movnode->first_node("set"); n != nullptr; n = n->next_sibling("set"))
|
|
_moveSet.push_back(n);
|
|
}
|
|
|
|
if (nodeValid("popup", node, false))
|
|
_pop.load(node->first_node("popup"));
|
|
|
|
gameOver.clear();
|
|
if (nodeValid("game_over", node, false))
|
|
gameOver.load(node->first_node("game_over"));
|
|
else if (_playerIndex < _objects.size()) {
|
|
// The default lose condition is the death of the player
|
|
using namespace pyrodactyl::event;
|
|
Trigger t;
|
|
t._type = TRIG_STAT;
|
|
t._target = STATNAME_HEALTH;
|
|
t._subject = _objects[_playerIndex].id();
|
|
t._operation = "<";
|
|
t._val = "1";
|
|
gameOver.add(t);
|
|
}
|
|
|
|
calcProperties(info);
|
|
}
|
|
}
|
|
|
|
setCamera();
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Purpose: Build an index of all animation files, called once at start
|
|
//------------------------------------------------------------------------
|
|
void Level::loadMoves(const Common::Path &filename) {
|
|
XMLDoc movList(filename);
|
|
if (movList.ready()) {
|
|
rapidxml::xml_node<char> *node = movList.doc()->first_node("movelist");
|
|
for (auto n = node->first_node("set"); n != nullptr; n = n->next_sibling("set")) {
|
|
uint pos = _animSet.size();
|
|
|
|
loadNum(pos, "id", n);
|
|
if (pos >= _animSet.size())
|
|
_animSet.resize(pos + 1);
|
|
|
|
// See if there is an alternate moveset for low quality setting
|
|
// If no, just load the regular one
|
|
if (!g_engine->_screenSettings->_quality) {
|
|
if (!loadPath(_animSet[pos], "path_low", n))
|
|
loadPath(_animSet[pos], "path", n);
|
|
} else
|
|
loadPath(_animSet[pos], "path", n);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Purpose: Load the default sprite constant parameters
|
|
//------------------------------------------------------------------------
|
|
void Level::loadConst(const Common::Path &filename) {
|
|
XMLDoc doc(filename);
|
|
if (doc.ready()) {
|
|
rapidxml::xml_node<char> *node = doc.doc()->first_node("constant");
|
|
if (nodeValid(node))
|
|
_scDefault.load(node);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Purpose: Save all sprite positions to save file
|
|
//------------------------------------------------------------------------
|
|
void Level::saveState(rapidxml::xml_document<> &doc, rapidxml::xml_node<char> *root) {
|
|
root->append_attribute(doc.allocate_attribute("player_index", g_engine->_stringPool->get(_playerIndex)));
|
|
|
|
for (auto &i : _objects) {
|
|
rapidxml::xml_node<char> *child = doc.allocate_node(rapidxml::node_element, "sprite");
|
|
i.saveState(doc, child);
|
|
root->append_node(child);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------
|
|
// Purpose: Load all sprite positions from save file
|
|
//------------------------------------------------------------------------
|
|
void Level::loadState(rapidxml::xml_node<char> *node) {
|
|
loadNum(_playerIndex, "player_index", node);
|
|
|
|
auto i = _objects.begin();
|
|
for (auto *n = node->first_node("sprite"); n != nullptr && i != _objects.end(); n = n->next_sibling("sprite"), ++i)
|
|
i->loadState(n);
|
|
}
|
|
|
|
} // End of namespace Crab
|