Files
scummvm-cursorfix/engines/crab/level/level_load.cpp
2026-02-02 04:50:13 +01:00

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