Initial commit
This commit is contained in:
1251
engines/qdengine/qdcore/qd_animation.cpp
Normal file
1251
engines/qdengine/qdcore/qd_animation.cpp
Normal file
File diff suppressed because it is too large
Load Diff
318
engines/qdengine/qdcore/qd_animation.h
Normal file
318
engines/qdengine/qdcore/qd_animation.h
Normal file
@@ -0,0 +1,318 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_ANIMATION_H
|
||||
#define QDENGINE_QDCORE_QD_ANIMATION_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/system/graphics/gr_screen_region.h"
|
||||
#include "qdengine/system/graphics/gr_tile_animation.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_resource.h"
|
||||
#include "qdengine/qdcore/qd_animation_frame.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
class qdAnimationInfo;
|
||||
|
||||
const int QD_ANIMATION_FLAG_REFERENCE = 0x01;
|
||||
const int QD_ANIMATION_FLAG_LOOP = 0x04;
|
||||
const int QD_ANIMATION_FLAG_FLIP_HORIZONTAL = 0x08;
|
||||
const int QD_ANIMATION_FLAG_FLIP_VERTICAL = 0x10;
|
||||
const int QD_ANIMATION_FLAG_BLACK_FON = 0x20;
|
||||
const int QD_ANIMATION_FLAG_SUPPRESS_ALPHA = 0x40;
|
||||
const int QD_ANIMATION_FLAG_CROP = 0x80;
|
||||
const int QD_ANIMATION_FLAG_COMPRESS = 0x100;
|
||||
const int QD_ANIMATION_FLAG_TILE_COMPRESS = 0x200;
|
||||
|
||||
enum qdAnimationStatus {
|
||||
QD_ANIMATION_STOPPED = 0,
|
||||
QD_ANIMATION_PLAYING,
|
||||
QD_ANIMATION_PAUSED,
|
||||
QD_ANIMATION_END_PLAYING
|
||||
};
|
||||
|
||||
//! Анимация.
|
||||
class qdAnimation : public qdNamedObject, public qdResource {
|
||||
public:
|
||||
qdAnimation();
|
||||
qdAnimation(const qdAnimation &anm);
|
||||
~qdAnimation();
|
||||
|
||||
qdAnimation &operator = (const qdAnimation &anm);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_ANIMATION;
|
||||
}
|
||||
|
||||
const qdAnimationFrame *get_cur_frame() const;
|
||||
const qdAnimationFrame *get_cur_frame(float &scale) const;
|
||||
qdAnimationFrame *get_cur_frame();
|
||||
|
||||
void set_cur_frame(int number);
|
||||
int get_cur_frame_number() const;
|
||||
|
||||
qdAnimationFrame *get_frame(int number);
|
||||
const qdAnimationFrame *get_scaled_frame(int number, int scale_index) const;
|
||||
|
||||
int num_frames() const {
|
||||
return _num_frames;
|
||||
}
|
||||
|
||||
float length() const {
|
||||
return _length;
|
||||
}
|
||||
float cur_time() const {
|
||||
return _cur_time;
|
||||
}
|
||||
|
||||
void set_time(float tm) {
|
||||
_cur_time = tm;
|
||||
}
|
||||
|
||||
float cur_time_rel() const {
|
||||
if (_length > 0.01f)
|
||||
return _cur_time / _length;
|
||||
return 0.0f;
|
||||
}
|
||||
void set_time_rel(float tm) {
|
||||
if (tm < 0.0f) tm = 0.0f;
|
||||
if (tm > 0.99f) tm = 0.99f;
|
||||
_cur_time = _length * tm;
|
||||
}
|
||||
void advance_time(float tm);
|
||||
|
||||
void init_size();
|
||||
int size_x() const {
|
||||
return _sx;
|
||||
}
|
||||
int size_y() const {
|
||||
return _sy;
|
||||
}
|
||||
|
||||
int picture_size_x() const;
|
||||
int picture_size_y() const;
|
||||
|
||||
bool is_playing() const {
|
||||
return (_status == QD_ANIMATION_PLAYING ||
|
||||
_status == QD_ANIMATION_END_PLAYING);
|
||||
}
|
||||
|
||||
int status() const {
|
||||
return _status;
|
||||
}
|
||||
bool is_finished() const {
|
||||
return _is_finished;
|
||||
}
|
||||
bool need_stop() const {
|
||||
return _status == QD_ANIMATION_END_PLAYING;
|
||||
}
|
||||
|
||||
void start() {
|
||||
_status = QD_ANIMATION_PLAYING;
|
||||
_is_finished = false;
|
||||
_cur_time = 0.0f;
|
||||
}
|
||||
void stop() {
|
||||
_status = QD_ANIMATION_STOPPED;
|
||||
_is_finished = true;
|
||||
}
|
||||
void pause() {
|
||||
_status = QD_ANIMATION_PAUSED;
|
||||
}
|
||||
void resume() {
|
||||
_status = QD_ANIMATION_PLAYING;
|
||||
}
|
||||
|
||||
void quant(float dt);
|
||||
|
||||
void redraw(int x, int y, int z, int mode = 0) const;
|
||||
void redraw(int x, int y, int z, float scale, int mode = 0) const;
|
||||
|
||||
void redraw_rot(int x, int y, int z, float angle, int mode = 0) const;
|
||||
void redraw_rot(int x, int y, int z, float angle, const Vect2f &scale, int mode = 0) const;
|
||||
|
||||
void draw_mask(int x, int y, int z, uint32 mask_color, int mask_alpha, int mode = 0) const;
|
||||
void draw_mask(int x, int y, int z, uint32 mask_color, int mask_alpha, float scale, int mode = 0) const;
|
||||
|
||||
void draw_mask_rot(int x, int y, int z, float angle, uint32 mask_color, int mask_alpha, int mode = 0) const;
|
||||
void draw_mask_rot(int x, int y, int z, float angle, uint32 mask_color, int mask_alpha, const Vect2f &scale, int mode = 0) const;
|
||||
|
||||
void draw_contour(int x, int y, uint32 color) const;
|
||||
void draw_contour(int x, int y, uint32 color, float scale) const;
|
||||
|
||||
bool hit(int x, int y) const;
|
||||
bool hit(int x, int y, float scale) const;
|
||||
|
||||
bool add_frame(qdAnimationFrame *p, qdAnimationFrame *insert_pos = 0, bool insert_after = true);
|
||||
bool remove_frame(int number);
|
||||
bool remove_frame_range(int number0, int number1);
|
||||
bool reverse_frame_range(int number0, int number1);
|
||||
|
||||
void load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
const Common::Path qda_file() const {
|
||||
return _qda_file;
|
||||
}
|
||||
void qda_set_file(const Common::Path &fname);
|
||||
|
||||
bool qda_load(const Common::Path &fname);
|
||||
|
||||
bool load_resources();
|
||||
void free_resources();
|
||||
|
||||
bool scale(float coeff_x, float coeff_y);
|
||||
|
||||
bool crop();
|
||||
bool undo_crop();
|
||||
|
||||
Vect2i remove_edges();
|
||||
|
||||
bool compress();
|
||||
bool uncompress();
|
||||
bool tileCompress(grTileCompressionMethod method = TILE_UNCOMPRESSED, int tolerance = 0);
|
||||
|
||||
qdAnimationFrameList &frames_list() {
|
||||
return _frames;
|
||||
};
|
||||
|
||||
void create_reference(qdAnimation *p, const qdAnimationInfo *inf = NULL) const;
|
||||
bool is_reference(const qdAnimation *p) const {
|
||||
if (p->check_flag(QD_ANIMATION_FLAG_REFERENCE) && p->_parent == this) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
stop();
|
||||
_frames_ptr = &_frames;
|
||||
_parent = NULL;
|
||||
}
|
||||
|
||||
bool is_empty() const {
|
||||
return (_frames_ptr->empty());
|
||||
}
|
||||
|
||||
//! Возвращает область экрана, занимаемую анимацией.
|
||||
/**
|
||||
Координаты области - смещение от центра анимации.
|
||||
В mode задаются повороты анимации по горизонтали и вертикали
|
||||
(QD_ANIMATION_FLAG_FLIP_HORIZONTAL, QD_ANIMATION_FLAG_FLIP_VERTICAL)
|
||||
*/
|
||||
grScreenRegion screen_region(int mode = 0, float scale = 1.0f) const;
|
||||
|
||||
const qdAnimation *parent() const {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
// qdResource
|
||||
bool load_resource();
|
||||
bool free_resource();
|
||||
//! Устанавливает имя файла, в котором хранятся данные ресурса.
|
||||
void set_resource_file(const Common::Path &file_name) {
|
||||
qda_set_file(file_name);
|
||||
}
|
||||
//! Возвращает имя файла, в котором хранится анимация.
|
||||
const Common::Path resource_file() const {
|
||||
if (qda_file().empty()) {
|
||||
if (!check_flag(QD_ANIMATION_FLAG_REFERENCE) && !_frames.empty()) {
|
||||
if (_frames.front()->has_file())
|
||||
return _frames.front()->file();
|
||||
else
|
||||
return NULL;
|
||||
} else
|
||||
return NULL;
|
||||
} else
|
||||
return qda_file();
|
||||
}
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
uint32 resource_data_size() const;
|
||||
#endif
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
bool add_scale(float value);
|
||||
bool create_scaled_frames();
|
||||
|
||||
const Std::vector<float> &scales() const {
|
||||
if (check_flag(QD_ANIMATION_FLAG_REFERENCE) && _parent) return _parent->_scales;
|
||||
else return _scales;
|
||||
}
|
||||
void clear_scales() {
|
||||
_scales.clear();
|
||||
}
|
||||
|
||||
const grTileAnimation *tileAnimation() const {
|
||||
if (check_flag(QD_ANIMATION_FLAG_REFERENCE) && _parent)
|
||||
return _parent->_tileAnimation;
|
||||
else
|
||||
return _tileAnimation;
|
||||
}
|
||||
|
||||
static Common::String flag2str(int fl, bool truncate = false, bool icon = false);
|
||||
static Common::String status2str(int fl, bool truncate = false);
|
||||
|
||||
private:
|
||||
int _sx;
|
||||
int _sy;
|
||||
|
||||
enum {
|
||||
qda_version = 104
|
||||
};
|
||||
|
||||
float _length;
|
||||
float _cur_time;
|
||||
|
||||
float _playback_speed;
|
||||
|
||||
int _num_frames;
|
||||
|
||||
const qdAnimationFrameList *_frames_ptr;
|
||||
qdAnimationFrameList _frames;
|
||||
|
||||
const qdAnimationFrameList *_scaled_frames_ptr;
|
||||
qdAnimationFrameList _scaled_frames;
|
||||
Std::vector<float> _scales;
|
||||
|
||||
grTileAnimation *_tileAnimation;
|
||||
|
||||
int _status;
|
||||
bool _is_finished;
|
||||
|
||||
Common::Path _qda_file;
|
||||
|
||||
const qdAnimation *_parent;
|
||||
|
||||
int get_scale_index(float &scale_value) const;
|
||||
|
||||
bool copy_frames(const qdAnimation &anm);
|
||||
void clear_frames();
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_ANIMATION_H
|
||||
75
engines/qdengine/qdcore/qd_animation_frame.cpp
Normal file
75
engines/qdengine/qdcore/qd_animation_frame.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/* 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/file.h"
|
||||
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_animation_frame.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdAnimationFrame::qdAnimationFrame() : _start_time(0.0f),
|
||||
_length(0.0f) {
|
||||
}
|
||||
|
||||
qdAnimationFrame::qdAnimationFrame(const qdAnimationFrame &frm) : qdSprite(frm),
|
||||
_start_time(frm._start_time),
|
||||
_length(frm._length) {
|
||||
}
|
||||
|
||||
qdAnimationFrame::~qdAnimationFrame() {
|
||||
free();
|
||||
}
|
||||
|
||||
qdAnimationFrame &qdAnimationFrame::operator = (const qdAnimationFrame &frm) {
|
||||
if (this == &frm) return *this;
|
||||
|
||||
*static_cast<qdSprite *>(this) = frm;
|
||||
|
||||
_start_time = frm._start_time;
|
||||
_length = frm._length;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
qdAnimationFrame *qdAnimationFrame::clone() const {
|
||||
return new qdAnimationFrame(*this);
|
||||
}
|
||||
|
||||
void qdAnimationFrame::qda_load(Common::SeekableReadStream *fh, int version) {
|
||||
/*int32 fl = */fh->readSint32LE();
|
||||
_start_time = fh->readFloatLE();
|
||||
_length = fh->readFloatLE();
|
||||
|
||||
qdSprite::qda_load(fh, version);
|
||||
}
|
||||
|
||||
bool qdAnimationFrame::load_resources() {
|
||||
if (!load()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdAnimationFrame::free_resources() {
|
||||
free();
|
||||
}
|
||||
} // namespace QDEngine
|
||||
72
engines/qdengine/qdcore/qd_animation_frame.h
Normal file
72
engines/qdengine/qdcore/qd_animation_frame.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_ANIMATION_FRAME_H
|
||||
#define QDENGINE_QDCORE_QD_ANIMATION_FRAME_H
|
||||
|
||||
#include "qdengine/qdcore/qd_sprite.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Кадр анимации.
|
||||
class qdAnimationFrame : public qdSprite {
|
||||
public:
|
||||
qdAnimationFrame();
|
||||
qdAnimationFrame(const qdAnimationFrame &frm);
|
||||
~qdAnimationFrame();
|
||||
|
||||
qdAnimationFrame &operator = (const qdAnimationFrame &frm);
|
||||
|
||||
qdAnimationFrame *clone() const;
|
||||
|
||||
float start_time() const {
|
||||
return _start_time;
|
||||
}
|
||||
float end_time() const {
|
||||
return _start_time + _length;
|
||||
}
|
||||
float length() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
void set_start_time(float tm) {
|
||||
_start_time = tm;
|
||||
}
|
||||
void set_length(float tm) {
|
||||
_length = tm;
|
||||
}
|
||||
|
||||
virtual void qda_load(class Common::SeekableReadStream *fh, int version = 100);
|
||||
|
||||
bool load_resources();
|
||||
void free_resources();
|
||||
|
||||
private:
|
||||
float _start_time;
|
||||
float _length;
|
||||
};
|
||||
|
||||
typedef Std::list<qdAnimationFrame *> qdAnimationFrameList;
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_ANIMATION_FRAME_H
|
||||
128
engines/qdengine/qdcore/qd_animation_info.cpp
Normal file
128
engines/qdengine/qdcore/qd_animation_info.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/xmath.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_dispatcher.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
#include "qdengine/qdcore/qd_animation_info.h"
|
||||
#include "qdengine/qdcore/qd_animation.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdAnimationInfo::qdAnimationInfo() : _speed(0.0f), _animation_speed(1.0f) {
|
||||
}
|
||||
|
||||
qdAnimationInfo::qdAnimationInfo(const qdAnimationInfo &p) : qdNamedObject(p),
|
||||
_speed(p._speed),
|
||||
_animation_speed(p._animation_speed) {
|
||||
}
|
||||
|
||||
qdAnimationInfo::~qdAnimationInfo() {
|
||||
}
|
||||
|
||||
void qdAnimationInfo::load_script(const xml::tag *p) {
|
||||
int fl;
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_SPEED:
|
||||
xml::tag_buffer(*it) > _speed;
|
||||
break;
|
||||
case QDSCR_ANIMATION_SPEED:
|
||||
xml::tag_buffer(*it) > _animation_speed;
|
||||
break;
|
||||
case QDSCR_ANIMATION:
|
||||
set_animation_name(it->data());
|
||||
break;
|
||||
case QDSCR_FLAG:
|
||||
xml::tag_buffer(*it) > fl;
|
||||
set_flag(fl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool qdAnimationInfo::save_script(Common::WriteStream &fh, int indent) const {
|
||||
Common::String res;
|
||||
|
||||
if (flags()) {
|
||||
if (debugChannelSet(-1, kDebugLog))
|
||||
res += Common::String::format(" flags=\"%s\"", qdAnimation::flag2str(flags()).c_str());
|
||||
else
|
||||
res += Common::String::format(" flags=\"%d\"", flags());
|
||||
}
|
||||
|
||||
if (_speed > 0.01f)
|
||||
res += Common::String::format(" speed=\"%f\"", _speed);
|
||||
|
||||
if (_animation_speed != 1.0f)
|
||||
res += Common::String::format(" animation_speed=\"%f\"", _animation_speed);
|
||||
|
||||
if (animation_name())
|
||||
res += Common::String::format(" animation=\"%s\"", qdscr_XML_string(animation_name()));
|
||||
|
||||
if (!res.empty()) {
|
||||
for (int i = 0; i < indent; i++)
|
||||
fh.writeString("\t");
|
||||
|
||||
fh.writeString("<animation_info");
|
||||
fh.writeString(res);
|
||||
fh.writeString("/>\r\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qdAnimationInfo &qdAnimationInfo::operator = (const qdAnimationInfo &p) {
|
||||
if (this == &p)
|
||||
return *this;
|
||||
|
||||
*static_cast<qdNamedObject *>(this) = p;
|
||||
|
||||
_speed = p._speed;
|
||||
_animation_speed = p._animation_speed;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
qdAnimation *qdAnimationInfo::animation() const {
|
||||
if (animation_name()) {
|
||||
if (qdGameScene *p = static_cast<qdGameScene *>(owner(QD_NAMED_OBJECT_SCENE))) {
|
||||
if (qdAnimation *anm = p->get_animation(animation_name()))
|
||||
return anm;
|
||||
}
|
||||
|
||||
if (qdGameDispatcher *p = qd_get_game_dispatcher())
|
||||
return p->get_animation(animation_name());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
85
engines/qdengine/qdcore/qd_animation_info.h
Normal file
85
engines/qdengine/qdcore/qd_animation_info.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_ANIMATION_INFO_H
|
||||
#define QDENGINE_QDCORE_QD_ANIMATION_INFO_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdAnimation;
|
||||
|
||||
//! Информация об анимации.
|
||||
class qdAnimationInfo : public qdNamedObject {
|
||||
public:
|
||||
qdAnimationInfo();
|
||||
qdAnimationInfo(const qdAnimationInfo &p);
|
||||
~qdAnimationInfo();
|
||||
|
||||
qdAnimationInfo &operator = (const qdAnimationInfo &p);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_ANIMATION_INFO;
|
||||
}
|
||||
|
||||
float speed() const {
|
||||
return _speed;
|
||||
}
|
||||
void set_speed(float sp) {
|
||||
_speed = sp;
|
||||
}
|
||||
|
||||
float animation_speed() const {
|
||||
return _animation_speed;
|
||||
}
|
||||
void set_animation_speed(float sp) {
|
||||
_animation_speed = sp;
|
||||
}
|
||||
|
||||
qdAnimation *animation() const;
|
||||
const char *animation_name() const {
|
||||
return name();
|
||||
}
|
||||
|
||||
void load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
void set_animation_name(const char *name) {
|
||||
set_name(name);
|
||||
}
|
||||
void free_animation_name() {
|
||||
set_name(0);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
float _speed;
|
||||
float _animation_speed;
|
||||
};
|
||||
|
||||
typedef Std::vector<qdAnimationInfo> qdAnimationInfoVector;
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_ANIMATION_INFO_H
|
||||
451
engines/qdengine/qdcore/qd_animation_set.cpp
Normal file
451
engines/qdengine/qdcore/qd_animation_set.cpp
Normal file
@@ -0,0 +1,451 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_animation_set.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdAnimationSet::qdAnimationSet() {
|
||||
_start_angle = 0.0f;
|
||||
}
|
||||
|
||||
qdAnimationSet::qdAnimationSet(const qdAnimationSet &set) : qdNamedObject(set),
|
||||
_start_angle(set._start_angle),
|
||||
_animations(set._animations),
|
||||
_walk_sound_frequency(set._walk_sound_frequency),
|
||||
_static_animations(set._static_animations),
|
||||
_start_animations(set._start_animations),
|
||||
_stop_animations(set._stop_animations),
|
||||
_turn_animation(set._turn_animation) {
|
||||
_turn_animation.set_owner(this);
|
||||
|
||||
for (int i = 0; i < size(); i++) {
|
||||
_animations[i].set_owner(this);
|
||||
_static_animations[i].set_owner(this);
|
||||
_static_animations[i].set_owner(this);
|
||||
_stop_animations[i].set_owner(this);
|
||||
}
|
||||
}
|
||||
|
||||
qdAnimationSet::~qdAnimationSet() {
|
||||
_animations.clear();
|
||||
_static_animations.clear();
|
||||
_start_animations.clear();
|
||||
_stop_animations.clear();
|
||||
}
|
||||
|
||||
qdAnimationSet &qdAnimationSet::operator = (const qdAnimationSet &set) {
|
||||
if (this == &set) return *this;
|
||||
|
||||
*static_cast<qdNamedObject *>(this) = set;
|
||||
|
||||
_start_angle = set._start_angle;
|
||||
|
||||
_animations = set._animations;
|
||||
_static_animations = set._static_animations;
|
||||
_start_animations = set._stop_animations;
|
||||
_stop_animations = set._stop_animations;
|
||||
_walk_sound_frequency = set._walk_sound_frequency;
|
||||
|
||||
_turn_animation = set._turn_animation;
|
||||
_turn_animation.set_owner(this);
|
||||
|
||||
for (int i = 0; i < size(); i++) {
|
||||
_animations[i].set_owner(this);
|
||||
_static_animations[i].set_owner(this);
|
||||
_start_animations[i].set_owner(this);
|
||||
_stop_animations[i].set_owner(this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void qdAnimationSet::resize(int sz) {
|
||||
_animations.resize(sz);
|
||||
_static_animations.resize(sz);
|
||||
_start_animations.resize(sz);
|
||||
_stop_animations.resize(sz);
|
||||
_walk_sound_frequency.resize(sz, 1);
|
||||
|
||||
for (int i = 0; i < size(); i++) {
|
||||
_animations[i].set_owner(this);
|
||||
_static_animations[i].set_owner(this);
|
||||
}
|
||||
}
|
||||
|
||||
qdAnimationInfo *qdAnimationSet::get_animation_info(int index) {
|
||||
if (index >= 0 && index < size())
|
||||
return &_animations[index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qdAnimationSet::get_angle_index(float direction_angle, int dir_count) {
|
||||
if (direction_angle < 0.0f)
|
||||
direction_angle += 2.0f * M_PI;
|
||||
|
||||
int index = round(direction_angle * float(dir_count) / (2.0f * M_PI));
|
||||
if (index >= dir_count) index -= dir_count;
|
||||
if (index < 0) index += dir_count;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
float qdAnimationSet::get_index_angle(int index, int dir_count) {
|
||||
return index * 2.f * M_PI / dir_count;
|
||||
}
|
||||
|
||||
float qdAnimationSet::get_index_angle(int direction_index) const {
|
||||
return get_index_angle(direction_index, size()) + _start_angle;
|
||||
}
|
||||
|
||||
int qdAnimationSet::get_angle_index(float direction_angle) const {
|
||||
return get_angle_index(direction_angle - _start_angle, size());
|
||||
}
|
||||
|
||||
qdAnimationInfo *qdAnimationSet::get_animation_info(float direction_angle) {
|
||||
int index = get_angle_index(direction_angle);
|
||||
return get_animation_info(index);
|
||||
}
|
||||
|
||||
qdAnimationInfo *qdAnimationSet::get_static_animation_info(int index) {
|
||||
if (index >= 0 && index < size())
|
||||
return &_static_animations[index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdAnimationInfo *qdAnimationSet::get_static_animation_info(float direction_angle) {
|
||||
int index = get_angle_index(direction_angle);
|
||||
return get_static_animation_info(index);
|
||||
}
|
||||
|
||||
qdAnimationInfo *qdAnimationSet::get_start_animation_info(int index) {
|
||||
if (index >= 0 && index < size())
|
||||
return &_start_animations[index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdAnimationInfo *qdAnimationSet::get_start_animation_info(float direction_angle) {
|
||||
int index = get_angle_index(direction_angle);
|
||||
return get_start_animation_info(index);
|
||||
}
|
||||
|
||||
qdAnimationInfo *qdAnimationSet::get_stop_animation_info(int index) {
|
||||
if (index >= 0 && index < size())
|
||||
return &_stop_animations[index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdAnimationInfo *qdAnimationSet::get_stop_animation_info(float direction_angle) {
|
||||
int index = get_angle_index(direction_angle);
|
||||
return get_stop_animation_info(index);
|
||||
}
|
||||
|
||||
qdAnimation *qdAnimationSet::get_turn_animation() const {
|
||||
return _turn_animation.animation();
|
||||
}
|
||||
|
||||
void qdAnimationSet::load_script(const xml::tag *p) {
|
||||
int index = 0;
|
||||
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_SIZE:
|
||||
resize(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_ANIMATION_INFO:
|
||||
if (index < size())
|
||||
_animations[index].load_script(&*it);
|
||||
else if (index < size() * 2)
|
||||
_static_animations[index - size()].load_script(&*it);
|
||||
else if (index < size() * 3)
|
||||
_start_animations[index - size() * 2].load_script(&*it);
|
||||
else
|
||||
_stop_animations[index - size() * 3].load_script(&*it);
|
||||
|
||||
index++;
|
||||
break;
|
||||
case QDSCR_ANIMATION_SET_TURN:
|
||||
_turn_animation.set_animation_name(it->data());
|
||||
break;
|
||||
case QDSCR_ANIMATION_SET_START_ANGLE:
|
||||
xml::tag_buffer(*it) > _start_angle;
|
||||
break;
|
||||
case QDSCR_OBJECT_STATE_WALK_SOUND_FREQUENCY: {
|
||||
xml::tag_buffer buf(*it);
|
||||
_walk_sound_frequency.resize(it->data_size());
|
||||
for (int i = 0; i < it->data_size(); i++)
|
||||
buf > _walk_sound_frequency[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool qdAnimationSet::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<animation_set name=\"%s\"", qdscr_XML_string(name())));
|
||||
|
||||
if (_turn_animation.animation_name()) {
|
||||
fh.writeString(Common::String::format(" animation_turn=\"%s\"", qdscr_XML_string(_turn_animation.animation_name())));
|
||||
}
|
||||
|
||||
fh.writeString(Common::String::format(" size=\"%d\"", size()));
|
||||
|
||||
if (fabs(_start_angle) > FLT_EPS) {
|
||||
fh.writeString(Common::String::format(" start_angle=\"%f\"", _start_angle));
|
||||
}
|
||||
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
for (auto &it : _animations) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (auto &it : _static_animations) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (auto &it : _start_animations) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (auto &it : _stop_animations) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
if (_walk_sound_frequency.size()) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString(Common::String::format("<walk_sound_frequency>%u", _walk_sound_frequency.size()));
|
||||
for (uint i = 0; i < _walk_sound_frequency.size(); i++) {
|
||||
fh.writeString(Common::String::format(" %f", _walk_sound_frequency[i]));
|
||||
}
|
||||
|
||||
fh.writeString("</walk_sound_frequency>\r\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</animation_set>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdAnimationSet::load_animations(const qdNamedObject *res_owner) {
|
||||
if (qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher()) {
|
||||
for (auto &it : _animations) {
|
||||
if (qdAnimation *p = it.animation()) {
|
||||
dp->load_resource(p, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : _static_animations) {
|
||||
if (qdAnimation *p = it.animation()) {
|
||||
dp->load_resource(p, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (auto &it : _start_animations) {
|
||||
if (qdAnimation *p = it.animation()) {
|
||||
dp->load_resource(p, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : _stop_animations) {
|
||||
if (qdAnimation *p = it.animation()) {
|
||||
dp->load_resource(p, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
if (qdAnimation *p = _turn_animation.animation())
|
||||
dp->load_resource(p, res_owner);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdAnimationSet::free_animations(const qdNamedObject *res_owner) {
|
||||
if (qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher()) {
|
||||
for (auto &it : _animations) {
|
||||
if (qdAnimation *p = it.animation()) {
|
||||
dp->release_resource(p, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : _static_animations) {
|
||||
if (qdAnimation *p = it.animation()) {
|
||||
dp->release_resource(p, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : _start_animations) {
|
||||
if (qdAnimation *p = it.animation()) {
|
||||
dp->release_resource(p, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : _stop_animations) {
|
||||
if (qdAnimation *p = it.animation()) {
|
||||
dp->release_resource(p, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
if (qdAnimation *p = _turn_animation.animation())
|
||||
dp->release_resource(p, res_owner);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdAnimationSet::scale_animations(float coeff_x, float coeff_y) {
|
||||
bool res = true;
|
||||
|
||||
for (auto &it : _animations) {
|
||||
qdAnimation *p = it.animation();
|
||||
if (p)
|
||||
if (!p->scale(coeff_x, coeff_y)) res = false;
|
||||
}
|
||||
for (auto &it : _static_animations) {
|
||||
qdAnimation *p = it.animation();
|
||||
if (p)
|
||||
if (!p->scale(coeff_x, coeff_y)) res = false;
|
||||
}
|
||||
for (auto &it : _start_animations) {
|
||||
qdAnimation *p = it.animation();
|
||||
if (p)
|
||||
if (!p->scale(coeff_x, coeff_y)) res = false;
|
||||
}
|
||||
for (auto &it : _stop_animations) {
|
||||
qdAnimation *p = it.animation();
|
||||
if (p)
|
||||
if (!p->scale(coeff_x, coeff_y)) res = false;
|
||||
}
|
||||
|
||||
if (qdAnimation *p = _turn_animation.animation())
|
||||
if (!p->scale(coeff_x, coeff_y)) res = false;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool qdAnimationSet::register_resources(const qdNamedObject *res_owner) {
|
||||
if (qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher()) {
|
||||
for (auto &it : _animations) {
|
||||
if (qdAnimation *p = it.animation())
|
||||
dp->register_resource(p, res_owner);
|
||||
}
|
||||
for (auto &it : _static_animations) {
|
||||
if (qdAnimation *p = it.animation())
|
||||
dp->register_resource(p, res_owner);
|
||||
}
|
||||
for (auto &it : _start_animations) {
|
||||
if (qdAnimation *p = it.animation())
|
||||
dp->register_resource(p, res_owner);
|
||||
}
|
||||
for (auto &it : _stop_animations) {
|
||||
if (qdAnimation *p = it.animation())
|
||||
dp->register_resource(p, res_owner);
|
||||
}
|
||||
if (qdAnimation *p = _turn_animation.animation())
|
||||
dp->register_resource(p, res_owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdAnimationSet::unregister_resources(const qdNamedObject *res_owner) {
|
||||
if (qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher()) {
|
||||
for (auto &it : _animations) {
|
||||
if (qdAnimation *p = it.animation())
|
||||
dp->unregister_resource(p, res_owner);
|
||||
}
|
||||
for (auto &it : _static_animations) {
|
||||
if (qdAnimation *p = it.animation())
|
||||
dp->unregister_resource(p, res_owner);
|
||||
}
|
||||
for (auto &it : _start_animations) {
|
||||
if (qdAnimation *p = it.animation())
|
||||
dp->unregister_resource(p, res_owner);
|
||||
}
|
||||
for (auto &it : _stop_animations) {
|
||||
if (qdAnimation *p = it.animation())
|
||||
dp->unregister_resource(p, res_owner);
|
||||
}
|
||||
if (qdAnimation *p = _turn_animation.animation())
|
||||
dp->unregister_resource(p, res_owner);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float qdAnimationSet::adjust_angle(float angle) const {
|
||||
int dir = get_angle_index(angle);
|
||||
if (dir == -1) return 0.0f;
|
||||
|
||||
return get_index_angle(dir);
|
||||
}
|
||||
|
||||
float qdAnimationSet::walk_sound_frequency(int direction_index) const {
|
||||
if (direction_index < 0 || direction_index >= (int)_walk_sound_frequency.size())
|
||||
return 1;
|
||||
else
|
||||
return _walk_sound_frequency[direction_index];
|
||||
}
|
||||
|
||||
float qdAnimationSet::walk_sound_frequency(float direction_angle) const {
|
||||
int index = get_angle_index(direction_angle);
|
||||
return walk_sound_frequency(index);
|
||||
}
|
||||
|
||||
void qdAnimationSet::set_walk_sound_frequency(int direction_index, float freq) {
|
||||
assert(direction_index >= 0);
|
||||
|
||||
if (direction_index >= (int)_walk_sound_frequency.size())
|
||||
_walk_sound_frequency.resize(direction_index + 1, 1);
|
||||
|
||||
_walk_sound_frequency[direction_index] = freq;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
128
engines/qdengine/qdcore/qd_animation_set.h
Normal file
128
engines/qdengine/qdcore/qd_animation_set.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_ANIMATION_SET_H
|
||||
#define QDENGINE_QDCORE_QD_ANIMATION_SET_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
#include "qdengine/qdcore/qd_animation.h"
|
||||
#include "qdengine/qdcore/qd_animation_info.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
class qdAnimationSet : public qdNamedObject {
|
||||
public:
|
||||
qdAnimationSet();
|
||||
qdAnimationSet(const qdAnimationSet &set);
|
||||
~qdAnimationSet();
|
||||
|
||||
qdAnimationSet &operator = (const qdAnimationSet &set);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_ANIMATION_SET;
|
||||
}
|
||||
|
||||
int size() const {
|
||||
return _animations.size();
|
||||
}
|
||||
void resize(int sz);
|
||||
|
||||
//! выдает индекс походки и остановки, соответствующих углу
|
||||
int get_angle_index(float direction_angle) const;
|
||||
|
||||
//! выдает угол походки и остановки, соответствующих индексу
|
||||
float get_index_angle(int direction_index) const;
|
||||
|
||||
//! Возвращает ближайшее к angle направление, для которого есть анимация.
|
||||
float adjust_angle(float angle) const;
|
||||
|
||||
qdAnimationInfo *get_animation_info(int index = 0);
|
||||
qdAnimationInfo *get_animation_info(float direction_angle);
|
||||
|
||||
qdAnimationInfo *get_static_animation_info(int index = 0);
|
||||
qdAnimationInfo *get_static_animation_info(float direction_angle);
|
||||
|
||||
qdAnimationInfo *get_start_animation_info(int index = 0);
|
||||
qdAnimationInfo *get_start_animation_info(float direction_angle);
|
||||
|
||||
qdAnimationInfo *get_stop_animation_info(int index = 0);
|
||||
qdAnimationInfo *get_stop_animation_info(float direction_angle);
|
||||
|
||||
qdAnimation *get_turn_animation() const;
|
||||
qdAnimationInfo *get_turn_animation_info() {
|
||||
return &_turn_animation;
|
||||
}
|
||||
void set_turn_animation(const char *animation_name) {
|
||||
_turn_animation.set_animation_name(animation_name);
|
||||
}
|
||||
|
||||
float walk_sound_frequency(int direction_index) const;
|
||||
float walk_sound_frequency(float direction_angle) const;
|
||||
void set_walk_sound_frequency(int direction_index, float freq);
|
||||
|
||||
bool load_animations(const qdNamedObject *res_owner);
|
||||
bool free_animations(const qdNamedObject *res_owner);
|
||||
//! Регистрация ресурсов набора в диспетчере ресурсов.
|
||||
bool register_resources(const qdNamedObject *res_owner);
|
||||
//! Отмена регистрации ресурсов набора в диспетчере ресурсов.
|
||||
bool unregister_resources(const qdNamedObject *res_owner);
|
||||
|
||||
bool scale_animations(float coeff_x, float coeff_y);
|
||||
|
||||
void load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
float start_angle() const {
|
||||
return _start_angle;
|
||||
}
|
||||
void set_start_angle(float v) {
|
||||
_start_angle = v;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Угол, соответствующий первому направлению в походке.
|
||||
/**
|
||||
Если нулевой - первое направление вправо.
|
||||
*/
|
||||
float _start_angle;
|
||||
|
||||
qdAnimationInfoVector _animations;
|
||||
qdAnimationInfoVector _static_animations;
|
||||
qdAnimationInfoVector _start_animations;
|
||||
qdAnimationInfoVector _stop_animations;
|
||||
|
||||
/// анимация поворота, полный оборот начиная с направления вправо
|
||||
qdAnimationInfo _turn_animation;
|
||||
|
||||
//! Коэффициенты для частоты звука походки.
|
||||
Std::vector<float> _walk_sound_frequency;
|
||||
|
||||
static int get_angle_index(float direction_angle, int dir_count);
|
||||
static float get_index_angle(int index, int dir_count);
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_ANIMATION_SET_H
|
||||
42
engines/qdengine/qdcore/qd_animation_set_info.cpp
Normal file
42
engines/qdengine/qdcore/qd_animation_set_info.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_animation_set_info.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_game_scene.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdAnimationSet *qdAnimationSetInfo::animation_set() const {
|
||||
if (name()) {
|
||||
if (qdGameScene *p = static_cast<qdGameScene *>(owner(QD_NAMED_OBJECT_SCENE))) {
|
||||
if (qdAnimationSet *set = p->get_animation_set(name()))
|
||||
return set;
|
||||
}
|
||||
|
||||
if (qdGameDispatcher *p = qdGameDispatcher::get_dispatcher())
|
||||
return p->get_animation_set(name());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
48
engines/qdengine/qdcore/qd_animation_set_info.h
Normal file
48
engines/qdengine/qdcore/qd_animation_set_info.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_ANIMATION_SET_INFO_H
|
||||
#define QDENGINE_QDCORE_QD_ANIMATION_SET_INFO_H
|
||||
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdAnimationSet;
|
||||
|
||||
//! Информация о наборе анимаций.
|
||||
class qdAnimationSetInfo : public qdNamedObject {
|
||||
public:
|
||||
qdAnimationSetInfo() { }
|
||||
~qdAnimationSetInfo() { }
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_ANIMATION_SET_INFO;
|
||||
}
|
||||
|
||||
qdAnimationSet *animation_set() const;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_ANIMATION_SET_INFO_H
|
||||
243
engines/qdengine/qdcore/qd_animation_set_preview.cpp
Normal file
243
engines/qdengine/qdcore/qd_animation_set_preview.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/* 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/system.h"
|
||||
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_animation_set.h"
|
||||
#include "qdengine/qdcore/qd_animation_set_preview.h"
|
||||
#include "qdengine/qdcore/qd_camera.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdAnimationSetPreview::qdAnimationSetPreview(qdAnimationSet *p) :
|
||||
_graph_d(0),
|
||||
_animation_set(p),
|
||||
_preview_mode(VIEW_WALK_ANIMATIONS) {
|
||||
_animation = new qdAnimation;
|
||||
|
||||
_camera = new qdCamera;
|
||||
_camera->set_focus(2000.0f);
|
||||
_camera_angle = 45;
|
||||
|
||||
_start_time = 0;
|
||||
_back_color = 0x000000FF;
|
||||
_grid_color = 0x00FF00FF;
|
||||
|
||||
set_direction(0);
|
||||
|
||||
_cell_size = 100;
|
||||
|
||||
_personage_height = float(_animation->size_y());
|
||||
|
||||
p->load_animations(NULL);
|
||||
}
|
||||
|
||||
qdAnimationSetPreview::~qdAnimationSetPreview() {
|
||||
_animation_set->free_animations(NULL);
|
||||
|
||||
delete _animation;
|
||||
delete _camera;
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::set_graph_dispatcher(grDispatcher *p) {
|
||||
_graph_d = p;
|
||||
set_screen(Vect2s(0, 0), Vect2s(p->get_SizeX(), p->get_SizeY()));
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::start() {
|
||||
_start_time = g_system->getMillis();
|
||||
|
||||
_animation->start();
|
||||
_cell_offset = 0.0f;
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::quant() {
|
||||
int time = g_system->getMillis();
|
||||
float tm = float(time - _start_time) / 1000.0f;
|
||||
_start_time = time;
|
||||
|
||||
if (tm >= 0.3f) return;
|
||||
|
||||
quant(tm);
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::quant(float tm) {
|
||||
_animation->quant(tm);
|
||||
|
||||
_cell_offset -= _personage_speed * tm;
|
||||
while (_cell_offset <= -float(_cell_size)) _cell_offset += float(_cell_size);
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::redraw() {
|
||||
grDispatcher *gp = grDispatcher::set_instance(_graph_d);
|
||||
|
||||
grDispatcher::instance()->fill(_back_color);
|
||||
|
||||
redraw_grid();
|
||||
|
||||
Vect2s v = _camera->global2scr(Vect3f(0.0f, 0.0f, _personage_height / 2.0f));
|
||||
float scale = _camera->get_scale(Vect3f(0.0f, 0.0f, _personage_height / 2.0f));
|
||||
_animation->redraw(v.x, v.y, scale);
|
||||
|
||||
Vect2s v0 = _camera->global2scr(Vect3f(0.0f, 0.0f, _personage_height));
|
||||
Vect2s v1 = _camera->global2scr(Vect3f(0.0f, 0.0f, 0.0f));
|
||||
|
||||
const int rect_sz = 4;
|
||||
grDispatcher::instance()->rectangle(v.x - rect_sz / 2, v.y - rect_sz / 2, rect_sz, rect_sz, _grid_color, _grid_color, GR_FILLED);
|
||||
|
||||
const int line_sz = 10;
|
||||
grDispatcher::instance()->line(v0.x - line_sz, v0.y, v0.x + line_sz, v0.y, _grid_color);
|
||||
grDispatcher::instance()->line(v1.x - line_sz, v1.y, v1.x + line_sz, v1.y, _grid_color);
|
||||
grDispatcher::instance()->line(v0.x, v0.y, v1.x, v1.y, _grid_color);
|
||||
grDispatcher::instance()->rectangle(_screen_offset.x, _screen_offset.y, _screen_size.x, _screen_size.y, _grid_color, 0, GR_OUTLINED);
|
||||
grDispatcher::instance()->flush();
|
||||
|
||||
grDispatcher::set_instance(gp);
|
||||
}
|
||||
|
||||
bool qdAnimationSetPreview::set_direction(int dir) {
|
||||
bool result = false;
|
||||
|
||||
_animation->clear();
|
||||
_personage_speed = 0.0f;
|
||||
_direction = dir;
|
||||
_cell_offset = 0.0f;
|
||||
|
||||
float angle = _animation_set->get_index_angle(_direction) * 180.0f / M_PI;
|
||||
_camera->rotate_and_scale(_camera_angle, 0, angle, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
qdAnimationInfo *p = NULL;
|
||||
if (_preview_mode == VIEW_WALK_ANIMATIONS)
|
||||
p = _animation_set->get_animation_info(dir);
|
||||
else if (_preview_mode == VIEW_STATIC_ANIMATIONS)
|
||||
p = _animation_set->get_static_animation_info(dir);
|
||||
else if (_preview_mode == VIEW_START_ANIMATIONS)
|
||||
p = _animation_set->get_start_animation_info(dir);
|
||||
else if (_preview_mode == VIEW_STOP_ANIMATIONS)
|
||||
p = _animation_set->get_stop_animation_info(dir);
|
||||
|
||||
if (p) {
|
||||
qdAnimation *ap = p->animation();
|
||||
if (ap) {
|
||||
ap->create_reference(_animation, p);
|
||||
result = true;
|
||||
}
|
||||
_personage_speed = p->speed();
|
||||
}
|
||||
|
||||
_animation->start();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::set_cell_size(int sz) {
|
||||
_cell_size = sz;
|
||||
|
||||
_animation->start();
|
||||
_cell_offset = 0.0f;
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::set_screen(Vect2s offs, Vect2s size) {
|
||||
if (!_graph_d) return;
|
||||
|
||||
_screen_offset = offs;
|
||||
_screen_size = size;
|
||||
|
||||
_camera->set_scr_size(size.x, size.y);
|
||||
_camera->set_scr_center(offs.x + size.x / 2, offs.y + size.y * 3 / 4);
|
||||
|
||||
_graph_d->setClip(offs.x, offs.y, offs.x + size.x, offs.y + size.y);
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::redraw_grid() {
|
||||
float size = 0;
|
||||
Vect2f p = _camera->scr2plane(_screen_offset);
|
||||
if (fabs(p.x) > size) size = fabs(p.x);
|
||||
if (fabs(p.y) > size) size = fabs(p.y);
|
||||
p = _camera->scr2plane(_screen_offset + _screen_size);
|
||||
if (fabs(p.x) > size) size = fabs(p.x);
|
||||
if (fabs(p.y) > size) size = fabs(p.y);
|
||||
p = _camera->scr2plane(Vect2s(_screen_offset.x + _screen_size.x, _screen_offset.y));
|
||||
if (fabs(p.x) > size) size = fabs(p.x);
|
||||
if (fabs(p.y) > size) size = fabs(p.y);
|
||||
p = _camera->scr2plane(Vect2s(_screen_offset.x, _screen_offset.y + _screen_size.y));
|
||||
if (fabs(p.x) > size) size = fabs(p.x);
|
||||
if (fabs(p.y) > size) size = fabs(p.y);
|
||||
|
||||
int sz = round(size) + _cell_size;
|
||||
sz -= sz % _cell_size;
|
||||
for (int i = -sz; i <= sz; i += _cell_size) {
|
||||
int dx = round(_cell_offset);
|
||||
|
||||
Vect3f v00 = _camera->global2camera_coord(Vect3f(i + dx, -sz, 0));
|
||||
Vect3f v10 = _camera->global2camera_coord(Vect3f(i + dx, sz, 0));
|
||||
if (_camera->line_cutting(v00, v10)) {
|
||||
Vect2s v0 = _camera->camera_coord2scr(v00);
|
||||
Vect2s v1 = _camera->camera_coord2scr(v10);
|
||||
grDispatcher::instance()->line(v0.x, v0.y, v1.x, v1.y, _grid_color, 0);
|
||||
}
|
||||
|
||||
v00 = _camera->global2camera_coord(Vect3f(-sz + dx, i, 0));
|
||||
v10 = _camera->global2camera_coord(Vect3f(sz + dx, i, 0));
|
||||
if (_camera->line_cutting(v00, v10)) {
|
||||
Vect2s v0 = _camera->camera_coord2scr(v00);
|
||||
Vect2s v1 = _camera->camera_coord2scr(v10);
|
||||
grDispatcher::instance()->line(v0.x, v0.y, v1.x, v1.y, _grid_color, 0);
|
||||
}
|
||||
/*
|
||||
v0 = _camera->global2scr(Vect3f(-sz + dx,i,0));
|
||||
v1 = _camera->global2scr(Vect3f(sz + dx,i,0));
|
||||
grDispatcher::instance()->line(v0.x,v0.y,v1.x,v1.y,_grid_color,0);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::set_camera_angle(int ang) {
|
||||
_camera_angle = ang;
|
||||
|
||||
float angle = _animation_set->get_index_angle(_direction) * 180.0f / M_PI;
|
||||
_camera->rotate_and_scale(_camera_angle, 0, angle, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
float qdAnimationSetPreview::camera_focus() {
|
||||
return _camera->get_focus();
|
||||
}
|
||||
|
||||
void qdAnimationSetPreview::set_camera_focus(float f) {
|
||||
_camera->set_focus(f);
|
||||
}
|
||||
|
||||
bool qdAnimationSetPreview::set_phase(float phase) {
|
||||
if (!_animation->is_empty()) {
|
||||
if (!_animation->is_playing())
|
||||
_animation->start();
|
||||
|
||||
_cell_offset = 0.0f;
|
||||
_animation->set_time(0.0f);
|
||||
quant(_animation->length() * phase);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
150
engines/qdengine/qdcore/qd_animation_set_preview.h
Normal file
150
engines/qdengine/qdcore/qd_animation_set_preview.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_ANIMATION_SET_PREVIEW_H
|
||||
#define QDENGINE_QDCORE_ANIMATION_SET_PREVIEW_H
|
||||
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdCamera;
|
||||
|
||||
class qdAnimation;
|
||||
class qdAnimationSet;
|
||||
|
||||
//! Превью походки.
|
||||
class qdAnimationSetPreview {
|
||||
public:
|
||||
enum preview_mode_t {
|
||||
VIEW_WALK_ANIMATIONS,
|
||||
VIEW_STATIC_ANIMATIONS,
|
||||
VIEW_START_ANIMATIONS,
|
||||
VIEW_STOP_ANIMATIONS
|
||||
};
|
||||
|
||||
qdAnimationSetPreview(qdAnimationSet *p);
|
||||
~qdAnimationSetPreview();
|
||||
|
||||
preview_mode_t preview_mode() const {
|
||||
return _preview_mode;
|
||||
}
|
||||
void set_preview_mode(preview_mode_t md) {
|
||||
_preview_mode = md;
|
||||
}
|
||||
|
||||
void set_screen(Vect2s offs, Vect2s size);
|
||||
|
||||
uint32 back_color() const {
|
||||
return _back_color;
|
||||
}
|
||||
void set_back_color(uint32 col) {
|
||||
_back_color = col;
|
||||
}
|
||||
|
||||
uint32 grid_color() const {
|
||||
return _grid_color;
|
||||
}
|
||||
void set_grid_color(uint32 col) {
|
||||
_grid_color = col;
|
||||
}
|
||||
|
||||
int camera_angle() const {
|
||||
return _camera_angle;
|
||||
}
|
||||
void set_camera_angle(int ang);
|
||||
|
||||
float camera_focus();
|
||||
void set_camera_focus(float f);
|
||||
|
||||
int cell_size() const {
|
||||
return _cell_size;
|
||||
}
|
||||
void set_cell_size(int sz);
|
||||
|
||||
float personage_speed() const {
|
||||
return _personage_speed;
|
||||
}
|
||||
void set_personage_speed(float sp) {
|
||||
_personage_speed = sp;
|
||||
}
|
||||
|
||||
float personage_height() const {
|
||||
return _personage_height;
|
||||
}
|
||||
void set_personage_height(float h) {
|
||||
_personage_height = h;
|
||||
}
|
||||
|
||||
int direction() const {
|
||||
return _direction;
|
||||
}
|
||||
bool set_direction(int dir);
|
||||
|
||||
bool set_phase(float phase);
|
||||
|
||||
void set_graph_dispatcher(grDispatcher *p);
|
||||
|
||||
void start();
|
||||
void quant();
|
||||
void quant(float tm);
|
||||
|
||||
void redraw();
|
||||
|
||||
const qdAnimation *cur_animation() const {
|
||||
return _animation;
|
||||
}
|
||||
|
||||
private:
|
||||
int _start_time;
|
||||
|
||||
int _direction;
|
||||
//float speed_;
|
||||
|
||||
float _personage_speed;
|
||||
float _personage_height;
|
||||
|
||||
qdAnimation *_animation;
|
||||
qdAnimationSet *_animation_set;
|
||||
|
||||
qdCamera *_camera;
|
||||
int _camera_angle;
|
||||
|
||||
grDispatcher *_graph_d;
|
||||
|
||||
uint32 _back_color;
|
||||
uint32 _grid_color;
|
||||
|
||||
int _cell_size;
|
||||
float _cell_offset;
|
||||
|
||||
Vect2s _screen_offset;
|
||||
Vect2s _screen_size;
|
||||
|
||||
preview_mode_t _preview_mode;
|
||||
|
||||
void redraw_grid();
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_ANIMATION_SET_PREVIEW_H
|
||||
1562
engines/qdengine/qdcore/qd_camera.cpp
Normal file
1562
engines/qdengine/qdcore/qd_camera.cpp
Normal file
File diff suppressed because it is too large
Load Diff
505
engines/qdengine/qdcore/qd_camera.h
Normal file
505
engines/qdengine/qdcore/qd_camera.h
Normal file
@@ -0,0 +1,505 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_CAMERA_H
|
||||
#define QDENGINE_QDCORE_QD_CAMERA_H
|
||||
|
||||
#include "qdengine/qdcore/qd_d3dutils.h"
|
||||
#include "qdengine/qdcore/qd_camera_mode.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class sGridCell {
|
||||
public:
|
||||
//! Атрибуты
|
||||
enum cell_attribute_t {
|
||||
//! ячейка выделена
|
||||
CELL_SELECTED = 0x01,
|
||||
//! ячейка непроходима
|
||||
CELL_IMPASSABLE = 0x02,
|
||||
//! ячейка занята объектом
|
||||
CELL_OCCUPIED = 0x04,
|
||||
//! ячейка занята персонажем
|
||||
CELL_PERSONAGE_OCCUPIED = 0x08,
|
||||
//! по ячейке проходит путь персонажа
|
||||
CELL_PERSONAGE_PATH = 0x10
|
||||
};
|
||||
|
||||
sGridCell() {
|
||||
_attributes = CELL_IMPASSABLE;
|
||||
}
|
||||
sGridCell(uint16 atr, int16 h) {
|
||||
_attributes = atr;
|
||||
}
|
||||
~sGridCell() { }
|
||||
|
||||
bool is_walkable() const {
|
||||
return !check_attribute(CELL_IMPASSABLE);
|
||||
}
|
||||
void make_impassable() {
|
||||
set_attribute(CELL_IMPASSABLE);
|
||||
}
|
||||
void make_walkable() {
|
||||
drop_attribute(CELL_IMPASSABLE);
|
||||
}
|
||||
|
||||
void select() {
|
||||
set_attribute(CELL_SELECTED);
|
||||
}
|
||||
void deselect() {
|
||||
drop_attribute(CELL_SELECTED);
|
||||
}
|
||||
void toggle_select() {
|
||||
toggle_attribute(CELL_SELECTED);
|
||||
}
|
||||
bool is_selected() const {
|
||||
return check_attribute(CELL_SELECTED);
|
||||
}
|
||||
|
||||
int16 height() const {
|
||||
return 0;
|
||||
}
|
||||
void set_height(int16 h) { }
|
||||
|
||||
void set_attribute(uint32 attr) {
|
||||
_attributes |= attr;
|
||||
}
|
||||
void toggle_attribute(uint32 attr) {
|
||||
_attributes ^= attr;
|
||||
}
|
||||
void drop_attribute(uint32 attr) {
|
||||
_attributes &= ~attr;
|
||||
}
|
||||
bool check_attribute(uint32 attr) const {
|
||||
if (_attributes & attr) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
uint32 attributes() const {
|
||||
return _attributes;
|
||||
}
|
||||
void set_attributes(uint32 attr) {
|
||||
_attributes = attr;
|
||||
}
|
||||
|
||||
bool clear() {
|
||||
_attributes = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
byte _attributes;
|
||||
};
|
||||
|
||||
enum qdCameraRedrawMode {
|
||||
QDCAM_GRID_ABOVE,
|
||||
QDCAM_GRID_ZBUFFER,
|
||||
QDCAM_GRID_NONE
|
||||
};
|
||||
|
||||
class qdCamera {
|
||||
public:
|
||||
qdCamera();
|
||||
~qdCamera();
|
||||
|
||||
// Устанавливет параметры клетки с координатами cell_pos
|
||||
// по параметрам клетки cell
|
||||
bool set_grid_cell(const Vect2s &cell_pos, const sGridCell &cell);
|
||||
bool set_grid_cell_attributes(const Vect2s &cell_pos, int attr);
|
||||
|
||||
//! Устанавливает атрибуты для клеток из прямоугольника на сетке с ценром center_pos и размерами size.
|
||||
bool set_grid_attributes(const Vect2s ¢er_pos, const Vect2s &size, int attr);
|
||||
//! Очищает атрибуты для клеток из прямоугольника на сетке с ценром center_pos и размерами size.
|
||||
bool drop_grid_attributes(const Vect2s ¢er_pos, const Vect2s &size, int attr);
|
||||
//! Возвращает true, если в прямоугольнике на сетке ЕСТЬ ХОТЯ БЫ ОДНА ячейка с атрибутами attr.
|
||||
bool check_grid_attributes(const Vect2s ¢er_pos, const Vect2s &size, int attr) const;
|
||||
//! Возвращает количество ячеек в заданной области, имеющих именно аттрибуты attr
|
||||
int cells_num_with_exact_attributes(const Vect2s ¢er_pos, const Vect2s &size, int attr) const;
|
||||
|
||||
//! Устанавливает атрибуты для линии клеток.
|
||||
bool set_grid_line_attributes(const Vect2s &start_pos, const Vect2s &end_pos, const Vect2s &size, int attr);
|
||||
//! Очищает атрибуты для линии клеток.
|
||||
bool drop_grid_line_attributes(const Vect2s &start_pos, const Vect2s &end_pos, const Vect2s &size, int attr);
|
||||
//! Возвращает true, если в линии на сетке есть хотя бы одна ячейка с атрибутами attr.
|
||||
bool check_grid_line_attributes(const Vect2s &start_pos, const Vect2s &end_pos, const Vect2s &size, int attr) const;
|
||||
|
||||
bool is_walkable(const Vect2s ¢er_pos, const Vect2s &size, bool ignore_personages = false) const;
|
||||
|
||||
//! Устанавливает атрибуты attr для всех клеток сетки.
|
||||
bool set_grid_attributes(int attr);
|
||||
//! Очищает атрибуты attr для всех клеток сетки.
|
||||
bool drop_grid_attributes(int attr);
|
||||
|
||||
sGridCell *get_cell(const Vect2s &cell_pos);
|
||||
const sGridCell *get_cell(const Vect2s &cell_pos) const;
|
||||
|
||||
// Восстанавливает параметры клетки (сейчас - делает ее непроходимой
|
||||
// с нулевой высотой)
|
||||
bool restore_grid_cell(const Vect2s cell_pos);
|
||||
|
||||
void cycle_coords(int &x, int &y) const;
|
||||
|
||||
void set_redraw_mode(int md) const {
|
||||
_redraw_mode = md;
|
||||
}
|
||||
int get_redraw_mode() const {
|
||||
return _redraw_mode;
|
||||
}
|
||||
|
||||
void set_grid_size(int xs, int ys);
|
||||
|
||||
void scale_grid(int sx, int sy, int csx, int csy);
|
||||
void resize_grid(int sx, int sy);
|
||||
|
||||
int get_grid_sx() const {
|
||||
return _GSX;
|
||||
}
|
||||
int get_grid_sy() const {
|
||||
return _GSY;
|
||||
}
|
||||
|
||||
const sGridCell *get_grid() const {
|
||||
return _grid;
|
||||
}
|
||||
|
||||
int get_cell_sx() const {
|
||||
return _cellSX;
|
||||
}
|
||||
int get_cell_sy() const {
|
||||
return _cellSY;
|
||||
}
|
||||
|
||||
void set_cell_size(int csx, int csy) {
|
||||
_cellSX = csx;
|
||||
_cellSY = csy;
|
||||
}
|
||||
|
||||
void clear_grid();
|
||||
|
||||
// rotateAndScaling
|
||||
void rotate_and_scale(float XA, float YA, float ZA, float kX, float kY, float kZ);
|
||||
|
||||
float get_focus() const {
|
||||
return _focus;
|
||||
}
|
||||
void set_focus(float focus) {
|
||||
_focus = focus;
|
||||
}
|
||||
|
||||
void set_R(const float r);
|
||||
float get_R() const {
|
||||
return _m_fR;
|
||||
}
|
||||
|
||||
float get_x_angle() const {
|
||||
return _xAngle;
|
||||
}
|
||||
float get_y_angle() const {
|
||||
return _yAngle;
|
||||
}
|
||||
float get_z_angle() const {
|
||||
return _zAngle;
|
||||
}
|
||||
|
||||
inline void set_scr_size(int xs, int ys) {
|
||||
_scrSize.x = xs;
|
||||
_scrSize.y = ys;
|
||||
}
|
||||
|
||||
const Vect2i &get_scr_size() const {
|
||||
return _scrSize;
|
||||
}
|
||||
|
||||
// getScrSizeX
|
||||
int get_scr_sx() const {
|
||||
return _scrSize.x;
|
||||
}
|
||||
// getScrSizeY
|
||||
int get_scr_sy() const {
|
||||
return _scrSize.y;
|
||||
}
|
||||
|
||||
void set_scr_center(int xc, int yc) {
|
||||
_scrCenter.x = xc;
|
||||
_scrCenter.y = yc;
|
||||
}
|
||||
|
||||
const Vect2i &get_scr_center() const {
|
||||
return _scrCenter;
|
||||
}
|
||||
|
||||
int get_scr_center_x() const {
|
||||
return _scrCenter.x;
|
||||
}
|
||||
int get_scr_center_y() const {
|
||||
return _scrCenter.y;
|
||||
}
|
||||
|
||||
const Vect2i screen_center_limit_x() const;
|
||||
const Vect2i screen_center_limit_y() const;
|
||||
|
||||
const Vect2i &get_scr_offset() const {
|
||||
return _scrOffset;
|
||||
}
|
||||
void set_scr_offset(const Vect2i &offs) {
|
||||
_scrOffset = offs;
|
||||
}
|
||||
|
||||
const Vect2i &get_scr_center_initial() const {
|
||||
return _scrCenterInitial;
|
||||
}
|
||||
void set_scr_center_initial(const Vect2i &v) {
|
||||
_scrCenterInitial = v;
|
||||
}
|
||||
|
||||
void move_scr_center(int dxc, int dyc);
|
||||
|
||||
float scrolling_phase_x() const;
|
||||
float scrolling_phase_y() const;
|
||||
|
||||
const Vect3f scr2plane(const Vect2s &scrPoint) const;
|
||||
const Vect3f rscr2plane(const Vect2s &rscrPoint) const;
|
||||
|
||||
const Vect3f scr2plane_camera_coord(const Vect2s &scrPoint) const;
|
||||
const Vect3f rscr2plane_camera_coord(const Vect2s &scrPoint) const;
|
||||
const Vect2s plane2scr(const Vect3f &plnPoint) const;
|
||||
const Vect2s plane2rscr(const Vect3f &plnPoint) const;
|
||||
|
||||
const Vect3f rscr2camera_coord(const Vect2s &rScrPoint, float z) const;
|
||||
const Vect2s camera_coord2rscr(const Vect3f &coord) const;
|
||||
|
||||
const Vect2s rscr2scr(const Vect2s &v) const;
|
||||
const Vect2s scr2rscr(const Vect2s &v) const;
|
||||
|
||||
const Vect2s camera_coord2scr(const Vect3f &coord) const;
|
||||
|
||||
const Vect3f scr2global(const Vect2s &vScrPoint, float zInCameraCoord) const;
|
||||
const Vect3f rscr2global(const Vect2s rScrPoint, const float zInCameraCoord) const;
|
||||
const Vect3f global2camera_coord(const Vect3f &glCoord) const;
|
||||
const Vect3f camera_coord2global(const Vect3f &v) const;
|
||||
|
||||
const Vect2s global2scr(const Vect3f &glCoord) const;
|
||||
const Vect2s global2rscr(const Vect3f &glCoord) const;
|
||||
|
||||
//обрезание отрезка по плоскости отсечения камеры
|
||||
//возвращает false, если отрезок вообеще невидим
|
||||
bool line_cutting(Vect3f &b, Vect3f &e) const;
|
||||
//! Обрезка линиии, так чтобы она за сетку не выходила.
|
||||
/**
|
||||
Все координаты - сеточные, т.е. индексы ячеек сетки.
|
||||
*/
|
||||
bool clip_grid_line(Vect2s &v0, Vect2s &v1) const;
|
||||
|
||||
// getKScale
|
||||
float get_scale(const Vect3f &glCoord) const;
|
||||
|
||||
const Vect3f &get_grid_center() const {
|
||||
return _gridCenter;
|
||||
}
|
||||
void set_grid_center(const Vect3f &v) {
|
||||
_gridCenter = v;
|
||||
}
|
||||
|
||||
const sGridCell *get_cell(float X, float Y) const;
|
||||
const Vect2s get_cell_index(float X, float Y, bool grid_crop = true) const;
|
||||
const Vect2s get_cell_index(const Vect3f &v, bool grid_crop = true) const;
|
||||
const Vect3f get_cell_coords(int x_idx, int y_idx) const;
|
||||
const Vect3f get_cell_coords(const Vect2s &idxs) const;
|
||||
|
||||
void reset_all_select();
|
||||
//принимает глобальные координаты
|
||||
bool select_cell(int x, int y);
|
||||
|
||||
//принимает глобальные координаты
|
||||
bool deselect_cell(int x, int y);
|
||||
|
||||
void load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
//! Инициализация данных, вызывается при старте и перезапуске игры.
|
||||
bool init();
|
||||
|
||||
bool draw_grid() const;
|
||||
bool draw_cell(int x, int y, int z, int penWidth, uint32 color) const;
|
||||
|
||||
//! Установка текущего режима камеры.
|
||||
/**
|
||||
Если объект нулевой, то берется объект по-умолчанию.
|
||||
*/
|
||||
bool set_mode(const qdCameraMode &mode, qdGameObjectAnimated *object = NULL);
|
||||
//! Возвращает true, если в данный момент можно менять режим камеры.
|
||||
bool can_change_mode() const;
|
||||
|
||||
//! Установка объекта, за которым камера следит по умолчанию.
|
||||
void set_default_object(qdGameObjectAnimated *p) {
|
||||
_default_object = p;
|
||||
}
|
||||
|
||||
//! Обсчет логики (движения камеры и т.д), параметр - время в секундах.
|
||||
bool quant(float dt);
|
||||
|
||||
//! Возвращает false, если вся рабочая область камеры находится за пределами экрана.
|
||||
/**
|
||||
Параметр - дополнительное смещение центра рабочей области камеры.
|
||||
*/
|
||||
bool is_visible(const Vect2i ¢er_offs = Vect2i(0, 0)) const;
|
||||
|
||||
void set_cycle(bool cx, bool cy) {
|
||||
_cycle_x = cx;
|
||||
_cycle_y = cy;
|
||||
}
|
||||
|
||||
void dump_grid(const char *file_name) const;
|
||||
|
||||
//! Параметры функции масштабирования
|
||||
float scale_pow() const {
|
||||
return _scale_pow;
|
||||
}
|
||||
void set_scale_pow(float sp) {
|
||||
_scale_pow = sp;
|
||||
}
|
||||
float scale_z_offset() const {
|
||||
return _scale_z_offset;
|
||||
};
|
||||
void set_scale_z_offset(float szo) {
|
||||
_scale_z_offset = szo;
|
||||
};
|
||||
|
||||
bool need_perspective_correction() const {
|
||||
return (fabs(_scale_pow - 1) > 0.001 || fabs(_scale_z_offset) > 0.001);
|
||||
}
|
||||
|
||||
//! Возвращает режим работы камеры по умолчанию.
|
||||
const qdCameraMode &default_mode() const {
|
||||
return _default_mode;
|
||||
}
|
||||
//! Установка режима работы камеры по умолчанию.
|
||||
void set_default_mode(const qdCameraMode &mode) {
|
||||
_default_mode = mode;
|
||||
}
|
||||
|
||||
static qdCamera *current_camera() {
|
||||
return _current_camera;
|
||||
}
|
||||
static void set_current_camera(qdCamera *p) {
|
||||
_current_camera = p;
|
||||
}
|
||||
|
||||
MATRIX3D const &get_view_matrix() const {
|
||||
return _m_cam;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
MATRIX3D _m_cam;
|
||||
float _m_fR;
|
||||
float _xAngle, _yAngle, _zAngle;
|
||||
|
||||
int _GSX, _GSY;
|
||||
sGridCell *_grid;
|
||||
|
||||
bool _cycle_x;
|
||||
bool _cycle_y;
|
||||
|
||||
int _cellSX, _cellSY;
|
||||
float _focus;//! расстояние до ближней плоскости отсечения
|
||||
// расстояние от центра рабочей области до
|
||||
// верхнего левого угла окна
|
||||
Vect2i _scrCenter;
|
||||
|
||||
// начальное расстояние от центра рабочей области до
|
||||
// верхнего левого угла окна
|
||||
Vect2i _scrCenterInitial;
|
||||
|
||||
// размер рабочей области
|
||||
Vect2i _scrSize;
|
||||
// смещение рабочей области
|
||||
Vect2i _scrOffset;
|
||||
|
||||
// Координаты центра сетки
|
||||
Vect3f _gridCenter;
|
||||
|
||||
mutable int _redraw_mode;
|
||||
|
||||
//! Текущий режим работы камеры.
|
||||
qdCameraMode _current_mode;
|
||||
|
||||
//! Время в секуднах с установки текущего режима.
|
||||
float _current_mode_work_time;
|
||||
bool _current_mode_switch;
|
||||
|
||||
//! Объект, за которым следит камера.
|
||||
qdGameObjectAnimated *_current_object;
|
||||
|
||||
//! Объект, за которым камера следит по умолчанию.
|
||||
qdGameObjectAnimated *_default_object;
|
||||
//! Режим работы камеры по умолчанию.
|
||||
qdCameraMode _default_mode;
|
||||
|
||||
//! Параметры функции ускоренного масштабирования из get_scale()
|
||||
float _scale_pow;
|
||||
float _scale_z_offset;
|
||||
|
||||
static qdCamera *_current_camera;
|
||||
|
||||
static const float _NEAR_PLANE; //ближная плоскость отсечения
|
||||
static const float _FAR_PLANE; //дальняя
|
||||
|
||||
enum {
|
||||
clLEFT = 1,
|
||||
clRIGHT = 2,
|
||||
clBOTTOM = 4,
|
||||
clTOP = 8
|
||||
};
|
||||
|
||||
inline int clip_out_code(const Vect2s &v) const {
|
||||
int code = 0;
|
||||
if (v.y >= _GSY)
|
||||
code |= clTOP;
|
||||
else if (v.y < 0)
|
||||
code |= clBOTTOM;
|
||||
if (v.x >= _GSX)
|
||||
code |= clRIGHT;
|
||||
else if (v.x < 0)
|
||||
code |= clLEFT;
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
void clip_center_coords(int &x, int &y) const;
|
||||
};
|
||||
|
||||
inline Vect3f To3D(const Vect2f &v) {
|
||||
return Vect3f(v.x, v.y, 0);
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_CAMERA_H
|
||||
133
engines/qdengine/qdcore/qd_camera_mode.cpp
Normal file
133
engines/qdengine/qdcore/qd_camera_mode.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/* 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_camera_mode.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdCameraMode::qdCameraMode() : _camera_mode(MODE_UNASSIGNED),
|
||||
_work_time(0.0f),
|
||||
_scrolling_speed(100.0f),
|
||||
_scrolling_distance(100),
|
||||
_smooth_switch(false),
|
||||
_center_offset(0, 0) {
|
||||
}
|
||||
|
||||
bool qdCameraMode::load_script(const xml::tag *p) {
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
xml::tag_buffer buf(*it);
|
||||
|
||||
switch (it->ID()) {
|
||||
case QDSCR_TYPE:
|
||||
set_camera_mode(camera_mode_t(buf.get_int()));
|
||||
break;
|
||||
case QDSCR_TIME:
|
||||
set_work_time(buf.get_float());
|
||||
break;
|
||||
case QDSCR_CAMERA_SCROLLING_SPEED:
|
||||
set_scrolling_speed(buf.get_float());
|
||||
break;
|
||||
case QDSCR_CAMERA_SCROLLING_DIST:
|
||||
set_scrolling_distance(buf.get_int());
|
||||
break;
|
||||
case QDSCR_CAMERA_SMOOTH_SWITCH:
|
||||
_smooth_switch = (buf.get_int()) ? true : false;
|
||||
break;
|
||||
case QDSCR_CAMERA_SCREEN_CENTER:
|
||||
buf > _center_offset.x > _center_offset.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCameraMode::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString(Common::String::format("<camera_mode type=\"%d\"", (int)camera_mode()));
|
||||
fh.writeString(Common::String::format(" scrolling_speed=\"%f\"", _scrolling_speed));
|
||||
fh.writeString(Common::String::format(" scrolling_dist=\"%d\"", _scrolling_distance));
|
||||
|
||||
if (_center_offset.x || _center_offset.y) {
|
||||
fh.writeString(Common::String::format(" camera_screen_center=\"%d %d\"", _center_offset.x, _center_offset.y));
|
||||
}
|
||||
|
||||
if (has_work_time()) {
|
||||
fh.writeString(Common::String::format(" time=\"%f\"", work_time()));
|
||||
}
|
||||
|
||||
if (smooth_switch()) {
|
||||
fh.writeString(" smooth_switch=\"1\"");
|
||||
}
|
||||
|
||||
fh.writeString("/>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCameraMode::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
debugC(4, kDebugSave, " qdCameraMode::load_data(): before: %d", (int)fh.pos());
|
||||
/*int mode = */fh.readSint32LE();
|
||||
_work_time = fh.readFloatLE();
|
||||
_scrolling_speed = fh.readFloatLE();
|
||||
_scrolling_distance = fh.readSint32LE();
|
||||
_center_offset.x = fh.readSint32LE();
|
||||
_center_offset.y = fh.readSint32LE();
|
||||
|
||||
char switch_flag = fh.readByte();
|
||||
_smooth_switch = (switch_flag) ? true : false;
|
||||
debugC(4, kDebugSave, " qdCameraMode::load_data(): after: %d", (int)fh.pos());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCameraMode::save_data(Common::WriteStream &fh) const {
|
||||
debugC(4, kDebugSave, " qdCameraMode::save_data(): before: %d", (int)fh.pos());
|
||||
|
||||
fh.writeSint32LE((int)_camera_mode);
|
||||
fh.writeFloatLE(_work_time);
|
||||
fh.writeFloatLE(_scrolling_speed);
|
||||
fh.writeSint32LE(_scrolling_distance);
|
||||
fh.writeSint32LE(_center_offset.x);
|
||||
fh.writeSint32LE(_center_offset.y);
|
||||
|
||||
|
||||
if (_smooth_switch) {
|
||||
fh.writeByte(1);
|
||||
} else {
|
||||
fh.writeByte(0);
|
||||
}
|
||||
|
||||
debugC(4, kDebugSave, " qdCameraMode::save_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
152
engines/qdengine/qdcore/qd_camera_mode.h
Normal file
152
engines/qdengine/qdcore/qd_camera_mode.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_CAMERA_MODE_H
|
||||
#define QDENGINE_QDCORE_QD_CAMERA_MODE_H
|
||||
|
||||
#include "qdengine/xmath.h"
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdGameObjectState;
|
||||
class qdGameObjectAnimated;
|
||||
|
||||
//! Режим работы камеры.
|
||||
class qdCameraMode {
|
||||
public:
|
||||
qdCameraMode();
|
||||
~qdCameraMode() { }
|
||||
|
||||
//! идентификаторы режимов камеры
|
||||
enum camera_mode_t {
|
||||
//! камера не выпускает объект с экрана
|
||||
MODE_OBJECT_ON_SCREEN,
|
||||
//! камера жестко привязана к объекту
|
||||
MODE_CENTER_OBJECT,
|
||||
//! камера все время центруется на объекте
|
||||
MODE_FOLLOW_OBJECT,
|
||||
//! когда объект подходит к краю экрана камера плавно на нем центруется
|
||||
MODE_CENTER_OBJECT_WHEN_LEAVING,
|
||||
//! режим не установлен
|
||||
MODE_UNASSIGNED
|
||||
};
|
||||
|
||||
void set_camera_mode(camera_mode_t mode) {
|
||||
_camera_mode = mode;
|
||||
}
|
||||
camera_mode_t camera_mode() const {
|
||||
return _camera_mode;
|
||||
}
|
||||
|
||||
void set_work_time(float tm) {
|
||||
_work_time = tm;
|
||||
}
|
||||
float work_time() const {
|
||||
return _work_time;
|
||||
}
|
||||
bool has_work_time() const {
|
||||
return _work_time > 0.001f;
|
||||
}
|
||||
|
||||
void set_scrolling_speed(float v) {
|
||||
_scrolling_speed = v;
|
||||
}
|
||||
float scrolling_speed() const {
|
||||
return _scrolling_speed;
|
||||
}
|
||||
|
||||
void set_scrolling_distance(int dist) {
|
||||
_scrolling_distance = dist;
|
||||
}
|
||||
int scrolling_distance() const {
|
||||
return _scrolling_distance;
|
||||
}
|
||||
|
||||
bool smooth_switch() const {
|
||||
return _smooth_switch;
|
||||
}
|
||||
void set_smooth_switch(bool v) {
|
||||
_smooth_switch = v;
|
||||
}
|
||||
|
||||
const Vect2i ¢er_offset() const {
|
||||
return _center_offset;
|
||||
}
|
||||
void set_center_offset(const Vect2i &offs) {
|
||||
_center_offset = offs;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
private:
|
||||
|
||||
//! Идентификатор режима.
|
||||
camera_mode_t _camera_mode;
|
||||
|
||||
//! Время работы режима (в секундах).
|
||||
/**
|
||||
По истечении этого времени камера переключается
|
||||
на активного персонажа (если он есть).
|
||||
|
||||
Если это время нулевое, то сменить режим можно будет
|
||||
только в принудительном порядке из триггера.
|
||||
*/
|
||||
float _work_time;
|
||||
|
||||
//! Скорость, с которой камера скроллируется (в пикселах в секунду).
|
||||
float _scrolling_speed;
|
||||
|
||||
//! Расстояние от центра объекта до края экрана, при котором включается скроллинг.
|
||||
/**
|
||||
В режимах, когда камера не дает объекту выйти за пределы экрана или
|
||||
центруется на объекте когда он близко к краю экрана.
|
||||
|
||||
Задается в пикселах.
|
||||
*/
|
||||
int _scrolling_distance;
|
||||
|
||||
//! Смещение центра экрана в пикселах.
|
||||
/**
|
||||
Позволяет задавать режим, когда камера, центруясь на объекте,
|
||||
держит его в определенной точке экрана.
|
||||
*/
|
||||
Vect2i _center_offset;
|
||||
|
||||
//! Плавное переключение в режим, если true.
|
||||
bool _smooth_switch;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_CAMERA_MODE_H
|
||||
541
engines/qdengine/qdcore/qd_condition.cpp
Normal file
541
engines/qdengine/qdcore/qd_condition.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
/* 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 "qdengine/qdengine.h"
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/qdcore/qd_rnd.h"
|
||||
#include "qdengine/qdcore/qd_condition.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
bool qdCondition::_successful_click = false;
|
||||
bool qdCondition::_successful_object_click = false;
|
||||
|
||||
qdCondition::qdCondition() : _type(CONDITION_FALSE), _is_inversed(false), _is_in_group(false) {
|
||||
}
|
||||
|
||||
qdCondition::qdCondition(qdCondition::ConditionType tp) : _is_inversed(false), _is_in_group(false) {
|
||||
set_type(tp);
|
||||
}
|
||||
|
||||
qdCondition::qdCondition(const qdCondition &cnd) : _type(cnd._type),
|
||||
_owner(cnd._owner),
|
||||
_data(cnd._data),
|
||||
_objects(cnd._objects),
|
||||
_is_inversed(cnd._is_inversed),
|
||||
_is_in_group(false) {
|
||||
}
|
||||
|
||||
qdCondition &qdCondition::operator = (const qdCondition &cnd) {
|
||||
if (this == &cnd) return *this;
|
||||
|
||||
_type = cnd._type;
|
||||
_owner = cnd._owner;
|
||||
|
||||
_data = cnd._data;
|
||||
_objects = cnd._objects;
|
||||
|
||||
_is_inversed = cnd._is_inversed;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
qdCondition::~qdCondition() {
|
||||
}
|
||||
|
||||
void qdCondition::set_type(ConditionType tp) {
|
||||
_type = tp;
|
||||
|
||||
switch (_type) {
|
||||
case CONDITION_TRUE:
|
||||
case CONDITION_FALSE:
|
||||
break;
|
||||
case CONDITION_MOUSE_CLICK:
|
||||
case CONDITION_PERSONAGE_ACTIVE:
|
||||
case CONDITION_MOUSE_ZONE_CLICK:
|
||||
_data.resize(1);
|
||||
_objects.resize(1);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_MOUSE_OBJECT_CLICK:
|
||||
_data.resize(2);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_OBJECT_IN_ZONE:
|
||||
_data.resize(2);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_PERSONAGE_WALK_DIRECTION:
|
||||
case CONDITION_PERSONAGE_STATIC_DIRECTION:
|
||||
_data.resize(2);
|
||||
_objects.resize(1);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_FLOAT, 1);
|
||||
break;
|
||||
case CONDITION_TIMER:
|
||||
_data.resize(2);
|
||||
init_data(0, qdConditionData::DATA_FLOAT, 2);
|
||||
init_data(1, qdConditionData::DATA_INT, 2);
|
||||
break;
|
||||
case CONDITION_MOUSE_DIALOG_CLICK:
|
||||
break;
|
||||
case CONDITION_MINIGAME_STATE:
|
||||
_data.resize(2);
|
||||
_objects.resize(1);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_OBJECT_STATE:
|
||||
case CONDITION_OBJECT_PREV_STATE:
|
||||
_data.resize(2);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_OBJECT_NOT_IN_STATE:
|
||||
inverse();
|
||||
_type = CONDITION_OBJECT_STATE;
|
||||
|
||||
_data.resize(2);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_MOUSE_OBJECT_ZONE_CLICK:
|
||||
_data.resize(2);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_OBJECT_STATE_WAS_ACTIVATED:
|
||||
_data.resize(2);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_OBJECT_STATE_WAS_NOT_ACTIVATED:
|
||||
inverse();
|
||||
_type = CONDITION_OBJECT_STATE_WAS_ACTIVATED;
|
||||
|
||||
_data.resize(2);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_OBJECTS_DISTANCE:
|
||||
_data.resize(3);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
init_data(2, qdConditionData::DATA_FLOAT, 1);
|
||||
break;
|
||||
case CONDITION_OBJECT_STATE_WAITING:
|
||||
_data.resize(2);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
break;
|
||||
case CONDITION_OBJECT_STATE_ANIMATION_PHASE:
|
||||
_data.resize(3);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_STRING);
|
||||
init_data(1, qdConditionData::DATA_STRING);
|
||||
init_data(2, qdConditionData::DATA_FLOAT, 2);
|
||||
break;
|
||||
case CONDITION_STATE_TIME_GREATER_THAN_VALUE:
|
||||
_data.resize(1);
|
||||
_objects.resize(1);
|
||||
init_data(0, qdConditionData::DATA_FLOAT, 1);
|
||||
break;
|
||||
case CONDITION_STATE_TIME_GREATER_THAN_STATE_TIME:
|
||||
_objects.resize(2);
|
||||
break;
|
||||
case CONDITION_STATE_TIME_IN_INTERVAL:
|
||||
_data.resize(1);
|
||||
_objects.resize(1);
|
||||
init_data(0, qdConditionData::DATA_FLOAT, 2);
|
||||
break;
|
||||
case CONDITION_COUNTER_GREATER_THAN_VALUE:
|
||||
case CONDITION_COUNTER_LESS_THAN_VALUE:
|
||||
_data.resize(1);
|
||||
_objects.resize(1);
|
||||
init_data(0, qdConditionData::DATA_INT, 1);
|
||||
break;
|
||||
case CONDITION_COUNTER_GREATER_THAN_COUNTER:
|
||||
_objects.resize(2);
|
||||
break;
|
||||
case CONDITION_COUNTER_IN_INTERVAL:
|
||||
_data.resize(1);
|
||||
_objects.resize(1);
|
||||
init_data(0, qdConditionData::DATA_INT, 2);
|
||||
break;
|
||||
case CONDITION_OBJECT_ON_PERSONAGE_WAY:
|
||||
_data.resize(1);
|
||||
_objects.resize(2);
|
||||
init_data(0, qdConditionData::DATA_FLOAT, 1);
|
||||
break;
|
||||
case CONDITION_KEYPRESS:
|
||||
_data.resize(1);
|
||||
init_data(0, qdConditionData::DATA_INT, 1);
|
||||
break;
|
||||
case CONDITION_ANY_PERSONAGE_IN_ZONE:
|
||||
_objects.resize(1);
|
||||
break;
|
||||
case CONDITION_MOUSE_RIGHT_CLICK:
|
||||
_objects.resize(1);
|
||||
break;
|
||||
case CONDITION_MOUSE_RIGHT_OBJECT_CLICK:
|
||||
_objects.resize(2);
|
||||
break;
|
||||
case CONDITION_MOUSE_RIGHT_ZONE_CLICK:
|
||||
_objects.resize(1);
|
||||
break;
|
||||
case CONDITION_MOUSE_RIGHT_OBJECT_ZONE_CLICK:
|
||||
_objects.resize(2);
|
||||
break;
|
||||
case CONDITION_OBJECT_HIDDEN:
|
||||
_objects.resize(1);
|
||||
break;
|
||||
case CONDITION_MOUSE_HOVER:
|
||||
_objects.resize(1);
|
||||
break;
|
||||
case CONDITION_MOUSE_OBJECT_HOVER:
|
||||
_objects.resize(2);
|
||||
break;
|
||||
case CONDITION_MOUSE_HOVER_ZONE:
|
||||
_objects.resize(1);
|
||||
break;
|
||||
case CONDITION_MOUSE_OBJECT_HOVER_ZONE:
|
||||
_objects.resize(2);
|
||||
break;
|
||||
case CONDITION_MOUSE_CLICK_FAILED:
|
||||
case CONDITION_MOUSE_OBJECT_CLICK_FAILED:
|
||||
case CONDITION_MOUSE_CLICK_EVENT:
|
||||
case CONDITION_MOUSE_RIGHT_CLICK_EVENT:
|
||||
break;
|
||||
case CONDITION_MOUSE_OBJECT_CLICK_EVENT:
|
||||
case CONDITION_MOUSE_RIGHT_OBJECT_CLICK_EVENT:
|
||||
case CONDITION_MOUSE_STATE_PHRASE_CLICK:
|
||||
_objects.resize(1);
|
||||
break;
|
||||
case CONDITION_OBJECT_IS_CLOSER:
|
||||
_objects.resize(3);
|
||||
break;
|
||||
case CONDITION_ANIMATED_OBJECT_IDLE_GREATER_THAN_VALUE:
|
||||
_objects.resize(1);
|
||||
_data.resize(1);
|
||||
init_data(0, qdConditionData::DATA_INT, 1);
|
||||
break;
|
||||
case CONDITION_ANIMATED_OBJECTS_INTERSECTIONAL_BOUNDS:
|
||||
_objects.resize(2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool qdCondition::put_value(int idx, const char *str) {
|
||||
assert(idx >= 0 && idx < (int)_data.size());
|
||||
return _data[idx].put_string(str);
|
||||
}
|
||||
|
||||
bool qdCondition::put_value(int idx, int val, int val_index) {
|
||||
assert(idx >= 0 && idx < (int)_data.size());
|
||||
return _data[idx].put_int(val, val_index);
|
||||
}
|
||||
|
||||
bool qdCondition::put_value(int idx, float val, int val_index) {
|
||||
assert(idx >= 0 && idx < (int)_data.size());
|
||||
return _data[idx].put_float(val, val_index);
|
||||
}
|
||||
|
||||
bool qdCondition::get_value(int idx, const char *&str) const {
|
||||
assert(idx >= 0 && idx < (int)_data.size());
|
||||
|
||||
if (_data[idx].get_string()) {
|
||||
str = _data[idx].get_string();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdCondition::get_value(int idx, int &val, int val_index) const {
|
||||
assert(idx >= 0 && idx < (int)_data.size());
|
||||
val = _data[idx].get_int(val_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCondition::get_value(int idx, float &val, int val_index) const {
|
||||
assert(idx >= 0 && idx < (int)_data.size());
|
||||
val = _data[idx].get_float(val_index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCondition::load_script(const xml::tag *p) {
|
||||
int data_idx = 0;
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_CONDITION_DATA_INT:
|
||||
case QDSCR_CONDITION_DATA_FLOAT:
|
||||
case QDSCR_CONDITION_DATA_STRING:
|
||||
if (data_idx < (int)_data.size())
|
||||
_data[data_idx++].load_script(&*it);
|
||||
break;
|
||||
case QDSCR_CONDITION_INVERSE:
|
||||
if (xml::tag_buffer(*it).get_int())
|
||||
inverse(true);
|
||||
else
|
||||
inverse(false);
|
||||
break;
|
||||
case QDSCR_CONDITION_OBJECT:
|
||||
if (const xml::tag *tp = it->search_subtag(QDSCR_ID)) {
|
||||
int object_idx = xml::tag_buffer(*tp).get_int();
|
||||
|
||||
if (object_idx >= 0 && object_idx < (int)_objects.size())
|
||||
_objects[object_idx].load_script(&*it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCondition::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
if (debugChannelSet(-1, kDebugLog)) {
|
||||
fh.writeString(Common::String::format("<condition type=\"%s\"", type2str(_type)));
|
||||
} else {
|
||||
fh.writeString(Common::String::format("<condition type=\"%d\"", _type));
|
||||
}
|
||||
|
||||
if (is_inversed()) {
|
||||
fh.writeString(" condition_inverse=\"1\"");
|
||||
}
|
||||
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
for (auto &it : _data) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _objects.size(); i++) {
|
||||
if (_objects[i].object())
|
||||
_objects[i].save_script(fh, indent + 1, i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("</condition>\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdCondition::quant(float dt) {
|
||||
debugC(9, kDebugQuant, "qdCondition::quant(%f)", dt);
|
||||
if (_type == CONDITION_TIMER) {
|
||||
float period, timer;
|
||||
if (!get_value(TIMER_PERIOD, period, 0)) return;
|
||||
if (!get_value(TIMER_PERIOD, timer, 1)) return;
|
||||
|
||||
timer += dt;
|
||||
|
||||
put_value(TIMER_PERIOD, timer, 1);
|
||||
|
||||
if (timer >= period) {
|
||||
debugC(3, kDebugQuant, "qdCondition::quant() timer >= period");
|
||||
timer -= period;
|
||||
put_value(TIMER_PERIOD, timer, 1);
|
||||
|
||||
int rnd;
|
||||
if (!get_value(TIMER_RND, rnd)) return;
|
||||
|
||||
int state = 1;
|
||||
if (rnd && qd_rnd(100 - rnd))
|
||||
state = 0;
|
||||
|
||||
put_value(TIMER_RND, state, 1);
|
||||
} else
|
||||
put_value(TIMER_RND, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool qdCondition::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
debugC(5, kDebugSave, " qdCondition::load_data(): before: %d", (int)fh.pos());
|
||||
if (_type == CONDITION_TIMER) {
|
||||
int state;
|
||||
float timer;
|
||||
|
||||
timer = fh.readFloatLE();
|
||||
state = fh.readSint32LE();
|
||||
|
||||
if (!put_value(TIMER_PERIOD, timer, 1)) return false;
|
||||
if (!put_value(TIMER_RND, state, 1)) return false;
|
||||
}
|
||||
|
||||
debugC(5, kDebugSave, " qdCondition::load_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCondition::save_data(Common::WriteStream &fh) const {
|
||||
debugC(5, kDebugSave, " qdCondition::save_data(): before: %d", (int)fh.pos());
|
||||
if (_type == CONDITION_TIMER) {
|
||||
float timer;
|
||||
if (!get_value(TIMER_PERIOD, timer, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int state;
|
||||
if (!get_value(TIMER_RND, state, 1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fh.writeFloatLE(timer);
|
||||
fh.writeSint32LE(state);
|
||||
}
|
||||
|
||||
debugC(5, kDebugSave, " qdCondition::save_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCondition::check() {
|
||||
bool result = false;
|
||||
if (qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher()) {
|
||||
if (dp->check_condition(this))
|
||||
result = !_is_inversed;
|
||||
else
|
||||
result = _is_inversed;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
if (is_click_condition())
|
||||
_successful_click = true;
|
||||
else if (is_object_click_condition())
|
||||
_successful_object_click = true;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool qdCondition::put_object(int idx, qdNamedObject *obj) {
|
||||
assert(idx >= 0 && idx < (int)_objects.size());
|
||||
_objects[idx].set_object(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
const qdNamedObject *qdCondition::get_object(int idx) {
|
||||
if (idx >= 0 && idx < (int)_objects.size()) {
|
||||
if (!_objects[idx].object())
|
||||
_objects[idx].find_object();
|
||||
|
||||
return _objects[idx].object();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
bool qdCondition::init() {
|
||||
if (_type == CONDITION_TIMER) {
|
||||
if (!put_value(TIMER_PERIOD, 0.0f, 1)) return false;
|
||||
if (!put_value(TIMER_RND, 0, 1)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *types[] = {
|
||||
"CONDITION_TRUE",
|
||||
"CONDITION_FALSE",
|
||||
"CONDITION_MOUSE_CLICK",
|
||||
"CONDITION_MOUSE_OBJECT_CLICK",
|
||||
"CONDITION_OBJECT_IN_ZONE",
|
||||
"CONDITION_PERSONAGE_WALK_DIRECTION",
|
||||
"CONDITION_PERSONAGE_STATIC_DIRECTION",
|
||||
"CONDITION_TIMER",
|
||||
"CONDITION_MOUSE_DIALOG_CLICK",
|
||||
"CONDITION_MINIGAME_STATE",
|
||||
"CONDITION_OBJECT_STATE",
|
||||
"CONDITION_MOUSE_ZONE_CLICK",
|
||||
"CONDITION_MOUSE_OBJECT_ZONE_CLICK",
|
||||
"CONDITION_OBJECT_STATE_WAS_ACTIVATED",
|
||||
"CONDITION_OBJECT_STATE_WAS_NOT_ACTIVATED",
|
||||
"CONDITION_OBJECT_NOT_IN_STATE",
|
||||
"CONDITION_OBJECTS_DISTANCE",
|
||||
"CONDITION_PERSONAGE_ACTIVE",
|
||||
"CONDITION_OBJECT_STATE_WAITING",
|
||||
"CONDITION_OBJECT_STATE_ANIMATION_PHASE",
|
||||
"CONDITION_OBJECT_PREV_STATE",
|
||||
"CONDITION_STATE_TIME_GREATER_THAN_VALUE",
|
||||
"CONDITION_STATE_TIME_GREATER_THAN_STATE_TIME",
|
||||
"CONDITION_STATE_TIME_IN_INTERVAL",
|
||||
"CONDITION_COUNTER_GREATER_THAN_VALUE",
|
||||
"CONDITION_COUNTER_LESS_THAN_VALUE",
|
||||
"CONDITION_COUNTER_GREATER_THAN_COUNTER",
|
||||
"CONDITION_COUNTER_IN_INTERVAL",
|
||||
"CONDITION_OBJECT_ON_PERSONAGE_WAY",
|
||||
"CONDITION_KEYPRESS",
|
||||
"CONDITION_ANY_PERSONAGE_IN_ZONE",
|
||||
"CONDITION_MOUSE_RIGHT_CLICK",
|
||||
"CONDITION_MOUSE_RIGHT_OBJECT_CLICK",
|
||||
"CONDITION_MOUSE_RIGHT_ZONE_CLICK",
|
||||
"CONDITION_MOUSE_RIGHT_OBJECT_ZONE_CLICK",
|
||||
"CONDITION_OBJECT_HIDDEN",
|
||||
"CONDITION_MOUSE_HOVER",
|
||||
"CONDITION_MOUSE_OBJECT_HOVER",
|
||||
"CONDITION_MOUSE_HOVER_ZONE",
|
||||
"CONDITION_MOUSE_OBJECT_HOVER_ZONE",
|
||||
"CONDITION_MOUSE_CLICK_FAILED",
|
||||
"CONDITION_MOUSE_OBJECT_CLICK_FAILED",
|
||||
"CONDITION_MOUSE_CLICK_EVENT",
|
||||
"CONDITION_MOUSE_OBJECT_CLICK_EVENT",
|
||||
"CONDITION_MOUSE_RIGHT_CLICK_EVENT",
|
||||
"CONDITION_MOUSE_RIGHT_OBJECT_CLICK_EVENT",
|
||||
"CONDITION_MOUSE_STATE_PHRASE_CLICK",
|
||||
"CONDITION_OBJECT_IS_CLOSER",
|
||||
"CONDITION_ANIMATED_OBJECT_IDLE_GREATER_THAN_VALUE",
|
||||
"CONDITION_ANIMATED_OBJECTS_INTERSECTIONAL_BOUNDS",
|
||||
};
|
||||
|
||||
const char *qdCondition::type2str(uint type) {
|
||||
if (type >= ARRAYSIZE(types))
|
||||
return "???";
|
||||
|
||||
return types[type];
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
598
engines/qdengine/qdcore/qd_condition.h
Normal file
598
engines/qdengine/qdcore/qd_condition.h
Normal file
@@ -0,0 +1,598 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_CONDITION_H
|
||||
#define QDENGINE_QDCORE_QD_CONDITION_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
#include "qdengine/qdcore/qd_condition_data.h"
|
||||
#include "qdengine/qdcore/qd_condition_object_reference.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
//! Условие.
|
||||
/**
|
||||
Структура данных по типам условий.
|
||||
|
||||
Индексы для доступа к объектам (если они используются в условии)
|
||||
совпадают с индексами для доступа к данным об именах объектов.
|
||||
|
||||
CONDITION_TRUE
|
||||
CONDITION_FALSE
|
||||
Данные: отсутствуют
|
||||
|
||||
CONDITION_MOUSE_CLICK
|
||||
Данные:
|
||||
string
|
||||
Объекты:
|
||||
qdGameObject
|
||||
Индескы данных:
|
||||
OBJECT_NAME
|
||||
Имя объекта, по которому надо кликнуть.
|
||||
Если пустое - проверяется клик по объекту, которому принадлежит
|
||||
состояние, в котором выставлено это условие.
|
||||
|
||||
CONDITION_MOUSE_OBJECT_CLICK
|
||||
Данные:
|
||||
string, string
|
||||
Объекты:
|
||||
qdGameObject, qdGameObject
|
||||
Индескы данных:
|
||||
OBJECT_NAME, MOUSE_OBJECT_NAME
|
||||
Имя объекта, по которому надо кликнуть
|
||||
и имя объекта, который должен быть на мыши.
|
||||
|
||||
CONDITION_OBJECT_IN_ZONE
|
||||
Данные:
|
||||
string, string
|
||||
Объекты:
|
||||
qdGameObject, qdGridZone
|
||||
Индескы данных:
|
||||
OBJECT_NAME, ZONE_NAME
|
||||
Имя объекта и имя зоны на сетке,
|
||||
в которую он должен попасть.
|
||||
|
||||
CONDITION_PERSONAGE_WALK_DIRECTION
|
||||
CONDITION_PERSONAGE_STATIC_DIRECTION
|
||||
Данные:
|
||||
string, float[1]
|
||||
Объекты:
|
||||
qdGameObjectMoving
|
||||
Индескы данных:
|
||||
PERSONAGE_NAME, DIRECTION_ANGLE
|
||||
Имя персонажа и угол направления в радианах.
|
||||
Угол задается так же, как и направления в походках
|
||||
(т.е. от направления направо против часовой стрелки)
|
||||
|
||||
CONDITION_TIMER
|
||||
Данные:
|
||||
float[2], int[2]
|
||||
Индескы данных:
|
||||
TIMER_PERIOD, TIMER_RND
|
||||
Период и текущее время таймера в секундах,
|
||||
вероятность выполнения условия по истечении времени
|
||||
таймера в процентах и текущее состояние условия.
|
||||
|
||||
CONDITION_MOUSE_DIALOG_CLICK
|
||||
Данные: отсутствуют
|
||||
|
||||
CONDITION_MINIGAME_STATE
|
||||
Данные:
|
||||
string, string
|
||||
Объекты:
|
||||
qdMiniGame
|
||||
Индескы данных:
|
||||
MINIGAME_NAME, MINIGAME_STATE_NAME
|
||||
Имя мини-игры и имя состояния, в котором она должна находиться
|
||||
для выполнения условия.
|
||||
|
||||
CONDITION_OBJECT_STATE
|
||||
Данные:
|
||||
string, string
|
||||
Объекты:
|
||||
qdGameObjectAnimated, qdGameObjectState
|
||||
Индескы данных:
|
||||
OBJECT_NAME, OBJECT_STATE_NAME
|
||||
Имя объекта и имя состояния, в котором он должен находиться
|
||||
для выполнения условия.
|
||||
|
||||
CONDITION_MOUSE_ZONE_CLICK
|
||||
Данные:
|
||||
string
|
||||
Объекты:
|
||||
qdGridZone
|
||||
Индескы данных:
|
||||
CLICK_ZONE_NAME
|
||||
Имя зоны на сетке,
|
||||
в которую надо кликнуть.
|
||||
|
||||
CONDITION_MOUSE_OBJECT_ZONE_CLICK
|
||||
Данные:
|
||||
string, string
|
||||
Объекты:
|
||||
qdGridZone, qdGameObject
|
||||
Индескы данных:
|
||||
CLICK_ZONE_NAME, MOUSE_OBJECT_NAME
|
||||
Имя зоны на сетке, в которую надо кликнуть
|
||||
и имя объекта, который должен быть на мыши.
|
||||
|
||||
CONDITION_OBJECT_STATE_WAS_ACTIVATED
|
||||
CONDITION_OBJECT_STATE_WAS_NOT_ACTIVATED
|
||||
Данные:
|
||||
string, string
|
||||
Объекты:
|
||||
qdGameObjectAnimated, qdGameObjectState
|
||||
Индескы данных:
|
||||
OBJECT_NAME, OBJECT_STATE_NAME
|
||||
Имя объекта и имя состояния.
|
||||
|
||||
CONDITION_OBJECT_NOT_IN_STATE
|
||||
см. CONDITION_OBJECT_STATE
|
||||
|
||||
CONDITION_OBJECTS_DISTANCE
|
||||
Данные:
|
||||
string, string, float
|
||||
Объекты:
|
||||
qdGameObject, qdGameObject
|
||||
Индескы данных:
|
||||
OBJECT_NAME, OBJECT2_NAME, OBJECTS_DISTANCE
|
||||
Имена объектов и расстояние по сетке.
|
||||
|
||||
CONDITION_PERSONAGE_ACTIVE
|
||||
Данные:
|
||||
string
|
||||
Объекты:
|
||||
qdGameObjectMoving
|
||||
Индескы данных:
|
||||
PERSONAGE_NAME
|
||||
Имя персонажа, который должен быть активным
|
||||
для выполнения условия.
|
||||
|
||||
CONDITION_OBJECT_STATE_WAITING
|
||||
Данные:
|
||||
string, string
|
||||
Объекты:
|
||||
qdGameObjectAnimated, qdGameObjectState
|
||||
Индескы данных:
|
||||
OBJECT_NAME, OBJECT_STATE_NAME
|
||||
Имя объекта и имя состояния.
|
||||
|
||||
CONDITION_OBJECT_STATE_ANIMATION_PHASE
|
||||
Данные:
|
||||
string, string, float[2]
|
||||
Объекты:
|
||||
qdGameObjectAnimated, qdGameObjectState
|
||||
Индескы данных:
|
||||
OBJECT_NAME, OBJECT_STATE_NAME, ANIMATION_PHASE
|
||||
Имя объекта, имя состояния и диапазон фазы анимации.
|
||||
|
||||
CONDITION_OBJECT_PREV_STATE
|
||||
Данные:
|
||||
string, string
|
||||
Объекты:
|
||||
qdGameObjectAnimated, qdGameObjectState
|
||||
Индескы данных:
|
||||
OBJECT_NAME, OBJECT_STATE_NAME
|
||||
Имя объекта и имя состояния.
|
||||
|
||||
CONDITION_STATE_TIME_GREATER_THAN_VALUE
|
||||
Данные:
|
||||
float
|
||||
Время работы состояния.
|
||||
Объекты:
|
||||
qdGameObjectState
|
||||
|
||||
CONDITION_STATE_TIME_GREATER_THAN_STATE_TIME
|
||||
Данные: отсутствуют
|
||||
Объекты:
|
||||
qdGameObjectState, qdGameObjectState
|
||||
Состояния, время работы которых сравнивается.
|
||||
|
||||
CONDITION_STATE_TIME_IN_INTERVAL
|
||||
Данные:
|
||||
float[2]
|
||||
Интервал, в котором должно находиться ремя работы состояния.
|
||||
Объекты:
|
||||
qdGameObjectState
|
||||
|
||||
CONDITION_COUNTER_GREATER_THAN_VALUE
|
||||
CONDITION_COUNTER_LESS_THAN_VALUE
|
||||
Данные:
|
||||
int
|
||||
Число, с которым сравнивается значение счетчика.
|
||||
Объекты:
|
||||
qdCounter
|
||||
|
||||
CONDITION_COUNTER_GREATER_THAN_COUNTER
|
||||
Данные: отсутствуют
|
||||
Объекты:
|
||||
qdCounter, qdCounter
|
||||
Счетчики, значения которых сравнивается.
|
||||
|
||||
CONDITION_COUNTER_IN_INTERVAL
|
||||
Данные:
|
||||
int[2]
|
||||
Интервал, в котором должно находиться значение счетчика.
|
||||
Объекты:
|
||||
qdCounter
|
||||
|
||||
CONDITION_OBJECT_ON_PERSONAGE_WAY
|
||||
Данные:
|
||||
float[1]
|
||||
Максимальное расстояние между объектам и персонажем по сетке.
|
||||
Объекты:
|
||||
qdGameObjectMoving, qdGameObject
|
||||
|
||||
CONDITION_KEYPRESS
|
||||
Данные:
|
||||
int[1]
|
||||
vkey кнопки.
|
||||
|
||||
CONDITION_ANY_PERSONAGE_IN_ZONE
|
||||
Объекты:
|
||||
qdGridZone
|
||||
|
||||
CONDITION_MOUSE_RIGHT_CLICK
|
||||
Объекты:
|
||||
qdGameObject
|
||||
Индескы данных:
|
||||
OBJECT_NAME
|
||||
Объект, по которому надо кликнуть.
|
||||
Если нулевой - проверяется клик по объекту, которому принадлежит
|
||||
состояние, в котором выставлено это условие.
|
||||
|
||||
CONDITION_MOUSE_RIGHT_OBJECT_CLICK
|
||||
Объекты:
|
||||
qdGameObject, qdGameObject
|
||||
Индескы данных:
|
||||
OBJECT_NAME, MOUSE_OBJECT_NAME
|
||||
Объект, по которому надо кликнуть
|
||||
и объект, который должен быть на мыши.
|
||||
|
||||
CONDITION_MOUSE_RIGHT_ZONE_CLICK
|
||||
Объекты:
|
||||
qdGridZone
|
||||
Индескы данных:
|
||||
CLICK_ZONE_NAME
|
||||
Зона на сетке,
|
||||
в которую надо кликнуть.
|
||||
|
||||
CONDITION_MOUSE_RIGHT_OBJECT_ZONE_CLICK
|
||||
Объекты:
|
||||
qdGridZone, qdGameObject
|
||||
Индескы данных:
|
||||
CLICK_ZONE_NAME, MOUSE_OBJECT_NAME
|
||||
Зона на сетке, в которую надо кликнуть
|
||||
и объект, который должен быть на мыши.
|
||||
|
||||
CONDITION_OBJECT_HIDDEN
|
||||
Объекты:
|
||||
qdGameObject
|
||||
Объект, который должен быть скрыт
|
||||
|
||||
CONDITION_MOUSE_HOVER
|
||||
Объекты:
|
||||
qdGameObject
|
||||
Объект, на который наводится мышь
|
||||
|
||||
CONDITION_MOUSE_OBJECT_HOVER
|
||||
Объекты:
|
||||
qdGameObject, qdGameObject
|
||||
Объект, на который наводится мышь,
|
||||
объект который на мыши
|
||||
|
||||
CONDITION_MOUSE_HOVER_ZONE
|
||||
Объекты:
|
||||
qdGridZone
|
||||
Зона, на которую наводится мышь
|
||||
|
||||
CONDITION_MOUSE_OBJECT_HOVER_ZONE
|
||||
Объекты:
|
||||
qdGridZone, qdGameObject
|
||||
Зона, на которую наводится мышь,
|
||||
объект который на мыши
|
||||
|
||||
CONDITION_MOUSE_CLICK_FAILED
|
||||
CONDITION_MOUSE_OBJECT_CLICK_FAILED
|
||||
CONDITION_MOUSE_CLICK_EVENT
|
||||
//CONDITION_MOUSE_OBJECT_CLICK_EVENT
|
||||
CONDITION_MOUSE_RIGHT_CLICK_EVENT
|
||||
//CONDITION_MOUSE_RIGHT_OBJECT_CLICK_EVENT
|
||||
Данных нет.
|
||||
|
||||
CONDITION_MOUSE_OBJECT_CLICK_EVENT
|
||||
CONDITION_MOUSE_RIGHT_OBJECT_CLICK_EVENT
|
||||
Объекты:
|
||||
qdGameObject
|
||||
Объект, которым надо кликнуть для выполнения условия.
|
||||
Если нулевй, то достаточно клика любым объектом.
|
||||
|
||||
CONDITION_MOUSE_STATE_PHRASE_CLICK
|
||||
Объекты:
|
||||
qdGameObjecState
|
||||
Состояние, по фразе которого надо кликнуть.
|
||||
|
||||
CONDITION_OBJECT_IS_CLOSER
|
||||
Объекты:
|
||||
qdGameObject, qdGameObject, qdGameObject
|
||||
Расстояние от первого объекта до второго должно быть меньше,
|
||||
чем расстояние от первого до третьего.
|
||||
|
||||
CONDITION_ANIMATED_OBJECT_IDLE_GREATER_THAN_VALUE
|
||||
Объекты:
|
||||
qdGameObjectAnimated, int
|
||||
Анимированный объект, который простаивает, и порог времени,
|
||||
который должен быть превышен временем ожидания заданного объекта.
|
||||
|
||||
CONDITION_ANIMATED_OBJECTS_INTERSECTIONAL_BOUNDS
|
||||
Объекты:
|
||||
qdGameObjectAnimated, qdGameObjectAnimated
|
||||
Два объекта, баунды которых пероверяются на пересечение.
|
||||
*/
|
||||
|
||||
class qdCondition {
|
||||
public:
|
||||
//! Типы условий.
|
||||
enum ConditionType {
|
||||
//! всегда true
|
||||
CONDITION_TRUE,
|
||||
//! всегда false
|
||||
CONDITION_FALSE,
|
||||
|
||||
//! клик мышью по объекту
|
||||
CONDITION_MOUSE_CLICK,
|
||||
//! клик объектом на мыши по объекту
|
||||
CONDITION_MOUSE_OBJECT_CLICK,
|
||||
//! персонаж или объект в определенном месте сетки
|
||||
CONDITION_OBJECT_IN_ZONE,
|
||||
//! персонаж движется в определенном направлении
|
||||
CONDITION_PERSONAGE_WALK_DIRECTION, // 5
|
||||
//! персонаж стоит и ориентирован в определенном направлении
|
||||
CONDITION_PERSONAGE_STATIC_DIRECTION,
|
||||
//! условие выпоняется с некоторой периодичностью
|
||||
CONDITION_TIMER,
|
||||
//! клик мышью по фразе в диалоге
|
||||
CONDITION_MOUSE_DIALOG_CLICK,
|
||||
//! мини-игра находится в определенном состоянии
|
||||
CONDITION_MINIGAME_STATE,
|
||||
//! объект находится в определенном состоянии
|
||||
CONDITION_OBJECT_STATE, // 10
|
||||
//! клик мышью по зоне на сетке сцены
|
||||
CONDITION_MOUSE_ZONE_CLICK,
|
||||
//! клик объектом по зоне на сетке сцены
|
||||
CONDITION_MOUSE_OBJECT_ZONE_CLICK,
|
||||
//! состояние объекта активировалось
|
||||
CONDITION_OBJECT_STATE_WAS_ACTIVATED,
|
||||
//! состояние объекта не активировалось
|
||||
CONDITION_OBJECT_STATE_WAS_NOT_ACTIVATED,
|
||||
//! объект не находится в определенном состоянии
|
||||
CONDITION_OBJECT_NOT_IN_STATE, // 15
|
||||
//! расстояние по сетке между двумя объектами меньше заданного
|
||||
CONDITION_OBJECTS_DISTANCE,
|
||||
//! персонаж активен
|
||||
CONDITION_PERSONAGE_ACTIVE,
|
||||
//! состояние объекта ждет активации
|
||||
CONDITION_OBJECT_STATE_WAITING,
|
||||
//! состояние в определенной фазе анимации
|
||||
CONDITION_OBJECT_STATE_ANIMATION_PHASE,
|
||||
//! предыдущее состояние объекта
|
||||
CONDITION_OBJECT_PREV_STATE, // 20
|
||||
//! время работы состояния больше значения
|
||||
CONDITION_STATE_TIME_GREATER_THAN_VALUE,
|
||||
//! время работы одного состояния больше времени работы другого
|
||||
CONDITION_STATE_TIME_GREATER_THAN_STATE_TIME,
|
||||
//! время работы состояния в интервале
|
||||
CONDITION_STATE_TIME_IN_INTERVAL,
|
||||
//! значние счетчика больше числа
|
||||
CONDITION_COUNTER_GREATER_THAN_VALUE,
|
||||
//! значние счетчика меньше числа
|
||||
CONDITION_COUNTER_LESS_THAN_VALUE, // 25
|
||||
//! значние счетчика больше значения другого счетчика
|
||||
CONDITION_COUNTER_GREATER_THAN_COUNTER,
|
||||
//! значние счетчика в интервале
|
||||
CONDITION_COUNTER_IN_INTERVAL,
|
||||
//! объект на пути персонажа
|
||||
CONDITION_OBJECT_ON_PERSONAGE_WAY,
|
||||
//! кнопка нажата
|
||||
CONDITION_KEYPRESS,
|
||||
//! в зоне хотя бы один персонаж
|
||||
CONDITION_ANY_PERSONAGE_IN_ZONE, // 30
|
||||
//! правый клик мыши по объекту
|
||||
CONDITION_MOUSE_RIGHT_CLICK,
|
||||
//! правый клик объектом на мыши по объекту
|
||||
CONDITION_MOUSE_RIGHT_OBJECT_CLICK,
|
||||
//! правый клик мышью по зоне на сетке сцены
|
||||
CONDITION_MOUSE_RIGHT_ZONE_CLICK,
|
||||
//! правый клик объектом по зоне на сетке сцены
|
||||
CONDITION_MOUSE_RIGHT_OBJECT_ZONE_CLICK,
|
||||
//! объект скрыт
|
||||
CONDITION_OBJECT_HIDDEN, // 35
|
||||
//! мышь наведена на объект
|
||||
CONDITION_MOUSE_HOVER,
|
||||
//! мышь наведена на объект, на мыши объект
|
||||
CONDITION_MOUSE_OBJECT_HOVER,
|
||||
//! мышь наведена на зону
|
||||
CONDITION_MOUSE_HOVER_ZONE,
|
||||
//! мышь наведена на зону, на мыши объект
|
||||
CONDITION_MOUSE_OBJECT_HOVER_ZONE,
|
||||
//! неудачный клик мыши
|
||||
CONDITION_MOUSE_CLICK_FAILED, // 40
|
||||
//! неудачный клик объектом на мыши
|
||||
CONDITION_MOUSE_OBJECT_CLICK_FAILED,
|
||||
//! был клик мыши
|
||||
CONDITION_MOUSE_CLICK_EVENT,
|
||||
//! был клик объектом на мыши
|
||||
CONDITION_MOUSE_OBJECT_CLICK_EVENT,
|
||||
//! был клик правой кнопкой мыши
|
||||
CONDITION_MOUSE_RIGHT_CLICK_EVENT,
|
||||
//! был клик правой кнопкой объектом на мыши
|
||||
CONDITION_MOUSE_RIGHT_OBJECT_CLICK_EVENT, // 45
|
||||
//! клик по фразе определённого состояния
|
||||
CONDITION_MOUSE_STATE_PHRASE_CLICK,
|
||||
//! расстояние до одного объекта меньше чем до другого
|
||||
CONDITION_OBJECT_IS_CLOSER,
|
||||
//! время простоя больше заданного порога
|
||||
CONDITION_ANIMATED_OBJECT_IDLE_GREATER_THAN_VALUE,
|
||||
//! баунды двух объектов пересекаются
|
||||
CONDITION_ANIMATED_OBJECTS_INTERSECTIONAL_BOUNDS,
|
||||
};
|
||||
|
||||
//! Индексы для обращения к данным в условиях.
|
||||
enum ConditionDataIndex {
|
||||
OBJECT_NAME = 0,
|
||||
MOUSE_OBJECT_NAME = 1,
|
||||
ZONE_NAME = 1,
|
||||
DIRECTION_ANGLE = 1,
|
||||
PERSONAGE_NAME = 0,
|
||||
TIMER_PERIOD = 0,
|
||||
TIMER_RND = 1,
|
||||
MINIGAME_NAME = 0,
|
||||
MINIGAME_STATE_NAME = 1,
|
||||
OBJECT_STATE_NAME = 1,
|
||||
CLICK_ZONE_NAME = 0,
|
||||
OBJECT2_NAME = 1,
|
||||
OBJECTS_DISTANCE = 2,
|
||||
ANIMATION_PHASE = 2,
|
||||
STATE_TIME = 2
|
||||
};
|
||||
|
||||
qdCondition();
|
||||
qdCondition(ConditionType tp);
|
||||
qdCondition(const qdCondition &cnd);
|
||||
~qdCondition();
|
||||
|
||||
qdCondition &operator = (const qdCondition &cnd);
|
||||
|
||||
ConditionType type() const {
|
||||
return _type;
|
||||
}
|
||||
void set_type(ConditionType tp);
|
||||
|
||||
static const char *type2str(uint type);
|
||||
|
||||
bool put_value(int idx, const char *str);
|
||||
|
||||
bool is_click_condition() const {
|
||||
return (_type == CONDITION_MOUSE_CLICK || _type == CONDITION_MOUSE_DIALOG_CLICK || _type == CONDITION_MOUSE_ZONE_CLICK);
|
||||
}
|
||||
bool is_object_click_condition() const {
|
||||
return (_type == CONDITION_MOUSE_OBJECT_CLICK || _type == CONDITION_MOUSE_OBJECT_ZONE_CLICK);
|
||||
}
|
||||
|
||||
// val_index - индекс, по которому пропишется значение
|
||||
// в qdConditionDataInt::_data или qdConditionDataFloat::_data
|
||||
bool put_value(int idx, int val, int val_index = 0);
|
||||
bool put_value(int idx, float val, int val_index = 0);
|
||||
|
||||
bool get_value(int idx, const char *&str) const;
|
||||
bool get_value(int idx, int &val, int val_index = 0) const;
|
||||
bool get_value(int idx, float &val, int val_index = 0) const;
|
||||
|
||||
bool put_object(int idx, qdNamedObject *obj);
|
||||
const qdNamedObject *get_object(int idx) ;
|
||||
|
||||
const qdNamedObject *owner() const {
|
||||
return _owner;
|
||||
}
|
||||
void set_owner(const qdNamedObject *p) {
|
||||
_owner = p;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
void quant(float dt);
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
//! Инициализация условия, вызывается при старте и перезапуске игры.
|
||||
bool init();
|
||||
|
||||
bool is_inversed() const {
|
||||
return _is_inversed;
|
||||
}
|
||||
void inverse(bool inverse_mode = true) {
|
||||
_is_inversed = inverse_mode;
|
||||
}
|
||||
|
||||
bool check();
|
||||
|
||||
bool is_in_group() const {
|
||||
return _is_in_group;
|
||||
}
|
||||
void add_group_reference() {
|
||||
_is_in_group = true;
|
||||
}
|
||||
void remove_group_reference() {
|
||||
_is_in_group = false;
|
||||
}
|
||||
|
||||
static bool successful_click() {
|
||||
return _successful_click;
|
||||
}
|
||||
static bool successful_object_click() {
|
||||
return _successful_object_click;
|
||||
}
|
||||
static void clear_successful_clicks() {
|
||||
_successful_click = _successful_object_click = false;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ConditionType _type;
|
||||
const qdNamedObject *_owner = nullptr;
|
||||
|
||||
typedef Std::vector<qdConditionData> data_container_t;
|
||||
data_container_t _data;
|
||||
|
||||
typedef Std::vector<qdConditionObjectReference> objects_container_t;
|
||||
objects_container_t _objects;
|
||||
|
||||
bool _is_inversed;
|
||||
|
||||
bool _is_in_group;
|
||||
|
||||
static bool _successful_click;
|
||||
static bool _successful_object_click;
|
||||
|
||||
bool init_data(int data_index, qdConditionData::data_t data_type, int data_size = 0) {
|
||||
assert(data_index >= 0 && data_index < (int)_data.size());
|
||||
|
||||
_data[data_index].set_type(data_type);
|
||||
if (data_size)
|
||||
_data[data_index].alloc_data(data_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_CONDITION_H
|
||||
127
engines/qdengine/qdcore/qd_condition_data.cpp
Normal file
127
engines/qdengine/qdcore/qd_condition_data.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_condition_data.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdConditionData::qdConditionData() : _type(DATA_STRING) {
|
||||
}
|
||||
|
||||
qdConditionData::qdConditionData(data_t data_type, int data_size) : _type(data_type) {
|
||||
if (data_size)
|
||||
alloc_data(data_size);
|
||||
}
|
||||
|
||||
qdConditionData::qdConditionData(const qdConditionData &data) : _type(data._type),
|
||||
_data(data._data) {
|
||||
}
|
||||
|
||||
qdConditionData::~qdConditionData() {
|
||||
}
|
||||
|
||||
qdConditionData &qdConditionData::operator = (const qdConditionData &data) {
|
||||
if (this == &data) return *this;
|
||||
|
||||
_type = data._type;
|
||||
_data = data._data;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdConditionData::alloc_data(int size) {
|
||||
switch (_type) {
|
||||
case DATA_INT:
|
||||
size *= sizeof(int);
|
||||
break;
|
||||
case DATA_FLOAT:
|
||||
size *= sizeof(float);
|
||||
break;
|
||||
case DATA_STRING:
|
||||
size++;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((int)_data.size() < size)
|
||||
_data.resize(size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionData::load_script(const xml::tag *p) {
|
||||
switch (_type) {
|
||||
case DATA_INT: {
|
||||
xml::tag_buffer buf(*p);
|
||||
for (int i = 0; i < p->data_size(); i++)
|
||||
put_int(buf.get_int(), i);
|
||||
}
|
||||
break;
|
||||
case DATA_FLOAT: {
|
||||
xml::tag_buffer buf(*p);
|
||||
for (int i = 0; i < p->data_size(); i++)
|
||||
put_float(buf.get_float(), i);
|
||||
}
|
||||
break;
|
||||
case DATA_STRING:
|
||||
put_string(p->data());
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionData::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
switch (_type) {
|
||||
case DATA_INT:
|
||||
fh.writeString(Common::String::format("<condition_data_int>%lu", _data.size() / sizeof(int32)));
|
||||
for (uint i = 0; i < _data.size() / sizeof(int32); i++) {
|
||||
fh.writeString(Common::String::format(" %d", get_int(i)));
|
||||
}
|
||||
fh.writeString("</condition_data_int>\r\n");
|
||||
break;
|
||||
case DATA_FLOAT:
|
||||
fh.writeString(Common::String::format("<condition_data_float>%lu", _data.size() / sizeof(float)));
|
||||
for (uint i = 0; i < _data.size() / sizeof(float); i++) {
|
||||
fh.writeString(Common::String::format(" %f", get_float(i)));
|
||||
}
|
||||
fh.writeString("</condition_data_float>\r\n");
|
||||
break;
|
||||
case DATA_STRING:
|
||||
fh.writeString("<condition_data_string>");
|
||||
if (!_data.empty()) {
|
||||
fh.writeString(Common::String::format("%s", qdscr_XML_string(&*_data.begin())));
|
||||
}
|
||||
fh.writeString("</condition_data_string>\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
107
engines/qdengine/qdcore/qd_condition_data.h
Normal file
107
engines/qdengine/qdcore/qd_condition_data.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_CONDITION_DATA_H
|
||||
#define QDENGINE_QDCORE_QD_CONDITION_DATA_H
|
||||
|
||||
#include "common/std/vector.h"
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdConditionData {
|
||||
public:
|
||||
enum data_t {
|
||||
DATA_INT,
|
||||
DATA_FLOAT,
|
||||
DATA_STRING
|
||||
};
|
||||
|
||||
qdConditionData();
|
||||
qdConditionData(data_t data_type, int data_size = 0);
|
||||
qdConditionData(const qdConditionData &data);
|
||||
~qdConditionData();
|
||||
|
||||
qdConditionData &operator = (const qdConditionData &data);
|
||||
|
||||
data_t type() const {
|
||||
return _type;
|
||||
}
|
||||
void set_type(data_t tp) {
|
||||
_type = tp;
|
||||
}
|
||||
|
||||
int get_int(int index = 0) const {
|
||||
return reinterpret_cast<const int32 *>(&*_data.begin())[index];
|
||||
}
|
||||
bool put_int(int value, int index = 0) {
|
||||
if (static_cast<int>(_data.size()) >= static_cast<int>((index - 1) * sizeof(int32))) {
|
||||
reinterpret_cast<int32 *>(&*_data.begin())[index] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float get_float(int index = 0) const {
|
||||
return reinterpret_cast<const float *>(&*_data.begin())[index];
|
||||
}
|
||||
bool put_float(float value, int index = 0) {
|
||||
if (static_cast<int>(_data.size()) >=
|
||||
static_cast<int>((index - 1) * sizeof(float))) {
|
||||
reinterpret_cast<float *>(&*_data.begin())[index] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *get_string() const {
|
||||
if (!_data.empty())
|
||||
return &*_data.begin();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool put_string(const char *str) {
|
||||
if (alloc_data(strlen(str) + 1)) {
|
||||
Common::strlcpy(&*_data.begin(), str, _data.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
bool alloc_data(int size);
|
||||
|
||||
private:
|
||||
|
||||
data_t _type;
|
||||
Std::vector<char> _data;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_CONDITION_DATA_H
|
||||
107
engines/qdengine/qdcore/qd_condition_group.cpp
Normal file
107
engines/qdengine/qdcore/qd_condition_group.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/qdcore/qd_condition_group.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdConditionGroup::qdConditionGroup(conditions_mode_t md) : _conditions_mode(md) {
|
||||
}
|
||||
|
||||
qdConditionGroup::qdConditionGroup(const qdConditionGroup &cg) : _conditions_mode(cg._conditions_mode), _conditions(cg._conditions) {
|
||||
}
|
||||
|
||||
qdConditionGroup::~qdConditionGroup() {
|
||||
}
|
||||
|
||||
qdConditionGroup &qdConditionGroup::operator = (const qdConditionGroup &cg) {
|
||||
if (this == &cg) return *this;
|
||||
|
||||
_conditions_mode = cg._conditions_mode;
|
||||
_conditions = cg._conditions;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdConditionGroup::add_condition(int condition_id) {
|
||||
conditions_container_t::iterator it = Common::find(_conditions.begin(), _conditions.end(), condition_id);
|
||||
if (it != _conditions.end())
|
||||
return false;
|
||||
|
||||
_conditions.push_back(condition_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionGroup::remove_condition(int condition_id) {
|
||||
for (conditions_container_t::iterator it = _conditions.begin(); it != _conditions.end(); ++it) {
|
||||
if (*it > condition_id)
|
||||
(*it)--;
|
||||
}
|
||||
|
||||
conditions_container_t::iterator it1 = Common::find(_conditions.begin(), _conditions.end(), condition_id);
|
||||
if (it1 != _conditions.end())
|
||||
return false;
|
||||
|
||||
_conditions.erase(it1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionGroup::load_script(const xml::tag *p) {
|
||||
_conditions.reserve(p->data_size());
|
||||
|
||||
if (const xml::tag *tp = p->search_subtag(QDSCR_TYPE))
|
||||
_conditions_mode = conditions_mode_t(xml::tag_buffer(*tp).get_int());
|
||||
|
||||
xml::tag_buffer buf(*p);
|
||||
for (int i = 0; i < p->data_size(); i++)
|
||||
_conditions.push_back(buf.get_int());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionGroup::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<condition_group");
|
||||
if (debugChannelSet(-1, kDebugLog))
|
||||
fh.writeString(Common::String::format(" type=\"%s\"", _conditions_mode == CONDITIONS_AND ? "CONDITIONS_AND" : "CONDITIONS_OR"));
|
||||
else
|
||||
fh.writeString(Common::String::format(" type=\"%d\"", (int)_conditions_mode));
|
||||
|
||||
fh.writeString(">");
|
||||
|
||||
fh.writeString(Common::String::format("%u", _conditions.size()));
|
||||
for (auto &it : _conditions) {
|
||||
fh.writeString(Common::String::format(" %d", it));
|
||||
}
|
||||
fh.writeString("</condition_group>\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
84
engines/qdengine/qdcore/qd_condition_group.h
Normal file
84
engines/qdengine/qdcore/qd_condition_group.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_CONDITION_GROUP_H
|
||||
#define QDENGINE_QDCORE_QD_CONDITION_GROUP_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Группа условий.
|
||||
class qdConditionGroup {
|
||||
public:
|
||||
//! Режим проверки условий.
|
||||
enum conditions_mode_t {
|
||||
//! "И" - должны выполниться все условия.
|
||||
CONDITIONS_AND,
|
||||
//! "ИЛИ" - достаточно выполнения одного из условий.
|
||||
CONDITIONS_OR
|
||||
};
|
||||
|
||||
explicit qdConditionGroup(conditions_mode_t md = CONDITIONS_AND);
|
||||
qdConditionGroup(const qdConditionGroup &cg);
|
||||
|
||||
qdConditionGroup &operator = (const qdConditionGroup &cg);
|
||||
|
||||
~qdConditionGroup();
|
||||
|
||||
typedef Std::vector<int> conditions_container_t;
|
||||
typedef conditions_container_t::const_iterator conditions_iterator_t;
|
||||
|
||||
conditions_iterator_t conditions_begin() const {
|
||||
return _conditions.begin();
|
||||
}
|
||||
conditions_iterator_t conditions_end() const {
|
||||
return _conditions.end();
|
||||
}
|
||||
|
||||
int conditions_size() const {
|
||||
return _conditions.size();
|
||||
}
|
||||
|
||||
conditions_mode_t conditions_mode() const {
|
||||
return _conditions_mode;
|
||||
}
|
||||
void set_conditions_mode(conditions_mode_t mode) {
|
||||
_conditions_mode = mode;
|
||||
}
|
||||
|
||||
bool add_condition(int condition_id);
|
||||
bool remove_condition(int condition_id);
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
private:
|
||||
|
||||
conditions_mode_t _conditions_mode;
|
||||
conditions_container_t _conditions;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_CONDITION_GROUP_H
|
||||
91
engines/qdengine/qdcore/qd_condition_object_reference.cpp
Normal file
91
engines/qdengine/qdcore/qd_condition_object_reference.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/xml_tag.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_named_object_indexer.h"
|
||||
#include "qdengine/qdcore/qd_condition_object_reference.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdConditionObjectReference::qdConditionObjectReference() : _object(NULL) {
|
||||
}
|
||||
|
||||
qdConditionObjectReference::qdConditionObjectReference(const qdConditionObjectReference &ref) :
|
||||
_object(ref._object) {
|
||||
}
|
||||
|
||||
qdConditionObjectReference::~qdConditionObjectReference() {
|
||||
}
|
||||
|
||||
qdConditionObjectReference &qdConditionObjectReference::operator = (const qdConditionObjectReference &ref) {
|
||||
if (this == &ref) return *this;
|
||||
|
||||
_object = ref._object;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void qdConditionObjectReference::set_object(qdNamedObject *p) {
|
||||
_object = p;
|
||||
}
|
||||
|
||||
bool qdConditionObjectReference::find_object() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdConditionObjectReference::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_NAMED_OBJECT: {
|
||||
qdNamedObjectReference &ref = qdNamedObjectIndexer::instance().add_reference((qdNamedObject *&)_object);
|
||||
ref.load_script(&*it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionObjectReference::save_script(Common::WriteStream &fh, int indent, int id) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString(Common::String::format("<condition_object ID=\"%d\">\r\n", id));
|
||||
if (_object) {
|
||||
qdNamedObjectReference ref(_object);
|
||||
ref.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</condition_object>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
66
engines/qdengine/qdcore/qd_condition_object_reference.h
Normal file
66
engines/qdengine/qdcore/qd_condition_object_reference.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_CONDITION_OBJECT_REFERENCE_H
|
||||
#define QDENGINE_QDCORE_QD_CONDITION_OBJECT_REFERENCE_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_named_object_reference.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdNamedObject;
|
||||
|
||||
class qdConditionObjectReference {
|
||||
public:
|
||||
qdConditionObjectReference();
|
||||
qdConditionObjectReference(const qdConditionObjectReference &ref);
|
||||
~qdConditionObjectReference();
|
||||
|
||||
qdConditionObjectReference &operator = (const qdConditionObjectReference &ref);
|
||||
|
||||
void set_object(qdNamedObject *p);
|
||||
bool find_object();
|
||||
|
||||
const qdNamedObject *object() const {
|
||||
return _object;
|
||||
}
|
||||
|
||||
bool is_empty() const {
|
||||
if (_object) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0, int id = 0) const;
|
||||
|
||||
private:
|
||||
|
||||
qdNamedObject *_object;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_CONDITION_OBJECT_REFERENCE_H
|
||||
310
engines/qdengine/qdcore/qd_conditional_object.cpp
Normal file
310
engines/qdengine/qdcore/qd_conditional_object.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
/* 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_conditional_object.h"
|
||||
#include "qdengine/qdcore/qd_game_scene.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
qdConditionalObject::qdConditionalObject() : _conditions_mode(CONDITIONS_OR) {
|
||||
}
|
||||
|
||||
qdConditionalObject::qdConditionalObject(const qdConditionalObject &obj) : qdNamedObject(obj),
|
||||
_conditions_mode(obj._conditions_mode),
|
||||
_conditions(obj._conditions),
|
||||
_condition_groups(obj._condition_groups) {
|
||||
}
|
||||
|
||||
qdConditionalObject::~qdConditionalObject() {
|
||||
}
|
||||
|
||||
qdConditionalObject &qdConditionalObject::operator = (const qdConditionalObject &obj) {
|
||||
if (this == &obj) return *this;
|
||||
|
||||
*static_cast<qdNamedObject *>(this) = obj;
|
||||
|
||||
_conditions_mode = obj._conditions_mode;
|
||||
_conditions = obj._conditions;
|
||||
_condition_groups = obj._condition_groups;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
int qdConditionalObject::add_condition(const qdCondition *p) {
|
||||
_conditions.push_back(*p);
|
||||
_conditions.back().set_owner(this);
|
||||
|
||||
return _conditions.size() - 1;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::update_condition(int num, const qdCondition &p) {
|
||||
assert(num >= 0 && num < (int)_conditions.size());
|
||||
|
||||
qdCondition &cond = _conditions[num];
|
||||
cond = p;
|
||||
cond.set_owner(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::check_conditions() {
|
||||
qdCondition::clear_successful_clicks();
|
||||
|
||||
if (!_conditions.empty()) {
|
||||
switch (conditions_mode()) {
|
||||
case CONDITIONS_AND:
|
||||
for (conditions_container_t::iterator it = _conditions.begin(); it != _conditions.end(); ++it) {
|
||||
if (!it->is_in_group()) {
|
||||
if (!it->check())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (condition_groups_container_t::iterator it = _condition_groups.begin(); it != _condition_groups.end(); ++it) {
|
||||
if (!check_group_conditions(*it))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case CONDITIONS_OR:
|
||||
for (conditions_container_t::iterator it = _conditions.begin(); it != _conditions.end(); ++it) {
|
||||
if (!it->is_in_group()) {
|
||||
if (it->check())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (condition_groups_container_t::iterator it = _condition_groups.begin(); it != _condition_groups.end(); ++it) {
|
||||
if (check_group_conditions(*it))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::remove_conditon(int idx) {
|
||||
assert(idx >= 0 && idx < (int)_conditions.size());
|
||||
|
||||
_conditions.erase(_conditions.begin() + idx);
|
||||
|
||||
for (condition_groups_container_t::iterator it = _condition_groups.begin(); it != _condition_groups.end(); ++it)
|
||||
it->remove_condition(idx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::load_conditions_script(const xml::tag *p) {
|
||||
int count = 0;
|
||||
int gr_count = 0;
|
||||
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_CONDITION:
|
||||
count++;
|
||||
break;
|
||||
case QDSCR_CONDITION_GROUP:
|
||||
gr_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count) _conditions.resize(count);
|
||||
conditions_container_t::iterator ict = _conditions.begin();
|
||||
|
||||
if (gr_count) _condition_groups.resize(gr_count);
|
||||
condition_groups_container_t::iterator igt = _condition_groups.begin();
|
||||
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_CONDITION:
|
||||
if (const xml::tag *tp = it->search_subtag(QDSCR_TYPE)) {
|
||||
qdCondition *cp = &*ict;
|
||||
cp->set_type(qdCondition::ConditionType(xml::tag_buffer(*tp).get_int()));
|
||||
cp->load_script(&*it);
|
||||
cp->set_owner(this);
|
||||
}
|
||||
++ict;
|
||||
break;
|
||||
case QDSCR_CONDITION_GROUP:
|
||||
if (const xml::tag *tp = it->search_subtag(QDSCR_TYPE))
|
||||
igt->set_conditions_mode(qdConditionGroup::conditions_mode_t(xml::tag_buffer(*tp).get_int()));
|
||||
igt->load_script(&*it);
|
||||
++igt;
|
||||
break;
|
||||
case QDSCR_CONDITIONS_MODE:
|
||||
set_conditions_mode(ConditionsMode((xml::tag_buffer(*it).get_int())));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _conditions.size(); i++) {
|
||||
if (is_condition_in_group(i))
|
||||
_conditions[i].add_group_reference();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::save_conditions_script(Common::WriteStream &fh, int indent) const {
|
||||
if (_conditions.size()) {
|
||||
for (auto &it : _conditions) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
if (debugChannelSet(-1, kDebugLog))
|
||||
fh.writeString(Common::String::format("<conditions_mode>%s</conditions_mode>\r\n", _conditions_mode == CONDITIONS_AND ? "CONDITIONS_AND" : "CONDITIONS_OR"));
|
||||
else
|
||||
fh.writeString(Common::String::format("<conditions_mode>%d</conditions_mode>\r\n", _conditions_mode));
|
||||
}
|
||||
|
||||
for (auto &it : _condition_groups) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdConditionalObject::conditions_quant(float dt) {
|
||||
for (auto &it : _conditions) {
|
||||
it.quant(dt);
|
||||
}
|
||||
}
|
||||
|
||||
bool qdConditionalObject::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
debugC(4, kDebugSave, " qdConditionalObject::load_data(): before: %d", (int)fh.pos());
|
||||
if (!qdNamedObject::load_data(fh, save_version))
|
||||
return false;
|
||||
|
||||
for (auto &it : _conditions)
|
||||
it.load_data(fh, save_version);
|
||||
|
||||
debugC(4, kDebugSave, " qdConditionalObject::load_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::save_data(Common::WriteStream &fh) const {
|
||||
debugC(4, kDebugSave, " qdConditionalObject::save_data(): before: %d", (int)fh.pos());
|
||||
if (!qdNamedObject::save_data(fh)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto &it : _conditions)
|
||||
it.save_data(fh);
|
||||
|
||||
debugC(4, kDebugSave, " qdConditionalObject::save_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::check_group_conditions(const qdConditionGroup &gr) {
|
||||
switch (gr.conditions_mode()) {
|
||||
case qdConditionGroup::CONDITIONS_AND:
|
||||
for (qdConditionGroup::conditions_iterator_t it = gr.conditions_begin(); it != gr.conditions_end(); ++it) {
|
||||
if (!_conditions[*it].check())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case qdConditionGroup::CONDITIONS_OR:
|
||||
for (qdConditionGroup::conditions_iterator_t it = gr.conditions_begin(); it != gr.conditions_end(); ++it) {
|
||||
if (_conditions[*it].check())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::is_condition_in_group(int condition_idx) const {
|
||||
for (condition_groups_container_t::const_iterator it = _condition_groups.begin(); it != _condition_groups.end(); ++it) {
|
||||
if (Common::find(it->conditions_begin(), it->conditions_end(), condition_idx) != it->conditions_end())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int qdConditionalObject::add_condition_group(const qdConditionGroup *p) {
|
||||
_condition_groups.push_back(*p);
|
||||
return _condition_groups.size() - 1;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::update_condition_group(int num, const qdConditionGroup &p) {
|
||||
assert(num >= 0 && num < (int)_condition_groups.size());
|
||||
|
||||
qdConditionGroup &gr = _condition_groups[num];
|
||||
gr = p;
|
||||
|
||||
for (uint i = 0; i < _conditions.size(); i++) {
|
||||
if (is_condition_in_group(i))
|
||||
_conditions[i].add_group_reference();
|
||||
else
|
||||
_conditions[i].remove_group_reference();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::remove_conditon_group(int idx) {
|
||||
assert(idx >= 0 && idx < (int)_condition_groups.size());
|
||||
|
||||
_condition_groups.erase(_condition_groups.begin() + idx);
|
||||
|
||||
for (uint i = 0; i < _conditions.size(); i++) {
|
||||
if (is_condition_in_group(i))
|
||||
_conditions[i].add_group_reference();
|
||||
else
|
||||
_conditions[i].remove_group_reference();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool qdConditionalObject::init() {
|
||||
bool result = true;
|
||||
|
||||
for (uint i = 0; i < _conditions.size(); i++) {
|
||||
if (!_conditions[i].init())
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool qdConditionalObject::trigger_can_start() const {
|
||||
if (const qdGameScene *p = static_cast<const qdGameScene *>(owner(QD_NAMED_OBJECT_SCENE)))
|
||||
return p->is_active();
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
163
engines/qdengine/qdcore/qd_conditional_object.h
Normal file
163
engines/qdengine/qdcore/qd_conditional_object.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_CONDITIONAL_OBJECT_H
|
||||
#define QDENGINE_QDCORE_CONDITIONAL_OBJECT_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_condition.h"
|
||||
#include "qdengine/qdcore/qd_condition_group.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Объект с условиями.
|
||||
class qdConditionalObject : public qdNamedObject {
|
||||
public:
|
||||
qdConditionalObject();
|
||||
qdConditionalObject(const qdConditionalObject &obj);
|
||||
~qdConditionalObject();
|
||||
|
||||
qdConditionalObject &operator = (const qdConditionalObject &obj);
|
||||
|
||||
//! Режим проверки условий.
|
||||
enum ConditionsMode {
|
||||
//! "И" - должны выполниться все условия.
|
||||
CONDITIONS_AND,
|
||||
//! "ИЛИ" - достаточно выполнения одного из условий.
|
||||
CONDITIONS_OR
|
||||
};
|
||||
|
||||
typedef Std::vector<qdCondition> conditions_container_t;
|
||||
typedef Std::vector<qdConditionGroup> condition_groups_container_t;
|
||||
|
||||
//! Возвращает true, если условия выполняются.
|
||||
virtual bool check_conditions();
|
||||
//! Добавляет условие. Возвращает поярдковый номер,-1 в случае ошибки.
|
||||
int add_condition(const qdCondition *p);
|
||||
//! Обновляет условие условие с порядковым номером num.
|
||||
bool update_condition(int num, const qdCondition &p);
|
||||
|
||||
//! Удаляет условие.
|
||||
bool remove_conditon(int idx);
|
||||
|
||||
//! Возвращает указатель на условие.
|
||||
const qdCondition *get_condition(int idx = 0) const {
|
||||
return &*(_conditions.begin() + idx);
|
||||
}
|
||||
|
||||
//! Возвращает количество условий.
|
||||
int conditions_count() const {
|
||||
return _conditions.size();
|
||||
}
|
||||
|
||||
//! Добавляет группу условий. Возвращает поярдковый номер,-1 в случае ошибки.
|
||||
int add_condition_group(const qdConditionGroup *p);
|
||||
//! Обновляет группу условий с порядковым номером num.
|
||||
bool update_condition_group(int num, const qdConditionGroup &p);
|
||||
|
||||
//! Удаляет группу условий.
|
||||
bool remove_conditon_group(int idx);
|
||||
|
||||
//! Возвращает указатель на группу условий.
|
||||
const qdConditionGroup *get_condition_group(int idx = 0) const {
|
||||
return &*(_condition_groups.begin() + idx);
|
||||
}
|
||||
|
||||
//! Возвращает количество групп условий.
|
||||
int condition_groups_count() const {
|
||||
return _condition_groups.size();
|
||||
}
|
||||
|
||||
//! Возвращает режим проверки условий.
|
||||
ConditionsMode conditions_mode() const {
|
||||
return _conditions_mode;
|
||||
}
|
||||
//! Устанавливает режим проверки условий.
|
||||
void set_conditions_mode(ConditionsMode m) {
|
||||
_conditions_mode = m;
|
||||
}
|
||||
|
||||
//! Возвращает true, если список условий не пустой.
|
||||
bool has_conditions() const {
|
||||
return !_conditions.empty();
|
||||
}
|
||||
|
||||
//! Обсчет логики условий, dt - время в секундах.
|
||||
void conditions_quant(float dt);
|
||||
|
||||
//! Инициализация объекта, вызывается при старте и перезепуске игры.
|
||||
virtual bool init();
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
bool is_condition_in_group(int condition_idx) const;
|
||||
|
||||
//! Варианты старта триггера.
|
||||
enum trigger_start_mode {
|
||||
//! запуск не удался
|
||||
TRIGGER_START_FAILED,
|
||||
//! включить активный режим у триггера
|
||||
TRIGGER_START_ACTIVATE,
|
||||
//! включить ждущий режим у триггера
|
||||
TRIGGER_START_WAIT
|
||||
};
|
||||
//! Активация триггера.
|
||||
virtual trigger_start_mode trigger_start() = 0;
|
||||
|
||||
//! Возвращает true, если триггер может быть активирован при выполнении его внутренних условий.
|
||||
/**
|
||||
Объект должен принадлежать активной сцене (игровые объекты, зоны на сетке, музыка)
|
||||
или не зависеть от нее (сцены, мини-игры и т.д.).
|
||||
*/
|
||||
virtual bool trigger_can_start() const;
|
||||
|
||||
protected:
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_conditions_script(const xml::tag *p);
|
||||
//! Запись данных в скрипт.
|
||||
bool save_conditions_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
private:
|
||||
|
||||
//! Логика проверки условий - И/ИЛИ.
|
||||
ConditionsMode _conditions_mode;
|
||||
|
||||
//! Условия.
|
||||
conditions_container_t _conditions;
|
||||
|
||||
//! Группы условий.
|
||||
condition_groups_container_t _condition_groups;
|
||||
|
||||
bool check_group_conditions(const qdConditionGroup &gr);
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_CONDITIONAL_OBJECT_H
|
||||
355
engines/qdengine/qdcore/qd_contour.cpp
Normal file
355
engines/qdengine/qdcore/qd_contour.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/qdcore/qd_contour.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdContour::qdContour(qdContourType tp) : _contour_type(tp),
|
||||
_size(0, 0),
|
||||
_mask_pos(0, 0) {
|
||||
}
|
||||
|
||||
qdContour::qdContour(const qdContour &ct) : _contour_type(ct._contour_type),
|
||||
_size(ct._size),
|
||||
_contour(ct._contour),
|
||||
_mask(ct._mask) {
|
||||
_mask_pos = ct._mask_pos;
|
||||
}
|
||||
|
||||
qdContour::~qdContour() {
|
||||
_contour.clear();
|
||||
}
|
||||
|
||||
qdContour &qdContour::operator = (const qdContour &ct) {
|
||||
if (this == &ct) return *this;
|
||||
|
||||
_contour_type = ct._contour_type;
|
||||
_size = ct._size;
|
||||
_mask_pos = ct._mask_pos;
|
||||
|
||||
_mask = ct._mask;
|
||||
|
||||
_contour = ct._contour;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void qdContour::add_contour_point(const Vect2s &pt) {
|
||||
_contour.push_back(pt);
|
||||
}
|
||||
|
||||
void qdContour::insert_contour_point(const Vect2s &pt, int insert_pos) {
|
||||
if (insert_pos < (int)_contour.size()) {
|
||||
if (insert_pos < 0) insert_pos = 0;
|
||||
_contour.insert(_contour.begin() + insert_pos, pt);
|
||||
} else {
|
||||
_contour.push_back(pt);
|
||||
}
|
||||
}
|
||||
|
||||
bool qdContour::remove_contour_point(int pos) {
|
||||
if (pos >= 0 && pos < (int)_contour.size()) {
|
||||
_contour.erase(_contour.begin() + pos);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdContour::update_contour_point(const Vect2s &pt, int pos) {
|
||||
if (pos >= 0 && pos < (int)_contour.size()) {
|
||||
_contour[pos] = pt;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdContour::createMaskOld(int x0, int y0, int x1, int y1) {
|
||||
_mask.resize(_size.x * _size.y);
|
||||
Common::fill(_mask.begin(), _mask.end(), 0);
|
||||
|
||||
Std::vector<int> intersections;
|
||||
intersections.reserve(_contour.size());
|
||||
|
||||
Std::vector<byte>::iterator it = _mask.begin();
|
||||
for (int y = y0; y <= y1; y++) {
|
||||
byte *ptr = &*it;
|
||||
|
||||
for (uint i = 0; i < _contour.size(); i++) {
|
||||
Vect2s p0 = _contour[i];
|
||||
Vect2s p1 = (i < _contour.size() - 1) ? _contour[i + 1] : _contour[0];
|
||||
|
||||
if (p0.y != p1.y) {
|
||||
if (((p0.y << 2) <= (y << 2) + 2 && (p1.y << 2) >= (y << 2) + 2) || ((p0.y << 2) >= (y << 2) + 2 && (p1.y << 2) <= (y << 2) + 2))
|
||||
intersections.push_back((y - p0.y) * (p1.x - p0.x) / (p1.y - p0.y) + p0.x);
|
||||
}
|
||||
}
|
||||
|
||||
if (intersections.size() > 1) {
|
||||
Common::sort(intersections.begin(), intersections.end());
|
||||
for (uint i = 0; i < intersections.size() - 1; i += 2) {
|
||||
int xl = intersections[i];
|
||||
int xr = intersections[i + 1];
|
||||
|
||||
if (xr > xl) {
|
||||
byte *p = ptr + xl - x0;
|
||||
for (int col = xl; col <= xr; col++)
|
||||
*p++ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intersections.clear();
|
||||
|
||||
for (uint i = 0; i < _contour.size(); i++) {
|
||||
Vect2s p0 = _contour[i];
|
||||
Vect2s p1 = (i < _contour.size() - 1) ? _contour[i + 1] : _contour[0];
|
||||
|
||||
if (p0.y != p1.y) {
|
||||
if (((p0.y << 2) <= (y << 2) - 2 && (p1.y << 2) >= (y << 2) - 2) || ((p0.y << 2) >= (y << 2) - 2 && (p1.y << 2) <= (y << 2) - 2))
|
||||
intersections.push_back((y - p0.y) * (p1.x - p0.x) / (p1.y - p0.y) + p0.x);
|
||||
}
|
||||
}
|
||||
|
||||
if (intersections.size() > 1) {
|
||||
Common::sort(intersections.begin(), intersections.end());
|
||||
for (uint i = 0; i < intersections.size() - 1; i += 2) {
|
||||
int xl = intersections[i];
|
||||
int xr = intersections[i + 1];
|
||||
|
||||
if (xr > xl) {
|
||||
byte *p = ptr + xl - x0;
|
||||
for (int col = xl; col <= xr; col++)
|
||||
*p++ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
intersections.clear();
|
||||
|
||||
it += _size.x;
|
||||
}
|
||||
}
|
||||
|
||||
bool qdContour::update_contour() {
|
||||
if (_contour_type != CONTOUR_POLYGON) return false;
|
||||
|
||||
if (_contour.empty())
|
||||
return false;
|
||||
|
||||
int x0 = _contour[0].x;
|
||||
int x1 = _contour[0].x;
|
||||
int y0 = _contour[0].y;
|
||||
int y1 = _contour[0].y;
|
||||
|
||||
for (uint i = 0; i < _contour.size(); i++) {
|
||||
if (_contour[i].x < x0) x0 = _contour[i].x;
|
||||
if (_contour[i].x > x1) x1 = _contour[i].x;
|
||||
if (_contour[i].y < y0) y0 = _contour[i].y;
|
||||
if (_contour[i].y > y1) y1 = _contour[i].y;
|
||||
}
|
||||
|
||||
_size = Vect2s(x1 - x0 + 1, y1 - y0 + 1);
|
||||
_mask_pos = Vect2s(x0 + _size.x / 2, y0 + _size.y / 2);
|
||||
|
||||
if (g_engine->_gameVersion <= 20050101)
|
||||
createMaskOld(x0, y0, x1, y1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdContour::is_inside(const Vect2s &pos) const {
|
||||
switch (_contour_type) {
|
||||
case CONTOUR_RECTANGLE:
|
||||
if (pos.x >= -_size.x / 2 && pos.x < _size.x / 2 && pos.y >= -_size.y / 2 && pos.y < _size.y / 2)
|
||||
return true;
|
||||
break;
|
||||
case CONTOUR_CIRCLE:
|
||||
if (pos.x * pos.x + pos.y * pos.y <= _size.x * _size.x)
|
||||
return true;
|
||||
break;
|
||||
case CONTOUR_POLYGON: {
|
||||
if (g_engine->_gameVersion > 20050101) {
|
||||
Vect2s p = pos;
|
||||
int intersections_lt0 = 0;
|
||||
int intersections_gt0 = 0;
|
||||
int intersections_lt1 = 0;
|
||||
int intersections_gt1 = 0;
|
||||
for (uint i = 0; i < _contour.size(); i ++) {
|
||||
Vect2s p0 = _contour[i];
|
||||
Vect2s p1 = (i < _contour.size() - 1) ? _contour[i + 1] : _contour[0];
|
||||
if (p0.y != p1.y) {
|
||||
if ((p0.y < p.y && p1.y >= p.y) || (p0.y >= p.y && p1.y < p.y)) {
|
||||
if (p0.x < p.x && p1.x < p.x)
|
||||
intersections_lt0++;
|
||||
else if (p0.x > p.x && p1.x > p.x)
|
||||
intersections_gt0++;
|
||||
else {
|
||||
int x = (p.y - p0.y) * (p1.x - p0.x) / (p1.y - p0.y) + p0.x;
|
||||
|
||||
if (x == p.x)
|
||||
return true;
|
||||
else if (x > p.x)
|
||||
intersections_gt0++;
|
||||
else
|
||||
intersections_lt0++;
|
||||
}
|
||||
}
|
||||
if ((p0.y <= p.y && p1.y > p.y) || (p0.y > p.y && p1.y <= p.y)) {
|
||||
if (p0.x < p.x && p1.x < p.x)
|
||||
intersections_lt1++;
|
||||
else if (p0.x > p.x && p1.x > p.x)
|
||||
intersections_gt1++;
|
||||
else {
|
||||
int x = (p.y - p0.y) * (p1.x - p0.x) / (p1.y - p0.y) + p0.x;
|
||||
|
||||
if (x == p.x)
|
||||
return true;
|
||||
else if (x > p.x)
|
||||
intersections_gt1++;
|
||||
else
|
||||
intersections_lt1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ((intersections_lt0 & 1) && intersections_gt0 != 0) ||
|
||||
((intersections_lt1 & 1) && intersections_gt1 != 0);
|
||||
} else {
|
||||
Vect2s p = pos - _mask_pos;
|
||||
p.x += _size.x / 2;
|
||||
p.y += _size.y / 2;
|
||||
if (p.x >= 0 && p.x < _size.x && p.y >= 0 && p.y < _size.y) {
|
||||
if (_mask[p.x + p.y * _size.x])
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdContour::save_script(Common::WriteStream &fh, int indent) const {
|
||||
if (_contour_type == CONTOUR_POLYGON) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<contour_polygon>%d", contour_size() * 2));
|
||||
for (int j = 0; j < contour_size(); j++) {
|
||||
fh.writeString(Common::String::format(" %d %d", _contour[j].x, _contour[j].y));
|
||||
}
|
||||
fh.writeString("</contour_polygon>\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_contour_type == CONTOUR_RECTANGLE) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<contour_rect>%d %d</contour_rect>\r\n", _size.x, _size.y));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_contour_type == CONTOUR_CIRCLE) {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<contour_circle>%d</contour_circle>\r\n", _size.x));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdContour::load_script(const xml::tag *p) {
|
||||
int i;
|
||||
|
||||
Vect2s v;
|
||||
xml::tag_buffer buf(*p);
|
||||
|
||||
switch (_contour_type) {
|
||||
case CONTOUR_RECTANGLE:
|
||||
buf > v.x > v.y;
|
||||
_size = Vect2s(v);
|
||||
return true;
|
||||
case CONTOUR_CIRCLE:
|
||||
_size.x = _size.y = buf.get_short();
|
||||
return true;
|
||||
case CONTOUR_POLYGON:
|
||||
_contour.reserve(p->data_size() / 2);
|
||||
for (i = 0; i < p->data_size(); i += 2) {
|
||||
buf > v.x > v.y;
|
||||
add_contour_point(v);
|
||||
}
|
||||
update_contour();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdContour::divide_contour(int shift) {
|
||||
Std::vector<Vect2s>::iterator _itr = _contour.begin(), _end = _contour.end();
|
||||
for (; _itr != _end; ++_itr) {
|
||||
Vect2s &v = *_itr;
|
||||
v.x >>= shift;
|
||||
v.y >>= shift;
|
||||
}
|
||||
}
|
||||
|
||||
void qdContour::mult_contour(int shift) {
|
||||
Std::vector<Vect2s>::iterator _itr = _contour.begin(), _end = _contour.end();
|
||||
for (; _itr != _end; ++_itr) {
|
||||
Vect2s &v = *_itr;
|
||||
v.x <<= shift;
|
||||
v.y <<= shift;
|
||||
}
|
||||
}
|
||||
|
||||
void qdContour::shift_contour(int dx, int dy) {
|
||||
Std::vector<Vect2s>::iterator _itr = _contour.begin(), _end = _contour.end();
|
||||
for (; _itr != _end; ++_itr) {
|
||||
Vect2s &v = *_itr;
|
||||
v.x += dx;
|
||||
v.y += dy;
|
||||
}
|
||||
}
|
||||
|
||||
bool qdContour::can_be_closed() const {
|
||||
if (_contour_type != CONTOUR_POLYGON)
|
||||
return false;
|
||||
|
||||
return (_contour.size() > 2);
|
||||
}
|
||||
|
||||
bool qdContour::is_contour_empty() const {
|
||||
if (_contour_type == CONTOUR_POLYGON)
|
||||
return (_contour.size() < 3);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
173
engines/qdengine/qdcore/qd_contour.h
Normal file
173
engines/qdengine/qdcore/qd_contour.h
Normal file
@@ -0,0 +1,173 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_CONTOUR_H
|
||||
#define QDENGINE_QDCORE_QD_CONTOUR_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/xmath.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Контур.
|
||||
/**
|
||||
Используется для задания масок на статических объектах,
|
||||
зон на сетке и формы элементов GUI.
|
||||
*/
|
||||
class qdContour {
|
||||
public:
|
||||
enum qdContourType {
|
||||
//! Прямоугольник
|
||||
CONTOUR_RECTANGLE,
|
||||
//! Окружность
|
||||
CONTOUR_CIRCLE,
|
||||
//! Произвольный многоугольник
|
||||
CONTOUR_POLYGON
|
||||
};
|
||||
|
||||
qdContour(qdContourType tp = CONTOUR_POLYGON);
|
||||
qdContour(const qdContour &ct);
|
||||
virtual ~qdContour();
|
||||
|
||||
qdContour &operator = (const qdContour &ct);
|
||||
|
||||
//! Возвращает тип контура.
|
||||
qdContourType contour_type() const {
|
||||
return _contour_type;
|
||||
}
|
||||
//! Устанавливает тип контура.
|
||||
void set_contour_type(qdContourType tp) {
|
||||
_contour_type = tp;
|
||||
}
|
||||
|
||||
//! Возвращает горизонтальный размер контура.
|
||||
int size_x() const {
|
||||
return _size.x;
|
||||
}
|
||||
//! Возвращает вертикальный размер контура.
|
||||
int size_y() const {
|
||||
return _size.y;
|
||||
}
|
||||
|
||||
//! Возвращает true, если точка с координатами pos лежит внутри контура.
|
||||
bool is_inside(const Vect2s &pos) const;
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
virtual bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Чтение данных из скрипта.
|
||||
virtual bool load_script(const xml::tag *p);
|
||||
|
||||
//! Добавляет точку в контур.
|
||||
/**
|
||||
pt - координаты точки
|
||||
*/
|
||||
void add_contour_point(const Vect2s &pt);
|
||||
//! Вставляет точку в контур.
|
||||
/**
|
||||
pt - координаты точки, insert_pos - номер точки, перед которой добавится новая.
|
||||
*/
|
||||
void insert_contour_point(const Vect2s &pt, int insert_pos = 0);
|
||||
//! Удаляет точку номер pos из контура.
|
||||
bool remove_contour_point(int pos);
|
||||
//! Присваивает точке номер pos контура координаты pt.
|
||||
bool update_contour_point(const Vect2s &pt, int pos);
|
||||
|
||||
//! Удаляет все точки из контура.
|
||||
void clear_contour() {
|
||||
_contour.clear();
|
||||
}
|
||||
|
||||
//! Делит координаты контура на 2 в степени shift.
|
||||
void divide_contour(int shift = 1);
|
||||
//! Умножает координаты контура на 2 в степени shift.
|
||||
void mult_contour(int shift = 1);
|
||||
//! Добавляет к соответствующим координатам dx, dy.
|
||||
void shift_contour(int dx, int dy);
|
||||
|
||||
//! Возвращает координаты точки контура номер pos.
|
||||
const Vect2s &get_point(int pos) const {
|
||||
return _contour[pos];
|
||||
}
|
||||
|
||||
void createMaskOld(int x0, int y0, int x1, int y1);
|
||||
|
||||
const byte *maskData() const {
|
||||
return &*_mask.begin();
|
||||
}
|
||||
|
||||
//! Возвращает размеры маски.
|
||||
const Vect2s &mask_size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
//! Возвращает координаты центра маски.
|
||||
const Vect2s &mask_pos() const {
|
||||
return _mask_pos;
|
||||
}
|
||||
|
||||
//! Возвращает количество точек в контуре.
|
||||
int contour_size() const {
|
||||
return _contour.size();
|
||||
}
|
||||
//! Возвращает массив точек контура.
|
||||
const Std::vector<Vect2s> &get_contour() const {
|
||||
return _contour;
|
||||
}
|
||||
|
||||
bool is_mask_empty() const {
|
||||
return _contour.empty();
|
||||
}
|
||||
|
||||
bool update_contour();
|
||||
|
||||
// можно ли замкнуть текущий контур.
|
||||
// для типов контура CONTOUR_CIRCLE и CONTOUR_RECTANGLE
|
||||
// всегда возвращается false
|
||||
bool can_be_closed() const;
|
||||
|
||||
//! Возвращает true, если контур пустой.
|
||||
bool is_contour_empty() const;
|
||||
|
||||
private:
|
||||
//! Тип контура.
|
||||
qdContourType _contour_type;
|
||||
|
||||
//! Размеры контура.
|
||||
Vect2s _size;
|
||||
|
||||
Vect2s _mask_pos;
|
||||
|
||||
Std::vector<byte> _mask;
|
||||
|
||||
//! Контур.
|
||||
/**
|
||||
Произвольный замкнутый контур. Задается для CONTOUR_POLYGON.
|
||||
*/
|
||||
Std::vector<Vect2s> _contour;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_CONTOUR_H
|
||||
520
engines/qdengine/qdcore/qd_coords_animation.cpp
Normal file
520
engines/qdengine/qdcore/qd_coords_animation.cpp
Normal file
@@ -0,0 +1,520 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/xmath.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/qdcore/qd_coords_animation.h"
|
||||
#include "qdengine/qdcore/qd_game_object_animated.h"
|
||||
#include "qdengine/qdcore/qd_game_object_moving.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdCoordsAnimation::qdCoordsAnimation() : _status(false),
|
||||
_is_finished(false),
|
||||
_type(CA_INTERPOLATE_COORDS),
|
||||
_animation_phase(0.0f),
|
||||
_speed(100.0f),
|
||||
_start_object(NULL),
|
||||
_cur_point(0) {
|
||||
}
|
||||
|
||||
qdCoordsAnimation::qdCoordsAnimation(const qdCoordsAnimation &anm) : qdNamedObject(anm),
|
||||
_status(false),
|
||||
_is_finished(false),
|
||||
_type(anm._type),
|
||||
_animation_phase(anm._animation_phase),
|
||||
_speed(anm._speed),
|
||||
_start_object(anm._start_object),
|
||||
_start_object_ref(anm.start_object_ref()),
|
||||
_points(anm._points),
|
||||
_cur_point(0) {
|
||||
}
|
||||
|
||||
qdCoordsAnimation &qdCoordsAnimation::operator = (const qdCoordsAnimation &anm) {
|
||||
qdNamedObject::operator=(anm);
|
||||
|
||||
_status = false;
|
||||
_is_finished = false;
|
||||
_type = anm._type;
|
||||
_animation_phase = anm._animation_phase;
|
||||
_speed = anm._speed;
|
||||
// Внутри функции устанавливается и _start_object_ref
|
||||
set_start_object(anm.start_object());
|
||||
_points = anm._points;
|
||||
_cur_point = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
qdCoordsAnimation::~qdCoordsAnimation() {
|
||||
_points.clear();
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::set_start_object(const qdGameObject *p_obj) {
|
||||
_start_object = p_obj;
|
||||
if (NULL != p_obj) {
|
||||
qdNamedObjectReference ref(p_obj);
|
||||
_start_object_ref = ref;
|
||||
} else
|
||||
_start_object_ref.clear();
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::calc_paths() const {
|
||||
for (size_t i = 1; i < _points.size(); i++)
|
||||
_points[i].calc_path(_points[i - 1]);
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::add_point(const qdCoordsAnimationPoint *p) {
|
||||
_points.push_back(*p);
|
||||
calc_paths();
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::insert_point(const qdCoordsAnimationPoint *p, int insert_pos) {
|
||||
_points.insert(_points.begin() + insert_pos, *p);
|
||||
calc_paths();
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::remove_point(int num) {
|
||||
assert(0 <= num && num < (int)_points.size());
|
||||
|
||||
_points.erase(_points.begin() + num);
|
||||
|
||||
if (_cur_point >= (int)_points.size())
|
||||
_cur_point = _points.size() - 1;
|
||||
|
||||
calc_paths();
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::clear() {
|
||||
if (!_points.empty())
|
||||
set_cur_point(0);
|
||||
_cur_point = -1;
|
||||
_points.clear();
|
||||
clear_flags();
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::start() const {
|
||||
_cur_point = 0;
|
||||
|
||||
if (!_points.empty()) {
|
||||
qdGameObjectAnimated *p = object();
|
||||
if (!p) return;
|
||||
|
||||
// Объект будет двигаться по шаблону =>
|
||||
// он выходит из состояния следования
|
||||
qdGameObjectMoving *obj = dynamic_cast<qdGameObjectMoving *>(p);
|
||||
if (NULL != obj)
|
||||
obj->set_follow_condition(qdGameObjectMoving::FOLLOW_DONE);
|
||||
|
||||
// Если траектория должна выполняться относительно текущего положения (или
|
||||
// от центра заданного объекта), то считаем дельту
|
||||
if (true == check_flag(QD_COORDS_ANM_RELATIVE_FLAG)) {
|
||||
if (NULL != _start_object)
|
||||
_del = _points[0].dest_pos() - _start_object->R();
|
||||
else _del = _points[0].dest_pos() - p->R();
|
||||
} else {
|
||||
_del.x = 0;
|
||||
_del.y = 0;
|
||||
_del.z = 0;
|
||||
};
|
||||
|
||||
if (check_flag(QD_COORDS_ANM_OBJECT_START_FLAG))
|
||||
_start_point.set_dest_pos(p->R());
|
||||
else {
|
||||
_start_point.set_dest_pos(_points[0].dest_pos() - _del);
|
||||
// Задана коорд. анимация с перемещением в точку и задан угол =>
|
||||
// устанавливаем направление для движущегося объекта
|
||||
qdGameObjectMoving *mov_obj = dynamic_cast<qdGameObjectMoving *>(obj);
|
||||
if ((NULL != mov_obj) &&
|
||||
(qdCoordsAnimationPoint::NO_DIRECTION != _points[0].direction_angle()))
|
||||
mov_obj->set_direction(_points[0].direction_angle());
|
||||
}
|
||||
|
||||
_points[0].calc_path(_start_point, _del);
|
||||
|
||||
_points[0].start();
|
||||
_status = true;
|
||||
|
||||
p->set_pos(cur_pos());
|
||||
}
|
||||
|
||||
_is_finished = false;
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::stop() const {
|
||||
_status = false;
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::quant(float dt) const {
|
||||
if (!_status || !_points.size()) return;
|
||||
|
||||
if (_type == CA_INTERPOLATE_COORDS) {
|
||||
float path = _speed * dt;
|
||||
while (_points[_cur_point].move(path)) {
|
||||
if (++_cur_point >= (int)_points.size()) {
|
||||
_is_finished = true;
|
||||
if (!check_flag(QD_COORDS_ANM_LOOP_FLAG)) {
|
||||
_cur_point --;
|
||||
stop();
|
||||
break;
|
||||
}
|
||||
|
||||
_start_point.set_dest_pos(_points[_points.size() - 1].dest_pos() - _del);
|
||||
// Расстояние считаем, переместившись в глобальне координаты, так как _points в глобальных
|
||||
_points[0].calc_path(_start_point, _del);
|
||||
|
||||
_cur_point = 0;
|
||||
}
|
||||
_points[_cur_point].start();
|
||||
}
|
||||
|
||||
qdGameObjectAnimated *obj = object();
|
||||
if (obj) obj->set_pos(cur_pos());
|
||||
} else { // _type == CA_WALK
|
||||
qdGameObjectAnimated *obj = object();
|
||||
if (obj->named_object_type() != QD_NAMED_OBJECT_MOVING_OBJ) return;
|
||||
qdGameObjectMoving *p = static_cast<qdGameObjectMoving *>(obj);
|
||||
|
||||
if (p->is_in_position(_points[_cur_point].dest_pos() - _del)) {
|
||||
if (++_cur_point >= (int)_points.size()) {
|
||||
_is_finished = true;
|
||||
if (!check_flag(QD_COORDS_ANM_LOOP_FLAG)) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
_start_point.set_dest_pos(_points[_points.size() - 1].dest_pos() - _del);
|
||||
// Расстояние считаем, переместившись в глобальне координаты
|
||||
_points[0].calc_path(_start_point, _del);
|
||||
|
||||
_cur_point = 0;
|
||||
}
|
||||
|
||||
_points[_cur_point].start();
|
||||
}
|
||||
|
||||
if (!p->is_moving())
|
||||
p->move(_points[_cur_point].dest_pos() - _del, _points[_cur_point].direction_angle());
|
||||
}
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::load_script(const xml::tag *p) {
|
||||
int v;
|
||||
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_COORDS_ANIMATION_POINT: {
|
||||
qdCoordsAnimationPoint fp;
|
||||
fp.load_script(&*it);
|
||||
add_point(&fp);
|
||||
}
|
||||
break;
|
||||
case QDSCR_TYPE:
|
||||
xml::tag_buffer(*it) > v;
|
||||
set_type((qdCoordsAnimationType)v);
|
||||
break;
|
||||
case QDSCR_FLAG:
|
||||
xml::tag_buffer(*it) > v;
|
||||
set_flag(v);
|
||||
break;
|
||||
case QDSCR_SPEED:
|
||||
xml::tag_buffer(*it) > _speed;
|
||||
break;
|
||||
case QDSCR_ANIMATION_PHASE:
|
||||
xml::tag_buffer(*it) > _animation_phase;
|
||||
break;
|
||||
case QDSCR_NAMED_OBJECT:
|
||||
_start_object_ref.load_script(&*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool qdCoordsAnimation::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<coords_animation");
|
||||
|
||||
if (name()) {
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
} else {
|
||||
fh.writeString(" name=\" \"");
|
||||
}
|
||||
|
||||
if (debugChannelSet(-1, kDebugLog))
|
||||
fh.writeString(Common::String::format(" type=\"%s\"", _type == CA_INTERPOLATE_COORDS ? "CA_INTERPOLATE_COORDS" : "CA_WALK"));
|
||||
else
|
||||
fh.writeString(Common::String::format(" type=\"%d\"", (int)_type));
|
||||
|
||||
fh.writeString(Common::String::format(" speed=\"%f\"", _speed));
|
||||
fh.writeString(Common::String::format(" animation_phase=\"%f\"", _animation_phase));
|
||||
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
for (auto &it: _points) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
if (flags()) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
if (debugChannelSet(-1, kDebugLog))
|
||||
fh.writeString(Common::String::format("<flag>%s</flag>\r\n", flag2str(flags()).c_str()));
|
||||
else
|
||||
fh.writeString(Common::String::format("<flag>%d</flag>\r\n", flags()));
|
||||
}
|
||||
|
||||
if (NULL != _start_object) {
|
||||
_start_object_ref.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</coords_animation>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Vect3f qdCoordsAnimation::cur_pos() const {
|
||||
// В cur_pos() учитываем дельту относительных координат
|
||||
qdCoordsAnimationPoint p0;
|
||||
if (0 != _cur_point) {
|
||||
p0 = _points[_cur_point - 1];
|
||||
p0.set_dest_pos(p0.dest_pos() - _del); // Перемещаемся в относительные координаты
|
||||
} else p0 = _start_point;
|
||||
qdCoordsAnimationPoint p1 = _points[_cur_point];
|
||||
p1.set_dest_pos(p1.dest_pos() - _del); // Перемещаемся в относительные координаты
|
||||
|
||||
Vect3f v = p0.dest_pos() + p1.passed_path() * (p1.dest_pos() - p0.dest_pos());
|
||||
return v;
|
||||
}
|
||||
|
||||
qdGameObjectAnimated *qdCoordsAnimation::object() const {
|
||||
if (owner() && owner()->named_object_type() == QD_NAMED_OBJECT_OBJ_STATE) {
|
||||
qdNamedObject *p = owner()->owner();
|
||||
if (p && (p->named_object_type() == QD_NAMED_OBJECT_ANIMATED_OBJ || p->named_object_type() == QD_NAMED_OBJECT_MOVING_OBJ))
|
||||
return static_cast<qdGameObjectAnimated *>(p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool qdCoordsAnimation::set_cur_point(int point_num) const {
|
||||
if (!_points.size()) return false;
|
||||
|
||||
start();
|
||||
|
||||
if (_type == CA_WALK) {
|
||||
if (!object() || object()->named_object_type() != QD_NAMED_OBJECT_MOVING_OBJ) return false;
|
||||
qdGameObjectMoving *p = static_cast<qdGameObjectMoving *>(object());
|
||||
p->set_pos(cur_pos());
|
||||
p->drop_flag(QD_OBJ_MOVING_FLAG);
|
||||
|
||||
p->move(_points[_cur_point].dest_pos());
|
||||
p->skip_movement();
|
||||
|
||||
for (int i = 0; i < point_num; i++) {
|
||||
if (++_cur_point >= (int)_points.size()) {
|
||||
if (!check_flag(QD_COORDS_ANM_LOOP_FLAG)) {
|
||||
stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
_start_point.set_dest_pos(_points[_points.size() - 1].dest_pos());
|
||||
_points[0].calc_path(_start_point);
|
||||
|
||||
_cur_point = 0;
|
||||
}
|
||||
|
||||
_points[_cur_point].start();
|
||||
|
||||
if (!p->move(_points[_cur_point].dest_pos())) return false;
|
||||
if (!p->skip_movement()) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (!object() || _speed < 0.01f) return false;
|
||||
qdGameObjectAnimated *p = object();
|
||||
p->get_animation()->set_time_rel(animation_phase());
|
||||
p->set_pos(cur_pos());
|
||||
|
||||
for (int i = 0; i < point_num; i++) {
|
||||
if (++_cur_point >= (int)_points.size()) {
|
||||
if (!check_flag(QD_COORDS_ANM_LOOP_FLAG)) {
|
||||
stop();
|
||||
if (p->named_object_type() == QD_NAMED_OBJECT_MOVING_OBJ)
|
||||
static_cast<qdGameObjectMoving *>(p)->adjust_z();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_start_point.set_dest_pos(_points[_points.size() - 1].dest_pos());
|
||||
_points[0].calc_path(_start_point);
|
||||
|
||||
_cur_point = 0;
|
||||
}
|
||||
|
||||
_points[_cur_point].start();
|
||||
|
||||
p->set_pos(_points[_cur_point].dest_pos());
|
||||
p->get_animation()->advance_time(_points[_cur_point].path_length() / _speed);
|
||||
}
|
||||
|
||||
if (p->named_object_type() == QD_NAMED_OBJECT_MOVING_OBJ)
|
||||
static_cast<qdGameObjectMoving * >(p)->adjust_z();
|
||||
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
const float dt = 0.005f;
|
||||
while(_cur_point < point_num || _points[_cur_point].passed_path() < 0.99f){
|
||||
quant(dt);
|
||||
p->quant(dt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdCoordsAnimation::reset_cur_point() const {
|
||||
return set_cur_point(_cur_point);
|
||||
}
|
||||
|
||||
void qdCoordsAnimation::set_time_rel(float tm) {
|
||||
assert(tm >= 0.0f && tm <= 1.0f);
|
||||
|
||||
if (!_points.size()) return;
|
||||
|
||||
int pt = tm * float(_points.size() - 1);
|
||||
set_cur_point(pt);
|
||||
}
|
||||
|
||||
bool qdCoordsAnimation::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
debugC(4, kDebugSave, " qdCoordsAnimation::load_data(): before: %d", (int)fh.pos());
|
||||
|
||||
if (!qdNamedObject::load_data(fh, save_version)) return false;
|
||||
|
||||
int v;
|
||||
v = fh.readSint32LE();
|
||||
_status = (v) ? true : false;
|
||||
|
||||
v = fh.readSint32LE();
|
||||
_is_finished = (v) ? true : false;
|
||||
|
||||
_cur_point = fh.readSint32LE();
|
||||
v = fh.readSint32LE();
|
||||
if ((int)_points.size() != v) return false;
|
||||
|
||||
if (save_version >= 101) {
|
||||
_del.x = fh.readFloatLE();
|
||||
_del.y = fh.readFloatLE();
|
||||
_del.z = fh.readFloatLE();
|
||||
} else {
|
||||
_del = Vect3f(0, 0, 0);
|
||||
}
|
||||
|
||||
for (auto &it : _points)
|
||||
it.load_data(fh, save_version);
|
||||
|
||||
_start_point.load_data(fh, save_version);
|
||||
|
||||
Vect3f vec;
|
||||
vec.x = fh.readFloatLE();
|
||||
vec.y = fh.readFloatLE();
|
||||
vec.z = fh.readFloatLE();
|
||||
_start_point.set_dest_pos(vec);
|
||||
|
||||
debugC(4, kDebugSave, " qdCoordsAnimation::load_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCoordsAnimation::save_data(Common::WriteStream &fh) const {
|
||||
debugC(4, kDebugSave, " qdCoordsAnimation::save_data(): before: %d", (int)fh.pos());
|
||||
if (!qdNamedObject::save_data(fh)) return false;
|
||||
|
||||
fh.writeSint32LE(static_cast<int>(_status));
|
||||
fh.writeSint32LE(static_cast<int>(_is_finished));
|
||||
fh.writeSint32LE(_cur_point);
|
||||
fh.writeUint32LE(_points.size());
|
||||
|
||||
fh.writeFloatLE(_del.x);
|
||||
fh.writeFloatLE(_del.y);
|
||||
fh.writeFloatLE(_del.z);
|
||||
|
||||
for (qdCoordsAnimationPointVector::const_iterator it = _points.begin(); it != _points.end(); ++it)
|
||||
it->save_data(fh);
|
||||
|
||||
_start_point.save_data(fh);
|
||||
|
||||
fh.writeFloatLE(_start_point.dest_pos().x);
|
||||
fh.writeFloatLE(_start_point.dest_pos().y);
|
||||
fh.writeFloatLE(_start_point.dest_pos().z);
|
||||
debugC(4, kDebugSave, " qdCoordsAnimation::save_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
#define defFlag(x) { x, #x }
|
||||
|
||||
struct FlagsList {
|
||||
int f;
|
||||
const char *s;
|
||||
} static flagList[] = {
|
||||
defFlag(QD_COORDS_ANM_OBJECT_START_FLAG),
|
||||
defFlag(QD_COORDS_ANM_LOOP_FLAG),
|
||||
defFlag(QD_COORDS_ANM_RELATIVE_FLAG),
|
||||
};
|
||||
|
||||
Common::String qdCoordsAnimation::flag2str(int fl) const {
|
||||
Common::String res;
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(flagList); i++) {
|
||||
if (fl & flagList[i].f) {
|
||||
if (!res.empty())
|
||||
res += " | ";
|
||||
|
||||
res += flagList[i].s;
|
||||
|
||||
fl &= ~flagList[i].f;
|
||||
}
|
||||
}
|
||||
|
||||
if (fl)
|
||||
res += Common::String::format(" | %x", fl);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
165
engines/qdengine/qdcore/qd_coords_animation.h
Normal file
165
engines/qdengine/qdcore/qd_coords_animation.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_COORDS_ANIMATION_H
|
||||
#define QDENGINE_QDCORE_QD_COORDS_ANIMATION_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
#include "qdengine/qdcore/qd_coords_animation_point.h"
|
||||
#include "qdengine/qdcore/qd_named_object_reference.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
const int QD_COORDS_ANM_OBJECT_START_FLAG = 0x01;
|
||||
const int QD_COORDS_ANM_LOOP_FLAG = 0x02;
|
||||
const int QD_COORDS_ANM_RELATIVE_FLAG = 0x04; // Флаг перемещения траектории в текущую точку нахождения объекта
|
||||
|
||||
class qdCoordsAnimation : public qdNamedObject {
|
||||
public:
|
||||
enum qdCoordsAnimationType {
|
||||
CA_INTERPOLATE_COORDS,
|
||||
CA_WALK
|
||||
};
|
||||
|
||||
qdCoordsAnimation();
|
||||
qdCoordsAnimation(const qdCoordsAnimation &anm);
|
||||
~qdCoordsAnimation();
|
||||
|
||||
qdCoordsAnimation &operator = (const qdCoordsAnimation &anm);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_COORDS_ANIMATION;
|
||||
}
|
||||
|
||||
float speed() const {
|
||||
return _speed;
|
||||
}
|
||||
void set_speed(float sp) {
|
||||
_speed = sp;
|
||||
}
|
||||
|
||||
const qdGameObject *start_object() const {
|
||||
return _start_object;
|
||||
}
|
||||
void set_start_object(const qdGameObject *p_obj);
|
||||
const qdNamedObjectReference &start_object_ref() const {
|
||||
return _start_object_ref;
|
||||
}
|
||||
|
||||
bool is_playing() const {
|
||||
return _status;
|
||||
}
|
||||
bool is_finished() const {
|
||||
return _is_finished;
|
||||
}
|
||||
|
||||
qdCoordsAnimationType type() const {
|
||||
return _type;
|
||||
}
|
||||
void set_type(qdCoordsAnimationType tp) {
|
||||
_type = tp;
|
||||
}
|
||||
|
||||
float animation_phase() const {
|
||||
return _animation_phase;
|
||||
}
|
||||
void set_animation_phase(float p) {
|
||||
_animation_phase = p;
|
||||
}
|
||||
|
||||
void start() const;
|
||||
void stop() const;
|
||||
void quant(float dt) const;
|
||||
|
||||
bool reset_cur_point() const;
|
||||
bool set_cur_point(int point_num) const;
|
||||
int get_cur_point() const {
|
||||
return _cur_point;
|
||||
}
|
||||
|
||||
void set_time_rel(float tm);
|
||||
|
||||
void add_point(const qdCoordsAnimationPoint *p);
|
||||
void insert_point(const qdCoordsAnimationPoint *p, int insert_pos);
|
||||
|
||||
void remove_point(int num);
|
||||
void clear();
|
||||
|
||||
qdCoordsAnimationPoint *get_point(int index = 0) {
|
||||
return &_points[index];
|
||||
};
|
||||
const qdCoordsAnimationPoint *get_point(int index = 0) const {
|
||||
return &_points[index];
|
||||
};
|
||||
|
||||
int size() const {
|
||||
return _points.size();
|
||||
}
|
||||
|
||||
void load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
bool is_empty() const {
|
||||
if (_points.empty()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
Common::String flag2str(int flags) const;
|
||||
|
||||
private:
|
||||
|
||||
qdCoordsAnimationType _type;
|
||||
qdCoordsAnimationPointVector _points;
|
||||
float _animation_phase;
|
||||
float _speed;
|
||||
|
||||
// Для относительного перемещения персонажа (QD_COORDS_ANM_RELATIVE_FLAG):
|
||||
// объект, относительно коориднат которого будет работать траектория движения (если не задано, то работаем
|
||||
// относительно координат объекта-владельца координатной анимации)
|
||||
const qdGameObject *_start_object;
|
||||
qdNamedObjectReference _start_object_ref;
|
||||
|
||||
mutable bool _status;
|
||||
mutable bool _is_finished;
|
||||
mutable qdCoordsAnimationPoint _start_point;
|
||||
mutable int _cur_point;
|
||||
|
||||
Vect3f cur_pos() const;
|
||||
class qdGameObjectAnimated *object() const;
|
||||
|
||||
void calc_paths() const;
|
||||
|
||||
// Дельта (вектор) смещения координат анимации
|
||||
mutable Vect3f _del;
|
||||
};
|
||||
|
||||
//typedef Std::list<qdCoordsAnimation*> qdCoordsAnimationList;
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_COORDS_ANIMATION_H
|
||||
93
engines/qdengine/qdcore/qd_coords_animation_point.cpp
Normal file
93
engines/qdengine/qdcore/qd_coords_animation_point.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/xmath.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_coords_animation_point.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
const float qdCoordsAnimationPoint::NO_DIRECTION = -1.f;
|
||||
qdCoordsAnimationPoint::qdCoordsAnimationPoint() : _pos(0, 0, 0),
|
||||
_direction_angle(NO_DIRECTION) {
|
||||
_path_length = _passed_path_length = 0.0f;
|
||||
}
|
||||
|
||||
qdCoordsAnimationPoint::~qdCoordsAnimationPoint() {
|
||||
}
|
||||
|
||||
void qdCoordsAnimationPoint::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_DEST_POS:
|
||||
xml::tag_buffer(*it) > _pos.x > _pos.y > _pos.z;
|
||||
break;
|
||||
case QDSCR_OBJECT_DIRECTION:
|
||||
xml::tag_buffer(*it) > _direction_angle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool qdCoordsAnimationPoint::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<coords_animation_point");
|
||||
fh.writeString(Common::String::format(" dest_pos=\"%f %f %f\"", _pos.x, _pos.y, _pos.z));
|
||||
|
||||
if (_direction_angle >= 0.0f) {
|
||||
fh.writeString(Common::String::format(" object_direction=\"%f\"", _direction_angle));
|
||||
}
|
||||
|
||||
fh.writeString("/>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdCoordsAnimationPoint::calc_path(const qdCoordsAnimationPoint &p, const Vect3f &shift) const {
|
||||
Vect3f dr = _pos - shift - p.dest_pos();
|
||||
_path_length = dr.norm();
|
||||
}
|
||||
|
||||
float qdCoordsAnimationPoint::passed_path() const {
|
||||
if (_path_length < 0.01f) return 1.0f;
|
||||
|
||||
return _passed_path_length / _path_length;
|
||||
}
|
||||
|
||||
bool qdCoordsAnimationPoint::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
_path_length = fh.readFloatLE();
|
||||
_passed_path_length = fh.readFloatLE();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCoordsAnimationPoint::save_data(Common::WriteStream &fh) const {
|
||||
fh.writeFloatLE(_path_length);
|
||||
fh.writeFloatLE(_passed_path_length);
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
91
engines/qdengine/qdcore/qd_coords_animation_point.h
Normal file
91
engines/qdengine/qdcore/qd_coords_animation_point.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_COORDS_ANIMATION_POINT_H
|
||||
#define QDENGINE_QDCORE_QD_COORDS_ANIMATION_POINT_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdCoordsAnimationPoint {
|
||||
public:
|
||||
qdCoordsAnimationPoint();
|
||||
~qdCoordsAnimationPoint();
|
||||
|
||||
static const float NO_DIRECTION;
|
||||
|
||||
const Vect3f &dest_pos() const {
|
||||
return _pos;
|
||||
}
|
||||
void set_dest_pos(const Vect3f &r) {
|
||||
_pos = r;
|
||||
}
|
||||
|
||||
float direction_angle() const {
|
||||
return _direction_angle;
|
||||
}
|
||||
void set_direction_angle(float ang) {
|
||||
_direction_angle = ang;
|
||||
}
|
||||
|
||||
void start() const {
|
||||
_passed_path_length = 0.0f;
|
||||
}
|
||||
|
||||
bool move(float &path) const {
|
||||
_passed_path_length += path;
|
||||
if (_passed_path_length >= _path_length) {
|
||||
path = _passed_path_length - _path_length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void calc_path(const qdCoordsAnimationPoint &p, const Vect3f &shift = Vect3f(0, 0, 0)) const;
|
||||
float passed_path() const;
|
||||
float path_length() const {
|
||||
return _path_length;
|
||||
}
|
||||
|
||||
void load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
private:
|
||||
|
||||
Vect3f _pos;
|
||||
float _direction_angle;
|
||||
|
||||
mutable float _path_length;
|
||||
mutable float _passed_path_length;
|
||||
};
|
||||
|
||||
typedef Std::vector<qdCoordsAnimationPoint> qdCoordsAnimationPointVector;
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_COORDS_ANIMATION_POINT_H
|
||||
308
engines/qdengine/qdcore/qd_counter.cpp
Normal file
308
engines/qdengine/qdcore/qd_counter.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
/* 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_counter.h"
|
||||
#include "qdengine/qdcore/qd_game_object_state.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdCounterElement::qdCounterElement() : _state(NULL),
|
||||
_last_state_status(false),
|
||||
_increment_value(true) {
|
||||
}
|
||||
|
||||
qdCounterElement::~qdCounterElement() {
|
||||
}
|
||||
|
||||
qdCounterElement::qdCounterElement(const qdGameObjectState *p, bool inc_value) : _state(p),
|
||||
_state_reference(p),
|
||||
_last_state_status(false),
|
||||
_increment_value(inc_value) {
|
||||
}
|
||||
|
||||
bool qdCounterElement::init() {
|
||||
// if(!_state){
|
||||
_state = dynamic_cast<const qdGameObjectState *>(_state_reference.object());
|
||||
if (!_state) {
|
||||
debugC(3, kDebugLog, "qdCounterElement::init() failed");
|
||||
return false;
|
||||
}
|
||||
// }
|
||||
|
||||
_last_state_status = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCounterElement::quant() {
|
||||
if (_state) {
|
||||
bool result = false;
|
||||
|
||||
bool status = _state->is_active();
|
||||
if (status && !_last_state_status)
|
||||
result = true;
|
||||
|
||||
_last_state_status = status;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdCounterElement::load_script(const xml::tag *p) {
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
xml::tag_buffer buf(*it);
|
||||
switch (it->ID()) {
|
||||
case QDSCR_NAMED_OBJECT:
|
||||
_state_reference.load_script(&*it);
|
||||
break;
|
||||
case QDSCR_COUNTER_INC_VALUE:
|
||||
_increment_value = (xml::tag_buffer(*it).get_int()) ? true : false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCounterElement::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<counter_element");
|
||||
|
||||
if (!_increment_value) {
|
||||
fh.writeString(" inc_value=\"0\"");
|
||||
}
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
if (_state) {
|
||||
qdNamedObjectReference ref(_state);
|
||||
ref.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</counter_element>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCounterElement::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
char v;
|
||||
v = fh.readByte();
|
||||
_last_state_status = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCounterElement::save_data(Common::WriteStream &fh) const {
|
||||
fh.writeByte(_last_state_status);
|
||||
return true;
|
||||
}
|
||||
|
||||
qdCounter::qdCounter() : _value(0),
|
||||
_value_limit(0) {
|
||||
}
|
||||
|
||||
qdCounter::~qdCounter() {
|
||||
}
|
||||
|
||||
void qdCounter::set_value(int value) {
|
||||
_value = value;
|
||||
|
||||
if (_value_limit > 0 && _value >= _value_limit)
|
||||
_value = 0;
|
||||
|
||||
if (check_flag(POSITIVE_VALUE) && _value < 0)
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
void qdCounter::add_value(int value_delta) {
|
||||
_value += value_delta;
|
||||
|
||||
if (_value_limit > 0 && _value >= _value_limit)
|
||||
_value = 0;
|
||||
|
||||
if (check_flag(POSITIVE_VALUE) && _value < 0)
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
bool qdCounter::add_element(const qdGameObjectState *p, bool inc_value) {
|
||||
element_container_t::const_iterator it = Common::find(_elements.begin(), _elements.end(), p);
|
||||
if (it != _elements.end())
|
||||
return false;
|
||||
|
||||
_elements.push_back(qdCounterElement(p, inc_value));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCounter::remove_element(const qdGameObjectState *p) {
|
||||
element_container_t::iterator it = Common::find(_elements.begin(), _elements.end(), p);
|
||||
if (it != _elements.end()) {
|
||||
_elements.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdCounter::remove_element(int idx) {
|
||||
assert(idx >= 0 && idx < (int)_elements.size());
|
||||
|
||||
_elements.erase(_elements.begin() + idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdCounter::quant() {
|
||||
int value_change = 0;
|
||||
for (element_container_t::iterator it = _elements.begin(); it != _elements.end(); ++it) {
|
||||
if (it->quant()) {
|
||||
if (it->increment_value())
|
||||
value_change++;
|
||||
else
|
||||
value_change--;
|
||||
}
|
||||
}
|
||||
|
||||
_value += value_change;
|
||||
|
||||
if (_value_limit > 0 && _value >= _value_limit)
|
||||
_value = 0;
|
||||
|
||||
if (check_flag(POSITIVE_VALUE) && _value < 0)
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
bool qdCounter::load_script(const xml::tag *p) {
|
||||
int num_elements = 0;
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
xml::tag_buffer buf(*it);
|
||||
switch (it->ID()) {
|
||||
case QDSCR_COUNTER_ELEMENT:
|
||||
num_elements++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_elements.reserve(num_elements);
|
||||
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
xml::tag_buffer buf(*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_COUNTER_ELEMENT: {
|
||||
qdCounterElement el;
|
||||
el.load_script(&*it);
|
||||
_elements.push_back(el);
|
||||
}
|
||||
break;
|
||||
case QDSCR_COUNTER_LIMIT:
|
||||
xml::tag_buffer(*it) > _value_limit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCounter::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<counter");
|
||||
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
|
||||
if (_value_limit) {
|
||||
fh.writeString(Common::String::format(" limit=\"%d\"", _value_limit));
|
||||
}
|
||||
|
||||
if (flags()) {
|
||||
fh.writeString(Common::String::format(" flags=\"%d\"", flags()));
|
||||
}
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
for (auto &it : _elements) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</counter>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCounter::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
debugC(3, kDebugSave, " qdCounter::load_data(): before: %d", (int)fh.pos());
|
||||
int sz;
|
||||
_value = fh.readSint32LE();
|
||||
sz = fh.readSint32LE();
|
||||
|
||||
if (sz != (int)_elements.size())
|
||||
return false;
|
||||
|
||||
for (auto &it : _elements)
|
||||
it.load_data(fh, save_version);
|
||||
|
||||
debugC(3, kDebugSave, " qdCounter::load_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdCounter::save_data(Common::WriteStream &fh) const {
|
||||
debugC(3, kDebugSave, " qdCounter::save_data(): before: %d", (int)fh.pos());
|
||||
fh.writeSint32LE(_value);
|
||||
fh.writeSint32LE(_elements.size());
|
||||
|
||||
for (auto &it : _elements) {
|
||||
it.save_data(fh);
|
||||
}
|
||||
|
||||
debugC(3, kDebugSave, " qdCounter::save_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdCounter::init() {
|
||||
for (element_container_t::iterator it = _elements.begin(); it != _elements.end(); ++it)
|
||||
it->init();
|
||||
|
||||
_value = 0;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
141
engines/qdengine/qdcore/qd_counter.h
Normal file
141
engines/qdengine/qdcore/qd_counter.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_COUNTER_H
|
||||
#define QDENGINE_QDCORE_QD_COUNTER_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_named_object_reference.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdGameObjectState;
|
||||
|
||||
class qdCounterElement {
|
||||
public:
|
||||
qdCounterElement();
|
||||
~qdCounterElement();
|
||||
explicit qdCounterElement(const qdGameObjectState *p, bool inc_value = true);
|
||||
|
||||
bool operator == (const qdGameObjectState *p) const {
|
||||
return _state == p;
|
||||
}
|
||||
|
||||
const qdGameObjectState *state() const {
|
||||
return _state;
|
||||
}
|
||||
bool increment_value() const {
|
||||
return _increment_value;
|
||||
}
|
||||
|
||||
bool init();
|
||||
bool quant();
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
private:
|
||||
|
||||
qdNamedObjectReference _state_reference;
|
||||
const qdGameObjectState *_state;
|
||||
bool _last_state_status;
|
||||
bool _increment_value;
|
||||
};
|
||||
|
||||
//! Счетчик состояний.
|
||||
class qdCounter : public qdNamedObject {
|
||||
public:
|
||||
qdCounter();
|
||||
~qdCounter();
|
||||
|
||||
//! Флаги счетчика.
|
||||
enum {
|
||||
//! принимает только положительные значения
|
||||
POSITIVE_VALUE = 0x01
|
||||
};
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_COUNTER;
|
||||
}
|
||||
|
||||
int value() const {
|
||||
return _value;
|
||||
}
|
||||
void set_value(int value);
|
||||
void add_value(int value_delta);
|
||||
|
||||
int value_limit() const {
|
||||
return _value_limit;
|
||||
}
|
||||
void set_value_limit(int limit) {
|
||||
_value_limit = limit;
|
||||
}
|
||||
|
||||
typedef Std::vector<qdCounterElement> element_container_t;
|
||||
const element_container_t &elements() const {
|
||||
return _elements;
|
||||
}
|
||||
|
||||
//! Добавление состояния. Возвращает false, если оно уже добавлено ранее.
|
||||
bool add_element(const qdGameObjectState *p, bool inc_value = true);
|
||||
|
||||
bool remove_element(const qdGameObjectState *p);
|
||||
bool remove_element(int idx);
|
||||
|
||||
void quant();
|
||||
|
||||
void init();
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
protected:
|
||||
private:
|
||||
|
||||
//! Состояния, которые при включении изменяют значение счетчика.
|
||||
element_container_t _elements;
|
||||
|
||||
//! Текущее значение счетчика.
|
||||
int _value;
|
||||
//! Предельное значение, по достижении которого счетчик скидывается в ноль.
|
||||
/**
|
||||
Если меньше или равно нулю - не учитывается.
|
||||
*/
|
||||
int _value_limit;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_COUNTER_H
|
||||
575
engines/qdengine/qdcore/qd_d3dutils.cpp
Normal file
575
engines/qdengine/qdcore/qd_d3dutils.cpp
Normal file
@@ -0,0 +1,575 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Note: Must Define D3D_OVERLOADS to get C++ version of MATRIX3D
|
||||
#include "qdengine/qdcore/qd_d3dutils.h"
|
||||
|
||||
//набор своих функций, потому что те, что представлены в xMath.h
|
||||
//не удовлетворяют потребностям
|
||||
//я порой такой требовательный, что самому страшно.
|
||||
namespace QDEngine {
|
||||
|
||||
namespace vector_helpers {
|
||||
inline VALUE3D
|
||||
SquareMagnitude(const Vect3f &v) {
|
||||
return v.x * v.x + v.y * v.y + v.z * v.z;
|
||||
}
|
||||
|
||||
inline VALUE3D
|
||||
Magnitude(const Vect3f &v) {
|
||||
return (VALUE3D) sqrt(SquareMagnitude(v));
|
||||
}
|
||||
|
||||
|
||||
inline Vect3f
|
||||
Normalize(const Vect3f &v) {
|
||||
return v / Magnitude(v);
|
||||
}
|
||||
|
||||
inline VALUE3D DotProduct(const Vect3f &v1, const Vect3f &v2) {
|
||||
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
|
||||
}
|
||||
|
||||
inline Vect3f
|
||||
CrossProduct(const Vect3f &v1, const Vect3f &v2) {
|
||||
Vect3f result;
|
||||
|
||||
result[0] = v1[1] * v2[2] - v1[2] * v2[1];
|
||||
result[1] = v1[2] * v2[0] - v1[0] * v2[2];
|
||||
result[2] = v1[0] * v2[1] - v1[1] * v2[0];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//угол между векторами лежащими в плоскости ХОУ
|
||||
//иначе ее применять НЕЛЬЗЯ
|
||||
float VectorAngle(const Vect3f &v1, const Vect3f &v2) {
|
||||
return float(atan2(v2.y, v2.x) - atan2(v1.y, v1.x));
|
||||
}
|
||||
|
||||
}//vector_helpers
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: ZeroMatrix
|
||||
** Purpose: sets D3D matrix to all 0's
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
ZeroMatrix() {
|
||||
MATRIX3D ret;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ret(i, j) = 0.0f;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} // end ZeroMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: IdentityMatrix
|
||||
** Purpose: sets D3D matrix to Identiy (1's on diagonal, zero's elsewhere)
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
IdentityMatrix() {
|
||||
MATRIX3D ret;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ret(i, j) = 0.0f;
|
||||
}
|
||||
ret(i, i) = 1.0f;
|
||||
}
|
||||
return ret;
|
||||
} // end IdentityMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: ProjectionMatrix
|
||||
** Purpose: sets Projection matrix from fov, near and far planes
|
||||
** Notes:
|
||||
** 1. fov is in radians.
|
||||
** 2. See Blinn, "A Trip Down the Graphics Pipeline" pg 188 for details.
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
ProjectionMatrix(const float near_plane,
|
||||
const float far_plane,
|
||||
const float fov) {
|
||||
float c = (float) cos(fov * 0.5);
|
||||
float s = (float) sin(fov * 0.5);
|
||||
float Q = s / (1.0f - near_plane / far_plane);
|
||||
|
||||
MATRIX3D ret = ZeroMatrix();
|
||||
ret(0, 0) = c;
|
||||
ret(1, 1) = c;
|
||||
ret(2, 2) = Q;
|
||||
ret(3, 2) = -Q * near_plane;
|
||||
ret(2, 3) = s;
|
||||
return ret;
|
||||
} // end ProjectionMatrix
|
||||
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: ViewMatrix
|
||||
** Purpose: Controls where the camara is.
|
||||
** Notes:
|
||||
** 1. Note the roll parameter is in radians and rools the viewpoint
|
||||
** around the viewing direction
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D ViewMatrixByDir(const Vect3f &from,
|
||||
const Vect3f &view_dir,
|
||||
const Vect3f &world_up,
|
||||
const Vect3f &cam_up) {
|
||||
MATRIX3D view = IdentityMatrix();
|
||||
//view_dir - Это ось Z в системе координат камеры
|
||||
Vect3f zAxis = view_dir;
|
||||
|
||||
//ось Х в правой системе координат
|
||||
Vect3f xAxis = vector_helpers::CrossProduct(zAxis, world_up);
|
||||
xAxis = vector_helpers::Normalize(xAxis);
|
||||
|
||||
Vect3f yAxis = vector_helpers::CrossProduct(zAxis, xAxis);
|
||||
|
||||
view(0, 0) = xAxis.x;
|
||||
view(1, 0) = xAxis.y;
|
||||
view(2, 0) = xAxis.z;
|
||||
|
||||
view(0, 1) = yAxis.x;
|
||||
view(1, 1) = yAxis.y;
|
||||
view(2, 1) = yAxis.z;
|
||||
|
||||
view(0, 2) = zAxis.x;
|
||||
view(1, 2) = zAxis.y;
|
||||
view(2, 2) = zAxis.z;
|
||||
|
||||
view(3, 0) = -vector_helpers::DotProduct(xAxis, from);
|
||||
view(3, 1) = -vector_helpers::DotProduct(cam_up, from);
|
||||
view(3, 2) = -vector_helpers::DotProduct(zAxis, from);
|
||||
/*
|
||||
* после всех вычислений верх камеры имеет с верхом мира угол небольше 90 градусов,
|
||||
* что по сути своей не всегда правильно. Для того, чтобы вычислить правильно поворот
|
||||
* вокруг оси Z используем up и cam_up. Где cam_up - это верх камеры, который должен
|
||||
* быть у неё после поворота.
|
||||
* Перед тем как вычислить угол переводим оба вектора в координаты камеры, тогда они
|
||||
* будут лежать в плоскости ХОУ. вычисляем угол и поворачиваем.
|
||||
*/
|
||||
|
||||
|
||||
//переводим в координаты камеры, чтобы получить
|
||||
//плоскую картинку и пользоваться atan2
|
||||
float r = vector_helpers::VectorAngle(TransformVector(cam_up, view),
|
||||
TransformVector(yAxis, view));
|
||||
|
||||
view = MatrixMult(RotateZMatrix(-r), view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
MATRIX3D
|
||||
ViewMatrix(const Vect3f &from,
|
||||
const Vect3f &at,
|
||||
const Vect3f &world_up,
|
||||
const Vect3f &cam_up) {
|
||||
|
||||
Vect3f view_dir = vector_helpers::Normalize(at - from);
|
||||
return ViewMatrixByDir(from, view_dir, world_up, cam_up);
|
||||
} // end ViewMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: RotateXMatrix
|
||||
** Purpose: Rotate matrix about X axis
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
RotateXMatrix(const float rads) {
|
||||
float cosine = (float) cos(rads);
|
||||
float sine = (float) sin(rads);
|
||||
MATRIX3D ret = IdentityMatrix();
|
||||
ret(1, 1) = cosine;
|
||||
ret(2, 2) = -cosine;
|
||||
ret(1, 2) = sine;
|
||||
ret(2, 1) = sine;
|
||||
return ret;
|
||||
} // end RotateXMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: RotateYMatrix
|
||||
** Purpose: Rotate matrix about Y axis
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
RotateYMatrix(const float rads) {
|
||||
float const cosine = (float) cos(rads);
|
||||
float const sine = (float) sin(rads);
|
||||
|
||||
MATRIX3D ret = IdentityMatrix();
|
||||
ret(0, 0) = cosine;
|
||||
ret(2, 2) = -cosine;
|
||||
|
||||
ret(0, 2) = sine;
|
||||
ret(2, 0) = sine;
|
||||
|
||||
return ret;
|
||||
} // end RotateY
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: RotateZMatrix
|
||||
** Purpose: Rotate matrix about Z axis
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
RotateZMatrix(const float rads) {
|
||||
float const cosine = (float) cos(rads);
|
||||
float const sine = (float) sin(rads);
|
||||
MATRIX3D ret = IdentityMatrix();
|
||||
ret(0, 0) = cosine;
|
||||
ret(1, 1) = -cosine;
|
||||
|
||||
ret(0, 1) = sine;
|
||||
ret(1, 0) = sine;
|
||||
return ret;
|
||||
} // end RotateZMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: TranslateMatrix
|
||||
** Purpose: Returns matrix to translate by (dx, dy, dz)
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
TranslateMatrix(const float dx, const float dy, const float dz) {
|
||||
MATRIX3D ret = IdentityMatrix();
|
||||
ret(3, 0) = dx;
|
||||
ret(3, 1) = dy;
|
||||
ret(3, 2) = dz;
|
||||
return ret;
|
||||
} // end TranslateMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: TranslateMatrix
|
||||
** Purpose: Returns matrix to translate by v
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
TranslateMatrix(const Vect3f &v) {
|
||||
MATRIX3D ret = IdentityMatrix();
|
||||
ret(3, 0) = v[0];
|
||||
ret(3, 1) = v[1];
|
||||
ret(3, 2) = v[2];
|
||||
return ret;
|
||||
} // end TranslateMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: ScaleMatrix
|
||||
** Purpose: scale matrix (uniform)
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
ScaleMatrix(const float size) {
|
||||
MATRIX3D ret = IdentityMatrix();
|
||||
ret(0, 0) = size;
|
||||
ret(1, 1) = size;
|
||||
ret(2, 2) = size;
|
||||
return ret;
|
||||
} // end ScaleMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: ScaleMatrix
|
||||
** Purpose: scale matrix
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
ScaleMatrix(const float a, const float b, const float c) {
|
||||
MATRIX3D ret = IdentityMatrix();
|
||||
ret(0, 0) = a;
|
||||
ret(1, 1) = b;
|
||||
ret(2, 2) = c;
|
||||
return ret;
|
||||
} // end ScaleMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: ScaleMatrix
|
||||
** Purpose: scale matrix
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
ScaleMatrix(const Vect3f &v) {
|
||||
MATRIX3D ret = IdentityMatrix();
|
||||
ret(0, 0) = v.x;
|
||||
ret(1, 1) = v.y;
|
||||
ret(2, 2) = v.z;
|
||||
return ret;
|
||||
} // end ScaleMatrix
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: MatrixMult
|
||||
** Purpose: [C] = [A] * [B]
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
MatrixMult(const MATRIX3D &a, const MATRIX3D &b) {
|
||||
MATRIX3D ret = ZeroMatrix();
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int k = 0; k < 4; k++) {
|
||||
ret(i, j) += a(k, j) * b(i, k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} // end MatrixMult
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: TransformVector
|
||||
** Purpose: V' = V * [M]
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Vect3f
|
||||
TransformVector(const Vect3f &v, const MATRIX3D &m) {
|
||||
float hvec[4] = {0.f};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
hvec[i] = 0.0f;
|
||||
// for (int j=0; j<3; j++) {
|
||||
// hvec[i] += v[j] * m(j, i);
|
||||
// }
|
||||
// hvec[i] += m(3, i);
|
||||
hvec[i] = v[0] * m(0, i)
|
||||
+ v[1] * m(1, i)
|
||||
+ v[2] * m(2, i)
|
||||
+ m(3, i);
|
||||
}
|
||||
return Vect3f(hvec[0] / hvec[3], hvec[1] / hvec[3], hvec[2] / hvec[3]);
|
||||
} // end TransformVector
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: TransformNormal
|
||||
** Purpose: N' = N * [M]
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Vect3f
|
||||
TransformNormal(const Vect3f &v, const MATRIX3D &mat) {
|
||||
MATRIX3D m;
|
||||
|
||||
m = MatrixInverse(mat);
|
||||
m = MatrixTranspose(m);
|
||||
return TransformVector(v, m);
|
||||
} // end TransformNormal
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: MatrixInverse
|
||||
** Purpose: Creates the inverse of a 4x4 matrix
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void lubksb(MATRIX3D &a, int *indx, float *b);
|
||||
static void ludcmp(MATRIX3D &a, int *indx, float *d);
|
||||
|
||||
MATRIX3D
|
||||
MatrixInverse(const MATRIX3D &m) {
|
||||
MATRIX3D n, y;
|
||||
int i, j, indx[4];
|
||||
float d, col[4];
|
||||
|
||||
n = m;
|
||||
ludcmp(n, indx, &d);
|
||||
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
col[i] = 0.0f;
|
||||
}
|
||||
col[j] = 1.0f;
|
||||
lubksb(n, indx, col);
|
||||
for (i = 0; i < 4; i++) {
|
||||
y(i, j) = col[i];
|
||||
}
|
||||
}
|
||||
return y;
|
||||
} // end MatrixInverse
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: lubksb
|
||||
** Purpose: backward subsitution
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
lubksb(MATRIX3D &a, int *indx, float *b) {
|
||||
int i, j, ii = -1, ip;
|
||||
float sum;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
ip = indx[i];
|
||||
sum = b[ip];
|
||||
b[ip] = b[i];
|
||||
if (ii >= 0) {
|
||||
for (j = ii; j <= i - 1; j++) {
|
||||
sum -= a(i, j) * b[j];
|
||||
}
|
||||
} else if (sum != 0.0) {
|
||||
ii = i;
|
||||
}
|
||||
b[i] = sum;
|
||||
}
|
||||
for (i = 3; i >= 0; i--) {
|
||||
sum = b[i];
|
||||
for (j = i + 1; j < 4; j++) {
|
||||
sum -= a(i, j) * b[j];
|
||||
}
|
||||
b[i] = sum / a(i, i);
|
||||
}
|
||||
} // end lubksb
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: ludcmp
|
||||
** Purpose: LU decomposition
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
ludcmp(MATRIX3D &a, int *indx, float *d) {
|
||||
float vv[4]; /* implicit scale for each row */
|
||||
float big, dum, sum, tmp;
|
||||
int i, imax = 0, j, k;
|
||||
|
||||
*d = 1.0f;
|
||||
for (i = 0; i < 4; i++) {
|
||||
big = 0.0f;
|
||||
for (j = 0; j < 4; j++) {
|
||||
if ((tmp = (float) fabs(a(i, j))) > big) {
|
||||
big = tmp;
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (big == 0.0f) {
|
||||
printf("ludcmp(): singular matrix found...\n");
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
vv[i] = 1.0f / big;
|
||||
}
|
||||
for (j = 0; j < 4; j++) {
|
||||
for (i = 0; i < j; i++) {
|
||||
sum = a(i, j);
|
||||
for (k = 0; k < i; k++) {
|
||||
sum -= a(i, k) * a(k, j);
|
||||
}
|
||||
a(i, j) = sum;
|
||||
}
|
||||
big = 0.0f;
|
||||
for (i = j; i < 4; i++) {
|
||||
sum = a(i, j);
|
||||
for (k = 0; k < j; k++) {
|
||||
sum -= a(i, k) * a(k, j);
|
||||
}
|
||||
a(i, j) = sum;
|
||||
if ((dum = vv[i] * (float)fabs(sum)) >= big) {
|
||||
big = dum;
|
||||
imax = i;
|
||||
}
|
||||
}
|
||||
if (j != imax) {
|
||||
for (k = 0; k < 4; k++) {
|
||||
dum = a(imax, k);
|
||||
a(imax, k) = a(j, k);
|
||||
a(j, k) = dum;
|
||||
}
|
||||
*d = -(*d);
|
||||
vv[imax] = vv[j];
|
||||
}
|
||||
indx[j] = imax;
|
||||
if (a(j, j) == 0.0f) {
|
||||
a(j, j) = 1.0e-20f; /* can be 0.0 also... */
|
||||
}
|
||||
if (j != 3) {
|
||||
dum = 1.0f / a(j, j);
|
||||
for (i = j + 1; i < 4; i++) {
|
||||
a(i, j) *= dum;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end ludcmp
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Name: Matrix Transpose
|
||||
** Purpose: [M] = [M]'
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MATRIX3D
|
||||
MatrixTranspose(const MATRIX3D &m) {
|
||||
MATRIX3D ret;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = 0; j < 4; j++) {
|
||||
ret(i, j) = m(j, i);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} // end MatrixTranspose
|
||||
|
||||
/*
|
||||
Class Methods
|
||||
*/
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** end of File
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
} // namespace QDEngine
|
||||
108
engines/qdengine/qdcore/qd_d3dutils.h
Normal file
108
engines/qdengine/qdcore/qd_d3dutils.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_ENGINE_D3DUTILS_H
|
||||
#define QDENGINE_QDCORE_QD_ENGINE_D3DUTILS_H
|
||||
|
||||
#include "qdengine/xmath.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
typedef float VALUE3D;
|
||||
typedef struct _MATRIX3D {
|
||||
VALUE3D m[4][4];
|
||||
|
||||
_MATRIX3D() { }
|
||||
_MATRIX3D(VALUE3D _m00, VALUE3D _m01, VALUE3D _m02, VALUE3D _m03,
|
||||
VALUE3D _m10, VALUE3D _m11, VALUE3D _m12, VALUE3D _m13,
|
||||
VALUE3D _m20, VALUE3D _m21, VALUE3D _m22, VALUE3D _m23,
|
||||
VALUE3D _m30, VALUE3D _m31, VALUE3D _m32, VALUE3D _m33
|
||||
) {
|
||||
m[0][0] = _m00;
|
||||
m[0][1] = _m01;
|
||||
m[0][2] = _m02;
|
||||
m[0][3] = _m03;
|
||||
m[1][0] = _m10;
|
||||
m[1][1] = _m11;
|
||||
m[1][2] = _m12;
|
||||
m[1][3] = _m13;
|
||||
m[2][0] = _m20;
|
||||
m[2][1] = _m21;
|
||||
m[2][2] = _m22;
|
||||
m[2][3] = _m23;
|
||||
m[3][0] = _m30;
|
||||
m[3][1] = _m31;
|
||||
m[3][2] = _m32;
|
||||
m[3][3] = _m33;
|
||||
}
|
||||
|
||||
VALUE3D &operator()(int iRow, int iColumn) {
|
||||
return m[iRow][iColumn];
|
||||
}
|
||||
const VALUE3D &operator()(int iRow, int iColumn) const {
|
||||
return m[iRow][iColumn];
|
||||
}
|
||||
} MATRIX3D, *LPDMATRIX3D;
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** Function Prototypes
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
// generic simple matrix routines
|
||||
MATRIX3D ZeroMatrix();
|
||||
MATRIX3D IdentityMatrix();
|
||||
|
||||
MATRIX3D ProjectionMatrix(const float near_plane, const float far_plane, const float fov);
|
||||
MATRIX3D ViewMatrixByDir(const Vect3f &from,
|
||||
const Vect3f &view_dir,
|
||||
const Vect3f &world_up,
|
||||
const Vect3f &cam_up);
|
||||
MATRIX3D ViewMatrix(const Vect3f &from, const Vect3f &at,
|
||||
const Vect3f &world_up,
|
||||
const Vect3f &cam_up);
|
||||
|
||||
MATRIX3D RotateXMatrix(const float rads);
|
||||
MATRIX3D RotateYMatrix(const float rads);
|
||||
MATRIX3D RotateZMatrix(const float rads);
|
||||
MATRIX3D TranslateMatrix(const float dx, const float dy, const float dz);
|
||||
MATRIX3D TranslateMatrix(const Vect3f &v);
|
||||
MATRIX3D ScaleMatrix(const float size);
|
||||
MATRIX3D ScaleMatrix(const float a, const float b, const float c);
|
||||
MATRIX3D ScaleMatrix(const Vect3f &v);
|
||||
|
||||
MATRIX3D MatrixMult(const MATRIX3D &a, const MATRIX3D &b);
|
||||
MATRIX3D MatrixInverse(const MATRIX3D &m);
|
||||
MATRIX3D MatrixTranspose(const MATRIX3D &m);
|
||||
|
||||
Vect3f TransformVector(const Vect3f &v, const MATRIX3D &m);
|
||||
Vect3f TransformNormal(const Vect3f &v, const MATRIX3D &m);
|
||||
|
||||
/*
|
||||
**-----------------------------------------------------------------------------
|
||||
** End of File
|
||||
**-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_ENGINE_D3DUTILS_H
|
||||
86
engines/qdengine/qdcore/qd_engine_interface.h
Normal file
86
engines/qdengine/qdcore/qd_engine_interface.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_ENGINE_INTERFACE_H
|
||||
#define QDENGINE_QDCORE_QD_ENGINE_INTERFACE_H
|
||||
|
||||
#include "qdengine/qdcore/qd_rnd.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdGameScene;
|
||||
|
||||
namespace qdmg {
|
||||
|
||||
/// Интерфейс к движку для миниигр, реализация.
|
||||
class qdEngineInterfaceImpl : public qdEngineInterface {
|
||||
public:
|
||||
static const qdEngineInterfaceImpl &instance();
|
||||
|
||||
qdMinigameSceneInterface *current_scene_interface() const;
|
||||
qdMinigameSceneInterface *scene_interface(qdGameScene *scene) const;
|
||||
void release_scene_interface(qdMinigameSceneInterface *p) const;
|
||||
|
||||
qdMinigameCounterInterface *counter_interface(const char *counter_name) const;
|
||||
void release_counter_interface(qdMinigameCounterInterface *p) const;
|
||||
|
||||
//! Возвращает размер экрана в пикселах.
|
||||
mgVect2i screen_size() const;
|
||||
|
||||
//! Возвращает true, если на клавиатуре нажата кнопка vkey.
|
||||
bool is_key_pressed(int vkey) const;
|
||||
|
||||
//! Возвращает true, если в данный момент произошло событие event_id.
|
||||
bool is_mouse_event_active(qdMinigameMouseEvent event_id) const;
|
||||
|
||||
//! Возвращает текущие координаты мышиного курсора.
|
||||
mgVect2i mouse_cursor_position() const;
|
||||
|
||||
/// Добавляет набранные очки в таблицу рекордов.
|
||||
/// Если очков оказалось достаточно, возвращает true.
|
||||
bool add_hall_of_fame_entry(int score) const;
|
||||
|
||||
bool set_interface_text(const char *screen_name, const char *control_name, const char *text) const;
|
||||
|
||||
/// Инициализация rnd
|
||||
void rnd_init(int seed) const {
|
||||
qd_rnd_init(seed);
|
||||
}
|
||||
/// Возвращает случайное значение в интервале [0, m-1].
|
||||
uint32 rnd(uint32 m) const {
|
||||
return qd_rnd(m);
|
||||
}
|
||||
/// Возвращает случайное значение в интервале [-x, x].
|
||||
float frnd(float x) const {
|
||||
return qd_frnd(x);
|
||||
}
|
||||
/// Возвращает случайное значение в интервале [0, x].
|
||||
float fabs_rnd(float x) const {
|
||||
return qd_fabs_rnd(x);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace qdmg
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_ENGINE_INTERFACE_H
|
||||
147
engines/qdengine/qdcore/qd_file_manager.cpp
Normal file
147
engines/qdengine/qdcore/qd_file_manager.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
/* 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/file.h"
|
||||
#include "common/compression/unzip.h"
|
||||
|
||||
#include "qdengine/qdengine.h"
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_file_manager.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdFilePackage::qdFilePackage() : _container_index(0) {
|
||||
}
|
||||
|
||||
qdFilePackage::~qdFilePackage() {
|
||||
close();
|
||||
}
|
||||
|
||||
bool qdFilePackage::open() {
|
||||
Common::File zipFile;
|
||||
if (zipFile.exists(file_name())) {
|
||||
_container = Common::makeZipArchive(file_name());
|
||||
|
||||
return is_open();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdFilePackage::close() {
|
||||
delete _container;
|
||||
_container = nullptr;
|
||||
}
|
||||
|
||||
bool qdFilePackage::check_container() {
|
||||
Common::File zipFile;
|
||||
return zipFile.exists(file_name());
|
||||
}
|
||||
|
||||
const char *qdFilePackage::file_name() const {
|
||||
static Common::String fname;
|
||||
|
||||
fname = Common::String::format("Resource/resource%d.pak", _container_index);
|
||||
|
||||
return fname.c_str();
|
||||
}
|
||||
|
||||
void qdFilePackage::init() {
|
||||
}
|
||||
|
||||
qdFileManager::qdFileManager() {
|
||||
for (int i = 0; i < ARRAYSIZE(_packages); i++) {
|
||||
_packages[i].init();
|
||||
_packages[i].set_container_index(i);
|
||||
|
||||
if (_packages[i].check_container())
|
||||
_packageCount = i + 1;
|
||||
}
|
||||
|
||||
debug(0, "qdFileManager(): Package count: %d", _packageCount);
|
||||
}
|
||||
|
||||
qdFileManager::~qdFileManager() {
|
||||
}
|
||||
|
||||
bool qdFileManager::init(int cd_count) {
|
||||
return true;
|
||||
}
|
||||
|
||||
qdFileManager *mgr = nullptr;
|
||||
|
||||
qdFileManager &qdFileManager::instance() {
|
||||
if (!mgr)
|
||||
mgr = new qdFileManager();
|
||||
|
||||
return *mgr;
|
||||
}
|
||||
|
||||
void qdFileManager::Finit() {
|
||||
delete mgr;
|
||||
}
|
||||
|
||||
bool qdFileManager::open_file(Common::SeekableReadStream **fh, const Common::Path &file_name, bool err_message) {
|
||||
debugC(4, kDebugLoad, "qdFileManager::open_file(%s)", transCyrillic(file_name.toString()));
|
||||
|
||||
if (SearchMan.hasFile((char *)transCyrillic(file_name.toString()))) {
|
||||
Common::File *f = new Common::File;
|
||||
|
||||
if (f->open((char *)transCyrillic(file_name.toString())))
|
||||
*fh = f;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _packageCount; i++) {
|
||||
if (!_packages[i].is_open())
|
||||
_packages[i].open();
|
||||
|
||||
if (!_packages[i].is_open())
|
||||
continue;
|
||||
|
||||
if (_packages[i]._container->hasFile(file_name)) {
|
||||
debugC(5, kDebugLoad, "qdFileManager::open_file(%s): found in %s", transCyrillic(file_name.toString()), _packages[i].file_name());
|
||||
|
||||
*fh = _packages[i]._container->createReadStreamForMember(file_name);
|
||||
|
||||
if (*fh)
|
||||
return true;
|
||||
|
||||
debugC(4, kDebugLoad, "qdFileManager::open_file(%s): Cannot read file", transCyrillic(file_name.toString()));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
warning("qdFileManager::open_file(%s) (%s): NOT FOUND", transCyrillic(file_name.toString()), file_name.toString().c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdFileManager::is_package_available(const qdFileOwner &file_owner) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
124
engines/qdengine/qdcore/qd_file_manager.h
Normal file
124
engines/qdengine/qdcore/qd_file_manager.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_FILE_MANAGER_H
|
||||
#define QDENGINE_QDCORE_QD_FILE_MANAGER_H
|
||||
|
||||
#include "qdengine/qdcore/qd_file_owner.h"
|
||||
|
||||
namespace Common {
|
||||
class Archive;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdFilePackage {
|
||||
public:
|
||||
qdFilePackage();
|
||||
~qdFilePackage();
|
||||
|
||||
const char *file_name() const;
|
||||
|
||||
void set_drive_ID(int drive_id) {
|
||||
}
|
||||
void set_container_index(int idx) {
|
||||
_container_index = idx;
|
||||
}
|
||||
|
||||
bool is_open() {
|
||||
return _container != nullptr;
|
||||
}
|
||||
|
||||
void init();
|
||||
bool open();
|
||||
void close();
|
||||
|
||||
bool check_container();
|
||||
|
||||
Common::Archive *_container = nullptr;
|
||||
|
||||
private:
|
||||
int _container_index;
|
||||
};
|
||||
|
||||
//! Менеджер файлов.
|
||||
class qdFileManager {
|
||||
public:
|
||||
~qdFileManager();
|
||||
|
||||
bool init(int cd_count);
|
||||
void Finit();
|
||||
|
||||
void enable_packages() {}
|
||||
|
||||
bool open_file(Common::SeekableReadStream **fh, const Common::Path &file_name, bool err_message = true);
|
||||
|
||||
int last_CD_id() const {
|
||||
return 1;
|
||||
}
|
||||
void set_last_CD_id(int cd_id) {
|
||||
}
|
||||
|
||||
int CD_count() const {
|
||||
return 1;
|
||||
}
|
||||
bool is_CD_available(int cd_id) const {
|
||||
return true;
|
||||
}
|
||||
bool is_package_available(int idx) {
|
||||
assert(idx >= 0 && idx < _packageCount);
|
||||
return _packages[idx].is_open();
|
||||
}
|
||||
bool is_package_available(const qdFileOwner &file_owner);
|
||||
int get_num_packages() { return _packageCount; }
|
||||
|
||||
Common::Archive *get_package(int idx) {
|
||||
if (!_packages[idx].is_open())
|
||||
_packages[idx].open();
|
||||
|
||||
return _packages[idx]._container;
|
||||
}
|
||||
|
||||
bool scan_drives(const qdFileOwner *file_owner = NULL) { return true; }
|
||||
bool scan_drives(int cd_id) { return true; }
|
||||
void update_packages() {}
|
||||
|
||||
void toggle_silent_update_mode(bool mode) {
|
||||
}
|
||||
|
||||
bool check_drives(const char *cdkey = NULL) { return true; }
|
||||
bool check_drive(int drive_letter) { return true; }
|
||||
|
||||
static qdFileManager &instance();
|
||||
|
||||
private:
|
||||
|
||||
qdFileManager();
|
||||
|
||||
qdFilePackage _packages[3];
|
||||
|
||||
int _packageCount = 0;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_FILE_MANAGER_H
|
||||
59
engines/qdengine/qdcore/qd_file_owner.h
Normal file
59
engines/qdengine/qdcore/qd_file_owner.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_FILE_OWNER
|
||||
#define QDENGINE_QDCORE_QD_FILE_OWNER
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdFileOwner {
|
||||
public:
|
||||
qdFileOwner() : _cd_info(0) { }
|
||||
virtual ~qdFileOwner() {}
|
||||
|
||||
void add_to_CD(int cd_number) {
|
||||
_cd_info |= 1 << cd_number;
|
||||
}
|
||||
void remove_from_CD(int cd_number) {
|
||||
_cd_info &= ~(1 << cd_number);
|
||||
}
|
||||
bool is_on_CD(int cd_number = 1) const {
|
||||
int inf = (_cd_info) ? _cd_info : 1;
|
||||
return (inf & (1 << cd_number));
|
||||
}
|
||||
void clear_cd_info() {
|
||||
_cd_info = 0;
|
||||
}
|
||||
uint32 CD_info() const {
|
||||
return _cd_info;
|
||||
}
|
||||
void set_CD_info(uint32 inf) {
|
||||
_cd_info = inf;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
uint32 _cd_info;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_FILE_OWNER
|
||||
137
engines/qdengine/qdcore/qd_font_info.cpp
Normal file
137
engines/qdengine/qdcore/qd_font_info.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/* 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/path.h"
|
||||
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_font_info.h"
|
||||
#include "qdengine/qdcore/qd_file_manager.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdFontInfo::qdFontInfo(const qdFontInfo &fi) : qdNamedObject(fi),
|
||||
_type(fi.type()), _font_file_name(fi.font_file_name()) {
|
||||
if (NULL != fi.font()) {
|
||||
_font = new grFont;
|
||||
*_font = *fi.font();
|
||||
} else
|
||||
_font = NULL;
|
||||
}
|
||||
|
||||
|
||||
qdFontInfo::~qdFontInfo() {
|
||||
delete _font;
|
||||
}
|
||||
|
||||
qdFontInfo &qdFontInfo::operator = (const qdFontInfo &fi) {
|
||||
if (this == &fi) return *this;
|
||||
|
||||
*static_cast<qdNamedObject *>(this) = fi;
|
||||
|
||||
_type = fi.type();
|
||||
_font_file_name = fi.font_file_name();
|
||||
|
||||
delete _font;
|
||||
|
||||
if (NULL != fi.font()) {
|
||||
_font = new grFont;
|
||||
*_font = *fi.font();
|
||||
} else
|
||||
_font = NULL;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool qdFontInfo::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_TYPE:
|
||||
set_type(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_FILE:
|
||||
set_font_file_name(Common::Path(it->data(), '\\'));
|
||||
break;
|
||||
case QDSCR_NAME:
|
||||
set_name(it->data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdFontInfo::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<fontinfo type=\"%d\"", _type));
|
||||
|
||||
if (!_font_file_name.empty()) {
|
||||
fh.writeString(Common::String::format(" file=\"%s\"", qdscr_XML_string(_font_file_name.toString('\\'))));
|
||||
}
|
||||
|
||||
if (name()) {
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
}
|
||||
|
||||
fh.writeString("/>\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdFontInfo::load_font() {
|
||||
grFont *buf_font = new grFont;
|
||||
|
||||
bool load_fl = false; // По умолчанию загрузка прошла успешно
|
||||
|
||||
Common::SeekableReadStream *fh;
|
||||
if (qdFileManager::instance().open_file(&fh, font_file_name(), false)) {
|
||||
// Грузим альфу шрифта из .tga
|
||||
if (buf_font->load_alpha(fh)) {
|
||||
// Меняем расширение с .tga на .idx
|
||||
Common::String fpath(font_file_name().toString());
|
||||
Common::String tgaExt = ".tga";
|
||||
Common::String idxExt = ".idx";
|
||||
|
||||
Common::replace(fpath, tgaExt, idxExt);
|
||||
|
||||
delete fh;
|
||||
fh = nullptr;
|
||||
|
||||
// Открываем .idx и грузим индекс
|
||||
if (qdFileManager::instance().open_file(&fh, Common::Path(fpath), false)) {
|
||||
if (buf_font->load_index(fh))
|
||||
load_fl = true;
|
||||
}
|
||||
}
|
||||
|
||||
delete fh;
|
||||
}
|
||||
|
||||
if (!load_fl) {
|
||||
delete buf_font;
|
||||
return false;
|
||||
}
|
||||
|
||||
_font = buf_font;
|
||||
return true;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
96
engines/qdengine/qdcore/qd_font_info.h
Normal file
96
engines/qdengine/qdcore/qd_font_info.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_FONT_INFO_H
|
||||
#define QDENGINE_QDCORE_QD_FONT_INFO_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/parser/xml_tag.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/system/graphics/gr_font.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
#include "qdengine/qdcore/qd_object_list_container.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Шрифт
|
||||
class qdFontInfo : public qdNamedObject {
|
||||
public:
|
||||
qdFontInfo() : _type(0), _font(NULL) {}
|
||||
explicit qdFontInfo(int tp) : _type(tp), _font(NULL) {}
|
||||
// Копирующий конструктор
|
||||
qdFontInfo(const qdFontInfo &fi);
|
||||
~qdFontInfo();
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_FONT_INFO;
|
||||
}
|
||||
|
||||
bool operator == (const qdFontInfo &fi) const {
|
||||
return (fi.type() == _type) && (fi._font_file_name == _font_file_name);
|
||||
}
|
||||
bool operator == (int t) const {
|
||||
return (t == _type);
|
||||
}
|
||||
qdFontInfo &operator = (const qdFontInfo &fi);
|
||||
|
||||
int type() const {
|
||||
return _type;
|
||||
}
|
||||
void set_type(int tp) {
|
||||
_type = tp;
|
||||
}
|
||||
|
||||
void set_font_file_name(const Common::Path &fname) {
|
||||
_font_file_name = fname;
|
||||
}
|
||||
const Common::Path font_file_name() const {
|
||||
return _font_file_name;
|
||||
}
|
||||
|
||||
const grFont *font() const {
|
||||
return _font;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Грузит шрифт из файлов: font_file_name_ (хранит путь к *.tga части)
|
||||
//! и файла аналогичного font_file_name_, но с расш-ем. *.idx (индексная часть)
|
||||
bool load_font();
|
||||
|
||||
private:
|
||||
|
||||
//! Тип шрифта.
|
||||
int _type;
|
||||
//! Файл шрифта (*.tga).
|
||||
Common::Path _font_file_name;
|
||||
//! Сам шрифт
|
||||
grFont *_font;
|
||||
};
|
||||
|
||||
typedef Std::list<qdFontInfo *> qdFontInfoList;
|
||||
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_FONT_INFO_H
|
||||
3257
engines/qdengine/qdcore/qd_game_dispatcher.cpp
Normal file
3257
engines/qdengine/qdcore/qd_game_dispatcher.cpp
Normal file
File diff suppressed because it is too large
Load Diff
681
engines/qdengine/qdcore/qd_game_dispatcher.h
Normal file
681
engines/qdengine/qdcore/qd_game_dispatcher.h
Normal file
@@ -0,0 +1,681 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_DISPATCHER_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_DISPATCHER_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/system/input/mouse_input.h"
|
||||
#include "qdengine/system/graphics/gr_screen_region.h"
|
||||
#include "qdengine/qdcore/qd_camera_mode.h"
|
||||
#include "qdengine/qdcore/qd_object_list_container.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher_base.h"
|
||||
#include "qdengine/qdcore/qd_resource_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_screen_text_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_interface_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_inventory.h"
|
||||
#include "qdengine/qdcore/qd_font_info.h"
|
||||
#include "qdengine/qdcore/qd_file_owner.h"
|
||||
#include "qdengine/qdcore/util/WinVideo.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class grFont;
|
||||
class qdGameDispatcher : public qdGameDispatcherBase, public qdResourceDispatcher<qdNamedObject>, public qdFileOwner {
|
||||
public:
|
||||
//! Идентификаторы наборов текстов.
|
||||
enum {
|
||||
//! Фразы диалогов, отображаемые в данный момент на экране
|
||||
TEXT_SET_DIALOGS = 0
|
||||
};
|
||||
|
||||
//! Флаги
|
||||
enum {
|
||||
EXIT_FLAG = 0x01,
|
||||
RESTART_FLAG = 0x02,
|
||||
OBJECT_CLICK_FLAG = 0x04,
|
||||
DIALOG_CLICK_FLAG = 0x08,
|
||||
FULLSCREEN_REDRAW_FLAG = 0x10,
|
||||
SKIP_REDRAW_FLAG = 0x20,
|
||||
MAIN_MENU_FLAG = 0x40,
|
||||
INTRO_MODE_FLAG = 0x80,
|
||||
CLICK_FAILED_FLAG = 0x100,
|
||||
OBJECT_CLICK_FAILED_FLAG = 0x200,
|
||||
CLICK_WAS_FAILED_FLAG = 0x400,
|
||||
OBJECT_CLICK_WAS_FAILED_FLAG = 0x800,
|
||||
LOAD_GAME_FLAG = 0x1000,
|
||||
SAVE_GAME_FLAG = 0x2000,
|
||||
FADE_IN_FLAG = 0x4000,
|
||||
FADE_OUT_FLAG = 0x8000,
|
||||
NEXT_FRAME_FLAG = 0x10000
|
||||
};
|
||||
|
||||
qdGameDispatcher();
|
||||
~qdGameDispatcher();
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_DISPATCHER;
|
||||
}
|
||||
|
||||
qdGameObjectMouse *mouse_object() {
|
||||
return _mouse_obj;
|
||||
}
|
||||
qdGameObjectMouse const *mouse_object() const {
|
||||
return _mouse_obj;
|
||||
}
|
||||
bool drop_mouse_object();
|
||||
|
||||
int CD_count() const;
|
||||
|
||||
int resource_compression() const {
|
||||
return _resource_compression;
|
||||
}
|
||||
void set_resource_compression(int compression) {
|
||||
_resource_compression = compression;
|
||||
}
|
||||
|
||||
void request_file_package(const qdFileOwner &file_owner) const;
|
||||
Common::Path find_file(const Common::Path &file_name, const qdFileOwner &file_owner) const;
|
||||
void startup_check() const;
|
||||
|
||||
qdLoadingProgressFnc set_scene_loading_progress_callback(qdLoadingProgressFnc p, void *dp = 0) {
|
||||
qdLoadingProgressFnc old_fnc = _scene_loading_progress_fnc;
|
||||
_scene_loading_progress_fnc = p;
|
||||
_scene_loading_progress_data = dp;
|
||||
|
||||
return old_fnc;
|
||||
}
|
||||
|
||||
qdLoadingProgressFnc get_scene_loading_progress_callback() {
|
||||
return _scene_loading_progress_fnc;
|
||||
}
|
||||
|
||||
void *get_scene_loading_progress_data() {
|
||||
return _scene_loading_progress_data;
|
||||
}
|
||||
|
||||
void set_time(int tm) {
|
||||
_timer = tm;
|
||||
}
|
||||
int get_time() const {
|
||||
return _timer;
|
||||
}
|
||||
|
||||
bool start_intro_videos();
|
||||
|
||||
void quant();
|
||||
void quant(float dt);
|
||||
void pre_redraw();
|
||||
void redraw();
|
||||
void post_redraw();
|
||||
|
||||
void update_time();
|
||||
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
bool keyboard_handler(Common::KeyCode vkey, bool event);
|
||||
|
||||
bool add_game_end(qdGameEnd *p);
|
||||
bool rename_game_end(qdGameEnd *p, const char *name);
|
||||
bool remove_game_end(qdGameEnd *p);
|
||||
qdGameEnd *get_game_end(const char *name);
|
||||
bool is_game_end_in_list(const char *name);
|
||||
bool is_game_end_in_list(qdGameEnd *p);
|
||||
|
||||
bool add_counter(qdCounter *p);
|
||||
bool rename_counter(qdCounter *p, const char *name);
|
||||
bool remove_counter(qdCounter *p);
|
||||
qdCounter *get_counter(const char *name);
|
||||
bool is_counter_in_list(const char *name);
|
||||
bool is_counter_in_list(qdCounter *p);
|
||||
|
||||
bool add_minigame(qdMiniGame *p);
|
||||
bool rename_minigame(qdMiniGame *p, const char *name);
|
||||
bool remove_minigame(const char *name);
|
||||
bool remove_minigame(qdMiniGame *p);
|
||||
qdMiniGame *get_minigame(const char *name);
|
||||
bool is_minigame_in_list(const char *name);
|
||||
bool is_minigame_in_list(qdMiniGame *p);
|
||||
|
||||
void set_mouse_click_state(const qdGameObjectState *p) {
|
||||
_mouse_click_state = p;
|
||||
}
|
||||
|
||||
bool add_inventory(qdInventory *p) {
|
||||
if (_inventories.add_object(p)) {
|
||||
p->set_owner(this);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
bool remove_inventory(const char *name) {
|
||||
return _inventories.remove_object(name);
|
||||
}
|
||||
bool remove_inventory(qdInventory *p) {
|
||||
return _inventories.remove_object(p);
|
||||
}
|
||||
qdInventory *get_inventory(const char *name) {
|
||||
return _inventories.get_object(name);
|
||||
}
|
||||
bool is_inventory_in_list(const char *name) {
|
||||
return _inventories.is_in_list(name);
|
||||
}
|
||||
bool is_inventory_in_list(qdInventory *p) {
|
||||
return _inventories.is_in_list(p);
|
||||
}
|
||||
bool rename_inventory(qdInventory *p, const char *name);
|
||||
|
||||
const qdInventoryCellType *add_inventory_cell_type(const qdInventoryCellType &tp) {
|
||||
//проверяем уникальность идентификатора, вставляемого типа
|
||||
assert(find_inventory_cell_type(tp.type()) == _inventory_cell_types.end());
|
||||
_inventory_cell_types.push_back(tp);
|
||||
|
||||
return &_inventory_cell_types.back();
|
||||
}
|
||||
bool remove_inventory_cell_type(int type) {
|
||||
typedef qdInventoryCellTypeVector::iterator i_t;
|
||||
i_t res = find_inventory_cell_type(type);
|
||||
if (res != _inventory_cell_types.end()) {
|
||||
_inventory_cell_types.erase(res);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const qdInventoryCellType *get_inventory_cell_type(int type) const {
|
||||
typedef qdInventoryCellTypeVector::const_iterator ci_t;
|
||||
ci_t res = find_inventory_cell_type(type);
|
||||
if (res != _inventory_cell_types.end())
|
||||
return &*res;
|
||||
return NULL;
|
||||
}
|
||||
int get_unique_inventory_cell_type() const {
|
||||
if (_inventory_cell_types.empty()) return 0;
|
||||
return _inventory_cell_types.back().type() + 1;
|
||||
}
|
||||
bool set_inventory_cell_type(const qdInventoryCellType &tp) {
|
||||
typedef qdInventoryCellTypeVector::iterator i_t;
|
||||
i_t res = find_inventory_cell_type(tp.type());
|
||||
if (res != _inventory_cell_types.end()) {
|
||||
*res = tp;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const qdInventoryCellTypeVector &inventory_cell_types() const {
|
||||
return _inventory_cell_types;
|
||||
}
|
||||
|
||||
qdInventoryCellTypeVector ¬_const_inventory_cell_types() {
|
||||
return _inventory_cell_types;
|
||||
}
|
||||
|
||||
//! Операции со шрифтами
|
||||
/**
|
||||
Для создания типов всех добавляемых шрифтов нужно
|
||||
использовать get_unique_font_info_type().
|
||||
Самостоятельное задание типов шрифтов крайне не рекомендуется -
|
||||
возможны проблемы с уникальностью типов шрифтов и извлечением шрифта по типу.
|
||||
*/
|
||||
bool add_font_info(qdFontInfo *fi);
|
||||
bool remove_font_info(qdFontInfo *fi);
|
||||
bool rename_font_info(qdFontInfo *fi, char const *name);
|
||||
|
||||
const qdFontInfo *get_font_info(int type) const;
|
||||
int get_unique_font_info_type() const;
|
||||
bool set_font_info(const qdFontInfo &fi);
|
||||
const qdFontInfoList &fonts_list() const {
|
||||
return _fonts.get_list();
|
||||
}
|
||||
|
||||
int default_font() const {
|
||||
return _default_font;
|
||||
}
|
||||
void set_default_font(int font) {
|
||||
_default_font = font;
|
||||
}
|
||||
|
||||
bool toggle_inventory(bool state);
|
||||
bool toggle_inventory() {
|
||||
if (!_cur_inventory) return toggle_inventory(true);
|
||||
else return toggle_inventory(false);
|
||||
}
|
||||
bool put_to_inventory(qdGameObjectAnimated *p);
|
||||
bool remove_from_inventory(qdGameObjectAnimated *p);
|
||||
bool is_in_inventory(const qdGameObjectAnimated *p) const;
|
||||
bool is_on_mouse(const qdGameObjectAnimated *p) const;
|
||||
|
||||
const qdInventory *cur_inventory() const {
|
||||
return _cur_inventory;
|
||||
}
|
||||
|
||||
bool add_video(qdVideo *p, qdVideo const *before = NULL);
|
||||
bool remove_video(const char *name);
|
||||
bool remove_video(qdVideo *p);
|
||||
qdVideo *get_video(const char *name);
|
||||
bool is_video_in_list(const char *name);
|
||||
bool is_video_in_list(qdVideo *p);
|
||||
bool rename_video(qdVideo *p, const char *name);
|
||||
|
||||
bool add_trigger_chain(qdTriggerChain *p);
|
||||
bool remove_trigger_chain(const char *name);
|
||||
bool remove_trigger_chain(qdTriggerChain *p);
|
||||
qdTriggerChain *get_trigger_chain(const char *name);
|
||||
bool is_trigger_chain_in_list(const char *name);
|
||||
bool is_trigger_chain_in_list(qdTriggerChain *p);
|
||||
bool rename_trigger_chain(qdTriggerChain *p, const char *name);
|
||||
|
||||
bool add_scene(qdGameScene *p);
|
||||
bool rename_scene(qdGameScene *p, const char *name);
|
||||
bool remove_scene(qdGameScene *p);
|
||||
qdGameScene *get_scene(const char *name);
|
||||
bool is_scene_in_list(const char *name);
|
||||
bool is_scene_in_list(const qdGameScene *p);
|
||||
|
||||
bool add_global_object(qdGameObject *p);
|
||||
bool rename_global_object(qdGameObject *p, const char *name);
|
||||
bool remove_global_object(const char *name);
|
||||
bool remove_global_object(qdGameObject *p);
|
||||
qdGameObject *get_global_object(const char *name);
|
||||
bool is_global_object_in_list(const char *name);
|
||||
bool is_global_object_in_list(qdGameObject *p);
|
||||
|
||||
bool merge_global_objects(qdGameObject *obj = NULL);
|
||||
bool split_global_objects(qdGameObject *obj = NULL);
|
||||
bool update_walk_state(const char *object_name, qdGameObjectState *p);
|
||||
qdGameObjectState *get_walk_state(const char *object_name);
|
||||
|
||||
// Управление видеовставками
|
||||
bool play_video(const char *vid_name);
|
||||
bool play_video(qdVideo *p);
|
||||
bool pause_video();
|
||||
bool stop_video();
|
||||
bool close_video();
|
||||
bool is_video_finished();
|
||||
bool is_video_playing() {
|
||||
if (!_cur_video) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void continueVideo();
|
||||
bool is_video_playing(qdVideo *p) {
|
||||
return (_cur_video == p);
|
||||
}
|
||||
|
||||
bool play_music_track(const qdMusicTrack *p, bool interface_mode = false);
|
||||
const qdMusicTrack *current_music() const {
|
||||
return _cur_music_track;
|
||||
}
|
||||
bool stop_music();
|
||||
|
||||
bool select_scene(const char *s_name);
|
||||
bool select_scene(qdGameScene *sp, bool resources_flag = true);
|
||||
|
||||
//! Делает активными все линки, идущие от объекта в триггерах.
|
||||
bool activate_trigger_links(const qdNamedObject *p);
|
||||
//! Делает неактивными все триггера сцены.
|
||||
bool deactivate_scene_triggers(const qdGameScene *p);
|
||||
|
||||
void set_next_scene(qdGameScene *p) {
|
||||
_next_scene = p;
|
||||
}
|
||||
|
||||
int load_resources();
|
||||
void free_resources();
|
||||
int get_resources_size();
|
||||
|
||||
void load_script(const char *fname);
|
||||
void load_script(const xml::tag *p);
|
||||
bool save_script(Common::SeekableWriteStream &fh) const;
|
||||
bool save_script(const char *fname) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_save(Common::SeekableReadStream *fh);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_save(Common::WriteStream *stream) const;
|
||||
|
||||
bool save_game(int slot_id) const;
|
||||
|
||||
//! Инициализация данных, вызывается один раз сразу после загрузки скрипта.
|
||||
bool init();
|
||||
|
||||
bool init_triggers();
|
||||
bool reset_triggers();
|
||||
|
||||
const qdVideoList &video_list() const {
|
||||
return _videos.get_list();
|
||||
}
|
||||
const qdTriggerChainList &trigger_chain_list() const {
|
||||
return _trigger_chains.get_list();
|
||||
}
|
||||
const qdGameObjectList &global_object_list() const {
|
||||
return _global_objects.get_list();
|
||||
}
|
||||
const qdInventoryList &inventory_list() const {
|
||||
return _inventories.get_list();
|
||||
}
|
||||
const qdMiniGameList &minigame_list() const {
|
||||
return _minigames.get_list();
|
||||
}
|
||||
const qdGameEndList &game_end_list() const {
|
||||
return _game_ends.get_list();
|
||||
}
|
||||
const qdGameSceneList &scene_list() const {
|
||||
return _scenes.get_list();
|
||||
}
|
||||
const qdCounterList &counter_list() const {
|
||||
return _counters.get_list();
|
||||
}
|
||||
|
||||
qdGameScene *get_active_scene() const {
|
||||
return _cur_scene;
|
||||
}
|
||||
|
||||
qdSound *get_sound(const char *name);
|
||||
qdAnimation *get_animation(const char *name);
|
||||
qdAnimationSet *get_animation_set(const char *name);
|
||||
qdGameObject *get_object(const char *name);
|
||||
qdGameObjectMoving *get_active_personage();
|
||||
qdNamedObject *get_named_object(const qdNamedObjectReference *ref);
|
||||
|
||||
qdScaleInfo *get_scale_info(const char *p);
|
||||
|
||||
bool check_condition(qdCondition *cnd);
|
||||
|
||||
void pause();
|
||||
void resume();
|
||||
bool is_paused() {
|
||||
return _is_paused;
|
||||
}
|
||||
|
||||
bool is_gameplay_paused() {
|
||||
return _is_gameplay_paused;
|
||||
}
|
||||
|
||||
void pause_gameplay(bool pause) { _is_gameplay_paused = pause; }
|
||||
|
||||
bool restart();
|
||||
|
||||
qdScreenTextDispatcher &screen_texts_dispatcher() {
|
||||
return _screen_texts;
|
||||
}
|
||||
|
||||
bool toggle_main_menu() {
|
||||
return toggle_main_menu(!_interface_dispatcher.is_active());
|
||||
}
|
||||
bool toggle_main_menu(bool state, const char *screen_name = NULL);
|
||||
bool has_main_menu() const {
|
||||
return _interface_dispatcher.has_main_menu();
|
||||
}
|
||||
bool is_main_menu_exit_enabled() const;
|
||||
|
||||
void set_game_end(const qdGameEnd *p) {
|
||||
_game_end = p;
|
||||
}
|
||||
bool end_game(const qdGameEnd *p);
|
||||
|
||||
bool add_redraw_region(const grScreenRegion ®);
|
||||
|
||||
//! Ставит флаг, что надо выйти из игры.
|
||||
void toggle_exit() {
|
||||
set_flag(EXIT_FLAG);
|
||||
}
|
||||
//! Возвращает true, если надо выйти из игры.
|
||||
bool need_exit() const {
|
||||
return check_flag(EXIT_FLAG);
|
||||
}
|
||||
|
||||
//! Ставит флаг, что надо перезапустить игру.
|
||||
void toggle_restart() {
|
||||
set_flag(RESTART_FLAG);
|
||||
}
|
||||
//! Возвращает true, если надо перезапустить игру.
|
||||
bool need_restart() const {
|
||||
return check_flag(RESTART_FLAG);
|
||||
}
|
||||
|
||||
void toggle_full_redraw() {
|
||||
set_flag(FULLSCREEN_REDRAW_FLAG);
|
||||
}
|
||||
bool need_full_redraw() const {
|
||||
return check_flag(FULLSCREEN_REDRAW_FLAG);
|
||||
}
|
||||
|
||||
static void set_dispatcher(qdGameDispatcher *p);
|
||||
static qdGameDispatcher *get_dispatcher() {
|
||||
return _dispatcher;
|
||||
}
|
||||
|
||||
//! Возвращает имя стартовой сцены игры.
|
||||
const char *startup_scene() const {
|
||||
return _startup_scene.c_str();
|
||||
}
|
||||
//! Устанавливает имя стартовой сцены игры.
|
||||
/**
|
||||
Передавать NULL, чтобы скинуть установку.
|
||||
*/
|
||||
void set_startup_scene(const char *name) {
|
||||
if (name)
|
||||
_startup_scene = name;
|
||||
else
|
||||
_startup_scene.clear();
|
||||
}
|
||||
//! Возвращает true, если задана стартовая сцена игры.
|
||||
bool has_startup_scene() const {
|
||||
return !_startup_scene.empty();
|
||||
}
|
||||
|
||||
bool game_screenshot(Graphics::Surface &thumb) const;
|
||||
|
||||
void set_game_title(const char *p) {
|
||||
_game_title = p;
|
||||
}
|
||||
const char *game_title() const {
|
||||
return _game_title.c_str();
|
||||
}
|
||||
|
||||
void set_texts_database(const Common::Path &file_name) {
|
||||
_texts_database = file_name;
|
||||
}
|
||||
const Common::Path texts_database() const {
|
||||
return _texts_database;
|
||||
}
|
||||
|
||||
void set_cd_key(const char *key) {
|
||||
_cd_key = key;
|
||||
}
|
||||
const char *cd_key() const {
|
||||
return _cd_key.c_str();
|
||||
}
|
||||
|
||||
bool add_dialog_state(qdGameObjectState *p);
|
||||
|
||||
const Vect2f &mouse_cursor_pos() const {
|
||||
return _mouse_cursor_pos;
|
||||
}
|
||||
|
||||
bool is_autosave_slot(int save_slot) {
|
||||
return save_slot == _autosave_slot;
|
||||
}
|
||||
|
||||
void set_auto_save(int save_slot) {
|
||||
set_flag(SAVE_GAME_FLAG);
|
||||
_autosave_slot = save_slot;
|
||||
}
|
||||
void set_auto_load(int save_slot) {
|
||||
set_flag(LOAD_GAME_FLAG);
|
||||
_autosave_slot = save_slot;
|
||||
}
|
||||
|
||||
static grFont *create_font(int font_idx);
|
||||
static void free_font(grFont *fnt);
|
||||
|
||||
//! Поиск шрифтов
|
||||
qdFontInfo *find_font_info(int type);
|
||||
const qdFontInfo *find_font_info(int type) const;
|
||||
const grFont *find_font(int type) const;
|
||||
|
||||
bool set_fade(bool fade_in, float duration);
|
||||
|
||||
bool write_resource_stats(const char *file_name) const;
|
||||
|
||||
int hall_of_fame_size() const {
|
||||
return _hall_of_fame_size;
|
||||
}
|
||||
void set_hall_of_fame_size(int size) {
|
||||
_hall_of_fame_size = size;
|
||||
}
|
||||
|
||||
const char *hall_of_fame_player_name(int place) const;
|
||||
void set_hall_of_fame_player_name(int place, const char *name);
|
||||
|
||||
int hall_of_fame_player_score(int place) const;
|
||||
|
||||
bool is_hall_of_fame_updated(int place) const;
|
||||
|
||||
bool has_hall_of_fame() const {
|
||||
return _hall_of_fame_size != 0;
|
||||
}
|
||||
bool load_hall_of_fame();
|
||||
bool save_hall_of_fame() const;
|
||||
bool add_hall_of_fame_entry(int score);
|
||||
|
||||
private:
|
||||
|
||||
int _timer;
|
||||
|
||||
bool _is_paused;
|
||||
bool _is_gameplay_paused = false;
|
||||
|
||||
bool _enable_file_packages;
|
||||
/// компрессия ресурсов в архивах, 0 - отключена, 9 - максимальная
|
||||
int _resource_compression;
|
||||
|
||||
/// таблица рекордов, если нету - размер нулевой
|
||||
int _hall_of_fame_size;
|
||||
struct HallOfFameEntry {
|
||||
Common::String _player_name;
|
||||
int _score;
|
||||
|
||||
bool _updated;
|
||||
|
||||
HallOfFameEntry() {
|
||||
_score = 0;
|
||||
_updated = false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef Std::vector<HallOfFameEntry> HallOfFame;
|
||||
HallOfFame _hall_of_fame;
|
||||
|
||||
qdInterfaceDispatcher _interface_dispatcher;
|
||||
|
||||
winVideo _video_player;
|
||||
qdVideo *_cur_video;
|
||||
qdObjectListContainer<qdVideo> _videos;
|
||||
|
||||
qdObjectListContainer<qdGameObject> _global_objects;
|
||||
qdObjectListContainer<qdTriggerChain> _trigger_chains;
|
||||
qdObjectListContainer<qdInventory> _inventories;
|
||||
qdObjectListContainer<qdGameEnd> _game_ends;
|
||||
qdObjectListContainer<qdGameScene> _scenes;
|
||||
qdObjectListContainer<qdCounter> _counters;
|
||||
|
||||
qdGameScene *_cur_scene;
|
||||
bool _scene_saved;
|
||||
int _autosave_slot;
|
||||
|
||||
//! Если ненулевой - игра заканчивается с переходом на него.
|
||||
const qdGameEnd *_game_end;
|
||||
|
||||
qdObjectListContainer<qdMiniGame> _minigames;
|
||||
|
||||
qdInventory *_cur_inventory;
|
||||
qdInventoryCellTypeVector _inventory_cell_types;
|
||||
//! Шрифты
|
||||
qdObjectListContainer<qdFontInfo> _fonts;
|
||||
|
||||
//! Шрифт, используемый для отрисовки текстов, в формате который шрифт не задан.
|
||||
int _default_font;
|
||||
|
||||
qdGameObjectMouse *_mouse_obj;
|
||||
qdGameObjectAnimated *_mouse_click_obj;
|
||||
const qdGameObjectState *_mouse_click_state;
|
||||
qdAnimation *_mouse_animation;
|
||||
Vect2f _mouse_cursor_pos;
|
||||
|
||||
typedef Std::vector<qdGameObjectState *> dialog_states_container_t;
|
||||
dialog_states_container_t _dialog_states;
|
||||
dialog_states_container_t _dialog_states_last;
|
||||
|
||||
qdScreenTextDispatcher _screen_texts;
|
||||
|
||||
Common::String _startup_scene;
|
||||
|
||||
//! Файл с субтитрами.
|
||||
Common::Path _texts_database;
|
||||
|
||||
//! Название игры.
|
||||
Common::String _game_title;
|
||||
|
||||
Common::String _cd_key;
|
||||
|
||||
void *_scene_loading_progress_data;
|
||||
qdLoadingProgressFnc _scene_loading_progress_fnc;
|
||||
|
||||
qdGameScene *_next_scene;
|
||||
|
||||
bool _interface_music_mode;
|
||||
const qdMusicTrack *_cur_music_track;
|
||||
const qdMusicTrack *_cur_interface_music_track;
|
||||
|
||||
float _fade_timer;
|
||||
float _fade_duration;
|
||||
|
||||
qdCameraMode _default_camera_mode;
|
||||
|
||||
static qdGameDispatcher *_dispatcher;
|
||||
|
||||
bool init_inventories();
|
||||
|
||||
qdInventoryCellTypeVector::iterator find_inventory_cell_type(int type) {
|
||||
return Common::find(_inventory_cell_types.begin(),
|
||||
_inventory_cell_types.end(), type);
|
||||
}
|
||||
|
||||
qdInventoryCellTypeVector::const_iterator find_inventory_cell_type(int type) const {
|
||||
return Common::find(_inventory_cell_types.begin(), _inventory_cell_types.end(), type);
|
||||
}
|
||||
|
||||
void redraw(const grScreenRegion ®);
|
||||
void redraw_scene(bool draw_interface = true);
|
||||
|
||||
/// включает нужный экран внутриигрового интерфейса
|
||||
bool update_ingame_interface();
|
||||
|
||||
/// вытаскивает из интерфейса имена игроков в таблице рекордов
|
||||
bool update_hall_of_fame_names();
|
||||
};
|
||||
|
||||
qdGameDispatcher *qd_get_game_dispatcher();
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_DISPATCHER_H
|
||||
251
engines/qdengine/qdcore/qd_game_dispatcher_base.cpp
Normal file
251
engines/qdengine/qdcore/qd_game_dispatcher_base.cpp
Normal file
@@ -0,0 +1,251 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
|
||||
#include "qdengine/parser/xml_tag.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_sound.h"
|
||||
#include "qdengine/qdcore/qd_animation.h"
|
||||
#include "qdengine/qdcore/qd_animation_set.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher_base.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdGameDispatcherBase::qdGameDispatcherBase() {
|
||||
}
|
||||
|
||||
qdGameDispatcherBase::~qdGameDispatcherBase() {
|
||||
}
|
||||
|
||||
void qdGameDispatcherBase::load_script_body(const xml::tag *p) {
|
||||
qdAnimation *ap;
|
||||
qdAnimationSet *asp;
|
||||
qdSound *snd;
|
||||
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_OBJ_SCALE_INFO: {
|
||||
qdScaleInfo sp;
|
||||
sp.load_script(&*it);
|
||||
add_scale_info(&sp);
|
||||
}
|
||||
break;
|
||||
case QDSCR_ANIMATION:
|
||||
ap = new qdAnimation;
|
||||
ap->load_script(&*it);
|
||||
add_animation(ap);
|
||||
break;
|
||||
case QDSCR_ANIMATION_SET:
|
||||
asp = new qdAnimationSet;
|
||||
asp->load_script(&*it);
|
||||
add_animation_set(asp);
|
||||
break;
|
||||
case QDSCR_SOUND:
|
||||
snd = new qdSound;
|
||||
snd->load_script(&*it);
|
||||
add_sound(snd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
for (auto &it : _scale_infos) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (auto &it : sound_list()) {
|
||||
it->save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (auto &it : animation_list()) {
|
||||
it->save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (auto &it : animation_set_list()) {
|
||||
it->save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::get_object_scale(const char *p, float &sc) {
|
||||
qdScaleInfo *si = get_scale_info(p);
|
||||
if (si) {
|
||||
sc = si->scale();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdScaleInfo *qdGameDispatcherBase::get_scale_info(const char *p) {
|
||||
for (scale_info_container_t::iterator it = _scale_infos.begin(); it != _scale_infos.end(); ++it) {
|
||||
if (!strcmp(it->name(), p)) {
|
||||
return &*it;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::set_object_scale(const char *p, float sc) {
|
||||
for (scale_info_container_t::iterator it = _scale_infos.begin(); it != _scale_infos.end(); ++it) {
|
||||
if (!strcmp(it->name(), p)) {
|
||||
it->set_scale(sc);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
qdScaleInfo scl;
|
||||
scl.set_name(p);
|
||||
scl.set_scale(sc);
|
||||
|
||||
add_scale_info(&scl);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int qdGameDispatcherBase::load_resources() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qdGameDispatcherBase::free_resources() {
|
||||
for (auto &ia : animation_list()) {
|
||||
ia->free_resources();
|
||||
}
|
||||
|
||||
for (auto &is : sound_list()) {
|
||||
is->free_resource();
|
||||
}
|
||||
}
|
||||
|
||||
int qdGameDispatcherBase::get_resources_size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qdGameDispatcherBase::show_loading_progress(int sz) {
|
||||
_loading_progress.show_progress(sz);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::add_sound(qdSound *p) {
|
||||
if (_sounds.add_object(p)) {
|
||||
p->set_owner(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::remove_sound(const char *name) {
|
||||
return _sounds.remove_object(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::remove_sound(qdSound *p) {
|
||||
return _sounds.remove_object(p);
|
||||
}
|
||||
|
||||
qdSound *qdGameDispatcherBase::get_sound(const char *name) {
|
||||
return _sounds.get_object(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::is_sound_in_list(const char *name) {
|
||||
return _sounds.is_in_list(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::is_sound_in_list(qdSound *p) {
|
||||
return _sounds.is_in_list(p);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::add_animation(qdAnimation *p) {
|
||||
if (_animations.add_object(p)) {
|
||||
p->set_owner(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::remove_animation(const char *name) {
|
||||
return _animations.remove_object(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::remove_animation(qdAnimation *p) {
|
||||
return _animations.remove_object(p);
|
||||
}
|
||||
|
||||
qdAnimation *qdGameDispatcherBase::get_animation(const char *name) {
|
||||
return _animations.get_object(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::is_animation_in_list(const char *name) {
|
||||
return _animations.is_in_list(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::is_animation_in_list(qdAnimation *p) {
|
||||
return _animations.is_in_list(p);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::add_animation_set(qdAnimationSet *p) {
|
||||
if (_animation_sets.add_object(p)) {
|
||||
p->set_owner(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::remove_animation_set(const char *name) {
|
||||
return _animation_sets.remove_object(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::remove_animation_set(qdAnimationSet *p) {
|
||||
return _animation_sets.remove_object(p);
|
||||
}
|
||||
|
||||
qdAnimationSet *qdGameDispatcherBase::get_animation_set(const char *name) {
|
||||
return _animation_sets.get_object(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::is_animation_set_in_list(const char *name) {
|
||||
return _animation_sets.is_in_list(name);
|
||||
}
|
||||
|
||||
bool qdGameDispatcherBase::is_animation_set_in_list(qdAnimationSet *p) {
|
||||
return _animation_sets.is_in_list(p);
|
||||
}
|
||||
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
bool qdGameDispatcherBase::get_resources_info(qdResourceInfoContainer &infos) const {
|
||||
for (qdSoundList::const_iterator it = sound_list().begin(); it != sound_list().end(); ++it) {
|
||||
if ((*it)->is_resource_loaded())
|
||||
infos.push_back(qdResourceInfo(*it, *it));
|
||||
}
|
||||
|
||||
for (qdAnimationList::const_iterator it = animation_list().begin(); it != animation_list().end(); ++it) {
|
||||
if ((*it)->is_resource_loaded())
|
||||
infos.push_back(qdResourceInfo(*it, *it));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace QDEngine
|
||||
165
engines/qdengine/qdcore/qd_game_dispatcher_base.h
Normal file
165
engines/qdengine/qdcore/qd_game_dispatcher_base.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_DISPATCHER_BASE_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_DISPATCHER_BASE_H
|
||||
|
||||
#include "qdengine/qdcore/qd_conditional_object.h"
|
||||
#include "qdengine/qdcore/qd_object_map_container.h"
|
||||
#include "qdengine/qdcore/qd_scale_info.h"
|
||||
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
#include "qdengine/qdcore/qd_resource.h"
|
||||
#endif
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
typedef void (*qdLoadingProgressFnc)(int percents_loaded, void *data);
|
||||
|
||||
class qdLoadingProgressInfo {
|
||||
uint32 _total_size;
|
||||
uint32 _loaded_size;
|
||||
void *_data;
|
||||
qdLoadingProgressFnc _progress_fnc;
|
||||
|
||||
public:
|
||||
|
||||
qdLoadingProgressFnc set_callback_fnc(qdLoadingProgressFnc p, void *dp) {
|
||||
qdLoadingProgressFnc old_fnc = _progress_fnc;
|
||||
_progress_fnc = p;
|
||||
_data = dp;
|
||||
|
||||
return old_fnc;
|
||||
}
|
||||
|
||||
void set_total_size(int sz) {
|
||||
_total_size = sz;
|
||||
_loaded_size = 0;
|
||||
}
|
||||
int total_size() const {
|
||||
return _total_size;
|
||||
}
|
||||
|
||||
void show_progress(int sz) {
|
||||
if (!_total_size || !_progress_fnc) return;
|
||||
_loaded_size += sz;
|
||||
uint32 percents = round(float(_loaded_size) / float(_total_size) * 100.0f);
|
||||
(*_progress_fnc)(percents, _data);
|
||||
}
|
||||
|
||||
qdLoadingProgressInfo() {
|
||||
_progress_fnc = 0;
|
||||
_total_size = _loaded_size = 0;
|
||||
_data = 0;
|
||||
}
|
||||
~qdLoadingProgressInfo() { };
|
||||
};
|
||||
|
||||
class qdGameDispatcherBase : public qdConditionalObject {
|
||||
public:
|
||||
qdGameDispatcherBase();
|
||||
~qdGameDispatcherBase();
|
||||
|
||||
void set_resources_size(int sz) {
|
||||
_loading_progress.set_total_size(sz);
|
||||
}
|
||||
|
||||
qdLoadingProgressFnc set_loading_progress_callback(qdLoadingProgressFnc p, void *dp = 0) {
|
||||
return _loading_progress.set_callback_fnc(p, dp);
|
||||
}
|
||||
|
||||
void show_loading_progress(int sz = 0);
|
||||
|
||||
bool add_sound(qdSound *p);
|
||||
bool remove_sound(const char *name);
|
||||
bool remove_sound(qdSound *p);
|
||||
virtual qdSound *get_sound(const char *name);
|
||||
bool is_sound_in_list(const char *name);
|
||||
bool is_sound_in_list(qdSound *p);
|
||||
|
||||
bool add_animation(qdAnimation *p);
|
||||
bool remove_animation(const char *name);
|
||||
bool remove_animation(qdAnimation *p);
|
||||
virtual qdAnimation *get_animation(const char *name);
|
||||
bool is_animation_in_list(const char *name);
|
||||
bool is_animation_in_list(qdAnimation *p);
|
||||
|
||||
bool add_animation_set(qdAnimationSet *p);
|
||||
bool remove_animation_set(const char *name);
|
||||
bool remove_animation_set(qdAnimationSet *p);
|
||||
virtual qdAnimationSet *get_animation_set(const char *name);
|
||||
bool is_animation_set_in_list(const char *name);
|
||||
bool is_animation_set_in_list(qdAnimationSet *p);
|
||||
|
||||
const qdSoundList &sound_list() const {
|
||||
return _sounds.get_list();
|
||||
}
|
||||
const qdAnimationList &animation_list() const {
|
||||
return _animations.get_list();
|
||||
}
|
||||
const qdAnimationSetList &animation_set_list() const {
|
||||
return _animation_sets.get_list();
|
||||
}
|
||||
|
||||
virtual void load_script_body(const xml::tag *p);
|
||||
virtual bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
virtual int load_resources();
|
||||
void free_resources();
|
||||
|
||||
virtual void quant(float dt) { };
|
||||
|
||||
void add_scale_info(qdScaleInfo *p) {
|
||||
_scale_infos.push_back(*p);
|
||||
}
|
||||
bool get_object_scale(const char *p, float &sc);
|
||||
bool set_object_scale(const char *p, float sc);
|
||||
|
||||
virtual qdScaleInfo *get_scale_info(const char *p);
|
||||
|
||||
virtual int get_resources_size();
|
||||
|
||||
qdConditionalObject::trigger_start_mode trigger_start() {
|
||||
return qdConditionalObject::TRIGGER_START_FAILED;
|
||||
}
|
||||
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
virtual bool get_resources_info(qdResourceInfoContainer &infos) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
qdObjectMapContainer<qdAnimation> _animations;
|
||||
qdObjectMapContainer<qdAnimationSet> _animation_sets;
|
||||
qdObjectMapContainer<qdSound> _sounds;
|
||||
|
||||
typedef Std::vector<qdScaleInfo> scale_info_container_t;
|
||||
scale_info_container_t _scale_infos;
|
||||
|
||||
qdLoadingProgressInfo _loading_progress;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_DISPATCHER_BASE_H
|
||||
114
engines/qdengine/qdcore/qd_game_end.cpp
Normal file
114
engines/qdengine/qdcore/qd_game_end.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_game_end.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdGameEnd::qdGameEnd() {
|
||||
}
|
||||
|
||||
qdGameEnd::qdGameEnd(const qdGameEnd &end) : qdConditionalObject(end),
|
||||
_interface_screen(end._interface_screen) {
|
||||
}
|
||||
|
||||
qdGameEnd::~qdGameEnd() {
|
||||
}
|
||||
|
||||
qdGameEnd &qdGameEnd::operator = (const qdGameEnd &end) {
|
||||
if (this == &end) return *this;
|
||||
|
||||
*static_cast<qdConditionalObject *>(this) = end;
|
||||
|
||||
_interface_screen = end._interface_screen;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
qdConditionalObject::trigger_start_mode qdGameEnd::trigger_start() {
|
||||
if (qdGameDispatcher *p = qdGameDispatcher::get_dispatcher()) {
|
||||
p->set_game_end(this);
|
||||
return qdConditionalObject::TRIGGER_START_ACTIVATE;
|
||||
}
|
||||
|
||||
return qdConditionalObject::TRIGGER_START_FAILED;
|
||||
}
|
||||
|
||||
bool qdGameEnd::load_script(const xml::tag *p) {
|
||||
load_conditions_script(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_GAME_END_SCREEN:
|
||||
set_interface_screen(it->data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameEnd::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<game_end");
|
||||
|
||||
if (name()) {
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
}
|
||||
|
||||
if (flags()) {
|
||||
fh.writeString(Common::String::format(" flags=\"%d\"", flags()));
|
||||
}
|
||||
|
||||
if (!_interface_screen.empty()) {
|
||||
fh.writeString(Common::String::format(" end_screen=\"%s\"", qdscr_XML_string(_interface_screen.c_str())));
|
||||
}
|
||||
|
||||
if (has_conditions()) {
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
save_conditions_script(fh, indent);
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("</game_end>\r\n");
|
||||
} else {
|
||||
fh.writeString("/>\r\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
71
engines/qdengine/qdcore/qd_game_end.h
Normal file
71
engines/qdengine/qdcore/qd_game_end.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_END_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_END_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_conditional_object.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Концовка игры.
|
||||
class qdGameEnd : public qdConditionalObject {
|
||||
public:
|
||||
qdGameEnd();
|
||||
qdGameEnd(const qdGameEnd &end);
|
||||
|
||||
qdGameEnd &operator = (const qdGameEnd &end);
|
||||
|
||||
~qdGameEnd();
|
||||
|
||||
const char *interface_screen() const {
|
||||
return _interface_screen.c_str();
|
||||
}
|
||||
bool has_interface_screen() const {
|
||||
return !_interface_screen.empty();
|
||||
}
|
||||
void set_interface_screen(const char *name) {
|
||||
if (name) _interface_screen = name;
|
||||
else _interface_screen.clear();
|
||||
}
|
||||
|
||||
qdConditionalObject::trigger_start_mode trigger_start();
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_GAME_END;
|
||||
};
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
private:
|
||||
|
||||
//! Имя интерфейсного экрана, на который выходить из игры.
|
||||
/**
|
||||
Если строка пустая - будет выход в main menu.
|
||||
*/
|
||||
Common::String _interface_screen;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_END_H
|
||||
235
engines/qdengine/qdcore/qd_game_object.cpp
Normal file
235
engines/qdengine/qdcore/qd_game_object.cpp
Normal file
@@ -0,0 +1,235 @@
|
||||
/* 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/xmath.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_game_object.h"
|
||||
#include "qdengine/qdcore/qd_camera.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdGameObject::qdGameObject() : _r(0, 0, 0),
|
||||
_parallax_offset(0.0f, 0.0f),
|
||||
_screen_r(0, 0),
|
||||
_screen_depth(0.0f), _tempPosInList(0) {
|
||||
}
|
||||
|
||||
qdGameObject::qdGameObject(const qdGameObject &obj) : qdNamedObject(obj),
|
||||
_r(obj._r),
|
||||
_parallax_offset(obj._parallax_offset),
|
||||
_screen_r(obj._screen_r),
|
||||
_screen_depth(obj._screen_depth), _tempPosInList(obj._tempPosInList) {
|
||||
}
|
||||
|
||||
qdGameObject::~qdGameObject() {
|
||||
}
|
||||
|
||||
qdGameObject &qdGameObject::operator = (const qdGameObject &obj) {
|
||||
if (this == &obj) return *this;
|
||||
|
||||
*static_cast<qdNamedObject *>(this) = obj;
|
||||
|
||||
_r = obj._r;
|
||||
_parallax_offset = obj._parallax_offset;
|
||||
|
||||
_screen_r = obj._screen_r;
|
||||
_screen_depth = obj._screen_depth;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdGameObject::load_script_body(const xml::tag *p) {
|
||||
int fl;
|
||||
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_POS2D:
|
||||
xml::tag_buffer(*it) > _r.x > _r.y;
|
||||
_r.z = 0.0f;
|
||||
break;
|
||||
case QDSCR_POS3D:
|
||||
xml::tag_buffer(*it) > _r.x > _r.y > _r.z;
|
||||
break;
|
||||
case QDSCR_FLAG:
|
||||
xml::tag_buffer(*it) > fl;
|
||||
set_flag(fl);
|
||||
break;
|
||||
case QDSCR_PARALLAX_OFFSET:
|
||||
xml::tag_buffer(*it) > _parallax_offset.x > _parallax_offset.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObject::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString(Common::String::format("<pos_3d>%f %f %f</pos_3d>\r\n", _r.x, _r.y, _r.z));
|
||||
|
||||
if (_parallax_offset.x || _parallax_offset.y) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<parallax_offset>%d %d</parallax_offset>\r\n", _parallax_offset.x, _parallax_offset.y));
|
||||
}
|
||||
|
||||
if (flags()) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
if (debugChannelSet(-1, kDebugLog))
|
||||
fh.writeString(Common::String::format("<flag>%s</flag>\r\n", flag2str(flags()).c_str()));
|
||||
else
|
||||
fh.writeString(Common::String::format("<flag>%d</flag>\r\n", flags()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdGameObject::quant(float dt) {
|
||||
}
|
||||
|
||||
bool qdGameObject::update_screen_pos() {
|
||||
if (!check_flag(QD_OBJ_SCREEN_COORDS_FLAG)) {
|
||||
if (const qdCamera * cp = qdCamera::current_camera()) {
|
||||
Vect3f v = cp->global2camera_coord(R());
|
||||
|
||||
if (check_flag(QD_OBJ_FIXED_SCREEN_COORDS_FLAG)) {
|
||||
_screen_r = cp->camera_coord2rscr(v);
|
||||
_screen_r.x += cp->get_scr_sx() / 2;
|
||||
_screen_r.y = cp->get_scr_sy() / 2 - _screen_r.y;
|
||||
|
||||
_screen_depth = 0.0f;
|
||||
} else {
|
||||
_screen_r = cp->camera_coord2scr(v);
|
||||
|
||||
Vect3f rr = R();
|
||||
rr.z = cp->get_grid_center().z;
|
||||
_screen_depth = cp->global2camera_coord(rr).z;
|
||||
}
|
||||
|
||||
if (_parallax_offset.x || _parallax_offset.y) {
|
||||
_screen_r.x += round(float(_parallax_offset.x) * cp->scrolling_phase_x());
|
||||
_screen_r.y += round(float(_parallax_offset.y) * cp->scrolling_phase_y());
|
||||
}
|
||||
} else
|
||||
return false;
|
||||
} else {
|
||||
_screen_r = Vect2i(R().xi(), R().yi());
|
||||
_screen_depth = 0.0f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObject::load_data(Common::SeekableReadStream &fh, int saveVersion) {
|
||||
debugC(3, kDebugSave, " qdGameObject::load_data(): before: %d", (int)fh.pos());
|
||||
|
||||
if (!qdNamedObject::load_data(fh, saveVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_r.x = fh.readFloatLE();
|
||||
_r.y = fh.readFloatLE();
|
||||
_r.z = fh.readFloatLE();
|
||||
|
||||
debugC(3, kDebugSave, " qdGameObject::load_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObject::save_data(Common::WriteStream &fh) const {
|
||||
debugC(3, kDebugSave, " qdGameObject::save_data(): before: %d", (int)fh.pos());
|
||||
if (!qdNamedObject::save_data(fh)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fh.writeFloatLE(_r.x);
|
||||
fh.writeFloatLE(_r.y);
|
||||
fh.writeFloatLE(_r.z);
|
||||
|
||||
debugC(3, kDebugSave, " qdGameObject::save_data(): after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObject::init() {
|
||||
drop_flag(QD_OBJ_SCREEN_COORDS_FLAG);
|
||||
drop_flag(QD_OBJ_STATE_CHANGE_FLAG | QD_OBJ_IS_IN_TRIGGER_FLAG | QD_OBJ_IS_IN_INVENTORY_FLAG);
|
||||
drop_flag(QD_OBJ_HIDDEN_FLAG);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define defFlag(x) { x, #x }
|
||||
|
||||
struct FlagsList {
|
||||
int f;
|
||||
const char *s;
|
||||
} static flagList[] = {
|
||||
defFlag(QD_OBJ_MOVING_FLAG),
|
||||
defFlag(QD_OBJ_HIDDEN_FLAG),
|
||||
defFlag(QD_OBJ_INVERSE_PERSPECTIVE_FLAG),
|
||||
defFlag(QD_OBJ_SHOW_NAME_FLAG),
|
||||
defFlag(QD_OBJ_NO_SCALE_FLAG),
|
||||
defFlag(QD_OBJ_SCREEN_COORDS_FLAG),
|
||||
defFlag(QD_OBJ_NON_PLAYER_PERSONAGE_FLAG),
|
||||
defFlag(QD_OBJ_HAS_BOUND_FLAG),
|
||||
defFlag(QD_OBJ_DISABLE_MOVEMENT_FLAG),
|
||||
defFlag(QD_OBJ_DISABLE_MOUSE_FLAG),
|
||||
defFlag(QD_OBJ_IS_IN_TRIGGER_FLAG),
|
||||
defFlag(QD_OBJ_STATE_CHANGE_FLAG),
|
||||
defFlag(QD_OBJ_IS_IN_INVENTORY_FLAG),
|
||||
defFlag(QD_OBJ_KEYBOARD_CONTROL_FLAG),
|
||||
defFlag(QD_OBJ_FIXED_SCREEN_COORDS_FLAG),
|
||||
};
|
||||
|
||||
Common::String qdGameObject::flag2str(int fl) const {
|
||||
Common::String res;
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(flagList); i++) {
|
||||
if (fl & flagList[i].f) {
|
||||
if (!res.empty())
|
||||
res += " | ";
|
||||
|
||||
res += flagList[i].s;
|
||||
|
||||
fl &= ~flagList[i].f;
|
||||
}
|
||||
}
|
||||
|
||||
if (fl)
|
||||
res += Common::String::format(" | %x", fl);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
199
engines/qdengine/qdcore/qd_game_object.h
Normal file
199
engines/qdengine/qdcore/qd_game_object.h
Normal file
@@ -0,0 +1,199 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_OBJECT_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_OBJECT_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/system/input/mouse_input.h"
|
||||
#include "qdengine/system/graphics/gr_screen_region.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
const int QD_OBJ_MOVING_FLAG = 0x01;
|
||||
const int QD_OBJ_HIDDEN_FLAG = 0x02;
|
||||
const int QD_OBJ_INVERSE_PERSPECTIVE_FLAG = 0x04;
|
||||
const int QD_OBJ_SHOW_NAME_FLAG = 0x08;
|
||||
const int QD_OBJ_NO_SCALE_FLAG = 0x10;
|
||||
const int QD_OBJ_SCREEN_COORDS_FLAG = 0x20;
|
||||
const int QD_OBJ_NON_PLAYER_PERSONAGE_FLAG = 0x40;
|
||||
const int QD_OBJ_HAS_BOUND_FLAG = 0x80;
|
||||
const int QD_OBJ_DISABLE_MOVEMENT_FLAG = 0x100;
|
||||
const int QD_OBJ_DISABLE_MOUSE_FLAG = 0x200;
|
||||
const int QD_OBJ_IS_IN_TRIGGER_FLAG = 0x400;
|
||||
const int QD_OBJ_STATE_CHANGE_FLAG = 0x800;
|
||||
const int QD_OBJ_IS_IN_INVENTORY_FLAG = 0x1000;
|
||||
const int QD_OBJ_KEYBOARD_CONTROL_FLAG = 0x2000;
|
||||
const int QD_OBJ_FIXED_SCREEN_COORDS_FLAG = 0x4000;
|
||||
|
||||
//! Базовый класс для игровых объектов.
|
||||
class qdGameObject : public qdNamedObject {
|
||||
public:
|
||||
qdGameObject();
|
||||
qdGameObject(const qdGameObject &obj);
|
||||
~qdGameObject();
|
||||
|
||||
qdGameObject &operator = (const qdGameObject &obj);
|
||||
|
||||
void set_parallax_offset(int offs_x, int offs_y) {
|
||||
_parallax_offset.x = offs_x;
|
||||
_parallax_offset.y = offs_y;
|
||||
}
|
||||
const Vect2i &get_parallax_offset() const {
|
||||
return _parallax_offset;
|
||||
}
|
||||
|
||||
virtual void redraw(int offs_x = 0, int offs_y = 0) const = 0;
|
||||
virtual void debug_redraw() const = 0;
|
||||
virtual void draw_contour(uint32 color) const = 0;
|
||||
virtual void draw_shadow(int offs_x, int offs_y, uint32 color, int alpha) const = 0;
|
||||
|
||||
virtual bool need_redraw() const {
|
||||
return false;
|
||||
}
|
||||
virtual void post_redraw() { }
|
||||
|
||||
virtual const grScreenRegion last_screen_region() const {
|
||||
return grScreenRegion_EMPTY;
|
||||
}
|
||||
virtual grScreenRegion screen_region() const {
|
||||
return grScreenRegion(grScreenRegion_EMPTY);
|
||||
}
|
||||
|
||||
virtual bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) = 0;
|
||||
virtual bool hit(int x, int y) const = 0;
|
||||
|
||||
const Vect2i &screen_pos() const {
|
||||
return _screen_r;
|
||||
}
|
||||
virtual bool update_screen_pos();
|
||||
virtual Vect2s screen_size() const = 0;
|
||||
|
||||
float screen_depth() const {
|
||||
return _screen_depth;
|
||||
}
|
||||
|
||||
virtual bool is_visible() const {
|
||||
return !check_flag(QD_OBJ_HIDDEN_FLAG);
|
||||
}
|
||||
|
||||
const Vect3f &R() const {
|
||||
return _r;
|
||||
}
|
||||
void set_pos(const Vect3f &rr) {
|
||||
_r = rr;
|
||||
}
|
||||
|
||||
virtual bool load_script(const xml::tag *p) = 0;
|
||||
virtual bool save_script(Common::WriteStream &fh, int indent = 0) const = 0;
|
||||
|
||||
virtual bool load_resources() {
|
||||
return true;
|
||||
};
|
||||
virtual void free_resources() { };
|
||||
|
||||
//! Инициализация объекта, вызывается при старте и перезапуске игры.
|
||||
virtual bool init();
|
||||
|
||||
virtual void quant(float dt);
|
||||
|
||||
virtual bool init_grid_zone() {
|
||||
return false;
|
||||
}
|
||||
virtual bool toggle_grid_zone(bool make_walkable = false) {
|
||||
return false;
|
||||
}
|
||||
virtual bool save_grid_zone() {
|
||||
return false;
|
||||
}
|
||||
virtual bool restore_grid_zone() {
|
||||
return false;
|
||||
}
|
||||
virtual bool set_grid_zone_attributes(int attr) const {
|
||||
return false;
|
||||
}
|
||||
virtual bool drop_grid_zone_attributes(int attr) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Копирует в буфер отладочную информацию для вывода на экран в отладочном режиме.
|
||||
virtual bool get_debug_info(Common::String &buf) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int saveVersion);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
const Vect2i &get_screen_R() const {
|
||||
return _screen_r;
|
||||
}
|
||||
|
||||
void setTempPosInList(uint pos) { _tempPosInList = pos; }
|
||||
uint tempPosInList() const { return _tempPosInList; }
|
||||
|
||||
Common::String flag2str(int flags) const;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool load_script_body(const xml::tag *p);
|
||||
virtual bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
void set_screen_R(const Vect2i &v) {
|
||||
_screen_r = v;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Vect3f _r;
|
||||
Vect2i _parallax_offset;
|
||||
|
||||
Vect2i _screen_r;
|
||||
float _screen_depth;
|
||||
uint _tempPosInList;
|
||||
};
|
||||
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
inline bool qdbg_is_object(const qdNamedObject *obj, const char *scene_name, const char *object_name) {
|
||||
if (dynamic_cast<const qdGameObject * >(obj)) {
|
||||
if (obj->name() && !strcmp(object_name, obj->name())) {
|
||||
if (!scene_name || (obj->owner() && obj->owner()->name() && !strcmp(obj->owner()->name(), scene_name)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
inline bool qdbg_is_object(const qdNamedObject *, const char *, const char *) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_OBJECT_H
|
||||
1607
engines/qdengine/qdcore/qd_game_object_animated.cpp
Normal file
1607
engines/qdengine/qdcore/qd_game_object_animated.cpp
Normal file
File diff suppressed because it is too large
Load Diff
391
engines/qdengine/qdcore/qd_game_object_animated.h
Normal file
391
engines/qdengine/qdcore/qd_game_object_animated.h
Normal file
@@ -0,0 +1,391 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_OBJECT_ANIMATED_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_OBJECT_ANIMATED_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_animation.h"
|
||||
#include "qdengine/qdcore/qd_coords_animation.h"
|
||||
#include "qdengine/qdcore/qd_game_object.h"
|
||||
#include "qdengine/qdcore/qd_game_object_state.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Dynamic object
|
||||
/**
|
||||
Paticularly dynamic object, actors and the mouse.
|
||||
*/
|
||||
class qdGameObjectAnimated : public qdGameObject {
|
||||
public:
|
||||
enum StateStatus {
|
||||
STATE_INACTIVE,
|
||||
STATE_QUEUED,
|
||||
STATE_ACTIVE,
|
||||
STATE_DONE
|
||||
};
|
||||
|
||||
qdGameObjectAnimated();
|
||||
qdGameObjectAnimated(const qdGameObjectAnimated &obj);
|
||||
~qdGameObjectAnimated();
|
||||
|
||||
qdGameObjectAnimated &operator = (const qdGameObjectAnimated &obj);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_ANIMATED_OBJ;
|
||||
}
|
||||
|
||||
//! Возвращает баунд объекта.
|
||||
virtual const Vect3f &bound(bool perspective_correction = true) const;
|
||||
|
||||
//! Устанавливает баунд объекта по текущему состоянию.
|
||||
bool auto_bound();
|
||||
//! Возвращает радиус объекта.
|
||||
virtual float radius() const;
|
||||
//! Устанавливает баунд объекта.
|
||||
void set_bound(const Vect3f &b);
|
||||
//! Возвращает true, если у объекта выставлен баунд.
|
||||
bool has_bound() const {
|
||||
if (check_flag(QD_OBJ_HAS_BOUND_FLAG)) return true;
|
||||
if (_cur_state != -1 && _states[_cur_state]->has_bound()) return true;
|
||||
return false;
|
||||
}
|
||||
//! Отрисовка баунда (для отладки).
|
||||
void draw_bound() const;
|
||||
void draw_bound(Vect3f r, Vect3f const &bound, int const color) const;
|
||||
//! Пересекается ли баунд, расположенный в точке с заданным баундом с центром в cen
|
||||
bool inters_with_bound(Vect3f bnd, Vect3f cen, bool perspective_correction = true) const;
|
||||
|
||||
//! Возвращает номер текущего состояния объекта.
|
||||
int cur_state() const {
|
||||
return _cur_state;
|
||||
}
|
||||
//! Устанавливает номер текущего состояния объекта.
|
||||
void set_cur_state(int st) {
|
||||
_cur_state = st;
|
||||
}
|
||||
//! Возвращает количество состояний объекта.
|
||||
int max_state() const {
|
||||
return _states.size();
|
||||
}
|
||||
//! Возвращает номер состояния или -1 если не может такое состояние найти.
|
||||
int get_state_index(const qdGameObjectState *p) const;
|
||||
|
||||
//! Установка владельца состояний.
|
||||
void set_states_owner();
|
||||
|
||||
//! Возвращает true, если состояние с именем state_name активно.
|
||||
bool is_state_active(const char *state_name) const;
|
||||
//! Возвращает true, если состояние с именем state_name было активировано.
|
||||
bool was_state_active(const char *state_name) const;
|
||||
|
||||
//! Возвращает true, если состояние state активно.
|
||||
bool is_state_active(const qdGameObjectState *p) const {
|
||||
if (_cur_state != -1 && _states[_cur_state] == p)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Возвращает true, если состояние с именем state_name было активно перед активным в данный момент состоянием.
|
||||
bool was_state_previous(const char *state_name) const;
|
||||
//! Возвращает true, если состояние p было активно перед активным в данный момент состоянием.
|
||||
bool was_state_previous(const qdGameObjectState *p) const {
|
||||
return (_last_state == p);
|
||||
}
|
||||
|
||||
//! Возвращает true, если состояние state было активировано.
|
||||
bool was_state_active(const qdGameObjectState *p) const {
|
||||
return p->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_WAS_ACTIVATED);
|
||||
}
|
||||
|
||||
bool is_state_waiting(const qdGameObjectState *p) const {
|
||||
if (_queued_state == p) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_state_waiting(const char *state_name) const;
|
||||
|
||||
//! Возвращает состояния объекта.
|
||||
const qdGameObjectStateVector &state_vector() const {
|
||||
return _states;
|
||||
}
|
||||
|
||||
//! Возвращает true, если объект в данный момент может менять состояние.
|
||||
virtual bool can_change_state(const qdGameObjectState *state = NULL) const;
|
||||
|
||||
qdGameObjectState *get_state(const char *state_name);
|
||||
qdGameObjectState *get_state(int state_index);
|
||||
qdGameObjectState *get_cur_state() {
|
||||
return get_state(cur_state());
|
||||
}
|
||||
|
||||
const qdGameObjectState *get_state(const char *state_name) const;
|
||||
const qdGameObjectState *get_state(int state_index) const;
|
||||
const qdGameObjectState *get_cur_state() const {
|
||||
return get_state(cur_state());
|
||||
}
|
||||
|
||||
void set_queued_state(qdGameObjectState *st) {
|
||||
_queued_state = st;
|
||||
}
|
||||
|
||||
qdGameObjectState *queued_state() {
|
||||
return _queued_state;
|
||||
}
|
||||
const qdGameObjectState *queued_state() const {
|
||||
return _queued_state;
|
||||
}
|
||||
|
||||
void merge_states(qdGameObjectAnimated *p);
|
||||
void split_states(qdGameObjectAnimated *p);
|
||||
|
||||
StateStatus state_status(const qdGameObjectState *p) const;
|
||||
|
||||
bool add_state(qdGameObjectState *p);
|
||||
bool insert_state(int iBefore, qdGameObjectState *p);
|
||||
qdGameObjectState *remove_state(int state_num);
|
||||
bool remove_state(qdGameObjectState *p);
|
||||
|
||||
virtual void set_state(int st);
|
||||
virtual void set_state(qdGameObjectState *p);
|
||||
void restore_state();
|
||||
|
||||
bool has_camera_mode() const;
|
||||
const qdCameraMode &camera_mode() const;
|
||||
|
||||
//! Возвращает количество имеющихся у объекта направлений.
|
||||
int num_directions() const;
|
||||
|
||||
const Vect3f &default_R() const {
|
||||
return _default_r;
|
||||
}
|
||||
void set_default_pos(const Vect3f &r) {
|
||||
_default_r = r;
|
||||
}
|
||||
|
||||
void set_default_state();
|
||||
virtual qdGameObjectState *get_default_state();
|
||||
virtual const qdGameObjectState *get_default_state() const;
|
||||
|
||||
qdGameObjectState *get_inventory_state();
|
||||
qdGameObjectState *get_mouse_state();
|
||||
qdGameObjectState *get_mouse_hover_state();
|
||||
|
||||
bool update_screen_pos();
|
||||
|
||||
// Animation
|
||||
qdAnimation *get_animation() {
|
||||
return &_animation;
|
||||
}
|
||||
const qdAnimation *get_animation() const {
|
||||
return &_animation;
|
||||
}
|
||||
|
||||
void set_animation(qdAnimation *p, const qdAnimationInfo *inf = NULL);
|
||||
void set_animation_info(qdAnimationInfo *inf);
|
||||
Vect2s screen_size() const {
|
||||
return Vect2s(_animation.size_x(), _animation.size_y());
|
||||
}
|
||||
|
||||
void set_screen_rotation(float target_angle, float speed);
|
||||
float screen_rotation() const;
|
||||
|
||||
void set_screen_scale(const Vect2f &scale, const Vect2f &speed);
|
||||
const Vect2f &screen_scale() const;
|
||||
|
||||
bool has_screen_transform() const {
|
||||
return _current_transform();
|
||||
}
|
||||
|
||||
// Inventory
|
||||
int inventory_type() const {
|
||||
return _inventory_type;
|
||||
}
|
||||
void set_inventory_type(int tp) {
|
||||
_inventory_type = tp;
|
||||
}
|
||||
|
||||
// Logic
|
||||
bool hit(int x, int y) const;
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
void quant(float dt);
|
||||
//! Обработка окончания текущего состояния.
|
||||
bool handle_state_end();
|
||||
|
||||
// Redraw
|
||||
void redraw(int offs_x = 0, int offs_y = 0) const;
|
||||
bool need_redraw() const;
|
||||
|
||||
void post_redraw();
|
||||
void draw_shadow(int offs_x, int offs_y, uint32 color, int alpha) const;
|
||||
|
||||
bool get_debug_info(Common::String &buf) const;
|
||||
|
||||
void debug_redraw() const;
|
||||
void draw_contour(uint32 color) const;
|
||||
void draw_grid_zone(const Vect2s sz) const;
|
||||
|
||||
int mouse_cursor_ID() const;
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
bool load_resources();
|
||||
void free_resources();
|
||||
|
||||
//! Инициализация объекта, вызывается при старте и перезапуске игры.
|
||||
bool init();
|
||||
|
||||
bool is_visible() const;
|
||||
|
||||
const Vect2s &grid_size() const {
|
||||
return _grid_size;
|
||||
}
|
||||
|
||||
bool init_grid_zone();
|
||||
virtual bool toggle_grid_zone(bool make_walkable = false);
|
||||
bool save_grid_zone();
|
||||
bool restore_grid_zone();
|
||||
bool set_grid_zone_attributes(int attr) const;
|
||||
bool check_grid_zone_attributes(int attr) const;
|
||||
bool drop_grid_zone_attributes(int attr) const;
|
||||
bool set_grid_zone_attributes(const Vect2f &r, int attr) const;
|
||||
bool check_grid_zone_attributes(const Vect2f &r, int attr) const;
|
||||
bool drop_grid_zone_attributes(const Vect2f &r, int attr) const;
|
||||
|
||||
const char *inventory_name() const {
|
||||
return _inventory_name.c_str();
|
||||
}
|
||||
void set_inventory_name(const char *name) {
|
||||
if (name)
|
||||
_inventory_name = name;
|
||||
else
|
||||
_inventory_name.clear();
|
||||
}
|
||||
bool has_inventory_name() const {
|
||||
return !_inventory_name.empty();
|
||||
}
|
||||
|
||||
const grScreenRegion last_screen_region() const {
|
||||
return _last_screen_region;
|
||||
}
|
||||
virtual grScreenRegion screen_region() const;
|
||||
|
||||
int inventory_cell_index() const {
|
||||
return _inventory_cell_index;
|
||||
}
|
||||
void set_inventory_cell_index(int idx) {
|
||||
_inventory_cell_index = idx;
|
||||
}
|
||||
|
||||
int last_chg_time() const {
|
||||
return _last_chg_time;
|
||||
}
|
||||
void set_last_chg_time(int time) {
|
||||
_last_chg_time = time;
|
||||
}
|
||||
int idle_time() const;
|
||||
|
||||
int shadow_color() const;
|
||||
int shadow_alpha() const;
|
||||
void set_shadow(uint32 color, int alpha) {
|
||||
_shadow_color = color;
|
||||
_shadow_alpha = alpha;
|
||||
}
|
||||
void clear_shadow() {
|
||||
set_shadow(0, QD_NO_SHADOW_ALPHA);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool load_script_body(const xml::tag *p);
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
void set_last_state(qdGameObjectState *p) {
|
||||
if (!p || !p->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_MOUSE_STATE | qdGameObjectState::QD_OBJ_STATE_FLAG_MOUSE_HOVER_STATE))
|
||||
_last_state = p;
|
||||
}
|
||||
|
||||
void set_last_inventory_state(qdGameObjectState *p) {
|
||||
if (!p || (p->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_INVENTORY) && !p->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_MOUSE_STATE | qdGameObjectState::QD_OBJ_STATE_FLAG_MOUSE_HOVER_STATE)))
|
||||
_last_inventory_state = p;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int _cur_state;
|
||||
qdGameObjectStateVector _states;
|
||||
|
||||
qdGameObjectState *_queued_state;
|
||||
qdGameObjectState *_last_inventory_state;
|
||||
|
||||
int _inventory_type;
|
||||
|
||||
qdAnimation _animation;
|
||||
|
||||
Vect3f _bound;
|
||||
float _radius;
|
||||
|
||||
Vect3f _default_r;
|
||||
|
||||
Vect3f _grid_r;
|
||||
Vect2s _grid_size;
|
||||
|
||||
Common::String _inventory_name;
|
||||
|
||||
qdScreenTransform _current_transform;
|
||||
qdScreenTransform _target_transform;
|
||||
qdScreenTransform _transform_speed;
|
||||
|
||||
qdScreenTransform _last_transform;
|
||||
|
||||
qdGameObjectState *_last_state;
|
||||
|
||||
//! Индекс ячейки инвентори, в которой лежал объект.
|
||||
int _inventory_cell_index;
|
||||
|
||||
const qdAnimationFrame *_last_frame;
|
||||
grScreenRegion _last_screen_region;
|
||||
float _last_screen_depth;
|
||||
|
||||
uint32 _lastShadowColor;
|
||||
int _lastShadowAlpha;
|
||||
|
||||
//! Последнее время изменения объекта
|
||||
int _last_chg_time;
|
||||
|
||||
//! Цвет затенения.
|
||||
uint32 _shadow_color;
|
||||
//! Прозрачность затенения, значения - [0, 255], если равно QD_NO_SHADOW_ALPHA, то персонаж не затеняется.
|
||||
int _shadow_alpha;
|
||||
|
||||
void clear_states();
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_OBJECT_ANIMATED_H
|
||||
293
engines/qdengine/qdcore/qd_game_object_mouse.cpp
Normal file
293
engines/qdengine/qdcore/qd_game_object_mouse.cpp
Normal file
@@ -0,0 +1,293 @@
|
||||
/* 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/qdcore/qd_rnd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_game_object_mouse.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdGameObjectMouse::qdGameObjectMouse() : _object(NULL),
|
||||
_object_screen_region(grScreenRegion_EMPTY) {
|
||||
set_flag(QD_OBJ_SCREEN_COORDS_FLAG);
|
||||
set_name("\xcc\xfb\xf8\xfc"); // "Мышь" -- mouse
|
||||
|
||||
_screen_pos_offset = _screen_pos_offset_delta = Vect2f(0, 0);
|
||||
|
||||
for (int i = 0; i < MAX_CURSOR_ID; i++)
|
||||
_default_cursors[i] = 0;
|
||||
}
|
||||
|
||||
qdGameObjectMouse::qdGameObjectMouse(const qdGameObjectMouse &obj) : qdGameObjectAnimated(obj),
|
||||
_object(NULL),
|
||||
_object_screen_region(grScreenRegion_EMPTY) {
|
||||
set_flag(QD_OBJ_SCREEN_COORDS_FLAG);
|
||||
set_name("\xcc\xfb\xf8\xfc"); // "Мышь" -- mouse
|
||||
|
||||
for (int i = 0; i < MAX_CURSOR_ID; i++)
|
||||
_default_cursors[i] = 0;
|
||||
}
|
||||
|
||||
qdGameObjectMouse::~qdGameObjectMouse() {
|
||||
}
|
||||
|
||||
qdGameObjectMouse &qdGameObjectMouse::operator = (const qdGameObjectMouse &obj) {
|
||||
if (this == &obj) return *this;
|
||||
|
||||
*static_cast<qdGameObjectAnimated *>(this) = obj;
|
||||
|
||||
for (int i = 0; i < MAX_CURSOR_ID; i++)
|
||||
_default_cursors[i] = obj._default_cursors[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdGameObjectMouse::load_script_body(const xml::tag *p) {
|
||||
qdGameObjectAnimated::load_script_body(p);
|
||||
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_MOUSE_DEFAULT_CURSORS: {
|
||||
xml::tag_buffer buf(*it);
|
||||
for (int i = 0; i < MAX_CURSOR_ID; i++) buf > _default_cursors[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < max_state(); i++) {
|
||||
if (get_state(i)->state_type() == qdGameObjectState::STATE_STATIC) {
|
||||
static_cast<qdGameObjectStateStatic *>(get_state(i))->animation_info()->set_flag(QD_ANIMATION_FLAG_LOOP);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObjectMouse::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
return qdGameObjectAnimated::save_script_body(fh, indent);
|
||||
}
|
||||
|
||||
bool qdGameObjectMouse::load_script(const xml::tag *p) {
|
||||
return load_script_body(p);
|
||||
}
|
||||
|
||||
bool qdGameObjectMouse::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<mouse_object name=\"%s\"", qdscr_XML_string(name())));
|
||||
|
||||
fh.writeString(" default_cursors=\"");
|
||||
for (int i = 0; i < MAX_CURSOR_ID; i++) {
|
||||
if (i) fh.writeString(" ");
|
||||
fh.writeString(Common::String::format("%d", _default_cursors[i]));
|
||||
}
|
||||
|
||||
fh.writeString("\">\r\n");
|
||||
|
||||
save_script_body(fh, indent);
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</mouse_object>\r\n");
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool qdGameObjectMouse::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
debugC(3, kDebugSave, " qdGameObjectMouse::load_data before: %d", (int)fh.pos());
|
||||
if (!qdGameObjectAnimated::load_data(fh, save_version))
|
||||
return false;
|
||||
|
||||
int fl = fh.readSint32LE();
|
||||
|
||||
if (fl) {
|
||||
qdNamedObjectReference ref;
|
||||
if (!ref.load_data(fh, save_version))
|
||||
return false;
|
||||
|
||||
if (qdGameDispatcher * p = qdGameDispatcher::get_dispatcher())
|
||||
_object = static_cast<qdGameObjectAnimated * >(p->get_named_object(&ref));
|
||||
|
||||
if (!_object) return false;
|
||||
}
|
||||
|
||||
debugC(3, kDebugSave, " qdGameObjectMouse::load_data after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObjectMouse::save_data(Common::WriteStream &fh) const {
|
||||
debugC(3, kDebugSave, " qdGameObjectMouse::save_data before: %d", (int)fh.pos());
|
||||
|
||||
if (!qdGameObjectAnimated::save_data(fh))
|
||||
return false;
|
||||
|
||||
if (_object) {
|
||||
fh.writeUint32LE(1);
|
||||
qdNamedObjectReference ref(_object);
|
||||
if (!ref.save_data(fh)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
fh.writeUint32LE(0);
|
||||
}
|
||||
|
||||
debugC(3, kDebugSave, " qdGameObjectMouse::save_data after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdGameObjectMouse::redraw(int offs_x, int offs_y) const {
|
||||
debugC(2, kDebugGraphics, "qdGameObjectMouse::redraw([%d, %d]), name: '%s'", offs_x, offs_y, transCyrillic(name()));
|
||||
|
||||
if (_object && !qdInterfaceDispatcher::get_dispatcher()->is_active()) {
|
||||
update_object_position();
|
||||
const qdGameObjectState *p = _object-> get_cur_state();
|
||||
|
||||
if (p->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_STAY_IN_INVENTORY) || !p->has_mouse_cursor_ID())
|
||||
_object->redraw(offs_x, offs_y);
|
||||
|
||||
if (p->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_STAY_IN_INVENTORY) || p->has_mouse_cursor_ID())
|
||||
qdGameObjectAnimated::redraw(offs_x, offs_y);
|
||||
} else {
|
||||
qdGameObjectAnimated::redraw(offs_x, offs_y);
|
||||
}
|
||||
}
|
||||
|
||||
void qdGameObjectMouse::set_cursor(cursor_ID_t id) {
|
||||
debugC(2, kDebugGraphics, "qdGameObjectMouse::set_cursor(%d)", id);
|
||||
if (cur_state() != _default_cursors[id])
|
||||
set_state(_default_cursors[id]);
|
||||
}
|
||||
|
||||
void qdGameObjectMouse::take_object(qdGameObjectAnimated *p) {
|
||||
if (_object) {
|
||||
if (_object->get_cur_state() && _object->get_cur_state()->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_MOUSE_STATE)) {
|
||||
if (qdGameObjectState * sp = _object->get_inventory_state())
|
||||
_object->set_state(sp);
|
||||
}
|
||||
|
||||
// object_->drop_flag(QD_OBJ_IS_IN_INVENTORY_FLAG);
|
||||
}
|
||||
|
||||
_object = p;
|
||||
|
||||
if (_object) {
|
||||
_object->set_flag(QD_OBJ_IS_IN_INVENTORY_FLAG);
|
||||
if (qdGameObjectState * sp = _object->get_mouse_state()) {
|
||||
if (_object->get_cur_state() != sp) {
|
||||
qdGameObjectState *cur_st = _object->get_cur_state();
|
||||
if (cur_st && cur_st->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_MOUSE_HOVER_STATE))
|
||||
cur_st = cur_st->prev_state();
|
||||
|
||||
sp->set_prev_state(cur_st);
|
||||
_object->set_state(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qdGameObjectMouse::update_object_position() const {
|
||||
if (_object) {
|
||||
if (_object-> get_cur_state()->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_STAY_IN_INVENTORY)) {
|
||||
if (const qdGameDispatcher * dp = static_cast<const qdGameDispatcher * >(owner())) {
|
||||
Vect2s pos = dp->cur_inventory()->cell_position(_object->inventory_cell_index());
|
||||
_object->set_pos(Vect3f(pos.x, pos.y, 0));
|
||||
}
|
||||
} else
|
||||
_object->set_pos(R());
|
||||
|
||||
_object->update_screen_pos();
|
||||
}
|
||||
}
|
||||
|
||||
void qdGameObjectMouse::pre_redraw() {
|
||||
qdGameDispatcher *dp = static_cast<qdGameDispatcher *>(owner());
|
||||
if (!dp) return;
|
||||
|
||||
update_object_position();
|
||||
|
||||
if (!dp->need_full_redraw()) {
|
||||
if (_object && !qdInterfaceDispatcher::get_dispatcher()->is_active()) {
|
||||
if (_object->need_redraw()) {
|
||||
dp->add_redraw_region(_object->last_screen_region());
|
||||
dp->add_redraw_region(_object->screen_region());
|
||||
}
|
||||
} else
|
||||
dp->add_redraw_region(_object_screen_region);
|
||||
|
||||
dp->add_redraw_region(last_screen_region());
|
||||
dp->add_redraw_region(screen_region());
|
||||
}
|
||||
}
|
||||
|
||||
void qdGameObjectMouse::post_redraw() {
|
||||
if (_object && !qdInterfaceDispatcher::get_dispatcher()->is_active()) {
|
||||
_object->post_redraw();
|
||||
_object_screen_region = _object->last_screen_region();
|
||||
} else
|
||||
_object_screen_region = grScreenRegion_EMPTY;
|
||||
|
||||
qdGameObjectAnimated::post_redraw();
|
||||
}
|
||||
|
||||
void qdGameObjectMouse::quant(float dt) {
|
||||
qdGameObjectAnimated::quant(dt);
|
||||
|
||||
if (_object)
|
||||
_object->quant(dt);
|
||||
|
||||
if (const qdGameObjectState * p = get_cur_state()) {
|
||||
if (p->rnd_move_radius() > FLT_EPS) {
|
||||
if (_screen_pos_offset.norm2() >= sqr(p->rnd_move_radius()) || (_screen_pos_offset_delta.x <= FLT_EPS && _screen_pos_offset_delta.y <= FLT_EPS)) {
|
||||
float angle = qd_fabs_rnd(M_PI * 2.0f);
|
||||
|
||||
Vect2f r(p->rnd_move_radius() * cos(angle), p->rnd_move_radius() * sin(angle));
|
||||
_screen_pos_offset_delta = r - _screen_pos_offset;
|
||||
_screen_pos_offset_delta.normalize(p->rnd_move_speed());
|
||||
}
|
||||
|
||||
_screen_pos_offset.x += _screen_pos_offset_delta.x * dt;
|
||||
_screen_pos_offset.y += _screen_pos_offset_delta.y * dt;
|
||||
} else
|
||||
_screen_pos_offset = _screen_pos_offset_delta = Vect2f(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool qdGameObjectMouse::update_screen_pos() {
|
||||
if (qdGameObjectAnimated::update_screen_pos()) {
|
||||
set_screen_R(get_screen_R() + _screen_pos_offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
127
engines/qdengine/qdcore/qd_game_object_mouse.h
Normal file
127
engines/qdengine/qdcore/qd_game_object_mouse.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_OBJECT_MOUSE_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_OBJECT_MOUSE_H
|
||||
|
||||
#include "qdengine/qdcore/qd_game_object_animated.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Mouse
|
||||
class qdGameObjectMouse : public qdGameObjectAnimated {
|
||||
public:
|
||||
qdGameObjectMouse();
|
||||
qdGameObjectMouse(const qdGameObjectMouse &obj);
|
||||
~qdGameObjectMouse();
|
||||
|
||||
qdGameObjectMouse &operator = (const qdGameObjectMouse &obj);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_MOUSE_OBJ;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
void take_object(qdGameObjectAnimated *p);
|
||||
qdGameObjectAnimated *object() {
|
||||
return _object;
|
||||
}
|
||||
|
||||
//! Идентификаторы для курсоров по-умолчанию.
|
||||
enum cursor_ID_t {
|
||||
//! общий курсор по-умолчанию
|
||||
DEFAULT_CURSOR,
|
||||
//! курсор для анимированных объектов
|
||||
OBJECT_CURSOR,
|
||||
//! курсор для зон на сетке
|
||||
ZONE_CURSOR,
|
||||
//! курсор для main menu
|
||||
MAIN_MENU_CURSOR,
|
||||
//! курсор для внутриигрового интерфейса
|
||||
INGAME_INTERFACE_CURSOR,
|
||||
//! курсор для объектов в инвентори
|
||||
INVENTORY_OBJECT_CURSOR,
|
||||
|
||||
MAX_CURSOR_ID
|
||||
};
|
||||
|
||||
//! Установка курсора по-умолчанию.
|
||||
/**
|
||||
Номер состояния отсчитывается с нуля.
|
||||
*/
|
||||
void set_default_cursor(cursor_ID_t id, int state_index) {
|
||||
_default_cursors[id] = state_index;
|
||||
}
|
||||
//! Возвращает курсор по-умолчанию.
|
||||
int default_cursor(cursor_ID_t id) const {
|
||||
return _default_cursors[id];
|
||||
}
|
||||
|
||||
void set_cursor(cursor_ID_t id);
|
||||
void set_cursor_state(int state_idx) {
|
||||
if (cur_state() != state_idx) set_state(state_idx);
|
||||
}
|
||||
|
||||
void pre_redraw();
|
||||
void redraw(int offs_x = 0, int offs_y = 0) const;
|
||||
void post_redraw();
|
||||
|
||||
void quant(float dt);
|
||||
|
||||
bool update_screen_pos();
|
||||
|
||||
const Vect2f &screen_pos_offset() const {
|
||||
return _screen_pos_offset;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool load_script_body(const xml::tag *p);
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
private:
|
||||
|
||||
//! Объект, который прицеплен к курсору.
|
||||
qdGameObjectAnimated *_object;
|
||||
|
||||
//! Номера состояний, соответствующие курсорам по-умолчанию.
|
||||
int _default_cursors[MAX_CURSOR_ID];
|
||||
|
||||
grScreenRegion _object_screen_region;
|
||||
|
||||
Vect2f _screen_pos_offset;
|
||||
Vect2f _screen_pos_offset_delta;
|
||||
|
||||
void update_object_position() const;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_OBJECT_MOUSE_H
|
||||
2835
engines/qdengine/qdcore/qd_game_object_moving.cpp
Normal file
2835
engines/qdengine/qdcore/qd_game_object_moving.cpp
Normal file
File diff suppressed because it is too large
Load Diff
500
engines/qdengine/qdcore/qd_game_object_moving.h
Normal file
500
engines/qdengine/qdcore/qd_game_object_moving.h
Normal file
@@ -0,0 +1,500 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_OBJECT_MOVING_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_OBJECT_MOVING_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_game_object_animated.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdInterfaceButton;
|
||||
|
||||
const int QD_MOVING_OBJ_PATH_LENGTH = 200;
|
||||
|
||||
//! Персонаж.
|
||||
class qdGameObjectMoving : public qdGameObjectAnimated {
|
||||
public:
|
||||
qdGameObjectMoving();
|
||||
qdGameObjectMoving(const qdGameObjectMoving &obj);
|
||||
~qdGameObjectMoving();
|
||||
|
||||
qdGameObjectMoving &operator = (const qdGameObjectMoving &obj);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_MOVING_OBJ;
|
||||
}
|
||||
|
||||
enum movement_mode_t {
|
||||
MOVEMENT_MODE_STOP,
|
||||
MOVEMENT_MODE_TURN,
|
||||
MOVEMENT_MODE_START,
|
||||
MOVEMENT_MODE_MOVE,
|
||||
MOVEMENT_MODE_END,
|
||||
MOVEMENT_MODE_NONE_EARLY
|
||||
};
|
||||
|
||||
//! режимы управления персонажем
|
||||
enum control_type_t {
|
||||
//! можно указывать мышью точки куда идти
|
||||
CONTROL_MOUSE = 0x01,
|
||||
//! можно рулить с клавиатуры
|
||||
CONTROL_KEYBOARD = 0x02,
|
||||
//! можно толкать другим персонажем
|
||||
CONTROL_COLLISION = 0x04,
|
||||
//! автоматически избегать столкновений с другими персонажами
|
||||
CONTROL_AVOID_COLLISION = 0x10,
|
||||
//! автоматически двигаться
|
||||
CONTROL_AUTO_MOVE = 0x20,
|
||||
//! сгонять с пути других персонажей, если блокируют дорогу
|
||||
CONTROL_CLEAR_PATH = 0x40,
|
||||
//! Персонаж стремится не отходить от активного персонажа более чем на некоторый радиус
|
||||
CONTROL_FOLLOW_ACTIVE_PERSONAGE = 0x80,
|
||||
//! Персонаж пытается двигаться в ту же сторону, что и активный
|
||||
CONTROL_REPEAT_ACTIVE_PERSONAGE_MOVEMENT = 0x100,
|
||||
//! Жесткая привязка персонажа к заданному персонажу
|
||||
CONTROL_ATTACHMENT_WITH_DIR_REL = 0x200,
|
||||
/** Жесткая привязка персонажа к заданному персонажу _без учета направления движения_
|
||||
персонажа к которому привязываемся */
|
||||
CONTROL_ATTACHMENT_WITHOUT_DIR_REL = 0x400,
|
||||
// Подходить к точке привязки относительно активного
|
||||
CONTROL_ATTACHMENT_TO_ACTIVE_WITH_MOVING = 0x800,
|
||||
//! Режим реагирования на клик активному персонажу (персонаж бежит туда же)
|
||||
CONTROL_ACTIVE_CLICK_REACTING = 0x1000,
|
||||
//! Режим с анимацией поворота
|
||||
CONTROL_ANIMATED_ROTATION = 0x2000
|
||||
};
|
||||
|
||||
//! флаги следования
|
||||
enum follow_condition_t {
|
||||
//! Для персонажа нужно просчитать путь следования
|
||||
FOLLOW_UPDATE_PATH = 0x01,
|
||||
//! Все ок
|
||||
FOLLOW_DONE = 0x02,
|
||||
//! Персонаж ждет, когда можно будет возобновить попытку следования
|
||||
FOLLOW_WAIT = 0x03,
|
||||
//! Персонаж ждет остановки всех следующих персонажей, чтобы продолжить следование
|
||||
FOLLOW_FULL_STOP_WAIT = 0x04,
|
||||
//! Персонаж следует
|
||||
FOLLOW_MOVING = 0x05
|
||||
};
|
||||
|
||||
bool has_control_type(control_type_t type) const {
|
||||
if (_control_types & type) return true;
|
||||
return false;
|
||||
}
|
||||
void add_control_type(control_type_t type) {
|
||||
_control_types |= type;
|
||||
}
|
||||
void remove_control_type(control_type_t type) {
|
||||
_control_types &= ~type;
|
||||
}
|
||||
|
||||
int get_control_types() { return _control_types; }
|
||||
int get_movement_mode() { return _movement_mode; }
|
||||
|
||||
qdGameObjectStateWalk::movement_type_t movement_type() const;
|
||||
|
||||
bool is_walkable(const Vect3f &pos) const;
|
||||
bool is_walkable(const Vect2s &pos) const;
|
||||
|
||||
const Vect3f &bound(bool perspective_correction = true) const;
|
||||
Vect3f calc_bound_in_pos(Vect3f pos, bool perspective_correction = true);
|
||||
bool calc_walk_grid(Vect2s ¢er, Vect2s &size) const;
|
||||
//! Возвращает текущее положение сетки движения, и положение сетки через dt
|
||||
bool calc_cur_and_future_walk_grid(float dt, Vect2s &cen_cur, Vect2s &size_cur,
|
||||
Vect2s &cen_next, Vect2s &size_next);
|
||||
float radius() const;
|
||||
|
||||
bool adjust_z();
|
||||
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
|
||||
float direction_angle() const {
|
||||
return _direction_angle;
|
||||
}
|
||||
float calc_direction_angle(const Vect3f &target) const;
|
||||
float animate_rotation(float dt);
|
||||
float rotation_angle() const {
|
||||
return _rotation_angle;
|
||||
}
|
||||
|
||||
float rotation_angle_per_quant() const {
|
||||
return _rotation_angle_per_quant;
|
||||
}
|
||||
void set_rotation_angle_per_quant(float ang) {
|
||||
_rotation_angle_per_quant = ang;
|
||||
}
|
||||
|
||||
bool set_direction(float angle);
|
||||
int get_direction(float angle) const;
|
||||
|
||||
float default_direction_angle() const {
|
||||
return _default_direction_angle;
|
||||
}
|
||||
void set_default_direction(float ang) {
|
||||
_default_direction_angle = ang;
|
||||
}
|
||||
|
||||
void set_state(int st);
|
||||
void set_state(qdGameObjectState *p);
|
||||
|
||||
void set_last_walk_state(qdGameObjectState *p) {
|
||||
_last_walk_state = p;
|
||||
}
|
||||
qdGameObjectState *last_walk_state() {
|
||||
return _last_walk_state;
|
||||
}
|
||||
|
||||
qdGameObjectState *get_default_state();
|
||||
const qdGameObjectState *get_default_state() const;
|
||||
|
||||
void merge(qdGameObjectMoving *p);
|
||||
void split(qdGameObjectMoving *p);
|
||||
|
||||
void set_button(qdInterfaceButton *p) {
|
||||
_button = p;
|
||||
}
|
||||
qdInterfaceButton *button() const {
|
||||
return _button;
|
||||
}
|
||||
|
||||
bool move(const Vect3f &target, bool lock_target = false);
|
||||
bool move(const Vect3f &target, float angle, bool lock_target = false);
|
||||
|
||||
bool move2position(const Vect3f target);
|
||||
|
||||
bool skip_movement();
|
||||
bool stop_movement();
|
||||
|
||||
bool is_moving() const {
|
||||
return check_flag(QD_OBJ_MOVING_FLAG);
|
||||
}
|
||||
|
||||
bool can_move() const;
|
||||
|
||||
bool is_in_position(const Vect3f pos) const;
|
||||
bool is_in_position(const Vect3f pos, float angle) const;
|
||||
|
||||
bool is_moving2position(const Vect3f pos) const;
|
||||
bool is_moving2position(const Vect3f pos, float angle) const;
|
||||
|
||||
//! Текущая точка, к которой движется персонаж.
|
||||
Vect3f local_target_position() const {
|
||||
if (is_moving())
|
||||
return _target_r;
|
||||
else
|
||||
return R();
|
||||
}
|
||||
|
||||
//! Точка, к которой движется персонаж.
|
||||
Vect3f target_position() const {
|
||||
if (is_moving())
|
||||
return ((_path_length) ? _path[_path_length] : _target_r);
|
||||
else
|
||||
return R();
|
||||
}
|
||||
|
||||
void set_scale(float sc) {
|
||||
_scale = sc;
|
||||
}
|
||||
float scale() const {
|
||||
return _scale;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
bool load_resources();
|
||||
|
||||
//! Возвращает true, если объект в данный момент может менять состояние.
|
||||
bool can_change_state(const qdGameObjectState *state = NULL) const;
|
||||
|
||||
//! Инициализация объекта, вызывается при старте и перезапуске игры.
|
||||
bool init();
|
||||
|
||||
Vect3f get_future_r(float dt, bool &end_movement, bool real_moving = false);
|
||||
void quant(float dt);
|
||||
|
||||
void redraw(int offs_x = 0, int offs_y = 0) const;
|
||||
void drawDebugPath() const;
|
||||
void debug_redraw() const;
|
||||
void draw_contour(uint32 color) const;
|
||||
void draw_shadow(int offs_x, int offs_y, uint32 color, int alpha) const;
|
||||
|
||||
bool get_debug_info(Common::String &buf) const;
|
||||
|
||||
grScreenRegion screen_region() const;
|
||||
|
||||
bool hit(int x, int y) const;
|
||||
|
||||
bool update_screen_pos();
|
||||
Vect2s screen_size() const;
|
||||
|
||||
void disable_control() {
|
||||
_disable_control = true;
|
||||
}
|
||||
void enable_control() {
|
||||
_disable_control = false;
|
||||
}
|
||||
bool is_control_disabled() const {
|
||||
return _disable_control;
|
||||
}
|
||||
|
||||
bool keyboard_move();
|
||||
|
||||
bool set_movement_impulse(float dir_angle);
|
||||
|
||||
float collision_radius() const {
|
||||
if (_collision_radius > FLT_EPS)
|
||||
return _collision_radius;
|
||||
else
|
||||
return radius();
|
||||
}
|
||||
|
||||
void set_collision_radius(float r) {
|
||||
_collision_radius = r;
|
||||
}
|
||||
|
||||
float collision_delay() const {
|
||||
return _collision_delay;
|
||||
}
|
||||
void set_collision_delay(float r) {
|
||||
_collision_delay = r;
|
||||
}
|
||||
|
||||
float collision_path() const {
|
||||
return _collision_path;
|
||||
}
|
||||
void set_collision_path(float path) {
|
||||
_collision_path = path;
|
||||
}
|
||||
|
||||
float follow_min_radius() const {
|
||||
return _follow_min_radius;
|
||||
}
|
||||
void set_follow_min_radius(float fmr) {
|
||||
_follow_min_radius = fmr;
|
||||
}
|
||||
|
||||
float follow_max_radius() const {
|
||||
return _follow_max_radius;
|
||||
}
|
||||
void set_follow_max_radius(float fmr) {
|
||||
_follow_max_radius = fmr;
|
||||
}
|
||||
|
||||
int follow_condition() const {
|
||||
return _follow_condition;
|
||||
};
|
||||
void set_follow_condition(int cond) {
|
||||
_follow_condition = cond;
|
||||
};
|
||||
|
||||
const Std::vector<const qdGameObjectMoving *> &const_ref_circuit_objs() const {
|
||||
return _circuit_objs;
|
||||
};
|
||||
Std::vector<const qdGameObjectMoving *> &ref_circuit_objs() {
|
||||
return _circuit_objs;
|
||||
};
|
||||
|
||||
// Для CONTROL_ATTACHMENT
|
||||
const qdGameObjectMoving *attacher() const {
|
||||
return _attacher;
|
||||
}
|
||||
void set_attacher(const qdGameObjectMoving *mov_obj);
|
||||
const qdNamedObjectReference &attacher_ref() const {
|
||||
return _attacher_ref;
|
||||
}
|
||||
Vect2s attach_shift() const {
|
||||
return _attach_shift;
|
||||
}
|
||||
void set_attach_shift(Vect2s shift) {
|
||||
_attach_shift = shift;
|
||||
}
|
||||
|
||||
Vect3f last_move_order() const {
|
||||
return _last_move_order;
|
||||
};
|
||||
void set_last_move_order(const Vect3f &pnt) {
|
||||
_last_move_order = pnt;
|
||||
};
|
||||
|
||||
bool avoid_collision(const qdGameObjectMoving *p);
|
||||
bool move_from_personage_path();
|
||||
|
||||
bool toggle_grid_zone(bool make_walkable = false);
|
||||
void toggle_selection(bool state) {
|
||||
_is_selected = state;
|
||||
}
|
||||
|
||||
void set_path_attributes(int attr) const;
|
||||
void clear_path_attributes(int attr) const;
|
||||
|
||||
static Common::String control2str(int control, bool truncate = false);
|
||||
static Common::String movement2str(int movement, bool truncate = false);
|
||||
|
||||
protected:
|
||||
|
||||
bool load_script_body(const xml::tag *p);
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
private:
|
||||
|
||||
//! Дистанция, на котрой персонаж взаимодействует с другими персонажами.
|
||||
/**
|
||||
Если не установлен, высчитывается по баунду персонажа.
|
||||
*/
|
||||
float _collision_radius;
|
||||
//! Задержка от момента столкновения с другим персонажем до начала движения.
|
||||
float _collision_delay;
|
||||
//! Путь, который персонаж проходит после того, как другой персонаж его толкает.
|
||||
float _collision_path;
|
||||
|
||||
//! Минимальный и максимальный радиусы следования
|
||||
float _follow_min_radius;
|
||||
float _follow_max_radius;
|
||||
|
||||
//! Состояние следования
|
||||
int _follow_condition;
|
||||
//! Объекты, который текущий объект пытается обойти
|
||||
Std::vector<const qdGameObjectMoving *> _circuit_objs;
|
||||
|
||||
//! Для CONTROL_HARD_ATTACHMENT
|
||||
const qdGameObjectMoving *_attacher; // Объект, который присоединяет к себе наш объект
|
||||
qdNamedObjectReference _attacher_ref;
|
||||
Vect2s _attach_shift; // Позиция нашего объекта - смещение от центра attacher'а
|
||||
|
||||
//! Режимы управления персонажем - комбинация значений control_type_t.
|
||||
int _control_types;
|
||||
|
||||
bool _disable_control;
|
||||
|
||||
bool _impulse_movement_mode;
|
||||
float _impulse_timer;
|
||||
float _impulse_start_timer;
|
||||
float _impulse_direction;
|
||||
|
||||
movement_mode_t _movement_mode;
|
||||
float _movement_mode_time;
|
||||
float _movement_mode_time_current;
|
||||
|
||||
float _scale;
|
||||
float _direction_angle;
|
||||
float _rotation_angle;
|
||||
float _rotation_angle_per_quant;
|
||||
|
||||
float _default_direction_angle;
|
||||
|
||||
float _speed_delta;
|
||||
|
||||
Vect3f _last_move_order; //! Точка, заданная последним приказом на движение
|
||||
|
||||
Vect3f _target_r;
|
||||
int _path_length;
|
||||
int _cur_path_index;
|
||||
float _target_angle;
|
||||
Vect3f _path[QD_MOVING_OBJ_PATH_LENGTH];
|
||||
|
||||
Vect2s _walk_grid_size;
|
||||
qdGameObjectState *_last_walk_state;
|
||||
|
||||
bool _ignore_personages;
|
||||
bool _is_selected;
|
||||
|
||||
mutable qdInterfaceButton *_button;
|
||||
|
||||
Vect2s get_nearest_walkable_point(const Vect2s &target) const;
|
||||
//! Возвращает доступную точку, предшествующую последней до target пустОте
|
||||
Vect2s get_pre_last_walkable_point(const Vect2s &target) const;
|
||||
bool is_path_walkable(int x1, int y1, int x2, int y2) const;
|
||||
bool is_path_walkable(const Vect2i &src, const Vect2i &trg) const {
|
||||
return is_path_walkable(src.x, src.y, trg.x, trg.y);
|
||||
}
|
||||
bool is_path_walkable(const Vect3f &src, const Vect3f &trg) const;
|
||||
bool enough_far_target(const Vect3f &dest) const;
|
||||
|
||||
void toggle_ignore_personages(bool state) {
|
||||
_ignore_personages = state;
|
||||
}
|
||||
|
||||
bool find_path(const Vect3f target, bool lock_target = false);
|
||||
|
||||
void optimize_path(Std::vector<Vect2i> &path) const;
|
||||
|
||||
void optimize_path_four_dirs(Std::list<Vect2i> &path) const;
|
||||
// Спрямление четырех точек для пути с восемью направлениями
|
||||
bool four_pts_eight_dir_straight(Std::list<Vect2i> &path,
|
||||
Std::list<Vect2i>::reverse_iterator cur) const;
|
||||
bool four_pts_eight_dir_straight_old(Std::list<Vect2i> path, Std::list<Vect2i>::iterator cur) const;
|
||||
// Удаляем точки, лежащие внутри прямых отрезков пути
|
||||
bool del_coll_pts(Std::list<Vect2i> &path) const;
|
||||
void optimize_path_eight_dirs(Std::list<Vect2i> &path) const;
|
||||
void optimize_path_smooth(Std::list<Vect2i> &path) const;
|
||||
void finalize_path(const Vect3f &from, const Vect3f &to, const Std::vector<Vect2i> &path, Std::vector<Vect3f> &out_path) const;
|
||||
|
||||
bool adjust_position(Vect3f &pos) const;
|
||||
bool adjust_direction_angle(float &angle);
|
||||
|
||||
void change_direction_angle(float angle);
|
||||
|
||||
bool is_direction_allowed(float angle) const;
|
||||
int allowed_directions_count() const;
|
||||
|
||||
float calc_scale() const {
|
||||
return calc_scale(R());
|
||||
}
|
||||
float calc_scale(const Vect3f &r) const;
|
||||
|
||||
bool set_walk_animation();
|
||||
bool movement_impulse();
|
||||
|
||||
float speed();
|
||||
bool get_speed_parameters(float &speed, float &speed_max, float &acceleration);
|
||||
|
||||
const qdGameObjectStateWalk *current_walk_state() const;
|
||||
|
||||
bool adjust_position(Vect3f &pos, float dir_angle) const;
|
||||
|
||||
Vect2s walk_grid_size(const Vect3f &r) const;
|
||||
Vect2s walk_grid_size(const Vect2s &r) const;
|
||||
Vect2s walk_grid_size() const {
|
||||
return walk_grid_size(R());
|
||||
}
|
||||
|
||||
bool start_auto_move();
|
||||
|
||||
//! Проверяет, является ли корректной последующая позиция при движении персонажа
|
||||
bool future_pos_correct(float dt);
|
||||
|
||||
/// Проверка, закончилось ли движение.
|
||||
bool is_movement_finished() const;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_OBJECT_MOVING_H
|
||||
1570
engines/qdengine/qdcore/qd_game_object_state.cpp
Normal file
1570
engines/qdengine/qdcore/qd_game_object_state.cpp
Normal file
File diff suppressed because it is too large
Load Diff
936
engines/qdengine/qdcore/qd_game_object_state.h
Normal file
936
engines/qdengine/qdcore/qd_game_object_state.h
Normal file
@@ -0,0 +1,936 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_OBJECT_STATE_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_OBJECT_STATE_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_contour.h"
|
||||
#include "qdengine/qdcore/qd_sound_info.h"
|
||||
#include "qdengine/qdcore/qd_animation_info.h"
|
||||
#include "qdengine/qdcore/qd_animation_set_info.h"
|
||||
#include "qdengine/qdcore/qd_conditional_object.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
#include "qdengine/qdcore/qd_coords_animation.h"
|
||||
#include "qdengine/qdcore/qd_camera_mode.h"
|
||||
#include "qdengine/qdcore/qd_sound_handle.h"
|
||||
#include "qdengine/qdcore/qd_screen_text.h"
|
||||
#include "qdengine/qdcore/qd_grid_zone.h"
|
||||
#include "qdengine/system/sound/snd_sound.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdScreenTransform {
|
||||
public:
|
||||
qdScreenTransform(float angle = 0.f, const Vect2f &scale = Vect2f(1.f, 1.f)) : _angle(angle), _scale(scale) { }
|
||||
|
||||
bool operator == (const qdScreenTransform &trans) const;
|
||||
bool operator != (const qdScreenTransform &trans) const {
|
||||
return !(*this == trans);
|
||||
}
|
||||
bool operator()() const {
|
||||
return _angle != 0.f || _scale.x != 1.f || _scale.y != 1.f;
|
||||
}
|
||||
|
||||
qdScreenTransform operator *(float value) const {
|
||||
return qdScreenTransform(_angle *value, _scale *value);
|
||||
}
|
||||
|
||||
qdScreenTransform &operator += (const qdScreenTransform &trans) {
|
||||
_angle += trans._angle;
|
||||
_scale += trans._scale;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool change(float dt, const qdScreenTransform &target_trans, const qdScreenTransform &speed);
|
||||
|
||||
float angle() const {
|
||||
return _angle;
|
||||
}
|
||||
void set_angle(float angle) {
|
||||
_angle = angle;
|
||||
}
|
||||
|
||||
const Vect2f &scale() const {
|
||||
return _scale;
|
||||
}
|
||||
void set_scale(const Vect2f &scale) {
|
||||
_scale = scale;
|
||||
}
|
||||
bool has_scale() const {
|
||||
return fabs(_scale.x - 1.f) > FLT_EPS || fabs(_scale.y - 1.f) > FLT_EPS;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
float _angle;
|
||||
Vect2f _scale;
|
||||
|
||||
};
|
||||
|
||||
//! Состояние динамического объекта - базовый класс.
|
||||
class qdGameObjectState : public qdConditionalObject {
|
||||
public:
|
||||
//! Флаги состояния.
|
||||
enum {
|
||||
//! Объект спрятан.
|
||||
QD_OBJ_STATE_FLAG_HIDDEN = 0x01,
|
||||
//! The state is not in triggers. Deprecated, replaced with is_in_triggers()
|
||||
QD_OBJ_STATE_FLAG_NOT_IN_TRIGGERS = 0x02,
|
||||
//! Восстанавливать предыдущее состояние по окончании состояния.
|
||||
QD_OBJ_STATE_FLAG_RESTORE_PREV_STATE = 0x04,
|
||||
//! Прятать объект по окончании состояния.
|
||||
QD_OBJ_STATE_FLAG_HIDE_OBJECT = 0x08,
|
||||
//! Объект, которому принадлежит состояние - глобальный.
|
||||
QD_OBJ_STATE_FLAG_GLOBAL_OWNER = 0x10,
|
||||
//! Состояние для инвентори.
|
||||
QD_OBJ_STATE_FLAG_INVENTORY = 0x20,
|
||||
//! Положить объект в инвентори по окончании состояния.
|
||||
QD_OBJ_STATE_FLAG_MOVE_TO_INVENTORY = 0x40,
|
||||
//! Положить в инвентори не удалось.
|
||||
QD_OBJ_STATE_FLAG_MOVE_TO_INVENTORY_FAILED = 0x80,
|
||||
//! У состояния задан баунд.
|
||||
QD_OBJ_STATE_FLAG_HAS_BOUND = 0x100,
|
||||
//! Активирована задержка перед включением состояния.
|
||||
QD_OBJ_STATE_FLAG_ACTIVATION_TIMER = 0x200,
|
||||
//! Задержка перед включением состояния окончилась.
|
||||
QD_OBJ_STATE_FLAG_ACTIVATION_TIMER_END = 0x400,
|
||||
//! Заданный для состояния текст - вариант фразы для диалогов.
|
||||
/**
|
||||
Означает, что одно из условий активации состояния - клик мышью по
|
||||
соответствующему тексту на экране.
|
||||
*/
|
||||
QD_OBJ_STATE_FLAG_DIALOG_PHRASE = 0x800,
|
||||
//! Синхронизировать анимацию по звуку.
|
||||
/**
|
||||
Когда заканчивается звук, анимация останавливается.
|
||||
Работает только для qdGameObjectStateStatic без координатной анимации.
|
||||
*/
|
||||
QD_OBJ_STATE_FLAG_SOUND_SYNC = 0x1000,
|
||||
//! Разрешить прерывать состояние.
|
||||
/**
|
||||
Если флаг установлен, то состояние может быть прервано до
|
||||
окончания его работы (например для персонажа - кликом мыши).
|
||||
*/
|
||||
QD_OBJ_STATE_FLAG_ENABLE_INTERRUPT = 0x2000,
|
||||
//! Состояние уже было активировано.
|
||||
/**
|
||||
Показывает, что состояние уже было хотя бы один раз активировано.
|
||||
*/
|
||||
QD_OBJ_STATE_FLAG_WAS_ACTIVATED = 0x4000,
|
||||
//! Запретить прерывать подход к стартовой точке состояния.
|
||||
/**
|
||||
Имеет смысл только если для состояний с подходом к точке запуска
|
||||
(need_to_walk() == true).
|
||||
*/
|
||||
QD_OBJ_STATE_FLAG_DISABLE_WALK_INTERRUPT = 0x8000,
|
||||
//! Включать состояние, когда объект взят на мышь.
|
||||
QD_OBJ_STATE_FLAG_MOUSE_STATE = 0x10000,
|
||||
//! Включать состояние, когда мышь над объектом в инвентори.
|
||||
QD_OBJ_STATE_FLAG_MOUSE_HOVER_STATE = 0x20000,
|
||||
//! Не вытаскивать объект из инвентори, когда он взят на мышь.
|
||||
QD_OBJ_STATE_FLAG_STAY_IN_INVENTORY = 0x40000,
|
||||
/**
|
||||
Принудительно загружать ресурсы состояния в память при заходе на сцену,
|
||||
не выгружать их до выхода со сцены.
|
||||
*/
|
||||
QD_OBJ_STATE_FLAG_FORCED_LOAD = 0x80000,
|
||||
//! Состояние можно скиповать кликом мыши.
|
||||
QD_OBJ_STATE_FLAG_ENABLE_SKIP = 0x100000,
|
||||
//! При включении состояния класть объект на зону под мышью.
|
||||
QD_OBJ_STATE_FLAG_MOVE_TO_ZONE = 0x200000,
|
||||
//! При включении состояния класть объект в центр объекта под мышью.
|
||||
QD_OBJ_STATE_FLAG_MOVE_ON_OBJECT = 0x400000,
|
||||
//! По окончании работы состояния делать персонажа-владельца активным.
|
||||
QD_OBJ_STATE_FLAG_ACTIVATE_PERSONAGE = 0x800000,
|
||||
//! Автоматически загружать сэйв при активации состояния.
|
||||
QD_OBJ_STATE_FLAG_AUTO_LOAD = 0x1000000,
|
||||
//! Автоматически писать сэйв при активации состояния.
|
||||
QD_OBJ_STATE_FLAG_AUTO_SAVE = 0x2000000,
|
||||
QD_OBJ_STATE_FLAG_FADE_IN = 0x4000000,
|
||||
QD_OBJ_STATE_FLAG_FADE_OUT = 0x8000000,
|
||||
};
|
||||
|
||||
//! Тип состояния.
|
||||
enum StateType {
|
||||
//! Статическая анимация.
|
||||
STATE_STATIC,
|
||||
//! Походка.
|
||||
STATE_WALK,
|
||||
//! Маска на фоне.
|
||||
STATE_MASK
|
||||
};
|
||||
|
||||
enum {
|
||||
CURSOR_UNASSIGNED = -1
|
||||
};
|
||||
|
||||
qdGameObjectState(StateType tp);
|
||||
qdGameObjectState(const qdGameObjectState &st);
|
||||
virtual ~qdGameObjectState();
|
||||
|
||||
virtual qdGameObjectState &operator = (const qdGameObjectState &st);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_OBJ_STATE;
|
||||
}
|
||||
|
||||
//! Возвращает указатель на траекторию движения объекта для состояния.
|
||||
qdCoordsAnimation *coords_animation() {
|
||||
return &_coords_animation;
|
||||
}
|
||||
//! Возвращает указатель на траекторию движения объекта для состояния.
|
||||
const qdCoordsAnimation *coords_animation() const {
|
||||
return &_coords_animation;
|
||||
}
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
virtual bool load_script(const xml::tag *p) = 0;
|
||||
//! Запись данных в скрипт.
|
||||
virtual bool save_script(Common::WriteStream &fh, int indent = 0) const = 0;
|
||||
|
||||
//! Инициализация состояния, вызывается при старте и перезапуске игры.
|
||||
bool init();
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
//! Регистрация ресурсов состояния в диспетчере ресурсов.
|
||||
virtual bool register_resources();
|
||||
//! Отмена регистрации ресурсов состояния в диспетчере ресурсов.
|
||||
virtual bool unregister_resources();
|
||||
//! Загрузка ресурсов.
|
||||
virtual bool load_resources();
|
||||
//! Выгрузка ресурсов.
|
||||
virtual bool free_resources();
|
||||
|
||||
//! Возвращает true, если условия активации состояния выполняются.
|
||||
bool check_conditions();
|
||||
|
||||
//! Возвращет смещение центра объекта для состояния (в экранных координатах).
|
||||
const Vect2s ¢er_offset() const {
|
||||
return _center_offset;
|
||||
}
|
||||
//! Устанавливает смещение центра объекта для состояния (в экранных координатах).
|
||||
void set_center_offset(const Vect2s offs) {
|
||||
_center_offset = offs;
|
||||
}
|
||||
|
||||
//! Логический квант состояния.
|
||||
void quant(float dt);
|
||||
|
||||
//! Возвращает указатель на предыдущее состояние.
|
||||
qdGameObjectState *prev_state() {
|
||||
return _prev_state;
|
||||
}
|
||||
//! Устанавливает предыдущее состояние.
|
||||
void set_prev_state(qdGameObjectState *p) {
|
||||
_prev_state = p;
|
||||
}
|
||||
|
||||
//! Возвращает тип состояния.
|
||||
StateType state_type() const {
|
||||
return _state_type;
|
||||
}
|
||||
|
||||
//! Возвращает идентификатор мышиного курсора для состояния.
|
||||
int mouse_cursor_ID() const {
|
||||
return _mouse_cursor_id;
|
||||
}
|
||||
//! Устанавливает идентификатор мышиного курсора для состояния.
|
||||
/**
|
||||
Если должен использоваться курсор по-умолчанию -
|
||||
параметр должен быть равен CURSOR_UNASSIGNED.
|
||||
*/
|
||||
void set_mouse_cursor_ID(int id) {
|
||||
_mouse_cursor_id = id;
|
||||
}
|
||||
//! Возвращает true, если состоянию назначен особый мышиный курсор.
|
||||
bool has_mouse_cursor_ID() const {
|
||||
return _mouse_cursor_id != CURSOR_UNASSIGNED;
|
||||
}
|
||||
|
||||
//! Устанавливает имя звукового эффекта, привязанного к состоянию.
|
||||
const char *sound_name() const {
|
||||
return _sound_info.name();
|
||||
}
|
||||
//! Возвращает имя звукового эффекта, привязанного к состоянию.
|
||||
void set_sound_name(const char *p) {
|
||||
_sound_info.set_name(p);
|
||||
}
|
||||
//! Возвращает указатель на звуковой эффект, привязанный к состоянию.
|
||||
qdSound *sound() const;
|
||||
//! Возвращает true, если для состояния задан звук.
|
||||
bool has_sound() const {
|
||||
if (sound_name()) return true;
|
||||
else return false;
|
||||
}
|
||||
//! Возвращает хэндл звука.
|
||||
const qdSoundHandle *sound_handle() const {
|
||||
return &_sound_handle;
|
||||
}
|
||||
//! Запускает звук, position - стартовяя позиция, от 0.0 до 1.0.
|
||||
bool play_sound();
|
||||
//! Останавливает звук.
|
||||
bool stop_sound() const;
|
||||
//! Установка частоты звука.
|
||||
bool set_sound_frequency(float frequency_coeff) const;
|
||||
bool is_sound_finished() const;
|
||||
bool is_sound_playing() const;
|
||||
|
||||
//! Устанавливает флаг для звука.
|
||||
void set_sound_flag(int fl) {
|
||||
_sound_info.set_flag(fl);
|
||||
}
|
||||
//! Скидывает флаг для звука.
|
||||
void drop_sound_flag(int fl) {
|
||||
_sound_info.drop_flag(fl);
|
||||
}
|
||||
//! Возвращает true, если установлен флаг для звука.
|
||||
bool check_sound_flag(int fl) const {
|
||||
return _sound_info.check_flag(fl);
|
||||
}
|
||||
|
||||
//! Возвращает true, если состояние пустое.
|
||||
virtual bool is_state_empty() const;
|
||||
|
||||
//! Возвращает true, если в данный момент состояние включено.
|
||||
bool is_active() const;
|
||||
//! Возвращает true, если состояние стартовое.
|
||||
bool is_default() const;
|
||||
|
||||
//! Возвращает задержку (в секундах) перед активацией состояния.
|
||||
float activation_delay() const {
|
||||
return _activation_delay;
|
||||
}
|
||||
//! Устанавливает задержку (в секундах) перед активацией состояния.
|
||||
void set_activation_delay(float tm) {
|
||||
_activation_delay = tm;
|
||||
}
|
||||
//! Устанавливает таймер перед активацией состояния.
|
||||
void set_activation_timer() {
|
||||
_activation_timer = _activation_delay;
|
||||
}
|
||||
|
||||
//! Вызывается при активации состояния.
|
||||
void start() {
|
||||
_cur_time = 0.0f;
|
||||
_is_sound_started = false;
|
||||
}
|
||||
|
||||
//! Возвращает время в секундах, прошедшее с момента активации состояния.
|
||||
float cur_time() const {
|
||||
return _cur_time;
|
||||
}
|
||||
//! Возвращает длительность состояния в секундах.
|
||||
float work_time() const;
|
||||
//! Устанавливает длительность состояния в секундах.
|
||||
void set_work_time(float tm) {
|
||||
_work_time = tm;
|
||||
}
|
||||
|
||||
//! Возвращает true, если персонажу требуется подойти к точке включения состояния.
|
||||
bool need_to_walk() const {
|
||||
if (!_coords_animation.is_empty()
|
||||
&& _coords_animation.check_flag(QD_COORDS_ANM_OBJECT_START_FLAG))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual qdGameObjectState *clone() const = 0;
|
||||
|
||||
virtual float adjust_direction_angle(float angle) const {
|
||||
return angle;
|
||||
}
|
||||
|
||||
//! Возвращает координаты точки, в которой должно активироваться состояние.
|
||||
const Vect3f start_pos() const {
|
||||
if (!_coords_animation.is_empty()) {
|
||||
return _coords_animation.get_point(0)->dest_pos();
|
||||
} else
|
||||
return Vect3f(0, 0, 0);
|
||||
}
|
||||
//! Возвращает направление объекта в точке, в которой должно активироваться состояние.
|
||||
float start_direction_angle() const {
|
||||
if (!_coords_animation.is_empty()) {
|
||||
return _coords_animation.get_point(0)->direction_angle();
|
||||
} else
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
//! Возвращает количество ссылок на состояние.
|
||||
int reference_count() const {
|
||||
return _reference_count;
|
||||
}
|
||||
//! Инкремент количества ссылок на состояние.
|
||||
void inc_reference_count() {
|
||||
_reference_count++;
|
||||
}
|
||||
//! Декремент количества ссылок на состояние.
|
||||
void dec_reference_count() {
|
||||
if (_reference_count) _reference_count--;
|
||||
}
|
||||
|
||||
//! Возвращает true, если у состояния задан текст субтитров.
|
||||
bool has_text() const {
|
||||
return (!_text_ID.empty() || !_short_text_ID.empty());
|
||||
}
|
||||
//! Возвращает текст субтитров.
|
||||
const char *text() const {
|
||||
if (has_full_text()) return full_text();
|
||||
else return short_text();
|
||||
}
|
||||
//! Возвращает полный текст субтитров.
|
||||
const char *full_text() const;
|
||||
//! Возвращает сокращенный текст субтитров.
|
||||
const char *short_text() const;
|
||||
|
||||
//! Возвращает true, если у состояния задан текст субтитров.
|
||||
bool has_full_text() const {
|
||||
return !_text_ID.empty();
|
||||
}
|
||||
//! Возвращает true, если у состояния задан сокращенный текст субтитров.
|
||||
bool has_short_text() const {
|
||||
return !_short_text_ID.empty();
|
||||
}
|
||||
//! Возвращает полный текст субтитров.
|
||||
const char *full_text_ID() const {
|
||||
return _text_ID.c_str();
|
||||
}
|
||||
//! Устанавливает полный текст субтитров.
|
||||
/**
|
||||
Если параметр нулевой, то текст очищается.
|
||||
*/
|
||||
void set_full_text_ID(const char *p) {
|
||||
if (p) _text_ID = p;
|
||||
else _text_ID.clear();
|
||||
}
|
||||
//! Возвращает сокращенный текст субтитров.
|
||||
const char *short_text_ID() const {
|
||||
return _short_text_ID.c_str();
|
||||
}
|
||||
//! Устанавливает сокращенный текст субтитров.
|
||||
/**
|
||||
Если параметр нулевой, то текст очищается.
|
||||
*/
|
||||
void set_short_text_ID(const char *p) {
|
||||
if (p) _short_text_ID = p;
|
||||
else _short_text_ID.clear();
|
||||
}
|
||||
|
||||
//! Возвращает true, если у состояния задан баунд.
|
||||
bool has_bound() const {
|
||||
return check_flag(QD_OBJ_STATE_FLAG_HAS_BOUND);
|
||||
}
|
||||
//! Возвращает баунд состояния.
|
||||
const Vect3f &bound() const {
|
||||
return _bound;
|
||||
}
|
||||
//! Возвращает радиус состояния.
|
||||
float radius() const {
|
||||
return _radius;
|
||||
}
|
||||
//! Устанавливает баунд состояния.
|
||||
void set_bound(const Vect3f &b);
|
||||
//! Устанавливает баунд состояния по анимации.
|
||||
virtual bool auto_bound() {
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Устанавливает режим работы камеры, включается при активации состояния.
|
||||
void set_camera_mode(const qdCameraMode &mode) {
|
||||
_camera_mode = mode;
|
||||
}
|
||||
//! Режим работы камеры, включается при активации состояния.
|
||||
const qdCameraMode &camera_mode() const {
|
||||
return _camera_mode;
|
||||
}
|
||||
//! Возвращает true, если у состояния задан режим работы камеры.
|
||||
bool has_camera_mode() const {
|
||||
return _camera_mode.camera_mode() != qdCameraMode::MODE_UNASSIGNED;
|
||||
}
|
||||
|
||||
float rnd_move_radius() const {
|
||||
return _rnd_move_radius;
|
||||
}
|
||||
void set_rnd_move_radius(float radius) {
|
||||
_rnd_move_radius = radius;
|
||||
}
|
||||
|
||||
float rnd_move_speed() const {
|
||||
return _rnd_move_speed;
|
||||
}
|
||||
void set_rnd_move_speed(float speed) {
|
||||
_rnd_move_speed = speed;
|
||||
}
|
||||
|
||||
qdConditionalObject::trigger_start_mode trigger_start();
|
||||
bool trigger_can_start() const;
|
||||
|
||||
bool forced_load() const {
|
||||
return check_flag(QD_OBJ_STATE_FLAG_FORCED_LOAD);
|
||||
}
|
||||
|
||||
float text_delay() const {
|
||||
return _text_delay;
|
||||
}
|
||||
bool has_text_delay() const {
|
||||
return _text_delay > FLT_EPS;
|
||||
}
|
||||
void set_text_delay(float delay) {
|
||||
_text_delay = delay;
|
||||
}
|
||||
|
||||
float sound_delay() const {
|
||||
return _sound_delay;
|
||||
}
|
||||
bool has_sound_delay() const {
|
||||
return _sound_delay > FLT_EPS;
|
||||
}
|
||||
void set_sound_delay(float delay) {
|
||||
_sound_delay = delay;
|
||||
}
|
||||
|
||||
int autosave_slot() const {
|
||||
return _autosave_slot;
|
||||
}
|
||||
void set_autosave_slot(int slot) {
|
||||
_autosave_slot = slot;
|
||||
}
|
||||
|
||||
float fade_time() const {
|
||||
return _fade_time;
|
||||
}
|
||||
void set_fade_time(float time) {
|
||||
_fade_time = time;
|
||||
}
|
||||
|
||||
uint32 shadow_color() const {
|
||||
return _shadow_color;
|
||||
}
|
||||
int shadow_alpha() const {
|
||||
return _shadow_alpha;
|
||||
}
|
||||
|
||||
void set_shadow(uint32 color, int alpha) {
|
||||
_shadow_color = color;
|
||||
_shadow_alpha = alpha;
|
||||
}
|
||||
|
||||
const qdScreenTextFormat &text_format(bool topic_mode = false) const {
|
||||
if (_text_format.is_global_depend()) {
|
||||
return (topic_mode && check_flag(QD_OBJ_STATE_FLAG_DIALOG_PHRASE)) ?
|
||||
qdScreenTextFormat::global_topic_format() : qdScreenTextFormat::global_text_format();
|
||||
}
|
||||
return _text_format;
|
||||
}
|
||||
void set_text_format(const qdScreenTextFormat &text_format) {
|
||||
_text_format = text_format;
|
||||
}
|
||||
|
||||
bool has_transform() const {
|
||||
return _transform() || _transform_speed();
|
||||
}
|
||||
|
||||
const qdScreenTransform &transform() const {
|
||||
return _transform;
|
||||
}
|
||||
void set_transform(const qdScreenTransform &tr) {
|
||||
_transform = tr;
|
||||
}
|
||||
const qdScreenTransform &transform_speed() const {
|
||||
return _transform_speed;
|
||||
}
|
||||
void set_transform_speed(const qdScreenTransform &tr_speed) {
|
||||
_transform_speed = tr_speed;
|
||||
}
|
||||
|
||||
static Common::String flag2str(int fl, bool truncate = false, bool icon = false);
|
||||
|
||||
protected:
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script_body(const xml::tag *p);
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Возвращает true, если надо перезапустить звук.
|
||||
virtual bool need_sound_restart() const;
|
||||
|
||||
private:
|
||||
|
||||
//! Тип состояния.
|
||||
StateType _state_type;
|
||||
|
||||
//! Смещение центра анимации относительно центра объекта в экранных координатах.
|
||||
Vect2s _center_offset;
|
||||
//! Баунд.
|
||||
Vect3f _bound;
|
||||
//! Радиус сферы, описывающей баунд.
|
||||
float _radius;
|
||||
|
||||
//! Траектория движения объекта.
|
||||
qdCoordsAnimation _coords_animation;
|
||||
|
||||
//! Задержка перед активацией состояния (в секундах)
|
||||
float _activation_delay;
|
||||
//! Время в секундах, оставшееся до активации состояния.
|
||||
float _activation_timer;
|
||||
|
||||
//! Длительность состояния в секундах.
|
||||
/**
|
||||
Если нулевая, то состояние работает до конца анимации
|
||||
или до конца траектории движения.
|
||||
*/
|
||||
float _work_time;
|
||||
//! Время в секундах, прошедшее с момента активации состояния.
|
||||
float _cur_time;
|
||||
|
||||
//! Информация о звуке, привязанном к состоянию.
|
||||
qdSoundInfo _sound_info;
|
||||
//! Хэндл для управления звуком, привязанным к состоянию.
|
||||
qdSoundHandle _sound_handle;
|
||||
//! Задержка запуска звука от старта состояния (в секундах)
|
||||
float _sound_delay;
|
||||
//! true, если звук состояния запущен
|
||||
bool _is_sound_started;
|
||||
|
||||
//! Задержка перед появлением текста от старта состояния (в секундах)
|
||||
float _text_delay;
|
||||
//! true, если текст состояния появился
|
||||
bool _is_text_shown;
|
||||
|
||||
//! Номер мышиного курсора, который включается, если мышь над объектом в этом состоянии.
|
||||
int _mouse_cursor_id;
|
||||
|
||||
//! Текст, выводимый на экран при работе состояния (для диалогов и т.д.)
|
||||
Common::String _text_ID;
|
||||
//! Короткий вариант текста, выводимого на экран при работе состояния (для диалогов и т.д.)
|
||||
Common::String _short_text_ID;
|
||||
|
||||
//! Режим работы камеры, включается при активации состояния.
|
||||
qdCameraMode _camera_mode;
|
||||
|
||||
float _rnd_move_radius;
|
||||
float _rnd_move_speed;
|
||||
|
||||
/// Номер слота автосэйва
|
||||
int _autosave_slot;
|
||||
|
||||
/// Время фэйда экрана при включении состояния
|
||||
float _fade_time;
|
||||
|
||||
//! Цвет затенения.
|
||||
uint32 _shadow_color;
|
||||
//! Прозрачность затенения, значения - [0, 255], если равно QD_NO_SHADOW_ALPHA, то объект не затеняется.
|
||||
int _shadow_alpha;
|
||||
|
||||
/// Преобразование картинки объекта, включается при активации состояния
|
||||
qdScreenTransform _transform;
|
||||
qdScreenTransform _transform_speed;
|
||||
|
||||
//! Формат текста.
|
||||
qdScreenTextFormat _text_format;
|
||||
|
||||
//! Количество ссылок на состояние.
|
||||
/**
|
||||
Если объект, которому принадлежит состояние - глобальный (т.е. принадлежит
|
||||
игровому диспетрчеру, а не сцене), то состояние может одновременно находиться в более чем одном списке.
|
||||
*/
|
||||
int _reference_count;
|
||||
|
||||
//! Предыдущее состояние.
|
||||
qdGameObjectState *_prev_state;
|
||||
|
||||
};
|
||||
|
||||
typedef Std::vector<qdGameObjectState *> qdGameObjectStateVector;
|
||||
|
||||
//! Состояние динамического объекта - статическая анимация.
|
||||
class qdGameObjectStateStatic : public qdGameObjectState {
|
||||
public:
|
||||
qdGameObjectStateStatic();
|
||||
qdGameObjectStateStatic(const qdGameObjectStateStatic &st);
|
||||
~qdGameObjectStateStatic();
|
||||
|
||||
qdGameObjectState &operator = (const qdGameObjectState &st);
|
||||
qdGameObjectStateStatic &operator = (const qdGameObjectStateStatic &st);
|
||||
|
||||
qdAnimation *animation() {
|
||||
return _animation_info.animation();
|
||||
}
|
||||
const qdAnimation *animation() const {
|
||||
return _animation_info.animation();
|
||||
}
|
||||
qdAnimationInfo *animation_info() {
|
||||
return &_animation_info;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Регистрация ресурсов состояния в диспетчере ресурсов.
|
||||
bool register_resources();
|
||||
//! Отмена регистрации ресурсов состояния в диспетчере ресурсов.
|
||||
bool unregister_resources();
|
||||
bool load_resources();
|
||||
bool free_resources();
|
||||
|
||||
bool is_state_empty() const;
|
||||
|
||||
qdGameObjectState *clone() const {
|
||||
return new qdGameObjectStateStatic(*this);
|
||||
}
|
||||
|
||||
//! Устанавливает баунд состояния по анимации.
|
||||
bool auto_bound();
|
||||
|
||||
private:
|
||||
qdAnimationInfo _animation_info;
|
||||
};
|
||||
|
||||
//! Состояние динамического объекта - походка.
|
||||
class qdGameObjectStateWalk : public qdGameObjectState {
|
||||
public:
|
||||
qdGameObjectStateWalk();
|
||||
qdGameObjectStateWalk(const qdGameObjectStateWalk &st);
|
||||
~qdGameObjectStateWalk();
|
||||
|
||||
qdGameObjectState &operator = (const qdGameObjectState &st);
|
||||
qdGameObjectStateWalk &operator = (const qdGameObjectStateWalk &st);
|
||||
|
||||
//! режимы передвижения для персонажа
|
||||
enum movement_type_t {
|
||||
//! ходит только влево
|
||||
MOVEMENT_LEFT,
|
||||
//! ходит только вверх
|
||||
MOVEMENT_UP,
|
||||
//! ходит только вправо
|
||||
MOVEMENT_RIGHT,
|
||||
//! ходит только вниз
|
||||
MOVEMENT_DOWN,
|
||||
//! ходит только по горизонтали
|
||||
MOVEMENT_HORIZONTAL,
|
||||
//! ходит только по вертикали
|
||||
MOVEMENT_VERTICAL,
|
||||
//! ходит по четырем направлениям
|
||||
MOVEMENT_FOUR_DIRS,
|
||||
//! ходит по восьми направлениям
|
||||
MOVEMENT_EIGHT_DIRS,
|
||||
//! ходит по восьми и больше направлениям со сглаживанием
|
||||
MOVEMENT_SMOOTH,
|
||||
|
||||
//! ходит только влево-вверх
|
||||
MOVEMENT_UP_LEFT,
|
||||
//! ходит только вправо-вверх
|
||||
MOVEMENT_UP_RIGHT,
|
||||
//! ходит только вправо-вниз
|
||||
MOVEMENT_DOWN_RIGHT,
|
||||
//! ходит только влево-вниз
|
||||
MOVEMENT_DOWN_LEFT
|
||||
};
|
||||
|
||||
enum OffsetType {
|
||||
OFFSET_STATIC = 0,
|
||||
OFFSET_WALK,
|
||||
OFFSET_START,
|
||||
OFFSET_END
|
||||
};
|
||||
|
||||
qdAnimationSet *animation_set() const;
|
||||
|
||||
qdAnimation *animation(float direction_angle);
|
||||
qdAnimation *static_animation(float direction_angle);
|
||||
|
||||
qdAnimationInfo *animation_info(float direction_angle);
|
||||
qdAnimationInfo *static_animation_info(float direction_angle);
|
||||
|
||||
const Vect2i ¢er_offset(int direction_index, OffsetType offset_type = OFFSET_WALK) const;
|
||||
const Vect2i ¢er_offset(float direction_angle, OffsetType offset_type = OFFSET_WALK) const;
|
||||
void set_center_offset(int direction_index, const Vect2i &offs, OffsetType offset_type = OFFSET_WALK);
|
||||
|
||||
float walk_sound_frequency(int direction_index) const;
|
||||
float walk_sound_frequency(float direction_angle) const;
|
||||
void set_walk_sound_frequency(int direction_index, float freq);
|
||||
|
||||
//! Установка частоты звука.
|
||||
bool update_sound_frequency(float direction_angle) const;
|
||||
|
||||
qdAnimationSetInfo *animation_set_info() {
|
||||
return &_animation_set_info;
|
||||
}
|
||||
|
||||
float adjust_direction_angle(float angle) const;
|
||||
|
||||
float direction_angle() const {
|
||||
return _direction_angle;
|
||||
}
|
||||
void set_direction_angle(float ang) {
|
||||
_direction_angle = ang;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Регистрация ресурсов состояния в диспетчере ресурсов.
|
||||
bool register_resources();
|
||||
//! Отмена регистрации ресурсов состояния в диспетчере ресурсов.
|
||||
bool unregister_resources();
|
||||
bool load_resources();
|
||||
bool free_resources();
|
||||
|
||||
bool is_state_empty() const;
|
||||
|
||||
qdGameObjectState *clone() const {
|
||||
return new qdGameObjectStateWalk(*this);
|
||||
}
|
||||
|
||||
//! Устанавливает баунд состояния по анимации.
|
||||
bool auto_bound();
|
||||
|
||||
float acceleration() const {
|
||||
return _acceleration;
|
||||
}
|
||||
void set_acceleration(float acc) {
|
||||
_acceleration = acc;
|
||||
}
|
||||
|
||||
float max_speed() const {
|
||||
return _max_speed;
|
||||
}
|
||||
void set_max_speed(float max_sp) {
|
||||
_max_speed = max_sp;
|
||||
}
|
||||
|
||||
void set_movement_type(movement_type_t type) {
|
||||
_movement_type = type;
|
||||
}
|
||||
movement_type_t movement_type() const {
|
||||
return _movement_type;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//! Возвращает true, если надо перезапустить звук.
|
||||
bool need_sound_restart() const;
|
||||
|
||||
private:
|
||||
|
||||
float _direction_angle;
|
||||
qdAnimationSetInfo _animation_set_info;
|
||||
|
||||
//! Ускорение - насколько увеличивается скорость передвижения за секунду.
|
||||
float _acceleration;
|
||||
//! Максимальная для походки скорость передвижения.
|
||||
/**
|
||||
Если нулевая - ограничения нет.
|
||||
*/
|
||||
float _max_speed;
|
||||
|
||||
//! Режим передвижения персонажа.
|
||||
movement_type_t _movement_type;
|
||||
|
||||
//! Смещения центров анимаций походок.
|
||||
Std::vector<Vect2i> _center_offsets;
|
||||
//! Смещения центров статических анимаций.
|
||||
Std::vector<Vect2i> _static_center_offsets;
|
||||
//! Смещения центров анимаций стартов.
|
||||
Std::vector<Vect2i> _start_center_offsets;
|
||||
//! Смещения центров анимаций стопов.
|
||||
Std::vector<Vect2i> _stop_center_offsets;
|
||||
|
||||
//! Коэффициенты для частоты звука походки.
|
||||
Std::vector<float> _walk_sound_frequency;
|
||||
};
|
||||
|
||||
//! Состояние динамического объекта - маска на статическом объекте.
|
||||
class qdGameObjectStateMask : public qdGameObjectState, public qdContour {
|
||||
public:
|
||||
qdGameObjectStateMask();
|
||||
qdGameObjectStateMask(const qdGameObjectStateMask &st);
|
||||
~qdGameObjectStateMask();
|
||||
|
||||
qdGameObjectState &operator = (const qdGameObjectState &st);
|
||||
qdGameObjectStateMask &operator = (const qdGameObjectStateMask &st);
|
||||
|
||||
const char *parent_name() const {
|
||||
return _parent_name.c_str();
|
||||
}
|
||||
void set_parent_name(const char *p) {
|
||||
_parent_name = p;
|
||||
_parent = 0;
|
||||
}
|
||||
|
||||
qdGameObject *parent();
|
||||
const qdGameObject *parent() const;
|
||||
|
||||
bool hit(int x, int y) const;
|
||||
bool draw_mask(uint32 color) const;
|
||||
|
||||
bool can_be_closed() const {
|
||||
return (contour_size() > 2);
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
bool is_state_empty() const;
|
||||
|
||||
bool load_resources();
|
||||
|
||||
qdGameObjectState *clone() const {
|
||||
return new qdGameObjectStateMask(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Имя объекта, к которому привязана маска.
|
||||
Common::String _parent_name;
|
||||
|
||||
//! Указатель на объект, к которому привязана маска.
|
||||
qdGameObject *_parent;
|
||||
};
|
||||
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
inline bool qdbg_is_object_state(const qdNamedObject *obj, const char *scene_name, const char *object_name, const char *state_name) {
|
||||
if (dynamic_cast<const qdGameObjectState *>(obj)) {
|
||||
if (obj->name() && !strcmp(state_name, obj->name())) {
|
||||
if (!object_name || (obj->owner() && obj->owner()->name() && !strcmp(object_name, obj->owner()->name()))) {
|
||||
if (!scene_name || (obj->owner()->owner() && obj->owner()->owner()->name() && !strcmp(obj->owner()->owner()->name(), scene_name)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
inline bool qdbg_is_object_state(const qdNamedObject *obj, const char *scene_name, const char *object_name, const char *state_name) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_OBJECT_STATE_H
|
||||
111
engines/qdengine/qdcore/qd_game_object_static.cpp
Normal file
111
engines/qdengine/qdcore/qd_game_object_static.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/xml_tag.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_game_object_static.h"
|
||||
#include "qdengine/qdcore/qd_game_scene.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdGameObjectStatic::qdGameObjectStatic() {
|
||||
}
|
||||
|
||||
qdGameObjectStatic::~qdGameObjectStatic() {
|
||||
}
|
||||
|
||||
void qdGameObjectStatic::redraw(int offs_x, int offs_y) const {
|
||||
debugC(2, kDebugGraphics, "qdGameObjectStatic::redraw([%d, %d]), name: '%s'", offs_x, offs_y, transCyrillic(name()));
|
||||
|
||||
Vect2i scrCoord = screen_pos() + Vect2i(offs_x, offs_y);
|
||||
_sprite.redraw(scrCoord.x, scrCoord.y, screen_depth(), 0);
|
||||
}
|
||||
|
||||
bool qdGameObjectStatic::load_script(const xml::tag *p) {
|
||||
return load_script_body(p);
|
||||
}
|
||||
|
||||
bool qdGameObjectStatic::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString(Common::String::format("<static_object name=\"%s\">\r\n", qdscr_XML_string(name())));
|
||||
|
||||
save_script_body(fh, indent);
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</static_object>\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObjectStatic::load_script_body(const xml::tag *p) {
|
||||
qdGameObject::load_script_body(p);
|
||||
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_FILE:
|
||||
_sprite.set_file(Common::Path(it->data(), '\\'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObjectStatic::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
qdGameObject::save_script_body(fh, indent);
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
if (!_sprite.file().empty()) {
|
||||
fh.writeString(Common::String::format("<file>%s</file>\r\n", qdscr_XML_string(_sprite.file().toString('\\'))));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdGameObjectStatic::load_resources() {
|
||||
return _sprite.load();
|
||||
}
|
||||
|
||||
void qdGameObjectStatic::free_resources() {
|
||||
_sprite.free();
|
||||
}
|
||||
|
||||
bool qdGameObjectStatic::hit(int x, int y) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdGameObjectStatic::draw_contour(uint32 color) const {
|
||||
Vect2s pos = screen_pos();
|
||||
_sprite.draw_contour(pos.x, pos.y, color);
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
79
engines/qdengine/qdcore/qd_game_object_static.h
Normal file
79
engines/qdengine/qdcore/qd_game_object_static.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_OBJECT_STATIC_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_OBJECT_STATIC_H
|
||||
|
||||
#include "qdengine/qdcore/qd_sprite.h"
|
||||
#include "qdengine/qdcore/qd_game_object.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdGameObjectStatic : public qdGameObject {
|
||||
public:
|
||||
qdGameObjectStatic();
|
||||
~qdGameObjectStatic();
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_STATIC_OBJ;
|
||||
}
|
||||
|
||||
const qdSprite *get_sprite() const {
|
||||
return &_sprite;
|
||||
}
|
||||
qdSprite *get_sprite() {
|
||||
return &_sprite;
|
||||
}
|
||||
|
||||
void redraw(int offs_x = 0, int offs_y = 0) const;
|
||||
void debug_redraw() const { }
|
||||
void draw_contour(uint32 color) const;
|
||||
void draw_shadow(int offs_x, int offs_y, uint32 color, int alpha) const { }
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool load_resources();
|
||||
void free_resources();
|
||||
|
||||
Vect2s screen_size() const {
|
||||
return Vect2s(_sprite.size_x(), _sprite.size_y());
|
||||
}
|
||||
|
||||
bool hit(int x, int y) const;
|
||||
|
||||
protected:
|
||||
|
||||
bool load_script_body(const xml::tag *p);
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
private:
|
||||
qdSprite _sprite;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_OBJECT_STATIC_H
|
||||
1742
engines/qdengine/qdcore/qd_game_scene.cpp
Normal file
1742
engines/qdengine/qdcore/qd_game_scene.cpp
Normal file
File diff suppressed because it is too large
Load Diff
321
engines/qdengine/qdcore/qd_game_scene.h
Normal file
321
engines/qdengine/qdcore/qd_game_scene.h
Normal file
@@ -0,0 +1,321 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GAME_SCENE_H
|
||||
#define QDENGINE_QDCORE_QD_GAME_SCENE_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_camera.h"
|
||||
#include "qdengine/qdcore/qd_conditional_object.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher_base.h"
|
||||
#include "qdengine/qdcore/qd_object_map_container.h"
|
||||
#include "qdengine/qdcore/qd_object_list_container.h"
|
||||
#include "qdengine/qdcore/qd_file_owner.h"
|
||||
#include "qdengine/qdcore/util/fps_counter.h"
|
||||
#include "qdengine/system/input/mouse_input.h"
|
||||
#include "qdengine/system/graphics/gr_screen_region.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdMiniGame;
|
||||
|
||||
typedef Std::vector<qdGameObjectMoving *> personages_container_t;
|
||||
|
||||
//! Сцена.
|
||||
class qdGameScene : public qdGameDispatcherBase, public qdFileOwner {
|
||||
public:
|
||||
qdGameScene();
|
||||
~qdGameScene();
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_SCENE;
|
||||
}
|
||||
|
||||
//! флаги
|
||||
enum {
|
||||
/// зациклить сцену по горизонтали
|
||||
CYCLE_X = 0x01,
|
||||
/// зациклить сцену по вертикали
|
||||
CYCLE_Y = 0x02,
|
||||
|
||||
/// перезапускать триггера при заходе на сцену
|
||||
RESET_TRIGGERS_ON_LOAD = 0x04,
|
||||
|
||||
/// не переключать персонажей с клавиатуры
|
||||
DISABLE_KEYBOARD_PERSONAGE_SWITCH = 0x08,
|
||||
|
||||
/// не давать выйти в главное меню по ESC
|
||||
DISABLE_MAIN_MENU = 0x10
|
||||
};
|
||||
|
||||
qdNamedObject *mouse_click_object() {
|
||||
return _mouse_click_object;
|
||||
}
|
||||
void set_mouse_click_object(qdNamedObject *p) {
|
||||
_mouse_click_object = p;
|
||||
}
|
||||
|
||||
qdNamedObject *mouse_right_click_object() {
|
||||
return _mouse_right_click_object;
|
||||
}
|
||||
void set_mouse_right_click_object(qdNamedObject *p) {
|
||||
_mouse_right_click_object = p;
|
||||
}
|
||||
|
||||
qdNamedObject *mouse_hover_object() {
|
||||
return _mouse_hover_object;
|
||||
}
|
||||
void set_mouse_hover_object(qdNamedObject *p) {
|
||||
_mouse_hover_object = p;
|
||||
}
|
||||
|
||||
const Vect2f mouse_click_pos() const {
|
||||
return _mouse_click_pos;
|
||||
}
|
||||
|
||||
bool need_to_redraw_inventory(const char *inventory_name) const;
|
||||
|
||||
const char *minigame_name() const {
|
||||
return _minigame_name.c_str();
|
||||
}
|
||||
void set_minigame_name(const char *name) {
|
||||
_minigame_name = name;
|
||||
}
|
||||
bool has_minigame() const {
|
||||
return !_minigame_name.empty();
|
||||
}
|
||||
|
||||
const qdMiniGame *minigame() const {
|
||||
return _minigame;
|
||||
}
|
||||
void start_minigame();
|
||||
|
||||
bool restart_minigame_on_load() const {
|
||||
return _restart_minigame_on_load;
|
||||
}
|
||||
void toggle_restart_minigame_on_load(bool state) {
|
||||
_restart_minigame_on_load = state;
|
||||
}
|
||||
|
||||
bool add_object(qdGameObject *p);
|
||||
bool rename_object(qdGameObject *p, const char *name);
|
||||
bool remove_object(const char *name);
|
||||
bool remove_object(qdGameObject *p);
|
||||
qdGameObject *get_object(const char *name);
|
||||
bool is_object_in_list(const char *name);
|
||||
bool is_object_in_list(qdGameObject *p);
|
||||
|
||||
bool is_active() const;
|
||||
|
||||
void set_active_personage(qdGameObjectMoving *p);
|
||||
void set_active_object(qdGameObjectAnimated *p);
|
||||
qdGameObjectMoving *get_active_personage() {
|
||||
return _selected_object;
|
||||
}
|
||||
bool change_active_personage(void);
|
||||
|
||||
bool set_personage_button(qdInterfaceButton *p);
|
||||
|
||||
bool add_grid_zone(qdGridZone *p);
|
||||
bool rename_grid_zone(qdGridZone *p, const char *name);
|
||||
bool remove_grid_zone(const char *name);
|
||||
bool remove_grid_zone(qdGridZone *p);
|
||||
qdGridZone *get_grid_zone(const char *name);
|
||||
bool is_grid_zone_in_list(const char *name);
|
||||
bool is_grid_zone_in_list(qdGridZone *p);
|
||||
|
||||
bool is_any_personage_in_zone(const qdGridZone *p) const;
|
||||
|
||||
bool add_music_track(qdMusicTrack *p);
|
||||
bool rename_music_track(qdMusicTrack *p, const char *name);
|
||||
bool remove_music_track(const char *name);
|
||||
bool remove_music_track(qdMusicTrack *p);
|
||||
qdMusicTrack *get_music_track(const char *name);
|
||||
bool is_music_track_in_list(const char *name) const;
|
||||
bool is_music_track_in_list(qdMusicTrack *p) const;
|
||||
|
||||
void init_objects_grid();
|
||||
void quant(float dt);
|
||||
|
||||
//! Вызывается при заходе на сцену.
|
||||
bool activate();
|
||||
//! Вызывается при выходе со сцены.
|
||||
bool deactivate();
|
||||
|
||||
//! Инициализация данных, вызывается при старте и перезапуске игры.
|
||||
bool init();
|
||||
|
||||
void pre_redraw();
|
||||
void redraw();
|
||||
void post_redraw();
|
||||
void debug_redraw();
|
||||
|
||||
void add_redraw_region(const grScreenRegion ®) const;
|
||||
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
|
||||
void load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
int load_resources();
|
||||
void free_resources();
|
||||
|
||||
qdCamera *get_camera() {
|
||||
return &_camera;
|
||||
}
|
||||
const qdCamera *get_camera() const {
|
||||
return &_camera;
|
||||
}
|
||||
|
||||
const qdGameObjectList &object_list() const {
|
||||
return _objects.get_list();
|
||||
}
|
||||
const qdGridZoneList &grid_zone_list() const {
|
||||
return _grid_zones.get_list();
|
||||
}
|
||||
const qdMusicTrackList &music_track_list() const {
|
||||
return _music_tracks.get_list();
|
||||
}
|
||||
|
||||
bool merge_global_objects(qdGameObject *obj = NULL);
|
||||
bool split_global_objects(qdGameObject *obj = NULL);
|
||||
|
||||
int get_resources_size();
|
||||
|
||||
void inc_zone_update_count() {
|
||||
_zone_update_count++;
|
||||
}
|
||||
uint32 zone_update_count() const {
|
||||
return _zone_update_count;
|
||||
}
|
||||
|
||||
qdConditionalObject::trigger_start_mode trigger_start();
|
||||
|
||||
static fpsCounter *fps_counter();
|
||||
|
||||
int autosave_slot() const {
|
||||
return _autosave_slot;
|
||||
}
|
||||
void set_autosave_slot(int slot) {
|
||||
_autosave_slot = slot;
|
||||
}
|
||||
|
||||
bool has_interface_screen() const {
|
||||
return !_interface_screen_name.empty();
|
||||
}
|
||||
const char *interface_screen_name() const {
|
||||
return _interface_screen_name.c_str();
|
||||
}
|
||||
void set_interface_screen_name(const char *name) {
|
||||
_interface_screen_name = name;
|
||||
}
|
||||
|
||||
qdGameObject *get_hitted_obj(int x, int y);
|
||||
|
||||
bool set_camera_mode(const qdCameraMode &mode, qdGameObjectAnimated *object);
|
||||
|
||||
personages_container_t *getPersonages() { return &_personages; }
|
||||
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
bool get_resources_info(qdResourceInfoContainer &infos) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
int _autosave_slot;
|
||||
|
||||
qdObjectMapContainer<qdGameObject> _objects;
|
||||
qdObjectListContainer<qdGridZone> _grid_zones;
|
||||
qdObjectListContainer<qdMusicTrack> _music_tracks;
|
||||
|
||||
qdCamera _camera;
|
||||
|
||||
//! текущий персонаж
|
||||
qdGameObjectMoving *_selected_object;
|
||||
|
||||
/// миниигра, управляющая сценой
|
||||
qdMiniGame *_minigame;
|
||||
|
||||
/// true если нужен перезапуск миниигры при загрузке из сэйва
|
||||
bool _restart_minigame_on_load;
|
||||
|
||||
//! список персонажей сцены
|
||||
personages_container_t _personages;
|
||||
|
||||
//! кликнутый мышью объект
|
||||
qdNamedObject *_mouse_click_object;
|
||||
//! кликнутый правой кнопкой мыши объект
|
||||
qdNamedObject *_mouse_right_click_object;
|
||||
//! объект, над кторым мышиный курсор
|
||||
qdNamedObject *_mouse_hover_object;
|
||||
|
||||
//! кликнутая мышью точка на плоскости сцены
|
||||
Vect2f _mouse_click_pos;
|
||||
|
||||
/// имя миниигры, управляющей сценой
|
||||
Common::String _minigame_name;
|
||||
|
||||
/// используемый для сцены интерфейсный экран
|
||||
Common::String _interface_screen_name;
|
||||
|
||||
uint32 _zone_update_count;
|
||||
|
||||
static char _fps_string[255];
|
||||
|
||||
bool init_visible_objects_list();
|
||||
void update_mouse_cursor();
|
||||
|
||||
void personages_quant();
|
||||
|
||||
//! Инициализирует персонажей, участвующих в следовании
|
||||
void follow_pers_init(int follow_cond);
|
||||
//! Пытается найти путь к точке следования для pObj. Если идти нужно, но не удастся, то false.
|
||||
bool follow_path_seek(qdGameObjectMoving *pObj, bool lock_target);
|
||||
|
||||
//! Реализует движение всех "следующих", кто достаточно далеко от точки следования
|
||||
void follow_implement_update_path();
|
||||
//! Снимает состояние FOLLOW_WAIT и заставляет пытаться следовать снова
|
||||
void follow_wakening();
|
||||
/** Обработка пересечений и попытка первого перса обойти второго, разрешив
|
||||
таким образом пересечение */
|
||||
void follow_circuit(float dt);
|
||||
//! Останавливает дошедших следующих персонажей
|
||||
void follow_end_moving();
|
||||
//! Квант следования
|
||||
void follow_quant(float dt);
|
||||
|
||||
void collision_quant();
|
||||
|
||||
void create_minigame_objects();
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GAME_SCENE_H
|
||||
346
engines/qdengine/qdcore/qd_grid_zone.cpp
Normal file
346
engines/qdengine/qdcore/qd_grid_zone.cpp
Normal file
@@ -0,0 +1,346 @@
|
||||
/* 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 = maskData();
|
||||
|
||||
if (_state) {
|
||||
for (int y = 0; y < mask_size().y; y++) {
|
||||
for (int x = 0; x < mask_size().x; x++) {
|
||||
if ((g_engine->_gameVersion <= 20050101 && *mask_ptr++) || is_inside(pos + Vect2s(x, y))) {
|
||||
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 ((g_engine->_gameVersion <= 20050101 && *mask_ptr++) || is_inside(pos + Vect2s(x, y))) {
|
||||
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 = maskData();
|
||||
|
||||
if (bSelect) {
|
||||
for (int y = 0; y < mask_size().y; y++) {
|
||||
for (int x = 0; x < mask_size().x; x++) {
|
||||
if ((g_engine->_gameVersion <= 20050101 && *mask_ptr++) || is_inside(pos + Vect2s(x, y))) {
|
||||
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 ((g_engine->_gameVersion <= 20050101 && *mask_ptr++) || is_inside(pos + Vect2s(x, y))) {
|
||||
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
|
||||
160
engines/qdengine/qdcore/qd_grid_zone.h
Normal file
160
engines/qdengine/qdcore/qd_grid_zone.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GRID_ZONE_H
|
||||
#define QDENGINE_QDCORE_QD_GRID_ZONE_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_contour.h"
|
||||
#include "qdengine/qdcore/qd_grid_zone_state.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdCamera;
|
||||
|
||||
const int QD_NO_SHADOW_ALPHA = -1;
|
||||
const int QD_SHADOW_ALPHA_MIN = 0;
|
||||
const int QD_SHADOW_ALPHA_MAX = 255;
|
||||
|
||||
//! Зона на сетке сцены.
|
||||
class qdGridZone : public qdNamedObject, public qdContour {
|
||||
public:
|
||||
qdGridZone();
|
||||
qdGridZone(const qdGridZone &gz);
|
||||
|
||||
qdGridZone &operator = (const qdGridZone &gz);
|
||||
|
||||
~qdGridZone();
|
||||
|
||||
//! Команды для изменения состояния зоны в триггерах.
|
||||
enum status_change {
|
||||
//! выключить зону
|
||||
ZONE_OFF = 0,
|
||||
//! включить зону
|
||||
ZONE_ON,
|
||||
//! переключить зону
|
||||
ZONE_TOGGLE
|
||||
};
|
||||
|
||||
//! Флаги
|
||||
enum {
|
||||
//! т.н. "зона выхода" - при наведении на нее мышью курсор меняется
|
||||
ZONE_EXIT_FLAG = 0x01
|
||||
};
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_GRID_ZONE;
|
||||
}
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int saveVersion);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
bool state() const {
|
||||
return _state;
|
||||
}
|
||||
bool set_state(bool st);
|
||||
bool toggle_state() {
|
||||
return set_state(!_state);
|
||||
}
|
||||
|
||||
uint32 height() const {
|
||||
return _height;
|
||||
}
|
||||
bool set_height(int _h);
|
||||
|
||||
bool select(qdCamera *camera, bool bSelect) const;
|
||||
bool select(bool bSelect) const;
|
||||
|
||||
bool is_object_in_zone(const qdGameObject *obj) const;
|
||||
bool is_point_in_zone(const Vect2f &vPoint) const;
|
||||
|
||||
uint32 update_timer() const {
|
||||
return _update_timer;
|
||||
}
|
||||
|
||||
qdGridZoneState *get_state(const char *state_name);
|
||||
|
||||
//! Инициализация данных, вызывается при старте и перезапуске игры.
|
||||
bool init();
|
||||
|
||||
bool is_any_personage_in_zone() const;
|
||||
|
||||
int shadow_alpha() const {
|
||||
return _shadow_alpha;
|
||||
}
|
||||
void set_shadow_alpha(int alpha) {
|
||||
_shadow_alpha = alpha;
|
||||
}
|
||||
|
||||
uint32 shadow_color() const {
|
||||
return _shadow_color;
|
||||
}
|
||||
void set_shadow_color(uint32 color) {
|
||||
_shadow_color = color;
|
||||
}
|
||||
bool has_shadow() const {
|
||||
return (_shadow_alpha != QD_NO_SHADOW_ALPHA);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Текущее состояние зоны (вкл/выкл).
|
||||
bool _state;
|
||||
//! Начальное состояние зоны (вкл/выкл).
|
||||
bool _initial_state;
|
||||
|
||||
//! Цвет затенения персонажа, когда он находится в зоне, RGB().
|
||||
uint32 _shadow_color;
|
||||
//! Прозрачность затенения персонажа, когда он находится в зоне.
|
||||
/**
|
||||
Значения - [0, 255].
|
||||
Допускается также QD_NO_SHADOW_ALPHA, затенения при этом отключается.
|
||||
*/
|
||||
int _shadow_alpha;
|
||||
|
||||
//! Высота зоны.
|
||||
uint32 _height;
|
||||
|
||||
//! Время изменения состояния.
|
||||
uint32 _update_timer;
|
||||
|
||||
//! Состояние включающее зону.
|
||||
qdGridZoneState _state_on;
|
||||
//! Состояние выключающее зону.
|
||||
qdGridZoneState _state_off;
|
||||
|
||||
bool apply_zone() const;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GRID_ZONE_H
|
||||
92
engines/qdengine/qdcore/qd_grid_zone_state.cpp
Normal file
92
engines/qdengine/qdcore/qd_grid_zone_state.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_grid_zone.h"
|
||||
#include "qdengine/qdcore/qd_grid_zone_state.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
const char *const qdGridZoneState::ZONE_STATE_ON_NAME = "\xc2\xea\xeb"; // "Вкл" -- "On"
|
||||
const char *const qdGridZoneState::ZONE_STATE_OFF_NAME = "\xc2\xfb\xea\xeb"; // "Выкл" -- "Off"
|
||||
|
||||
qdGridZoneState::qdGridZoneState(bool st) : _state(st) {
|
||||
if (st)
|
||||
set_name(ZONE_STATE_ON_NAME);
|
||||
else
|
||||
set_name(ZONE_STATE_OFF_NAME);
|
||||
}
|
||||
|
||||
qdGridZoneState::qdGridZoneState(const qdGridZoneState &st) : qdConditionalObject(st),
|
||||
_state(st._state) {
|
||||
}
|
||||
|
||||
qdGridZoneState::~qdGridZoneState() {
|
||||
}
|
||||
|
||||
qdGridZoneState &qdGridZoneState::operator = (const qdGridZoneState &st) {
|
||||
if (this == &st) return *this;
|
||||
|
||||
_state = st._state;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdGridZoneState::load_script(const xml::tag *p) {
|
||||
return load_conditions_script(p);
|
||||
}
|
||||
|
||||
bool qdGridZoneState::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("<grid_zone_state");
|
||||
|
||||
if (_state) {
|
||||
fh.writeString(" state=\"1\"");
|
||||
} else {
|
||||
fh.writeString(" state=\"0\"");
|
||||
};
|
||||
|
||||
if (has_conditions()) {
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
save_conditions_script(fh, indent);
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</grid_zone_state>\r\n");
|
||||
} else {
|
||||
fh.writeString("/>\r\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qdConditionalObject::trigger_start_mode qdGridZoneState::trigger_start() {
|
||||
if (!owner()) return qdConditionalObject::TRIGGER_START_FAILED;
|
||||
|
||||
static_cast<qdGridZone *>(owner())->set_state(state());
|
||||
|
||||
return qdConditionalObject::TRIGGER_START_ACTIVATE;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
66
engines/qdengine/qdcore/qd_grid_zone_state.h
Normal file
66
engines/qdengine/qdcore/qd_grid_zone_state.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_GRID_ZONE_STATE_H
|
||||
#define QDENGINE_QDCORE_QD_GRID_ZONE_STATE_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_conditional_object.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Состояние зоны на сетке сцены.
|
||||
class qdGridZoneState : public qdConditionalObject {
|
||||
public:
|
||||
explicit qdGridZoneState(bool st);
|
||||
qdGridZoneState(const qdGridZoneState &st);
|
||||
~qdGridZoneState();
|
||||
|
||||
qdGridZoneState &operator = (const qdGridZoneState &st);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_GRID_ZONE_STATE;
|
||||
}
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Включить или выключить зону.
|
||||
bool state() const {
|
||||
return _state;
|
||||
}
|
||||
|
||||
qdConditionalObject::trigger_start_mode trigger_start();
|
||||
|
||||
static const char *const ZONE_STATE_ON_NAME;
|
||||
static const char *const ZONE_STATE_OFF_NAME;
|
||||
|
||||
private:
|
||||
|
||||
//! Включить или выключить зону.
|
||||
bool _state;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_GRID_ZONE_STATE_H
|
||||
85
engines/qdengine/qdcore/qd_interface_background.cpp
Normal file
85
engines/qdengine/qdcore/qd_interface_background.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag.h"
|
||||
#include "qdengine/qdcore/qd_interface_background.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceBackground::qdInterfaceBackground() {
|
||||
_state.set_owner(this);
|
||||
}
|
||||
|
||||
qdInterfaceBackground::qdInterfaceBackground(const qdInterfaceBackground &bk) : qdInterfaceElement(bk) {
|
||||
_state.set_owner(this);
|
||||
_state = bk._state;
|
||||
}
|
||||
|
||||
qdInterfaceBackground::~qdInterfaceBackground() {
|
||||
_state.unregister_resources();
|
||||
}
|
||||
|
||||
qdInterfaceBackground &qdInterfaceBackground::operator = (const qdInterfaceBackground &bk) {
|
||||
if (this == &bk) return *this;
|
||||
|
||||
*static_cast<qdInterfaceElement *>(this) = bk;
|
||||
|
||||
_state = bk._state;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdInterfaceBackground::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
if (!_state.save_script(fh, indent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceBackground::load_script_body(const xml::tag *p) {
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_INTERFACE_ELEMENT_STATE:
|
||||
if (!_state.load_script(&*it)) return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceBackground::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceBackground::keyboard_handler(Common::KeyCode vkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceBackground::init(bool is_game_active) {
|
||||
return set_state(&_state);
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
106
engines/qdengine/qdcore/qd_interface_background.h
Normal file
106
engines/qdengine/qdcore/qd_interface_background.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_BACKGROUND_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_BACKGROUND_H
|
||||
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Интерфейсный элемент - фон.
|
||||
class qdInterfaceBackground : public qdInterfaceElement {
|
||||
public:
|
||||
qdInterfaceBackground();
|
||||
qdInterfaceBackground(const qdInterfaceBackground &bk);
|
||||
~qdInterfaceBackground();
|
||||
|
||||
qdInterfaceBackground &operator = (const qdInterfaceBackground &bk);
|
||||
|
||||
//! Возвращает тип элемента.
|
||||
qdInterfaceElement::element_type get_element_type() const {
|
||||
return qdInterfaceElement::EL_BACKGROUND;
|
||||
}
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
|
||||
//! Инициализация элемента.
|
||||
/**
|
||||
Вызывается каждый раз при заходе на экран, которому принадлежит элемент.
|
||||
*/
|
||||
bool init(bool is_game_active = true);
|
||||
|
||||
//! Устанавливает имя файла для анимации.
|
||||
/**
|
||||
Если надо убрать анимацию - передать NULL в качестве имени файла.
|
||||
*/
|
||||
void set_animation_file(const Common::Path &name) {
|
||||
_state.set_animation_file(name);
|
||||
}
|
||||
//! Возвращает имя файла для анимации.
|
||||
const Common::Path animation_file() const {
|
||||
return _state.animation_file();
|
||||
}
|
||||
//! Возвращает флаги анимации.
|
||||
int animation_flags() const {
|
||||
return _state.animation_flags();
|
||||
}
|
||||
|
||||
//! Устанавливает флаг анимации.
|
||||
void set_animation_flag(int fl) {
|
||||
_state.set_animation_flag(fl);
|
||||
}
|
||||
//! Скидывает флаг анимации.
|
||||
void drop_animation_flag(int fl) {
|
||||
_state.drop_animation_flag(fl);
|
||||
}
|
||||
//! Возвращает true, если для анимации установлен флаг fl.
|
||||
bool check_animation_flag(int fl) const {
|
||||
return _state.check_animation_flag(fl);
|
||||
}
|
||||
|
||||
//! Возвращает true, если к фону привязана анимация.
|
||||
bool has_animation() const {
|
||||
return _state.has_animation();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script_body(const xml::tag *p);
|
||||
|
||||
private:
|
||||
|
||||
//! Состояние, в котором хранятся все необходимые настройки.
|
||||
qdInterfaceElementState _state;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_BACKGROUND_H
|
||||
298
engines/qdengine/qdcore/qd_interface_button.cpp
Normal file
298
engines/qdengine/qdcore/qd_interface_button.cpp
Normal file
@@ -0,0 +1,298 @@
|
||||
/* 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 "qdengine/qdengine.h"
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_interface_button.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceButton::qdInterfaceButton() : _cur_state(-1) {
|
||||
}
|
||||
|
||||
qdInterfaceButton::qdInterfaceButton(const qdInterfaceButton &bt) : qdInterfaceElement(bt),
|
||||
#ifndef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
_states(bt._states),
|
||||
#endif
|
||||
_cur_state(-1) {
|
||||
|
||||
#ifdef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
for (int i = 0; i < bt.num_states(); i++)
|
||||
_states.push_back(new qdInterfaceElementState(*bt.get_state(i)));
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < num_states(); i++) {
|
||||
get_state(i)->set_owner(this);
|
||||
get_state(i)->register_resources();
|
||||
}
|
||||
}
|
||||
|
||||
qdInterfaceButton::~qdInterfaceButton() {
|
||||
_states.clear();
|
||||
}
|
||||
|
||||
qdInterfaceButton &qdInterfaceButton::operator = (const qdInterfaceButton &bt) {
|
||||
if (this == &bt) return *this;
|
||||
|
||||
*static_cast<qdInterfaceElement *>(this) = bt;
|
||||
|
||||
#ifdef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
for (state_container_t::iterator it = _states.begin(); it != _states.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
_states.clear();
|
||||
|
||||
for (int i = 0; i < bt.num_states(); i++)
|
||||
_states.push_back(new qdInterfaceElementState(*bt.get_state(i)));
|
||||
#else
|
||||
_states.clear();
|
||||
_states = bt._states;
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < num_states(); i++) {
|
||||
get_state(i)->set_owner(this);
|
||||
get_state(i)->register_resources();
|
||||
}
|
||||
|
||||
_cur_state = -1;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::activate_state(int state_num) {
|
||||
if (state_num >= (int)_states.size())
|
||||
state_num = _states.size() - 1;
|
||||
|
||||
if (!_states.size() || _cur_state == state_num) return false;
|
||||
|
||||
if (state_num < 0)
|
||||
state_num = 0;
|
||||
|
||||
_cur_state = state_num;
|
||||
|
||||
if (state_num < (int)_states.size())
|
||||
return set_state(get_state(state_num));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::activate_state(const char *state_name) {
|
||||
for (int i = 0; i < num_states(); i++) {
|
||||
qdInterfaceElementState *p = get_state(i);
|
||||
if (!strcmp(p->name(), state_name))
|
||||
return activate_state(i);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::set_option_value(int value) {
|
||||
value = CLIP<int>(value, 0, _states.size() - 1);
|
||||
|
||||
activate_state(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::add_state(const qdInterfaceElementState &st) {
|
||||
#ifdef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
_states.push_back(new qdInterfaceElementState(st));
|
||||
#else
|
||||
_states.push_back(st);
|
||||
#endif
|
||||
|
||||
get_state(_states.size() - 1)->set_owner(this);
|
||||
get_state(_states.size() - 1)->register_resources();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::insert_state(int insert_before, const qdInterfaceElementState &st) {
|
||||
assert(insert_before >= 0 && insert_before < (int)_states.size());
|
||||
|
||||
#ifdef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
_states.insert(_states.begin() + insert_before, new qdInterfaceElementState(st));
|
||||
#else
|
||||
_states.insert(_states.begin() + insert_before, st);
|
||||
#endif
|
||||
|
||||
get_state(insert_before)->set_owner(this);
|
||||
get_state(insert_before)->register_resources();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::erase_state(int state_num) {
|
||||
assert(state_num >= 0 && state_num < (int)_states.size());
|
||||
|
||||
#ifdef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
// delete *(_states.begin() + state_num);
|
||||
#endif
|
||||
|
||||
_states.erase(_states.begin() + state_num);
|
||||
|
||||
if (_cur_state == state_num)
|
||||
activate_state(--_cur_state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
if (_cur_state == -1) return false;
|
||||
|
||||
return get_state(_cur_state)->mouse_handler(x, y, ev);
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::keyboard_handler(Common::KeyCode vkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::init(bool is_game_active) {
|
||||
set_lock(false);
|
||||
|
||||
if (!is_game_active) {
|
||||
for (int i = 0; i < num_states(); i++) {
|
||||
if (get_state(i)->need_active_game()) {
|
||||
set_lock(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_states(); i++) {
|
||||
qdInterfaceElementState *p = get_state(i);
|
||||
p->set_state_mode(qdInterfaceElementState::DEFAULT_MODE);
|
||||
}
|
||||
|
||||
if (_cur_state != -1)
|
||||
return set_state(get_state(_cur_state));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < num_states(); i++) {
|
||||
if (!get_state(i)->save_script(fh, indent + 1))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::load_script_body(const xml::tag *p) {
|
||||
int num_states = 0;
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_INTERFACE_ELEMENT_STATE:
|
||||
num_states++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_states) {
|
||||
_states.reserve(num_states);
|
||||
_cur_state = 0;
|
||||
}
|
||||
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_INTERFACE_ELEMENT_STATE: {
|
||||
qdInterfaceElementState st;
|
||||
if (!st.load_script(&*it))
|
||||
return false;
|
||||
add_state(st);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::quant(float dt) {
|
||||
debugC(9, kDebugQuant, "qdInterfaceButton::quant()");
|
||||
qdInterfaceElement::quant(dt);
|
||||
|
||||
if (find_event(qdInterfaceEvent::EVENT_CLEAR_MOUSE)) {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
debugC(3, kDebugQuant, "qdInterfaceButton::quant()");
|
||||
if (dp->is_on_mouse(NULL))
|
||||
activate_state(1);
|
||||
else
|
||||
activate_state(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (_cur_state != -1) {
|
||||
get_state(_cur_state)->quant(dt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::hit_test(int x, int y) const {
|
||||
if (_cur_state != -1) {
|
||||
if (get_state(_cur_state)->has_contour(get_state(_cur_state)->state_mode()))
|
||||
return get_state(_cur_state)->hit_test(x - r().x, y - r().y, get_state(_cur_state)->state_mode());
|
||||
}
|
||||
|
||||
return qdInterfaceElement::hit_test(x, y);
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::change_state(bool direction) {
|
||||
if (num_states()) {
|
||||
if (_cur_state != -1) {
|
||||
_cur_state += (direction) ? 1 : -1;
|
||||
if (_cur_state < 0) _cur_state = num_states() - 1;
|
||||
if (_cur_state >= num_states()) _cur_state = 0;
|
||||
} else
|
||||
_cur_state = 0;
|
||||
|
||||
return activate_state(_cur_state);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const qdInterfaceEvent *qdInterfaceButton::find_event(qdInterfaceEvent::event_t type) const {
|
||||
for (int i = 0; i < num_states(); i++) {
|
||||
const qdInterfaceElementState *p = get_state(i);
|
||||
if (const qdInterfaceEvent * ev = p->find_event(type))
|
||||
return ev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdInterfaceButton::has_event(qdInterfaceEvent::event_t type, const char *ev_data) const {
|
||||
for (int i = 0; i < num_states(); i++) {
|
||||
const qdInterfaceElementState *p = get_state(i);
|
||||
if (p->has_event(type, ev_data))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
163
engines/qdengine/qdcore/qd_interface_button.h
Normal file
163
engines/qdengine/qdcore/qd_interface_button.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_BUTTON_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_BUTTON_H
|
||||
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Интерфейсный элемент - кнопка.
|
||||
class qdInterfaceButton : public qdInterfaceElement {
|
||||
public:
|
||||
qdInterfaceButton();
|
||||
qdInterfaceButton(const qdInterfaceButton &bt);
|
||||
~qdInterfaceButton();
|
||||
|
||||
qdInterfaceButton &operator = (const qdInterfaceButton &bt);
|
||||
|
||||
//! Возвращает тип элемента.
|
||||
qdInterfaceElement::element_type get_element_type() const {
|
||||
return qdInterfaceElement::EL_BUTTON;
|
||||
}
|
||||
|
||||
//! Возвращает количество состояний кнопки.
|
||||
int num_states() const {
|
||||
return _states.size();
|
||||
}
|
||||
|
||||
//! Включает состояние номер state_num.
|
||||
bool activate_state(int state_num);
|
||||
//! Включает состояние с именем state_name.
|
||||
bool activate_state(const char *state_name);
|
||||
|
||||
int option_value() const {
|
||||
return _cur_state;
|
||||
}
|
||||
bool set_option_value(int value);
|
||||
|
||||
//! Возвращает указатель на состояние кнопки.
|
||||
const qdInterfaceElementState *get_state(int state_num) const {
|
||||
assert(state_num >= 0 && state_num < (int)_states.size());
|
||||
#ifndef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
return &_states[state_num];
|
||||
#else
|
||||
return &*_states[state_num];
|
||||
#endif
|
||||
}
|
||||
//! Возвращает указатель на состояние кнопки.
|
||||
qdInterfaceElementState *get_state(int state_num) {
|
||||
assert(state_num >= 0 && state_num < (int)_states.size());
|
||||
#ifndef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
return &_states[state_num];
|
||||
#else
|
||||
return &*_states[state_num];
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Добавляет состояние кнопки.
|
||||
/**
|
||||
Параметры из состояния st копируются во внутренние данные.
|
||||
*/
|
||||
bool add_state(const qdInterfaceElementState &st);
|
||||
|
||||
//! Добавляет состояние кнопки.
|
||||
/**
|
||||
Новое состояние добавляется в список перед состоянием номер insert_before.
|
||||
Параметры из состояния st копируются во внутренние данные.
|
||||
*/
|
||||
bool insert_state(int insert_before, const qdInterfaceElementState &st);
|
||||
|
||||
//! Удаляет состояние номер state_num.
|
||||
bool erase_state(int state_num);
|
||||
|
||||
//! Модифицирует состояние кнопки.
|
||||
/**
|
||||
Соответствующему состоянию присваивается значение st.
|
||||
*/
|
||||
bool modify_state(int state_num, const qdInterfaceElementState &st) {
|
||||
assert(state_num >= 0 && state_num < (int)_states.size());
|
||||
#ifdef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
*_states[state_num] = st;
|
||||
_states[state_num]->set_owner(this);
|
||||
#else
|
||||
_states[state_num] = st;
|
||||
_states[state_num].set_owner(this);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Переключает состояние кнопки.
|
||||
/**
|
||||
Если direction == true включается следующее состояние, если false - предыдущее.
|
||||
*/
|
||||
bool change_state(bool direction = true);
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
|
||||
//! Инициализация элемента.
|
||||
/**
|
||||
Вызывается каждый раз при заходе на экран, которому принадлежит элемент.
|
||||
*/
|
||||
bool init(bool is_game_active = true);
|
||||
|
||||
//! Обсчет логики, параметр - время в секундах.
|
||||
bool quant(float dt);
|
||||
|
||||
//! Возвращает true, если точка с экранными координатами (x,у) попадает в элемент.
|
||||
bool hit_test(int x, int y) const;
|
||||
|
||||
const qdInterfaceEvent *find_event(qdInterfaceEvent::event_t type) const;
|
||||
bool has_event(qdInterfaceEvent::event_t type, const char *ev_data = NULL) const;
|
||||
|
||||
protected:
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script_body(const xml::tag *p);
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _QD_INTERFACE_BUTTON_PTR_CONTAINER
|
||||
typedef Std::vector<qdInterfaceElementState *> state_container_t;
|
||||
#else
|
||||
typedef Std::vector<qdInterfaceElementState> state_container_t;
|
||||
#endif
|
||||
|
||||
//! Состояния кнопки.
|
||||
state_container_t _states;
|
||||
|
||||
//! Текущее состояние кнопки.
|
||||
int _cur_state;
|
||||
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_BUTTON_H
|
||||
206
engines/qdengine/qdcore/qd_interface_counter.cpp
Normal file
206
engines/qdengine/qdcore/qd_interface_counter.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_counter.h"
|
||||
#include "qdengine/qdcore/qd_interface_counter.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceCounter::qdInterfaceCounter() : _counter(0) {
|
||||
_digits = 4;
|
||||
|
||||
_lastValue = -1;
|
||||
|
||||
_textFormat.toggle_global_depend(false);
|
||||
}
|
||||
|
||||
qdInterfaceCounter::qdInterfaceCounter(const qdInterfaceCounter &counter) : qdInterfaceElement(counter),
|
||||
_textFormat(counter._textFormat),
|
||||
_digits(counter._digits),
|
||||
_counterName(counter._counterName),
|
||||
_counter(counter._counter) {
|
||||
_lastValue = -1;
|
||||
_textFormat.toggle_global_depend(false);
|
||||
}
|
||||
|
||||
qdInterfaceCounter::~qdInterfaceCounter() {
|
||||
}
|
||||
|
||||
qdInterfaceCounter &qdInterfaceCounter::operator = (const qdInterfaceCounter &counter) {
|
||||
if (this == &counter) return *this;
|
||||
|
||||
*static_cast<qdInterfaceElement *>(this) = counter;
|
||||
|
||||
_textFormat = counter._textFormat;
|
||||
|
||||
_digits = counter._digits;
|
||||
|
||||
_counterName = counter._counterName;
|
||||
_counter = counter._counter;
|
||||
|
||||
_lastValue = -1;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdInterfaceCounter::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<counter_name>%s</counter_name>\r\n", qdscr_XML_string(counterName())));
|
||||
|
||||
_textFormat.save_script(fh, indent + 1);
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<digits>%d</digits>\r\n", _digits));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceCounter::load_script_body(const xml::tag *p) {
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_COUNTER_NAME:
|
||||
setCounterName(it->data());
|
||||
break;
|
||||
case QDSCR_SCREEN_TEXT_FORMAT:
|
||||
_textFormat.load_script(&*it);
|
||||
break;
|
||||
case QDSCR_COUNTER_DIGITS:
|
||||
_digits = xml::tag_buffer(*it).get_int();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::String qdInterfaceCounter::data() const {
|
||||
Common::String str;
|
||||
|
||||
int val = 0;
|
||||
if (_counter)
|
||||
val = _counter->value();
|
||||
|
||||
if (val < 0)
|
||||
str += "-";
|
||||
|
||||
int delta = 10;
|
||||
for (int i = 1; i < _digits; i++) {
|
||||
if (abs(val) < abs(delta))
|
||||
str += "0";
|
||||
|
||||
delta *= 10;
|
||||
}
|
||||
|
||||
str += Common::String::format("%d", abs(val));
|
||||
debugC(3, kDebugLog, "qdInterfaceCounter::data() %s", str.c_str());
|
||||
return str;
|
||||
}
|
||||
|
||||
bool qdInterfaceCounter::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceCounter::keyboard_handler(Common::KeyCode vkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
grScreenRegion qdInterfaceCounter::screen_region() const {
|
||||
Vect2i sz = Vect2i(size_x(), size_y());
|
||||
Vect2i pos = r();
|
||||
|
||||
return grScreenRegion(pos.x, pos.y, sz.x, sz.y);
|
||||
}
|
||||
|
||||
bool qdInterfaceCounter::init(bool is_game_active) {
|
||||
_counter = qdGameDispatcher::get_dispatcher()->get_counter(counterName());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceCounter::redraw() const {
|
||||
qdInterfaceElement::redraw();
|
||||
|
||||
if (_counter) {
|
||||
const grFont *font = qdGameDispatcher::get_dispatcher()->
|
||||
find_font(_textFormat.font_type());
|
||||
|
||||
Vect2i sz = Vect2i(size_x(), size_y());
|
||||
Vect2i pos = r() - sz / 2;
|
||||
grDispatcher::instance()->drawAlignedText(pos.x, pos.y, sz.x, sz.y,
|
||||
_textFormat.color(), data().c_str(), GR_ALIGN_LEFT, 0, 0, font);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceCounter::need_redraw() const {
|
||||
if (qdInterfaceElement::need_redraw())
|
||||
return true;
|
||||
|
||||
if (_counter)
|
||||
return _lastValue != _counter->value();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceCounter::post_redraw() {
|
||||
qdInterfaceElement::post_redraw();
|
||||
|
||||
if (_counter)
|
||||
_lastValue = _counter->value();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int qdInterfaceCounter::size_x() const {
|
||||
const grFont *font = qdGameDispatcher::get_dispatcher()->find_font(_textFormat.font_type());
|
||||
return grDispatcher::instance()->textWidth(data().c_str(), 0, font);
|
||||
}
|
||||
|
||||
int qdInterfaceCounter::size_y() const {
|
||||
const grFont *font = qdGameDispatcher::get_dispatcher()->find_font(_textFormat.font_type());
|
||||
return grDispatcher::instance()->textHeight(data().c_str(), 0, font);
|
||||
}
|
||||
|
||||
void qdInterfaceCounter::setCounter(const qdCounter *counter) {
|
||||
_counter = counter;
|
||||
_counterName = (counter) ? counter->name() : "";
|
||||
}
|
||||
|
||||
const char *qdInterfaceCounter::counterName() const {
|
||||
return _counterName.c_str();
|
||||
}
|
||||
|
||||
void qdInterfaceCounter::setCounterName(const char *name) {
|
||||
_counterName = name;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
115
engines/qdengine/qdcore/qd_interface_counter.h
Normal file
115
engines/qdengine/qdcore/qd_interface_counter.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_COUNTER_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_COUNTER_H
|
||||
|
||||
#include "qdengine/qdcore/qd_named_object_reference.h"
|
||||
#include "qdengine/qdcore/qd_screen_text.h"
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Interface widget for displaying a counter
|
||||
|
||||
class qdInterfaceCounter : public qdInterfaceElement {
|
||||
public:
|
||||
qdInterfaceCounter();
|
||||
qdInterfaceCounter(const qdInterfaceCounter &counter);
|
||||
~qdInterfaceCounter();
|
||||
|
||||
qdInterfaceCounter &operator = (const qdInterfaceCounter &counter);
|
||||
|
||||
//! Возвращает тип элемента.
|
||||
qdInterfaceElement::element_type get_element_type() const {
|
||||
return qdInterfaceElement::EL_COUNTER;
|
||||
}
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
|
||||
grScreenRegion screen_region() const;
|
||||
|
||||
//! Инициализация элемента.
|
||||
/**
|
||||
Вызывается каждый раз при заходе на экран, которому принадлежит элемент.
|
||||
*/
|
||||
bool init(bool is_game_active = true);
|
||||
|
||||
bool redraw() const;
|
||||
bool need_redraw() const;
|
||||
bool post_redraw();
|
||||
|
||||
//! Возвращает размер элемента по горизонтали в пикселах.
|
||||
int size_x() const;
|
||||
//! Возвращает размер элемента по вертикали в пикселах.
|
||||
int size_y() const;
|
||||
|
||||
/// количество отображаемых разрядов
|
||||
int digits() const {
|
||||
return _digits;
|
||||
}
|
||||
void setDigits(int digits) {
|
||||
_digits = digits;
|
||||
}
|
||||
|
||||
const qdScreenTextFormat &textFormat() const {
|
||||
return _textFormat;
|
||||
}
|
||||
void setTextFormat(const qdScreenTextFormat &text_format) {
|
||||
_textFormat = text_format;
|
||||
}
|
||||
|
||||
const qdCounter *counter() const {
|
||||
return _counter;
|
||||
}
|
||||
void setCounter(const qdCounter *counter);
|
||||
|
||||
const char *counterName() const;
|
||||
void setCounterName(const char *name);
|
||||
|
||||
protected:
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script_body(const xml::tag *p);
|
||||
|
||||
Common::String data() const;
|
||||
|
||||
private:
|
||||
|
||||
qdScreenTextFormat _textFormat;
|
||||
|
||||
int _digits;
|
||||
|
||||
Common::String _counterName;
|
||||
const qdCounter *_counter;
|
||||
|
||||
int _lastValue;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_COUNTER_H
|
||||
752
engines/qdengine/qdcore/qd_interface_dispatcher.cpp
Normal file
752
engines/qdengine/qdcore/qd_interface_dispatcher.cpp
Normal file
@@ -0,0 +1,752 @@
|
||||
/* 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/config-manager.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/savefile.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/system/input/mouse_input.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_interface_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_interface_screen.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state.h"
|
||||
#include "qdengine/qdcore/qd_interface_save.h"
|
||||
#include "qdengine/qdcore/qd_interface_button.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_game_object_moving.h"
|
||||
#include "qdengine/qdcore/qd_game_scene.h"
|
||||
#include "qdengine/qdcore/qd_setup.h"
|
||||
#include "qdengine/qdcore/qd_interface_text_window.h"
|
||||
#include "qdengine/qdcore/qd_resource.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceDispatcher *qdInterfaceDispatcher::_dispatcher = NULL;
|
||||
|
||||
qdInterfaceDispatcher::qdInterfaceDispatcher() : _cur_screen(NULL),
|
||||
_next_screen(NULL),
|
||||
_is_active(false),
|
||||
_is_mouse_hover(false),
|
||||
_autohide_disable(false),
|
||||
_need_full_redraw(false),
|
||||
_need_scene_redraw(false),
|
||||
_end_game_mode(false),
|
||||
_need_save_screenshot(true),
|
||||
_need_show_save_time(false),
|
||||
_need_show_save_title(false),
|
||||
_save_font_type(QD_FONT_TYPE_NONE),
|
||||
_save_font_color(0x00FFFFFF),
|
||||
_background_screen(NULL),
|
||||
_background_screen_lock(false),
|
||||
_modalScreenMode(MODAL_SCREEN_OTHER) {
|
||||
}
|
||||
|
||||
qdInterfaceDispatcher::~qdInterfaceDispatcher() {
|
||||
_screens.clear();
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::add_screen(qdInterfaceScreen *scr) {
|
||||
return _screens.add_object(scr);
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::rename_screen(qdInterfaceScreen *scr, const char *name) {
|
||||
return _screens.rename_object(scr, name);
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::remove_screen(qdInterfaceScreen *scr) {
|
||||
return _screens.remove_object(scr);
|
||||
}
|
||||
|
||||
qdInterfaceScreen *qdInterfaceDispatcher::get_screen(const char *screen_name) {
|
||||
if (!screen_name) return NULL;
|
||||
|
||||
return _screens.get_object(screen_name);
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::is_screen_in_list(const qdInterfaceScreen *scr) {
|
||||
return _screens.is_in_list(scr);
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::select_screen(const char *screen_name, bool lock_resources) {
|
||||
qdInterfaceScreen *p = get_screen(screen_name);
|
||||
|
||||
if (p) {
|
||||
if (_cur_screen && _cur_screen->is_locked()) {
|
||||
debugC(3, kDebugQuant, "qdInterfaceDispatcher::select_screen() Selecting screen: %s", transCyrillic(screen_name));
|
||||
for (resource_container_t::resource_list_t::const_iterator it = _resources.resource_list().begin(); it != _resources.resource_list().end(); ++it) {
|
||||
if (p->has_references(*it)) {
|
||||
if (!(*it)->is_resource_loaded()) {
|
||||
debugC(3, kDebugQuant, "qdInterfaceDispatcher::select_screen() Resource is used in both screens %s and %s", transCyrillic(_cur_screen->name()), transCyrillic(p->name()));
|
||||
(*it)->load_resource();
|
||||
}
|
||||
} else {
|
||||
if ((*it)->is_resource_loaded() && !_cur_screen->has_references(*it))
|
||||
(*it)->free_resource();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (resource_container_t::resource_list_t::const_iterator it = _resources.resource_list().begin(); it != _resources.resource_list().end(); ++it) {
|
||||
if (p->has_references(*it)) {
|
||||
if (!(*it)->is_resource_loaded())
|
||||
(*it)->load_resource();
|
||||
} else {
|
||||
if ((*it)->is_resource_loaded())
|
||||
(*it)->free_resource();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_cur_screen && _cur_screen->is_locked()) {
|
||||
for (resource_container_t::resource_list_t::const_iterator it = _resources.resource_list().begin(); it != _resources.resource_list().end(); ++it) {
|
||||
if ((*it)->is_resource_loaded() && !_cur_screen->has_references(*it))
|
||||
(*it)->free_resource();
|
||||
}
|
||||
} else {
|
||||
for (resource_container_t::resource_list_t::const_iterator it = _resources.resource_list().begin(); it != _resources.resource_list().end(); ++it) {
|
||||
if ((*it)->is_resource_loaded())
|
||||
(*it)->free_resource();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p && _cur_screen != p)
|
||||
p->set_autohide_phase(1.0f);
|
||||
|
||||
_cur_screen = p;
|
||||
|
||||
if (_cur_screen) {
|
||||
debugC(3, kDebugQuant, "qdInterfaceDispatcher::select_screen() if(cur_scene_): %s", transCyrillic(screen_name));
|
||||
bool is_game_active = false;
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
if (dp->get_active_scene())
|
||||
is_game_active = true;
|
||||
|
||||
if (_cur_screen->has_music_track())
|
||||
dp->play_music_track(&_cur_screen->music_track(), true);
|
||||
}
|
||||
|
||||
_cur_screen->init(is_game_active);
|
||||
if (lock_resources)
|
||||
_cur_screen->lock_resources();
|
||||
}
|
||||
|
||||
_need_full_redraw = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::select_background_screen(qdInterfaceScreen *p) {
|
||||
if (_background_screen && _background_screen != p) {
|
||||
if (!_background_screen_lock)
|
||||
_background_screen->unlock_resources();
|
||||
_background_screen = 0;
|
||||
_need_full_redraw = true;
|
||||
}
|
||||
|
||||
if (p) {
|
||||
_background_screen = p;
|
||||
_background_screen_lock = p->is_locked();
|
||||
p->lock_resources();
|
||||
_need_full_redraw = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::select_ingame_screen(bool inventory_state) {
|
||||
if (has_ingame_screen(inventory_state)) {
|
||||
debugC(3, kDebugQuant, "qdInterfaceDispatcher::select_ingame_screen(): Selecting ingame screen: %s", transCyrillic(ingame_screen_name(inventory_state)));
|
||||
return select_screen(ingame_screen_name(inventory_state), true);
|
||||
}
|
||||
|
||||
return select_screen(NULL);
|
||||
}
|
||||
|
||||
qdResource *qdInterfaceDispatcher::add_resource(const Common::Path &file_name, const qdInterfaceElementState *owner) {
|
||||
return _resources.add_resource(file_name, owner);
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::remove_resource(const Common::Path &file_name, const qdInterfaceElementState *owner) {
|
||||
return _resources.remove_resource(file_name, owner);
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::redraw(int dx, int dy) const {
|
||||
if (_background_screen)
|
||||
_background_screen->redraw(dx, dy);
|
||||
|
||||
if (_cur_screen)
|
||||
return _cur_screen->redraw(dx, dy);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::pre_redraw() {
|
||||
if (_cur_screen)
|
||||
_cur_screen->pre_redraw(_need_full_redraw);
|
||||
|
||||
if (_background_screen)
|
||||
_background_screen->pre_redraw(_need_full_redraw);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::post_redraw() {
|
||||
_need_full_redraw = false;
|
||||
|
||||
if (_cur_screen)
|
||||
return _cur_screen->post_redraw();
|
||||
|
||||
if (_background_screen)
|
||||
_background_screen->post_redraw();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::quant(float dt) {
|
||||
if (_next_screen) {
|
||||
select_screen(_next_screen);
|
||||
set_next_screen(NULL);
|
||||
}
|
||||
|
||||
if (_cur_screen)
|
||||
return _cur_screen->quant(dt);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
debugC(9, kDebugInput, "qdInterfaceDispatcher::mouse_handler() x: %d, y: %d, ev: %d", x, y, ev);
|
||||
_is_mouse_hover = false;
|
||||
_autohide_disable = false;
|
||||
|
||||
if (_end_game_mode) {
|
||||
debugC(3, kDebugInput, "qdInterfaceDispatcher::mouse_handler() _end_game_mode: %d", _end_game_mode);
|
||||
if (ev == mouseDispatcher::EV_LEFT_DOWN || ev == mouseDispatcher::EV_RIGHT_DOWN) {
|
||||
handle_event(qdInterfaceEvent::EVENT_CHANGE_INTERFACE_SCREEN, main_menu_screen_name());
|
||||
_end_game_mode = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_cur_screen) {
|
||||
debugC(9, kDebugInput, "qdInterfaceDispatcher::mouse_handler() _cur_screen");
|
||||
return _cur_screen->mouse_handler(x, y, ev);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::keyboard_handler(Common::KeyCode vkey) {
|
||||
if (_cur_screen) {
|
||||
if (vkey == Common::KEYCODE_ESCAPE && has_main_menu()) {
|
||||
if (_cur_screen->name() && !strcmp(_cur_screen->name(), main_menu_screen_name()))
|
||||
handle_event(qdInterfaceEvent::EVENT_RESUME_GAME, NULL);
|
||||
else {
|
||||
if (qdGameDispatcher::get_dispatcher()->is_main_menu_exit_enabled())
|
||||
select_screen(main_menu_screen_name());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return _cur_screen->keyboard_handler(vkey);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::char_input_handler(int vkey) {
|
||||
if (_cur_screen)
|
||||
return _cur_screen->char_input_handler(vkey);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<interface");
|
||||
|
||||
if (has_main_menu()) {
|
||||
fh.writeString(Common::String::format(" main_menu=\"%s\"", qdscr_XML_string(main_menu_screen_name())));
|
||||
}
|
||||
|
||||
if (need_scene_redraw()) {
|
||||
fh.writeString(" draw_scene=\"1\"");
|
||||
}
|
||||
|
||||
if (has_ingame_screen(false)) {
|
||||
fh.writeString(Common::String::format(" ingame_screen0=\"%s\"", qdscr_XML_string(ingame_screen_name(false))));
|
||||
}
|
||||
|
||||
if (has_ingame_screen(true)) {
|
||||
fh.writeString(Common::String::format(" ingame_screen1=\"%s\"", qdscr_XML_string(ingame_screen_name(true))));
|
||||
}
|
||||
|
||||
if (!_save_prompt_screen_name.empty()) {
|
||||
fh.writeString(Common::String::format(" save_prompt_screen=\"%s\"", qdscr_XML_string(_save_prompt_screen_name.c_str())));
|
||||
}
|
||||
|
||||
if (!_save_title_screen_name.empty()) {
|
||||
fh.writeString(Common::String::format(" save_title_screen=\"%s\"", qdscr_XML_string(_save_title_screen_name.c_str())));
|
||||
}
|
||||
|
||||
// Значение по умолчанию - true, значит сохраняем только false
|
||||
if (!_need_save_screenshot) {
|
||||
fh.writeString(" need_save_screenshot=\"0\"");
|
||||
}
|
||||
|
||||
if (_need_show_save_time) {
|
||||
fh.writeString(" need_show_save_time=\"1\"");
|
||||
}
|
||||
|
||||
if (_need_show_save_title) {
|
||||
fh.writeString(" need_show_save_name=\"1\"");
|
||||
}
|
||||
|
||||
if (QD_FONT_TYPE_NONE != _save_font_type) {
|
||||
fh.writeString(Common::String::format(" save_font_type=\"%d\"", _save_font_type));
|
||||
}
|
||||
|
||||
if (0x00FFFFFF != _save_font_color) {
|
||||
fh.writeString(Common::String::format(" save_font_color=\"%d\"", _save_font_color));
|
||||
}
|
||||
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
|
||||
for (auto &it : screen_list()) {
|
||||
it->save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("</interface>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::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_INTERFACE_SCENE_REDRAW:
|
||||
set_scene_redraw(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_INTERFACE_SCREEN: {
|
||||
qdInterfaceScreen *scr = new qdInterfaceScreen;
|
||||
scr->set_owner(this);
|
||||
scr->load_script(&*it);
|
||||
add_screen(scr);
|
||||
}
|
||||
break;
|
||||
case QDSCR_INTERFACE_MAIN_MENU:
|
||||
set_main_menu_screen(it->data());
|
||||
break;
|
||||
case QDSCR_INTERFACE_INGAME_SCREEN0:
|
||||
_ingame_screen_names[0] = it->data();
|
||||
break;
|
||||
case QDSCR_INTERFACE_INGAME_SCREEN1:
|
||||
_ingame_screen_names[1] = it->data();
|
||||
break;
|
||||
case QDSCR_INTERFACE_SAVE_PROMPT_SCREEN:
|
||||
_save_prompt_screen_name = it->data();
|
||||
break;
|
||||
case QDSCR_INTERFACE_SAVE_NAME_SCREEN:
|
||||
_save_title_screen_name = it->data();
|
||||
break;
|
||||
case QDSCR_INTERFACE_NEED_SAVE_SCREENSHOT:
|
||||
_need_save_screenshot = (0 != xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_INTERFACE_NEED_SHOW_SAVE_TIME:
|
||||
_need_show_save_time = (0 != xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_INTERFACE_NEED_SHOW_SAVE_NAME:
|
||||
_need_show_save_title = (0 != xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_INTERFACE_SAVE_FONT_TYPE:
|
||||
_save_font_type = xml::tag_buffer(*it).get_int();
|
||||
break;
|
||||
case QDSCR_INTERFACE_SAVE_FONT_COLOR:
|
||||
_save_font_color = xml::tag_buffer(*it).get_int();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdInterfaceDispatcher::set_main_menu_screen(const char *name) {
|
||||
if (name)
|
||||
_main_menu_screen_name = name;
|
||||
else
|
||||
_main_menu_screen_name.clear();
|
||||
}
|
||||
|
||||
void qdInterfaceDispatcher::set_ingame_screen(const char *name, bool inventory_state) {
|
||||
if (name)
|
||||
_ingame_screen_names[inventory_state] = name;
|
||||
else
|
||||
_ingame_screen_names[inventory_state].clear();
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::handle_event(int event_code, const char *event_data, qdInterfaceObjectBase *sender) {
|
||||
switch (event_code) {
|
||||
case qdInterfaceEvent::EVENT_EXIT:
|
||||
if (qdGameDispatcher * p = qd_get_game_dispatcher()) {
|
||||
p->toggle_exit();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_CHANGE_INTERFACE_SCREEN:
|
||||
if (event_data) {
|
||||
if (has_main_menu() && !strcmp(main_menu_screen_name(), event_data)) {
|
||||
if (qdGameDispatcher * p = qdGameDispatcher::get_dispatcher()) {
|
||||
p->set_flag(qdGameDispatcher::MAIN_MENU_FLAG);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
set_next_screen(event_data);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case qdInterfaceEvent::EVENT_TMP_HIDE_ELEMENT:
|
||||
if (_cur_screen)
|
||||
return _cur_screen->hide_element(event_data, true);
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_HIDE_ELEMENT:
|
||||
if (_cur_screen)
|
||||
return _cur_screen->hide_element(event_data);
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_SHOW_ELEMENT:
|
||||
if (_cur_screen)
|
||||
return _cur_screen->show_element(event_data);
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_RESUME_GAME:
|
||||
if (qdGameDispatcher * p = qd_get_game_dispatcher()) {
|
||||
if (p->get_active_scene())
|
||||
return p->toggle_main_menu(false);
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_SET_SAVE_MODE:
|
||||
qdInterfaceSave::set_save_mode(true);
|
||||
return true;
|
||||
case qdInterfaceEvent::EVENT_SET_LOAD_MODE:
|
||||
qdInterfaceSave::set_save_mode(false);
|
||||
return true;
|
||||
case qdInterfaceEvent::EVENT_NEW_GAME:
|
||||
if (qdGameDispatcher * p = qd_get_game_dispatcher()) {
|
||||
p->toggle_main_menu(false);
|
||||
return p->restart();
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_ACTIVATE_PERSONAGE:
|
||||
if (!event_data) return false;
|
||||
if (qdGameDispatcher * p = qd_get_game_dispatcher()) {
|
||||
if (qdGameScene * sp = p->get_active_scene()) {
|
||||
qdGameObjectMoving *obj = dynamic_cast<qdGameObjectMoving *>(sp->get_object(event_data));
|
||||
if (!obj || obj == sp->get_active_personage()) return false;
|
||||
sp->set_active_personage(obj);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_CHANGE_PERSONAGE:
|
||||
if (qdGameDispatcher * p = qd_get_game_dispatcher()) {
|
||||
if (qdGameScene * sp = p->get_active_scene()) {
|
||||
sp->change_active_personage();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_PREV_ELEMENT_STATE:
|
||||
if (_cur_screen && event_data) {
|
||||
if (qdInterfaceButton * p = dynamic_cast<qdInterfaceButton * >(_cur_screen->get_element(event_data)))
|
||||
return p->change_state(false);
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_NEXT_ELEMENT_STATE:
|
||||
if (_cur_screen && event_data) {
|
||||
if (qdInterfaceButton * p = dynamic_cast<qdInterfaceButton * >(_cur_screen->get_element(event_data)))
|
||||
return p->change_state(true);
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_MAIN_MENU:
|
||||
if (qdGameDispatcher * p = qdGameDispatcher::get_dispatcher()) {
|
||||
p->set_flag(qdGameDispatcher::MAIN_MENU_FLAG);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_PLAY_VIDEO:
|
||||
if (event_data) {
|
||||
if (qdGameDispatcher * p = qdGameDispatcher::get_dispatcher()) {
|
||||
if (p->play_video(event_data)) {
|
||||
p->pause();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_BUTTON_STATE:
|
||||
if (_cur_screen && event_data) {
|
||||
Common::String str = event_data;
|
||||
size_t pos = str.find("::");
|
||||
if (pos != Common::String::npos) {
|
||||
if (qdInterfaceButton * p = dynamic_cast<qdInterfaceButton * >(_cur_screen->get_element(str.substr(0, pos).c_str()))) {
|
||||
return p->activate_state(str.substr(pos + 2).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_CLEAR_MOUSE:
|
||||
if (qdGameDispatcher * p = qdGameDispatcher::get_dispatcher()) {
|
||||
return p->drop_mouse_object();
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_LOAD_SCENE:
|
||||
if (event_data) {
|
||||
if (qdGameDispatcher * p = qdGameDispatcher::get_dispatcher()) {
|
||||
if (qdGameScene * sp = p->get_scene(event_data)) {
|
||||
p->set_next_scene(sp);
|
||||
p->activate_trigger_links(sp);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_SCROLL_LEFT:
|
||||
case qdInterfaceEvent::EVENT_SCROLL_RIGHT:
|
||||
case qdInterfaceEvent::EVENT_SCROLL_UP:
|
||||
case qdInterfaceEvent::EVENT_SCROLL_DOWN:
|
||||
if (qdGameDispatcher * p = qdGameDispatcher::get_dispatcher()) {
|
||||
if (!p->get_active_personage())
|
||||
break;
|
||||
if (qdInventory * sp = p->get_inventory(p->get_active_personage()->inventory_name())) {
|
||||
if (qdInterfaceEvent::EVENT_SCROLL_LEFT == event_code)
|
||||
sp->scroll_left();
|
||||
else if (qdInterfaceEvent::EVENT_SCROLL_RIGHT == event_code)
|
||||
sp->scroll_right();
|
||||
else if (qdInterfaceEvent::EVENT_SCROLL_UP == event_code)
|
||||
sp->scroll_up();
|
||||
else sp->scroll_down();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_SHOW_INTERFACE_SCREEN_AS_MODAL:
|
||||
if (event_data) {
|
||||
if (qdInterfaceScreen * screen = get_screen(event_data))
|
||||
screen->set_modal_caller(sender);
|
||||
select_background_screen(_cur_screen);
|
||||
select_screen(event_data);
|
||||
if (_modalScreenMode == MODAL_SCREEN_SAVE_NAME_EDIT) {
|
||||
if (qdInterfaceSave * save = dynamic_cast<qdInterfaceSave * >(sender))
|
||||
set_save_title(save->title());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case qdInterfaceEvent::EVENT_MODAL_OK:
|
||||
case qdInterfaceEvent::EVENT_MODAL_CANCEL:
|
||||
if (sender) {
|
||||
select_background_screen(0);
|
||||
// Определяем экран, от которого пришло событие
|
||||
qdInterfaceScreen *screen_ptr = NULL;
|
||||
if (sender->owner())
|
||||
screen_ptr = dynamic_cast<qdInterfaceScreen * >(sender->owner());
|
||||
if (!screen_ptr)
|
||||
screen_ptr = dynamic_cast<qdInterfaceScreen * >(sender);
|
||||
if (!screen_ptr) {
|
||||
assert(0 && "Не найден экран, от которого пришло событие модального типа");
|
||||
return true; // Сообщение все же обработано
|
||||
}
|
||||
// Обрабатываем положительную реакцию пользователя на запрос
|
||||
qdInterfaceObjectBase *modal_caller_ptr = screen_ptr->modal_caller();
|
||||
if (!modal_caller_ptr) return false;
|
||||
|
||||
if (_modalScreenMode == MODAL_SCREEN_SAVE_OVERWRITE) {
|
||||
if (qdInterfaceEvent::EVENT_MODAL_OK == event_code) {
|
||||
if (qdInterfaceSave * save = dynamic_cast<qdInterfaceSave * >(modal_caller_ptr)) {
|
||||
save->set_title(_save_title.c_str());
|
||||
save->perform_save();
|
||||
handle_event(qdInterfaceEvent::EVENT_RESUME_GAME, NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (_modalScreenMode == MODAL_SCREEN_SAVE_NAME_EDIT) {
|
||||
if (qdInterfaceEvent::EVENT_MODAL_OK == event_code) {
|
||||
_save_title = get_save_title();
|
||||
if (qdInterfaceSave *save = dynamic_cast<qdInterfaceSave * >(modal_caller_ptr)) {
|
||||
if (has_save_prompt_screen() && g_engine->getSaveFileManager()->exists(g_engine->getSaveStateName(save->save_ID()))) {
|
||||
setModalScreenMode(qdInterfaceDispatcher::MODAL_SCREEN_SAVE_OVERWRITE);
|
||||
screen_ptr = dynamic_cast<qdInterfaceScreen *>(modal_caller_ptr->owner());
|
||||
if (!screen_ptr)
|
||||
screen_ptr = dynamic_cast<qdInterfaceScreen * >(modal_caller_ptr);
|
||||
if (screen_ptr)
|
||||
select_screen(screen_ptr->name());
|
||||
|
||||
handle_event(qdInterfaceEvent::EVENT_SHOW_INTERFACE_SCREEN_AS_MODAL, save_prompt_screen_name(), save);
|
||||
return true;
|
||||
} else {
|
||||
save->set_title(_save_title.c_str());
|
||||
save->perform_save();
|
||||
handle_event(qdInterfaceEvent::EVENT_RESUME_GAME, NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
screen_ptr = dynamic_cast<qdInterfaceScreen *>(modal_caller_ptr->owner());
|
||||
if (!screen_ptr)
|
||||
screen_ptr = dynamic_cast<qdInterfaceScreen * >(modal_caller_ptr);
|
||||
if (!screen_ptr) {
|
||||
assert(0 && "Не найден экран, от которого пришло событие модального типа");
|
||||
return true;
|
||||
}
|
||||
select_screen(screen_ptr->name());
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int qdInterfaceDispatcher::option_value(int option_id, const char *option_data) {
|
||||
switch (option_id) {
|
||||
case qdInterfaceElement::OPTION_SOUND:
|
||||
return ConfMan.getBool("enable_sound");
|
||||
case qdInterfaceElement::OPTION_SOUND_VOLUME:
|
||||
return ConfMan.getInt("sound_volume");
|
||||
case qdInterfaceElement::OPTION_MUSIC:
|
||||
return ConfMan.getBool("enable_music");
|
||||
case qdInterfaceElement::OPTION_MUSIC_VOLUME:
|
||||
return ConfMan.getInt("music_volume");
|
||||
case qdInterfaceElement::OPTION_ACTIVE_PERSONAGE:
|
||||
if (option_data) {
|
||||
if (qdGameObjectMoving * p = qdGameDispatcher::get_dispatcher()->get_active_personage()) {
|
||||
if (!strcmp(p->name(), option_data)) return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool qdInterfaceDispatcher::set_option_value(int option_id, int value, const char *option_data) {
|
||||
switch (option_id) {
|
||||
case qdInterfaceElement::OPTION_SOUND:
|
||||
ConfMan.setBool("enable_sound", value > 0);
|
||||
ConfMan.flushToDisk();
|
||||
g_engine->syncSoundSettings();
|
||||
return true;
|
||||
case qdInterfaceElement::OPTION_SOUND_VOLUME:
|
||||
ConfMan.setInt("sound_volume", value);
|
||||
ConfMan.flushToDisk();
|
||||
g_engine->syncSoundSettings();
|
||||
return true;
|
||||
case qdInterfaceElement::OPTION_MUSIC:
|
||||
ConfMan.setBool("enable_music", value > 0);
|
||||
ConfMan.flushToDisk();
|
||||
g_engine->syncSoundSettings();
|
||||
return true;
|
||||
case qdInterfaceElement::OPTION_MUSIC_VOLUME:
|
||||
ConfMan.setInt("music_volume", value);
|
||||
ConfMan.flushToDisk();
|
||||
g_engine->syncSoundSettings();
|
||||
return true;
|
||||
case qdInterfaceElement::OPTION_ACTIVE_PERSONAGE:
|
||||
if (option_data) {
|
||||
if (qdGameScene * sp = qdGameDispatcher::get_dispatcher()->get_active_scene()) {
|
||||
qdGameObjectMoving *obj = dynamic_cast<qdGameObjectMoving *>(sp->get_object(option_data));
|
||||
if (!obj || obj == sp->get_active_personage()) return false;
|
||||
sp->set_active_personage(obj);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdInterfaceDispatcher::update_personage_buttons() {
|
||||
if (_cur_screen)
|
||||
_cur_screen->update_personage_buttons();
|
||||
}
|
||||
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
bool qdInterfaceDispatcher::get_resources_info(qdResourceInfoContainer &infos) const {
|
||||
for (resource_container_t::resource_list_t::const_iterator it = _resources.resource_list().begin(); it != _resources.resource_list().end(); ++it) {
|
||||
if ((*it)->is_resource_loaded())
|
||||
infos.push_back(qdResourceInfo(*it));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool qdInterfaceDispatcher::set_save_title(const char *title) {
|
||||
if (!_cur_screen)
|
||||
return false;
|
||||
|
||||
const qdInterfaceScreen::element_list_t &lst = _cur_screen->element_list();
|
||||
for (qdInterfaceScreen::element_list_t::const_iterator it = lst.begin(); it != lst.end(); ++it) {
|
||||
if ((*it)->get_element_type() == qdInterfaceElement::EL_TEXT_WINDOW) {
|
||||
qdInterfaceTextWindow *wnd = static_cast<qdInterfaceTextWindow *>(*it);
|
||||
if (wnd->windowType() == qdInterfaceTextWindow::WINDOW_EDIT) {
|
||||
wnd->set_input_string(title);
|
||||
wnd->edit_start();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *qdInterfaceDispatcher::get_save_title() const {
|
||||
if (!_cur_screen)
|
||||
return nullptr;
|
||||
|
||||
const qdInterfaceScreen::element_list_t &lst = _cur_screen->element_list();
|
||||
for (qdInterfaceScreen::element_list_t::const_iterator it = lst.begin(); it != lst.end(); ++it) {
|
||||
if ((*it)->get_element_type() == qdInterfaceElement::EL_TEXT_WINDOW) {
|
||||
qdInterfaceTextWindow *wnd = static_cast<qdInterfaceTextWindow *>(*it);
|
||||
if (wnd->windowType() == qdInterfaceTextWindow::WINDOW_EDIT)
|
||||
return wnd->input_string();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
341
engines/qdengine/qdcore/qd_interface_dispatcher.h
Normal file
341
engines/qdengine/qdcore/qd_interface_dispatcher.h
Normal file
@@ -0,0 +1,341 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_DISPATCHER_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_DISPATCHER_H
|
||||
|
||||
#include "common/keyboard.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_resource_container.h"
|
||||
#include "qdengine/qdcore/qd_interface_object_base.h"
|
||||
#include "qdengine/qdcore/qd_object_list_container.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdInterfaceScreen;
|
||||
class qdInterfaceElementState;
|
||||
|
||||
class qdInterfaceDispatcher : public qdInterfaceObjectBase {
|
||||
public:
|
||||
qdInterfaceDispatcher();
|
||||
~qdInterfaceDispatcher();
|
||||
|
||||
/// для чего вызван модальный экран
|
||||
enum ModalScreenMode {
|
||||
MODAL_SCREEN_SAVE_OVERWRITE,
|
||||
MODAL_SCREEN_SAVE_NAME_EDIT,
|
||||
MODAL_SCREEN_OTHER
|
||||
};
|
||||
|
||||
//! Отрисовка интерфейса.
|
||||
bool redraw(int dx = 0, int dy = 0) const;
|
||||
bool pre_redraw();
|
||||
bool post_redraw();
|
||||
|
||||
//! Обсчет логики, параметр - время в секундах.
|
||||
bool quant(float dt);
|
||||
|
||||
//! Добавление экрана.
|
||||
bool add_screen(qdInterfaceScreen *scr);
|
||||
//! Изменение имени экрана.
|
||||
bool rename_screen(qdInterfaceScreen *scr, const char *name);
|
||||
//! Удаление экрана из списка.
|
||||
bool remove_screen(qdInterfaceScreen *scr);
|
||||
//! Поиск экрана по имени.
|
||||
qdInterfaceScreen *get_screen(const char *screen_name);
|
||||
//! Возвращает true, если экран есть в списке.
|
||||
bool is_screen_in_list(const qdInterfaceScreen *scr);
|
||||
|
||||
typedef Std::list<qdInterfaceScreen *> screen_list_t;
|
||||
//! Возвращает список экранов.
|
||||
const screen_list_t &screen_list() const {
|
||||
return _screens.get_list();
|
||||
}
|
||||
|
||||
//! Установка активного экрана.
|
||||
/**
|
||||
Имя можно передавать нулевое, для сброса активного экрана.
|
||||
*/
|
||||
bool select_screen(const char *screen_name, bool lock_resources = false);
|
||||
/// Установка фонового экрана.
|
||||
bool select_background_screen(qdInterfaceScreen *p);
|
||||
|
||||
//! Включает внутриигровой интерфейс.
|
||||
bool select_ingame_screen(bool inventory_state = false);
|
||||
|
||||
//! Включает кнопки, связанные с персонажем p, выключает кнопки остальных персонажей.
|
||||
void update_personage_buttons();
|
||||
|
||||
qdInterfaceScreen *selected_screen() const {
|
||||
return _cur_screen;
|
||||
}
|
||||
|
||||
//! Возвращает true, если экран p в данный момент активен.
|
||||
bool is_screen_active(const qdInterfaceScreen *p) const {
|
||||
return (_cur_screen == p);
|
||||
}
|
||||
|
||||
//! Добавляет ресурс file_name с владельцем owner.
|
||||
qdResource *add_resource(const Common::Path &file_name, const qdInterfaceElementState *owner);
|
||||
//! Удаляет ресурс file_name с владельцем owner.
|
||||
bool remove_resource(const Common::Path &file_name, const qdInterfaceElementState *owner);
|
||||
//! Возвращает указатель на ресурс file_name.
|
||||
qdResource *get_resource(const Common::Path &file_name) const {
|
||||
return _resources.get_resource(file_name);
|
||||
}
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
bool char_input_handler(int vkey);
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
|
||||
//! Установка имени экрана с главным меню игры.
|
||||
void set_main_menu_screen(const char *name);
|
||||
//! Возвращает имя экрана с главным меню игры.
|
||||
const char *main_menu_screen_name() const {
|
||||
return _main_menu_screen_name.c_str();
|
||||
}
|
||||
//! Возвращает true, если установлено имя экрана с главным меню игры.
|
||||
bool has_main_menu() const {
|
||||
return !_main_menu_screen_name.empty();
|
||||
}
|
||||
|
||||
//! Установка имени внутриигрового экрана.
|
||||
void set_ingame_screen(const char *name, bool inventory_state = false);
|
||||
//! Возвращает имя внутриигрового экрана.
|
||||
const char *ingame_screen_name(bool inventory_state = false) const {
|
||||
return _ingame_screen_names[inventory_state].c_str();
|
||||
}
|
||||
//! Возвращает true, если установлено имя внутриигрового экрана.
|
||||
bool has_ingame_screen(bool inventory_state = false) const {
|
||||
return !_ingame_screen_names[inventory_state].empty();
|
||||
}
|
||||
|
||||
//! Имя модального экрана подсказки: перезаписывать сэйв или нет.
|
||||
const char *save_prompt_screen_name() const {
|
||||
return _save_prompt_screen_name.c_str();
|
||||
}
|
||||
void set_save_prompt_screen_name(const char *str) {
|
||||
if (str) _save_prompt_screen_name = str;
|
||||
else _save_prompt_screen_name = "";
|
||||
}
|
||||
bool has_save_prompt_screen() const {
|
||||
return !_save_prompt_screen_name.empty();
|
||||
}
|
||||
|
||||
const char *save_title_screen_name() const {
|
||||
return _save_title_screen_name.c_str();
|
||||
}
|
||||
void set_save_title_screen_name(const char *name) {
|
||||
_save_title_screen_name = name;
|
||||
}
|
||||
bool has_save_title_screen() const {
|
||||
return !_save_title_screen_name.empty();
|
||||
}
|
||||
|
||||
//! Нужно ли выводить скриншот к сохраненке
|
||||
bool need_save_screenshot() const {
|
||||
return _need_save_screenshot;
|
||||
}
|
||||
void toggle_save_screenshot(bool state) {
|
||||
_need_save_screenshot = state;
|
||||
}
|
||||
//! Нужно ли выводить дату и время при отображении сэйва
|
||||
bool need_show_save_time() const {
|
||||
return _need_show_save_time;
|
||||
}
|
||||
void toggle_show_save_time(bool state) {
|
||||
_need_show_save_time = state;
|
||||
}
|
||||
bool need_show_save_title() const {
|
||||
return _need_show_save_title;
|
||||
}
|
||||
void toggle_show_save_title(bool state) {
|
||||
_need_show_save_title = state;
|
||||
}
|
||||
//! Тип шрифт, которым выводится текст сэйва (в частности дата и время)
|
||||
int save_font_type() const {
|
||||
return _save_font_type;
|
||||
}
|
||||
void set_save_font_type(int type) {
|
||||
_save_font_type = type;
|
||||
}
|
||||
//! Цвет, которым выводится текст сэйва (в частности дата и время)
|
||||
int save_font_color() const {
|
||||
return _save_font_color;
|
||||
}
|
||||
void set_save_font_color(int clr) {
|
||||
_save_font_color = clr;
|
||||
}
|
||||
|
||||
//! Возвращает true, если интерфейс отрисовывается поверх сцены.
|
||||
bool need_scene_redraw() const {
|
||||
return _need_scene_redraw;
|
||||
}
|
||||
//! Устанавливает, надо ли если интерфейсу отрисовываться поверх сцены.
|
||||
void set_scene_redraw(bool state) {
|
||||
_need_scene_redraw = state;
|
||||
}
|
||||
|
||||
static void set_dispatcher(qdInterfaceDispatcher *p) {
|
||||
_dispatcher = p;
|
||||
}
|
||||
static qdInterfaceDispatcher *get_dispatcher() {
|
||||
return _dispatcher;
|
||||
}
|
||||
|
||||
void activate() {
|
||||
_is_active = true;
|
||||
}
|
||||
void deactivate() {
|
||||
_is_active = false;
|
||||
}
|
||||
bool is_active() const {
|
||||
return _is_active;
|
||||
}
|
||||
|
||||
bool is_mouse_hover() const {
|
||||
return _is_mouse_hover;
|
||||
}
|
||||
void toggle_mouse_hover() {
|
||||
_is_mouse_hover = true;
|
||||
}
|
||||
bool is_autohide_enabled() const {
|
||||
return !_autohide_disable;
|
||||
}
|
||||
void disable_autohide() {
|
||||
_autohide_disable = true;
|
||||
}
|
||||
|
||||
ModalScreenMode modalScreenMode() const {
|
||||
return _modalScreenMode;
|
||||
}
|
||||
void setModalScreenMode(ModalScreenMode mode) {
|
||||
_modalScreenMode = mode;
|
||||
}
|
||||
|
||||
bool set_save_title(const char *title);
|
||||
const char *get_save_title() const;
|
||||
|
||||
/**
|
||||
Обработка события.
|
||||
sender - тот, кто послал событие на выполнение. NULL - sender не известен.
|
||||
*/
|
||||
bool handle_event(int event_code, const char *event_data, qdInterfaceObjectBase *sender = NULL);
|
||||
|
||||
void toggle_end_game_mode(bool state) {
|
||||
_end_game_mode = state;
|
||||
}
|
||||
|
||||
//! Устанавливает следующий экран.
|
||||
void set_next_screen(const char *screen_name) {
|
||||
_next_screen = screen_name;
|
||||
}
|
||||
|
||||
static int option_value(int option_id, const char *option_data = NULL);
|
||||
static bool set_option_value(int option_id, int value, const char *oprtion_data = NULL);
|
||||
|
||||
#ifdef __QD_DEBUG_ENABLE__
|
||||
bool get_resources_info(qdResourceInfoContainer &infos) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
//! Активный интерфейсный экран.
|
||||
qdInterfaceScreen *_cur_screen;
|
||||
|
||||
/// Фоновый экран, рисуется под активным
|
||||
qdInterfaceScreen *_background_screen;
|
||||
/// true если ресурсы фонового экрана не надо выгружать
|
||||
bool _background_screen_lock;
|
||||
|
||||
ModalScreenMode _modalScreenMode;
|
||||
|
||||
//! Имя экрана с главным меню игры
|
||||
Common::String _main_menu_screen_name;
|
||||
|
||||
//! Имена экраноы с внутриигровым интерфейсом.
|
||||
/**
|
||||
Первый экран показывается когда инвентори спрятано, вотрой - когда оно активно.
|
||||
*/
|
||||
Common::String _ingame_screen_names[2];
|
||||
|
||||
/// Экран ввода имени сэйва
|
||||
Common::String _save_title_screen_name;
|
||||
Common::String _save_title;
|
||||
|
||||
//! Экран, вызывающийся при подтверждении перезаписи файла сэйва
|
||||
Common::String _save_prompt_screen_name;
|
||||
|
||||
//! Нужно ли выводить скриншот к сохраненке
|
||||
bool _need_save_screenshot;
|
||||
//! Нужно ли выводить дату и время при отображении сэйва
|
||||
bool _need_show_save_time;
|
||||
//! Нужно ли выводить имя при отображении сэйва
|
||||
bool _need_show_save_title;
|
||||
//! Тип шрифта, которым выводится текст сэйва (в частности дата и время)
|
||||
int _save_font_type;
|
||||
//! Цвет, которым выводится текст сэйва (в частности дата и время)
|
||||
int _save_font_color;
|
||||
|
||||
//! Интерфейсные экраны.
|
||||
qdObjectListContainer<qdInterfaceScreen> _screens;
|
||||
|
||||
typedef qdResourceContainer<qdInterfaceElementState> resource_container_t;
|
||||
//! Интерфейсные ресурсы.
|
||||
resource_container_t _resources;
|
||||
|
||||
//! Равно true, если интерфейс активен.
|
||||
bool _is_active;
|
||||
|
||||
//! Равно true, если курсор мыши попадает в интерфейс.
|
||||
bool _is_mouse_hover;
|
||||
/// true если надо показывать
|
||||
bool _autohide_disable;
|
||||
|
||||
//! Равно true, если требуется полная отрисовка интерфейса, после отрисовки скидывается.
|
||||
bool _need_full_redraw;
|
||||
|
||||
//! Равно true, если отрисовка сцены под интерфейсом.
|
||||
bool _need_scene_redraw;
|
||||
|
||||
//! Режим окончания игры - после любого клика возврат с текущего экрана в главное меню.
|
||||
//! После загрузки меню скидывается в false.
|
||||
bool _end_game_mode;
|
||||
|
||||
//! Имя экрана, на который надо перейти.
|
||||
const char *_next_screen;
|
||||
|
||||
//! Текущий диспетчер интерфейса.
|
||||
static qdInterfaceDispatcher *_dispatcher;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_DISPATCHER_H
|
||||
268
engines/qdengine/qdcore/qd_interface_element.cpp
Normal file
268
engines/qdengine/qdcore/qd_interface_element.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/system/sound/snd_dispatcher.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_sound.h"
|
||||
#include "qdengine/qdcore/qd_interface_screen.h"
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state.h"
|
||||
#include "qdengine/qdcore/qd_interface_background.h"
|
||||
#include "qdengine/qdcore/qd_interface_counter.h"
|
||||
#include "qdengine/qdcore/qd_interface_button.h"
|
||||
#include "qdengine/qdcore/qd_interface_save.h"
|
||||
#include "qdengine/qdcore/qd_interface_slider.h"
|
||||
#include "qdengine/qdcore/qd_interface_text_window.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceElement::qdInterfaceElement() : _r(0, 0),
|
||||
_option_ID(OPTION_NONE),
|
||||
_screen_depth(0),
|
||||
_is_visible(true),
|
||||
_is_locked(false),
|
||||
_last_animation_frame(NULL) {
|
||||
}
|
||||
|
||||
qdInterfaceElement::qdInterfaceElement(const qdInterfaceElement &el) : qdInterfaceObjectBase(el),
|
||||
_r(el._r),
|
||||
_option_ID(el._option_ID),
|
||||
_option_data(el._option_data),
|
||||
_screen_depth(el._screen_depth),
|
||||
_is_visible(el._is_visible),
|
||||
_is_locked(el._is_locked),
|
||||
_last_animation_frame(NULL) {
|
||||
}
|
||||
|
||||
qdInterfaceElement::~qdInterfaceElement() {
|
||||
}
|
||||
|
||||
qdInterfaceElement &qdInterfaceElement::operator = (const qdInterfaceElement &el) {
|
||||
if (this == &el) return *this;
|
||||
|
||||
this->qdInterfaceObjectBase::operator = (el);
|
||||
|
||||
_r = el._r;
|
||||
_option_ID = el._option_ID;
|
||||
_option_data = el._option_data;
|
||||
_screen_depth = el._screen_depth;
|
||||
_is_visible = el._is_visible;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::set_animation(const qdAnimation *anm, int anm_flags) {
|
||||
if (anm) {
|
||||
anm->create_reference(&_animation);
|
||||
|
||||
if (anm_flags & QD_ANIMATION_FLAG_LOOP)
|
||||
_animation.set_flag(QD_ANIMATION_FLAG_LOOP);
|
||||
|
||||
if (anm_flags & QD_ANIMATION_FLAG_FLIP_HORIZONTAL)
|
||||
_animation.set_flag(QD_ANIMATION_FLAG_FLIP_HORIZONTAL);
|
||||
|
||||
if (anm_flags & QD_ANIMATION_FLAG_FLIP_VERTICAL)
|
||||
_animation.set_flag(QD_ANIMATION_FLAG_FLIP_VERTICAL);
|
||||
|
||||
_animation.start();
|
||||
} else
|
||||
_animation.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::set_state(const qdInterfaceElementState *p) {
|
||||
qdInterfaceElementState::state_mode_t mode = p->state_mode();
|
||||
|
||||
set_animation(p->animation(mode), p->animation_flags(mode));
|
||||
|
||||
if (p->sound(mode)) {
|
||||
if (sndDispatcher * dp = sndDispatcher::get_dispatcher())
|
||||
dp->stop_sound(&_sound_handle);
|
||||
|
||||
p->sound(mode)->play(&_sound_handle);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::redraw() const {
|
||||
_animation.redraw(r().x, r().y, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::need_redraw() const {
|
||||
if (_last_animation_frame != _animation.get_cur_frame())
|
||||
return true;
|
||||
|
||||
if (_last_screen_region != screen_region())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::post_redraw() {
|
||||
_last_screen_region = screen_region();
|
||||
_last_animation_frame = _animation.get_cur_frame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::quant(float dt) {
|
||||
_animation.quant(dt);
|
||||
return true;
|
||||
}
|
||||
|
||||
grScreenRegion qdInterfaceElement::screen_region() const {
|
||||
if (!_animation.is_empty()) {
|
||||
grScreenRegion reg = _animation.screen_region();
|
||||
reg.move(r().x, r().y);
|
||||
|
||||
return reg;
|
||||
} else
|
||||
return grScreenRegion_EMPTY;
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<interface_element");
|
||||
fh.writeString(Common::String::format(" type=\"%d\"", static_cast<int>(get_element_type())));
|
||||
|
||||
if (name()) {
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
}
|
||||
fh.writeString(Common::String::format(" pos=\"%d %d %d\"", _r.x, _r.y, _screen_depth));
|
||||
|
||||
if (_option_ID != OPTION_NONE) {
|
||||
fh.writeString(Common::String::format(" option_id=\"%d\"", (int)_option_ID));
|
||||
}
|
||||
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
if (!save_script_body(fh, indent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("</interface_element>\r\n");
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::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_INTERFACE_ELEMENT_POS:
|
||||
xml::tag_buffer(*it) > _r.x > _r.y > _screen_depth;
|
||||
break;
|
||||
case QDSCR_INTERFACE_OPTION_ID:
|
||||
_option_ID = option_ID_t(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return load_script_body(p);
|
||||
}
|
||||
|
||||
qdResource *qdInterfaceElement::add_resource(const Common::Path &file_name, const qdInterfaceElementState *res_owner) {
|
||||
if (qdInterfaceScreen * p = dynamic_cast<qdInterfaceScreen * >(owner()))
|
||||
return p->add_resource(file_name, res_owner);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdInterfaceElement::remove_resource(const Common::Path &file_name, const qdInterfaceElementState *res_owner) {
|
||||
if (qdInterfaceScreen * p = dynamic_cast<qdInterfaceScreen * >(owner()))
|
||||
return p->remove_resource(file_name, res_owner);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdInterfaceElement *qdInterfaceElement::create_element(element_type tp) {
|
||||
switch (tp) {
|
||||
case EL_BACKGROUND:
|
||||
return new qdInterfaceBackground;
|
||||
case EL_BUTTON:
|
||||
return new qdInterfaceButton;
|
||||
case EL_SLIDER:
|
||||
return new qdInterfaceSlider;
|
||||
case EL_SAVE:
|
||||
return new qdInterfaceSave;
|
||||
case EL_TEXT_WINDOW:
|
||||
return new qdInterfaceTextWindow;
|
||||
case EL_COUNTER:
|
||||
return new qdInterfaceCounter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void qdInterfaceElement::destroy_element(qdInterfaceElement *p) {
|
||||
delete p;
|
||||
}
|
||||
|
||||
|
||||
bool qdInterfaceElement::hit_test(int x, int y) const {
|
||||
if (!_animation.is_empty()) {
|
||||
x -= r().x;
|
||||
y -= r().y;
|
||||
|
||||
return _animation.hit(x, y);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdInterfaceElement::state_status_t qdInterfaceElement::state_status(const qdInterfaceElementState *p) const {
|
||||
qdInterfaceElementState::state_mode_t mode = p->state_mode();
|
||||
|
||||
if (p->animation(mode)) {
|
||||
if (p->animation(mode)->is_reference(&_animation)) {
|
||||
if (!_animation.is_finished())
|
||||
return STATE_ACTIVE;
|
||||
} else
|
||||
return STATE_INACTIVE;
|
||||
} else {
|
||||
if (!_animation.is_empty())
|
||||
return STATE_INACTIVE;
|
||||
}
|
||||
|
||||
if (p->sound(mode)) {
|
||||
if (!p->sound(mode)->is_stopped(&_sound_handle))
|
||||
return STATE_ACTIVE;
|
||||
}
|
||||
|
||||
return STATE_DONE;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
266
engines/qdengine/qdcore/qd_interface_element.h
Normal file
266
engines/qdengine/qdcore/qd_interface_element.h
Normal file
@@ -0,0 +1,266 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_H
|
||||
|
||||
#include "common/keyboard.h"
|
||||
|
||||
#include "qdengine/system/sound/snd_sound.h"
|
||||
#include "qdengine/system/input/mouse_input.h"
|
||||
#include "qdengine/system/graphics/gr_screen_region.h"
|
||||
#include "qdengine/qdcore/qd_animation.h"
|
||||
#include "qdengine/qdcore/qd_interface_object_base.h"
|
||||
#include "qdengine/qdcore/qd_sound_handle.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//class qdInterfaceScreen;
|
||||
class qdInterfaceElementState;
|
||||
|
||||
//! Базовый класс для элементов GUI.
|
||||
class qdInterfaceElement : public qdInterfaceObjectBase {
|
||||
public:
|
||||
qdInterfaceElement();
|
||||
qdInterfaceElement(const qdInterfaceElement &el);
|
||||
virtual ~qdInterfaceElement() = 0;
|
||||
|
||||
qdInterfaceElement &operator = (const qdInterfaceElement &el);
|
||||
|
||||
//! Идентификаторы настроек игры.
|
||||
enum option_ID_t {
|
||||
OPTION_NONE = 0,
|
||||
/// звук вкл/выкл, 1/0
|
||||
OPTION_SOUND,
|
||||
/// громкость звука, [0, 255]
|
||||
OPTION_SOUND_VOLUME,
|
||||
/// музыка вкл/выкл, 1/0
|
||||
OPTION_MUSIC,
|
||||
/// громкость музыки, [0, 255]
|
||||
OPTION_MUSIC_VOLUME,
|
||||
/// определенный персонаж персонаж активен/неактивен, 1/0
|
||||
OPTION_ACTIVE_PERSONAGE
|
||||
};
|
||||
|
||||
//! Типы элементов интерфейса.
|
||||
enum element_type {
|
||||
//! фон
|
||||
EL_BACKGROUND,
|
||||
//! кнопка
|
||||
EL_BUTTON,
|
||||
//! слайдер
|
||||
EL_SLIDER,
|
||||
//! сэйв
|
||||
EL_SAVE,
|
||||
//! окно с текстами
|
||||
EL_TEXT_WINDOW,
|
||||
//! счётчик
|
||||
EL_COUNTER
|
||||
};
|
||||
|
||||
//! Статус состояния.
|
||||
enum state_status_t {
|
||||
//! состояние неактивно
|
||||
STATE_INACTIVE,
|
||||
//! состояние активно
|
||||
STATE_ACTIVE,
|
||||
//! работа состояния закончилась
|
||||
STATE_DONE
|
||||
};
|
||||
|
||||
//! Создание элемента интерфейса заданного типа.
|
||||
static qdInterfaceElement *create_element(element_type tp);
|
||||
//! Уничтожение элемента интерфейса.
|
||||
static void destroy_element(qdInterfaceElement *p);
|
||||
//! Возвращает тип элемента.
|
||||
virtual element_type get_element_type() const = 0;
|
||||
|
||||
//! Возвращает идентификатор настройки игры, связанной с элементом.
|
||||
option_ID_t option_ID() const {
|
||||
return _option_ID;
|
||||
}
|
||||
//! Устанавливает идентификатор настройки игры, связанной с элементом.
|
||||
void set_option_ID(option_ID_t id) {
|
||||
_option_ID = id;
|
||||
}
|
||||
//! Возвращает true, если с элементом связана настройка игры.
|
||||
bool linked_to_option() const {
|
||||
return (_option_ID != OPTION_NONE);
|
||||
}
|
||||
//! Возвращает значение настройки игры, связанной с элементом.
|
||||
virtual int option_value() const {
|
||||
return -1;
|
||||
}
|
||||
//! Устанавливает значение настройки игры, связанной с элементом.
|
||||
virtual bool set_option_value(int value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Возвращает экранные координаты центра элемента.
|
||||
virtual const Vect2i r() const {
|
||||
return _r + g_engine->screen_offset();
|
||||
}
|
||||
//! Устанавливает экранные координаты центра элемента.
|
||||
void set_r(const Vect2i &v) {
|
||||
_r = v;
|
||||
}
|
||||
|
||||
//! Возвращает размер элемента по горизонтали в пикселах.
|
||||
virtual int size_x() const {
|
||||
return _animation.size_x();
|
||||
}
|
||||
//! Возвращает размер элемента по вертикали в пикселах.
|
||||
virtual int size_y() const {
|
||||
return _animation.size_y();
|
||||
}
|
||||
|
||||
virtual grScreenRegion screen_region() const;
|
||||
const grScreenRegion &last_screen_region() const {
|
||||
return _last_screen_region;
|
||||
}
|
||||
|
||||
//! Устанавливает экранную глубину элемента.
|
||||
void set_screen_depth(int v) {
|
||||
_screen_depth = v;
|
||||
}
|
||||
//! Возвращает экранную глубину эелмента.
|
||||
int screen_depth() const {
|
||||
return _screen_depth;
|
||||
}
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
|
||||
//! Отрисовка элемента.
|
||||
virtual bool redraw() const;
|
||||
virtual bool need_redraw() const;
|
||||
virtual bool post_redraw();
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
virtual bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) = 0;
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
virtual bool keyboard_handler(Common::KeyCode vkey) = 0;
|
||||
//! Обработчик ввода символов с клавиатуры.
|
||||
virtual bool char_input_handler(int vkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void hover_clear() { }
|
||||
|
||||
//! Инициализация элемента.
|
||||
/**
|
||||
Вызывается каждый раз при заходе на экран, которому принадлежит элемент.
|
||||
*/
|
||||
virtual bool init(bool is_game_active = true) = 0;
|
||||
|
||||
//! Обсчет логики, параметр - время в секундах.
|
||||
virtual bool quant(float dt);
|
||||
|
||||
const qdAnimation &animation() const {
|
||||
return _animation;
|
||||
}
|
||||
|
||||
//! Устанавливает анимацию для элемента.
|
||||
bool set_animation(const qdAnimation *anm, int anm_flags = 0);
|
||||
//! Включает состояние элемента.
|
||||
bool set_state(const qdInterfaceElementState *p);
|
||||
|
||||
//! Добавляет ресурс file_name с владельцем owner.
|
||||
qdResource *add_resource(const Common::Path &file_name, const qdInterfaceElementState *res_owner);
|
||||
//! Удаляет ресурс file_name с владельцем owner.
|
||||
bool remove_resource(const Common::Path &file_name, const qdInterfaceElementState *res_owner);
|
||||
|
||||
//! Возвращает true, если точка с экранными координатами (x,у) попадает в элемент.
|
||||
virtual bool hit_test(int x, int y) const;
|
||||
|
||||
//! Возвращает статус состояния.
|
||||
state_status_t state_status(const qdInterfaceElementState *p) const;
|
||||
|
||||
//! Прячет элемент.
|
||||
void hide() {
|
||||
_is_visible = false;
|
||||
}
|
||||
//! Показывает элемент.
|
||||
void show() {
|
||||
_is_visible = true;
|
||||
}
|
||||
//! Возвращает true, если элемент не спрятан.
|
||||
bool is_visible() const {
|
||||
return _is_visible;
|
||||
}
|
||||
|
||||
//! Возвращает true, если элемент заблокирован.
|
||||
bool is_locked() const {
|
||||
return _is_locked;
|
||||
}
|
||||
//! Блокировка/разблокировка элемента.
|
||||
void set_lock(bool state) {
|
||||
_is_locked = state;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
virtual bool save_script_body(Common::WriteStream &fh, int indent = 0) const = 0;
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
virtual bool load_script_body(const xml::tag *p) = 0;
|
||||
|
||||
void clear_screen_region() {
|
||||
_last_screen_region = grScreenRegion_EMPTY;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Идентификатор настройки игры, связанной с элементом.
|
||||
option_ID_t _option_ID;
|
||||
//! Данные для настройки игры, связанной с элементом.
|
||||
Common::String _option_data;
|
||||
|
||||
//! Экранные координаты центра элемента.
|
||||
Vect2i _r;
|
||||
|
||||
//! Экранная глубина. Чем больше значение - тем дальше элемент.
|
||||
int _screen_depth;
|
||||
|
||||
//! Анимация элемента.
|
||||
qdAnimation _animation;
|
||||
|
||||
//! Хэндл для управления звуками.
|
||||
qdSoundHandle _sound_handle;
|
||||
|
||||
//! Равно false, если элемент спрятан.
|
||||
bool _is_visible;
|
||||
|
||||
//! Равно true, если элемент заблокирован (не реагирует на клавиатуру/мышь).
|
||||
bool _is_locked;
|
||||
|
||||
grScreenRegion _last_screen_region;
|
||||
const qdAnimationFrame *_last_animation_frame;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_H
|
||||
453
engines/qdengine/qdcore/qd_interface_element_state.cpp
Normal file
453
engines/qdengine/qdcore/qd_interface_element_state.cpp
Normal file
@@ -0,0 +1,453 @@
|
||||
/* 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 "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_sound.h"
|
||||
#include "qdengine/qdcore/qd_animation.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_interface_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceElementState::qdInterfaceElementState() : _state_mode(DEFAULT_MODE), _prev_state_mode(DEFAULT_MODE) {
|
||||
}
|
||||
|
||||
qdInterfaceElementState::qdInterfaceElementState(const qdInterfaceElementState &st) : qdInterfaceObjectBase(st),
|
||||
_events(st._events),
|
||||
_state_mode(st._state_mode),
|
||||
_prev_state_mode(st._prev_state_mode) {
|
||||
for (int i = 0; i < NUM_MODES; i++)
|
||||
_modes[i] = st._modes[i];
|
||||
|
||||
register_resources();
|
||||
}
|
||||
|
||||
qdInterfaceElementState::~qdInterfaceElementState() {
|
||||
unregister_resources();
|
||||
}
|
||||
|
||||
qdInterfaceElementState &qdInterfaceElementState::operator = (const qdInterfaceElementState &st) {
|
||||
if (this == &st) return *this;
|
||||
|
||||
unregister_resources();
|
||||
|
||||
this->qdInterfaceObjectBase::operator = (st);
|
||||
|
||||
_events = st._events;
|
||||
|
||||
for (int i = 0; i < NUM_MODES; i++)
|
||||
_modes[i] = st._modes[i];
|
||||
|
||||
register_resources();
|
||||
|
||||
_state_mode = st._state_mode;
|
||||
_prev_state_mode = st._prev_state_mode;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define defEnum(x) #x
|
||||
|
||||
static const char *eventList[] = {
|
||||
defEnum(EVENT_NONE),
|
||||
defEnum(EVENT_EXIT),
|
||||
defEnum(EVENT_LOAD_SCENE),
|
||||
defEnum(EVENT_SAVE_GAME),
|
||||
defEnum(EVENT_NEW_GAME),
|
||||
defEnum(EVENT_CHANGE_INTERFACE_SCREEN),
|
||||
defEnum(EVENT_CHANGE_PERSONAGE),
|
||||
defEnum(EVENT_TMP_HIDE_ELEMENT),
|
||||
defEnum(EVENT_HIDE_ELEMENT),
|
||||
defEnum(EVENT_SHOW_ELEMENT),
|
||||
defEnum(EVENT_RESUME_GAME),
|
||||
defEnum(EVENT_SET_SAVE_MODE),
|
||||
defEnum(EVENT_SET_LOAD_MODE),
|
||||
defEnum(EVENT_ACTIVATE_PERSONAGE),
|
||||
defEnum(EVENT_PREV_ELEMENT_STATE),
|
||||
defEnum(EVENT_NEXT_ELEMENT_STATE),
|
||||
defEnum(EVENT_MAIN_MENU),
|
||||
defEnum(EVENT_PLAY_VIDEO),
|
||||
defEnum(EVENT_BUTTON_STATE),
|
||||
defEnum(EVENT_CLEAR_MOUSE),
|
||||
defEnum(EVENT_SCROLL_LEFT),
|
||||
defEnum(EVENT_SCROLL_RIGHT),
|
||||
defEnum(EVENT_SCROLL_UP),
|
||||
defEnum(EVENT_SCROLL_DOWN),
|
||||
defEnum(EVENT_SHOW_INTERFACE_SCREEN_AS_MODAL),
|
||||
defEnum(EVENT_MODAL_OK),
|
||||
defEnum(EVENT_MODAL_CANCEL),
|
||||
defEnum(EVENT_HALL_OF_FAME_PLAYER),
|
||||
defEnum(EVENT_HALL_OF_FAME_SCORE),
|
||||
defEnum(EVENT_HALL_OF_FAME_CUR_SCORE),
|
||||
};
|
||||
|
||||
static const char *eventActivationList[] = {
|
||||
defEnum(EVENT_ACTIVATION_CLICK),
|
||||
defEnum(EVENT_ACTIVATION_HOVER),
|
||||
};
|
||||
|
||||
Common::String qdInterfaceElementState::event2Str(int fl, bool truncate) const {
|
||||
if (fl >= ARRAYSIZE(eventList) || fl < 0)
|
||||
return Common::String::format("<%d>", fl);
|
||||
|
||||
return Common::String(&eventList[fl][truncate ? 6 : 0]);
|
||||
}
|
||||
|
||||
Common::String qdInterfaceElementState::eventActivation2Str(int fl, bool truncate) const {
|
||||
if (fl >= ARRAYSIZE(eventActivationList) || fl < 0)
|
||||
return Common::String::format("<%d>", fl);
|
||||
|
||||
return Common::String(&eventActivationList[fl][truncate ? 17 : 0]);
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<interface_element_state");
|
||||
|
||||
if (name()) {
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
}
|
||||
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
for (uint j = 0; j < _events.size(); j++) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
if (debugChannelSet(-1, kDebugLog)) {
|
||||
fh.writeString(Common::String::format("<event type=\"%s\"", event2Str(_events[j].event()).c_str()));
|
||||
} else {
|
||||
fh.writeString(Common::String::format("<event type=\"%d\"", int(_events[j].event())));
|
||||
}
|
||||
|
||||
if (_events[j].has_data()) {
|
||||
fh.writeString(Common::String::format(" event_data=\"%s\"", qdscr_XML_string(_events[j].event_data())));
|
||||
}
|
||||
|
||||
if (_events[j].is_before_animation()) {
|
||||
fh.writeString(" before_animation=\"1\"");
|
||||
}
|
||||
|
||||
if (_events[j].activation() != qdInterfaceEvent::EVENT_ACTIVATION_CLICK) {
|
||||
if (debugChannelSet(-1, kDebugLog)) {
|
||||
fh.writeString(Common::String::format(" activation_type=\"%s\"", eventActivation2Str((int)_events[j].activation()).c_str()));
|
||||
} else {
|
||||
fh.writeString(Common::String::format(" activation_type=\"%d\"", (int)_events[j].activation()));
|
||||
}
|
||||
}
|
||||
|
||||
fh.writeString("/>\r\n");
|
||||
}
|
||||
|
||||
for (int i = 0; i < NUM_MODES; i++) {
|
||||
if (has_state_mode(state_mode_t(i))) {
|
||||
_modes[i].save_script(fh, i, indent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</interface_element_state>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::load_script(const xml::tag *p) {
|
||||
int num_events = 0;
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_INTERFACE_EVENT:
|
||||
num_events++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_events)
|
||||
_events.reserve(num_events);
|
||||
|
||||
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_INTERFACE_ELEMENT_STATE_MODE:
|
||||
if (const xml::tag * tg = it->search_subtag(QDSCR_TYPE))
|
||||
_modes[state_mode_t(xml::tag_buffer(*tg).get_int())].load_script(&*it);
|
||||
break;
|
||||
case QDSCR_INTERFACE_EVENT: {
|
||||
qdInterfaceEvent::event_t ev = qdInterfaceEvent::EVENT_NONE;
|
||||
qdInterfaceEvent::activation_t act = qdInterfaceEvent::EVENT_ACTIVATION_CLICK;
|
||||
const char *ev_data = "";
|
||||
bool anm_flag = false;
|
||||
|
||||
if (const xml::tag * tg = it->search_subtag(QDSCR_TYPE))
|
||||
ev = qdInterfaceEvent::event_t(xml::tag_buffer(*tg).get_int());
|
||||
if (const xml::tag * tg = it->search_subtag(QDSCR_INTERFACE_EVENT_DATA))
|
||||
ev_data = tg->data();
|
||||
if (const xml::tag * tg = it->search_subtag(QDSCR_INTERFACE_EVENT_BEFORE_ANIMATION)) {
|
||||
if (xml::tag_buffer(*tg).get_int())
|
||||
anm_flag = true;
|
||||
}
|
||||
if (const xml::tag * tg = it->search_subtag(QDSCR_INTERFACE_EVENT_ACTIVATION_TYPE))
|
||||
act = qdInterfaceEvent::activation_t(xml::tag_buffer(*tg).get_int());
|
||||
|
||||
_events.push_back(qdInterfaceEvent(ev, ev_data, anm_flag, act));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
register_resources();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::quant(float dt) {
|
||||
debugC(9, kDebugQuant, "qdInterfaceElementState::quant(%f)", dt);
|
||||
if (qdInterfaceElement * ep = dynamic_cast<qdInterfaceElement * >(owner())) {
|
||||
if (_prev_state_mode == MOUSE_HOVER_MODE && state_mode() == DEFAULT_MODE)
|
||||
handle_events(qdInterfaceEvent::EVENT_ACTIVATION_HOVER, false);
|
||||
|
||||
_prev_state_mode = state_mode();
|
||||
|
||||
switch (ep->state_status(this)) {
|
||||
case qdInterfaceElement::STATE_INACTIVE:
|
||||
ep->set_state(this);
|
||||
break;
|
||||
case qdInterfaceElement::STATE_DONE:
|
||||
if (state_mode() == EVENT_MODE) {
|
||||
debugC(3, kDebugQuant, "qdInterfaceElementState::quant(%f) - EVENT_MODE", dt);
|
||||
handle_events(qdInterfaceEvent::EVENT_ACTIVATION_CLICK, false);
|
||||
}
|
||||
|
||||
|
||||
set_state_mode(DEFAULT_MODE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdInterfaceElementState::set_sound_file(const Common::Path &str, state_mode_t snd_id) {
|
||||
if (has_sound(snd_id)) {
|
||||
if (qdInterfaceElement * p = dynamic_cast<qdInterfaceElement * >(owner()))
|
||||
p->remove_resource(sound_file(snd_id), this);
|
||||
|
||||
_modes[snd_id].set_sound(NULL);
|
||||
}
|
||||
|
||||
_modes[snd_id].set_sound_file(str);
|
||||
if (has_sound(snd_id)) {
|
||||
if (qdInterfaceElement * p = dynamic_cast<qdInterfaceElement * >(owner()))
|
||||
_modes[snd_id].set_sound(dynamic_cast<const qdSound * >(p->add_resource(sound_file(snd_id), this)));
|
||||
}
|
||||
}
|
||||
|
||||
void qdInterfaceElementState::set_animation_file(const Common::Path &name, state_mode_t anm_id) {
|
||||
if (has_animation(anm_id)) {
|
||||
if (qdInterfaceElement * p = dynamic_cast<qdInterfaceElement * >(owner()))
|
||||
p->remove_resource(animation_file(anm_id), this);
|
||||
|
||||
_modes[anm_id].set_animation(NULL);
|
||||
}
|
||||
|
||||
_modes[anm_id].set_animation_file(name);
|
||||
if (has_animation(anm_id)) {
|
||||
if (qdInterfaceElement * p = dynamic_cast<qdInterfaceElement * >(owner()))
|
||||
_modes[anm_id].set_animation(dynamic_cast<const qdAnimation * >(p->add_resource(animation_file(anm_id), this)));
|
||||
}
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::unregister_resources() {
|
||||
bool res = true;
|
||||
|
||||
for (int i = 0; i < NUM_MODES; i++) {
|
||||
if (has_animation(state_mode_t(i))) {
|
||||
if (qdInterfaceElement * p = dynamic_cast<qdInterfaceElement * >(owner())) {
|
||||
if (!p->remove_resource(animation_file(state_mode_t(i)), this))
|
||||
res = false;
|
||||
|
||||
_modes[i].set_animation(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_sound(state_mode_t(i))) {
|
||||
if (qdInterfaceElement * p = dynamic_cast<qdInterfaceElement * >(owner())) {
|
||||
if (!p->remove_resource(sound_file(state_mode_t(i)), this))
|
||||
res = false;
|
||||
|
||||
_modes[i].set_sound(NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::register_resources() {
|
||||
bool res = true;
|
||||
|
||||
for (int i = 0; i < NUM_MODES; i++) {
|
||||
if (has_animation(state_mode_t(i))) {
|
||||
if (qdInterfaceElement * p = dynamic_cast<qdInterfaceElement * >(owner()))
|
||||
_modes[i].set_animation(dynamic_cast<const qdAnimation * >(p->add_resource(animation_file(state_mode_t(i)), this)));
|
||||
|
||||
if (!_modes[i].animation()) res = false;
|
||||
}
|
||||
|
||||
if (has_sound(state_mode_t(i))) {
|
||||
if (qdInterfaceElement * p = dynamic_cast<qdInterfaceElement * >(owner()))
|
||||
_modes[i].set_sound(dynamic_cast<const qdSound * >(p->add_resource(sound_file(state_mode_t(i)), this)));
|
||||
|
||||
if (!_modes[i].sound()) res = false;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::has_state_mode(state_mode_t mode) const {
|
||||
switch (mode) {
|
||||
case DEFAULT_MODE:
|
||||
return true;
|
||||
case MOUSE_HOVER_MODE:
|
||||
if (has_animation(MOUSE_HOVER_MODE) || has_sound(MOUSE_HOVER_MODE) || has_contour(MOUSE_HOVER_MODE)) return true;
|
||||
return false;
|
||||
case EVENT_MODE:
|
||||
if (_events.size()) return true;
|
||||
if (has_animation(EVENT_MODE) || has_sound(EVENT_MODE) || has_contour(EVENT_MODE)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
switch (ev) {
|
||||
case mouseDispatcher::EV_MOUSE_MOVE:
|
||||
if (state_mode() != EVENT_MODE) {
|
||||
if (has_state_mode(MOUSE_HOVER_MODE)) {
|
||||
set_state_mode(MOUSE_HOVER_MODE);
|
||||
if (_prev_state_mode != MOUSE_HOVER_MODE)
|
||||
handle_events(qdInterfaceEvent::EVENT_ACTIVATION_HOVER, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mouseDispatcher::EV_LEFT_DOWN:
|
||||
case mouseDispatcher::EV_RIGHT_DOWN:
|
||||
if (has_state_mode(EVENT_MODE)) {
|
||||
set_state_mode(EVENT_MODE);
|
||||
handle_events(qdInterfaceEvent::EVENT_ACTIVATION_CLICK, true);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::keyboard_handler(Common::KeyCode vkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::handle_events(qdInterfaceEvent::activation_t activation_type, bool before_animation) {
|
||||
if (qdInterfaceDispatcher * dp = qdInterfaceDispatcher::get_dispatcher()) {
|
||||
for (uint i = 0; i < _events.size(); i++) {
|
||||
if (_events[i].activation() == activation_type && _events[i].is_before_animation() == before_animation) {
|
||||
dp->handle_event(_events[i].event(), _events[i].event_data(), owner());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::get_contour(state_mode_t mode, qdContour &cnt) const {
|
||||
_modes[mode].get_contour(cnt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::set_contour(state_mode_t mode, const qdContour &cnt) {
|
||||
_modes[mode].set_contour(cnt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::need_active_game() const {
|
||||
for (uint i = 0; i < _events.size(); i++) {
|
||||
if (_events[i].event() == qdInterfaceEvent::EVENT_SAVE_GAME)
|
||||
return true;
|
||||
if (_events[i].event() == qdInterfaceEvent::EVENT_CHANGE_PERSONAGE)
|
||||
return true;
|
||||
if (_events[i].event() == qdInterfaceEvent::EVENT_RESUME_GAME)
|
||||
return true;
|
||||
if (_events[i].event() == qdInterfaceEvent::EVENT_ACTIVATE_PERSONAGE)
|
||||
return true;
|
||||
if (_events[i].event() == qdInterfaceEvent::EVENT_SET_SAVE_MODE)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const qdInterfaceEvent *qdInterfaceElementState::find_event(qdInterfaceEvent::event_t type) const {
|
||||
events_container_t::const_iterator it = Common::find(_events.begin(), _events.end(), type);
|
||||
if (it != _events.end())
|
||||
return &*it;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementState::has_event(qdInterfaceEvent::event_t type, const char *ev_data) const {
|
||||
for (events_container_t::const_iterator it = _events.begin(); it != _events.end(); ++it) {
|
||||
if (it->event() == type) {
|
||||
if ((!ev_data && !it->event_data()) || (it->event_data() && ev_data && !strcmp(ev_data, it->event_data())))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
332
engines/qdengine/qdcore/qd_interface_element_state.h
Normal file
332
engines/qdengine/qdcore/qd_interface_element_state.h
Normal file
@@ -0,0 +1,332 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_STATE_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_STATE_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_animation_info.h"
|
||||
#include "qdengine/qdcore/qd_interface_object_base.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state_mode.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
//! Интерфейсное событие.
|
||||
class qdInterfaceEvent {
|
||||
public:
|
||||
//! События, производимые элементами интерфейса.
|
||||
enum event_t {
|
||||
EVENT_NONE = 0,
|
||||
//! выйти из игры
|
||||
EVENT_EXIT, // 1
|
||||
//! перейти на сцену, параметр - имя сцены
|
||||
EVENT_LOAD_SCENE, // 2
|
||||
//! записать игру [не используется]
|
||||
EVENT_SAVE_GAME, // 3
|
||||
//! новая игра
|
||||
EVENT_NEW_GAME, // 4
|
||||
//! перейти на другой интерфейсный экран (парметер имя экрана)
|
||||
EVENT_CHANGE_INTERFACE_SCREEN, // 5
|
||||
//! сменить активного персонажа
|
||||
EVENT_CHANGE_PERSONAGE, // 6
|
||||
//! временно спрятать элемент активного экрана (до перехода на другой экран)
|
||||
// (парметер имя элемента)
|
||||
EVENT_TMP_HIDE_ELEMENT, // 7
|
||||
//! спрятать элемент активного экрана (насовсем)
|
||||
// (парметер имя элемента)
|
||||
EVENT_HIDE_ELEMENT, // 8
|
||||
//! показать элемент активного экрана
|
||||
// (парметер имя элемента)
|
||||
EVENT_SHOW_ELEMENT, // 9
|
||||
//! продолжить игру
|
||||
EVENT_RESUME_GAME, // 10
|
||||
//! включить режим записи игры
|
||||
/**
|
||||
при заходе на экран с сэйвами будет происходить
|
||||
запись игры при клике по сэйву
|
||||
*/
|
||||
EVENT_SET_SAVE_MODE, // 11
|
||||
//! включить режим загрузки игры
|
||||
/**
|
||||
при заходе на экран с сэйвами будет происходить
|
||||
загрузка сохраненной игры при клике по сэйву
|
||||
*/
|
||||
EVENT_SET_LOAD_MODE, // 12
|
||||
//! сделать персонажа активным, имя персонажа - в данных события
|
||||
EVENT_ACTIVATE_PERSONAGE, // 13
|
||||
//! включить предыдущее состояние кнопки (парметер имя кнопки)
|
||||
EVENT_PREV_ELEMENT_STATE, // 14
|
||||
//! включить следующее состояние кнопки (парметер имя кнопки)
|
||||
EVENT_NEXT_ELEMENT_STATE, // 15
|
||||
//! перейти в main menu
|
||||
EVENT_MAIN_MENU, // 16
|
||||
//! играть видеоролик (параметр - имя видеоролика из списка в qdGameDispatcher)
|
||||
EVENT_PLAY_VIDEO, // 17
|
||||
//! включить определенное состояние кнопки, параметр - имя кнопки
|
||||
EVENT_BUTTON_STATE, // 18
|
||||
//! скинуть с мыши объект в инвентори
|
||||
EVENT_CLEAR_MOUSE, // 19
|
||||
//! скроллинг
|
||||
EVENT_SCROLL_LEFT, // 20
|
||||
EVENT_SCROLL_RIGHT, // 21
|
||||
EVENT_SCROLL_UP, // 22
|
||||
EVENT_SCROLL_DOWN, // 23
|
||||
//! показать экран интерфейса, как модальный
|
||||
EVENT_SHOW_INTERFACE_SCREEN_AS_MODAL, // 24
|
||||
//! пользователь завершил работу с модальным окном и ответил Ок
|
||||
EVENT_MODAL_OK, // 25
|
||||
//! пользователь завершил работу с модальным окном и ответил Отмена
|
||||
EVENT_MODAL_CANCEL, // 26
|
||||
/// Имя игрока в таблице рекордов, параметр - номер места
|
||||
EVENT_HALL_OF_FAME_PLAYER, // 27
|
||||
/// Очки игрока в таблице рекордов, параметр - номер места
|
||||
EVENT_HALL_OF_FAME_SCORE, // 28
|
||||
/// Текущие очки игрока на экране таблицы рекордов
|
||||
EVENT_HALL_OF_FAME_CUR_SCORE // 29
|
||||
};
|
||||
|
||||
/// Способы запуска события
|
||||
enum activation_t {
|
||||
/// левый клик по кнопке
|
||||
EVENT_ACTIVATION_CLICK = 0,
|
||||
/// наведение мышиного курсора
|
||||
EVENT_ACTIVATION_HOVER
|
||||
};
|
||||
|
||||
qdInterfaceEvent(event_t id, const char *data, bool anm_flag, activation_t activation = EVENT_ACTIVATION_CLICK) : _event(id), _event_data(data), _is_before_animation(anm_flag), _activation(activation) { }
|
||||
~qdInterfaceEvent() {}
|
||||
|
||||
bool operator == (event_t id) const {
|
||||
return (_event == id);
|
||||
}
|
||||
|
||||
//! Код события.
|
||||
event_t event() const {
|
||||
return _event;
|
||||
}
|
||||
//! Возвращает true, если у события есть данные.
|
||||
bool has_data() const {
|
||||
return !_event_data.empty();
|
||||
}
|
||||
//! Возвращает данные для события.
|
||||
const char *event_data() const {
|
||||
return _event_data.c_str();
|
||||
}
|
||||
//! Возвращает true, если событие должно происходить до включения анимации.
|
||||
bool is_before_animation() const {
|
||||
return _is_before_animation;
|
||||
}
|
||||
activation_t activation() const {
|
||||
return _activation;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Код события.
|
||||
event_t _event;
|
||||
//! Данные для события.
|
||||
Common::String _event_data;
|
||||
//! Равно true, если событие должно происходить до включения анимации.
|
||||
bool _is_before_animation;
|
||||
//! Как событие активируется
|
||||
activation_t _activation;
|
||||
};
|
||||
|
||||
//! Состояние элемента интерфейса.
|
||||
class qdInterfaceElementState : public qdInterfaceObjectBase {
|
||||
public:
|
||||
//! Идентификаторы для режимов работы состояния.
|
||||
enum state_mode_t {
|
||||
//! режим по умолчанию
|
||||
DEFAULT_MODE = 0,
|
||||
//! режим, который включается когда мышиный курсор находится над элементом-владельцем
|
||||
MOUSE_HOVER_MODE,
|
||||
//! режим, который включается при клике по элементу-владельцу
|
||||
EVENT_MODE
|
||||
};
|
||||
|
||||
enum {
|
||||
//! количество режимов работы состояния
|
||||
NUM_MODES = 3
|
||||
};
|
||||
|
||||
qdInterfaceElementState();
|
||||
qdInterfaceElementState(const qdInterfaceElementState &st);
|
||||
~qdInterfaceElementState();
|
||||
|
||||
qdInterfaceElementState &operator = (const qdInterfaceElementState &st);
|
||||
|
||||
//! Устанавливает имя файла звукового эффекта, привязанного к состоянию.
|
||||
/**
|
||||
Если надо убрать звук - передать NULL в качестве имени файла.
|
||||
*/
|
||||
void set_sound_file(const Common::Path &str, state_mode_t snd_id = DEFAULT_MODE);
|
||||
//! Возвращает имя файла звукового эффекта, привязанного к состоянию.
|
||||
const Common::Path sound_file(state_mode_t snd_id = DEFAULT_MODE) const {
|
||||
return _modes[snd_id].sound_file();
|
||||
}
|
||||
//! Возвращает указатель на звуковой эффект, привязанный к состоянию.
|
||||
const qdSound *sound(state_mode_t snd_id = DEFAULT_MODE) const {
|
||||
return _modes[snd_id].sound();
|
||||
}
|
||||
//! Возвращает true, если к состоянию привязан звук.
|
||||
bool has_sound(state_mode_t snd_id = DEFAULT_MODE) const {
|
||||
return _modes[snd_id].has_sound();
|
||||
}
|
||||
|
||||
//! Устанавливает имя файла для анимации.
|
||||
/**
|
||||
Если надо убрать анимацию - передать NULL в качестве имени файла.
|
||||
*/
|
||||
void set_animation_file(const Common::Path &name, state_mode_t anm_id = DEFAULT_MODE);
|
||||
//! Возвращает имя файла для анимации.
|
||||
const Common::Path animation_file(state_mode_t anm_id = DEFAULT_MODE) const {
|
||||
return _modes[anm_id].animation_file();
|
||||
}
|
||||
//! Возвращает флаги анимации.
|
||||
int animation_flags(state_mode_t anm_id = DEFAULT_MODE) const {
|
||||
return _modes[anm_id].animation_flags();
|
||||
}
|
||||
|
||||
//! Устанавливает флаг анимации.
|
||||
void set_animation_flag(int fl, state_mode_t anm_id = DEFAULT_MODE) {
|
||||
_modes[anm_id].set_animation_flag(fl);
|
||||
}
|
||||
//! Скидывает флаг анимации.
|
||||
void drop_animation_flag(int fl, state_mode_t anm_id = DEFAULT_MODE) {
|
||||
_modes[anm_id].drop_animation_flag(fl);
|
||||
}
|
||||
//! Возвращает true, если для анимации установлен флаг fl.
|
||||
bool check_animation_flag(int fl, state_mode_t anm_id = DEFAULT_MODE) const {
|
||||
return _modes[anm_id].check_animation_flag(fl);
|
||||
}
|
||||
|
||||
//! Возвращает указатель на анимацию, привязанную к состоянию.
|
||||
const qdAnimation *animation(state_mode_t anm_id = DEFAULT_MODE) const {
|
||||
return _modes[anm_id].animation();
|
||||
}
|
||||
//! Возвращает true, если к состоянию привязана анимация.
|
||||
bool has_animation(state_mode_t anm_id = DEFAULT_MODE) const {
|
||||
return _modes[anm_id].has_animation();
|
||||
}
|
||||
|
||||
//! Регистрирует ресурсы, связанные с состоянием (анимацию и звук).
|
||||
bool register_resources();
|
||||
//! Высвобождает ресурсы, связанные с состоянием (анимацию и звук).
|
||||
bool unregister_resources();
|
||||
|
||||
Common::String event2Str(int fl, bool truncate = false) const;
|
||||
Common::String eventActivation2Str(int fl, bool truncate = false) const;
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
|
||||
//! Обсчет логики, параметр - время в секундах.
|
||||
/**
|
||||
Вызывается владельцем для активного состояния.
|
||||
*/
|
||||
bool quant(float dt);
|
||||
|
||||
//! Устанавливает режим работы состояния.
|
||||
void set_state_mode(state_mode_t mode) {
|
||||
_state_mode = mode;
|
||||
}
|
||||
//! Возвращает режим работы состояния.
|
||||
state_mode_t state_mode() const {
|
||||
return _state_mode;
|
||||
}
|
||||
//! Возвращает true, если у состояния может быть включен режим работы mode.
|
||||
bool has_state_mode(state_mode_t mode) const;
|
||||
|
||||
//! Возвращает true, если у состояния задан контур для режима mode.
|
||||
bool has_contour(state_mode_t mode) const {
|
||||
return _modes[mode].has_contour();
|
||||
}
|
||||
//! Записывает контур режима mode в cnt.
|
||||
bool get_contour(state_mode_t mode, qdContour &cnt) const;
|
||||
//! Устанавливает контур для режима mode.
|
||||
bool set_contour(state_mode_t mode, const qdContour &cnt);
|
||||
|
||||
//! Возвращает true, если точка с экранными координатами (x,у) попадает внутрь контура режима mode.
|
||||
bool hit_test(int x, int y, state_mode_t mode) const {
|
||||
return _modes[mode].hit_test(x, y);
|
||||
}
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
|
||||
typedef Std::vector<qdInterfaceEvent> events_container_t;
|
||||
//! Список событий.
|
||||
const events_container_t &events() const {
|
||||
return _events;
|
||||
}
|
||||
//! Добавление события.
|
||||
void add_event(const qdInterfaceEvent &ev) {
|
||||
_events.push_back(ev);
|
||||
}
|
||||
//! Уделение события
|
||||
void erase_event(int iNum) {
|
||||
_events.erase(_events.begin() + iNum);
|
||||
}
|
||||
//! Удаление всех событий
|
||||
void erase_all_events() {
|
||||
_events.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
Возвращает true, если хотя бы для одного из событий состояния необходимо
|
||||
наличие загруженной сцены (т.е. оно происходит только во время игры).
|
||||
*/
|
||||
bool need_active_game() const;
|
||||
|
||||
const qdInterfaceEvent *find_event(qdInterfaceEvent::event_t type) const;
|
||||
bool has_event(qdInterfaceEvent::event_t type, const char *ev_data = NULL) const;
|
||||
|
||||
private:
|
||||
|
||||
//! События, происходящие при активации состояния.
|
||||
events_container_t _events;
|
||||
|
||||
//! События состояния.
|
||||
qdInterfaceElementStateMode _modes[NUM_MODES];
|
||||
|
||||
//! Текущий режим работы состояния.
|
||||
state_mode_t _state_mode;
|
||||
//! Режим работы состояния в прошлый квант времени.
|
||||
state_mode_t _prev_state_mode;
|
||||
|
||||
//! Обработка событий состояния.
|
||||
/**
|
||||
Параметром выбирается, какие события выполнять - которые должны
|
||||
происхолить до анимации (параметр true) или после нее (параметр false).
|
||||
*/
|
||||
bool handle_events(qdInterfaceEvent::activation_t activation_type, bool before_animation);
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_STATE_H
|
||||
157
engines/qdengine/qdcore/qd_interface_element_state_mode.cpp
Normal file
157
engines/qdengine/qdcore/qd_interface_element_state_mode.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_animation.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
|
||||
#include "qd_interface_element_state_mode.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceElementStateMode::qdInterfaceElementStateMode() : _sound(NULL),
|
||||
_animation_flags(0),
|
||||
_animation(NULL),
|
||||
_contour(qdContour::CONTOUR_POLYGON) {
|
||||
}
|
||||
|
||||
qdInterfaceElementStateMode::qdInterfaceElementStateMode(const qdInterfaceElementStateMode &ev) : _sound_file(ev._sound_file),
|
||||
_sound(ev._sound),
|
||||
_animation_file(ev._animation_file),
|
||||
_animation_flags(ev._animation_flags),
|
||||
_animation(ev._animation),
|
||||
_contour(ev._contour) {
|
||||
}
|
||||
|
||||
qdInterfaceElementStateMode::~qdInterfaceElementStateMode() {
|
||||
}
|
||||
|
||||
qdInterfaceElementStateMode &qdInterfaceElementStateMode::operator = (const qdInterfaceElementStateMode &ev) {
|
||||
if (this == &ev) return *this;
|
||||
|
||||
_sound_file = ev._sound_file;
|
||||
_sound = ev._sound;
|
||||
|
||||
_animation_file = ev._animation_file;
|
||||
_animation_flags = ev._animation_flags;
|
||||
_animation = ev._animation;
|
||||
|
||||
_contour = ev._contour;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void qdInterfaceElementStateMode::set_sound_file(const Common::Path &name) {
|
||||
_sound_file = name;
|
||||
}
|
||||
|
||||
void qdInterfaceElementStateMode::set_animation_file(const Common::Path &name) {
|
||||
_animation_file = name;
|
||||
}
|
||||
|
||||
#define defEnum(x) #x
|
||||
|
||||
static const char *stateModeList[] = {
|
||||
defEnum(DEFAULT_MODE),
|
||||
defEnum(MOUSE_HOVER_MODE),
|
||||
defEnum(EVENT_MODE),
|
||||
};
|
||||
|
||||
Common::String qdInterfaceElementStateMode::stateMode2Str(int fl, bool truncate) const {
|
||||
if (fl >= ARRAYSIZE(stateModeList) || fl < 0)
|
||||
return Common::String::format("<%d>", fl);
|
||||
|
||||
Common::String out(stateModeList[fl]);
|
||||
return truncate ? out.substr(0, out.size() - 5) : out;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementStateMode::save_script(Common::WriteStream &fh, int type_id, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
if (debugChannelSet(-1, kDebugLog)) {
|
||||
fh.writeString(Common::String::format("<state_mode type=\"%s\"", stateMode2Str(type_id).c_str()));
|
||||
} else {
|
||||
fh.writeString(Common::String::format("<state_mode type=\"%d\"", type_id));
|
||||
}
|
||||
|
||||
if (has_animation()) {
|
||||
fh.writeString(Common::String::format(" animation=\"%s\"", qdscr_XML_string(animation_file().toString('\\'))));
|
||||
}
|
||||
|
||||
if (_animation_flags) {
|
||||
if (debugChannelSet(-1, kDebugLog))
|
||||
fh.writeString(Common::String::format(" animation_flags=\"%s\"", qdAnimation::flag2str(_animation_flags).c_str()));
|
||||
else
|
||||
fh.writeString(Common::String::format(" animation_flags=\"%d\"", _animation_flags));
|
||||
}
|
||||
|
||||
if (has_sound()) {
|
||||
fh.writeString(Common::String::format(" sound=\"%s\"", qdscr_XML_string(sound_file().toString('\\'))));
|
||||
}
|
||||
|
||||
if (has_contour()) {
|
||||
fh.writeString(">\r\n");
|
||||
_contour.save_script(fh, indent + 1);
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</state_mode>\r\n");
|
||||
} else {
|
||||
fh.writeString("/>\r\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceElementStateMode::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_SOUND:
|
||||
set_sound_file(Common::Path(it->data(), '\\'));
|
||||
break;
|
||||
case QDSCR_INTERFACE_ANIMATION_FLAGS:
|
||||
xml::tag_buffer(*it) > _animation_flags;
|
||||
break;
|
||||
case QDSCR_ANIMATION:
|
||||
set_animation_file(Common::Path(it->data(), '\\'));
|
||||
break;
|
||||
case QDSCR_CONTOUR_CIRCLE:
|
||||
_contour.set_contour_type(qdContour::CONTOUR_CIRCLE);
|
||||
_contour.load_script(&*it);
|
||||
break;
|
||||
case QDSCR_CONTOUR_RECTANGLE:
|
||||
_contour.set_contour_type(qdContour::CONTOUR_RECTANGLE);
|
||||
_contour.load_script(&*it);
|
||||
break;
|
||||
case QDSCR_CONTOUR_POLYGON:
|
||||
_contour.set_contour_type(qdContour::CONTOUR_POLYGON);
|
||||
_contour.load_script(&*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
158
engines/qdengine/qdcore/qd_interface_element_state_mode.h
Normal file
158
engines/qdengine/qdcore/qd_interface_element_state_mode.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_STATE_MODE_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_STATE_MODE_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "qdengine/qdcore/qd_contour.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Событие, привязанное к состоянию интерфейсного элемента.
|
||||
/**
|
||||
Включает анимацию и звук при выполнении некоторых условий (например при наведении
|
||||
мыши на элемент интерфейса.
|
||||
*/
|
||||
class qdInterfaceElementStateMode {
|
||||
public:
|
||||
qdInterfaceElementStateMode();
|
||||
qdInterfaceElementStateMode(const qdInterfaceElementStateMode &ev);
|
||||
~qdInterfaceElementStateMode();
|
||||
|
||||
qdInterfaceElementStateMode &operator = (const qdInterfaceElementStateMode &ev);
|
||||
|
||||
//! Устанавливает имя файла звука.
|
||||
/**
|
||||
Если надо убрать звук - передать NULL в качестве имени файла.
|
||||
*/
|
||||
void set_sound_file(const Common::Path &name);
|
||||
//! Возвращает имя файла звука.
|
||||
const Common::Path sound_file() const {
|
||||
return _sound_file;
|
||||
}
|
||||
//! Устанавливает звук события.
|
||||
void set_sound(const qdSound *p) {
|
||||
_sound = p;
|
||||
}
|
||||
//! Возвращает звук события.
|
||||
const qdSound *sound() const {
|
||||
return _sound;
|
||||
}
|
||||
//! Возвращает true, если к событию привязан звук.
|
||||
bool has_sound() const {
|
||||
return !_sound_file.empty();
|
||||
}
|
||||
|
||||
//! Устанавливает имя файла для анимации.
|
||||
/**
|
||||
Если надо убрать анимацию - передать NULL в качестве имени файла.
|
||||
*/
|
||||
void set_animation_file(const Common::Path &name);
|
||||
//! Возвращает имя файла для анимации.
|
||||
const Common::Path animation_file() const {
|
||||
return _animation_file;
|
||||
}
|
||||
//! Возвращает флаги анимации.
|
||||
int animation_flags() const {
|
||||
return _animation_flags;
|
||||
}
|
||||
|
||||
//! Устанавливает флаг анимации.
|
||||
void set_animation_flag(int fl) {
|
||||
_animation_flags |= fl;
|
||||
}
|
||||
//! Скидывает флаг анимации.
|
||||
void drop_animation_flag(int fl) {
|
||||
_animation_flags &= ~fl;
|
||||
}
|
||||
//! Возвращает true, если для анимации установлен флаг fl.
|
||||
bool check_animation_flag(int fl) const {
|
||||
if (_animation_flags & fl) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Устанавливает указатель на анимацию события.
|
||||
void set_animation(const qdAnimation *p) {
|
||||
_animation = p;
|
||||
}
|
||||
//! Возвращает указатель на анимацию события.
|
||||
const qdAnimation *animation() const {
|
||||
return _animation;
|
||||
}
|
||||
//! Возвращает true, если к состоянию привязана анимация.
|
||||
bool has_animation() const {
|
||||
return !_animation_file.empty();
|
||||
}
|
||||
//! Возвращает true, если у состояния задан контур.
|
||||
bool has_contour() const {
|
||||
return !_contour.is_contour_empty();
|
||||
}
|
||||
//! Возвращает true, если точка с экранными координатами (x,у) попадает внутрь контура.
|
||||
bool hit_test(int x, int y) const {
|
||||
return _contour.is_inside(Vect2s(x, y));
|
||||
}
|
||||
|
||||
//! Записывает контур в cnt.
|
||||
bool get_contour(qdContour &cnt) const {
|
||||
cnt = _contour;
|
||||
return true;
|
||||
}
|
||||
//! Устанавливает контур.
|
||||
bool set_contour(const qdContour &cnt) {
|
||||
_contour = cnt;
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::String stateMode2Str(int fl, bool truncate = false) const;
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
/**
|
||||
type_id - тип события
|
||||
*/
|
||||
bool save_script(Common::WriteStream &fh, int type_id = 0, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
|
||||
private:
|
||||
|
||||
//! Имя файла звука.
|
||||
Common::Path _sound_file;
|
||||
|
||||
//! Звук, включаемый событием.
|
||||
const qdSound *_sound;
|
||||
|
||||
//! Имя файла для анимации
|
||||
Common::Path _animation_file;
|
||||
//! Флаги для анимации.
|
||||
int _animation_flags;
|
||||
|
||||
//! Анимация, включаемая событием.
|
||||
const qdAnimation *_animation;
|
||||
|
||||
//! Контур.
|
||||
qdContour _contour;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_ELEMENT_STATE_MODE_H
|
||||
47
engines/qdengine/qdcore/qd_interface_object_base.cpp
Normal file
47
engines/qdengine/qdcore/qd_interface_object_base.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_interface_object_base.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceObjectBase::qdInterfaceObjectBase() : _owner(NULL) {
|
||||
}
|
||||
|
||||
qdInterfaceObjectBase::qdInterfaceObjectBase(const qdInterfaceObjectBase &obj) : qdNamedObjectBase(obj),
|
||||
_owner(obj._owner) {
|
||||
}
|
||||
|
||||
qdInterfaceObjectBase::~qdInterfaceObjectBase() {
|
||||
}
|
||||
|
||||
qdInterfaceObjectBase &qdInterfaceObjectBase::operator = (const qdInterfaceObjectBase &obj) {
|
||||
if (this == &obj) return *this;
|
||||
|
||||
*static_cast<qdNamedObjectBase *>(this) = obj;
|
||||
|
||||
_owner = obj._owner;
|
||||
|
||||
return *this;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
59
engines/qdengine/qdcore/qd_interface_object_base.h
Normal file
59
engines/qdengine/qdcore/qd_interface_object_base.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_OBJECT_BASE_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_OBJECT_BASE_H
|
||||
|
||||
#include "qdengine/qdcore/qd_named_object_base.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Базовый класс для всех интерфейсных объектов.
|
||||
class qdInterfaceObjectBase : public qdNamedObjectBase {
|
||||
public:
|
||||
qdInterfaceObjectBase();
|
||||
qdInterfaceObjectBase(const qdInterfaceObjectBase &obj);
|
||||
~qdInterfaceObjectBase();
|
||||
|
||||
//! Устанавливает владельца объекта.
|
||||
void set_owner(qdInterfaceObjectBase *p) {
|
||||
_owner = p;
|
||||
}
|
||||
//! Возвращает указатель на владельца объекта.
|
||||
qdInterfaceObjectBase *owner() const {
|
||||
return _owner;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
qdInterfaceObjectBase &operator = (const qdInterfaceObjectBase &obj);
|
||||
|
||||
private:
|
||||
|
||||
//! Владелец объекта.
|
||||
mutable qdInterfaceObjectBase *_owner;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_OBJECT_BASE_H
|
||||
357
engines/qdengine/qdcore/qd_interface_save.cpp
Normal file
357
engines/qdengine/qdcore/qd_interface_save.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
/* 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/file.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "engines/metaengine.h"
|
||||
|
||||
#include "qdengine/qdengine.h"
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_interface_save.h"
|
||||
#include "qdengine/qdcore/qd_interface_screen.h"
|
||||
#include "qdengine/qdcore/qd_interface_dispatcher.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
bool qdInterfaceSave::_save_mode = false;
|
||||
int qdInterfaceSave::_current_save_ID = 0;
|
||||
|
||||
qdInterfaceSave::qdInterfaceSave() : _save_ID(0),
|
||||
_thumbnail_size_x(0),
|
||||
_thumbnail_size_y(0),
|
||||
_text_dx(0),
|
||||
_text_dy(0) {
|
||||
_thumbnail.set_owner(this);
|
||||
_frame.set_owner(this);
|
||||
|
||||
_isAutosaveSlot = false;
|
||||
|
||||
_save_ID = _current_save_ID++;
|
||||
}
|
||||
|
||||
qdInterfaceSave::qdInterfaceSave(const qdInterfaceSave &sv) : qdInterfaceElement(sv),
|
||||
_save_ID(sv._save_ID),
|
||||
_thumbnail_size_x(sv._thumbnail_size_x),
|
||||
_thumbnail_size_y(sv._thumbnail_size_y),
|
||||
_text_dx(sv.text_dx()),
|
||||
_text_dy(sv.text_dy()),
|
||||
_isAutosaveSlot(sv._isAutosaveSlot) {
|
||||
_thumbnail.set_owner(this);
|
||||
_thumbnail = sv._thumbnail;
|
||||
|
||||
_frame.set_owner(this);
|
||||
_frame = sv._frame;
|
||||
}
|
||||
|
||||
qdInterfaceSave::~qdInterfaceSave() {
|
||||
_thumbnail.unregister_resources();
|
||||
_frame.unregister_resources();
|
||||
}
|
||||
|
||||
qdInterfaceSave &qdInterfaceSave::operator = (const qdInterfaceSave &sv) {
|
||||
if (this == &sv) return *this;
|
||||
|
||||
*static_cast<qdInterfaceElement *>(this) = sv;
|
||||
|
||||
_save_ID = sv._save_ID;
|
||||
|
||||
_thumbnail_size_x = sv._thumbnail_size_x;
|
||||
_thumbnail_size_y = sv._thumbnail_size_y;
|
||||
|
||||
_isAutosaveSlot = sv._isAutosaveSlot;
|
||||
|
||||
_text_dx = sv.text_dx();
|
||||
_text_dy = sv.text_dy();
|
||||
|
||||
_thumbnail = sv._thumbnail;
|
||||
_frame = sv._frame;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
_frame.mouse_handler(x, y, ev);
|
||||
debugC(9, kDebugInput, "qdInterfaceSave::mouse_handler(): ev = %d, x = %d, y = %d", ev, x, y);
|
||||
|
||||
switch (ev) {
|
||||
case mouseDispatcher::EV_LEFT_DOWN:
|
||||
case mouseDispatcher::EV_RIGHT_DOWN:
|
||||
if (/*qdGameDispatcher *dp = */qdGameDispatcher::get_dispatcher()) {
|
||||
debugC(1, kDebugSave, "qdInterfaceSave::mouse_handler(): _save_mode = %d", _save_mode);
|
||||
clear_screen_region();
|
||||
|
||||
if (_save_mode) {
|
||||
if (isAutosaveSlot())
|
||||
return true;
|
||||
|
||||
qdInterfaceDispatcher *ip = qdInterfaceDispatcher::get_dispatcher();
|
||||
if (ip) {
|
||||
if (ip->has_save_title_screen()) {
|
||||
ip->setModalScreenMode(qdInterfaceDispatcher::MODAL_SCREEN_SAVE_NAME_EDIT);
|
||||
ip->handle_event(qdInterfaceEvent::EVENT_SHOW_INTERFACE_SCREEN_AS_MODAL, ip->save_title_screen_name(), this);
|
||||
} else if (ip->has_save_prompt_screen() && g_engine->getSaveFileManager()->exists(g_engine->getSaveStateName(_save_ID))) {
|
||||
ip->setModalScreenMode(qdInterfaceDispatcher::MODAL_SCREEN_SAVE_OVERWRITE);
|
||||
ip->handle_event(qdInterfaceEvent::EVENT_SHOW_INTERFACE_SCREEN_AS_MODAL, ip->save_prompt_screen_name(), this);
|
||||
} else {
|
||||
perform_save();
|
||||
ip->handle_event(qdInterfaceEvent::EVENT_RESUME_GAME, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
debugC(1, kDebugSave, "qdInterfaceSave::mouse_handler(): load_game() _save_ID = %d", _save_ID);
|
||||
g_engine->loadGameState(_save_ID);
|
||||
if (qdInterfaceDispatcher *ip = qdInterfaceDispatcher::get_dispatcher())
|
||||
ip->handle_event(qdInterfaceEvent::EVENT_RESUME_GAME, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::keyboard_handler(Common::KeyCode vkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::init(bool is_game_active) {
|
||||
if (!is_game_active && _frame.need_active_game())
|
||||
set_lock(true);
|
||||
else
|
||||
set_lock(false);
|
||||
|
||||
Common::String saveFileName(g_engine->getSaveStateName(_save_ID));
|
||||
bool fileExists = false;
|
||||
|
||||
if (g_engine->getSaveFileManager()->exists(saveFileName)) {
|
||||
Common::InSaveFile *saveFile = g_engine->getSaveFileManager()->openForLoading(saveFileName);
|
||||
|
||||
fileExists = true;
|
||||
|
||||
ExtendedSavegameHeader header;
|
||||
|
||||
if (MetaEngine::readSavegameHeader(saveFile, &header, true))
|
||||
_save_title = header.description.c_str();
|
||||
|
||||
delete saveFile;
|
||||
|
||||
_thumbnail.set_animation_file(Common::Path(Common::String::format("scummvm/%s", saveFileName.c_str())));
|
||||
} else {
|
||||
_save_title = "";
|
||||
}
|
||||
|
||||
set_state(&_frame);
|
||||
|
||||
if (!_save_mode && !fileExists) {
|
||||
if (is_visible()) {
|
||||
debugC(3, kDebugInput, "qdInterfaceSave::init(): Hide %s", saveFileName.c_str());
|
||||
hide();
|
||||
|
||||
if (qdInterfaceScreen *sp = dynamic_cast<qdInterfaceScreen * >(owner()))
|
||||
sp->build_visible_elements_list();
|
||||
}
|
||||
} else {
|
||||
if (!is_visible()) {
|
||||
show();
|
||||
|
||||
if (qdInterfaceScreen *sp = dynamic_cast<qdInterfaceScreen * >(owner()))
|
||||
sp->build_visible_elements_list();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::redraw() const {
|
||||
//warning("STUB: qdInterfaceSave::redraw()");
|
||||
if (qdInterfaceDispatcher *pid = qdInterfaceDispatcher::get_dispatcher()) {
|
||||
if (pid->need_save_screenshot())
|
||||
if (const qdAnimation *p = _thumbnail.animation())
|
||||
p->redraw(r().x, r().y, 0);
|
||||
|
||||
Common::String text;
|
||||
|
||||
if (pid->need_show_save_title()) {
|
||||
text = title();
|
||||
if (pid->need_show_save_time())
|
||||
text += " ";
|
||||
}
|
||||
|
||||
grDispatcher *gr_disp = grDispatcher::instance();
|
||||
if (!text.empty()) {
|
||||
qdGameDispatcher *game_disp = qdGameDispatcher::get_dispatcher();
|
||||
const grFont *font = NULL;
|
||||
if ((QD_FONT_TYPE_NONE != pid->save_font_type()) && game_disp)
|
||||
font = game_disp->find_font(pid->save_font_type());
|
||||
else
|
||||
font = gr_disp->get_default_font();
|
||||
|
||||
int tx = r().x - size_x() / 2 + text_dx();
|
||||
int ty = r().y - size_y() / 2 + text_dy();
|
||||
|
||||
gr_disp->drawText(tx, ty, pid->save_font_color(), text.c_str(), 0, 0, font);
|
||||
}
|
||||
}
|
||||
|
||||
return qdInterfaceElement::redraw();
|
||||
}
|
||||
|
||||
grScreenRegion qdInterfaceSave::screen_region() const {
|
||||
grScreenRegion reg0 = qdInterfaceElement::screen_region();
|
||||
grScreenRegion reg1(r().x, r().y, _thumbnail_size_x, _thumbnail_size_y);
|
||||
|
||||
reg0 += reg1;
|
||||
|
||||
return reg0;
|
||||
}
|
||||
|
||||
int qdInterfaceSave::size_x() const {
|
||||
int x = _thumbnail_size_x;
|
||||
if (const qdAnimation *p = _frame.animation()) {
|
||||
if (x < p->size_x())
|
||||
x = p->size_x();
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
int qdInterfaceSave::size_y() const {
|
||||
int y = _thumbnail_size_y;
|
||||
if (const qdAnimation *p = _frame.animation()) {
|
||||
if (y < p->size_y())
|
||||
y = p->size_y();
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::quant(float dt) {
|
||||
qdInterfaceElement::quant(dt);
|
||||
|
||||
_frame.quant(dt);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::hit_test(int x, int y) const {
|
||||
if (qdInterfaceElement::hit_test(x, y)) return true;
|
||||
|
||||
x -= r().x;
|
||||
y -= r().y;
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (x >= -_thumbnail_size_x / 2 && x < _thumbnail_size_x / 2 && y >= -_thumbnail_size_y / 2 && y < _thumbnail_size_y / 2)
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::perform_save() {
|
||||
bool is_ok = true;
|
||||
if (qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher()) {
|
||||
debugC(1, kDebugSave, "qdInterfaceSave::perform_save(): _save_ID = %d", _save_ID);
|
||||
is_ok &= (g_engine->saveGameState(_save_ID, _save_title.c_str(), dp->is_autosave_slot(_save_ID)).getCode() == Common::kNoError);
|
||||
|
||||
debugC(1, kDebugSave, "qdInterfaceSave::perform_save(): is_ok = %d", is_ok);
|
||||
|
||||
is_ok &= init(true);
|
||||
return is_ok;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
if (!_frame.save_script(fh, indent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<ID>%d</ID>\r\n", _save_ID));
|
||||
|
||||
if (_thumbnail_size_x || _thumbnail_size_y) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<thumbnail_size>%d %d</thumbnail_size>\r\n", _thumbnail_size_x, _thumbnail_size_y));
|
||||
}
|
||||
|
||||
if (_text_dx || _text_dy) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<text_shift>%d %d</text_shift>\r\n", _text_dx, _text_dy));
|
||||
}
|
||||
|
||||
if (isAutosaveSlot()) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("<is_autosave>1</is_autosave>\r\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceSave::load_script_body(const xml::tag *p) {
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_INTERFACE_ELEMENT_STATE:
|
||||
if (!_frame.load_script(&*it)) return false;
|
||||
break;
|
||||
case QDSCR_INTERFACE_THUMBNAIL_SIZE:
|
||||
xml::tag_buffer(*it) > _thumbnail_size_x > _thumbnail_size_y;
|
||||
|
||||
g_engine->_thumbSizeX = _thumbnail_size_x;
|
||||
g_engine->_thumbSizeY = _thumbnail_size_y;
|
||||
break;
|
||||
case QDSCR_INTERFACE_TEXT_SHIFT:
|
||||
xml::tag_buffer(*it) > _text_dx > _text_dy;
|
||||
break;
|
||||
case QDSCR_ID:
|
||||
xml::tag_buffer(*it) > _save_ID;
|
||||
break;
|
||||
case QDSCR_INTERFACE_SAVE_IS_AUTOSAVE:
|
||||
setAutosaveSlot(xml::tag_buffer(*it).get_int() != 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
220
engines/qdengine/qdcore/qd_interface_save.h
Normal file
220
engines/qdengine/qdcore/qd_interface_save.h
Normal file
@@ -0,0 +1,220 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_SAVE_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_SAVE_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
//! Интерфейсный элемент - сэйв.
|
||||
class qdInterfaceSave : public qdInterfaceElement {
|
||||
public:
|
||||
qdInterfaceSave();
|
||||
qdInterfaceSave(const qdInterfaceSave &sv);
|
||||
~qdInterfaceSave();
|
||||
|
||||
qdInterfaceSave &operator = (const qdInterfaceSave &sv);
|
||||
|
||||
//! Возвращает тип элемента.
|
||||
qdInterfaceElement::element_type get_element_type() const {
|
||||
return qdInterfaceElement::EL_SAVE;
|
||||
}
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
|
||||
//! Инициализация элемента.
|
||||
/**
|
||||
Вызывается каждый раз при заходе на экран, которому принадлежит элемент.
|
||||
*/
|
||||
bool init(bool is_game_active = true);
|
||||
|
||||
//! Отрисовка элемента.
|
||||
bool redraw() const;
|
||||
|
||||
grScreenRegion screen_region() const;
|
||||
|
||||
//! Возвращает размер элемента по горизонтали в пикселах.
|
||||
int size_x() const;
|
||||
//! Возвращает размер элемента по вертикали в пикселах.
|
||||
int size_y() const;
|
||||
|
||||
//! Возвращает размер картики-превью по горизонтали в пикселах.
|
||||
int thumbnail_size_x() const {
|
||||
return _thumbnail_size_x;
|
||||
}
|
||||
//! Возвращает размер картики-превью по вертикали в пикселах.
|
||||
int thumbnail_size_y() const {
|
||||
return _thumbnail_size_y;
|
||||
}
|
||||
|
||||
//! Назначает размер картики-превью по горизонтали в пикселах.
|
||||
void set_thumbnail_size_x(int sx) {
|
||||
_thumbnail_size_x = sx;
|
||||
}
|
||||
//! Назначает размер картики-превью по вертикали в пикселах.
|
||||
void set_thumbnail_size_y(int sy) {
|
||||
_thumbnail_size_y = sy;
|
||||
}
|
||||
|
||||
//! Смещение текста, выводимого в сэйве, относительно левого-верхнего угла
|
||||
int text_dx() const {
|
||||
return _text_dx;
|
||||
}
|
||||
int text_dy() const {
|
||||
return _text_dy;
|
||||
}
|
||||
void set_test_dx(int val) {
|
||||
_text_dx = val;
|
||||
}
|
||||
void set_test_dy(int val) {
|
||||
_text_dy = val;
|
||||
}
|
||||
|
||||
//! Обсчет логики, параметр - время в секундах.
|
||||
bool quant(float dt);
|
||||
|
||||
//! Возвращает true, если точка с экранными координатами (x,у) попадает в элемент.
|
||||
bool hit_test(int x, int y) const;
|
||||
|
||||
//! Возвращает номер сэйва.
|
||||
int save_ID() const {
|
||||
return _save_ID;
|
||||
}
|
||||
//! Устанавливает номер сэйва.
|
||||
void set_save_ID(int id) {
|
||||
_save_ID = id;
|
||||
}
|
||||
|
||||
//! Устанавливает режим работы - записывать (state == true) или загружать (state == false) сэйвы.
|
||||
static void set_save_mode(bool state) {
|
||||
_save_mode = state;
|
||||
}
|
||||
|
||||
//! Устанавливает имя файла для анимации.
|
||||
/**
|
||||
Если надо убрать анимацию - передать NULL в качестве имени файла.
|
||||
*/
|
||||
void set_frame_animation_file(const Common::Path &name, qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) {
|
||||
_frame.set_animation_file(name, mode);
|
||||
}
|
||||
//! Возвращает имя файла для анимации.
|
||||
const Common::Path frame_animation_file(qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) const {
|
||||
return _frame.animation_file(mode);
|
||||
}
|
||||
//! Возвращает флаги анимации.
|
||||
int frame_animation_flags(qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) const {
|
||||
return _frame.animation_flags(mode);
|
||||
}
|
||||
|
||||
//! Устанавливает флаг анимации.
|
||||
void set_frame_animation_flag(int fl, qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) {
|
||||
_frame.set_animation_flag(fl, mode);
|
||||
}
|
||||
//! Скидывает флаг анимации.
|
||||
void drop_frame_animation_flag(int fl, qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) {
|
||||
_frame.drop_animation_flag(fl, mode);
|
||||
}
|
||||
//! Возвращает true, если для анимации установлен флаг fl.
|
||||
bool check_frame_animation_flag(int fl, qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) const {
|
||||
return _frame.check_animation_flag(fl, mode);
|
||||
}
|
||||
|
||||
//! Возвращает true, если к сейву привязана анимация рамки.
|
||||
bool frame_has_animation(qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) const {
|
||||
return _frame.has_animation(mode);
|
||||
}
|
||||
|
||||
void set_frame_sound_file(const char *name, qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) {
|
||||
_frame.set_sound_file(name, mode);
|
||||
}
|
||||
const Common::Path frame_sound_file(qdInterfaceElementState::state_mode_t mode = qdInterfaceElementState::MOUSE_HOVER_MODE) const {
|
||||
return _frame.sound_file(mode);
|
||||
}
|
||||
|
||||
bool isAutosaveSlot() const {
|
||||
return _isAutosaveSlot;
|
||||
}
|
||||
void setAutosaveSlot(bool state) {
|
||||
_isAutosaveSlot = state;
|
||||
}
|
||||
|
||||
void set_title(const char *title) {
|
||||
_save_title = title;
|
||||
}
|
||||
const char *title() const {
|
||||
return _save_title.c_str();
|
||||
}
|
||||
|
||||
//! Осуществить сохранение текущего состояния игры в ячейку сэйва.
|
||||
bool perform_save();
|
||||
|
||||
protected:
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script_body(const xml::tag *p);
|
||||
|
||||
private:
|
||||
|
||||
//! Горизонтальный размер картинки-превью сэйва.
|
||||
int _thumbnail_size_x;
|
||||
//! Вертикальный размер картинки-превью сэйва.
|
||||
int _thumbnail_size_y;
|
||||
|
||||
//! Смещение текста, выводимого в сэйве, относительно левого-верхнего угла
|
||||
int _text_dx;
|
||||
int _text_dy;
|
||||
|
||||
//! Номер сэйва, имя файла имеет вид saveNNN.dat, где NNN - save_ID_.
|
||||
int _save_ID;
|
||||
|
||||
/// если true, то игрок сам не может записать игру в этот слот
|
||||
bool _isAutosaveSlot;
|
||||
|
||||
//! Превью сэйва.
|
||||
qdInterfaceElementState _thumbnail;
|
||||
|
||||
Common::String _save_title;
|
||||
|
||||
//! Опциональная рамка вокруг картинки-превью сэйва.
|
||||
qdInterfaceElementState _frame;
|
||||
|
||||
//! Режим работы сэйвов - чтение/запись (== false/true).
|
||||
static bool _save_mode;
|
||||
|
||||
//! Текущий номер сэйва.
|
||||
static int _current_save_ID;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_SAVE_H
|
||||
400
engines/qdengine/qdcore/qd_interface_screen.cpp
Normal file
400
engines/qdengine/qdcore/qd_interface_screen.cpp
Normal file
@@ -0,0 +1,400 @@
|
||||
/* 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 "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_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_interface_button.h"
|
||||
#include "qdengine/qdcore/qd_interface_screen.h"
|
||||
#include "qdengine/qdcore/qd_interface_dispatcher.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_game_scene.h"
|
||||
#include "qdengine/qdcore/qd_game_object_moving.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
struct qdInterfaceElementsOrdering {
|
||||
bool operator()(const qdInterfaceElement *p0, const qdInterfaceElement *p1) {
|
||||
return p0->screen_depth() < p1->screen_depth();
|
||||
}
|
||||
};
|
||||
|
||||
qdInterfaceScreen::qdInterfaceScreen() : _is_locked(false),
|
||||
_autohide_time(0.0f),
|
||||
_autohide_phase(1.0f),
|
||||
_autohide_offset(Vect2i(0, 0)),
|
||||
_modal_caller(NULL) {
|
||||
_sorted_elements.reserve(20);
|
||||
}
|
||||
|
||||
qdInterfaceScreen::~qdInterfaceScreen() {
|
||||
_elements.clear();
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::redraw(int dx, int dy) const {
|
||||
debugC(6, kDebugText, "qdInterfaceScreen::redraw(): %d elements", _sorted_elements.size());
|
||||
|
||||
for (sorted_element_list_t::const_reverse_iterator it = _sorted_elements.rbegin(); it != _sorted_elements.rend(); ++it)
|
||||
(*it)->redraw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::pre_redraw(bool force_full_redraw) {
|
||||
qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher();
|
||||
if (!dp) return false;
|
||||
|
||||
if (force_full_redraw) {
|
||||
for (sorted_element_list_t::iterator it = _sorted_elements.begin(); it != _sorted_elements.end(); ++it) {
|
||||
if ((*it)->last_screen_region() != (*it)->screen_region())
|
||||
dp->add_redraw_region((*it)->last_screen_region());
|
||||
|
||||
dp->add_redraw_region((*it)->screen_region());
|
||||
}
|
||||
} else {
|
||||
for (sorted_element_list_t::iterator it = _sorted_elements.begin(); it != _sorted_elements.end(); ++it) {
|
||||
if ((*it)->need_redraw()) {
|
||||
if ((*it)->last_screen_region() != (*it)->screen_region())
|
||||
dp->add_redraw_region((*it)->last_screen_region());
|
||||
|
||||
dp->add_redraw_region((*it)->screen_region());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::post_redraw() {
|
||||
for (sorted_element_list_t::iterator it = _sorted_elements.begin(); it != _sorted_elements.end(); ++it)
|
||||
(*it)->post_redraw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::quant(float dt) {
|
||||
debugC(9, kDebugQuant, "qdInterfaceScreen::quant(%f)", dt);
|
||||
if (_autohide_time > FLT_EPS) {
|
||||
float delta = dt / _autohide_time;
|
||||
|
||||
qdInterfaceDispatcher *dp = dynamic_cast<qdInterfaceDispatcher *>(owner());
|
||||
|
||||
if (dp && !dp->is_autohide_enabled())
|
||||
_autohide_phase -= delta;
|
||||
else
|
||||
_autohide_phase += delta;
|
||||
|
||||
if (_autohide_phase < 0.0f)
|
||||
_autohide_phase = 0.0f;
|
||||
if (_autohide_phase > 1.0f)
|
||||
_autohide_phase = 1.0f;
|
||||
|
||||
int x = round(float(_autohide_offset.x) * _autohide_phase);
|
||||
int y = round(float(_autohide_offset.y) * _autohide_phase);
|
||||
|
||||
g_engine->set_screen_offset(Vect2i(x, y));
|
||||
} else {
|
||||
g_engine->set_screen_offset(Vect2i(0, 0));
|
||||
}
|
||||
|
||||
for (element_list_t::const_iterator it = element_list().begin(); it != element_list().end(); ++it) {
|
||||
if ((*it)->linked_to_option() && qdInterfaceDispatcher::option_value((*it)->option_ID()) != (*it)->option_value())
|
||||
qdInterfaceDispatcher::set_option_value((*it)->option_ID(), (*it)->option_value());
|
||||
|
||||
(*it)->quant(dt);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("<interface_screen");
|
||||
|
||||
if (name()) {
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
}
|
||||
|
||||
if (_autohide_time > FLT_EPS) {
|
||||
fh.writeString(Common::String::format(" hide_time=\"%f\"", _autohide_time));
|
||||
}
|
||||
|
||||
if (_autohide_offset.x || _autohide_offset.y) {
|
||||
fh.writeString(Common::String::format(" hide_offset=\"%d %d\"", _autohide_offset.x, _autohide_offset.y));
|
||||
}
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
if (has_music_track()) {
|
||||
_music_track.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (auto &it : element_list()) {
|
||||
it->save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</interface_screen>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::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_INTERFACE_ELEMENT:
|
||||
if (const xml::tag *tg = it->search_subtag(QDSCR_TYPE)) {
|
||||
if (qdInterfaceElement *el = qdInterfaceElement::create_element(static_cast<qdInterfaceElement::element_type>(xml::tag_buffer(*tg).get_int()))) {
|
||||
el->set_owner(this);
|
||||
el->load_script(&*it);
|
||||
add_element(el);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QDSCR_INTERFACE_SCREEN_HIDE_TIME:
|
||||
xml::tag_buffer(*it) > _autohide_time;
|
||||
break;
|
||||
case QDSCR_INTERFACE_SCREEN_HIDE_OFFSET:
|
||||
xml::tag_buffer(*it) > _autohide_offset.x > _autohide_offset.y;
|
||||
break;
|
||||
case QDSCR_MUSIC_TRACK:
|
||||
_music_track.load_script(&*it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::add_element(qdInterfaceElement *p) {
|
||||
debugC(3, kDebugText, "qdInterfaceScreen::add_element('%s')", transCyrillic(p->name()));
|
||||
|
||||
if (_elements.add_object(p)) {
|
||||
_sorted_elements.push_back(p);
|
||||
sort_elements();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::rename_element(qdInterfaceElement *p, const char *name) {
|
||||
return _elements.rename_object(p, name);
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::remove_element(qdInterfaceElement *p) {
|
||||
sorted_element_list_t::iterator it = Common::find(_sorted_elements.begin(), _sorted_elements.end(), p);
|
||||
if (it != _sorted_elements.end())
|
||||
_sorted_elements.erase(it);
|
||||
return _elements.remove_object(p);
|
||||
}
|
||||
|
||||
qdInterfaceElement *qdInterfaceScreen::get_element(const char *el_name) {
|
||||
return _elements.get_object(el_name);
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::is_element_in_list(const qdInterfaceElement *el) const {
|
||||
return _elements.is_in_list(el);
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
debugC(9, kDebugInput, "qdInterfaceScreen::mouse_handler(%d, %d, %u)", x, y, _sorted_elements.size());
|
||||
if (qdInterfaceDispatcher *dp = dynamic_cast<qdInterfaceDispatcher* >(owner())) {
|
||||
for (auto &it : _sorted_elements) {
|
||||
if (it->hit_test(x, y)) {
|
||||
if (ev != mouseDispatcher::EV_MOUSE_MOVE)
|
||||
debugC(2, kDebugInput, "qdInterfaceScreen::mouse_handler(): [%d, %d], ev: %d", x, y, ev);
|
||||
|
||||
dp->toggle_mouse_hover();
|
||||
if (it->get_element_type() != qdInterfaceElement::EL_TEXT_WINDOW)
|
||||
dp->disable_autohide();
|
||||
|
||||
if (!it->is_locked() && it->mouse_handler(x, y, ev))
|
||||
return true;
|
||||
} else
|
||||
it->hover_clear();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::keyboard_handler(Common::KeyCode vkey) {
|
||||
for (element_list_t::const_iterator it = element_list().begin(); it != element_list().end(); ++it) {
|
||||
if (!(*it)->is_locked() && (*it)->keyboard_handler(vkey))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::char_input_handler(int vkey) {
|
||||
for (element_list_t::const_iterator it = element_list().begin(); it != element_list().end(); ++it) {
|
||||
if (!(*it)->is_locked() && (*it)->char_input_handler(vkey))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdResource *qdInterfaceScreen::add_resource(const Common::Path &file_name, const qdInterfaceElementState *res_owner) {
|
||||
if (qdInterfaceDispatcher *dp = dynamic_cast<qdInterfaceDispatcher * >(owner())) {
|
||||
if (qdResource *p = dp->add_resource(file_name, res_owner)) {
|
||||
_resources.register_resource(p, res_owner);
|
||||
if (dp->is_screen_active(this) && !p->is_resource_loaded())
|
||||
p->load_resource();
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::remove_resource(const Common::Path &file_name, const qdInterfaceElementState *res_owner) {
|
||||
if (qdInterfaceDispatcher *dp = dynamic_cast<qdInterfaceDispatcher * >(owner())) {
|
||||
if (qdResource *p = dp->get_resource(file_name)) {
|
||||
_resources.unregister_resource(p, res_owner);
|
||||
return dp->remove_resource(file_name, res_owner);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::init(bool is_game_active) {
|
||||
for (element_list_t::const_iterator it = element_list().begin(); it != element_list().end(); ++it) {
|
||||
(*it)->init(is_game_active);
|
||||
if ((*it)->linked_to_option())
|
||||
(*it)->set_option_value(qdInterfaceDispatcher::option_value((*it)->option_ID()));
|
||||
}
|
||||
|
||||
build_visible_elements_list();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::hide_element(const char *element_name, bool temporary_hide) {
|
||||
if (qdInterfaceElement *p = get_element(element_name))
|
||||
return hide_element(p, temporary_hide);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::hide_element(qdInterfaceElement *p, bool temporary_hide) {
|
||||
if (!temporary_hide)
|
||||
p->hide();
|
||||
|
||||
sorted_element_list_t::iterator it = Common::find(_sorted_elements.begin(), _sorted_elements.end(), p);
|
||||
if (it != _sorted_elements.end())
|
||||
_sorted_elements.erase(it);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::show_element(const char *element_name) {
|
||||
if (qdInterfaceElement *p = get_element(element_name))
|
||||
return show_element(p);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::show_element(qdInterfaceElement *p) {
|
||||
p->show();
|
||||
|
||||
debugC(2, kDebugText, "qdInterfaceScreen::show_element('%s')", transCyrillic(p->name()));
|
||||
|
||||
sorted_element_list_t::iterator it = Common::find(_sorted_elements.begin(), _sorted_elements.end(), p);
|
||||
if (it == _sorted_elements.end()) {
|
||||
_sorted_elements.push_back(p);
|
||||
sort_elements();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::sort_elements() {
|
||||
Common::sort(_sorted_elements.begin(), _sorted_elements.end(), qdInterfaceElementsOrdering());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceScreen::build_visible_elements_list() {
|
||||
_sorted_elements.clear();
|
||||
|
||||
for (element_list_t::const_iterator it = element_list().begin(); it != element_list().end(); ++it) {
|
||||
if ((*it)->is_visible())
|
||||
_sorted_elements.push_back(*it);
|
||||
}
|
||||
|
||||
sort_elements();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdInterfaceScreen::activate_personage_buttons(const qdNamedObject *p) {
|
||||
for (element_list_t::const_iterator it = element_list().begin(); it != element_list().end(); ++it) {
|
||||
if (qdInterfaceButton *bt = dynamic_cast<qdInterfaceButton *>(*it)) {
|
||||
if (const qdInterfaceEvent *ev = bt->find_event(qdInterfaceEvent::EVENT_ACTIVATE_PERSONAGE)) {
|
||||
if (p) {
|
||||
if (ev->has_data() && !strcmp(p->name(), ev->event_data()))
|
||||
bt->activate_state(1);
|
||||
else
|
||||
bt->activate_state(0);
|
||||
} else
|
||||
bt->activate_state(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qdInterfaceScreen::update_personage_buttons() {
|
||||
qdGameDispatcher *p = qdGameDispatcher::get_dispatcher();
|
||||
if (!p) return;
|
||||
|
||||
qdGameScene *sp = p->get_active_scene();
|
||||
if (!sp) return;
|
||||
|
||||
for (element_list_t::const_iterator it = element_list().begin(); it != element_list().end(); ++it) {
|
||||
if (qdInterfaceButton *bt = dynamic_cast<qdInterfaceButton * >(*it)) {
|
||||
if (!sp->set_personage_button(bt)) {
|
||||
if (bt->find_event(qdInterfaceEvent::EVENT_ACTIVATE_PERSONAGE))
|
||||
hide_element(bt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
202
engines/qdengine/qdcore/qd_interface_screen.h
Normal file
202
engines/qdengine/qdcore/qd_interface_screen.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_SCREEN_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_SCREEN_H
|
||||
|
||||
#include "common/keyboard.h"
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/xmath.h"
|
||||
#include "qdengine/qdcore/qd_interface_object_base.h"
|
||||
#include "qdengine/qdcore/qd_object_list_container.h"
|
||||
#include "qdengine/qdcore/qd_resource_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_music_track.h"
|
||||
#include "qdengine/system/graphics/gr_screen_region.h"
|
||||
#include "qdengine/system/input/mouse_input.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdInterfaceElement;
|
||||
class qdInterfaceElementState;
|
||||
|
||||
//! Интерфейсный экран.
|
||||
class qdInterfaceScreen : public qdInterfaceObjectBase {
|
||||
public:
|
||||
qdInterfaceScreen();
|
||||
~qdInterfaceScreen();
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
|
||||
//! Отрисовка экрана.
|
||||
bool redraw(int dx = 0, int dy = 0) const;
|
||||
|
||||
bool pre_redraw(bool force_full_redraw = false);
|
||||
bool post_redraw();
|
||||
|
||||
//! Обсчет логики, параметр - время в секундах.
|
||||
bool quant(float dt);
|
||||
|
||||
//! Добавление элемента.
|
||||
bool add_element(qdInterfaceElement *p);
|
||||
//! Изменение имени элемента.
|
||||
bool rename_element(qdInterfaceElement *p, const char *name);
|
||||
//! Удаление элемента из списка.
|
||||
bool remove_element(qdInterfaceElement *p);
|
||||
//! Поиск элемента по имени.
|
||||
qdInterfaceElement *get_element(const char *el_name);
|
||||
//! Возвращает true, если элемент есть в списке.
|
||||
bool is_element_in_list(const qdInterfaceElement *el) const;
|
||||
|
||||
typedef Std::list<qdInterfaceElement *> element_list_t;
|
||||
//! Возвращает список элементов экрана.
|
||||
const element_list_t &element_list() const {
|
||||
return _elements.get_list();
|
||||
}
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
bool char_input_handler(int vkey);
|
||||
|
||||
//! Добавляет ресурс file_name с владельцем owner.
|
||||
qdResource *add_resource(const Common::Path &file_name, const qdInterfaceElementState *res_owner);
|
||||
//! Удаляет ресурс file_name с владельцем owner.
|
||||
bool remove_resource(const Common::Path &file_name, const qdInterfaceElementState *res_owner);
|
||||
//! Возвращает true, если на ресурс есть ссылки.
|
||||
bool has_references(const qdResource *p) const {
|
||||
return _resources.is_registered(p);
|
||||
}
|
||||
|
||||
//! Прячет элемент.
|
||||
bool hide_element(const char *element_name, bool temporary_hide = true);
|
||||
//! Прячет элемент.
|
||||
bool hide_element(qdInterfaceElement *p, bool temporary_hide = true);
|
||||
//! Показывает элемент.
|
||||
bool show_element(const char *element_name);
|
||||
//! Показывает элемент.
|
||||
bool show_element(qdInterfaceElement *p);
|
||||
|
||||
//! Инициализация экрана при заходе на него.
|
||||
bool init(bool is_game_active = true);
|
||||
|
||||
//! Строит сортированный список видимых элементов.
|
||||
bool build_visible_elements_list();
|
||||
|
||||
//! Устанавливает, что ресурсы экрана не надо выгружать при выходе с него.
|
||||
void lock_resources() {
|
||||
_is_locked = true;
|
||||
}
|
||||
//! Устанавливает, что ресурсы экрана надо выгружать при выходе с него.
|
||||
void unlock_resources() {
|
||||
_is_locked = false;
|
||||
}
|
||||
//! Возвращает true, если ресурсы экрана не надо выгружать при выходе с него.
|
||||
bool is_locked() const {
|
||||
return _is_locked;
|
||||
}
|
||||
|
||||
//! Включает кнопки, связанные с персонажем p, выключает кнопки остальных персонажей.
|
||||
void activate_personage_buttons(const qdNamedObject *p);
|
||||
|
||||
void update_personage_buttons();
|
||||
|
||||
float autohide_time() const {
|
||||
return _autohide_time;
|
||||
}
|
||||
void set_autohide_time(float time) {
|
||||
_autohide_time = time;
|
||||
}
|
||||
|
||||
const Vect2i &autohide_offset() const {
|
||||
return _autohide_offset;
|
||||
}
|
||||
void set_autohide_offset(const Vect2i &offset) {
|
||||
_autohide_offset = offset;
|
||||
}
|
||||
|
||||
//! Фоновая музыка.
|
||||
const qdMusicTrack &music_track() const {
|
||||
return _music_track;
|
||||
}
|
||||
//! Устанавливает фоновую музыку.
|
||||
void set_music_track(const qdMusicTrack &track) {
|
||||
_music_track = track;
|
||||
}
|
||||
//! Возвращает true, если экрану задана фоновая музыка.
|
||||
bool has_music_track() const {
|
||||
return _music_track.has_file_name();
|
||||
}
|
||||
|
||||
void set_autohide_phase(float ph) {
|
||||
_autohide_phase = ph;
|
||||
}
|
||||
|
||||
// Указатель на объект, последним вызвавший данный как модальный экран
|
||||
qdInterfaceObjectBase *modal_caller() {
|
||||
return _modal_caller;
|
||||
}
|
||||
void set_modal_caller(qdInterfaceObjectBase *caller) {
|
||||
_modal_caller = caller;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
//! Список интерфейсных элементов экрана.
|
||||
qdObjectListContainer<qdInterfaceElement> _elements;
|
||||
|
||||
//! Ресурсы, на которые ссылается экран.
|
||||
qdResourceDispatcher<qdInterfaceElementState> _resources;
|
||||
|
||||
typedef Std::vector<qdInterfaceElement *> sorted_element_list_t;
|
||||
//! Отсортированный по глубине список элементов экрана.
|
||||
sorted_element_list_t _sorted_elements;
|
||||
|
||||
//! Сортирует элементы по глубине.
|
||||
bool sort_elements();
|
||||
|
||||
//! true, если ресурсы экрана не надо выгружать при выходе с него.
|
||||
bool _is_locked;
|
||||
|
||||
//! Время всплывания экрана в секундах.
|
||||
float _autohide_time;
|
||||
//! Смещение экрана, когда он минимизирован.
|
||||
Vect2i _autohide_offset;
|
||||
|
||||
//! Текущая фаза всплывания экрана.
|
||||
float _autohide_phase;
|
||||
|
||||
//! Фоновая музыка.
|
||||
qdMusicTrack _music_track;
|
||||
|
||||
//! Указатель на объект, который последним вызвал данный экран в качестве модального
|
||||
qdInterfaceObjectBase *_modal_caller;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_SCREEN_H
|
||||
341
engines/qdengine/qdcore/qd_interface_slider.cpp
Normal file
341
engines/qdengine/qdcore/qd_interface_slider.cpp
Normal file
@@ -0,0 +1,341 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/qdcore/qd_interface_slider.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdInterfaceSlider::qdInterfaceSlider() : _active_rectangle(0, 0),
|
||||
_phase(0.5f),
|
||||
_orientation(SL_HORIZONTAL),
|
||||
_track_mouse(false),
|
||||
_background_offset(Vect2i(0, 0)) {
|
||||
_inverse_direction = false;
|
||||
_background.set_owner(this);
|
||||
_slider.set_owner(this);
|
||||
}
|
||||
|
||||
qdInterfaceSlider::qdInterfaceSlider(const qdInterfaceSlider &sl) : qdInterfaceElement(sl),
|
||||
_active_rectangle(sl._active_rectangle),
|
||||
_phase(sl._phase),
|
||||
_orientation(sl._orientation),
|
||||
_inverse_direction(sl._inverse_direction),
|
||||
_track_mouse(false) {
|
||||
_background.set_owner(this);
|
||||
_slider.set_owner(this);
|
||||
|
||||
_background = sl._background;
|
||||
_background_offset = sl._background_offset;
|
||||
_slider = sl._slider;
|
||||
}
|
||||
|
||||
qdInterfaceSlider::~qdInterfaceSlider() {
|
||||
_background.unregister_resources();
|
||||
_slider.unregister_resources();
|
||||
}
|
||||
|
||||
qdInterfaceSlider &qdInterfaceSlider::operator = (const qdInterfaceSlider &sl) {
|
||||
if (this == &sl) return *this;
|
||||
|
||||
*static_cast<qdInterfaceElement *>(this) = sl;
|
||||
|
||||
_background = sl._background;
|
||||
_background_offset = sl._background_offset;
|
||||
_slider = sl._slider;
|
||||
|
||||
_active_rectangle = sl._active_rectangle;
|
||||
|
||||
_phase = sl._phase;
|
||||
_orientation = sl._orientation;
|
||||
_inverse_direction = sl._inverse_direction;
|
||||
|
||||
_track_mouse = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
x -= r().x;
|
||||
y -= r().y;
|
||||
|
||||
Vect2i rect(_active_rectangle);
|
||||
if (!_slider_animation.is_empty()) {
|
||||
if (rect.x < _slider_animation.size_x())
|
||||
rect.x = _slider_animation.size_x();
|
||||
if (rect.y < _slider_animation.size_y())
|
||||
rect.y = _slider_animation.size_y();
|
||||
}
|
||||
|
||||
switch (ev) {
|
||||
case mouseDispatcher::EV_LEFT_DOWN:
|
||||
if (x >= -rect.x / 2 && x < rect.x / 2 && y >= -rect.y / 2 && y < rect.y / 2) {
|
||||
set_phase(offset2phase(Vect2i(x, y)));
|
||||
_track_mouse = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case mouseDispatcher::EV_MOUSE_MOVE:
|
||||
if (_track_mouse) {
|
||||
if (mouseDispatcher::instance()->is_pressed(mouseDispatcher::ID_BUTTON_LEFT)) {
|
||||
set_phase(offset2phase(Vect2i(x, y)));
|
||||
return true;
|
||||
} else
|
||||
_track_mouse = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::keyboard_handler(Common::KeyCode vkey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int qdInterfaceSlider::option_value() const {
|
||||
return round(_phase * 255.0f);
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::set_option_value(int value) {
|
||||
set_phase(float(value) / 255.0f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::init(bool is_game_active) {
|
||||
set_state(&_background);
|
||||
set_slider_animation(_slider.animation());
|
||||
|
||||
_track_mouse = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
if (!_background.save_script(fh, indent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_slider.save_script(fh, indent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_active_rectangle.x || _active_rectangle.y) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<slider_rect>%d %d</slider_rect>\r\n", _active_rectangle.x, _active_rectangle.y));
|
||||
}
|
||||
|
||||
if (_background_offset.x || _background_offset.y) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<background_offset>%d %d</background_offset>\r\n", _background_offset.x, _background_offset.y));
|
||||
}
|
||||
|
||||
if (_orientation != SL_HORIZONTAL) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<slider_orientation>%d</slider_orientation>\r\n", int(_orientation)));
|
||||
}
|
||||
|
||||
if (_inverse_direction) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("<inverse_direction>1</inverse_direction>\r\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::load_script_body(const xml::tag *p) {
|
||||
bool background_flag = false;
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_INTERFACE_ELEMENT_STATE:
|
||||
if (!background_flag) {
|
||||
if (!_background.load_script(&*it)) return false;
|
||||
background_flag = true;
|
||||
} else {
|
||||
if (!_slider.load_script(&*it)) return false;
|
||||
}
|
||||
break;
|
||||
case QDSCR_INTERFACE_SLIDER_RECTANGLE:
|
||||
xml::tag_buffer(*it) > _active_rectangle.x > _active_rectangle.y;
|
||||
break;
|
||||
case QDSCR_INTERFACE_SLIDER_ORIENTATION: {
|
||||
int v;
|
||||
xml::tag_buffer(*it) > v;
|
||||
_orientation = orientation_t(v);
|
||||
}
|
||||
break;
|
||||
case QDSCR_INVERSE_DIRECTION:
|
||||
_inverse_direction = xml::tag_buffer(*it).get_int() != 0;
|
||||
break;
|
||||
case QDSCR_INTERFACE_BACKGROUND_OFFSET:
|
||||
xml::tag_buffer(*it) > _background_offset.x > _background_offset.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::redraw() const {
|
||||
Vect2i rr = r() + _background_offset;
|
||||
animation().redraw(rr.x, rr.y, 0);
|
||||
|
||||
if (!_slider_animation.is_empty()) {
|
||||
rr = r() + phase2offset(_phase);
|
||||
_slider_animation.redraw(rr.x, rr.y, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int qdInterfaceSlider::size_x() const {
|
||||
int x = _active_rectangle.x;
|
||||
|
||||
if (!_slider_animation.is_empty()) {
|
||||
if (x < _slider_animation.size_x())
|
||||
x = _slider_animation.size_x();
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
int qdInterfaceSlider::size_y() const {
|
||||
int y = _active_rectangle.y;
|
||||
|
||||
if (!_slider_animation.is_empty()) {
|
||||
if (y < _slider_animation.size_y())
|
||||
y = _slider_animation.size_y();
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
grScreenRegion qdInterfaceSlider::screen_region() const {
|
||||
if (!_slider_animation.is_empty()) {
|
||||
grScreenRegion reg = qdInterfaceElement::screen_region();
|
||||
reg.move(_background_offset.x, _background_offset.y);
|
||||
|
||||
Vect2i rr = r() + phase2offset(_phase);
|
||||
grScreenRegion reg1 = _slider_animation.screen_region();
|
||||
reg1.move(rr.x, rr.y);
|
||||
|
||||
reg += reg1;
|
||||
|
||||
return reg;
|
||||
} else
|
||||
return qdInterfaceElement::screen_region();
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::set_slider_animation(const qdAnimation *anm, int anm_flags) {
|
||||
if (anm) {
|
||||
anm->create_reference(&_slider_animation);
|
||||
|
||||
if (anm_flags & QD_ANIMATION_FLAG_LOOP)
|
||||
_slider_animation.set_flag(QD_ANIMATION_FLAG_LOOP);
|
||||
|
||||
if (anm_flags & QD_ANIMATION_FLAG_FLIP_HORIZONTAL)
|
||||
_slider_animation.set_flag(QD_ANIMATION_FLAG_FLIP_HORIZONTAL);
|
||||
|
||||
if (anm_flags & QD_ANIMATION_FLAG_FLIP_VERTICAL)
|
||||
_slider_animation.set_flag(QD_ANIMATION_FLAG_FLIP_VERTICAL);
|
||||
|
||||
_slider_animation.start();
|
||||
} else
|
||||
_slider_animation.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Vect2i qdInterfaceSlider::phase2offset(float ph) const {
|
||||
if (ph < 0.0f) ph = 0.0f;
|
||||
if (ph > 1.0f) ph = 1.0f;
|
||||
|
||||
Vect2i offs(0, 0);
|
||||
|
||||
if (_inverse_direction)
|
||||
ph = 1.0f - ph;
|
||||
|
||||
switch (_orientation) {
|
||||
case SL_HORIZONTAL:
|
||||
offs.x = int(ph * _active_rectangle.x) - _active_rectangle.x / 2;
|
||||
break;
|
||||
case SL_VERTICAL:
|
||||
offs.y = _active_rectangle.y / 2 - int(ph * _active_rectangle.y);
|
||||
break;
|
||||
}
|
||||
|
||||
return offs;
|
||||
}
|
||||
|
||||
float qdInterfaceSlider::offset2phase(const Vect2i &offs) const {
|
||||
float ph = 0.0f;
|
||||
|
||||
switch (_orientation) {
|
||||
case SL_HORIZONTAL:
|
||||
if (!_active_rectangle.x) return 0.0f;
|
||||
ph = float(offs.x + _active_rectangle.x / 2) / float(_active_rectangle.x);
|
||||
break;
|
||||
case SL_VERTICAL:
|
||||
if (!_active_rectangle.y) return 0.0f;
|
||||
ph = float(-offs.y + _active_rectangle.y / 2) / float(_active_rectangle.y);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ph < 0.0f) ph = 0.0f;
|
||||
if (ph > 1.0f) ph = 1.0f;
|
||||
|
||||
if (_inverse_direction)
|
||||
ph = 1.0f - ph;
|
||||
|
||||
return ph;
|
||||
}
|
||||
|
||||
bool qdInterfaceSlider::hit_test(int x, int y) const {
|
||||
x -= r().x;
|
||||
y -= r().y;
|
||||
|
||||
Vect2i rect(_active_rectangle);
|
||||
if (!_slider_animation.is_empty()) {
|
||||
if (rect.x < _slider_animation.size_x())
|
||||
rect.x = _slider_animation.size_x();
|
||||
if (rect.y < _slider_animation.size_y())
|
||||
rect.y = _slider_animation.size_y();
|
||||
}
|
||||
|
||||
if (x >= -rect.x / 2 && x < rect.x / 2 && y >= -rect.y / 2 && y < rect.y / 2)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
181
engines/qdengine/qdcore/qd_interface_slider.h
Normal file
181
engines/qdengine/qdcore/qd_interface_slider.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_SLIDER_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_SLIDER_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
//! Интерфейсный элемент - слайдер.
|
||||
/**
|
||||
Состоит из двух частей - неподвижной подложки и "ползунка".
|
||||
Подложка не обязательна, она может быть нарисована прямо на фоне.
|
||||
*/
|
||||
class qdInterfaceSlider : public qdInterfaceElement {
|
||||
public:
|
||||
//! Ориентация слайдера (по-умолчанию - горизонтально).
|
||||
enum orientation_t {
|
||||
SL_HORIZONTAL,
|
||||
SL_VERTICAL
|
||||
};
|
||||
|
||||
qdInterfaceSlider();
|
||||
qdInterfaceSlider(const qdInterfaceSlider &sl);
|
||||
~qdInterfaceSlider();
|
||||
|
||||
qdInterfaceSlider &operator = (const qdInterfaceSlider &sl);
|
||||
|
||||
//! Возвращает тип элемента.
|
||||
qdInterfaceElement::element_type get_element_type() const {
|
||||
return qdInterfaceElement::EL_SLIDER;
|
||||
}
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
|
||||
int option_value() const;
|
||||
bool set_option_value(int value);
|
||||
|
||||
//! Инициализация элемента.
|
||||
/**
|
||||
Вызывается каждый раз при заходе на экран, которому принадлежит элемент.
|
||||
*/
|
||||
bool init(bool is_game_active = true);
|
||||
|
||||
//! Отрисовка элемента.
|
||||
bool redraw() const;
|
||||
|
||||
grScreenRegion screen_region() const;
|
||||
|
||||
//! Возвращает размер элемента по горизонтали в пикселах.
|
||||
int size_x() const;
|
||||
//! Возвращает размер элемента по вертикали в пикселах.
|
||||
int size_y() const;
|
||||
|
||||
bool inverse_direction() const {
|
||||
return _inverse_direction;
|
||||
}
|
||||
void set_inverse_direction(bool state) {
|
||||
_inverse_direction = state;
|
||||
}
|
||||
|
||||
const Vect2i &active_rectangle() const {
|
||||
return _active_rectangle;
|
||||
}
|
||||
void set_active_rectangle(const Vect2i &rect) {
|
||||
_active_rectangle = rect;
|
||||
}
|
||||
|
||||
const qdInterfaceElementState *background() const {
|
||||
return &_background;
|
||||
}
|
||||
void update_background(const qdInterfaceElementState &st) {
|
||||
_background = st;
|
||||
}
|
||||
|
||||
const Vect2i &background_offset() const {
|
||||
return _background_offset;
|
||||
}
|
||||
void set_background_offset(const Vect2i &offs) {
|
||||
_background_offset = offs;
|
||||
}
|
||||
|
||||
const qdInterfaceElementState *slider() const {
|
||||
return &_slider;
|
||||
}
|
||||
void update_slider(const qdInterfaceElementState &st) {
|
||||
_slider = st;
|
||||
}
|
||||
|
||||
float phase() const {
|
||||
return _phase;
|
||||
}
|
||||
void set_phase(float ph) {
|
||||
_phase = ph;
|
||||
}
|
||||
|
||||
orientation_t orientation() const {
|
||||
return _orientation;
|
||||
}
|
||||
void set_orientation(orientation_t v) {
|
||||
_orientation = v;
|
||||
}
|
||||
|
||||
//! Возвращает true, если точка с экранными координатами (x,у) попадает в элемент.
|
||||
bool hit_test(int x, int y) const;
|
||||
|
||||
protected:
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script_body(const xml::tag *p);
|
||||
|
||||
private:
|
||||
//! Подложка под ползунком.
|
||||
qdInterfaceElementState _background;
|
||||
/// Смещение подложки относительно центра ползунка.
|
||||
Vect2i _background_offset;
|
||||
|
||||
//! Ползунок.
|
||||
qdInterfaceElementState _slider;
|
||||
|
||||
//! Анимация ползунка.
|
||||
qdAnimation _slider_animation;
|
||||
|
||||
//! Прямоугольник, внутри которого ездит ползунок.
|
||||
/**
|
||||
По нему же отслеживаются мышиные клики.
|
||||
Отсчитывается от центра элемента, в экранных координатах.
|
||||
*/
|
||||
Vect2i _active_rectangle;
|
||||
|
||||
//! Текущая фаза, диапазон значений - [0.0, 1.0].
|
||||
float _phase;
|
||||
|
||||
//! Ориентация - по горизонтали или по вертикали.
|
||||
orientation_t _orientation;
|
||||
bool _inverse_direction;
|
||||
|
||||
//! true, если слайдер следит за перемещениями мышиного курсора
|
||||
bool _track_mouse;
|
||||
|
||||
bool set_slider_animation(const qdAnimation *anm, int anm_flags = 0);
|
||||
|
||||
//! Пересчет фазы в смещение от центра элемента в экранных координатах.
|
||||
Vect2i phase2offset(float ph) const;
|
||||
//! Пересчет смещения от центра элемента в экранных координатах в фазу.
|
||||
float offset2phase(const Vect2i &offs) const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_SLIDER_H
|
||||
715
engines/qdengine/qdcore/qd_interface_text_window.cpp
Normal file
715
engines/qdengine/qdcore/qd_interface_text_window.cpp
Normal file
@@ -0,0 +1,715 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_setup.h"
|
||||
#include "qdengine/qdcore/qd_interface_screen.h"
|
||||
#include "qdengine/qdcore/qd_interface_text_window.h"
|
||||
#include "qdengine/qdcore/qd_interface_slider.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
const float qdInterfaceCaretPeriod = 0.3f;
|
||||
|
||||
bool qdInterfaceTextWindow::_caretVisible = false;
|
||||
float qdInterfaceTextWindow::_caretTimer = 0.f;
|
||||
|
||||
qdInterfaceTextWindow::qdInterfaceTextWindow() : _text_size(0, 0),
|
||||
_scrolling_speed(0),
|
||||
_text_set(NULL),
|
||||
_text_set_id(qdGameDispatcher::TEXT_SET_DIALOGS),
|
||||
_slider(NULL),
|
||||
_windowType(WINDOW_DIALOGS),
|
||||
_infoType(INFO_NONE) {
|
||||
_textFormat.toggle_global_depend(false);
|
||||
|
||||
_inputStringLimit = 0;
|
||||
_scrolling_position = 0;
|
||||
_text_set_position = 0;
|
||||
|
||||
_textVAlign = VALIGN_BOTTOM;
|
||||
|
||||
_background_color = 0;
|
||||
_has_background_color = false;
|
||||
_background_alpha = 0;
|
||||
|
||||
_isEditing = false;
|
||||
_caretPose = -1;
|
||||
|
||||
_playerID = 0;
|
||||
|
||||
_border_background.set_owner(this);
|
||||
}
|
||||
|
||||
qdInterfaceTextWindow::qdInterfaceTextWindow(const qdInterfaceTextWindow &wnd) : qdInterfaceElement(wnd),
|
||||
_text_size(wnd._text_size),
|
||||
_scrolling_speed(wnd._scrolling_speed),
|
||||
_text_set(wnd._text_set),
|
||||
_text_set_id(wnd._text_set_id),
|
||||
_slider_name(wnd._slider_name),
|
||||
_slider(wnd._slider),
|
||||
_windowType(wnd._windowType),
|
||||
_infoType(wnd._infoType),
|
||||
_playerID(wnd._playerID),
|
||||
_inputString(wnd._inputString),
|
||||
_inputStringBackup(wnd._inputStringBackup),
|
||||
_inputStringLimit(wnd._inputStringLimit),
|
||||
_textFormat(wnd._textFormat),
|
||||
_textVAlign(wnd._textVAlign) {
|
||||
_scrolling_position = 0;
|
||||
_text_set_position = 0;
|
||||
|
||||
_background_color = wnd._background_color;
|
||||
_has_background_color = wnd._has_background_color;
|
||||
_background_alpha = wnd._background_alpha;
|
||||
|
||||
_isEditing = wnd._isEditing;
|
||||
_caretPose = wnd._caretPose;
|
||||
|
||||
_border_background.set_owner(this);
|
||||
_border_background = wnd._border_background;
|
||||
}
|
||||
|
||||
qdInterfaceTextWindow &qdInterfaceTextWindow::operator = (const qdInterfaceTextWindow &wnd) {
|
||||
if (this == &wnd) return *this;
|
||||
|
||||
*static_cast<qdInterfaceElement *>(this) = wnd;
|
||||
|
||||
_text_size = wnd._text_size;
|
||||
_scrolling_speed = wnd._scrolling_speed;
|
||||
_text_set = wnd._text_set;
|
||||
_text_set_id = wnd._text_set_id;
|
||||
_slider_name = wnd._slider_name;
|
||||
_slider = wnd._slider;
|
||||
|
||||
_windowType = wnd._windowType;
|
||||
_infoType = wnd._infoType;
|
||||
_playerID = wnd._playerID;
|
||||
|
||||
_inputString = wnd._inputString;
|
||||
_inputStringBackup = wnd._inputStringBackup;
|
||||
_inputStringLimit = wnd._inputStringLimit;
|
||||
_textFormat = wnd._textFormat;
|
||||
|
||||
_textVAlign = wnd._textVAlign;
|
||||
|
||||
_isEditing = wnd._isEditing;
|
||||
_caretPose = wnd._caretPose;
|
||||
|
||||
_border_background = wnd._border_background;
|
||||
_background_color = wnd._background_color;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
qdInterfaceTextWindow::~qdInterfaceTextWindow() {
|
||||
_border_background.unregister_resources();
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
if (!_text_set) return false;
|
||||
|
||||
if (_windowType == WINDOW_DIALOGS) {
|
||||
if (ev == mouseDispatcher::EV_LEFT_DOWN) {
|
||||
if (qdScreenText * p = _text_set->get_text(x, y)) {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
dp->set_flag(qdGameDispatcher::DIALOG_CLICK_FLAG);
|
||||
dp->set_mouse_click_state(p->owner());
|
||||
|
||||
debugC(2, kDebugText, "qdInterfaceTextWindow::mouse_handler(): click [%d, %d], ev: %d", x, y, ev);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else if (ev == mouseDispatcher::EV_MOUSE_MOVE) {
|
||||
_text_set->clear_hover_mode();
|
||||
if (qdScreenText *p = _text_set->get_text(x, y))
|
||||
p->set_hover_mode(true);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::keyboard_handler(Common::KeyCode vkey) {
|
||||
if (_windowType == WINDOW_EDIT && _isEditing)
|
||||
return edit_input(vkey);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::char_input_handler(int input) {
|
||||
bool ret = qdInterfaceElement::char_input_handler(input);
|
||||
|
||||
if (_windowType == WINDOW_EDIT && _isEditing) {
|
||||
if (!_inputStringLimit || (int)_inputString.size() < _inputStringLimit) {
|
||||
if (Common::isPrint(input) || input == '_' || input == '-' || input == ' ') {
|
||||
_inputString.insertChar(input, _caretPose++);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qdInterfaceTextWindow::hover_clear() {
|
||||
if (_windowType == WINDOW_DIALOGS) {
|
||||
if (_text_set)
|
||||
_text_set->clear_hover_mode();
|
||||
}
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::init(bool is_game_active) {
|
||||
set_state(&_border_background);
|
||||
|
||||
if (_windowType == WINDOW_DIALOGS) {
|
||||
if (!_text_set)
|
||||
_text_set = qdGameDispatcher::get_dispatcher()->screen_texts_dispatcher().get_text_set(_text_set_id);
|
||||
|
||||
if (!_slider) {
|
||||
if (qdInterfaceScreen * p = static_cast<qdInterfaceScreen * >(owner()))
|
||||
_slider = dynamic_cast<qdInterfaceSlider * >(p->get_element(slider_name()));
|
||||
}
|
||||
|
||||
if (_text_set) {
|
||||
_text_set->set_max_text_width(_text_size.x);
|
||||
update_text_position();
|
||||
}
|
||||
} else {
|
||||
qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher();
|
||||
|
||||
switch (_infoType) {
|
||||
case INFO_PLAYER_NAME:
|
||||
_inputString = dp->hall_of_fame_player_name(_playerID);
|
||||
if (dp->is_hall_of_fame_updated(_playerID) && !_isEditing)
|
||||
edit_start();
|
||||
break;
|
||||
case INFO_PLAYER_SCORE:
|
||||
if (dp->hall_of_fame_player_score(_playerID)) {
|
||||
Common::String buf;
|
||||
buf += Common::String::format("%d", dp->hall_of_fame_player_score(_playerID));
|
||||
_inputString = buf.c_str();
|
||||
} else
|
||||
_inputString = "";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (_windowType == WINDOW_TEXT)
|
||||
set_input_string(input_string());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::save_script_body(Common::WriteStream &fh, int indent) const {
|
||||
if (_border_background.has_animation()) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<border_back>%s</border_back>\r\n", qdscr_XML_string(_border_background.animation_file().toString('\\'))));
|
||||
}
|
||||
|
||||
if (!_slider_name.empty()) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<window_slider>%s</window_slider>\r\n", qdscr_XML_string(_slider_name.c_str())));
|
||||
}
|
||||
|
||||
if (_text_size.x || _text_size.y) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<screen_size>%d %d</screen_size>\r\n", _text_size.x, _text_size.y));
|
||||
}
|
||||
|
||||
if (_background_color) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<color>%u</color>\r\n", _background_color));
|
||||
}
|
||||
|
||||
if (_has_background_color) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("<enable_background>1</enable_background>\r\n");
|
||||
}
|
||||
|
||||
if (_background_alpha) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<alpha>%d</alpha>\r\n", _background_alpha));
|
||||
}
|
||||
|
||||
if (_windowType != WINDOW_DIALOGS) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<window_type>%d</window_type>\r\n", (int)_windowType));
|
||||
}
|
||||
|
||||
if (_infoType != INFO_NONE) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<info_type>%d</info_type>\r\n", (int)_infoType));
|
||||
}
|
||||
|
||||
if (_playerID) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<player_id>%d</player_id>\r\n", _playerID));
|
||||
}
|
||||
|
||||
if (!_inputString.empty()) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<text>%s</text>\r\n", qdscr_XML_string(_inputString.c_str())));
|
||||
}
|
||||
|
||||
if (_inputStringLimit) {
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<string_length>%d</string_length>\r\n", _inputStringLimit));
|
||||
}
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<valign>%d</valign>\r\n", _textVAlign));
|
||||
|
||||
if (_textFormat != qdScreenTextFormat::default_format()) {
|
||||
_textFormat.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::load_script_body(const xml::tag *p) {
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_TEXT_WINDOW_BORDER_BACK:
|
||||
set_border_background_file(Common::Path(it->data(), '\\'));
|
||||
break;
|
||||
case QDSCR_TEXT_WINDOW_SLIDER:
|
||||
set_slider_name(it->data());
|
||||
break;
|
||||
case QDSCR_SCREEN_SIZE:
|
||||
xml::tag_buffer(*it) > _text_size.x > _text_size.y;
|
||||
break;
|
||||
case QDSCR_COLOR:
|
||||
xml::tag_buffer(*it) > _background_color;
|
||||
break;
|
||||
case QDSCR_ALPHA:
|
||||
xml::tag_buffer(*it) > _background_alpha;
|
||||
break;
|
||||
case QDSCR_ENABLE_BACKGROUND:
|
||||
_has_background_color = xml::tag_buffer(*it).get_int() != 0;
|
||||
break;
|
||||
case QDSCR_TEXT_WINDOW_TYPE:
|
||||
_windowType = WindowType(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_TEXT_WINDOW_INFO_TYPE:
|
||||
_infoType = InfoType(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_TEXT_WINDOW_PLAYER_ID:
|
||||
xml::tag_buffer(*it) > _playerID;
|
||||
break;
|
||||
case QDSCR_SCREEN_TEXT_FORMAT:
|
||||
_textFormat.load_script(&*it);
|
||||
_textFormat.toggle_global_depend(false);
|
||||
break;
|
||||
case QDSCR_TEXT_WINDOW_MAX_STRING_LENGTH:
|
||||
xml::tag_buffer(*it) > _inputStringLimit;
|
||||
break;
|
||||
case QDSCR_TEXT:
|
||||
_inputString = it->data();
|
||||
break;
|
||||
case QDSCR_VALIGN:
|
||||
_textVAlign = TextVAlign(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::redraw() const {
|
||||
qdInterfaceElement::redraw();
|
||||
|
||||
if (_windowType == WINDOW_DIALOGS) {
|
||||
debugC(3, kDebugText, "qdInterfaceTextWindow::redraw(): DIALOGS");
|
||||
if (_text_set) {
|
||||
debugC(3, kDebugText, "qdInterfaceTextWindow::redraw(): text_set");
|
||||
int l_clip, t_clip, r_clip, b_clip;
|
||||
grDispatcher::instance()->getClip(l_clip, t_clip, r_clip, b_clip);
|
||||
|
||||
Vect2i ar = r();
|
||||
grDispatcher::instance()->limitClip(ar.x - _text_size.x / 2, ar.y - _text_size.y / 2, ar.x + _text_size.x / 2, ar.y + _text_size.y / 2);
|
||||
|
||||
if (_has_background_color) {
|
||||
Vect2i text_r = _text_set->screen_pos();
|
||||
Vect2i text_sz = _text_set->screen_size();
|
||||
|
||||
if (!_background_alpha)
|
||||
grDispatcher::instance()->rectangle(ar.x - _text_size.x / 2, text_r.y - text_sz.y / 2, _text_size.x, text_sz.y, _background_color, _background_color, GR_FILLED);
|
||||
else
|
||||
grDispatcher::instance()->rectangleAlpha(ar.x - _text_size.x / 2, text_r.y - text_sz.y / 2, _text_size.x, text_sz.y, _background_color, _background_alpha);
|
||||
}
|
||||
|
||||
_text_set->redraw();
|
||||
|
||||
grDispatcher::instance()->setClip(l_clip, t_clip, r_clip, b_clip);
|
||||
|
||||
if (g_engine->_debugDraw)
|
||||
grDispatcher::instance()->rectangle(ar.x - _text_size.x / 2, ar.y - _text_size.y / 2, _text_size.x, _text_size.y, 0xFFFFFF, 0, GR_OUTLINED, 3);
|
||||
}
|
||||
} else if (_windowType == WINDOW_EDIT || _windowType == WINDOW_TEXT) {
|
||||
debugC(3, kDebugText, "qdInterfaceTextWindow::redraw(): text_edit (%d)", _windowType);
|
||||
if (_has_background_color) {
|
||||
Vect2i ar = r();
|
||||
if (!_background_alpha)
|
||||
grDispatcher::instance()->rectangle(ar.x - _text_size.x / 2, ar.y - _text_size.y / 2, _text_size.x, _text_size.y, _background_color, _background_color, GR_FILLED);
|
||||
else
|
||||
grDispatcher::instance()->rectangleAlpha(ar.x - _text_size.x / 2, ar.y - _text_size.y / 2, _text_size.x, _text_size.y, _background_color, _background_alpha);
|
||||
}
|
||||
|
||||
text_redraw();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::need_redraw() const {
|
||||
if (qdInterfaceElement::need_redraw())
|
||||
return true;
|
||||
|
||||
if (_windowType == WINDOW_DIALOGS) {
|
||||
if (_text_set && _text_set->need_redraw())
|
||||
return true;
|
||||
|
||||
if (_slider && _slider->need_redraw())
|
||||
return true;
|
||||
} else if (_windowType == WINDOW_EDIT || _windowType == WINDOW_TEXT)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::quant(float dt) {
|
||||
qdInterfaceElement::quant(dt);
|
||||
|
||||
debugC(1, kDebugText, "*********** qdInterfaceTextWindow::quant()");
|
||||
debugC(1, kDebugQuant, "*********** qdInterfaceTextWindow::quant()");
|
||||
|
||||
if (_isEditing) {
|
||||
_caretTimer -= dt;
|
||||
if (_caretTimer < 0.f) {
|
||||
_caretVisible = !_caretVisible;
|
||||
_caretTimer = qdInterfaceCaretPeriod;
|
||||
}
|
||||
}
|
||||
|
||||
if (_windowType == WINDOW_DIALOGS) {
|
||||
debugC(2, kDebugText, "** qdInterfaceTextWindow::quant(): DIALOGS");
|
||||
|
||||
if (is_visible() && _text_set && _text_set->was_changed())
|
||||
update_text_position();
|
||||
|
||||
if (_text_set) {
|
||||
debugC(2, kDebugText,"** qdInterfaceTextWindow::quant(): text_set, id: %d", _text_set->ID());
|
||||
|
||||
if (fabs(_scrolling_position) > FLT_EPS) {
|
||||
float delta = _scrolling_speed * dt;
|
||||
if (fabs(_scrolling_position) > delta)
|
||||
_scrolling_position += (_scrolling_position > 0) ? -delta : delta;
|
||||
else
|
||||
_scrolling_position = 0;
|
||||
|
||||
Vect2i pos = _text_set->screen_pos();
|
||||
pos.y = _text_set_position + round(_scrolling_position);
|
||||
_text_set->set_screen_pos(pos);
|
||||
}
|
||||
|
||||
if (_text_set->is_empty()) {
|
||||
debugC(2, kDebugText,"** qdInterfaceTextWindow::quant(): text_set->empty, vis: %d", is_visible());
|
||||
|
||||
if (is_visible()) {
|
||||
hide();
|
||||
if (qdInterfaceScreen * sp = dynamic_cast<qdInterfaceScreen * >(owner()))
|
||||
sp->build_visible_elements_list();
|
||||
|
||||
qdGameDispatcher::get_dispatcher()->toggle_full_redraw();
|
||||
}
|
||||
} else {
|
||||
debugC(2, kDebugText, "** qdInterfaceTextWindow::quant(): text_set->empty NOT, vis: %d", is_visible());
|
||||
|
||||
if (!is_visible()) {
|
||||
show();
|
||||
if (qdInterfaceScreen * sp = dynamic_cast<qdInterfaceScreen * >(owner()))
|
||||
sp->build_visible_elements_list();
|
||||
}
|
||||
}
|
||||
|
||||
if (_slider) {
|
||||
if (!is_visible() || _text_size.y > _text_set->screen_size().y) {
|
||||
if (_slider->is_visible()) {
|
||||
_slider->hide();
|
||||
|
||||
if (qdInterfaceScreen * sp = dynamic_cast<qdInterfaceScreen * >(owner()))
|
||||
sp->build_visible_elements_list();
|
||||
|
||||
qdGameDispatcher::get_dispatcher()->toggle_full_redraw();
|
||||
}
|
||||
} else {
|
||||
if (!_slider->is_visible()) {
|
||||
_slider->show();
|
||||
|
||||
if (qdInterfaceScreen * sp = dynamic_cast<qdInterfaceScreen * >(owner()))
|
||||
sp->build_visible_elements_list();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void qdInterfaceTextWindow::update_text_position() {
|
||||
if (_text_set) {
|
||||
Vect2f rr = r() - text_size() / 2 + _text_set->screen_size() / 2;
|
||||
switch (_textVAlign) {
|
||||
case VALIGN_CENTER:
|
||||
rr.y += (float)(text_size().y - _text_set->screen_size().y) / 2.0;
|
||||
break;
|
||||
case VALIGN_BOTTOM:
|
||||
rr.y += text_size().y - _text_set->screen_size().y;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
_text_set->set_screen_pos(rr);
|
||||
_text_set_position = rr.y;
|
||||
|
||||
set_scrolling(_text_set->new_texts_height());
|
||||
_text_set->clear_new_texts_height();
|
||||
|
||||
_text_set->toggle_changed(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::hit_test(int x, int y) const {
|
||||
x -= r().x;
|
||||
y -= r().y;
|
||||
|
||||
if (x >= -size_x() / 2 && x < size_x() / 2 && y >= -size_y() / 2 && y < size_y() / 2)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
grScreenRegion qdInterfaceTextWindow::screen_region() const {
|
||||
return grScreenRegion(r().x, r().y, size_x(), size_y());
|
||||
}
|
||||
|
||||
int qdInterfaceTextWindow::size_x() const {
|
||||
return (qdInterfaceElement::size_x() > _text_size.x) ? qdInterfaceElement::size_x() : _text_size.x;
|
||||
}
|
||||
|
||||
int qdInterfaceTextWindow::size_y() const {
|
||||
return (qdInterfaceElement::size_y() > _text_size.y) ? qdInterfaceElement::size_y() : _text_size.y;
|
||||
}
|
||||
|
||||
void qdInterfaceTextWindow::set_scrolling(int y_delta) {
|
||||
if (_scrolling_speed > FLT_EPS)
|
||||
_scrolling_position = y_delta;
|
||||
else
|
||||
_scrolling_position = 0;
|
||||
}
|
||||
|
||||
void qdInterfaceTextWindow::text_redraw() const {
|
||||
Vect2i ar = r() - _text_size / 2;
|
||||
|
||||
uint32 col = _textFormat.color();
|
||||
|
||||
const grFont *font = qdGameDispatcher::get_dispatcher()->
|
||||
find_font(_textFormat.font_type());
|
||||
|
||||
if (_windowType == WINDOW_EDIT && _isEditing) {
|
||||
int sz0 = grDispatcher::instance()->textWidth("|", 0, font);
|
||||
int sz1 = grDispatcher::instance()->textWidth(_inputString.c_str(), 0, font);
|
||||
int x0 = ar.x;
|
||||
switch (_textFormat.alignment()) {
|
||||
case qdScreenTextFormat::ALIGN_LEFT:
|
||||
break;
|
||||
case qdScreenTextFormat::ALIGN_CENTER:
|
||||
x0 += (_text_size.x - sz0 - sz1) / 2;
|
||||
break;
|
||||
case qdScreenTextFormat::ALIGN_RIGHT:
|
||||
x0 += _text_size.x - sz0 - sz1;
|
||||
break;
|
||||
}
|
||||
|
||||
Common::String str = _inputString.substr(0, _caretPose);
|
||||
if (!str.empty()) {
|
||||
grDispatcher::instance()->drawAlignedText(x0, ar.y, _text_size.x, _text_size.y, col, str.c_str(), GR_ALIGN_LEFT, 0, 0, font);
|
||||
x0 += grDispatcher::instance()->textWidth(str.c_str(), 0, font);
|
||||
}
|
||||
if (_caretVisible)
|
||||
grDispatcher::instance()->drawAlignedText(x0, ar.y, _text_size.x, _text_size.y, col, "|", GR_ALIGN_LEFT, 0, 0, font);
|
||||
x0 += grDispatcher::instance()->textWidth("|", 0, font);
|
||||
|
||||
str = _inputString.substr(_caretPose, Common::String::npos);
|
||||
if (!str.empty())
|
||||
grDispatcher::instance()->drawAlignedText(x0, ar.y, _text_size.x, _text_size.y, col, str.c_str(), GR_ALIGN_LEFT, 0, 0, font);
|
||||
} else {
|
||||
if (_windowType == WINDOW_TEXT)
|
||||
grDispatcher::instance()->drawParsedText(ar.x, ar.y, _text_size.x, _text_size.y, col, &_parser, grTextAlign(_textFormat.alignment()), font);
|
||||
else
|
||||
grDispatcher::instance()->drawAlignedText(ar.x, ar.y, _text_size.x, _text_size.y, col, _inputString.c_str(), grTextAlign(_textFormat.alignment()), 0, 0, font);
|
||||
}
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::edit_input(Common::KeyCode vkey) {
|
||||
if (_isEditing) {
|
||||
switch (vkey) {
|
||||
case Common::KEYCODE_ESCAPE:
|
||||
if (!edit_done(true))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case Common::KEYCODE_RETURN:
|
||||
if (!edit_done(false))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case Common::KEYCODE_LEFT:
|
||||
if (_caretPose > 0)
|
||||
--_caretPose;
|
||||
return true;
|
||||
|
||||
case Common::KEYCODE_HOME:
|
||||
_caretPose = 0;
|
||||
return true;
|
||||
|
||||
case Common::KEYCODE_END:
|
||||
_caretPose = _inputString.size();
|
||||
return true;
|
||||
|
||||
case Common::KEYCODE_RIGHT:
|
||||
if (_caretPose < (int)_inputString.size())
|
||||
++_caretPose;
|
||||
return true;
|
||||
|
||||
case Common::KEYCODE_BACKSPACE:
|
||||
if (_caretPose > 0 && _caretPose <= (int)_inputString.size())
|
||||
_inputString.erase(--_caretPose, 1);
|
||||
return true;
|
||||
|
||||
case Common::KEYCODE_DELETE:
|
||||
if (_caretPose >= 0 && _caretPose < (int)_inputString.size())
|
||||
_inputString.erase(_caretPose, 1);
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdInterfaceTextWindow::set_input_string(const char *str) {
|
||||
_inputString = str;
|
||||
|
||||
if (_windowType == WINDOW_TEXT) {
|
||||
_parser.setFont(qdGameDispatcher::get_dispatcher()->find_font(_textFormat.font_type()));
|
||||
_parser.parseString(_inputString.c_str(), _textFormat.color());
|
||||
}
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::edit_start() {
|
||||
if (!_isEditing) {
|
||||
_isEditing = true;
|
||||
_inputStringBackup = _inputString;
|
||||
_caretPose = _inputString.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInterfaceTextWindow::edit_done(bool cancel) {
|
||||
if (_isEditing) {
|
||||
bool end_edit = true;
|
||||
|
||||
switch (_infoType) {
|
||||
case INFO_NONE:
|
||||
if (qdInterfaceDispatcher * dp = qdInterfaceDispatcher::get_dispatcher())
|
||||
dp->handle_event(!cancel ? qdInterfaceEvent::EVENT_MODAL_OK : qdInterfaceEvent::EVENT_MODAL_CANCEL, 0, this);
|
||||
break;
|
||||
case INFO_PLAYER_NAME:
|
||||
if (cancel || _inputString.empty()) {
|
||||
end_edit = false;
|
||||
} else {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
dp->set_hall_of_fame_player_name(_playerID, _inputString.c_str());
|
||||
dp->save_hall_of_fame();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (end_edit) {
|
||||
_isEditing = false;
|
||||
|
||||
if (cancel)
|
||||
_inputString = _inputStringBackup;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
249
engines/qdengine/qdcore/qd_interface_text_window.h
Normal file
249
engines/qdengine/qdcore/qd_interface_text_window.h
Normal file
@@ -0,0 +1,249 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INTERFACE_TEXT_WINDOW_H
|
||||
#define QDENGINE_QDCORE_QD_INTERFACE_TEXT_WINDOW_H
|
||||
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_interface_element_state.h"
|
||||
#include "qdengine/system/graphics/UI_TextParser.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdScreenTextSet;
|
||||
class qdInterfaceSlider;
|
||||
|
||||
//! Интерфейсный элемент - окно для текстов.
|
||||
class qdInterfaceTextWindow : public qdInterfaceElement {
|
||||
public:
|
||||
qdInterfaceTextWindow();
|
||||
qdInterfaceTextWindow(const qdInterfaceTextWindow &wnd);
|
||||
~qdInterfaceTextWindow();
|
||||
|
||||
enum WindowType {
|
||||
WINDOW_DIALOGS,
|
||||
WINDOW_EDIT,
|
||||
WINDOW_TEXT
|
||||
};
|
||||
|
||||
enum TextVAlign {
|
||||
VALIGN_TOP,
|
||||
VALIGN_CENTER,
|
||||
VALIGN_BOTTOM
|
||||
};
|
||||
|
||||
enum InfoType {
|
||||
INFO_NONE,
|
||||
INFO_PLAYER_NAME,
|
||||
INFO_PLAYER_SCORE
|
||||
};
|
||||
|
||||
qdInterfaceTextWindow &operator = (const qdInterfaceTextWindow &wnd);
|
||||
|
||||
qdInterfaceElement::element_type get_element_type() const {
|
||||
return qdInterfaceElement::EL_TEXT_WINDOW;
|
||||
}
|
||||
|
||||
//! Обработчик событий мыши.
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
//! Обработчик ввода с клавиатуры.
|
||||
bool keyboard_handler(Common::KeyCode vkey);
|
||||
bool char_input_handler(int input);
|
||||
|
||||
void hover_clear();
|
||||
|
||||
//! Инициализация элемента.
|
||||
/**
|
||||
Вызывается каждый раз при заходе на экран, которому принадлежит элемент.
|
||||
*/
|
||||
bool init(bool is_game_active = true);
|
||||
|
||||
bool quant(float dt);
|
||||
|
||||
const Common::Path border_background_file() const {
|
||||
return _border_background.animation_file();
|
||||
}
|
||||
void set_border_background_file(const Common::Path &file_name) {
|
||||
_border_background.set_animation_file(file_name);
|
||||
}
|
||||
|
||||
uint32 background_color() const {
|
||||
return _background_color;
|
||||
}
|
||||
void set_background_color(uint32 color) {
|
||||
_background_color = color;
|
||||
}
|
||||
|
||||
int background_alpha() const {
|
||||
return _background_alpha;
|
||||
}
|
||||
void set_background_alpha(int alpha) {
|
||||
_background_alpha = alpha;
|
||||
}
|
||||
|
||||
bool has_background_color() const {
|
||||
return _has_background_color;
|
||||
}
|
||||
void toggle_background_color(bool state) {
|
||||
_has_background_color = state;
|
||||
}
|
||||
|
||||
//! Возвращает экранные координаты центра окна.
|
||||
virtual const Vect2i r() const {
|
||||
return qdInterfaceElement::r() - g_engine->screen_offset();
|
||||
}
|
||||
|
||||
//! Отрисовка окна.
|
||||
bool redraw() const;
|
||||
bool need_redraw() const;
|
||||
|
||||
grScreenRegion screen_region() const;
|
||||
|
||||
//! Возвращает размер окна вместе с рамкой по горизонтали в пикселах.
|
||||
int size_x() const;
|
||||
//! Возвращает размер окна вместе с рамкой по вертикали в пикселах.
|
||||
int size_y() const;
|
||||
|
||||
const Vect2i &text_size() const {
|
||||
return _text_size;
|
||||
}
|
||||
void set_text_size(const Vect2i &sz) {
|
||||
_text_size = sz;
|
||||
}
|
||||
|
||||
const char *slider_name() const {
|
||||
return _slider_name.c_str();
|
||||
}
|
||||
void set_slider_name(const char *name) {
|
||||
_slider_name = name;
|
||||
}
|
||||
|
||||
//! Возвращает true, если точка с экранными координатами (x,у) попадает в элемент.
|
||||
bool hit_test(int x, int y) const;
|
||||
|
||||
WindowType windowType() const {
|
||||
return _windowType;
|
||||
}
|
||||
void setWindowType(WindowType type) {
|
||||
_windowType = type;
|
||||
}
|
||||
|
||||
InfoType infoType() const {
|
||||
return _infoType;
|
||||
}
|
||||
void setInfoType(InfoType type) {
|
||||
_infoType = type;
|
||||
}
|
||||
|
||||
int playerID() const {
|
||||
return _playerID;
|
||||
}
|
||||
void setPlayerID(int id) {
|
||||
_playerID = id;
|
||||
}
|
||||
|
||||
const char *input_string() const {
|
||||
return _inputString.c_str();
|
||||
}
|
||||
void set_input_string(const char *str);
|
||||
bool edit_start();
|
||||
bool edit_done(bool cancel = false);
|
||||
|
||||
TextVAlign text_valign() const {
|
||||
return _textVAlign;
|
||||
}
|
||||
void set_text_valign(TextVAlign align) {
|
||||
_textVAlign = align;
|
||||
}
|
||||
|
||||
int inputStringLimit() const {
|
||||
return _inputStringLimit;
|
||||
}
|
||||
void setInputStringLimit(int length) {
|
||||
_inputStringLimit = length;
|
||||
}
|
||||
|
||||
const qdScreenTextFormat &textFormat() const {
|
||||
return _textFormat;
|
||||
}
|
||||
void setTextFormat(const qdScreenTextFormat &format) {
|
||||
_textFormat = format;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script_body(Common::WriteStream &fh, int indent = 0) const;
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script_body(const xml::tag *p);
|
||||
|
||||
private:
|
||||
|
||||
WindowType _windowType;
|
||||
|
||||
InfoType _infoType;
|
||||
int _playerID;
|
||||
|
||||
//! Размер текстовой области окна.
|
||||
Vect2i _text_size;
|
||||
|
||||
TextVAlign _textVAlign;
|
||||
|
||||
//! Скорость выезжания текста, если нулевая появляется мгновенно.
|
||||
float _scrolling_speed;
|
||||
|
||||
float _scrolling_position;
|
||||
int _text_set_position;
|
||||
|
||||
qdInterfaceElementState _border_background;
|
||||
uint32 _background_color;
|
||||
bool _has_background_color;
|
||||
int _background_alpha;
|
||||
|
||||
int _text_set_id;
|
||||
qdScreenTextSet *_text_set;
|
||||
|
||||
Common::String _slider_name;
|
||||
qdInterfaceSlider *_slider;
|
||||
|
||||
Common::String _inputString;
|
||||
Common::String _inputStringBackup;
|
||||
qdScreenTextFormat _textFormat;
|
||||
int _inputStringLimit;
|
||||
bool _isEditing;
|
||||
int _caretPose;
|
||||
|
||||
UI_TextParser _parser;
|
||||
|
||||
static bool _caretVisible;
|
||||
static float _caretTimer;
|
||||
|
||||
void update_text_position();
|
||||
void set_scrolling(int y_delta);
|
||||
|
||||
void text_redraw() const;
|
||||
bool edit_input(Common::KeyCode vkey);
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INTERFACE_TEXT_WINDOW_H
|
||||
424
engines/qdengine/qdcore/qd_inventory.cpp
Normal file
424
engines/qdengine/qdcore/qd_inventory.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
/* 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/qdengine.h"
|
||||
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/qdcore/qd_inventory.h"
|
||||
#include "qdengine/qdcore/qd_game_scene.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_game_object_mouse.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
|
||||
qdInventory::qdInventory() : _need_redraw(false),
|
||||
_shadow_color(INV_DEFAULT_SHADOW_COLOR),
|
||||
_shadow_alpha(INV_DEFAULT_SHADOW_ALPHA),
|
||||
_additional_cells(0, 0) {
|
||||
}
|
||||
|
||||
qdInventory::~qdInventory() {
|
||||
_cell_sets.clear();
|
||||
}
|
||||
|
||||
void qdInventory::redraw(int offs_x, int offs_y, bool inactive_mode) const {
|
||||
qdInventoryCell::set_shadow(_shadow_color, _shadow_alpha);
|
||||
|
||||
for (qdInventoryCellSetVector::const_iterator it = _cell_sets.begin(); it != _cell_sets.end(); ++it)
|
||||
it->redraw(offs_x, offs_y, inactive_mode);
|
||||
}
|
||||
|
||||
void qdInventory::pre_redraw() const {
|
||||
for (qdInventoryCellSetVector::const_iterator it = _cell_sets.begin(); it != _cell_sets.end(); ++it)
|
||||
it->pre_redraw();
|
||||
|
||||
if (_need_redraw) {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
for (qdInventoryCellSetVector::const_iterator it = _cell_sets.begin(); it != _cell_sets.end(); ++it) {
|
||||
dp->add_redraw_region(it->screen_region());
|
||||
dp->add_redraw_region(it->last_screen_region());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qdInventory::post_redraw() {
|
||||
toggle_redraw(false);
|
||||
|
||||
for (qdInventoryCellSetVector::iterator it = _cell_sets.begin(); it != _cell_sets.end(); ++it)
|
||||
it->post_redraw();
|
||||
}
|
||||
|
||||
bool qdInventory::put_object(qdGameObjectAnimated *p) {
|
||||
if (p->inventory_cell_index() != -1) {
|
||||
if (put_object(p, cell_position(p->inventory_cell_index())))
|
||||
return true;
|
||||
}
|
||||
|
||||
for (auto &it : _cell_sets) {
|
||||
if (it.put_object(p)) {
|
||||
p->set_inventory_cell_index(cell_index(p));
|
||||
p->set_flag(QD_OBJ_IS_IN_INVENTORY_FLAG);
|
||||
_need_redraw = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInventory::put_object(qdGameObjectAnimated *p, const Vect2s &pos) {
|
||||
for (auto &it : _cell_sets) {
|
||||
if (it.put_object(p, pos)) {
|
||||
p->set_inventory_cell_index(cell_index(p));
|
||||
p->set_flag(QD_OBJ_IS_IN_INVENTORY_FLAG);
|
||||
_need_redraw = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdGameObjectAnimated *qdInventory::get_object(const Vect2s &pos) const {
|
||||
for (auto &it : _cell_sets) {
|
||||
if (it.hit(pos)) {
|
||||
qdGameObjectAnimated *p = it.get_object(pos);
|
||||
if (p) return p;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdInventory::remove_object(qdGameObjectAnimated *p) {
|
||||
for (auto &it : _cell_sets) {
|
||||
if (it.remove_object(p)) {
|
||||
p->drop_flag(QD_OBJ_IS_IN_INVENTORY_FLAG);
|
||||
_need_redraw = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInventory::is_object_in_list(const qdGameObjectAnimated *p) const {
|
||||
for (auto &it : _cell_sets) {
|
||||
if (it.is_object_in_list(p))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInventory::load_script(const xml::tag *p) {
|
||||
qdInventoryCellSet set;
|
||||
|
||||
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_INVENTORY_CELL_SET:
|
||||
set.load_script(&*it);
|
||||
add_cell_set(set);
|
||||
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;
|
||||
case QDSCR_INVENTORY_CELL_SET_ADDITIONAL_CELLS:
|
||||
xml::tag_buffer(*it) > _additional_cells.x > _additional_cells.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool qdInventory::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<inventory name=");
|
||||
|
||||
if (name()) {
|
||||
fh.writeString(Common::String::format("\"%s\"", qdscr_XML_string(name())));
|
||||
} else {
|
||||
fh.writeString("\" \"");
|
||||
}
|
||||
|
||||
if (flags()) {
|
||||
fh.writeString(Common::String::format(" flags=\"%d\"", flags()));
|
||||
}
|
||||
|
||||
if (_shadow_color != INV_DEFAULT_SHADOW_COLOR) {
|
||||
fh.writeString(Common::String::format(" shadow_color=\"%u\"", _shadow_color));
|
||||
}
|
||||
|
||||
if (_shadow_alpha != INV_DEFAULT_SHADOW_ALPHA) {
|
||||
fh.writeString(Common::String::format(" shadow_alpha=\"%d\"", _shadow_alpha));
|
||||
}
|
||||
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<inventory_cell_set_additional_cells>%d %d</inventory_cell_set_additional_cells>\r\n", _additional_cells.x, _additional_cells.y));
|
||||
|
||||
for (auto &it : _cell_sets) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</inventory>\r\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventory::init(const qdInventoryCellTypeVector &tp) {
|
||||
bool result = true;
|
||||
for (auto &it : _cell_sets) {
|
||||
if (!it.init(tp)) {
|
||||
result = false;
|
||||
}
|
||||
it.set_additional_cells(_additional_cells);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool qdInventory::mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev) {
|
||||
if (ev == mouseDispatcher::EV_LEFT_DOWN) {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
bool ret_val = false;
|
||||
bool obj_flag = false;
|
||||
qdGameObjectAnimated *obj = get_object(Vect2s(x, y));
|
||||
|
||||
qdGameObjectMouse *mp = dp->mouse_object();
|
||||
if (mp->object()) {
|
||||
if (!obj) {
|
||||
if (put_object(mp->object(), mp->screen_pos())) {
|
||||
mp->take_object(NULL);
|
||||
ret_val = true;
|
||||
obj_flag = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (obj) {
|
||||
remove_object(obj);
|
||||
mp->take_object(obj);
|
||||
ret_val = true;
|
||||
obj_flag = true;
|
||||
}
|
||||
}
|
||||
if (obj) {
|
||||
if (qdGameScene * sp = dp->get_active_scene()) {
|
||||
sp->set_mouse_click_object(obj);
|
||||
ret_val = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!obj_flag && check_flag(INV_PUT_OBJECT_AFTER_CLICK) && mp->object()) {
|
||||
if (put_object(mp->object()))
|
||||
mp->take_object(NULL);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
} else if (ev == mouseDispatcher::EV_RIGHT_DOWN) {
|
||||
if (check_flag(INV_ENABLE_RIGHT_CLICK)) {
|
||||
if (qdGameDispatcher * dp = qd_get_game_dispatcher()) {
|
||||
qdGameObjectMouse *mp = dp->mouse_object();
|
||||
if (mp->object()) {
|
||||
if (put_object(mp->object())) {
|
||||
mp->take_object(NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
if (qdGameObjectAnimated * obj = get_object(Vect2s(x, y))) {
|
||||
if (qdGameScene * sp = dp->get_active_scene()) {
|
||||
sp->set_mouse_right_click_object(obj);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ev == mouseDispatcher::EV_MOUSE_MOVE) {
|
||||
qdGameObjectAnimated *obj = get_object(Vect2s(x, y));
|
||||
|
||||
if (obj) {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
if (qdGameScene * sp = dp->get_active_scene()) {
|
||||
sp->set_mouse_hover_object(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &it : _cell_sets) {
|
||||
it.set_mouse_hover_object(obj);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdInventory::remove_cell_set(int idx) {
|
||||
assert(-1 < idx && idx < static_cast<int>(_cell_sets.size()));
|
||||
|
||||
_cell_sets.erase(_cell_sets.begin() + idx);
|
||||
}
|
||||
|
||||
bool qdInventory::load_resources() {
|
||||
debugC(4, kDebugLoad, "qdInventory::load_resources(), %u cells", _cell_sets.size());
|
||||
|
||||
for (auto &it : _cell_sets)
|
||||
it.load_resources();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventory::free_resources() {
|
||||
for (auto &it : _cell_sets) {
|
||||
it.free_resources();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventory::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
debugC(3, kDebugSave, " qdInventory::load_data before: %d", (int)fh.pos());
|
||||
for (auto &it : _cell_sets) {
|
||||
if (!it.load_data(fh, save_version))
|
||||
return false;
|
||||
}
|
||||
debugC(3, kDebugSave, " qdInventory::load_data after: %d", (int)fh.pos());
|
||||
|
||||
debug_log();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventory::save_data(Common::WriteStream &fh) const {
|
||||
debugC(3, kDebugSave, " qdInventory::save_data before: %d", (int)fh.pos());
|
||||
for (auto &it : _cell_sets) {
|
||||
if (!it.save_data(fh)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
debugC(3, kDebugSave, " qdInventory::save_data after: %d", (int)fh.pos());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int qdInventory::cell_index(const qdGameObjectAnimated *obj) const {
|
||||
int index = 0;
|
||||
for (auto &it : _cell_sets) {
|
||||
int idx = it.cell_index(obj);
|
||||
if (idx != -1) {
|
||||
return index + idx;
|
||||
}
|
||||
else {
|
||||
index += it.num_cells();
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Vect2s qdInventory::cell_position(int cell_idx) const {
|
||||
for (auto &it : _cell_sets) {
|
||||
if (cell_idx < it.num_cells())
|
||||
return it.cell_position(cell_idx);
|
||||
|
||||
cell_idx -= it.num_cells();
|
||||
}
|
||||
|
||||
return Vect2s(0, 0);
|
||||
}
|
||||
|
||||
void qdInventory::objects_quant(float dt) {
|
||||
for (auto &it : _cell_sets) {
|
||||
it.objects_quant(dt);
|
||||
}
|
||||
}
|
||||
|
||||
void qdInventory::scroll_left() {
|
||||
for (auto &it : _cell_sets) {
|
||||
it.scroll_left();
|
||||
}
|
||||
toggle_redraw(true);
|
||||
}
|
||||
|
||||
void qdInventory::scroll_right() {
|
||||
for (auto &it : _cell_sets) {
|
||||
it.scroll_right();
|
||||
}
|
||||
toggle_redraw(true);
|
||||
}
|
||||
|
||||
void qdInventory::scroll_up() {
|
||||
for (auto &it : _cell_sets) {
|
||||
it.scroll_up();
|
||||
}
|
||||
toggle_redraw(true);
|
||||
}
|
||||
|
||||
void qdInventory::scroll_down() {
|
||||
for (auto &it : _cell_sets) {
|
||||
it.scroll_down();
|
||||
}
|
||||
toggle_redraw(true);
|
||||
}
|
||||
|
||||
void qdInventory::debug_log() const {
|
||||
#ifdef _DEBUG
|
||||
debugCN(3, kDebugLog, "Inventory ");
|
||||
if (name())
|
||||
debugCN(3, kDebugLog, "%s", transCyrillic(name()));
|
||||
|
||||
debugC(3, kDebugLog, "--------------");
|
||||
|
||||
for (auto &it : _cell_sets) {
|
||||
it.debug_log();
|
||||
}
|
||||
|
||||
debugC(3, kDebugLog, "--------------");
|
||||
#endif
|
||||
}
|
||||
} // namespace QDEngine
|
||||
163
engines/qdengine/qdcore/qd_inventory.h
Normal file
163
engines/qdengine/qdcore/qd_inventory.h
Normal file
@@ -0,0 +1,163 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INVENTORY_H
|
||||
#define QDENGINE_QDCORE_QD_INVENTORY_H
|
||||
|
||||
#include "qdengine/system/input/mouse_input.h"
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
#include "qdengine/qdcore/qd_inventory_cell.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
//! Инвентори.
|
||||
class qdInventory : public qdNamedObject {
|
||||
public:
|
||||
qdInventory();
|
||||
~qdInventory();
|
||||
|
||||
//! Флаги.
|
||||
enum {
|
||||
//! если установлен, объект берется сначала на мышь
|
||||
INV_TAKE_TO_MOUSE = 0x01,
|
||||
//! если установлен, то после взятия объекта инвентори не открывается
|
||||
INV_DONT_OPEN_AFTER_TAKE = 0x02,
|
||||
//! если установлен, то после клика объектом он возвращается в инветори
|
||||
INV_PUT_OBJECT_AFTER_CLICK = 0x04,
|
||||
//! если установлен, объект возвращается в инветори по правому клику мыши
|
||||
INV_ENABLE_RIGHT_CLICK = 0x08,
|
||||
//! отрисовывается даже если неактивно в данный момент
|
||||
INV_VISIBLE_WHEN_INACTIVE = 0x10
|
||||
};
|
||||
|
||||
enum {
|
||||
INV_DEFAULT_SHADOW_COLOR = 0,
|
||||
INV_DEFAULT_SHADOW_ALPHA = 128
|
||||
};
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_INVENTORY;
|
||||
}
|
||||
|
||||
void add_cell_set(const qdInventoryCellSet &set) {
|
||||
_cell_sets.push_back(set);
|
||||
}
|
||||
void remove_cell_set(int idx);
|
||||
|
||||
const qdInventoryCellSet &get_cell_set(int id = 0) const {
|
||||
return _cell_sets[id];
|
||||
}
|
||||
|
||||
void set_cells_pos(int set_id, const Vect2s &pos) {
|
||||
if (set_id >= 0 && set_id < (int)_cell_sets.size())
|
||||
_cell_sets[set_id].set_screen_pos(pos);
|
||||
}
|
||||
void set_cells_type(int set_id, const qdInventoryCellType &tp) {
|
||||
if (set_id >= 0 && set_id < (int)_cell_sets.size())
|
||||
_cell_sets[set_id].set_cell_type(tp);
|
||||
}
|
||||
void set_cells_size(int set_id, const Vect2s &sz) {
|
||||
if (set_id >= 0 && set_id < (int)_cell_sets.size())
|
||||
_cell_sets[set_id].set_size(sz);
|
||||
}
|
||||
|
||||
int cell_index(const qdGameObjectAnimated *obj) const;
|
||||
Vect2s cell_position(int cell_idx) const;
|
||||
|
||||
void redraw(int offs_x = 0, int offs_y = 0, bool inactive_mode = false) const;
|
||||
void toggle_redraw(bool state) {
|
||||
_need_redraw = state;
|
||||
}
|
||||
void pre_redraw() const;
|
||||
void post_redraw();
|
||||
|
||||
bool put_object(qdGameObjectAnimated *p);
|
||||
bool put_object(qdGameObjectAnimated *p, const Vect2s &pos);
|
||||
bool remove_object(qdGameObjectAnimated *p);
|
||||
qdGameObjectAnimated *get_object(const Vect2s &pos) const;
|
||||
bool is_object_in_list(const qdGameObjectAnimated *p) const;
|
||||
|
||||
uint32 shadow_color() const {
|
||||
return _shadow_color;
|
||||
}
|
||||
void set_shadow_color(uint32 color) {
|
||||
_shadow_color = color;
|
||||
}
|
||||
|
||||
int shadow_alpha() const {
|
||||
return _shadow_alpha;
|
||||
}
|
||||
void set_shadow_alpha(int alpha) {
|
||||
_shadow_alpha = alpha;
|
||||
}
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
bool load_resources();
|
||||
bool free_resources();
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
bool init(const qdInventoryCellTypeVector &tp);
|
||||
|
||||
bool mouse_handler(int x, int y, mouseDispatcher::mouseEvent ev);
|
||||
|
||||
void objects_quant(float dt);
|
||||
|
||||
Vect2s additional_cells() const {
|
||||
return _additional_cells;
|
||||
}
|
||||
void set_additional_cells(Vect2s val) {
|
||||
_additional_cells = val;
|
||||
}
|
||||
|
||||
//! Скроллинг
|
||||
void scroll_left();
|
||||
void scroll_right();
|
||||
void scroll_up();
|
||||
void scroll_down();
|
||||
|
||||
void debug_log() const;
|
||||
|
||||
private:
|
||||
|
||||
qdInventoryCellSetVector _cell_sets;
|
||||
|
||||
bool _need_redraw;
|
||||
|
||||
uint32 _shadow_color;
|
||||
int _shadow_alpha;
|
||||
|
||||
//! Дополнительные ячейки для всех наборов инвентори
|
||||
Vect2s _additional_cells;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INVENTORY_H
|
||||
578
engines/qdengine/qdcore/qd_inventory_cell.cpp
Normal file
578
engines/qdengine/qdcore/qd_inventory_cell.cpp
Normal file
@@ -0,0 +1,578 @@
|
||||
/* 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/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_inventory_cell.h"
|
||||
#include "qdengine/qdcore/qd_interface_element.h"
|
||||
#include "qdengine/qdcore/qd_named_object_reference.h"
|
||||
#include "qdengine/qdcore/qd_game_object_animated.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
// class qdInventoryCellType
|
||||
|
||||
bool qdInventoryCellType::load_resources() const {
|
||||
return _sprite.load();
|
||||
}
|
||||
|
||||
void qdInventoryCellType::free_resources() const {
|
||||
_sprite.free();
|
||||
}
|
||||
|
||||
bool qdInventoryCellType::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_TYPE:
|
||||
set_type(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_FILE:
|
||||
_sprite.set_file(Common::Path(it->data(), '\\'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCellType::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString(Common::String::format("<inventory_cell_type type=\"%d\"", _type));
|
||||
if (!_sprite.file().empty()) {
|
||||
fh.writeString(Common::String::format(" file=\"%s\"", qdscr_XML_string(_sprite.file().toString('\\'))));
|
||||
}
|
||||
fh.writeString("/>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// class qdInventoryCell
|
||||
|
||||
uint32 qdInventoryCell::_shadow_color = 0;
|
||||
int qdInventoryCell::_shadow_alpha = -1;
|
||||
|
||||
qdInventoryCell::qdInventoryCell() : _type(0),
|
||||
_sprite(NULL),
|
||||
_object(NULL) {
|
||||
}
|
||||
|
||||
qdInventoryCell::qdInventoryCell(const qdInventoryCellType &tp) : _type(tp.type()),
|
||||
_sprite(tp.sprite()),
|
||||
_object(NULL) {
|
||||
}
|
||||
|
||||
qdInventoryCell::qdInventoryCell(const qdInventoryCell &cl) : _type(cl._type),
|
||||
_sprite(cl._sprite),
|
||||
_object(cl._object) {
|
||||
}
|
||||
|
||||
qdInventoryCell &qdInventoryCell::operator = (const qdInventoryCell &cl) {
|
||||
if (this == &cl) return *this;
|
||||
|
||||
_type = cl._type;
|
||||
_sprite = cl._sprite;
|
||||
_object = cl._object;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void qdInventoryCell::redraw(int x, int y, bool inactive_mode) const {
|
||||
if (sprite())
|
||||
sprite()->redraw(x, y, 0);
|
||||
|
||||
if (_object) {
|
||||
_object->set_pos(Vect3f(x, y, 0));
|
||||
_object->set_flag(QD_OBJ_SCREEN_COORDS_FLAG);
|
||||
_object->update_screen_pos();
|
||||
_object->redraw();
|
||||
|
||||
if (inactive_mode)
|
||||
_object->draw_shadow(0, 0, _shadow_color, _shadow_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void qdInventoryCell::set_object(qdGameObjectAnimated *obj) {
|
||||
_object = obj;
|
||||
if (_object) _object->set_flag(QD_OBJ_SCREEN_COORDS_FLAG);
|
||||
}
|
||||
|
||||
bool qdInventoryCell::load_resources() {
|
||||
if (_object)
|
||||
return _object->load_resources();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCell::free_resources() {
|
||||
if (_object) _object->free_resources();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCell::load_data(Common::SeekableReadStream &fh, int saveVersion) {
|
||||
debugC(5, kDebugSave, " qdInventoryCell::load_data before: %d", (int)fh.pos());
|
||||
char flag = fh.readByte();
|
||||
|
||||
if (flag) {
|
||||
qdNamedObjectReference ref;
|
||||
if (!ref.load_data(fh, saveVersion)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (qdGameDispatcher * p = qdGameDispatcher::get_dispatcher()) {
|
||||
_object = static_cast<qdGameObjectAnimated *>(p->get_named_object(&ref));
|
||||
}
|
||||
} else
|
||||
_object = NULL;
|
||||
|
||||
debugC(5, kDebugSave, " qdInventoryCell::load_data after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCell::save_data(Common::WriteStream &fh) const {
|
||||
debugC(5, kDebugSave, " qdInventoryCell::save_data before: %d", (int)fh.pos());
|
||||
if (_object) {
|
||||
fh.writeByte(1);
|
||||
|
||||
qdNamedObjectReference ref(_object);
|
||||
if (!ref.save_data(fh)) {
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
fh.writeByte(0);
|
||||
|
||||
debugC(5, kDebugSave, " qdInventoryCell::save_data after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
// class qdInventoryCellSet
|
||||
|
||||
qdInventoryCellSet::qdInventoryCellSet() : _size(0, 0),
|
||||
_screen_pos(0, 0),
|
||||
_additional_cells(0, 0),
|
||||
_cells_shift(0, 0) {
|
||||
}
|
||||
|
||||
qdInventoryCellSet::qdInventoryCellSet(int x, int y, int sx, int sy, int16 addit_sx, int16 addit_sy, const qdInventoryCellType &tp) : _size(sx, sy),
|
||||
_screen_pos(x, y),
|
||||
_additional_cells(addit_sx, addit_sy),
|
||||
_cells_shift(0, 0),
|
||||
_cells((sx + addit_sx) * (sy + addit_sy), tp) {
|
||||
}
|
||||
|
||||
qdInventoryCellSet::qdInventoryCellSet(const qdInventoryCellSet &set) : _size(set._size),
|
||||
_cells(set._cells),
|
||||
_screen_pos(set._screen_pos),
|
||||
_additional_cells(set._additional_cells),
|
||||
_cells_shift(set._cells_shift) {
|
||||
}
|
||||
|
||||
qdInventoryCellSet::~qdInventoryCellSet() {
|
||||
_cells.clear();
|
||||
}
|
||||
|
||||
qdInventoryCellSet &qdInventoryCellSet::operator = (const qdInventoryCellSet &set) {
|
||||
if (this == &set) return *this;
|
||||
|
||||
_size = set._size;
|
||||
_cells = set._cells;
|
||||
_screen_pos = set._screen_pos;
|
||||
_additional_cells = set._additional_cells;
|
||||
_cells_shift = set._cells_shift;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::redraw(int offs_x, int offs_y, bool inactive_mode) const {
|
||||
Vect2s pos = screen_pos();
|
||||
|
||||
int idx;
|
||||
for (int i = _cells_shift.y; i < _size.y + _cells_shift.y; i++) {
|
||||
idx = i * (_size.x + _additional_cells.x) + _cells_shift.x;
|
||||
for (int j = _cells_shift.x; j < _size.x + _cells_shift.x; j++) {
|
||||
assert(idx >= 0 && idx < (int)_cells.size());
|
||||
_cells[idx].redraw(offs_x + pos.x, offs_y + pos.y, inactive_mode);
|
||||
pos.x += _cells[idx].size_x();
|
||||
idx++;
|
||||
}
|
||||
pos.x = screen_pos().x;
|
||||
pos.y += _cells.front().size_y();
|
||||
}
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::put_object(qdGameObjectAnimated *p) {
|
||||
for (auto &it : _cells) {
|
||||
if (it.is_empty() && it.type() == p->inventory_type()) {
|
||||
it.set_object(p);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::hit(const Vect2s &pos) const {
|
||||
if (_cells.empty() || !_cells.front().size_x() || !_cells.front().size_y())
|
||||
return false;
|
||||
|
||||
Vect2s v = pos - screen_pos() + _cells.front().size() / 2;
|
||||
|
||||
if (v.x >= 0 && v.x < _size.x * _cells.front().size_x() && v.y >= 0 && v.y < _size.y * _cells.front().size_y())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
grScreenRegion qdInventoryCellSet::screen_region() const {
|
||||
if (_cells.empty() || !_cells.front().size_x() || !_cells.front().size_y())
|
||||
return grScreenRegion_EMPTY;
|
||||
|
||||
int sx = _size.x * _cells.front().size_x();
|
||||
int sy = _size.y * _cells.front().size_y();
|
||||
|
||||
int x = screen_pos().x - _cells.front().size_x() / 2 + sx / 2;
|
||||
int y = screen_pos().y - _cells.front().size_y() / 2 + sy / 2;
|
||||
|
||||
return grScreenRegion(x, y, sx, sy);
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::put_object(qdGameObjectAnimated *p, const Vect2s &pos) {
|
||||
if (!hit(pos)) return false;
|
||||
|
||||
if (_cells.front().size_x() == 0 || _cells.front().size_y() == 0)
|
||||
return false;
|
||||
|
||||
Vect2s v = pos - screen_pos() + _cells.front().size() / 2;
|
||||
int idx = v.x / _cells.front().size_x() + (v.y / _cells.front().size_y()) * _size.x;
|
||||
// Двигаем индекс на текущее смещение ячеек
|
||||
idx += _cells_shift.y * (_size.x + _additional_cells.x) + _cells_shift.x;
|
||||
|
||||
if (idx >= 0 && idx < (int)_cells.size() && _cells[idx].is_empty() && _cells[idx].type() == p->inventory_type()) {
|
||||
_cells[idx].set_object(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdGameObjectAnimated *qdInventoryCellSet::get_object(const Vect2s &pos) const {
|
||||
if (!hit(pos)) return NULL;
|
||||
|
||||
if (_cells.front().size_x() == 0 || _cells.front().size_y() == 0)
|
||||
return NULL;
|
||||
|
||||
Vect2s v = pos - screen_pos() + _cells.front().size() / 2;
|
||||
|
||||
int idx = v.x / _cells.front().size_x() + (v.y / _cells.front().size_y()) * _size.x;
|
||||
// Двигаем индекс на текущее смещение ячеек
|
||||
idx += _cells_shift.y * (_size.x + _additional_cells.x) + _cells_shift.x;
|
||||
|
||||
if (idx >= 0 && idx < (int)_cells.size())
|
||||
return _cells[idx].object();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::remove_object(qdGameObjectAnimated *p) {
|
||||
for (auto &it : _cells) {
|
||||
if (it.object() == p) {
|
||||
it.set_object(NULL);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::is_object_in_list(const qdGameObjectAnimated *p) const {
|
||||
for (auto &it : _cells) {
|
||||
if (it.object() == p)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::load_script(const xml::tag *p) {
|
||||
Vect2s v;
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_INVENTORY_CELL_SET_POS:
|
||||
xml::tag_buffer(*it) > v.x > v.y;
|
||||
set_screen_pos(v);
|
||||
break;
|
||||
case QDSCR_INVENTORY_CELL_SET_SIZE:
|
||||
xml::tag_buffer(*it) > v.x > v.y;
|
||||
set_size(v);
|
||||
break;
|
||||
case QDSCR_INVENTORY_CELL_SET_ADDITIONAL_CELLS:
|
||||
xml::tag_buffer(*it) > _additional_cells.x > _additional_cells.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (const xml::tag * tp = p->search_subtag(QDSCR_TYPE))
|
||||
set_cell_type(qdInventoryCellType(xml::tag_buffer(*tp).get_int()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::save_script(Common::WriteStream &fh, int indent) const {
|
||||
int tp = 0;
|
||||
if (!_cells.empty()) {
|
||||
tp = _cells.front().type();
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<inventory_cell_set type=\"%d\">\r\n", tp));
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<inventory_cell_set_size>%d %d</inventory_cell_set_size>\r\n", _size.x, _size.y));
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<inventory_cell_set_pos>%d %d</inventory_cell_set_pos>\r\n", _screen_pos.x, _screen_pos.y));
|
||||
|
||||
for (int i = 0; i <= indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString(Common::String::format("<inventory_cell_set_additional_cells>%d %d</inventory_cell_set_additional_cells>\r\n", _additional_cells.x, _additional_cells.y));
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</inventory_cell_set>\r\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::init(const qdInventoryCellTypeVector &tp) {
|
||||
if (_cells.empty()) return false;
|
||||
|
||||
for (auto &it : tp) {
|
||||
if (it.type() == _cells.front().type()) {
|
||||
set_cell_type(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::load_resources() {
|
||||
for (auto &it : _cells)
|
||||
it.load_resources();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::free_resources() {
|
||||
for (auto &it : _cells) {
|
||||
it.free_resources();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::load_data(Common::SeekableReadStream &fh, int save_version) {
|
||||
debugC(4, kDebugSave, " qdInventoryCellSet::load_data before: %d", (int)fh.pos());
|
||||
if (save_version >= 102) {
|
||||
_additional_cells.x = fh.readSint32LE();
|
||||
_additional_cells.y = fh.readSint32LE();
|
||||
}
|
||||
for (auto &it : _cells) {
|
||||
if (!it.load_data(fh, save_version))
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(4, kDebugSave, " qdInventoryCellSet::load_data after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::save_data(Common::WriteStream &fh) const {
|
||||
debugC(4, kDebugSave, " qdInventoryCellSet::save_data before: %d", (int)fh.pos());
|
||||
fh.writeSint32LE(_additional_cells.x);
|
||||
fh.writeSint32LE(_additional_cells.y);
|
||||
|
||||
for (auto &it : _cells) {
|
||||
if (!it.save_data(fh))
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(4, kDebugSave, " qdInventoryCellSet::save_data after: %d", (int)fh.pos());
|
||||
return true;
|
||||
}
|
||||
|
||||
int qdInventoryCellSet::cell_index(const qdGameObjectAnimated *obj) const {
|
||||
for (auto it = _cells.begin(); it != _cells.end(); it++) {
|
||||
if (it->object() == obj) {
|
||||
return (it - _cells.begin());
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Vect2s qdInventoryCellSet::cell_position(int cell_idx) const {
|
||||
if (cell_idx >= 0 && cell_idx < (int)_cells.size()) {
|
||||
int x = (cell_idx % _size.x) * _cells.front().size_x() + screen_pos().x;
|
||||
int y = (cell_idx / _size.x) * _cells.front().size_y() + screen_pos().y;
|
||||
// Делаем поправку на смещение ячеек
|
||||
x -= _cells.front().size_x() * _cells_shift.x;
|
||||
y -= _cells.front().size_y() * _cells_shift.y;
|
||||
return Vect2s(x, y);
|
||||
}
|
||||
|
||||
return Vect2s(0, 0);
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::set_mouse_hover_object(qdGameObjectAnimated *obj) {
|
||||
for (auto &it : _cells) {
|
||||
if (it.object() && it.object() != obj && it.object()->get_cur_state()) {
|
||||
if (it.object()->get_cur_state()->check_flag(qdGameObjectState::QD_OBJ_STATE_FLAG_MOUSE_HOVER_STATE)) {
|
||||
if (qdGameObjectState *sp = it.object()->get_inventory_state())
|
||||
it.object()->set_state(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (obj) {
|
||||
if (qdGameObjectState * p = obj->get_mouse_hover_state()) {
|
||||
if (obj->get_cur_state() != p)
|
||||
p->set_prev_state(obj->get_cur_state());
|
||||
obj->set_state(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::objects_quant(float dt) {
|
||||
for (auto &it : _cells) {
|
||||
if (!it.is_empty()) {
|
||||
it.object()->quant(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::pre_redraw() const {
|
||||
qdGameDispatcher *dp = qdGameDispatcher::get_dispatcher();
|
||||
if (!dp) return;
|
||||
|
||||
int idx;
|
||||
for (int i = _cells_shift.y; i < size().y + _cells_shift.y; i++) {
|
||||
idx = i * (_size.x + _additional_cells.x) + _cells_shift.x;
|
||||
for (int j = _cells_shift.x; j < size().x + _cells_shift.x; j++) {
|
||||
assert(idx >= 0 && idx < (int)_cells.size());
|
||||
if (!_cells[idx].is_empty() && _cells[idx].object()->need_redraw()) {
|
||||
dp->add_redraw_region(_cells[idx].object()->last_screen_region());
|
||||
dp->add_redraw_region(_cells[idx].object()->screen_region());
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
grScreenRegion reg = screen_region();
|
||||
if (reg != _last_screen_region) {
|
||||
dp->add_redraw_region(_last_screen_region);
|
||||
dp->add_redraw_region(reg);
|
||||
}
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::post_redraw() {
|
||||
int idx;
|
||||
for (int i = _cells_shift.y; i < size().y + _cells_shift.y; i++) {
|
||||
idx = i * (_size.x + _additional_cells.x) + _cells_shift.x;
|
||||
for (int j = _cells_shift.x; j < size().x + _cells_shift.x; j++) {
|
||||
assert(idx >= 0 && idx < (int)_cells.size());
|
||||
if (!_cells[idx].is_empty())
|
||||
_cells[idx].object()->post_redraw();
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
_last_screen_region = screen_region();
|
||||
}
|
||||
|
||||
bool qdInventoryCellSet::has_rect_objects(int left, int top, int right, int bottom) const {
|
||||
int idx;
|
||||
for (int i = top; i <= bottom; i++)
|
||||
for (int j = left; j <= right; j++) {
|
||||
idx = i * (_size.x + _additional_cells.x) + j;
|
||||
assert(idx >= 0 && idx < (int)_cells.size());
|
||||
// Нашли объект вне видимой области - значит скроллинг нужен
|
||||
if (!_cells[idx].is_empty())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::scroll_left() {
|
||||
if (!has_rect_objects(0, 0, _cells_shift.x - 1, _size.y + _additional_cells.y - 1))
|
||||
return;
|
||||
_cells_shift.x--;
|
||||
if (_cells_shift.x < 0) _cells_shift.x = _additional_cells.x;
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::scroll_right() {
|
||||
if (!has_rect_objects(_cells_shift.x + _size.x, 0, _size.x + _additional_cells.x - 1, _size.y + _additional_cells.y - 1))
|
||||
return;
|
||||
_cells_shift.x++;
|
||||
if (_cells_shift.x > _additional_cells.x) _cells_shift.x = 0;
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::scroll_up() {
|
||||
if (!has_rect_objects(0, 0, _size.x + _additional_cells.x - 1, _cells_shift.y - 1))
|
||||
return;
|
||||
_cells_shift.y--;
|
||||
if (_cells_shift.y < 0) _cells_shift.y = _additional_cells.y;
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::scroll_down() {
|
||||
if (!has_rect_objects(0, _cells_shift.y + _size.y, _size.x + _additional_cells.x - 1, _size.y + _additional_cells.y - 1))
|
||||
return;
|
||||
_cells_shift.y++;
|
||||
if (_cells_shift.y > _additional_cells.y) _cells_shift.y = 0;
|
||||
}
|
||||
|
||||
void qdInventoryCellSet::debug_log() const {
|
||||
#ifdef _DEBUG
|
||||
for (int i = _cells_shift.y; i < size().y + _cells_shift.y; i++) {
|
||||
int idx = i * (_size.x + _additional_cells.x) + _cells_shift.x;
|
||||
for (int j = _cells_shift.x; j < size().x + _cells_shift.x; j++) {
|
||||
if (!_cells[idx].is_empty()) {
|
||||
debugC(3, kDebugLog, "Inventory cell: %d %d %s", i, j, transCyrillic(_cells[idx].object()->name()));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
294
engines/qdengine/qdcore/qd_inventory_cell.h
Normal file
294
engines/qdengine/qdcore/qd_inventory_cell.h
Normal file
@@ -0,0 +1,294 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_INVENTORY_CELL_H
|
||||
#define QDENGINE_QDCORE_QD_INVENTORY_CELL_H
|
||||
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_sprite.h"
|
||||
|
||||
namespace Common {
|
||||
class WriteStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdGameObjectAnimated;
|
||||
|
||||
//! Описание ячейки инвентори.
|
||||
class qdInventoryCellType {
|
||||
public:
|
||||
qdInventoryCellType() : _type(0) { }
|
||||
explicit qdInventoryCellType(int tp) : _type(tp) { }
|
||||
~qdInventoryCellType() {
|
||||
_sprite.free();
|
||||
}
|
||||
|
||||
int type() const {
|
||||
return _type;
|
||||
}
|
||||
void set_type(int tp) {
|
||||
_type = tp;
|
||||
}
|
||||
|
||||
void set_sprite_file(const Common::Path &fname) {
|
||||
_sprite.set_file(fname);
|
||||
}
|
||||
const Common::Path sprite_file() const {
|
||||
return _sprite.file();
|
||||
}
|
||||
|
||||
const qdSprite *sprite() const {
|
||||
return &_sprite;
|
||||
}
|
||||
|
||||
bool load_resources() const;
|
||||
void free_resources() const;
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
const Vect2i &size() const {
|
||||
return _sprite.size();
|
||||
}
|
||||
|
||||
private:
|
||||
//! Тип ячейки.
|
||||
int _type;
|
||||
//! Внешний вид ячейки.
|
||||
mutable qdSprite _sprite;
|
||||
};
|
||||
|
||||
inline bool operator == (const qdInventoryCellType &f, const qdInventoryCellType &s) {
|
||||
return ((f.type() == s.type()) && (f.sprite() == s.sprite()));
|
||||
}
|
||||
|
||||
inline bool operator == (const qdInventoryCellType &f, int type) {
|
||||
return f.type() == type;
|
||||
}
|
||||
|
||||
typedef Std::vector<qdInventoryCellType> qdInventoryCellTypeVector;
|
||||
|
||||
//! Ячейка инвентори.
|
||||
class qdInventoryCell {
|
||||
public:
|
||||
qdInventoryCell();
|
||||
qdInventoryCell(const qdInventoryCellType &tp);
|
||||
qdInventoryCell(const qdInventoryCell &cl);
|
||||
~qdInventoryCell() { }
|
||||
|
||||
qdInventoryCell &operator = (const qdInventoryCell &cl);
|
||||
|
||||
int type() const {
|
||||
return _type;
|
||||
}
|
||||
void set_type(int tp) {
|
||||
_type = tp;
|
||||
}
|
||||
|
||||
const qdSprite *sprite() const {
|
||||
return _sprite;
|
||||
}
|
||||
void set_sprite(const qdSprite *spr) {
|
||||
_sprite = spr;
|
||||
}
|
||||
|
||||
qdGameObjectAnimated *object() const {
|
||||
return _object;
|
||||
}
|
||||
void set_object(qdGameObjectAnimated *obj);
|
||||
|
||||
bool is_empty() const {
|
||||
if (!_object) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
const Vect2i &size() const {
|
||||
if (sprite())
|
||||
return sprite()->size();
|
||||
|
||||
static Vect2i z = Vect2i(0, 0);
|
||||
return z;
|
||||
}
|
||||
|
||||
int size_x() const {
|
||||
if (sprite()) return sprite()->size_x();
|
||||
else return 0;
|
||||
}
|
||||
int size_y() const {
|
||||
if (sprite()) return sprite()->size_y();
|
||||
else return 0;
|
||||
}
|
||||
|
||||
void redraw(int x, int y, bool inactive_mode = false) const;
|
||||
|
||||
bool load_resources();
|
||||
bool free_resources();
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
static void set_shadow(uint32 color, int alpha) {
|
||||
_shadow_color = color;
|
||||
_shadow_alpha = alpha;
|
||||
}
|
||||
|
||||
private:
|
||||
//! Тип ячейки.
|
||||
int _type;
|
||||
|
||||
//! Внешний вид ячейки.
|
||||
/**
|
||||
Указывает на _sprite из qdInventoryCellType соответствующего типа.
|
||||
*/
|
||||
const qdSprite *_sprite;
|
||||
|
||||
//! Объект, который лежит в ячейке.
|
||||
mutable qdGameObjectAnimated *_object;
|
||||
|
||||
static uint32 _shadow_color;
|
||||
static int _shadow_alpha;
|
||||
};
|
||||
|
||||
typedef Std::vector<qdInventoryCell> qdInventoryCellVector;
|
||||
|
||||
//! Группа ячеек инвентори.
|
||||
class qdInventoryCellSet {
|
||||
public:
|
||||
qdInventoryCellSet();
|
||||
qdInventoryCellSet(int x, int y, int sx, int sy, int16 addit_sx, int16 addit_sy, const qdInventoryCellType &tp);
|
||||
qdInventoryCellSet(const qdInventoryCellSet &set);
|
||||
~qdInventoryCellSet();
|
||||
|
||||
qdInventoryCellSet &operator = (const qdInventoryCellSet &set);
|
||||
|
||||
const Vect2s screen_pos() const {
|
||||
return _screen_pos + g_engine->screen_offset();
|
||||
}
|
||||
void set_screen_pos(const Vect2s &pos) {
|
||||
_screen_pos = pos;
|
||||
}
|
||||
|
||||
grScreenRegion screen_region() const;
|
||||
const grScreenRegion &last_screen_region() const {
|
||||
return _last_screen_region;
|
||||
}
|
||||
|
||||
int cell_index(const qdGameObjectAnimated *obj) const;
|
||||
Vect2s cell_position(int cell_idx) const;
|
||||
|
||||
const Vect2s &size() const {
|
||||
return _size;
|
||||
}
|
||||
void set_size(const Vect2s &sz) {
|
||||
assert(sz.x && sz.y);
|
||||
qdInventoryCell t;
|
||||
if (_size.x != 0)//предполагаю, что либо оба равны либо оба неравны 0
|
||||
t = _cells.front();
|
||||
_size = sz;
|
||||
_cells.resize((sz.x + _additional_cells.x) * (sz.y + _additional_cells.y));
|
||||
Common::fill(_cells.begin(), _cells.end(), t);
|
||||
}
|
||||
|
||||
void set_cell_type(const qdInventoryCellType &tp) {
|
||||
Common::fill(_cells.begin(), _cells.end(), tp);
|
||||
}
|
||||
|
||||
bool hit(const Vect2s &pos) const;
|
||||
void set_mouse_hover_object(qdGameObjectAnimated *obj);
|
||||
|
||||
void pre_redraw() const;
|
||||
void redraw(int offs_x = 0, int offs_y = 0, bool inactive_mode = false) const;
|
||||
void post_redraw();
|
||||
|
||||
bool put_object(qdGameObjectAnimated *p);
|
||||
bool put_object(qdGameObjectAnimated *p, const Vect2s &pos);
|
||||
bool remove_object(qdGameObjectAnimated *p);
|
||||
qdGameObjectAnimated *get_object(const Vect2s &pos) const;
|
||||
bool is_object_in_list(const qdGameObjectAnimated *p) const;
|
||||
|
||||
bool load_script(const xml::tag *p);
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из сэйва.
|
||||
bool load_data(Common::SeekableReadStream &fh, int save_version);
|
||||
//! Запись данных в сэйв.
|
||||
bool save_data(Common::WriteStream &fh) const;
|
||||
|
||||
bool init(const qdInventoryCellTypeVector &tp);
|
||||
|
||||
const qdInventoryCellVector &cells() const {
|
||||
return _cells;
|
||||
}
|
||||
int num_cells() const {
|
||||
return _cells.size();
|
||||
}
|
||||
|
||||
bool load_resources();
|
||||
bool free_resources();
|
||||
|
||||
void objects_quant(float dt);
|
||||
|
||||
Vect2s additional_cells() const {
|
||||
return _additional_cells;
|
||||
}
|
||||
void set_additional_cells(Vect2s val) {
|
||||
_additional_cells = val;
|
||||
// Изменили кол-во доп. ячеек - изменяем и всех кол-во массива ячеек
|
||||
set_size(size());
|
||||
}
|
||||
|
||||
//! Скроллинг
|
||||
void scroll_left();
|
||||
void scroll_right();
|
||||
void scroll_up();
|
||||
void scroll_down();
|
||||
|
||||
void debug_log() const;
|
||||
|
||||
private:
|
||||
// Имеет ли область полного инвентори сета объекты
|
||||
bool has_rect_objects(int left, int top, int right, int bottom) const;
|
||||
|
||||
//! Размер группы.
|
||||
/**
|
||||
В группе _size.x * _size.y ячеек.
|
||||
*/
|
||||
Vect2s _size;
|
||||
//! Дополнительне ячейки по x и y
|
||||
Vect2s _additional_cells;
|
||||
//! Смещение по x и y (с него выводятся ячекйки в количестве _size)
|
||||
Vect2s _cells_shift;
|
||||
//! Ячейки.
|
||||
qdInventoryCellVector _cells;
|
||||
//! Экранные координаты центра первой ячейки группы.
|
||||
Vect2s _screen_pos;
|
||||
|
||||
grScreenRegion _last_screen_region;
|
||||
};
|
||||
|
||||
typedef Std::vector<qdInventoryCellSet> qdInventoryCellSetVector;
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_INVENTORY_CELL_H
|
||||
202
engines/qdengine/qdcore/qd_list.h
Normal file
202
engines/qdengine/qdcore/qd_list.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_LIST_H
|
||||
#define QDENGINE_QDCORE_QD_LIST_H
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
template <class Type> class qdList {
|
||||
int numElements;
|
||||
Type *firstElement;
|
||||
void test(int code);
|
||||
|
||||
public:
|
||||
|
||||
qdList();
|
||||
~qdList();
|
||||
|
||||
int size();
|
||||
Type *first();
|
||||
Type *last();
|
||||
|
||||
void clear();
|
||||
void delete_all();
|
||||
|
||||
void insert(Type *p);
|
||||
void append(Type *p);
|
||||
void insert(Type *pointer, Type *p);
|
||||
void append(Type *pointer, Type *p);
|
||||
void remove(Type *p);
|
||||
Type *search(int ID);
|
||||
};
|
||||
|
||||
template <class Type>
|
||||
inline void qdList<Type>::test(int code) {
|
||||
#ifdef _XT_TEST_LIST_
|
||||
Type *p = first();
|
||||
int cnt = 0;
|
||||
while (p) {
|
||||
cnt++;
|
||||
p = p->next;
|
||||
}
|
||||
if (cnt != numElements)
|
||||
ErrH.Abort("List", XERR_USER, code);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline qdList<Type>::qdList() {
|
||||
numElements = 0;
|
||||
firstElement = 0;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline qdList<Type>::~qdList() {
|
||||
clear();
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline void qdList<Type>::clear() {
|
||||
while (first())
|
||||
remove(first());
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline void qdList<Type>::delete_all() {
|
||||
Type *p;
|
||||
while ((p = first()) != 0) {
|
||||
remove(p);
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline int qdList<Type>::size() {
|
||||
return numElements;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline Type *qdList<Type>::first() {
|
||||
return firstElement;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline Type *qdList<Type>::last() {
|
||||
return firstElement ? firstElement->prev : 0;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline void qdList<Type>::insert(Type *p) {
|
||||
if (p->list)
|
||||
ErrH.Abort("Element is already in list");
|
||||
numElements++;
|
||||
if (firstElement) {
|
||||
p->next = firstElement;
|
||||
p->prev = firstElement->prev;
|
||||
firstElement->prev = p;
|
||||
} else {
|
||||
p->prev = p;
|
||||
p->next = 0;
|
||||
}
|
||||
firstElement = p;
|
||||
p->list = this;
|
||||
test(0);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline void qdList<Type>::insert(Type *pointer, Type *p) {
|
||||
if (!firstElement || firstElement == pointer) {
|
||||
insert(p);
|
||||
return;
|
||||
}
|
||||
if (!pointer) {
|
||||
append(p);
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->list)
|
||||
ErrH.Abort("Element is already in list");
|
||||
numElements++;
|
||||
p->next = pointer;
|
||||
p->prev = pointer->prev;
|
||||
pointer->prev->next = p;
|
||||
pointer->prev = p;
|
||||
p->list = this;
|
||||
test(5);
|
||||
}
|
||||
|
||||
|
||||
template <class Type>
|
||||
inline void qdList<Type>::append(Type *p) {
|
||||
// if(p->list)
|
||||
// ErrH.Abort("Element is already in list");
|
||||
numElements++;
|
||||
if (firstElement) {
|
||||
p->next = 0;
|
||||
p->prev = firstElement->prev;
|
||||
firstElement->prev->next = p;
|
||||
firstElement->prev = p;
|
||||
} else {
|
||||
p->next = 0;
|
||||
p->prev = firstElement = p;
|
||||
}
|
||||
p->list = this;
|
||||
test(1);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline void qdList<Type>::remove(Type *p) {
|
||||
// if(p->list != this)
|
||||
// ErrH.Abort("Removed element isn't in list");
|
||||
numElements--;
|
||||
if (p->next)
|
||||
p->next->prev = p->prev;
|
||||
else
|
||||
firstElement->prev = p->prev;
|
||||
|
||||
if (p != firstElement)
|
||||
p->prev->next = p->next;
|
||||
else {
|
||||
firstElement = p->next;
|
||||
if (firstElement)
|
||||
firstElement->prev = p->prev;
|
||||
}
|
||||
|
||||
p->next = p->prev = 0;
|
||||
p->list = 0;
|
||||
test(2);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline Type *qdList<Type>::search(int ID) {
|
||||
Type *p = first();
|
||||
while (p) {
|
||||
if (p->ID == ID)
|
||||
return p;
|
||||
p = p->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_LIST_H
|
||||
421
engines/qdengine/qdcore/qd_minigame.cpp
Normal file
421
engines/qdengine/qdcore/qd_minigame.cpp
Normal file
@@ -0,0 +1,421 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/system/input/mouse_input.h"
|
||||
#include "qdengine/system/input/keyboard_input.h"
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_minigame.h"
|
||||
#include "qdengine/qdcore/qd_setup.h"
|
||||
#include "qdengine/qdcore/qd_minigame_interface.h"
|
||||
#include "qdengine/qdcore/qd_engine_interface.h"
|
||||
|
||||
#include "qdengine/minigames/adv/RunTime.h"
|
||||
|
||||
#include "qdengine/minigames/qd_empty_minigame_interface.h"
|
||||
|
||||
// maski
|
||||
#include "qdengine/minigames/arkada_avtomat.h"
|
||||
#include "qdengine/minigames/kartiny.h"
|
||||
#include "qdengine/minigames/maski_21.h"
|
||||
#include "qdengine/minigames/masky_order.h"
|
||||
#include "qdengine/minigames/orchestra.h"
|
||||
#include "qdengine/minigames/scroll.h"
|
||||
#include "qdengine/minigames/tetris.h"
|
||||
|
||||
// 2mice1
|
||||
#include "qdengine/minigames/book_all.h"
|
||||
#include "qdengine/minigames/puzzle_all.h"
|
||||
|
||||
// shveik
|
||||
#include "qdengine/minigames/inv_popup.h"
|
||||
#include "qdengine/minigames/shveik_shkatulka.h"
|
||||
#include "qdengine/minigames/shveik_portret.h"
|
||||
|
||||
// 3mice2
|
||||
#include "qdengine/minigames/3mice2_sbor_karty.h"
|
||||
#include "qdengine/minigames/3mice2_kovrik.h"
|
||||
#include "qdengine/minigames/3mice2_sudoku.h"
|
||||
#include "qdengine/minigames/3mice2_states.h"
|
||||
#include "qdengine/minigames/3mice2_testo.h"
|
||||
#include "qdengine/minigames/3mice2_plate.h"
|
||||
#include "qdengine/minigames/3mice2_raskr_all.h"
|
||||
#include "qdengine/minigames/3mice2_babochka.h"
|
||||
|
||||
// dogncat
|
||||
#include "qdengine/minigames/adv/m_scores.h"
|
||||
#include "qdengine/minigames/adv/m_triangles.h"
|
||||
|
||||
// dogncat2
|
||||
#include "qdengine/minigames/adv/m_swap.h"
|
||||
|
||||
// klepa
|
||||
#include "qdengine/minigames/adv/m_puzzle.h"
|
||||
#include "qdengine/minigames/adv/m_karaoke.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdMiniGame::qdMiniGame() : _dll_handle(NULL),
|
||||
_interface(NULL) {
|
||||
}
|
||||
|
||||
qdMiniGame::qdMiniGame(const qdMiniGame &mg) : qdNamedObject(mg),
|
||||
_dll_name(mg._dll_name),
|
||||
_dll_handle(mg._dll_handle),
|
||||
_interface(mg._interface),
|
||||
_config(mg._config) {
|
||||
}
|
||||
|
||||
qdMiniGame::~qdMiniGame() {
|
||||
if (_interface)
|
||||
_interface->finit();
|
||||
release_interface();
|
||||
}
|
||||
|
||||
bool qdMiniGame::start() {
|
||||
if (load_interface()) {
|
||||
return _interface->init(&qdmg::qdEngineInterfaceImpl::instance());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdMiniGame::is_started() const {
|
||||
return _interface != 0;
|
||||
}
|
||||
|
||||
bool qdMiniGame::quant(float dt) {
|
||||
if (_interface)
|
||||
_interface->quant(dt);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdMiniGame::end() {
|
||||
if (_interface)
|
||||
_interface->finit();
|
||||
|
||||
return release_interface();
|
||||
}
|
||||
|
||||
int qdMiniGame::save_game(char *buffer, int buffer_size, qdGameScene *scene) {
|
||||
bool need_release = false;
|
||||
if (!is_started()) {
|
||||
if (!load_interface()) return 0;
|
||||
need_release = true;
|
||||
}
|
||||
|
||||
qdMinigameSceneInterface *scene_int = qdmg::qdEngineInterfaceImpl::instance().scene_interface(scene);
|
||||
int size = _interface->save_game(&qdmg::qdEngineInterfaceImpl::instance(), scene_int, buffer, buffer_size);
|
||||
qdmg::qdEngineInterfaceImpl::instance().release_scene_interface(scene_int);
|
||||
|
||||
if (need_release)
|
||||
release_interface();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int qdMiniGame::load_game(const char *buffer, int buffer_size, qdGameScene *scene) {
|
||||
bool need_release = false;
|
||||
if (!is_started()) {
|
||||
if (!load_interface()) return 0;
|
||||
need_release = true;
|
||||
}
|
||||
|
||||
qdMinigameSceneInterface *scene_int = qdmg::qdEngineInterfaceImpl::instance().scene_interface(scene);
|
||||
int size = _interface->load_game(&qdmg::qdEngineInterfaceImpl::instance(), scene_int, buffer, buffer_size);
|
||||
qdmg::qdEngineInterfaceImpl::instance().release_scene_interface(scene_int);
|
||||
|
||||
if (need_release)
|
||||
release_interface();
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool qdMiniGame::load_script(const xml::tag *p) {
|
||||
int config_size = 0;
|
||||
for (xml::tag::subtag_iterator it1 = p->subtags_begin(); it1 != p->subtags_end(); ++it1) {
|
||||
if (it1->ID() == QDSCR_MINIGAME_CONFIG_PARAMETER)
|
||||
config_size++;
|
||||
}
|
||||
|
||||
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
|
||||
switch (it->ID()) {
|
||||
case QDSCR_FLAG:
|
||||
set_flag(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
case QDSCR_NAME:
|
||||
set_name(it->data());
|
||||
break;
|
||||
case QDSCR_MINIGAME_DLL_NAME:
|
||||
set_dll_name(it->data());
|
||||
break;
|
||||
case QDSCR_MINIGAME_GAME_NAME:
|
||||
set_game_name(it->data());
|
||||
break;
|
||||
case QDSCR_MINIGAME_CONFIG_FILE:
|
||||
set_config_file_name(Common::Path(it->data(), '\\'));
|
||||
load_config();
|
||||
_config.reserve(_config.size() + config_size);
|
||||
break;
|
||||
case QDSCR_MINIGAME_CONFIG_PARAMETER: {
|
||||
/* if (!qdGameConfig::get_config().minigame_read_only_ini())
|
||||
* has been removed since none of the games require this setting
|
||||
*/
|
||||
qdMinigameConfigParameter prm;
|
||||
prm.load_script(&*it);
|
||||
config_container_t::iterator cfg_it = Common::find(_config.begin(), _config.end(), prm);
|
||||
if (cfg_it != _config.end()) {
|
||||
cfg_it->set_data_string(prm.data_string());
|
||||
cfg_it->set_data_count(prm.data_count());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdMiniGame::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
|
||||
fh.writeString("<minigame");
|
||||
|
||||
if (name()) {
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
}
|
||||
|
||||
if (flags()) {
|
||||
fh.writeString(Common::String::format(" flags=\"%d\"", flags()));
|
||||
}
|
||||
|
||||
if (!_config_file_name.empty()) {
|
||||
fh.writeString(Common::String::format(" config_file=\"%s\"", qdscr_XML_string(config_file_name().toString('\\'))));
|
||||
}
|
||||
|
||||
if (!_dll_name.empty()) {
|
||||
fh.writeString(Common::String::format(" dll_name=\"%s\"", qdscr_XML_string(dll_name())));
|
||||
}
|
||||
|
||||
if (!_game_name.empty()) {
|
||||
fh.writeString(Common::String::format(" game_name=\"%s\"", qdscr_XML_string(game_name())));
|
||||
}
|
||||
|
||||
if (!_config.empty()) {
|
||||
fh.writeString(">\r\n");
|
||||
|
||||
for (auto &it: _config) {
|
||||
it.save_script(fh, indent + 1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("</minigame>\r\n");
|
||||
} else {
|
||||
fh.writeString("/>\r\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qdMiniGame &qdMiniGame::operator = (const qdMiniGame &mg) {
|
||||
if (this == &mg) return *this;
|
||||
|
||||
*static_cast<qdNamedObject *>(this) = mg;
|
||||
|
||||
_dll_name = mg._dll_name;
|
||||
_dll_handle = mg._dll_handle;
|
||||
_interface = mg._interface;
|
||||
|
||||
_config_file_name = mg._config_file_name;
|
||||
_config = mg._config;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool qdMiniGame::init() {
|
||||
if (load_interface()) {
|
||||
_interface->new_game(&qdmg::qdEngineInterfaceImpl::instance());
|
||||
release_interface();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdMiniGame::load_config() {
|
||||
if (_config_file_name.empty())
|
||||
return false;
|
||||
|
||||
_config.clear();
|
||||
Common::INIFile ini;
|
||||
Common::INIFile::SectionList section_list;
|
||||
enumerateIniSections(ini, config_file_name(), section_list);
|
||||
|
||||
_config.reserve(section_list.size());
|
||||
|
||||
for (auto &it : section_list) {
|
||||
qdMinigameConfigParameter prm;
|
||||
prm.load_ini(ini, config_file_name(), it.name.c_str());
|
||||
_config.push_back(prm);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *qdMiniGame::config_parameter_value(const char *cfg_param_name) const {
|
||||
config_container_t::const_iterator it = Common::find(_config.begin(), _config.end(), cfg_param_name);
|
||||
if (it != _config.end())
|
||||
return it->data_string();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdMiniGame::load_interface() {
|
||||
if (!_dll_name.empty()) {
|
||||
|
||||
// maski
|
||||
if (_dll_name == "Resource\\DLL\\tetris.dll") {
|
||||
_interface = new qdTetrisMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "Resource\\DLL\\scroll.dll") {
|
||||
_interface = new qdScrollMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "Resource\\DLL\\MaskyOrder.dll") {
|
||||
_interface = new qdMaskyOrderMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "Resource\\DLL\\maski_21.dll") {
|
||||
_interface = new qdMaski21MiniGame(false);
|
||||
return true;
|
||||
} else if (_dll_name == "Resource\\DLL\\maski_21_random.dll") {
|
||||
_interface = new qdMaski21MiniGame(true);
|
||||
return true;
|
||||
} else if (_dll_name == "Resource\\DLL\\kartiny.dll") {
|
||||
_interface = new qdKartinyMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "Resource\\DLL\\orchestra.dll") {
|
||||
_interface = new qdOrchestraMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "Resource\\DLL\\Arkada_avtomat.dll") {
|
||||
_interface = new qdArkadaAvtomatMiniGame();
|
||||
return true;
|
||||
|
||||
|
||||
// 3mice1
|
||||
} else if (_dll_name == "DLL\\Book_gusenica.dll" || _dll_name == "DLL\\Book_les.dll"
|
||||
|| _dll_name == "DLL\\Book_buhta.dll") {
|
||||
_interface = new qdBookAllMiniGame(_dll_name, g_engine->getLanguage());
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\Puzzle_ep01.dll" || _dll_name == "DLL\\Puzzle_ep02.dll"
|
||||
|| _dll_name == "DLL\\Puzzle_ep04.dll" || _dll_name == "DLL\\Puzzle_ep05.dll"
|
||||
|| _dll_name == "DLL\\Puzzle_ep07.dll" || _dll_name == "DLL\\Puzzle_ep08.dll"
|
||||
|| _dll_name == "DLL\\Puzzle_ep13.dll") {
|
||||
_interface = new qdPuzzleAllMiniGame(_dll_name, g_engine->getLanguage());
|
||||
return true;
|
||||
|
||||
// shveik
|
||||
} else if (_dll_name == "DLL\\inv_popup.dll") {
|
||||
_interface = new qdInvPopupMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\ShveikShkatulka.dll") {
|
||||
_interface = new qdShveikShkatulkaMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\ShveikPortret.dll") {
|
||||
_interface = new qdShveikPortretMiniGame();
|
||||
return true;
|
||||
|
||||
// klepa
|
||||
} else if (_dll_name == "DLL\\puzzle.dll") {
|
||||
_interface = create_adv_minigame(_dll_name.c_str(), createMinigamePuzzle);
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\Karaoke.dll") {
|
||||
_interface = create_adv_minigame(_dll_name.c_str(), createMinigameKaraoke);
|
||||
return true;
|
||||
|
||||
// 3mice2
|
||||
} else if (_dll_name == "DLL\\3Mice2_sbor_karty.dll") {
|
||||
_interface = new qd3mice2SborKartyMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_kovrik.dll") {
|
||||
_interface = new qd3mice2KovrikMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_sudoku.dll") {
|
||||
_interface = new qd3mice2SudokuMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_states.dll") {
|
||||
_interface = new qd3mice2StatesMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_testo.dll") {
|
||||
_interface = new qd3mice2TestoMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_plate.dll") {
|
||||
_interface = new qd3mice2PlateMiniGame();
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_raskr1.dll") {
|
||||
_interface = new qd3mice2RaskrAllMiniGame(1);
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_raskr2.dll") {
|
||||
_interface = new qd3mice2RaskrAllMiniGame(2);
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_raskr3.dll") {
|
||||
_interface = new qd3mice2RaskrAllMiniGame(3);
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_raskr4.dll") {
|
||||
_interface = new qd3mice2RaskrAllMiniGame(4);
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\3Mice2_babochka.dll") {
|
||||
_interface = new qd3mice2BabochkaMiniGame();
|
||||
return true;
|
||||
|
||||
// dogncat
|
||||
} else if (_dll_name == "DLL\\triangles.dll") {
|
||||
_interface = create_adv_minigame(_dll_name.c_str(), createMinigameTriangle);
|
||||
return true;
|
||||
} else if (_dll_name == "DLL\\scores.dll") {
|
||||
_interface = create_adv_minigame(_dll_name.c_str(), createMinigameScores);
|
||||
return true;
|
||||
|
||||
// dogncat2
|
||||
} else if (_dll_name == "DLL\\swap.dll") {
|
||||
_interface = create_adv_minigame(_dll_name.c_str(), createMinigameSwap);
|
||||
return true;
|
||||
} else {
|
||||
warning("qdMiniGame::load_interface(): trying to load dll: %s", _dll_name.c_str());
|
||||
// call here dll->open_game_interface(game_name())
|
||||
_interface = new qdEmptyMiniGameInterface;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdMiniGame::release_interface() {
|
||||
if (_interface)
|
||||
close_adv_minigame(_interface);
|
||||
|
||||
_interface = nullptr;
|
||||
return true;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
135
engines/qdengine/qdcore/qd_minigame.h
Normal file
135
engines/qdengine/qdcore/qd_minigame.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_MINIGAME_H
|
||||
#define QDENGINE_QDCORE_QD_MINIGAME_H
|
||||
|
||||
#include "qdengine/qdcore/qd_named_object.h"
|
||||
#include "qdengine/qdcore/qd_minigame_config.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdMiniGameInterface;
|
||||
class qdEmptyMiniGameInterface;
|
||||
|
||||
//! Мини-игра.
|
||||
class qdMiniGame : public qdNamedObject {
|
||||
public:
|
||||
qdMiniGame();
|
||||
qdMiniGame(const qdMiniGame &mg);
|
||||
~qdMiniGame();
|
||||
|
||||
qdMiniGame &operator = (const qdMiniGame &mg);
|
||||
|
||||
int named_object_type() const {
|
||||
return QD_NAMED_OBJECT_MINIGAME;
|
||||
}
|
||||
|
||||
//! Инициализация данных, вызывается при старте и перезапуске основной игры.
|
||||
bool init();
|
||||
|
||||
const Common::Path config_file_name() const {
|
||||
return _config_file_name;
|
||||
}
|
||||
void set_config_file_name(const Common::Path &file_name) {
|
||||
_config_file_name = file_name;
|
||||
}
|
||||
bool has_config_file() const {
|
||||
return !_config_file_name.empty();
|
||||
}
|
||||
|
||||
//! Старт игры, вызывается при заходе на сцену, которой управляет игра.
|
||||
bool start();
|
||||
bool is_started() const;
|
||||
//! Логический квант игры, параметр - время, которое должно пройти в игре (в секундах).
|
||||
bool quant(float dt);
|
||||
//! Окончание игры, вызывается при уходе со сцены, которая управляется игрой.
|
||||
bool end();
|
||||
|
||||
/// Сохранение, вызывается при сохранении сцены \a scene
|
||||
int save_game(char *buffer, int buffer_size, qdGameScene *scene);
|
||||
/// Загрузка, вызывается при загрузке сцены \a scene
|
||||
int load_game(const char *buffer, int buffer_size, qdGameScene *scene);
|
||||
|
||||
//! Возвращает имя подгружаемой для игры dll.
|
||||
const char *dll_name() const {
|
||||
return _dll_name.c_str();
|
||||
}
|
||||
//! Устанавливает имя подгружаемой для игры dll.
|
||||
void set_dll_name(const char *p) {
|
||||
_dll_name = p;
|
||||
}
|
||||
bool has_dll() const {
|
||||
return !_dll_name.empty();
|
||||
}
|
||||
|
||||
const char *game_name() const {
|
||||
return _game_name.c_str();
|
||||
}
|
||||
void set_game_name(const char *p) {
|
||||
_game_name = p;
|
||||
}
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
typedef Std::vector<qdMinigameConfigParameter> config_container_t;
|
||||
|
||||
const config_container_t &config() const {
|
||||
return _config;
|
||||
}
|
||||
void set_config(const config_container_t &cfg) {
|
||||
_config = cfg;
|
||||
}
|
||||
bool load_config();
|
||||
|
||||
/// Возвращает значение параметра с именем cfg_param_name.
|
||||
/**
|
||||
Если параметр с таким именем не найден, то возвращает 0.
|
||||
*/
|
||||
const char *config_parameter_value(const char *cfg_param_name) const;
|
||||
|
||||
private:
|
||||
|
||||
//! Имя подгружаемой для игры dll.
|
||||
Common::String _dll_name;
|
||||
//! .ini файл с настройками игры.
|
||||
Common::Path _config_file_name;
|
||||
//! Имя игры, по которому она ищется в dll.
|
||||
Common::String _game_name;
|
||||
//! Хэндл подгруженной dll.
|
||||
void *_dll_handle;
|
||||
//! Интерфейс к игре из dll.
|
||||
qdMiniGameInterface *_interface;
|
||||
|
||||
//! Настройки игры.
|
||||
config_container_t _config;
|
||||
|
||||
bool load_interface();
|
||||
bool release_interface();
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_MINIGAME_H
|
||||
122
engines/qdengine/qdcore/qd_minigame_config.cpp
Normal file
122
engines/qdengine/qdcore/qd_minigame_config.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 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/str.h"
|
||||
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/qdscr_parser.h"
|
||||
#include "qdengine/parser/xml_tag_buffer.h"
|
||||
#include "qdengine/qdcore/qd_setup.h"
|
||||
#include "qdengine/qdcore/qd_minigame_config.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdMinigameConfigParameter::qdMinigameConfigParameter() : _data_type(PRM_DATA_STRING) {
|
||||
_data_count = 1;
|
||||
_is_data_valid = true;
|
||||
}
|
||||
|
||||
qdMinigameConfigParameter::~qdMinigameConfigParameter() {
|
||||
}
|
||||
|
||||
bool qdMinigameConfigParameter::load_script(const xml::tag *p) {
|
||||
set_data_string(p->data());
|
||||
|
||||
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_COMMENT:
|
||||
// set_comment(it->data());
|
||||
// break;
|
||||
// case QDSCR_TYPE:
|
||||
// set_data_type(data_type_t(xml::tag_buffer(*it).get_int()));
|
||||
// break;
|
||||
case QDSCR_SIZE:
|
||||
set_data_count(xml::tag_buffer(*it).get_int());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdMinigameConfigParameter::save_script(Common::WriteStream &fh, int indent) const {
|
||||
for (int i = 0; i < indent; i++) {
|
||||
fh.writeString("\t");
|
||||
}
|
||||
fh.writeString("<minigame_config_prm");
|
||||
|
||||
fh.writeString(Common::String::format(" name=\"%s\"", qdscr_XML_string(name())));
|
||||
// fh < " type=\"" <= int(_data_type) < "\"";
|
||||
|
||||
// if(!comment_.empty())
|
||||
// fh < " comment=\"" < qdscr_XML_string(comment()) < "\"";
|
||||
|
||||
if (_data_count > 1) {
|
||||
fh.writeString(Common::String::format(" size=\"%d\"", _data_count));
|
||||
}
|
||||
|
||||
fh.writeString(">");
|
||||
|
||||
fh.writeString(qdscr_XML_string(data_string()));
|
||||
|
||||
fh.writeString("</minigame_config_prm>\r\n");
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool qdMinigameConfigParameter::validate_data() {
|
||||
_is_data_valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdMinigameConfigParameter::load_ini(Common::INIFile& ini, const Common::Path &ini_file, const char *ini_section) {
|
||||
set_name(ini_section);
|
||||
Common::String str = getIniKey(ini, ini_file, ini_section, "type");
|
||||
if (!str.empty()) {
|
||||
if (str.equalsIgnoreCase("string"))
|
||||
set_data_type(PRM_DATA_STRING);
|
||||
else if (str.equalsIgnoreCase("file"))
|
||||
set_data_type(PRM_DATA_FILE);
|
||||
else if (str.equalsIgnoreCase("object"))
|
||||
set_data_type(PRM_DATA_OBJECT);
|
||||
}
|
||||
|
||||
str = getIniKey(ini, ini_file, ini_section, "count");
|
||||
if (!str.empty())
|
||||
set_data_count(atoi(str.c_str()));
|
||||
|
||||
str = getIniKey(ini, ini_file, ini_section, "value");
|
||||
if (!str.empty()) {
|
||||
set_data_string(str.c_str());
|
||||
}
|
||||
|
||||
str = getIniKey(ini, ini_file, ini_section, "comment");
|
||||
if (!str.empty())
|
||||
set_comment(str.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
160
engines/qdengine/qdcore/qd_minigame_config.h
Normal file
160
engines/qdengine/qdcore/qd_minigame_config.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_QD_MINIGAME_CONFIG_H
|
||||
#define QDENGINE_QDCORE_QD_MINIGAME_CONFIG_H
|
||||
|
||||
#include "common/formats/ini-file.h"
|
||||
#include "common/path.h"
|
||||
|
||||
namespace QDEngine {
|
||||
/// Конфигурационные данные для миниигры.
|
||||
/**
|
||||
В .ini файле:
|
||||
имя секции - название параметра
|
||||
|
||||
ключи
|
||||
type = "string" / "file" / "object" - тип данных data_type_
|
||||
count - количество данных, data_count_
|
||||
value - строка данных, data_string_
|
||||
comment - комментарий, comment_
|
||||
|
||||
Если тип данных не указан, то считается равным "string".
|
||||
|
||||
Пример:
|
||||
|
||||
[ParameterExample]
|
||||
type = "object"
|
||||
count = 2
|
||||
value = "Object0"
|
||||
comment = "пример параметра"
|
||||
*/
|
||||
class qdMinigameConfigParameter {
|
||||
public:
|
||||
qdMinigameConfigParameter();
|
||||
~qdMinigameConfigParameter();
|
||||
|
||||
bool operator == (const qdMinigameConfigParameter &prm) const {
|
||||
return (_name == prm._name);
|
||||
}
|
||||
bool operator == (const char *str) const {
|
||||
return !strcmp(str, name());
|
||||
}
|
||||
|
||||
//! Тип данных.
|
||||
enum data_type_t {
|
||||
/// данные - строка
|
||||
PRM_DATA_STRING,
|
||||
/// данные - имя файла
|
||||
PRM_DATA_FILE,
|
||||
/// данные - имя объекта из игровой сцены
|
||||
PRM_DATA_OBJECT
|
||||
};
|
||||
|
||||
const char *name() const {
|
||||
return _name.c_str();
|
||||
}
|
||||
void set_name(const char *name) {
|
||||
_name = name;
|
||||
}
|
||||
|
||||
data_type_t data_type() const {
|
||||
return _data_type;
|
||||
}
|
||||
void set_data_type(data_type_t tp) {
|
||||
_data_type = tp;
|
||||
}
|
||||
|
||||
const char *data_string() const {
|
||||
return _data_string.c_str();
|
||||
}
|
||||
void set_data_string(const char *str) {
|
||||
_data_string = str;
|
||||
}
|
||||
|
||||
const char *comment() const {
|
||||
return _comment.c_str();
|
||||
}
|
||||
void set_comment(const char *str) {
|
||||
_comment = str;
|
||||
}
|
||||
|
||||
int data_count() const {
|
||||
return _data_count;
|
||||
}
|
||||
void set_data_count(int cnt) {
|
||||
_data_count = cnt;
|
||||
}
|
||||
|
||||
/// Проверяет валидность данных.
|
||||
/**
|
||||
Если данные не того формата, то возвращает false и устанавливает
|
||||
is_data_valid_ в false.
|
||||
*/
|
||||
bool validate_data();
|
||||
bool is_data_valid() const {
|
||||
return _is_data_valid;
|
||||
}
|
||||
|
||||
//! Загрузка данных из скрипта.
|
||||
bool load_script(const xml::tag *p);
|
||||
//! Запись данных в скрипт.
|
||||
bool save_script(Common::WriteStream &fh, int indent = 0) const;
|
||||
|
||||
//! Загрузка данных из .ini файла.
|
||||
bool load_ini(Common::INIFile& ini, const Common::Path &ini_file, const char *ini_section);
|
||||
|
||||
private:
|
||||
|
||||
/// Имя параметра, данные из миниигры запрашиваются по нему.
|
||||
Common::String _name;
|
||||
|
||||
/// Тип данных.
|
||||
data_type_t _data_type;
|
||||
|
||||
/// Количество данных.
|
||||
/**
|
||||
Используется для числовых данных (указывает, сколько чисел записано в data_string_)
|
||||
и объектов (в сцене создаётся соответствующее количество копий объекта по имени data_string_,
|
||||
к их именам добавляется четырёхзначный порядковый номер).
|
||||
|
||||
По умолчанию = 1.
|
||||
*/
|
||||
int _data_count;
|
||||
|
||||
/// Строка данных.
|
||||
/**
|
||||
Формат зависит от типа данных.
|
||||
Для числовых данных - числа в текстовом виде через пробел, для
|
||||
остальных типов - просто строка.
|
||||
*/
|
||||
Common::String _data_string;
|
||||
|
||||
/// Комментарий.
|
||||
Common::String _comment;
|
||||
|
||||
/// false если строка данных не того формата.
|
||||
bool _is_data_valid;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_QD_MINIGAME_CONFIG_H
|
||||
614
engines/qdengine/qdcore/qd_minigame_interface.cpp
Normal file
614
engines/qdengine/qdcore/qd_minigame_interface.cpp
Normal file
@@ -0,0 +1,614 @@
|
||||
/* 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 "qdengine/qd_fwd.h"
|
||||
#include "qdengine/parser/xml_fwd.h"
|
||||
#include "qdengine/qdcore/qd_minigame.h"
|
||||
#include "qdengine/qdcore/qd_counter.h"
|
||||
#include "qdengine/qdcore/qd_minigame_interface.h"
|
||||
#include "qdengine/qdcore/qd_engine_interface.h"
|
||||
#include "qdengine/qdcore/qd_rnd.h"
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
#include "qdengine/system/input/keyboard_input.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_game_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_game_scene.h"
|
||||
#include "qdengine/qdcore/qd_game_object_mouse.h"
|
||||
#include "qdengine/qdcore/qd_game_object_animated.h"
|
||||
#include "qdengine/qdcore/qd_game_object_moving.h"
|
||||
|
||||
#include "qdengine/qdcore/qd_interface_dispatcher.h"
|
||||
#include "qdengine/qdcore/qd_interface_screen.h"
|
||||
#include "qdengine/qdcore/qd_interface_text_window.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
template<>
|
||||
void mgVect3<float>::write(Common::WriteStream &out) const {
|
||||
out.writeFloatLE(x);
|
||||
out.writeFloatLE(y);
|
||||
out.writeFloatLE(z);
|
||||
}
|
||||
|
||||
template<>
|
||||
void mgVect3<float>::read(Common::ReadStream &in) {
|
||||
x = in.readFloatLE();
|
||||
y = in.readFloatLE();
|
||||
z = in.readFloatLE();
|
||||
}
|
||||
|
||||
namespace qdmg {
|
||||
|
||||
class qdMinigameObjectInterfaceImplBase : public qdMinigameObjectInterface {
|
||||
public:
|
||||
qdMinigameObjectInterfaceImplBase(qdGameObjectAnimated *object) : _object(object) {
|
||||
assert(_object);
|
||||
}
|
||||
|
||||
/// Имя объекта.
|
||||
const char *name() const;
|
||||
|
||||
//! Возвращает true, если у объекта есть состояние с именем state_name.
|
||||
bool has_state(const char *state_name) const;
|
||||
//! Возвращает имя активного в данный момент состояния.
|
||||
//! Вернёт 0, если активного состояния нету.
|
||||
const char *current_state_name() const;
|
||||
//! Возвращает true, если состояние с именем state_name включено в данный момент.
|
||||
bool is_state_active(const char *state_name) const;
|
||||
//! Возвращает true, если состояние с именем state_name в данный момент ожидает активации.
|
||||
bool is_state_waiting_activation(const char *state_name) const;
|
||||
//! Возвращает номер включенного в данный момент состояния.
|
||||
int current_state_index() const;
|
||||
//! Включает состояние с именем state_name.
|
||||
bool set_state(const char *state_name);
|
||||
//! Включает состояние номер state_index (отсчитывается от нуля).
|
||||
bool set_state(int state_index);
|
||||
//! Возвращает номер состояния с именем state_name.
|
||||
/**
|
||||
Отсчитывается от нуля, если такого состояния нет, то
|
||||
возвращает -1.
|
||||
*/
|
||||
int state_index(const char *state_name) const;
|
||||
|
||||
//! Возвращает координаты объекта в мировой системе координат.
|
||||
mgVect3f R() const;
|
||||
//! Устанавливает координаты объекта в мировой системе координат.
|
||||
void set_R(const mgVect3f &r);
|
||||
|
||||
/// Проверка, попадает ли точка с экранными координатами pos в объект
|
||||
bool hit_test(const mgVect2i &pos) const;
|
||||
|
||||
//! Возвращает координаты объекта в экранной системе координат.
|
||||
mgVect2i screen_R() const;
|
||||
//! Обновляет координаты объекта в экранной системе координат.
|
||||
bool update_screen_R();
|
||||
//! Возвращает текущие экранные размеры объекта в пикселах.
|
||||
mgVect2i screen_size() const;
|
||||
|
||||
//! Устанавливает поворот картинки объекта.
|
||||
//! angle - угол, на который должна быть повёрнута картинка, в радианах
|
||||
//! speed - скорость поворота, в радианах в секунду
|
||||
void set_screen_rotation(float angle, float speed);
|
||||
//! Возвращает поворот картинки объекта в радианах.
|
||||
float screen_rotation() const;
|
||||
//! Устанавливает масштабирование картинки объекта.
|
||||
void set_screen_scale(const mgVect2f &scale, const mgVect2f &speed);
|
||||
//! Возвращает масштаб картинки объекта.
|
||||
mgVect2f screen_scale() const;
|
||||
|
||||
//! Возвращает цвет затенения.
|
||||
int shadow_color() const;
|
||||
//! Возвращает прозрачность затенения, значения - [0, 255], если равно -1, то затенения нет.
|
||||
int shadow_alpha() const;
|
||||
//! Устанавливает затенение.
|
||||
bool set_shadow(int shadow_color, int shadow_alpha);
|
||||
|
||||
//! Возвращает true, если объект не спрятан.
|
||||
virtual bool is_visible() const;
|
||||
|
||||
//! Возвращает размеры объекта в мировой системе координат.
|
||||
mgVect3f bound() const;
|
||||
|
||||
private:
|
||||
|
||||
qdGameObjectAnimated *_object;
|
||||
};
|
||||
|
||||
class qdMinigameObjectInterfaceImpl : public qdMinigameObjectInterfaceImplBase {
|
||||
public:
|
||||
qdMinigameObjectInterfaceImpl(qdGameObjectAnimated *object) : qdMinigameObjectInterfaceImplBase(object) { }
|
||||
|
||||
//! Команда персонажу идти к точке target_position.
|
||||
/**
|
||||
Если второй параметр равен false, то если target_position непроходима
|
||||
персонаж идёт к ближайшей от target_position проходимой точке.
|
||||
*/
|
||||
bool move(const mgVect3f &target_position, bool disable_target_change = false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
float direction_angle() const {
|
||||
return 0.f;
|
||||
}
|
||||
bool set_direction_angle(float direction) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//! Интерфейс к персонажу.
|
||||
class qdMinigamePersonageInterfaceImpl : public qdMinigameObjectInterfaceImplBase {
|
||||
public:
|
||||
qdMinigamePersonageInterfaceImpl(qdGameObjectMoving *p);
|
||||
|
||||
//! Команда персонажу идти к точке target_position.
|
||||
/**
|
||||
Если второй параметр равен false, то если target_position непроходима
|
||||
персонаж идёт к ближайшей от target_position проходимой точке.
|
||||
*/
|
||||
bool move(const mgVect3f &target_position, bool disable_target_change = false);
|
||||
|
||||
float direction_angle() const;
|
||||
bool set_direction_angle(float direction);
|
||||
|
||||
private:
|
||||
|
||||
qdGameObjectMoving *_personage_object;
|
||||
};
|
||||
|
||||
//! Интерфейс к сцене.
|
||||
class qdMinigameSceneInterfaceImpl : public qdMinigameSceneInterface {
|
||||
public:
|
||||
qdMinigameSceneInterfaceImpl(qdGameScene *scene);
|
||||
|
||||
/// Имя сцены.
|
||||
const char *name() const;
|
||||
|
||||
//! Создаёт интерфейс к объекту с именем object_name.
|
||||
qdMinigameObjectInterface *object_interface(const char *object_name, bool test = false);
|
||||
//! Создаёт интерфейс к персонажу с именем personage_name.
|
||||
qdMinigameObjectInterface *personage_interface(const char *personage_name);
|
||||
//! Активация персонажа с именем personage_name.
|
||||
bool activate_personage(const char *personage_name);
|
||||
|
||||
//! Преобразование из экранных координат в мировые.
|
||||
mgVect3f screen2world_coords(const mgVect2i &screen_pos, float screen_depth = 0) const;
|
||||
//! Преобразование из мировых координат в экранные.
|
||||
mgVect2i world2screen_coords(const mgVect3f &world_pos) const;
|
||||
//! Возвращает "глубину" точки с координатами pos в мировой системе координат.
|
||||
float screen_depth(const mgVect3f &pos) const;
|
||||
//! Возвращает мировые координаты точки на сетке по её экранным координатам.
|
||||
mgVect3f screen2grid_coords(const mgVect2i &screen_pos) const;
|
||||
|
||||
//! Создаёт интерфейс к объекту, который взят мышью в данный момент.
|
||||
qdMinigameObjectInterface *mouse_object_interface() const;
|
||||
//! Создаёт интерфейс к объекту, по которому кликнули мышью.
|
||||
qdMinigameObjectInterface *mouse_click_object_interface() const;
|
||||
//! Создаёт интерфейс к объекту, по которому кликнули правой кнопкой мыши.
|
||||
qdMinigameObjectInterface *mouse_right_click_object_interface() const;
|
||||
//! Создаёт интерфейс к объекту, над которым находится мышиный курсор.
|
||||
qdMinigameObjectInterface *mouse_hover_object_interface() const;
|
||||
|
||||
const char *minigame_parameter(const char *parameter_name) const;
|
||||
|
||||
void release_object_interface(qdMinigameObjectInterface *p) const;
|
||||
|
||||
private:
|
||||
|
||||
qdGameScene *_scene;
|
||||
};
|
||||
|
||||
/// Интерфейс к счётчику.
|
||||
class qdMinigameCounterInterfaceImpl : public qdMinigameCounterInterface {
|
||||
public:
|
||||
qdMinigameCounterInterfaceImpl(qdCounter *counter) : _counter(counter) {
|
||||
assert(_counter);
|
||||
}
|
||||
|
||||
/// возвращает текущее значение счётчика
|
||||
int value() const;
|
||||
/// устанавливает текущее значение счётчика
|
||||
void set_value(int value);
|
||||
/// добавляет к текущему значению счётчика value_delta
|
||||
void add_value(int value_delta);
|
||||
private:
|
||||
|
||||
qdCounter *_counter;
|
||||
};
|
||||
|
||||
} // namespace qdmg
|
||||
|
||||
/* ----------------------------- EXTERN SECTION ----------------------------- */
|
||||
/* --------------------------- PROTOTYPE SECTION ---------------------------- */
|
||||
/* --------------------------- DEFINITION SECTION --------------------------- */
|
||||
|
||||
namespace qdmg {
|
||||
|
||||
qdMinigameSceneInterfaceImpl::qdMinigameSceneInterfaceImpl(qdGameScene *scene) : _scene(scene) {
|
||||
assert(_scene);
|
||||
}
|
||||
|
||||
const char *qdMinigameSceneInterfaceImpl::minigame_parameter(const char *parameter_name) const {
|
||||
if (const qdMiniGame * p = _scene->minigame())
|
||||
return p->config_parameter_value(parameter_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qdMinigameObjectInterface *qdMinigameSceneInterfaceImpl::mouse_object_interface() const {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
if (dp->mouse_object()->object())
|
||||
return new qdMinigameObjectInterfaceImpl(dp->mouse_object()->object());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qdMinigameObjectInterface *qdMinigameSceneInterfaceImpl::mouse_click_object_interface() const {
|
||||
if (qdNamedObject * p = _scene->mouse_click_object()) {
|
||||
if (qdGameObjectAnimated * obj = dynamic_cast<qdGameObjectAnimated * >(p))
|
||||
return new qdMinigameObjectInterfaceImpl(obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdMinigameObjectInterface *qdMinigameSceneInterfaceImpl::mouse_right_click_object_interface() const {
|
||||
if (qdNamedObject * p = _scene->mouse_right_click_object()) {
|
||||
if (qdGameObjectAnimated * obj = dynamic_cast<qdGameObjectAnimated * >(p))
|
||||
return new qdMinigameObjectInterfaceImpl(obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
qdMinigameObjectInterface *qdMinigameSceneInterfaceImpl::mouse_hover_object_interface() const {
|
||||
if (qdNamedObject * p = _scene->mouse_hover_object()) {
|
||||
if (qdGameObjectAnimated * obj = dynamic_cast<qdGameObjectAnimated * >(p))
|
||||
return new qdMinigameObjectInterfaceImpl(obj);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
mgVect3f qdMinigameSceneInterfaceImpl::screen2world_coords(const mgVect2i &screen_pos, float screen_depth) const {
|
||||
const qdCamera *cp = _scene->get_camera();
|
||||
Vect3f pos = cp->rscr2global(cp->scr2rscr(Vect2s(screen_pos.x, screen_pos.y)), screen_depth);
|
||||
|
||||
return mgVect3f(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
mgVect2i qdMinigameSceneInterfaceImpl::world2screen_coords(const mgVect3f &world_pos) const {
|
||||
const qdCamera *cp = _scene->get_camera();
|
||||
Vect3f v = cp->global2camera_coord(Vect3f(world_pos.x, world_pos.y, world_pos.z));
|
||||
Vect2i screen_pos = cp->camera_coord2scr(v);
|
||||
|
||||
return mgVect2i(screen_pos.x, screen_pos.y);
|
||||
}
|
||||
|
||||
float qdMinigameSceneInterfaceImpl::screen_depth(const mgVect3f &pos) const {
|
||||
const qdCamera *cp = _scene->get_camera();
|
||||
Vect3f v = cp->global2camera_coord(Vect3f(pos.x, pos.y, pos.z));
|
||||
|
||||
return v.z;
|
||||
}
|
||||
|
||||
mgVect3f qdMinigameSceneInterfaceImpl::screen2grid_coords(const mgVect2i &screen_pos) const {
|
||||
const qdCamera *cp = _scene->get_camera();
|
||||
Vect3f pos = cp->scr2plane(Vect2s(screen_pos.x, screen_pos.y));
|
||||
|
||||
return mgVect3f(pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
void qdMinigameSceneInterfaceImpl::release_object_interface(qdMinigameObjectInterface *p) const {
|
||||
delete p;
|
||||
}
|
||||
|
||||
const char *qdMinigameSceneInterfaceImpl::name() const {
|
||||
return _scene->name();
|
||||
}
|
||||
|
||||
qdMinigameObjectInterface *qdMinigameSceneInterfaceImpl::object_interface(const char *object_name, bool test) {
|
||||
if (qdGameObjectAnimated * p = dynamic_cast<qdGameObjectAnimated * >(_scene->get_object(object_name)))
|
||||
return new qdMinigameObjectInterfaceImpl(p);
|
||||
|
||||
if (!test)
|
||||
warning("object_interface(): Unknown object '%s'", transCyrillic(object_name));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qdMinigameObjectInterface *qdMinigameSceneInterfaceImpl::personage_interface(const char *personage_name) {
|
||||
if (qdGameObjectMoving * p = dynamic_cast<qdGameObjectMoving * >(_scene->get_object(personage_name)))
|
||||
return new qdMinigamePersonageInterfaceImpl(p);
|
||||
|
||||
warning("personage_interface(): Unknown personage '%s'", transCyrillic(personage_name));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool qdMinigameSceneInterfaceImpl::activate_personage(const char *personage_name) {
|
||||
if (qdGameObjectMoving * p = dynamic_cast<qdGameObjectMoving * >(_scene->get_object(personage_name))) {
|
||||
_scene->set_active_personage(p);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
qdMinigamePersonageInterfaceImpl::qdMinigamePersonageInterfaceImpl(qdGameObjectMoving *object) : qdMinigameObjectInterfaceImplBase(object), _personage_object(object) {
|
||||
assert(_personage_object);
|
||||
}
|
||||
|
||||
bool qdMinigamePersonageInterfaceImpl::move(const mgVect3f &target_position, bool disable_target_change) {
|
||||
if (_personage_object) {
|
||||
Vect3f target(target_position.x, target_position.y, target_position.z);
|
||||
return _personage_object->move(target, disable_target_change);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
float qdMinigamePersonageInterfaceImpl::direction_angle() const {
|
||||
if (_personage_object)
|
||||
return _personage_object->direction_angle();
|
||||
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
bool qdMinigamePersonageInterfaceImpl::set_direction_angle(float direction) {
|
||||
if (_personage_object)
|
||||
return _personage_object->set_direction(direction);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
mgVect3f qdMinigameObjectInterfaceImplBase::bound() const {
|
||||
if (_object) {
|
||||
Vect3f b = _object->bound();
|
||||
return mgVect3f(b.x, b.y, b.z);
|
||||
}
|
||||
|
||||
return mgVect3f(0, 0, 0);
|
||||
}
|
||||
|
||||
const char *qdMinigameObjectInterfaceImplBase::name() const {
|
||||
if (_object)
|
||||
return _object->name();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::has_state(const char *state_name) const {
|
||||
if (_object && _object->get_state(state_name))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *qdMinigameObjectInterfaceImplBase::current_state_name() const {
|
||||
if (_object) {
|
||||
if (const qdGameObjectState * p = _object->get_cur_state())
|
||||
return p->name();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::is_state_active(const char *state_name) const {
|
||||
if (!has_state(state_name))
|
||||
warning("is_state_active(): Unknown state '%s'", transCyrillic(state_name));
|
||||
|
||||
return _object->is_state_active(state_name);
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::is_state_waiting_activation(const char *state_name) const {
|
||||
return _object->is_state_waiting(state_name);
|
||||
}
|
||||
|
||||
int qdMinigameObjectInterfaceImplBase::current_state_index() const {
|
||||
return _object->cur_state();
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::set_state(const char *state_name) {
|
||||
int idx = state_index(state_name);
|
||||
if (idx != -1) {
|
||||
_object->set_state(idx);
|
||||
return true;
|
||||
}
|
||||
|
||||
warning("set_state(): Unknown state '%s'", transCyrillic(state_name));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::set_state(int state_index) {
|
||||
_object->set_state(state_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
int qdMinigameObjectInterfaceImplBase::state_index(const char *state_name) const {
|
||||
if (const qdGameObjectState * p = _object->get_state(state_name))
|
||||
return _object->get_state_index(p);
|
||||
|
||||
warning("state_index(): Unknown state '%s'", transCyrillic(state_name));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
mgVect3f qdMinigameObjectInterfaceImplBase::R() const {
|
||||
Vect3f r = _object->R();
|
||||
return mgVect3f(r.x, r.y, r.z);
|
||||
}
|
||||
|
||||
void qdMinigameObjectInterfaceImplBase::set_R(const mgVect3f &r) {
|
||||
Vect3f rr(r.x, r.y, r.z);
|
||||
_object->set_pos(rr);
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::hit_test(const mgVect2i &pos) const {
|
||||
return _object->hit(pos.x, pos.y);
|
||||
}
|
||||
|
||||
mgVect2i qdMinigameObjectInterfaceImplBase::screen_R() const {
|
||||
return mgVect2i(_object->screen_pos().x, _object->screen_pos().y);
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::update_screen_R() {
|
||||
_object->update_screen_pos();
|
||||
return true;
|
||||
}
|
||||
|
||||
mgVect2i qdMinigameObjectInterfaceImplBase::screen_size() const {
|
||||
Vect2s sz = _object->screen_size();
|
||||
return mgVect2i(sz.x, sz.y);
|
||||
}
|
||||
|
||||
void qdMinigameObjectInterfaceImplBase::set_screen_rotation(float angle, float speed) {
|
||||
_object->set_screen_rotation(angle, speed);
|
||||
}
|
||||
|
||||
float qdMinigameObjectInterfaceImplBase::screen_rotation() const {
|
||||
return _object->screen_rotation();
|
||||
}
|
||||
|
||||
void qdMinigameObjectInterfaceImplBase::set_screen_scale(const mgVect2f &scale, const mgVect2f &speed) {
|
||||
_object->set_screen_scale(Vect2f(scale.x, scale.y), Vect2f(speed.x, speed.y));
|
||||
}
|
||||
|
||||
mgVect2f qdMinigameObjectInterfaceImplBase::screen_scale() const {
|
||||
return mgVect2f(_object->screen_scale().x, _object->screen_scale().y);
|
||||
}
|
||||
|
||||
int qdMinigameObjectInterfaceImplBase::shadow_color() const {
|
||||
return _object->shadow_color();
|
||||
}
|
||||
|
||||
int qdMinigameObjectInterfaceImplBase::shadow_alpha() const {
|
||||
return _object->shadow_alpha();
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::set_shadow(int shadow_color, int shadow_alpha) {
|
||||
_object->set_shadow(shadow_color, shadow_alpha);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qdMinigameObjectInterfaceImplBase::is_visible() const {
|
||||
return _object->is_visible();
|
||||
}
|
||||
|
||||
qdEngineInterfaceImpl *g_qdi = nullptr;
|
||||
|
||||
const qdEngineInterfaceImpl &qdEngineInterfaceImpl::instance() {
|
||||
if (!g_qdi)
|
||||
g_qdi = new qdEngineInterfaceImpl;
|
||||
|
||||
return *g_qdi;
|
||||
}
|
||||
|
||||
qdMinigameSceneInterface *qdEngineInterfaceImpl::current_scene_interface() const {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher())
|
||||
return new qdMinigameSceneInterfaceImpl(dp->get_active_scene());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qdMinigameSceneInterface *qdEngineInterfaceImpl::scene_interface(qdGameScene *scene) const {
|
||||
return new qdMinigameSceneInterfaceImpl(scene);
|
||||
}
|
||||
|
||||
mgVect2i qdEngineInterfaceImpl::screen_size() const {
|
||||
if (grDispatcher * dp = grDispatcher::instance())
|
||||
return mgVect2i(dp->get_SizeX(), dp->get_SizeY());
|
||||
|
||||
return mgVect2i(0, 0);
|
||||
}
|
||||
|
||||
void qdEngineInterfaceImpl::release_scene_interface(qdMinigameSceneInterface *p) const {
|
||||
delete p;
|
||||
}
|
||||
|
||||
qdMinigameCounterInterface *qdEngineInterfaceImpl::counter_interface(const char *counter_name) const {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher())
|
||||
return new qdMinigameCounterInterfaceImpl(dp->get_counter(counter_name));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qdEngineInterfaceImpl::release_counter_interface(qdMinigameCounterInterface *p) const {
|
||||
delete p;
|
||||
}
|
||||
|
||||
bool qdEngineInterfaceImpl::is_key_pressed(int vkey) const {
|
||||
return keyboardDispatcher::instance()->is_pressed(vkey);
|
||||
}
|
||||
|
||||
bool qdEngineInterfaceImpl::is_mouse_event_active(qdMinigameMouseEvent event_id) const {
|
||||
return mouseDispatcher::instance()->is_event_active(mouseDispatcher::mouseEvent(event_id));
|
||||
}
|
||||
|
||||
mgVect2i qdEngineInterfaceImpl::mouse_cursor_position() const {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher()) {
|
||||
Vect2f pos = dp->mouse_cursor_pos();
|
||||
return mgVect2i(pos.x, pos.y);
|
||||
}
|
||||
|
||||
return mgVect2i(0, 0);
|
||||
}
|
||||
|
||||
bool qdEngineInterfaceImpl::add_hall_of_fame_entry(int score) const {
|
||||
if (qdGameDispatcher * dp = qdGameDispatcher::get_dispatcher())
|
||||
return dp->add_hall_of_fame_entry(score);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool qdEngineInterfaceImpl::set_interface_text(const char *screen_name, const char *control_name, const char *text) const {
|
||||
if (qdInterfaceDispatcher * dp = qdInterfaceDispatcher::get_dispatcher()) {
|
||||
qdInterfaceScreen *scr = screen_name ? dp->get_screen(screen_name) : dp->selected_screen();
|
||||
|
||||
if (scr) {
|
||||
qdInterfaceElement *el = scr->get_element(control_name);
|
||||
if (el && el->get_element_type() == qdInterfaceElement::EL_TEXT_WINDOW) {
|
||||
static_cast<qdInterfaceTextWindow *>(el)->set_input_string(text);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int qdMinigameCounterInterfaceImpl::value() const {
|
||||
if (_counter)
|
||||
return _counter->value();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qdMinigameCounterInterfaceImpl::set_value(int value) {
|
||||
if (_counter)
|
||||
_counter->set_value(value);
|
||||
}
|
||||
|
||||
void qdMinigameCounterInterfaceImpl::add_value(int value_delta) {
|
||||
if (_counter)
|
||||
_counter->add_value(value_delta);
|
||||
}
|
||||
|
||||
} // namespace qdmg
|
||||
} // namespace QDEngine
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user