aboutsummaryrefslogtreecommitdiff
path: root/engines/teenagent/scene.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/teenagent/scene.cpp')
-rw-r--r--engines/teenagent/scene.cpp511
1 files changed, 511 insertions, 0 deletions
diff --git a/engines/teenagent/scene.cpp b/engines/teenagent/scene.cpp
new file mode 100644
index 0000000000..8e39008e8e
--- /dev/null
+++ b/engines/teenagent/scene.cpp
@@ -0,0 +1,511 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL: https://www.switchlink.se/svn/teen/scene.cpp $
+ * $Id: scene.cpp 303 2009-09-03 20:09:57Z megath $
+ */
+
+
+#include "scene.h"
+#include "resources.h"
+#include "surface.h"
+#include "common/debug.h"
+#include "objects.h"
+#include "teenagent.h"
+#include "dialog.h"
+#include "music.h"
+
+using namespace TeenAgent;
+
+Scene::Scene() : _engine(NULL),
+ _system(NULL),
+ _id(0), ons(0), walkboxes(0),
+ orientation(Object::ActorRight),
+ current_event(SceneEvent::None),
+ sound_id(0), sound_delay(0) {}
+
+void Scene::warp(const Common::Point & _point, byte o) {
+ Common::Point point(_point);
+ destination = position = position0 = point;
+ progress = 0; progress_total = 1;
+ if (o)
+ orientation = o;
+}
+
+void Scene::moveTo(const Common::Point & _point, byte orient, bool validate) {
+ Common::Point point(_point);
+ debug(0, "moveTo(%d, %d, %u)", point.x, point.y, orient);
+ if (validate) {
+ for(byte i = 0; i < walkboxes; ++i) {
+ if (walkbox[i]->rect.in(point)) {
+ debug(0, "bumped into walkbox %u", i);
+ return;
+ }
+ }
+ }
+ if (point == position) {
+ if (orient != 0)
+ orientation = orient;
+ nextEvent();
+ return;
+ }
+ destination = point;
+ orientation = orient;
+ position0 = position;
+ progress_total = 1 + sqrt((float)position.sqrDist(destination)) / 10;
+ progress = 0;
+}
+
+
+void Scene::init(TeenAgentEngine *engine, OSystem * system) {
+ _engine = engine;
+ _system = system;
+
+ Resources * res = Resources::instance();
+ Common::SeekableReadStream * s = res->varia.getStream(1);
+ if (s == NULL)
+ error("invalid resource data");
+
+ teenagent.load(s, Animation::TypeVaria);
+
+ s = res->varia.getStream(2);
+ if (s == NULL)
+ error("invalid resource data");
+
+ teenagent_idle.load(s, Animation::TypeVaria);
+}
+
+byte *Scene::getOns(int id) {
+ Resources * res = Resources::instance();
+ return res->dseg.ptr(res->dseg.get_word(0xb4f5 + (id - 1) * 2));
+}
+
+byte * Scene::getLans(int id) {
+ Resources * res = Resources::instance();
+ return res->dseg.ptr(0xd89e + (id - 1) * 4);
+}
+
+void Scene::loadOns() {
+ debug(0, "loading ons animation");
+ Resources * res = Resources::instance();
+
+ uint16 addr = res->dseg.get_word(0xb4f5 + (_id - 1) * 2);
+ //debug(0, "ons index: %04x", addr);
+
+ ons_count = 0;
+ byte b;
+ byte on_id[16];
+ while((b = res->dseg.get_byte(addr)) != 0xff) {
+ debug(0, "on: %04x = %02x", addr, b);
+ ++addr;
+ if (b == 0)
+ continue;
+
+ on_id[ons_count++] = b;
+ }
+
+ delete[] ons;
+ ons = NULL;
+
+ if (ons_count > 0) {
+ ons = new Surface[ons_count];
+ for(uint32 i = 0; i < ons_count; ++i) {
+ Common::SeekableReadStream * s = res->ons.getStream(on_id[i]);
+ if (s != NULL)
+ ons[i].load(s, Surface::TypeOns);
+ }
+ }
+}
+
+void Scene::loadLans() {
+ debug(0, "loading lans animation");
+ Resources * res = Resources::instance();
+ //load lan000
+ byte * table_27 = res->dseg.ptr(0x32C7);
+ memset(table_27, 0, 27 * 4);
+
+ for (int i = 0; i < 4; ++i) {
+ animations[i].free();
+
+ uint16 bx = 0xd89e + (_id - 1) * 4 + i;
+ byte bxv = res->dseg.get_byte(bx);
+ debug(0, "lan: [%04x] = %02x", bx, bxv);
+ if (bxv == 0)
+ continue;
+
+ Common::SeekableReadStream * s = res->loadLan000(4 * (_id - 1) + i + 1);
+ if (s != NULL) {
+ animations[i].load(s, Animation::TypeLan);
+ if (bxv != 0 && bxv != 0xff)
+ animations[i].id = bxv;
+ delete s;
+ }
+
+ //uint16 bp = res->dseg.get_word();
+ }
+
+}
+
+void Scene::init(int id, const Common::Point &pos) {
+ debug(0, "init(%d)", id);
+ _id = id;
+
+ if (background.pixels == NULL)
+ background.create(320, 200, 1);
+
+ warp(pos);
+
+ Resources * res = Resources::instance();
+ res->loadOff(background, palette, id);
+ if (id == 24) {
+ //dark scene
+ if (res->dseg.get_byte(0xDBA4) != 1) {
+ //dim down palette
+ uint i;
+ for(i = 0; i < 624; ++i) {
+ palette[i] = palette[i] > 0x20? palette[i] - 0x20: 0;
+ }
+ for(i = 726; i < 768; ++i) {
+ palette[i] = palette[i] > 0x20? palette[i] - 0x20: 0;
+ }
+ }
+ }
+ setPalette(_system, palette, 4);
+
+ Common::SeekableReadStream *stream = res->on.getStream(id);
+ on.load(stream, Surface::TypeOn);
+ delete stream;
+
+ loadOns();
+ loadLans();
+
+ byte * walkboxes_base = res->dseg.ptr(READ_LE_UINT16(res->dseg.ptr(0x6746 + (id - 1) * 2)));
+ walkboxes = *walkboxes_base++;
+
+ debug(0, "found %d walkboxes", walkboxes);
+ for (byte i = 0; i < walkboxes; ++i) {
+ walkbox[i] = (Walkbox *)(walkboxes_base + 14 * i);
+ walkbox[i]->dump();
+ }
+
+ if (id == 23 && res->dseg.get_byte(0xdbee) == 1) {
+ //talked to anne, lovers music
+ if (_engine->music->getId() != 6)
+ _engine->music->load(6);
+ } else {
+ //check music
+ int now_playing = _engine->music->getId();
+
+ if (now_playing != res->dseg.get_byte(0xDB90))
+ _engine->music->load(res->dseg.get_byte(0xDB90));
+ }
+
+}
+
+void Scene::playAnimation(byte idx, uint id) {
+ assert(idx < 4);
+ Common::SeekableReadStream * s = Resources::instance()->loadLan(id + 1);
+ if (s == NULL)
+ error("playing animation %u failed", id);
+
+ custom_animations[idx].load(s);
+ custom_animations[idx].loop = idx == 3; //looping face animation.
+}
+
+void Scene::push(const SceneEvent &event) {
+ //debug(0, "push");
+ //event.dump();
+ events.push_back(event);
+}
+
+bool Scene::processEvent(const Common::Event &event) {
+ if (!message.empty()) {
+ if (
+ event.type == Common::EVENT_LBUTTONDOWN ||
+ event.type == Common::EVENT_RBUTTONDOWN
+ ) {
+ message.clear();
+ custom_animations[3].free();
+ nextEvent();
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Scene::render(OSystem * system) {
+ //render background
+ bool busy = false;
+
+ system->copyRectToScreen((const byte *)background.pixels, background.pitch, 0, 0, background.w, background.h);
+
+ Graphics::Surface * surface = system->lockScreen();
+
+ if (ons != NULL) {
+ for(uint32 i = 0; i < ons_count; ++i) {
+ Surface* s = ons + i;
+ if (s != NULL)
+ s->render(surface);
+ }
+ }
+
+ for(int i = 3; i >= 0; --i) {
+ Animation &a = animations[i];
+ Surface *s = a.currentFrame();
+ if (s == NULL)
+ continue;
+
+ s->render(surface);
+
+ if (a.id == 0)
+ continue;
+
+ Object * obj = getObject(a.id);
+ if (obj != NULL) {
+ obj->rect.left = s->x;
+ obj->rect.top = s->y;
+ obj->rect.right = s->w + s->x;
+ obj->rect.bottom = s->h + s->y;
+ //obj->dump();
+ }
+ }
+
+ //render on
+ if (on.pixels != NULL) {
+ on.render(surface);
+ }
+
+ bool hide_actor = false;
+ bool got_any_animation = false;
+
+ for(int i = 3; i >= 0; --i) {
+ Animation &a = custom_animations[i];
+ Surface *s = a.currentFrame();
+ if (s == NULL) {
+ if (!a.empty() && current_event.type == SceneEvent::PlayAnimation) {
+ debug(0, "animation %u stopped", current_event.animation);
+ a.free();
+ nextEvent();
+ i = -1;
+ }
+ continue;
+ }
+
+ s->render(surface);
+ if (i == 0) {
+ //debug(0, "animation active @%u,%u, hiding actor", s->x, s->y);
+ hide_actor = true;
+ }
+ busy = true;
+ got_any_animation = true;
+ }
+
+ if (current_event.type == SceneEvent::WaitForAnimation && !got_any_animation) {
+ nextEvent();
+ }
+
+ if (destination != position) {
+ Common::Point dp(destination.x - position0.x, destination.y - position0.y);
+ int o;
+ if (ABS(dp.x) > ABS(dp.y))
+ o = dp.x > 0? Object::ActorRight: Object::ActorLeft;
+ else
+ o = dp.y > 0? Object::ActorDown: Object::ActorUp;
+
+ position.x = position0.x + dp.x * progress / progress_total;
+ position.y = position0.y + dp.y * progress / progress_total;
+ teenagent.render(surface, position, o, 1);
+ ++progress;
+ if (progress >= progress_total) {
+ position = destination;
+ if (orientation == 0)
+ orientation = o; //save last orientation
+ nextEvent();
+ } else
+ busy = true;
+ } else if (!hide_actor) {
+ teenagent.render(surface, position, orientation, 0);
+ }
+
+ busy |= processEventQueue();
+ //if (!current_event.empty())
+ // current_event.dump();
+
+ for (byte i = 0; i < walkboxes; ++i) {
+ Walkbox * w = walkbox[i];
+ w->rect.render(surface, 0xd0 + i);
+ }
+
+ if (!message.empty()) {
+ Resources::instance()->font7.render(surface, message_pos.x, message_pos.y, message);
+ busy = true;
+ }
+
+ system->unlockScreen();
+
+
+ if (sound_id != 0 && sound_delay != 0) {
+ if (--sound_delay == 0) {
+ debug(0, "delayed sound %u started", sound_id);
+ _engine->playSoundNow(sound_id);
+ sound_id = 0;
+ }
+ }
+
+ return busy;
+}
+
+bool Scene::processEventQueue() {
+ while (!events.empty() && current_event.empty()) {
+ //debug(0, "processing next event");
+ current_event = events.front();
+ events.pop_front();
+ switch(current_event.type) {
+
+ case SceneEvent::SetOn: {
+ byte * ptr = getOns(current_event.scene == 0? _id: current_event.scene);
+ debug(0, "on[%u] = %02x", current_event.ons - 1, current_event.color);
+ ptr[current_event.ons - 1] = current_event.color;
+ loadOns();
+ current_event.clear();
+ } break;
+
+ case SceneEvent::SetLan: {
+ if (current_event.lan != 0) {
+ debug(0, "lan[%u] = %02x", current_event.lan - 1, current_event.color);
+ byte * ptr = getLans(current_event.scene == 0? _id: current_event.scene);
+ ptr[current_event.lan - 1] = current_event.color;
+ }
+ loadLans();
+ current_event.clear();
+ } break;
+
+ case SceneEvent::LoadScene: {
+ init(current_event.scene, current_event.dst);
+ current_event.clear();
+ } break;
+
+ case SceneEvent::Walk: {
+ if (current_event.color != 0) {
+ warp(current_event.dst, current_event.orientation);
+ current_event.clear();
+ } else
+ moveTo(current_event.dst, current_event.orientation);
+ } break;
+
+ case SceneEvent::Message: {
+ //debug(0, "pop(%04x)", current_event.message);
+ message = current_event.message;
+ message_pos = messagePosition(message, position);
+ } break;
+
+ case SceneEvent::PlayAnimation: {
+ debug(0, "playing animation %u", current_event.animation);
+ playAnimation(current_event.color & 0x7f /*slot actually :)*/, current_event.animation);
+ if (current_event.color & 0x80)
+ nextEvent();
+ } break;
+
+ case SceneEvent::PlayMusic: {
+ debug(0, "setting music %u", current_event.music);
+ _engine->setMusic(current_event.music);
+ Resources::instance()->dseg.set_byte(0xDB90, current_event.music);
+ current_event.clear();
+ } break;
+
+ case SceneEvent::PlaySound: {
+ debug(0, "playing sound %u, delay: %u", current_event.sound, current_event.color);
+ if (current_event.color == 0) {
+ _engine->playSoundNow(current_event.sound);
+ } else {
+ sound_id = current_event.sound;
+ sound_delay = current_event.color;
+ }
+
+ current_event.clear();
+ } break;
+
+ case SceneEvent::EnableObject: {
+ debug(0, "%s object #%u", current_event.color?"enabling":"disabling", current_event.object - 1);
+ Object * obj = getObject(current_event.object - 1, current_event.scene == 0? _id: current_event.scene);
+ obj->enabled = current_event.color;
+ current_event.clear();
+ } break;
+
+ case SceneEvent::WaitForAnimation:
+ debug(0, "waiting for the animation");
+ break;
+
+ default:
+ error("empty/unhandler event[%d]", (int)current_event.type);
+ }
+ }
+ return !current_event.empty();
+}
+
+void Scene::setPalette(OSystem *system, const byte * buf, unsigned mul) {
+ byte p[1024];
+
+ memset(p, 0, 1024);
+ for(int i = 0; i < 256; ++i) {
+ for(int c = 0; c < 3; ++c)
+ p[i * 4 + c] = buf[i * 3 + c] * mul;
+ }
+
+ system->setPalette(p, 0, 256);
+}
+
+Object * Scene::getObject(int id, int scene_id) {
+ if (scene_id == 0)
+ scene_id = _id;
+
+ Resources * res = Resources::instance();
+ uint16 addr = res->dseg.get_word(0x7254 + (scene_id - 1) * 2);
+ //debug(0, "object base: %04x, x: %d, %d", addr, point.x, point.y);
+ uint16 object = res->dseg.get_word(addr + 2 * id - 2);
+
+ Object *obj = (Object *)res->dseg.ptr(object);
+ return obj;
+}
+
+Common::Point Scene::messagePosition(const Common::String &str, const Common::Point & position) {
+ Resources * res = Resources::instance();
+ uint w = res->font7.render(NULL, 0, 0, str);
+ Common::Point message_pos = position;
+ message_pos.x -= w / 2;
+ message_pos.y -= 62;
+ if (message_pos.x + w > 320)
+ message_pos.x = 320 - w;
+ if (message_pos.x < 0)
+ message_pos.x = 0;
+
+ return message_pos;
+}
+
+void Scene::displayMessage(const Common::String &str) {
+ debug(0, "displayMessage: %s", str.c_str());
+ message = str;
+ message_pos = messagePosition(str, position);
+}
+
+void Scene::clear() {
+ events.clear();
+ current_event.clear();
+}