scummvm/engines/qdengine/qdcore/qd_grid_zone.cpp

350 lines
8.7 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/qdengine.h"
#include "qdengine/qd_fwd.h"
#include "qdengine/parser/xml_tag_buffer.h"
#include "qdengine/parser/qdscr_parser.h"
#include "qdengine/qdcore/qd_game_scene.h"
#include "qdengine/qdcore/qd_game_object.h"
#include "qdengine/qdcore/qd_grid_zone.h"
namespace QDEngine {
qdGridZone::qdGridZone() : qdContour(CONTOUR_POLYGON),
_height(0),
_state(false),
_initial_state(false),
_state_on(true),
_state_off(false),
_update_timer(0),
_shadow_alpha(QD_NO_SHADOW_ALPHA),
_shadow_color(0) {
_state_on.set_owner(this);
_state_off.set_owner(this);
}
qdGridZone::qdGridZone(const qdGridZone &gz) : qdNamedObject(gz), qdContour(gz),
_state(gz._state),
_initial_state(gz._initial_state),
_height(gz._height),
_state_on(gz._state_on),
_state_off(gz._state_off),
_update_timer(gz._update_timer),
_shadow_alpha(gz._shadow_alpha),
_shadow_color(gz._shadow_color) {
}
qdGridZone::~qdGridZone() {
}
qdGridZone &qdGridZone::operator = (const qdGridZone &gz) {
if (this == &gz) return *this;
*static_cast<qdNamedObject *>(this) = gz;
*static_cast<qdContour *>(this) = gz;
_state = gz._state;
_initial_state = gz._initial_state;
_height = gz._height;
_state_on = gz._state_on;
_state_off = gz._state_off;
_update_timer = gz._update_timer;
_shadow_alpha = gz._shadow_alpha;
_shadow_color = gz._shadow_color;
return *this;
}
bool qdGridZone::load_script(const xml::tag *p) {
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_FLAG:
set_flag(xml::tag_buffer(*it).get_int());
break;
case QDSCR_STATE:
_initial_state = _state = (xml::tag_buffer(*it).get_int()) ? true : false;
break;
case QDSCR_GRID_ZONE_STATE:
if (const xml::tag * tg = it->search_subtag(QDSCR_STATE)) {
if (xml::tag_buffer(*tg).get_int())
_state_on.load_script(&*it);
else
_state_off.load_script(&*it);
}
break;
case QDSCR_GRID_ZONE_HEIGHT:
xml::tag_buffer(*it) > _height;
break;
case QDSCR_GRID_ZONE_CONTOUR:
case QDSCR_CONTOUR_POLYGON:
qdContour::load_script(&*it);
break;
case QDSCR_GRID_ZONE_SHADOW_COLOR:
xml::tag_buffer(*it) > _shadow_color;
break;
case QDSCR_GRID_ZONE_SHADOW_ALPHA:
xml::tag_buffer(*it) > _shadow_alpha;
break;
}
}
return true;
}
bool qdGridZone::save_script(Common::WriteStream &fh, int indent) const {
for (int i = 0; i < indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("<grid_zone name=\"%s\" grid_zone_height=\"%d\"", qdscr_XML_string(name()), _height));
if (flags()) {
if (debugChannelSet(-1, kDebugLog))
fh.writeString(Common::String::format(" flags=\"%s\"", flags() == 1 ? "ZONE_EXIT_FLAG" : flags() == 0 ? "" : "<error>"));
else
fh.writeString(Common::String::format(" flags=\"%d\"", flags()));
}
if (_state) {
fh.writeString(" state=\"1\"");
} else {
fh.writeString(" state=\"0\"");
}
if (_shadow_color) {
fh.writeString(Common::String::format(" shadow_color=\"%d\"", _shadow_color));
}
if (_shadow_alpha != QD_NO_SHADOW_ALPHA) {
fh.writeString(Common::String::format(" shadow_alpha=\"%d\"", _shadow_alpha));
}
fh.writeString(">\r\n");
_state_on.save_script(fh, indent + 1);
_state_off.save_script(fh, indent + 1);
if (contour_size()) {
qdContour::save_script(fh, indent + 1);
}
for (int i = 0; i < indent; i++) {
fh.writeString("\t");
}
fh.writeString("</grid_zone>\r\n");
return true;
}
bool qdGridZone::set_height(int _h) {
_height = _h;
if (_state) {
if (apply_zone()) {
qdGameScene *sp = static_cast<qdGameScene *>(owner());
_update_timer = sp->zone_update_count();
sp->inc_zone_update_count();
return true;
} else
return false;
}
return true;
}
bool qdGridZone::apply_zone() const {
if (!owner() || owner()->named_object_type() != QD_NAMED_OBJECT_SCENE) return false;
if (is_mask_empty()) return false;
qdCamera *camera = static_cast<qdGameScene *>(owner())->get_camera();
if (!camera) return false;
Vect2s pos = mask_pos();
pos.x -= mask_size().x / 2;
pos.y -= mask_size().y / 2;
// const byte* mask_ptr = mask_data();
if (_state) {
for (int y = 0; y < mask_size().y; y++) {
for (int x = 0; x < mask_size().x; x++) {
if (is_inside(pos + Vect2s(x, y))) {
// if(*mask_ptr++){
if (sGridCell * p = camera->get_cell(pos + Vect2s(x, y))) {
p->make_walkable();
p->set_height(_height);
}
}
}
}
} else {
for (int y = 0; y < mask_size().y; y++) {
for (int x = 0; x < mask_size().x; x++) {
if (is_inside(pos + Vect2s(x, y))) {
// if(*mask_ptr++){
if (sGridCell * p = camera->get_cell(pos + Vect2s(x, y))) {
p->make_impassable();
p->set_height(0);
}
}
}
}
}
return true;
}
bool qdGridZone::set_state(bool st) {
_state = st;
if (apply_zone()) {
debugC(3, kDebugLog, "[%d] zone condition: %s %s", g_system->getMillis(), transCyrillic(name()), (st) ? "on" : "off");
qdGameScene *sp = static_cast<qdGameScene *>(owner());
_update_timer = sp->zone_update_count();
sp->inc_zone_update_count();
return true;
}
return false;
}
bool qdGridZone::select(qdCamera *camera, bool bSelect) const {
if (is_mask_empty())
return false;
Vect2s pos = mask_pos();
pos.x -= mask_size().x / 2;
pos.y -= mask_size().y / 2;
// const byte* mask_ptr = mask_data();
if (bSelect) {
for (int y = 0; y < mask_size().y; y++) {
for (int x = 0; x < mask_size().x; x++) {
if (is_inside(pos + Vect2s(x, y))) {
// if(*mask_ptr++){
if (sGridCell * p = camera->get_cell(pos + Vect2s(x, y)))
p->select();
}
}
}
} else {
for (int y = 0; y < mask_size().y; y++) {
for (int x = 0; x < mask_size().x; x++) {
if (is_inside(pos + Vect2s(x, y))) {
// if(*mask_ptr++){
if (sGridCell * p = camera->get_cell(pos + Vect2s(x, y)))
p->deselect();
}
}
}
}
return true;
}
bool qdGridZone::select(bool bSelect) const {
assert(owner() || owner()->named_object_type() == QD_NAMED_OBJECT_SCENE);
qdNamedObject *obj = owner();
qdCamera *camera = static_cast<qdGameScene *>(obj)->get_camera();
if (!camera) return false;
return select(camera, bSelect);
}
bool qdGridZone::is_object_in_zone(const qdGameObject *obj) const {
if (!owner() || owner()->named_object_type() != QD_NAMED_OBJECT_SCENE || owner() != obj->owner()) return false;
return is_point_in_zone(Vect2f(obj->R().x, obj->R().y));
}
bool qdGridZone::is_point_in_zone(const Vect2f &r) const {
assert(owner());
qdCamera *camera = static_cast<qdGameScene *>(owner())->get_camera();
assert(camera);
Vect2s v = camera->get_cell_index(r.x, r.y);
if (v.x == -1) return false;
return is_inside(v);
}
qdGridZoneState *qdGridZone::get_state(const char *state_name) {
if (!strcmp(state_name, _state_on.name())) return &_state_on;
return &_state_off;
}
bool qdGridZone::load_data(Common::SeekableReadStream &fh, int saveVersion) {
debugC(3, kDebugSave, " qdGridZone::load_data before: %d", (int)fh.pos());
if (!qdNamedObject::load_data(fh, saveVersion)) {
return false;
}
char st = fh.readByte();
_update_timer = fh.readSint32LE();
_state = (st) ? true : false;
debugC(3, kDebugSave, " qdGridZone::load_data after: %d", (int)fh.pos());
return true;
}
bool qdGridZone::save_data(Common::WriteStream &fh) const {
debugC(3, kDebugSave, " qdGridZone::save_data before: %d", (int)fh.pos());
if (!qdNamedObject::save_data(fh)) {
return false;
}
fh.writeByte(_state);
fh.writeSint32LE(_update_timer);
debugC(3, kDebugSave, " qdGridZone::save_data after: %d", (int)fh.pos());
return true;
}
bool qdGridZone::init() {
return set_state(_initial_state);
}
bool qdGridZone::is_any_personage_in_zone() const {
if (!owner() || owner()->named_object_type() != QD_NAMED_OBJECT_SCENE) return false;
const qdGameScene *p = static_cast<const qdGameScene *>(owner());
return p->is_any_personage_in_zone(this);
}
} // namespace QDEngine