382 lines
9.5 KiB
C++
382 lines
9.5 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/debug.h"
|
|
|
|
#include "qdengine/qdengine.h"
|
|
#include "qdengine/minigames/adv/common.h"
|
|
#include "qdengine/minigames/adv/TextManager.h"
|
|
#include "qdengine/minigames/adv/RunTime.h"
|
|
#include "qdengine/minigames/adv/qdMath.h"
|
|
|
|
namespace QDEngine {
|
|
|
|
TextManager::TextManager(MinigameManager *runtime) {
|
|
char str_cache[256];
|
|
|
|
_runtime = runtime;
|
|
|
|
for (int idx = 0;; ++idx) {
|
|
snprintf(str_cache, 127, "register_font_%d", idx);
|
|
if (const char *descr = _runtime->parameter(str_cache, false)) {
|
|
sscanf(descr, "%255s", str_cache);
|
|
Font digit;
|
|
if (!digit.pool.load(str_cache, _runtime))
|
|
break;
|
|
|
|
debugCN(2, kDebugMinigames, "TextManager(): %d character set \"%s\" loaded, ", idx, str_cache);
|
|
|
|
snprintf(str_cache, 127, "font_size_%d", idx);
|
|
if ((descr = _runtime->parameter(str_cache, false))) {
|
|
int read = sscanf(descr, "%f %f", &digit.size.x, &digit.size.y);
|
|
if (read != 2)
|
|
warning("TextManager(): incorrect font size definition in [%s]", str_cache);
|
|
} else {
|
|
QDObject obj = digit.pool.getObject();
|
|
obj.setState("0");
|
|
digit.size = _runtime->getSize(obj);
|
|
digit.pool.releaseObject(obj, _runtime);
|
|
}
|
|
debugC(2, kDebugMinigames, "set size to (%5.1f, %5.1f)\n", digit.size.x, digit.size.y);
|
|
_fonts.push_back(digit);
|
|
} else
|
|
break;
|
|
}
|
|
|
|
for (int idx = 0;; ++idx) {
|
|
snprintf(str_cache, 127, "register_particle_escape_%d", idx);
|
|
if (const char *descr = _runtime->parameter(str_cache, false)) {
|
|
Escape escape;
|
|
int read = sscanf(descr, "%d (%f><%f, %f><%f) (%f><%f, %f><%f) %f '%15s",
|
|
&escape.depth,
|
|
&escape.vel_min.x, &escape.vel_max.x, &escape.vel_min.y, &escape.vel_max.y,
|
|
&escape.accel_min.x, &escape.accel_max.x, &escape.accel_min.y, &escape.accel_max.y,
|
|
&escape.aliveTime, escape.format);
|
|
|
|
if (read != 11) {
|
|
warning("TextManager(): incorrect particle definition in [%s]", str_cache);
|
|
break;
|
|
}
|
|
_escapes.push_back(escape);
|
|
} else
|
|
break;
|
|
}
|
|
debugCN(2, kDebugMinigames, "TextManager(): registered %d particle escapes", _escapes.size());
|
|
|
|
if (getStaticPreset(_show_scores, "show_scores"))
|
|
_show_scores.textID = createStaticText(_show_scores.pos, _show_scores.font, _show_scores.align);
|
|
else
|
|
_show_scores.textID = -1;
|
|
|
|
if (getStaticPreset(_show_time, "show_time"))
|
|
_show_time.textID = createStaticText(_show_time.pos, _show_time.font, _show_time.align);
|
|
else
|
|
_show_time.textID = -1;
|
|
|
|
_targetScore = 0;
|
|
_currentScore = 0;
|
|
_scoreUpdateTimer = 0.f;
|
|
|
|
_scoreUpdateTime = _runtime->getParameter("score_update_time", 0.1f);
|
|
}
|
|
|
|
bool TextManager::getStaticPreset(StaticTextPreset& preset, const char *name) const {
|
|
if (const char *descr = _runtime->parameter(name, false)) {
|
|
int align = 0;
|
|
char str[64];
|
|
str[63] = 0;
|
|
int read = sscanf(descr, "%d %d |%63s", &align, &preset.font, str);
|
|
|
|
if (read != 3) {
|
|
warning("TextManager::getStaticPreset(): Incorrect text format description in %s", transCyrillic(name));
|
|
return false;
|
|
}
|
|
|
|
char *pos_obj = strchr(str, '|');
|
|
|
|
if (!pos_obj) {
|
|
warning("TextManager::getStaticPreset(): Incorrect text format description (2) in %s", transCyrillic(name));
|
|
return false;
|
|
}
|
|
|
|
*pos_obj = 0;
|
|
++pos_obj;
|
|
|
|
strncpy(preset.format, str, 15);
|
|
|
|
switch (align) {
|
|
case 0:
|
|
preset.align = ALIGN_RIGHT;
|
|
break;
|
|
case 1:
|
|
preset.align = ALIGN_LEFT;
|
|
break;
|
|
default:
|
|
preset.align = ALIGN_CENTER;
|
|
break;
|
|
}
|
|
|
|
if (QDObject obj = _runtime->getObject(pos_obj)) {
|
|
preset.pos = _runtime->world2game(obj);
|
|
_runtime->release(obj);
|
|
} else
|
|
return false;
|
|
} else
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
TextManager::~TextManager() {
|
|
for (auto &mit : _flowMsgs)
|
|
mit.release();
|
|
|
|
for (auto &sit : _staticMsgs)
|
|
sit.release();
|
|
|
|
for (auto &dit : _fonts)
|
|
dit.pool.release(_runtime);
|
|
}
|
|
|
|
int TextManager::createStaticText(const mgVect3f& pos, int fontID, TextAlign align) {
|
|
assert(fontID >= 0 && fontID < (int)_fonts.size());
|
|
|
|
StaticMessage msg(_runtime, &_fonts[fontID]);
|
|
|
|
msg._align = align;
|
|
msg._depth = pos.z;
|
|
msg._pos = mgVect2f(pos.x, pos.y);
|
|
|
|
_staticMsgs.push_back(msg);
|
|
return (int)_staticMsgs.size() - 1;
|
|
}
|
|
|
|
void TextManager::updateStaticText(int textID, const char *txt) {
|
|
assert(textID >= 0 && textID < (int)_staticMsgs.size());
|
|
|
|
_staticMsgs[textID].setText(txt);
|
|
}
|
|
|
|
void TextManager::showText(const char *txt, const mgVect2f& pos, int fontID, int escapeID) {
|
|
assert(fontID >= 0 && fontID < (int)_fonts.size());
|
|
assert(escapeID >= 0 && escapeID < (int)_escapes.size());
|
|
|
|
Escape& es = _escapes[escapeID];
|
|
|
|
Message msg(_runtime, &_fonts[fontID]);
|
|
|
|
msg.setText(txt);
|
|
if (msg.empty())
|
|
return;
|
|
|
|
msg._time = es.aliveTime > 0 ? es.aliveTime : 1.e6f;
|
|
|
|
msg._depth = es.depth;
|
|
msg._pos = pos;
|
|
|
|
msg._vel.x = _runtime->rnd(es.vel_min.x, es.vel_max.x);
|
|
msg._vel.y = _runtime->rnd(es.vel_min.y, es.vel_max.y);
|
|
msg._accel.x = _runtime->rnd(es.accel_min.x, es.accel_max.x);
|
|
msg._accel.y = _runtime->rnd(es.accel_min.y, es.accel_max.y);
|
|
|
|
_flowMsgs.push_back(msg);
|
|
}
|
|
|
|
void TextManager::showNumber(int num, const mgVect2f& pos, int fontID, int escapeID) {
|
|
assert(fontID >= 0 && fontID < (int)_fonts.size());
|
|
assert(escapeID >= 0 && escapeID < (int)_escapes.size());
|
|
|
|
char buf[16];
|
|
buf[15] = 0;
|
|
snprintf(buf, 15, _escapes[escapeID].format, num);
|
|
|
|
showText(buf, pos, fontID, escapeID);
|
|
}
|
|
|
|
TextManager::Escape::Escape() {
|
|
depth = 0;
|
|
aliveTime = -1;
|
|
format[15] = 0;
|
|
}
|
|
|
|
TextManager::StaticTextPreset::StaticTextPreset() {
|
|
font = -1;
|
|
align = ALIGN_CENTER;
|
|
format[15] = 0;
|
|
textID = 0;
|
|
}
|
|
|
|
TextManager::StaticMessage::StaticMessage(MinigameManager *runtime, Font *font, TextAlign align) {
|
|
_font = font;
|
|
_align = align;
|
|
_depth = 0.f;
|
|
_runtime = runtime;
|
|
}
|
|
|
|
void TextManager::StaticMessage::release() {
|
|
for (auto &it : _objects)
|
|
_font->pool.releaseObject(it, _runtime);
|
|
|
|
_objects.clear();
|
|
}
|
|
|
|
void TextManager::StaticMessage::setText(const char *str) {
|
|
assert(_font);
|
|
|
|
if (!str) {
|
|
release();
|
|
return;
|
|
}
|
|
|
|
int len = (int)strlen(str);
|
|
|
|
if ((int)_objects.size() < len)
|
|
_objects.resize(len);
|
|
else
|
|
while ((int)_objects.size() > len) {
|
|
if (_objects.back())
|
|
_font->pool.releaseObject(_objects.back(), _runtime);
|
|
_objects.pop_back();
|
|
}
|
|
|
|
for (int idx = 0; idx < len; ++idx) {
|
|
if (validSymbol(str[idx])) {
|
|
if (!_objects[idx])
|
|
_objects[idx] = _font->pool.getObject();
|
|
} else if (_objects[idx])
|
|
_font->pool.releaseObject(_objects[idx], _runtime);
|
|
}
|
|
|
|
char name[2];
|
|
name[1] = 0;
|
|
for (int idx = 0; idx < len; ++idx) {
|
|
if (_objects[idx]) {
|
|
name[0] = str[idx];
|
|
_objects[idx].setState(name);
|
|
}
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
void TextManager::StaticMessage::update() {
|
|
if (_objects.empty())
|
|
return;
|
|
|
|
float width = _font->size.x * (_objects.size() - 1);
|
|
float x = _pos.x;
|
|
float y = _pos.y;
|
|
switch (_align) {
|
|
case ALIGN_RIGHT:
|
|
x -= width;
|
|
break;
|
|
case ALIGN_CENTER:
|
|
x -= width / 2.f;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (y < -_font->size.y || y > _runtime->screenSize().y + _font->size.y
|
|
|| x < -2 * width || x > _runtime->screenSize().x + 2 * width) {
|
|
release();
|
|
return;
|
|
}
|
|
|
|
for (auto &it : _objects) {
|
|
if (it)
|
|
it->set_R(_runtime->game2world(mgVect2f(x, y), _depth));
|
|
x += _font->size.x;
|
|
}
|
|
}
|
|
|
|
TextManager::Message::Message(MinigameManager *runtime, Font *font)
|
|
: StaticMessage(runtime, font) {
|
|
_time = 0.f;
|
|
}
|
|
|
|
void TextManager::Message::release() {
|
|
StaticMessage::release();
|
|
_time = 0.f;
|
|
}
|
|
|
|
void TextManager::Message::quant(float dt) {
|
|
if (empty())
|
|
return;
|
|
|
|
_time -= dt;
|
|
if (_time < 0.f) {
|
|
release();
|
|
return;
|
|
}
|
|
|
|
_vel += _accel * dt;
|
|
_pos += _vel * dt;
|
|
|
|
update();
|
|
}
|
|
|
|
void TextManager::quant(float dt) {
|
|
Messages::iterator it = _flowMsgs.begin();
|
|
while (it != _flowMsgs.end()) {
|
|
it->quant(dt);
|
|
if (it->empty())
|
|
it = _flowMsgs.erase(it);
|
|
else
|
|
++it;
|
|
}
|
|
|
|
if (_show_scores.textID >= 0) {
|
|
if (_scoreUpdateTimer >= 0.f && _scoreUpdateTimer <= _runtime->getTime()) {
|
|
int sgn = _targetScore - _currentScore < 0 ? -1 : 1;
|
|
int mod = abs(_currentScore - _targetScore);
|
|
_currentScore += sgn * (mod / 10 + 1);
|
|
|
|
char buf[16];
|
|
buf[15] = 0;
|
|
snprintf(buf, 15, _show_scores.format, _currentScore);
|
|
updateStaticText(_show_scores.textID, buf);
|
|
|
|
_scoreUpdateTimer = _currentScore != _targetScore ? _runtime->getTime() + _scoreUpdateTime : -1.f;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TextManager::updateScore(int score) {
|
|
_targetScore = score;
|
|
if (_scoreUpdateTimer < 0.f)
|
|
_scoreUpdateTimer = _runtime->getTime();
|
|
}
|
|
|
|
void TextManager::updateTime(int seconds) {
|
|
if (_show_time.textID >= 0) {
|
|
char buf[16];
|
|
buf[15] = 0;
|
|
int h = seconds / 3600;
|
|
seconds -= 3600 * h;
|
|
int minutes = seconds / 60;
|
|
seconds -= 60 * minutes;
|
|
snprintf(buf, 15, _show_time.format, h, minutes, seconds);
|
|
updateStaticText(_show_time.textID, buf);
|
|
}
|
|
}
|
|
|
|
} // namespace QDEngine
|