mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
350 lines
8.7 KiB
C++
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
|