diff options
Diffstat (limited to 'engines/teenagent/scene.cpp')
-rw-r--r-- | engines/teenagent/scene.cpp | 511 |
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(); +} |