Files
scummvm/engines/qdengine/qdcore/qd_trigger_chain.cpp
T
Eugene Sandulenko 539bbd3964 QDENGINE: Force file offsets to be 'int' in debug messages
This fixes annpying portability issue, generating tons of warnings,
since printing int64s is still platform-dependent.
2024-09-08 01:25:32 +02:00

353 lines
8.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/>.
*
*/
#include "common/debug.h"
#include "common/stream.h"
#include "qdengine/qd_fwd.h"
#include "qdengine/parser/xml_tag_buffer.h"
#include "qdengine/parser/qdscr_parser.h"
#include "qdengine/qdcore/qd_trigger_chain.h"
namespace QDEngine {
qdTriggerChain::qdTriggerChain() {
root_element()->set_id(qdTriggerElement::ROOT_ID);
root_element()->set_status(qdTriggerElement::TRIGGER_EL_DONE);
}
qdTriggerChain::~qdTriggerChain() {
for (auto &it : _elements) {
delete it;
}
_elements.clear();
}
bool qdTriggerChain::reindex_elements() {
int id = 0;
for (auto &it : _elements) {
it->set_id(id++);
}
return true;
}
qdTriggerElementPtr qdTriggerChain::search_element(int id) {
if (id == qdTriggerElement::ROOT_ID)
return root_element();
for (auto it : _elements)
if (it->ID() == id)
return it;
return 0;
}
qdTriggerElementPtr qdTriggerChain::add_element(qdNamedObject *p) {
if (!can_add_element(p)) return 0;
qdTriggerElementPtr el = new qdTriggerElement(p);
_elements.push_back(el);
reindex_elements();
return el;
}
bool qdTriggerChain::remove_element(qdTriggerElementPtr p, bool free_mem, bool relink_elements) {
for (auto it = _elements.begin(); it != _elements.end(); it++) {
if (*it == p) {
if (relink_elements) {
for (auto &it_c : (*it)->children()) {
it_c.element()->remove_parent(*it);
}
for (auto &it_p : (*it)->parents()) {
it_p.element()->remove_child(*it);
}
for (auto &it_c : (*it)->children()) {
for (auto &it_p : (*it)->parents()) {
it_c.element()->add_parent(it_p.element());
it_p.element()->add_child(it_c.element());
}
}
}
if (free_mem)
delete *it;
_elements.erase(it);
reindex_elements();
return true;
}
}
return false;
}
bool qdTriggerChain::can_add_element(const qdNamedObject *p) const {
if (is_element_in_list(p) && p->named_object_type() != QD_NAMED_OBJECT_SCENE) return false;
return true;
}
bool qdTriggerChain::init_elements() {
for (auto &it : _elements) {
it->clear_object_trigger_references();
}
for (auto &it : _elements) {
it->add_object_trigger_reference();
}
return true;
}
bool qdTriggerChain::is_element_in_list(qdNamedObject const *p) const {
for (auto &it : _elements) {
if (it->object() == p)
return true;
}
return false;
}
bool qdTriggerChain::is_element_in_list(qdTriggerElementConstPtr p) const {
for (auto &it : _elements) {
if (it == p || (it->object() && it->object() == p->object()))
return true;
}
return false;
}
bool qdTriggerChain::add_link(qdTriggerElementPtr from, qdTriggerElementPtr to, int link_type, bool auto_restart) {
if (!from->add_child(to, link_type, auto_restart)) return false;
if (!to->add_parent(from, link_type)) return false;
return true;
}
bool qdTriggerChain::remove_link(qdTriggerElementPtr from, qdTriggerElementPtr to) {
if (!from->remove_child(to)) return false;
if (!to->remove_parent(from)) return false;
return true;
}
bool qdTriggerChain::load_script(const xml::tag *p) {
int id0, id1, tp0;
qdTriggerElementPtr el, el1;
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
switch (it->ID()) {
case QDSCR_NAME:
set_name(it->data());
break;
case QDSCR_TRIGGER_CHAIN_ROOT:
root_element()->load_script(&*it);
root_element()->set_status(qdTriggerElement::TRIGGER_EL_DONE);
break;
case QDSCR_TRIGGER_ELEMENT:
el = qdTriggerElementPtr(new qdTriggerElement);
el->load_script(&*it);
_elements.push_back(el);
break;
case QDSCR_TRIGGER_ELEMENT_LINK:
xml::tag_buffer(*it) > id0 > id1 > tp0;
el = search_element(id0);
el1 = search_element(id1);
if (el && el1) {
bool auto_restart = false;
if (const xml::tag * tp = it->search_subtag(QDSCR_TRIGGER_ELEMENT_LINK_AUTO_RESTART)) {
if (xml::tag_buffer(*tp).get_int())
auto_restart = true;
else
auto_restart = false;
}
add_link(el, el1, tp0, auto_restart);
}
break;
}
}
root_element()->retrieve_link_elements(this);
for (qdTriggerElementList::iterator it = _elements.begin(); it != _elements.end(); ++it)
(*it)->retrieve_link_elements(this);
for (qdTriggerLinkList::iterator itl = root_element()->children().begin();
itl != root_element()->children().end();
++itl)
itl->activate();
return true;
}
bool qdTriggerChain::save_script(Common::WriteStream &fh, int indent) const {
for (int i = 0; i < indent; i++) {
fh.writeString("\t");
}
fh.writeString("<trigger_chain name=");
if (name()) {
fh.writeString(Common::String::format("\"%s\"", qdscr_XML_string(name())));
} else {
fh.writeString("\" \"");
}
fh.writeString(">\r\n");
root_element()->save_script(fh, indent + 1);
for (auto &it : _elements) {
it->save_script(fh, indent + 1);
};
for (int i = 0; i < indent; i++) {
fh.writeString("\t");
}
fh.writeString("</trigger_chain>\r\n");
return true;
}
void qdTriggerChain::quant(float dt) {
root_element()->quant(dt);
for (auto &it : _elements)
it->quant(dt);
}
bool qdTriggerChain::init_debug_check() {
root_element()->debug_set_done();
for (qdTriggerElementList::iterator it = _elements.begin(); it != _elements.end(); ++it)
(*it)->debug_set_done();
if (root_element()->is_active()) {
root_element()->debug_set_active();
root_element()->set_status(qdTriggerElement::TRIGGER_EL_DONE);
for (qdTriggerLinkList::iterator itl = root_element()->children().begin(); itl != root_element()->children().end(); ++itl) {
itl->activate();
}
}
for (qdTriggerElementList::iterator it = _elements.begin(); it != _elements.end(); ++it) {
if ((*it)->is_active())
(*it)->debug_set_active();
}
return true;
}
const char *qdTriggerChain::debug_comline() {
static const char *arg = "triggers_debug";
return arg;
}
bool qdTriggerChain::load_data(Common::SeekableReadStream &fh, int save_version) {
debugC(4, kDebugSave, " qdTriggerChain::load_data before: %d", (int)fh.pos());
int32 size = fh.readSint32LE();
if (size != (int)_elements.size()) {
return false;
}
if (!root_element()->load_data(fh, save_version)) {
return false;
}
for (auto &it : _elements) {
if (!it->load_data(fh, save_version)) {
return false;
}
}
debugC(4, kDebugSave, " qdTriggerChain::load_data after: %d", (int)fh.pos());
return true;
}
bool qdTriggerChain::save_data(Common::WriteStream &fh) const {
debugC(4, kDebugSave, " qdTriggerChain::save_data before: %d", (int)fh.pos());
fh.writeUint32LE(_elements.size());
if (!root_element()->save_data(fh)) {
return false;
}
for (auto &it : _elements) {
if (!it->save_data(fh)) {
return false;
}
}
debugC(4, kDebugSave, " qdTriggerChain::save_data after: %d", (int)fh.pos());
return true;
}
void qdTriggerChain::reset() {
root_element()->reset();
for (qdTriggerElementList::iterator it = _elements.begin(); it != _elements.end(); ++it)
(*it)->reset();
root_element()->set_status(qdTriggerElement::TRIGGER_EL_DONE);
for (qdTriggerLinkList::iterator itl = root_element()->children().begin(); itl != root_element()->children().end(); ++itl)
itl->activate();
}
bool qdTriggerChain::activate_links(const qdNamedObject *from) {
bool ret = false;
for (qdTriggerElementList::const_iterator it = _elements.begin(); it != _elements.end(); ++it) {
if ((*it)->object() == from) {
for (qdTriggerLinkList::iterator itl = (*it)->children().begin(); itl != (*it)->children().end(); ++itl)
itl->activate();
ret = true;
}
}
return ret;
}
bool qdTriggerChain::deactivate_object_triggers(const qdNamedObject *p) {
bool ret = false;
for (qdTriggerElementList::const_iterator it = _elements.begin(); it != _elements.end(); ++it) {
if ((*it)->object()) {
const qdNamedObject *obj = (*it)->object()->owner(qdNamedObjectType(p->named_object_type()));
if (obj == p) {
(*it)->deactivate(p);
ret = true;
}
}
}
return ret;
}
} // namespace QDEngine