From ebe1b94eb1561b566124b7dcbb73cf3b0a659b33 Mon Sep 17 00:00:00 2001 From: Vladimir Menshakov Date: Thu, 3 Sep 2009 20:59:17 +0000 Subject: imported teenagent engine sources. svn-id: r43922 --- base/plugins.cpp | 3 + configure | 1 + engines/engines.mk | 5 + engines/teenagent/actor.cpp | 70 ++ engines/teenagent/actor.h | 34 + engines/teenagent/animation.cpp | 185 ++++ engines/teenagent/animation.h | 64 ++ engines/teenagent/callbacks.cpp | 1807 +++++++++++++++++++++++++++++++++++++++ engines/teenagent/detection.cpp | 150 ++++ engines/teenagent/dialog.cpp | 106 +++ engines/teenagent/dialog.h | 42 + engines/teenagent/font.cpp | 142 +++ engines/teenagent/font.h | 48 ++ engines/teenagent/inventory.cpp | 285 ++++++ engines/teenagent/inventory.h | 84 ++ engines/teenagent/module.mk | 26 + engines/teenagent/music.cpp | 162 ++++ engines/teenagent/music.h | 77 ++ engines/teenagent/objects.cpp | 86 ++ engines/teenagent/objects.h | 104 +++ engines/teenagent/pack.cpp | 83 ++ engines/teenagent/pack.h | 49 ++ engines/teenagent/resources.cpp | 144 ++++ engines/teenagent/resources.h | 56 ++ engines/teenagent/scene.cpp | 511 +++++++++++ engines/teenagent/scene.h | 166 ++++ engines/teenagent/segment.cpp | 37 + engines/teenagent/segment.h | 80 ++ engines/teenagent/surface.cpp | 95 ++ engines/teenagent/surface.h | 52 ++ engines/teenagent/teenagent.cpp | 484 +++++++++++ engines/teenagent/teenagent.h | 110 +++ 32 files changed, 5348 insertions(+) create mode 100644 engines/teenagent/actor.cpp create mode 100644 engines/teenagent/actor.h create mode 100644 engines/teenagent/animation.cpp create mode 100644 engines/teenagent/animation.h create mode 100644 engines/teenagent/callbacks.cpp create mode 100644 engines/teenagent/detection.cpp create mode 100644 engines/teenagent/dialog.cpp create mode 100644 engines/teenagent/dialog.h create mode 100644 engines/teenagent/font.cpp create mode 100644 engines/teenagent/font.h create mode 100644 engines/teenagent/inventory.cpp create mode 100644 engines/teenagent/inventory.h create mode 100644 engines/teenagent/module.mk create mode 100644 engines/teenagent/music.cpp create mode 100644 engines/teenagent/music.h create mode 100644 engines/teenagent/objects.cpp create mode 100644 engines/teenagent/objects.h create mode 100644 engines/teenagent/pack.cpp create mode 100644 engines/teenagent/pack.h create mode 100644 engines/teenagent/resources.cpp create mode 100644 engines/teenagent/resources.h create mode 100644 engines/teenagent/scene.cpp create mode 100644 engines/teenagent/scene.h create mode 100644 engines/teenagent/segment.cpp create mode 100644 engines/teenagent/segment.h create mode 100644 engines/teenagent/surface.cpp create mode 100644 engines/teenagent/surface.h create mode 100644 engines/teenagent/teenagent.cpp create mode 100644 engines/teenagent/teenagent.h diff --git a/base/plugins.cpp b/base/plugins.cpp index 446c26e57c..6f821f7327 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -157,6 +157,9 @@ public: #if PLUGIN_ENABLED_STATIC(TUCKER) LINK_PLUGIN(TUCKER) #endif + #if PLUGIN_ENABLED_STATIC(TEENAGENT) + LINK_PLUGIN(TEENAGENT) + #endif // Music plugins // TODO: Use defines to disable or enable each MIDI driver as a diff --git a/configure b/configure index a157ecc544..4b7f626eb4 100755 --- a/configure +++ b/configure @@ -105,6 +105,7 @@ add_engine sword2 "Broken Sword 2" yes add_engine tinsel "Tinsel" yes add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes add_engine tucker "Bud Tucker in Double Trouble" yes +add_engine teenagent "Teen Agent" no # diff --git a/engines/engines.mk b/engines/engines.mk index acda075b46..19f99020ec 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -145,3 +145,8 @@ ifdef ENABLE_TUCKER DEFINES += -DENABLE_TUCKER=$(ENABLE_TUCKER) MODULES += engines/tucker endif + +ifdef ENABLE_TEENAGENT +DEFINES += -DENABLE_TEENAGENT=$(ENABLE_TEENAGENT) +MODULES += engines/teenagent +endif diff --git a/engines/teenagent/actor.cpp b/engines/teenagent/actor.cpp new file mode 100644 index 0000000000..9c8ff8e14a --- /dev/null +++ b/engines/teenagent/actor.cpp @@ -0,0 +1,70 @@ +/* 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/actor.cpp $ + * $Id: objects.h 172 2009-08-11 08:06:58Z megath $ + */ +#include "actor.h" +#include "objects.h" + +using namespace TeenAgent; + +void Actor::render(Graphics::Surface * surface, const Common::Point & position, uint8 orientation, int delta_frame) { + uint8 frames_left_right[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + uint8 frames_up[] = {18, 19, 20, 21, 22, 23, 24, 25, }; + uint8 frames_down[] = {10, 11, 12, 13, 14, 15, 16, 17, }; + + Surface * s = NULL; + + if (delta_frame == 0) { + index = 0; //static animation + } + int dx, dy; + switch(orientation) { + case Object::ActorLeft: + case Object::ActorRight: + if (index >= sizeof(frames_left_right)) + index = 1; + s = frames + frames_left_right[index]; + dx = 11; + dy = 62; + break; + case Object::ActorUp: + if (index >= sizeof(frames_up)) + index = 1; + s = frames + frames_up[index]; + dx = 29; + dy = 67; + break; + case Object::ActorDown: + if (index >= sizeof(frames_down)) + index = 1; + s = frames + frames_down[index]; + dx = 29; + dy = 67; + break; + default: + return; + } + index += delta_frame; + + if (s != NULL) + s->render(surface, position.x - dx, position.y - dy, orientation == Object::ActorLeft); +} diff --git a/engines/teenagent/actor.h b/engines/teenagent/actor.h new file mode 100644 index 0000000000..ca49ee4923 --- /dev/null +++ b/engines/teenagent/actor.h @@ -0,0 +1,34 @@ +/* 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/objects.h $ + * $Id: objects.h 172 2009-08-11 08:06:58Z megath $ + */ + +#include "animation.h" +#include "common/rect.h" + +namespace TeenAgent { + +class Actor : public Animation { +public: + void render(Graphics::Surface * surface, const Common::Point & position, uint8 orientation, int delta_frame); +}; +} \ No newline at end of file diff --git a/engines/teenagent/animation.cpp b/engines/teenagent/animation.cpp new file mode 100644 index 0000000000..3330acee2f --- /dev/null +++ b/engines/teenagent/animation.cpp @@ -0,0 +1,185 @@ +/* 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/animation.cpp $ + * $Id: animation.cpp 296 2009-09-01 19:55:58Z megath $ + */ + + +#include "animation.h" +#include "common/endian.h" + +using namespace TeenAgent; + +Animation::Animation() : id(0), x(0), y(0), loop(true), data(0), data_size(0), frames_count(0), frames(0), index(0) { +} + +Surface * Animation::currentFrame(int dt) { + if (frames == NULL || frames_count == 0) + return NULL; + + Surface * r; + + if (data != NULL) { + uint32 frame = 3 * index; + //debug(0, "%u/%u", index, data_size / 3); + index += dt; + + if (!loop && index >= data_size / 3) { + return NULL; + } + + if (data[frame] - 1 >= frames_count) { + warning("invalid frame %u(0x%x) (max %u) index %u, mod %u", frame, frame, frames_count, index - 1, data_size / 3); + return NULL; + } + + r = frames + data[frame] - 1; + uint16 pos = READ_LE_UINT16(data + frame + 1); + index %= (data_size / 3); + + if (pos != 0) { + x = r->x = pos % 320; + y = r->y = pos / 320; + } + } else { + //debug(0, "index %u", index); + r = frames + index; + index += dt; + index %= frames_count; + } + + return r; +} + + +void Animation::free() { + id = 0; + x = y = 0; + loop = true; + + delete[] data; + data = NULL; + data_size = 0; + + frames_count = 0; + delete[] frames; + frames = NULL; + + index = 0; +} + +void Animation::load(Common::SeekableReadStream * s, Type type) { + //fixme: do not reload the same animation each time + free(); + + if (s == NULL && s->size() <= 1) { + debug(0, "empty animation"); + return; + } + + uint16 pos = 0; + int off = 0; + switch(type) { + case TypeLan: + data_size = s->readUint16LE(); + if (s->eos()) { + debug(0, "empty animation"); + return; + } + + data_size -= 2; + data = new byte[data_size]; + data_size = s->read(data, data_size); +/* for(int i = 0; i < data_size; ++i) { + debug(0, "%02x ", data[i]); + } + debug(0, ", %u frames", data_size / 3); +*/ + frames_count = s->readByte(); + debug(0, "%u physical frames", frames_count); + if (frames_count == 0) + return; + + frames = new Surface[frames_count]; + + s->skip(frames_count * 2 - 2); //sizes + pos = s->readUint16LE(); + //debug(0, "pos?: %04x", pos); + + for(uint16 i = 0; i < frames_count; ++i) { + frames[i].load(s, Surface::TypeLan); + frames[i].x = 0; + frames[i].y = 0; + } + break; + + case TypeInventory: { + data_size = 3 * s->readByte(); + data = new byte[data_size]; + + frames_count = 0; + for(byte i = 0; i < data_size / 3; ++i) { + int idx = i * 3; + byte unk = s->readByte(); + data[idx] = s->readByte(); + if (data[idx] == 0) + data[idx] = 1; //fixme: investigate + if (data[idx] > frames_count) + frames_count = data[idx]; + data[idx + 1] = 0; + data[idx + 2] = 0; + //debug(0, "frame #%u", data[idx]); + } + + frames = new Surface[frames_count]; + + for(uint16 i = 0; i < frames_count; ++i) { + frames[i].load(s, Surface::TypeOns); + } + } + break; + + case TypeVaria: + frames_count = s->readByte(); + debug(0, "loading varia resource, %u physical frames", frames_count); + uint16 offset[255]; + for(byte i = 0; i < frames_count; ++i) { + offset[i] = s->readUint16LE(); + debug(0, "%u: %04x", i, offset[i]); + } + frames = new Surface[frames_count]; + for(uint16 i = 0; i < frames_count; ++i) { + debug(0, "%04x", offset[i]); + s->seek(offset[i] + off); + frames[i].load(s, Surface::TypeOns); + frames[i].x = 0; + frames[i].y = 0; + } + + break; + } + + debug(0, "%u frames", data_size / 3); +} + +Animation::~Animation() { + free(); +} diff --git a/engines/teenagent/animation.h b/engines/teenagent/animation.h new file mode 100644 index 0000000000..4304dc92a4 --- /dev/null +++ b/engines/teenagent/animation.h @@ -0,0 +1,64 @@ +/* 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/animation.h $ + * $Id: animation.h 214 2009-08-14 06:09:26Z megath $ + */ + + +#ifndef TEENAGENT_ANIMATION_H__ +#define TEENAGENT_ANIMATION_H__ + +#include "common/stream.h" +#include "surface.h" + +namespace TeenAgent { +class Animation { +public: + uint16 id, x, y; + bool loop; + + enum Type {TypeLan, TypeVaria, TypeInventory}; + + Animation(); + void load(Common::SeekableReadStream * s, Type type = TypeLan); + void free(); + + Surface * currentFrame(int dt = 1); + ~Animation(); + + bool empty() const { return frames == NULL; } + + //uint16 width() const { return frames? frames[0].w: 0; } + //uint16 height() const { return frames? frames[0].h: 0; } + +protected: + byte * data; + uint16 data_size; + + uint16 frames_count; + Surface * frames; + uint16 index; +}; +} + + +#endif + diff --git a/engines/teenagent/callbacks.cpp b/engines/teenagent/callbacks.cpp new file mode 100644 index 0000000000..2d78fc8c01 --- /dev/null +++ b/engines/teenagent/callbacks.cpp @@ -0,0 +1,1807 @@ +/* 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/objects.h $ + * $Id: objects.h 172 2009-08-11 08:06:58Z megath $ + */ + +#include "scene.h" +#include "teenagent.h" +#include "resources.h" +#include "dialog.h" + +using namespace TeenAgent; + +#define CHECK_FLAG(addr, v) (res->dseg.get_byte(addr) == (v)) +#define SET_FLAG(addr, v) (res->dseg.set_byte((addr), (v))) +#define GET_FLAG(addr) (res->dseg.get_byte(addr)) + +void TeenAgentEngine::rejectMessage() { + Resources * res = Resources::instance(); + //random reject message: + uint i = random.getRandomNumber(3); + //debug(0, "reject message: %s", (const char *)res->dseg.ptr(res->dseg.get_word(0x339e + 2 * i))); + scene->displayMessage((const char *)res->dseg.ptr(res->dseg.get_word(0x339e + 2 * i))); +} + +void TeenAgentEngine::anotherMansionTry() { + Resources * res = Resources::instance(); + byte tries = ++ *(res->dseg.ptr(0xDBEA)); + debug(0, "another mansion try: %u", tries); + if (tries >= 7) + return; + uint16 ptr = res->dseg.get_word(res->dseg.get_word((tries - 2) * 2 + 0x6035)); + + playMusic(11); + debug(0, "FIXME: cutscene: meanwhile in a mansion #%u, %04x", tries, ptr); + processCallback(ptr); + playMusic(6); + if (scene->getId() == 11 && CHECK_FLAG(0xDBEC, 1)) + return; + //call 0xac27 +} + +bool TeenAgentEngine::processCallback(uint16 addr) { + if (addr == 0) + return false; + + Resources * res = Resources::instance(); + debug(0, "processCallback(%04x)", addr); + byte * code = res->cseg.ptr(addr); + + //try trivial callbacks first + if (code[0] == 0xbb && code[3] == 0xe8 && code[6] == 0xc3) { + //call display_message, r + uint16 msg = READ_LE_UINT16(code + 1); + uint16 func = 6 + addr + READ_LE_UINT16(code + 4); + debug(0, "call %04x", func); + //debug(0, "trivial callback, showing message %s", (const char *)res->dseg.ptr(addr)); + switch(func) { + case 0x11c5: + Dialog::show(scene, msg); + return true; + case 0xa055: + displayMessage((const char *)res->dseg.ptr(msg)); + return true; + } + } + + if (code[0] == 0xe8 && code[3] == 0xc3) { + uint func = 3 + addr + READ_LE_UINT16(code + 1); + debug(0, "call %04x and return", func); + if (func == 0xa4d6) { + rejectMessage(); + return true; + } + } + + if (code[0] == 0xc7 && code[1] == 0x06 && code[2] == 0xf3 && code[3] == 0xb4 && + code[6] == 0xb8 && code[9] == 0xbb && code[12] == 0xbf && + code[22] == 0xe8 && code[25] == 0xc3) { + loadScene(code[4], Common::Point( + (READ_LE_UINT16(code + 7) + READ_LE_UINT16(code + 13) + 1) / 2 , + READ_LE_UINT16(code + 10))); + scene->setOrientation(code[21]); + return true; + } + + switch(addr) { + + case 0x4021: + //pulling out mysterious object + if (CHECK_FLAG(0xdbe1, 1)) { + playAnimation(844); + playAnimation(846); + playAnimation(845); + displayMessage(0x5696); + } else { + displayMessage(0x570f); + } + return true; + + case 0x4094: //climbing to the pole near mudpool + if (CHECK_FLAG(0xDBE4, 1)) { + displayMessage(0x57b2); + return true; + } else { + playSound(76); + playAnimation(864); + playAnimation(866); + //InventoryObject *obj = inventory->selectedObject(); + //if (obj != NULL && obj->id == 0x55) { + + //implement pause and using real object: + if (inventory->has(0x55)) { + playSound(5, 4); + playAnimation(867); + inventory->remove(0x55); + inventory->add(0x56); + moveTo(86, 195, true); //warp and orientation 1 + playAnimation(868); + SET_FLAG(0xDBE4, 1); + } else { + //fail! + moveTo(86, 195, true); //warp and orientation 1 + playAnimation(868); + Dialog::pop(scene, 0xDB72); + } + return true; + } + + case 0x419c: //getting the bird + setOns(0, 0); + playSound(56, 10); + playAnimation(875); + disableObject(6); + inventory->add(0x5c); + return true; + + + case 0x41ce: + moveTo(Common::Point(197, 159)); + setOns(0, 0); + playSound(71); + playAnimation(833); + moveTo(Common::Point(225, 159)); + inventory->add(0x4e); + disableObject(3); + return true; + + case 0x4267: + playSound(23, 8); + setOns(1, 0); + playAnimation(841); + setOns(1, 0x61); + setOns(2, 0); + playSound(63, 12); + playAnimation(842); + //shown in different positions + displayMessage(0x5656); + displayMessage(0x567a); + displayMessage(0x5682); + playAnimation(843); + moveTo(223, 149, true); + disableObject(7); + disableObject(1); + inventory->add(0x51); + displayMessage(0x5646); + return true; + + case 0x4388: + playSound(80); + loadScene(8, 155, 199); + scene->setOrientation(1); + return true; + + case 0x43b5: //HQ, first trial - prison + playSound(70); + playAnimation(962); + loadScene(7, 30, 184, 2); + if (res->dseg.get_byte(0xDBDF) < 2) { + moveTo(Common::Point(134, 167)); + displayMessage(0x54f7); + setLan(1, 0); + playAnimation(812, 1, true); + playAnimation(811); + Dialog::show(scene, 0x6117, 813); + loadScene(6, Common::Point(230, 184)); + Dialog::show(scene, 0x626a, 814); + playAnimation(815, 1); + setOns(1, 0); + + Dialog::show(scene, 0x62dc); + + SET_FLAG(0xDBDF, 1); + SET_FLAG(0xDB90, 5); + } + return true; + + case 0x4482: + if (CHECK_FLAG(0xDBDF, 0)) { + playAnimation(968); + displayMessage(0x5511); + } else { + playSound(80); + playAnimation(968); + loadScene(6, Common::Point(280, 186)); + } + return true; + + case 0x44fc: //pull out spring from bed + playSound(53, 25); + playAnimation(839); + moveTo(278, scene->getPosition().y, true); + inventory->add(0x50); + disableObject(1); + return true; + + case 0x44cb: + if (CHECK_FLAG(0xDBE5, 1)) { + scene->displayMessage((const char *)res->dseg.ptr(0x57c0)); + } else { + playSound(49); + playAnimation(869); + inventory->add(0x58); + SET_FLAG(0xDBE5, 1); + } + return true; + + case 0x4539: //prison cell: use crates + if (CHECK_FLAG(0xdbdd, 2)) { + //finished the meal - trap + displayMessage(0x55c0); + moveTo(306, 196); + //playAnimation(825, 1); //very long empty animation. what for? + setLan(1, 0); + playSound(71, 4); + playAnimation(823); + + //skipped one 826 animation for this scene! + playSound(74, 4); //delay 10 in code + loadScene(5, scene->getPosition()); + playAnimation(826); + loadScene(6, scene->getPosition()); + setOns(3, 0x5b); + displayMessage(0x55db); + SET_FLAG(0xdbdd, 3); + strcpy(scene->getObject(4)->name, "body"); + } else { + if (Dialog::pop(scene, 0xdb5c) != 0x636b) //not 'im getting hungry' + return true; + + playSound(52, 8); + playAnimation(820, 1); + setOns(3, 0x59); + //some moving animation is missing here + displayMessage(0x551f); + enableObject(4); + SET_FLAG(0xdbdc, 1); + } + return true; + + case 0x4662: + if (CHECK_FLAG(0xDBDD, 3)) { + moveTo(280, 179); + playSound(49, 7); + playAnimation(827); + inventory->add(0x4d); + SET_FLAG(0xDBDE, 1); + } else + displayMessage(0x5905); + return true; + + case 0x46af: //prison cell: use live cable + if (CHECK_FLAG(0xdbdc, 1)) { + displayMessage(0x555d); + setOns(2, 0); + playAnimation(821); + setOns(2, 0x5a); + setOns(3, 0); + playSound(22, 2); + playAnimation(822); + displayMessage(0x5577); + disableObject(5); + SET_FLAG(0xdbdd, 1); + } else + displayMessage(0x5528); + return true; + + case 0x4705: { //prison: getting lamp bulb + moveTo(144, 185); + playSound(56, 15); + setOns(0, 86); //hiding lamp + playAnimation(816, 0, true); + playAnimation(817, 1, true); + waitAnimation(); + setOns(0, 87); + + playSound(34, 1); + playAnimation(818); + playAnimation(819, 1, true); + waitAnimation(); + + moveTo(160, 188, true); + setOns(2, 88); + + disableObject(6); + enableObject(5); + inventory->add(0x4c); + } + return true; + + case 0x4794: //prison cell door + if (res->dseg.get_byte(0xDBDF) >= 2) { + loadScene(5, 287, 143); + } else { + displayMessage(0x592f); + } + return true; + + case 0x47bc: //prison: examining trash can + playSound(49, 5); + playAnimation(966); + displayMessage(0x5955); + return true; + + case 0x47db: //prison: use switch + if (CHECK_FLAG(0xDBDF, 1)) { + playSound(71, 4); + playAnimation(823); + if (CHECK_FLAG(0xDBDD, 0)) { + displayMessage(0x4d80); + } else { + playSound(74, 1); + playAnimation(824, 1); + if (CHECK_FLAG(0xDBDD, 1)) { + displayMessage(0x559a); + SET_FLAG(0xDBDD, 2); + } + } + } else { + displayMessage(0x52f6); + } + return true; + + case 0x4871: + playAnimation(965); + displayMessage(0x5511); + return true; + + case 0x4893: //taking pills + if (CHECK_FLAG(0xDBE6, 1)) { + SET_FLAG(0xDBE6, 2); + setOns(1, 0x67); + playSound(5, 9); + playAnimation(872); + inventory->add(0x5a); + disableObject(7); + } else { + playAnimation(964); + displayMessage(0x5511); + } + return true; + + case 0x4918: //talking with barmen + if (CHECK_FLAG(0xDBE7, 1)) { + moveTo(140, 152); + if (CHECK_FLAG(0xDBE8, 1)) { + Dialog::show(scene, 0x6f20); + displayMessage(0x5883, 0xef); + //reloadLan(); + setLan(1, 0); + playAnimation(882, 1); + playSound(75, 10); + setOns(2, 0); + playAnimation(883, 1); + disableObject(1); + disableObject(2); + SET_FLAG(0xDBE9, 1); + } else + displayMessage(0x5855); + } else { + if (CHECK_FLAG(0xDBDF, 3)) { + if (CHECK_FLAG(0xDBE3, 1)) { + Dialog::show(scene, 0x6BD6, 857); + } else { + Dialog::show(scene, 0x69B5, 857); //taking mug + playAnimation(859, 0, true); + playAnimation(858, 1, true); + waitAnimation(); + playSound(75, 6); + playAnimation(860); + Dialog::show(scene, 0x69C2, 857); + inventory->add(0x55); + SET_FLAG(0xDBE3, 1); + SET_FLAG(0xDBF0, 0); + } + } else { + Dialog::pop(scene, 0xDB68, 857); + } + } + return true; + + case 0x4f14: //use the hollow + displayMessage(CHECK_FLAG(0xDBA1, 1)? 0x370f: 0x36c2); + return true; + + case 0x4a64: + if (CHECK_FLAG(0xDBF0, 1)) { + displayMessage(0x5e25); + } else { + loadScene(5, 35, 162); + } + return true; + + case 0x4bf5: + playAnimation(959); + loadScene(8, 40, 152, 3); + return true; + + case 0x483a: + Dialog::pop(scene, 0xdb82); + return true; + + case 0x4844: + playSound(80, 4); + playAnimation(963); + loadScene(5, 166, 158); + return true; + + case 0x48ea: + setOns(0, 0); + playSound(5, 9); + playAnimation(836); + inventory->add(0x4f); + disableObject(12); + return true; + + case 0x4a8c: + if (CHECK_FLAG(0xDBE9, 1)) { + playSound(89, 5); + playAnimation(958); + loadScene(9, 240, 182, 4); + } else if (CHECK_FLAG(0xDBE9, 1)) { + displayMessage(0x5894); + } else { + Dialog::pop(scene, 0xDB8A, 857); + } + return true; + + case 0x4af4: //taking the crumbs + setOns(0, 0); + playAnimation(861); + playSound(49); + inventory->add(0x57); + disableObject(6); + return true; + + case 0x4b35: + playSound(15, 7); + playAnimation(884); + playSound(55, 1); + playAnimation(885, 1); + Dialog::show(scene, 0x67e5, 886); + playMusic(3); + loadScene(40, 198, 186, 1); + Dialog::show(scene, 0x7f20); + inventory->clear(); + inventory->add(0x1d); + //showFullscreenMessage(0xe45c); + loadScene(1, 198, 186); + playAnimation(956, 0, true); + Dialog::show(scene, 0x8bc4); + waitAnimation(); + loadScene(15, 157, 199, 1); + playMusic(6); + return true; + + case 0x4c3e: //get the grenade + playSound(32, 24); + playAnimation(862); + reloadLan(); + playAnimation(863, 1); + inventory->add(0x54); + disableObject(1); + SET_FLAG(0xDBE2, 2); + return true; + + case 0x4c70: + if (CHECK_FLAG(0xDBE2, 0)) { + if (CHECK_FLAG(0xDBDA, 1)) { //papers are shown + Dialog::pop(scene, 0xDB4C); + } else { + Dialog::pop(scene, 0xDB40); + } + return true; + } else { + displayMessage(0x5722); + + scene->displayMessage("He's totally addicted."); + } + return true; + + case 0x4c1c: + playAnimation(960); + displayMessage(0x5511); + return true; + + case 0x4cac: + if (CHECK_FLAG(0xdbda, 1)) { //papers are shown + loadScene(5, 124, 199); + } else { + playAnimation(809, 1, true); + Dialog::show(scene, 0x5FE9); + moveTo(Common::Point(269, 175)); + Dialog::pop(scene, 0xDB56); + } + return true; + + case 0x4cf1: { //talking with mansion guard + playAnimation(529, 1); + SET_FLAG(0xda96, 1); + if (Dialog::pop(scene, 0xdaa6) != 0x1b4) + return true; + Common::Point p = scene->getPosition(); + moveTo(159, 189); + + playAnimation(550); + playAnimation(551, 1); + + moveTo(p); + inventory->add(0x13); + playAnimation(529, 1); + Dialog::pop(scene, 0xdaa6); + } + return true; + + case 0x4e61: + loadScene(14, 280, 198); + return true; + + case 0x4f25: + playAnimation(967); + displayMessage(0x3542); + return true; + + case 0x4f32: + if (CHECK_FLAG(0xDBA1, 1)) { + break; + } else { + playAnimation(49); + playSound(56); + //there's some black magic here! investigate! + playAnimation(587); + displayMessage(0x4652); + displayMessage(0x3668); + return true; + } + + case 0x500d: //picking up wild plant + if (CHECK_FLAG(0xDB9E, 1)) { + displayMessage(0x35E8); //there are no more + } else { + SET_FLAG(0xDB9E, 1); + setOns(2, 0); + playAnimation(552); + setOns(2, 0x12); + inventory->add(0x14); + } + return true; + + case 0x5104: + loadScene(11, 319, 198, 4); //orientation: left + if (CHECK_FLAG(0xDB9C, 1)) + return true; + + SET_FLAG(0xDB9C, 1); //guard's drinking, boo! + playAnimation(544, 1); + displayMessage(0x3563); + playSound(17); + playAnimation(545, 1); + setOns(0, 16); + enableObject(2); + Dialog::show(scene, 0x0917); + + return true; + + case 0x5217: + displayMessage(CHECK_FLAG(0xDB9F, 1)? 0x402e: 0x34e1); + return true; + + case 0x5237: + if (!CHECK_FLAG(0xDB9F, 1)) { + displayMessage(0x34e1); + } else if (CHECK_FLAG(0xDBA0, 1)) + displayMessage(0x3E31); + else { + moveTo(173, 138); + playAnimation(583); + playAnimation(584); + playSound(72); + playAnimation(585); + loadScene(11, 194, 160); + playSound(28); + moveTo(138, 163); + displayMessage(0x3650); + SET_FLAG(0xDBA0, 1); + } + return true; + + case 0x55a8: { + uint16 d = Dialog::pop(scene, 0xdb08); + if (d == 0x2c5d) { + setOns(0, 0); + playAnimation(570, 1); + displayMessage(0x551f); + disableObject(5); + SET_FLAG(0xDBB0, 1); + } else if (d != 0x2c9b) { + playAnimation(569, 1); + } + } + return true; + + case 0x5663: + displayMessage(CHECK_FLAG(0xDBB0, 1)? 0x41b1: 0x417e); + return true; + + case 0x569c: + playAnimation(983); + displayMessage(0x5955); + return true; + + case 0x56b7: + playAnimation(984); + displayMessage(0x5955); + return true; + + case 0x5728: + inventory->add(0x0d); + disableObject(14); + setOns(0, 0); + playAnimation(566); + return true; + + case 0x5793: + if (!CHECK_FLAG(0xDB94, 1)) { + displayMessage(0x3e63); + } else if (CHECK_FLAG(0xDB95, 1)) { + displayMessage(0x3e75); + } else { + SET_FLAG(0xDB95, 1); + moveTo(188, 179); + playSound(7, 16); + playAnimation(519); + moveTo(168, 179); + inventory->add(3); + } + return true; + + case 0x5d88: + if (CHECK_FLAG(0xDBA5, 1)) { //dry laundry + SET_FLAG(0xDBA5, 2); + Dialog::show(scene, 0x1F4F); + playAnimation(604, 1); + + loadScene(21, scene->getPosition()); + setOns(0, 0); + disableObject(4); + enableObject(12); + playSound(46); + playAnimation(606, 1); + loadScene(23, scene->getPosition()); + playAnimation(605, 1); + Dialog::show(scene, 0x2002); + } else { + uint16 d = Dialog::pop(scene, 0xdada); + if (d == 0x1913) + displayMessage(0x34d5); //+orientation = 3 + } + return true; + + case 0x5ff3: //get duster + if (CHECK_FLAG(0xDB9A, 0)) { + Dialog::pop(scene, 0xdaf6); + } else { + Dialog::show(scene, 0x1e1e); + inventory->add(12); + disableObject(12); + setOns(0, 0); + playSound(5); + playAnimation(541); + } + return true; + + case 0x646e: + case 0x6475: + Dialog::show(scene, 0x32C1); + return true; + + case 0x6507: + if (CHECK_FLAG(0xDB96, 1)) { + rejectMessage(); + } else + displayMessage(0x47e7); + return true; + + case 0x65c3: + if (CHECK_FLAG(0xDBA9, 1)) { + playAnimation(635); + setOns(5, 0); + playSound(63); + playAnimation(636); + inventory->add(47); + inventory->add(48); + displayMessage(0x3b83); + SET_FLAG(0xDBA9, 2); + SET_FLAG(0xDBA8, 0); + } else + displayMessage(0x4808); + return true; + + case 0x7866: + if (CHECK_FLAG(0xdbdd, 3)) { + displayMessage(0x55ff); + return true; + } else + return false; + + case 0x7878: { + byte v = res->dseg.get_byte(0xDBDB) + 1; + if (v <= 6) + SET_FLAG(0xDBDB, v); + + switch(v) { + case 1: + displayMessage(0x5411); + return true; + case 2: + displayMessage(0x5463); + return true; + case 3: + displayMessage(0x5475); + return true; + case 4: + displayMessage(0x5484); + return true; + case 5: + displayMessage(0x54c4); + return true; + default: + displayMessage(0x54d5); + return true; + } + } + + case 0x78a9: + if (CHECK_FLAG(0xDBE6, 1)) { + displayMessage(0x5827); + return true; + } else + return false; + + case 0x78bb: + if (CHECK_FLAG(0xDBE8, 1)) { + displayMessage(0x58b0); + return true; + } else + return false; + + //case 0x78f5: //trunk description + // if (CHECK_FLAG(0xDB95, 1)) { + // displayMessage(0x3e75); + // } + // return; + + case 0x78ce: + if (!CHECK_FLAG(0xDBA1, 1)) { + displayMessage(0x3694); + return true; + } else + return false; + + case 0x792b: //left click on ann + moveTo(245, 198, 1); + if (CHECK_FLAG(0xDBAF, 1)) + return false; + + Dialog::show(scene, 0x2193); + SET_FLAG(0xDBAF, 1); + return true; + + case 0x7b26: //cutting the fence + setOns(0, 0); + playSound(5, 2); + playAnimation(837); + playSound(51, 3); + playAnimation(838); + setOns(0, 0x60); + moveTo(281, scene->getPosition().y, true); + disableObject(4); + SET_FLAG(0xDBE1, 1); + return true; + + case 0x7b89: //digging mysterious object + if (CHECK_FLAG(0xDBE1, 1)) { + playAnimation(844); + setOns(1, 0); + playSound(5, 5); + playAnimation(847); + playSound(5, 11); + playAnimation(848); + setOns(1, 0x64); + playAnimation(845); + disableObject(3); + inventory->add(0x52); + inventory->remove(0x51); + } else + displayMessage(0x56da); + return true; + + case 0x7bfd: + playSound(76, 18); + playAnimation(873); + moveTo(240, 163); + displayMessage(0x5837); + playSound(77, 2); + setLan(1, 0); + playAnimation(874, 1); + setOns(0, 0x68); + inventory->remove(0x5b); + enableObject(6); + disableObject(1); + return true; + + case 0x7ce5: //put spring on the solid ground + playSound(5, 2); + playAnimation(840); + setOns(1, 0x61); + inventory->remove(0x50); + disableObject(2); + enableObject(7); + return true; + + case 0x7d1a: //captain's key + door + if (res->dseg.get_byte(0xDBDF) <= 1) { + playSound(5, 2); + playAnimation(828); + moveTo(262, 160, true); + disableObject(4); + disableObject(3); + setOns(0, 0); + setOns(1, 85); + setOns(2, 0); + setOns(3, 0); + loadScene(5, scene->getPosition()); + setOns(0, 92); + playAnimation(829, 1); + setOns(0, 0); + Dialog::show(scene, 0x63a5, 830); + loadScene(7, 130, 195); + playMusic(4); + setLan(1, 1); + + Dialog::show(scene, 0x6406, 832); + + //playAnimation(831, 1); + + SET_FLAG(0xDBDF, 2); + + } else + displayMessage(0x52f6); + return true; + + case 0x7e02: //tickling the captain + if (CHECK_FLAG(0xdbe0, 1)) { + displayMessage(0x5632); + } else { + playSound(5, 6); + playAnimation(834, 0, true); + playAnimation(835, 1, true); + waitAnimation(); + + setOns(0, 94); + Dialog::show(scene, 0x65e9, 832); + enableObject(12); + SET_FLAG(0xdbe0, 1); + } + return true; + + case 0x7e4f: //giving magazine to captain + playSound(5, 3); + Dialog::show(scene, 0x66c0); + playAnimation(852, 0, true); + playAnimation(853, 0, true); + displayMessage(0x5742); + displayMessage(0x5757); + displayMessage(0x5770); + displayMessage(0x5782); + displayMessage(0x5799); + playAnimation(856, 1); + playSound(5, 3); + //playAnimation(854); + Dialog::show(scene, 0x66fe); + playAnimation(855, 1); + moveTo(30, 181); + disableObject(1); + setLan(1, 0); + SET_FLAG(0xDBDF, 3); + SET_FLAG(0xDBF0, 1); + loadScene(8, 155, 199); + return true; + + case 0x7fbd: //using bird & bartender + playSound(5, 3); + playAnimation(876); + setOns(1, 0); + playAnimation(877, 2); + playAnimation(880, 2, true); + + Dialog::show(scene, 0x6f0e, 857); + setOns(2, 0x6a); + reloadLan(); + playAnimation(878, 1); + playAnimation(879, 1); + inventory->remove(0x5c); + enableObject(1); + SET_FLAG(0xDBE7, 1); + return true; + + case 0x8047: + playSound(32, 5); + playAnimation(881); + setOns(2, 0x6b); + inventory->remove(0x56); + inventory->add(0x55); + SET_FLAG(0xDBE8, 1); + return true; + + case 0x808b: + if (CHECK_FLAG(0xDBDA, 1)) { + //alredy shown + displayMessage(0x53F2); + } else { + playSound(5); + displayMessage(0x53DD); + playAnimation(810, false); + Dialog::show(scene, 0x60BF); + SET_FLAG(0xDBDA, 1); + } + return true; + + case 0x80c3: //show kaleydoscope to the guard + Dialog::show(scene, 0x6811, 809); + playSound(5, 3); + playAnimation(849, 0, true); + playAnimation(851, 1, true); + waitAnimation(); + + playAnimation(850, 1); + reloadLan(); + inventory->add(0x53); + inventory->remove(0x52); + enableObject(1); + SET_FLAG(0xDBE2, 1); + return true; + + //Shore + + case 0x4d56: + inventory->add(16); + disableObject(2); + setOns(0, 0); + playSound(5); + playAnimation(547); + return true; + + + case 0x4eb9://Pick up wrapper + inventory->add(0x12); + setOns(1, 0); + playAnimation(549); + disableObject(13); + return true; + + case 0x5348: + if (CHECK_FLAG(0xdb99, 1)) { //got broken paddle from boat + displayMessage(0x351f); + } else { + SET_FLAG(0xDB99, 1); + playSound(57, 6); + playAnimation(536); + Dialog::show(scene, 0x30c3); + inventory->add(0x8); + } + return true; + + case 0x53a1: + if (CHECK_FLAG(0xdbb2, 1)) { //spoken to man in well + displayMessage(0x411d); + } else { + SET_FLAG(0xDBB2, 1); + displayMessage(0x408a); + displayMessage(0x4091); + displayMessage(0x4098); + displayMessage(0x40a7); + displayMessage(0x40b6); + displayMessage(0x40ce); + displayMessage(0x40e8); + displayMessage(0x410f); + } + return true; + + + case 0x5458: { + setOns(2, 0); + playSound(34); + playAnimation(535); + inventory->add(11); + disableObject(1); + + byte * scene_15_ons = scene->getOns(15); //patch ons for the scene 15 + scene_15_ons[0] = 0; + + byte f = GET_FLAG(0xDB98) + 1; + SET_FLAG(0xDB98, f); + if (f >= 2) { + //disable object boat for scene 15!! + scene->getObject(1, 15)->enabled = 0; + } + } + return true; + + case 0x54b3: { + setOns(1, 0); + setOns(3, 0); + playSound(33); + playAnimation(534); + inventory->add(10); + disableObject(2); + setOns(1, 10); + + byte * scene_15_ons = scene->getOns(15); //patch ons for the scene 15 + scene_15_ons[1] = 0; + byte f = GET_FLAG(0xDB98) + 1; + SET_FLAG(0xDB98, f); + if (f >= 2) { + //disable object boat for scene 15!! + scene->getObject(1, 15)->enabled = 0; + } + } + return true; + + case 0x5502: + setOns(0, 0); + loadScene(15, 115, 180, 1); + playAnimation(568); + playMusic(6); + return true; + + case 0x5561://Enter lakeside house + moveTo(81, 101); + loadScene(19, 223, 193); + return true; + + case 0x563b: + playSound(5); + playAnimation(561); + setOns(1, 0); + inventory->add(26); + disableObject(6); + return true; + + case 0x5756://Open car door + playSound(11, 4); + playAnimation(514); + setOns(4, 8); + setOns(2, 5); + enableObject(14); + enableObject(15); + enableObject(16); + disableObject(1); + return true; + + case 0x5805://Enter basketball house + playSound(70, 6); + moveTo(161, 165); + playAnimation(513); + loadScene(22, 51, 180); + return true; + + case 0x5832://Ring doorbell + playAnimation(509); + displayMessage(0x5dce); + return true; + + case 0x58a2: + Dialog::pop(scene, 0xdaba); + strcpy(scene->getObject(13)->name, (const char *)res->dseg.ptr(0x92e5)); + return true; + + case 0x58b7://Get comb from car + disableObject(14); + setOns(4,0); + playSound(5, 7); + playAnimation(521); + setOns(4, 0); + inventory->add(0x6); + return true; + + case 0x58df://Pull trunk lever in car + SET_FLAG(0xDB94, 1); + playSound(6, 1); + setOns(3, 6); + playAnimation(515); + return true; + + case 0x593e://Enter annes house + moveTo(100, 176); + //Need to add support for the choice of music + //After speaking with anne the default room song changes + loadScene(23, 94, 190); + if (CHECK_FLAG(0xdbee, 1)) {//spoken with anne + //playMusic(6);//Play lovers music + //i've added music changing right into scene. + } + return true; + + case 0x5994: + processCallback(0x599b); + processCallback(0x5a21); + return true; + + case 0x599b: + return true; + + case 0x5a21: + loadScene(24, 230, 170, 1); + playSound(52, 3); + playAnimation(601); + moveTo(230, 179, 3); + if (!CHECK_FLAG(0xDBA4, 1)) + displayMessage(0x37ea); //it's kinda dark here + return true; + + case 0x5a8b: + if (!CHECK_FLAG(0xDBAD, 1)) { + playSound(43, 4); //grrrrrr + setLan(1, 0); + playAnimation(656, 1); + setLan(1, 0xff); + displayMessage(0x3c16); + } else if (!CHECK_FLAG(0xDBA3, 1)) {//Dog has bone + playSound(28, 3); + playAnimation(596); + setOns(1, 30); + //loadScene(24, 100, 100);//TODO: Extend and fix the coords + SET_FLAG(0xDBA3, 1); + enableObject(8); + } else { + setOns(1, 0); + playSound(4, 4); + playAnimation(597); + SET_FLAG(0xDBA3, 0); + disableObject(8); + displayMessage(0x37b8); + setOns(1, 32, 24); + enableObject(4, 24); + } + return true; + + case 0x5b3a://Click on dog + Dialog::pop(scene, 0xDB14); + return true; + + case 0x5be1://Talk to grandpa + Dialog::pop(scene, 0xDAC4); + return true; + + case 0x5c0d: //grandpa - drawers + if (CHECK_FLAG(0xDBA7, 1)) { + displayMessage(0x3bac); + } else { + if (!CHECK_FLAG(0xDB92, 1)) + Dialog::show(scene, 0x15a0); //can I search your drawers? + + playSound(66); + playAnimation(631); + inventory->add(47); + SET_FLAG(0xDBA7, 1); + } + return true; + + case 0x5c84: + if (CHECK_FLAG(0xDB92, 1)) { + inventory->add(2); + disableObject(7); + playSound(32); + setOns(0, 0); + playAnimation(520); + } else { + Dialog::pop(scene, 0xDACE); + } + return true; + + case 0x5cf0://Exit basketball house + playSound(88, 5); + playAnimation(981); + loadScene(20, 161, 165); + return true; + + case 0x5d24: //getting the fan + if (CHECK_FLAG(0xDB92, 1)) { + setLan(2, 0); + playSound(32); + playAnimation(508); + disableObject(13); + inventory->add(7); + } else { + Dialog::pop(scene, 0xDAD4); + } + return true; + + case 0x5e4d: //right click on ann + if (!CHECK_FLAG(0xDB97, 0)) { + displayMessage(0x3d59); + } else { + moveTo(245, 198, 1); + Dialog::show(scene, 0x21d7); + SET_FLAG(0xDB97, 1); + playSound(13); + playAnimation(528, 1); + playMusic(7); + SET_FLAG(0xDBEE, 1); + playSound(56); + playAnimation(525); + playSound(56); + playAnimation(526); + playSound(54); + playAnimation(527); + Dialog::show(scene, 0x2219); + strcpy(scene->getObject(2)->name, (const char *)res->dseg.ptr(0x9820)); + } + return true; + + case 0x5f73://Exit annes house + //Need to fully understand what this does, there is a compare in the asm + //I assume it is probably to do with the music + loadScene(21, 161, 165); + + return true; + + case 0x5fba: + if (CHECK_FLAG(0xDBB1, 1)) { + displayMessage(0x4380); + } else { + Dialog::pop(scene, 0xDAFC); + } + return true; + + case 0x6480: //flips + if (CHECK_FLAG(0xDB96, 1)) { + setOns(3, 36); + playSound(56); + playAnimation(613); + inventory->add(39); + disableObject(5); + displayMessage(0x387c); + } else + displayMessage(0x3eb2); + return true; + + case 0x64c4: //mask (maybe flips) :) + if (CHECK_FLAG(0xDB96, 1)) { + setOns(2, 35); + playSound(63); + playAnimation(612); + inventory->add(40); + disableObject(6); + } else + displayMessage(0x3eb2); + return true; + + case 0x78f5://Describe trunk + if (CHECK_FLAG(0xdb95, 1)) {//trunk closed + displayMessage(0x3e75); + return true; + } + else { + displayMessage(0x9080); + return true; + } + + case 0x7907://Describe car lever + if (CHECK_FLAG(0xdb94, 1)) {//Already pulled lever? + displayMessage(0x3e4f); + return true; + } else + return false; + + case 0x612b://climb basement ladder(exit) + playSound(52, 10); + playAnimation(600); + loadScene(21, 297, 178, 3); + return true; + + case 0x6351: + if (CHECK_FLAG(0xdaca, 1)) { //cave bush is cut down + playMusic(8); + loadScene(26, 319, 169); + return true; + } else { + displayMessage(0x3bd2); + return true; + } + + case 0x6592: //Rake + setOns(1, 0); + playSound(18, 10); + playAnimation(553); + inventory->add(0x15); + displayMessage(0x3605); + disableObject(11); + return true; + + case 0x62d0://Get bone from under rock + playSound(26, 6); + setOns(0, 0); + playAnimation(594); + setOns(0, 29); + displayMessage(0x463c); + disableObject(1); + inventory->add(36); + playSound(5, 3); + playAnimation(595); + displayMessage(0x3790); + return true; + + case 0x6411://Kick hen + if (CHECK_FLAG(0xdb93, 1)) { //already kicked hen + displayMessage(0x3e08); + return true; + } else { + SET_FLAG(0xdb93, 1); + playSound(30, 26); + displayMessage(0x3dc6); + playAnimation(500, 0, true); + playAnimation(501, 1, true); + waitAnimation(); + setOns(0, 1); + enableObject(14); + displayMessage(0x3df4); + return true; + } + + case 0x6519://Sickle + setOns(4, 0); + playSound(5, 11); + playAnimation(625); + inventory->add(0x2c); + disableObject(8); + return true; + + case 0x655b://Get needle from haystack + if (CHECK_FLAG(0xdabb, 1)) { //already have needle + displayMessage(0x356a); + return true; + } else { + SET_FLAG(0xdabb, 1); + playSound(49, 3); + playAnimation(548); + inventory->add(0x11); + displayMessage(0x35b2); + return true; + } + + case 0x663c://Feather + setOns(0, 0); + playSound(5, 9); + playAnimation(511); + inventory->add(1); + disableObject(15); + return true; + + case 0x7f23://Use grenade on captains drawer + if (CHECK_FLAG(0xDBDF, 3)) { + playSound(5, 3); + playAnimation(870); + playSound(54, 15); + playAnimation(871); + SET_FLAG(0xDBE6, 1); + setOns(1, 0x66); + moveTo(224, 194, true); + debug(0, "FIXME: add cut message: 57DF"); + inventory->remove(0x59); + } else { + displayMessage(0x5de2); + } + return true; + + case 0x509a: + moveTo(203, 169); + setOns(1, 0); + playSound(5); + playAnimation(543); + inventory->add(15); + disableObject(9); + return true; + + case 0x78e0: + moveTo(203, 169); + return false; + + case 0x7919: + if (!CHECK_FLAG(0xDBA5, 1)) + return false; + displayMessage(0x3E98); + return true; + + case 0x7950: + if (!CHECK_FLAG(0xDBB1, 1)) + return false; + + displayMessage(0x3DAF); + return true; + + case 0x8174: + setOns(0, 0); + playSound(5); + playAnimation(542); + setOns(1, 15); + disableObject(3); + enableObject(9); + return true; + + case 0x8312: //hedgehog + plastic apple + playSound(5); + Dialog::show(scene, 0x3000); + setLan(1, 0); + playAnimation(562); + playAnimation(563, 1); + disableObject(6); + displayMessage(0x363f); + inventory->remove(27); + inventory->add(28); + return true; + + case 0x84c7: + playSound(20); + playAnimation(530); + loadScene(16, 236, 95, 1); + setOns(0, 9); + playAnimation(531); + playSound(36); + playAnimation(532); + playAnimation(533); + playMusic(9); + return true; + + case 0x8538://Sharpen sickle on well + setOns(2, 0); + //TODO: Remove handle sprite + playAnimation(643); + inventory->remove(0x2c); + inventory->add(0x2e); + return true; + + case 0x85eb: + if (CHECK_FLAG(0xDBB0, 1)) { + enableObject(6); + playSound(25); + playAnimation(559); + setOns(1, 23); + SET_FLAG(0xDBB0, 2); + } else + displayMessage(0x3d86); + + return true; + + case 0x863d: + playSound(12); + playAnimation(554); + inventory->remove(19); + inventory->add(22); + return true; + + case 0x8665: + playSound(5); + playAnimation(567); + inventory->remove(12); + inventory->add(33); + return true; + + case 0x86a9: //correcting height of the pole with spanner + if (CHECK_FLAG(0xDB92, 1)) { + displayMessage(0x3d40); + } else { + SET_FLAG(0xDB92, 1); + Dialog::show(scene, 0x0fcd); + playSound(5); + playAnimation(506, 1); + playAnimation(504); + setOns(0, 0); + playSound(24); + playAnimation(505); + displayMessage(0x3cfb); + playAnimation(507, 1); + setOns(0, 4); + Object * obj = scene->getObject(3); + obj->rect.top += 20; + obj->rect.bottom += 20; + playSound(10); + playAnimation(503, 1); + setLan(1, 0, 22); + scene->getObject(1, 22)->enabled = 0; + scene->getObject(13, 20)->enabled = 0; + setLan(1, 0); + disableObject(1); + disableObject(2); + disableObject(14); + disableObject(15); + disableObject(16); + moveTo(162, 164); + displayMessage(0x3d01, 0xe5); + displayMessage(0x3d20, 0xd8); + moveTo(162, 191); + setOns(1, 0); + setOns(2, 0); + setOns(3, 0); + setOns(4, 0); + scene->getWalkbox(0)->rect.clear(); + playSound(62); + //patch lan, 1 + displayMessage(0x3d3a); + scene->getObject(7)->actor_rect.left = 228; + scene->getObject(7)->actor_rect.top = 171; + scene->getObject(8)->actor_rect.left = 290; + scene->getObject(8)->actor_rect.top = 171; + } + return true; + + case 0x88c9: //give flower to old lady + if (CHECK_FLAG(0xDB9A, 1)) + return processCallback(0x890b); + + playAnimation(523, 1); + inventory->remove(10); + SET_FLAG(0xDB9A, 1); + processCallback(0x88DE); + return true; + + case 0x890b: + Dialog::pop(scene, 0xDAF0); + return true; + + case 0x8918://give flower to old lady + if (CHECK_FLAG(0xDB9A, 1)) + return processCallback(0x890B); + + playAnimation(523, 1); + inventory->remove(11); + SET_FLAG(0xDB9A, 1); + processCallback(0x88DE); + return true; + + case 0x88de: + playSound(5); + Dialog::show(scene, 0x1B5F); + playAnimation(537); + playAnimation(538, 1); + Dialog::show(scene, 0x1BE0); + return true; + + case 0x892d: + if (CHECK_FLAG(0xDB9B, 1)) + return processCallback(0x89aa); + + processCallback(0x8942); + inventory->remove(10); + SET_FLAG(0xDB9B, 1); + return true; + + case 0x8942: + playSound(5); + Dialog::show(scene, 0x2293); + playAnimation(540); + playAnimation(539, 1); + Dialog::show(scene, 0x24b1); + Dialog::show(scene, 0x24d7); + Dialog::show(scene, 0x2514); + moveTo(scene->getPosition().x, scene->getPosition().y + 1); + Dialog::show(scene, 0x2570); + return true; + + case 0x89aa: + Dialog::pop(scene, 0xdb02); + return true; + + case 0x89b7: + if (CHECK_FLAG(0xDB9B, 1)) + return processCallback(0x89aa); + + processCallback(0x8942); + inventory->remove(11); + SET_FLAG(0xDB9B, 1); + return true; + + case 0x89cc: + inventory->remove(23); + playSound(5); + Dialog::show(scene, 0x2634); + playAnimation(555); + playAnimation(556, 1); + playAnimation(557); + playAnimation(558, 1); + Dialog::show(scene, 0x2971); + inventory->add(24); + return true; + + case 0x8a22: + playAnimation(560); + playSound(45); + inventory->remove(26); + inventory->add(27); + Dialog::show(scene, 0x1ecd); + Dialog::show(scene, 0x1f09); + SET_FLAG(0xDBB1, 1); + return true; + + case 0x8b82: //use fan on laundry + setOns(0, 0); + playSound(5); + playAnimation(602); + displayMessage(0x464a); + playAnimation(603); + setOns(0, 27); + SET_FLAG(0xDBA5, 1); + return true; + + case 0x8bfc://Give bone to dog + displayMessage(0x3c31); + playSound(5, 3); + playAnimation(657, 0, true); + playAnimation(658, 1, true); + waitAnimation(); + + playAnimation(659, 1); + + displayMessage(0x3c3d); + inventory->remove(36); + SET_FLAG(0xDBAD, 1); + //TODO:Adjust Walkboxes + return true; + + case 0x8c6e://Use car jack on rock + playSound(5, 3); + playAnimation(592); + playSound(1, 5); + playAnimation(593); + setOns(0, 28); + disableObject(35); + enableObject(1); + inventory->remove(35); + return true; + + case 0x8cc8://Cut bush with sickle + moveTo(Common::Point(234, 152)); + setOns(1, 45); + playAnimation(645); + playAnimation(646); + playAnimation(647); + SET_FLAG(0xdaca, 1); + inventory->remove(0x2e); + disableObject(2); + return true; + + case 0x8f1d: + Dialog::show(scene, 0x2dd6); + displayMessage(0x34c7); + setLan(3, 0); + setLan(4, 0); + playSound(56); + playAnimation(516); + playAnimation(517, 2); + playAnimation(518, 3); + disableObject(2); + disableObject(3); + inventory->remove(2); + SET_FLAG(0xDB96, 1); + return true; + + case 0x9054: //mouse hole + if (CHECK_FLAG(0xDBAB, 1)) { + displayMessage(0x3c0b); + } else { + playSound(5); + moveTo(99, scene->getPosition().y); + playAnimation(632); + setOns(5, 40); + moveTo(239, 139, true); + playAnimation(633); + SET_FLAG(0xDBA8, 1); + inventory->remove(47); + if (!CHECK_FLAG(0xDBAA, 1)) { + SET_FLAG(0xDBAA, 1); + displayMessage(0x3b8b); + } + } + return true; + + case 0x98fa://Right click to open toolbox + inventory->remove(3); + inventory->add(4); + inventory->add(35); + inventory->activate(false); + inventory->resetSelectedObject(); + displayMessage(0x3468); + return true; + + case 0x9910: + inventory->remove(4); + inventory->add(5); + inventory->activate(false); + inventory->resetSelectedObject(); + displayMessage(0x3490); + return true; + + + //very last part of the game: + + + case 0x6be1: //handle to the bathroom + if (!CHECK_FLAG(0xDBD9, 1)) { + displayMessage(0x5326); //i'd better catch johnny + } else { + playSound(88); + playAnimation(808); + loadScene(36, 41, 195); + } + return true; + + case 0x6bad: + playAnimation(971); + loadScene(32, 139, 199); + return true; + + case 0x9c79: + if (scene->getId() != 36) { + displayMessage(0x52a9); + } else if (CHECK_FLAG(0xDBF1, 1)) { + displayMessage(0x52F6); + } else { + SET_FLAG(0xDBF1, 1); + moveTo(102, 195); + playAnimation(794); + //scene->getWalkbox(0)->rect.left = 0; + //scene->getWalkbox(0)->rect.top = 0; + moveTo(151, 197); + playAnimation(795); + moveTo(186, 198, true); + moveTo(220, 198); + scene->getWalkbox(0)->rect.top = 200; + + Object * obj = scene->getObject(1); + obj->actor_rect.left = obj->actor_rect.right = 270; + obj->actor_rect.top = obj->actor_rect.bottom = 193; + obj->actor_orientation = 2; + + obj = scene->getObject(3); + obj->actor_rect.left = obj->actor_rect.right = 254; + obj->actor_rect.top = obj->actor_rect.bottom = 193; + obj->actor_orientation = 1; + SET_FLAG(0xDBD7, 1); + } + return true; + + case 0x66b5: + playAnimation(969); + playSound(89); + loadScene(33, 319, 181); + return true; + } + + //unimplemented callback :( + for(uint i = 0; i < 32; ++i) { + debug(0, "code[%u] = %02x ", i, code[i]); + } + //error("invalid callback %04x called", addr); + debug(0, "invalid callback %04x called", addr); + return true; +} diff --git a/engines/teenagent/detection.cpp b/engines/teenagent/detection.cpp new file mode 100644 index 0000000000..7519448e6e --- /dev/null +++ b/engines/teenagent/detection.cpp @@ -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 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/detection.cpp $ + * $Id: detection.cpp 215 2009-08-14 07:11:27Z megath $ + */ + + +#include "engines/advancedDetector.h" +#include "base/plugins.h" +#include "teenagent/teenagent.h" +#include "common/system.h" +#include "common/savefile.h" + +static const PlainGameDescriptor teenAgentGames[] = { + { "teenagent", "Teen agent" }, + { 0, 0 } +}; + + +static const ADGameDescription teenAgentGameDescriptions[] = { + { + "teenagent", + "", + AD_ENTRY1s("teenagnt.exe", "b886cae8f875ea5eaefed04a8cc3c8a1", 152690), + Common::EN_ANY, + Common::kPlatformPC, + ADGF_NO_FLAGS, + Common::GUIO_NONE + }, + AD_TABLE_END_MARKER +}; + +static const ADParams detectionParams = { + (const byte *)teenAgentGameDescriptions, + sizeof(ADGameDescription), + 512, + teenAgentGames, + 0, + "teenagent", + 0, + 0, + Common::GUIO_NONE +}; + +#define MAX_SAVES 20 + +class TeenAgentMetaEngine : public AdvancedMetaEngine { +public: + TeenAgentMetaEngine() : AdvancedMetaEngine(detectionParams) { + } + + virtual const char *getName() const { + return "Teen Agent Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "TEENAGENT demo and TEENAGENT name copyright (c) Metropolis 1994."; + } + + virtual bool hasFeature(MetaEngineFeature f) const { + switch (f) { + case kSupportsListSaves: + case kSupportsDeleteSave: + case kSupportsLoadingDuringStartup: + //case kSavesSupportThumbnail: + return true; + default: + return false; + } + } + + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new TeenAgent::TeenAgentEngine(syst); + } + return desc != 0; + } + +// virtual const ADGameDescription *fallbackDetect(const Common::FSList &fslist) const { +// return 0; +// } + + static Common::String generateGameStateFileName(const char *target, int slot) { + char slotStr[16]; + snprintf(slotStr, sizeof(slotStr), ".%d", slot); + return slotStr; + } + + virtual SaveStateList listSaves(const char *target) const { + Common::String pattern = target; + pattern += ".*"; + + Common::StringList filenames = g_system->getSavefileManager()->listSavefiles(pattern); + bool slotsTable[MAX_SAVES]; + memset(slotsTable, 0, sizeof(slotsTable)); + SaveStateList saveList; + for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + int slot; + const char *ext = strrchr(file->c_str(), '.'); + if (ext && (slot = atoi(ext + 1)) >= 0 && slot < MAX_SAVES) { + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); + if (in) { + slotsTable[slot] = true; + delete in; + } + } + } + for (int slot = 0; slot < MAX_SAVES; ++slot) { + if (slotsTable[slot]) { + char description[64]; + snprintf(description, sizeof(description), "teenagent.%02d", slot); + saveList.push_back(SaveStateDescriptor(slot, description)); + } + } + return saveList; + } + + virtual int getMaximumSaveSlot() const { + return MAX_SAVES - 1; + } + + virtual void removeSaveState(const char *target, int slot) const { + Common::String filename = generateGameStateFileName(target, slot); + g_system->getSavefileManager()->removeSavefile(filename); + } +}; + +#if PLUGIN_ENABLED_DYNAMIC(TEENAGENT) + REGISTER_PLUGIN_DYNAMIC(TEENAGENT, PLUGIN_TYPE_ENGINE, TeenAgentMetaEngine); +#else + REGISTER_PLUGIN_STATIC(TEENAGENT, PLUGIN_TYPE_ENGINE, TeenAgentMetaEngine); +#endif diff --git a/engines/teenagent/dialog.cpp b/engines/teenagent/dialog.cpp new file mode 100644 index 0000000000..1ecffeefa0 --- /dev/null +++ b/engines/teenagent/dialog.cpp @@ -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 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/objects.h $ + * $Id: objects.h 172 2009-08-11 08:06:58Z megath $ + */ + +#include "dialog.h" +#include "resources.h" +#include "scene.h" + +using namespace TeenAgent; + +void Dialog::show(Scene * scene, uint16 addr, uint16 animation) { + debug(0, "Dialog::show(%04x, %u)", addr, animation); + Resources * res = Resources::instance(); + int n = 0; + Common::String message; + byte color = 0xd1; + + while (n < 4) { + byte c = res->eseg.get_byte(addr++); + switch(c) { + case 0: + ++n; + if (n == 3) { + color = color == 0xd1? 0xd0: 0xd1; + //debug(0, "changing color", message); + } + continue; + case 0xff: + { + SceneEvent e(SceneEvent::WaitForAnimation); + scene->push(e); + } + ++n; + continue; + default: + if (n > 1) { + if (!message.empty()) { + if (animation != 0) { + SceneEvent e(SceneEvent::PlayAnimation); + e.animation = animation; + e.color = 0x83; //3rd slot, async animation + scene->push(e); + } + SceneEvent e(SceneEvent::Message); + e.message = message; + e.color = color; + scene->push(e); + } + message = (const char *)Resources::instance()->eseg.ptr(addr - 1); + } else if (n == 1) { + message += '\n'; + message += (const char *)Resources::instance()->eseg.ptr(addr - 1); + } else if (n == 0 && message.empty()) { + message = (const char *)Resources::instance()->eseg.ptr(addr - 1); + } + n = 0; + } + } + if (!message.empty()) { + if (animation != 0) { + SceneEvent e(SceneEvent::PlayAnimation); + e.animation = animation; + e.color = 0x83; //3rd slot, async animation + scene->push(e); + } //copy paste ninja was here + SceneEvent e(SceneEvent::Message); + e.message = message; + e.color = color; + scene->push(e); + } +} + +uint16 Dialog::pop(Scene *scene, uint16 addr, uint16 animation) { + debug(0, "Dialog::pop(%04x, %u)", addr, animation); + Resources * res = Resources::instance(); + uint16 next; + do { + next = res->dseg.get_word(addr); + addr += 2; + } while(next == 0); + uint16 next2 = res->dseg.get_word(addr); + if (next2 != 0xffff) + res->dseg.set_word(addr - 2, 0); + show(scene, next, animation); + return next; +} diff --git a/engines/teenagent/dialog.h b/engines/teenagent/dialog.h new file mode 100644 index 0000000000..7bac3a0d4f --- /dev/null +++ b/engines/teenagent/dialog.h @@ -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 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/objects.h $ + * $Id: objects.h 172 2009-08-11 08:06:58Z megath $ + */ + +#ifndef TEENAGENT_DIALOG_H__ +#define TEENAGENT_DIALOG_H__ + +#include "common/endian.h" +#include "common/str.h" + +namespace TeenAgent { + +class Scene; +class Dialog { +public: + static uint16 pop(Scene *scene, uint16 addr, uint16 animation = 0); + static void show(Scene *scene, uint16 addr, uint16 animation = 0); +}; +} + +#endif + diff --git a/engines/teenagent/font.cpp b/engines/teenagent/font.cpp new file mode 100644 index 0000000000..b0527011f3 --- /dev/null +++ b/engines/teenagent/font.cpp @@ -0,0 +1,142 @@ +/* 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/font.cpp $ + * $Id: font.cpp 242 2009-08-15 11:44:27Z megath $ + */ + + +#include "font.h" +#include "resources.h" + +using namespace TeenAgent; + +Font::Font() : grid_color(0xd0), color(0xd1), data(0) { +} + +void Font::load(int id) { + delete[] data; + data = NULL; + + Common::SeekableReadStream * s = Resources::instance()->varia.getStream(id); + if (s == NULL) + error("loading font %d failed", id); + + data = new byte[s->size()]; + s->read(data, s->size()); + debug(0, "font size: %d", s->size()); +} + +uint Font::render(Graphics::Surface *surface, int x, int y, char c) { + unsigned idx = (unsigned char)c; + if (idx < 0x20 || idx >= 0x81) { + debug(0, "unhandled char 0x%02x", idx); + return 0; + } + idx -= 0x20; + byte * glyph = data + READ_LE_UINT16(data + idx * 2); + + uint h = glyph[0], w = glyph[1]; + if (surface == NULL || surface->pixels == NULL) + return w; + + //debug(0, "char %c, width: %dx%d", c, w, h); + glyph += 2; + byte * dst = (byte *)surface->getBasePtr(x, y); + for(uint i = 0; i < h; ++i) { + for(uint j = 0; j < w; ++j) { + byte v = *glyph++; + switch(v) { + case 1: + dst[j] = 0; + break; + case 2: + dst[j] = color; + break; + } + } + dst += surface->pitch; + } + return w - 1; +} + +static uint find_in_str(const Common::String &str, char c, uint pos = 0) { + while(pos < str.size() && str[pos] != c) ++pos; + return pos; +} + +uint Font::render(Graphics::Surface *surface, int x, int y, const Common::String &str, bool show_grid) { + const int height = 10; + if (surface != NULL) { + uint max_w = render(NULL, 0, 0, str, false); + if (show_grid) + grid(surface, x - 4, y - 2, max_w + 8, 8 + 6, grid_color); + + uint i = 0, j; + do { + j = find_in_str(str, '\n', i); + Common::String line(str.c_str() + i, j - i); + //debug(0, "line: %s", line.c_str()); + + uint w = render(NULL, 0, 0, line, false); + int xp = x + (max_w - w) / 2; + for (uint k = 0; k < line.size(); ++k) { + xp += render(surface, xp, y, line[k]); + } + + y += height; + i = j + 1; + } while(i < str.size()); + return max_w; + } else { + //surface == NULL; + uint w = 0, max_w = 0; + for (uint i = 0; i < str.size(); ++i) { + char c = str[i]; + if (c == '\n') { + y += height; + if (w > max_w) + max_w = w; + w = 0; + continue; + } + w += render(NULL, 0, 0, c); + } + if (w > max_w) + max_w = w; + + return max_w; + } +} + +void Font::grid(Graphics::Surface *surface, int x, int y, int w, int h, byte color) { + byte * dst = (byte *)surface->getBasePtr(x, y); + for(int i = 0; i < h; ++i) { + for(int j = 0; j < w; ++j) { + if (((i ^ j) & 1) == 0) + dst[j] = color; + } + dst += surface->pitch; + } +} + +Font::~Font() { + delete[] data; +} diff --git a/engines/teenagent/font.h b/engines/teenagent/font.h new file mode 100644 index 0000000000..1012a1cf33 --- /dev/null +++ b/engines/teenagent/font.h @@ -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 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/font.h $ + * $Id: font.h 173 2009-08-11 08:10:22Z megath $ + */ + +#ifndef TEENAGENT_FONT_H__ +#define TEENAGENT_FONT_H__ + +#include "graphics/surface.h" + +namespace TeenAgent { +class Font { +public: + byte grid_color, color; + + Font(); + void load(int id); + uint render(Graphics::Surface *surface, int x, int y, const Common::String &str, bool grid = false); + uint render(Graphics::Surface *surface, int x, int y, char c); + static void grid(Graphics::Surface *surface, int x, int y, int w, int h, byte color); + + ~Font(); +private: + byte *data; +}; +} + +#endif + diff --git a/engines/teenagent/inventory.cpp b/engines/teenagent/inventory.cpp new file mode 100644 index 0000000000..6ee720d3f5 --- /dev/null +++ b/engines/teenagent/inventory.cpp @@ -0,0 +1,285 @@ +/* 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/objects.h $ + * $Id: objects.h 172 2009-08-11 08:06:58Z megath $ + */ + +#include "inventory.h" +#include "resources.h" +#include "common/stream.h" +#include "objects.h" +#include "teenagent.h" + +using namespace TeenAgent; + +void Inventory::init(TeenAgentEngine * engine) { + _engine = engine; + _active = false; + Resources * res = Resources::instance(); + + Common::SeekableReadStream * s = res->varia.getStream(3); + assert(s != NULL); + debug(0, "loading inventory background..."); + background.load(s, Surface::TypeOns); + + items = res->varia.getStream(4); + assert(items != NULL); + + byte offsets = items->readByte(); + assert(offsets == 92); + for(byte i = 0; i < offsets; ++i) { + offset[i] = items->readUint16LE(); + } + objects = res->dseg.ptr(0xc4a4); + inventory = res->dseg.ptr(0xc48d); + + for(int y = 0; y < 4; ++y) + for(int x = 0; x < 6; ++x) { + int i = y * 6 + x; + graphics[i].rect.left = 28 + 45 * x - 1; + graphics[i].rect.top = 23 + 31 * y - 1; + graphics[i].rect.right = graphics[i].rect.left + 40; + graphics[i].rect.bottom = graphics[i].rect.top + 26; + } + + hovered_obj = selected_obj = NULL; +} + +bool Inventory::has(byte item) const { + for(int i = 0; i < 24; ++i) { + if (inventory[i] == item) + return true; + } + return false; +} + +void Inventory::remove(byte item) { + debug(0, "removing %02x from inventory", item); + int i; + for(i = 0; i < 24; ++i) { + if (inventory[i] == item) { + break; + } + } + for(; i < 23; ++i) { + inventory[i] = inventory[i + 1]; + graphics[i].free(); + } + inventory[23] = 0; + graphics[23].free(); +} + +void Inventory::clear() { + debug(0, "clearing inventory"); + for(int i = 0; i < 24; ++i) { + inventory[i] = 0; + graphics[i].free(); + } +} + + +void Inventory::add(byte item) { + if (has(item)) + return; + debug(0, "adding %02x to inventory", item); + for(int i = 0; i < 24; ++i) { + if (inventory[i] == 0) { + inventory[i] = item; + return; + } + } + error("no room for item %02x", item); +} + +bool Inventory::processEvent(const Common::Event &event) { + Resources * res = Resources::instance(); + + switch(event.type) { + case Common::EVENT_MOUSEMOVE: + mouse = event.mouse; + if (!active() && event.mouse.y < 5) { + activate(true); + return _active; + } + + if (event.mouse.x < 17 || event.mouse.x >= 303 || event.mouse.y >= 153) { + activate(false); + return _active; + } + + if (!_active) + return false; + + hovered_obj = NULL; + + for(int i = 0; i < 24; ++i) { + byte item = inventory[i]; + if (item == 0) + continue; + + graphics[i].hovered = graphics[i].rect.in(mouse); + if (graphics[i].hovered) + hovered_obj = (InventoryObject *)res->dseg.ptr(READ_LE_UINT16(objects + item * 2)); + } + return true; + + case Common::EVENT_LBUTTONDOWN: { + //check combine + if (selected_obj == NULL || hovered_obj == NULL) + return _active; + + int id1 = selected_obj->id; + int id2 = hovered_obj->id; + + debug(0, "combine(0x%02x, 0x%02x)!", id1, id2); + byte * table = res->dseg.ptr(0xC335); + while(table[0] != 0 && table[1] != 0) { + if ( + (id1 == table[0] && id2 == table[1]) || + (id2 == table[0] && id1 == table[1]) + ) { + remove(id1); + remove(id2); + add(table[2]); + uint16 msg = READ_LE_UINT16(table + 3); + _engine->displayMessage(msg); + _engine->playSoundNow(69); + activate(false); + resetSelectedObject(); + return true; + } + table += 5; + } + _engine->displayMessage(0xc3e2); + activate(false); + resetSelectedObject(); + return true; + } + + case Common::EVENT_RBUTTONDOWN: + if (!_active) + return false; + + if (hovered_obj != NULL) { + byte id = hovered_obj->id; + debug(0, "rclick object %u", id); + uint i = 0; + for(byte * table = res->dseg.ptr(0xBB6F + 3); //original offset + 3 bytes. + table[0] != 0 && i < 7; table += 3, ++i) { + if (table[0] == id) { + resetSelectedObject(); + activate(false); + if (_engine->processCallback(READ_LE_UINT16(table + 1))) + return true; + else { + //some callbacks returns false if they need to display default description + _engine->displayMessage(hovered_obj->description()); + activate(false); + resetSelectedObject(); + return true; + } + } + } + } + + selected_obj = hovered_obj; + if (selected_obj) + debug(0, "selected object %s", selected_obj->name); + return true; + + case Common::EVENT_KEYDOWN: + if (_active && event.kbd.keycode == Common::KEYCODE_ESCAPE) { + activate(false); + return true; + } + return false; + + case Common::EVENT_LBUTTONUP: + case Common::EVENT_RBUTTONUP: + return _active; + + default: + return false; + } +} + + +void Inventory::Item::free() { + animation.free(); + surface.free(); +} + +void Inventory::Item::render(Inventory * inventory, InventoryObject *obj, Graphics::Surface * dst) { + Resources * res = Resources::instance(); + + rect.render(dst, hovered? 233: 234); + if (obj->animated) { + if (animation.empty()) { + debug(0, "loading item %d from offset %x", obj->id, inventory->offset[obj->id - 1]); + inventory->items->seek(inventory->offset[obj->id - 1]); + animation.load(inventory->items, Animation::TypeInventory); + } + Surface * s = animation.currentFrame(); + if (s != NULL) + s->render(dst, rect.left + 1, rect.top + 1); + } else { + if (surface.empty()) { + debug(0, "loading item %d from offset %x", obj->id, inventory->offset[obj->id - 1]); + inventory->items->seek(inventory->offset[obj->id - 1]); + surface.load(inventory->items, Surface::TypeOns); + } + surface.render(dst, rect.left + 1, rect.top + 1); + } + + Common::String name; + if (inventory->selected_obj && inventory->selected_obj != inventory->hovered_obj) { + name = inventory->selected_obj->name; + name += " & "; + } + name += obj->name; + + if (hovered) { + int w = res->font7.render(NULL, 0, 0, name, true); + res->font7.render(dst, (320 - w) / 2, 180, name, true); + } +} + +void Inventory::render(Graphics::Surface * surface) { + if (!_active) + return; + + background.render(surface); + Resources * res = Resources::instance(); + + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 6; x++) { + int idx = x + 6 * y; + byte item = inventory[idx]; + if (item == 0) + continue; + + //debug(0, "%d,%d -> %u", x0, y0, item); + + InventoryObject * obj = (InventoryObject *)res->dseg.ptr(READ_LE_UINT16(objects + item * 2)); + graphics[idx].render(this, obj, surface); + } + } +} diff --git a/engines/teenagent/inventory.h b/engines/teenagent/inventory.h new file mode 100644 index 0000000000..f2f8f94a52 --- /dev/null +++ b/engines/teenagent/inventory.h @@ -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 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/objects.h $ + * $Id: objects.h 172 2009-08-11 08:06:58Z megath $ + */ + +#ifndef TEENAGENT_INVENTORY_H__ +#define TEENAGENT_INVENTORY_H__ + +#include "surface.h" +#include "animation.h" +#include "common/events.h" +#include "objects.h" + +namespace TeenAgent { + +struct InventoryObject; +class TeenAgentEngine; + +class Inventory { +public: + void init(TeenAgentEngine * engine); + void render(Graphics::Surface * surface); + + void clear(); + void add(byte item); + bool has(byte item) const; + void remove(byte item); + + void activate(bool a) { _active = a; } + bool active() const { return _active; } + + bool processEvent(const Common::Event &event); + + InventoryObject *selectedObject() { return selected_obj; } + void resetSelectedObject() { selected_obj = NULL; } + +private: + TeenAgentEngine *_engine; + Surface background; + Common::SeekableReadStream *items; + uint16 offset[92]; + + byte *objects; + byte *inventory; + struct Item { + Animation animation; + Surface surface; + Rect rect; + bool hovered; + + Item() : hovered(false) {} + void free(); + void render(Inventory *inventory, InventoryObject *obj, Graphics::Surface * surface); + } graphics[24]; + + bool _active; + Common::Point mouse; + int hovered; + + InventoryObject *hovered_obj, *selected_obj; +}; +} + +#endif + diff --git a/engines/teenagent/module.mk b/engines/teenagent/module.mk new file mode 100644 index 0000000000..6432eba310 --- /dev/null +++ b/engines/teenagent/module.mk @@ -0,0 +1,26 @@ +MODULE := engines/teenagent + +MODULE_OBJS := \ + detection.o \ + teenagent.o \ + resources.o \ + pack.o \ + segment.o \ + scene.o \ + animation.o \ + font.o \ + surface.o \ + actor.o \ + callbacks.o \ + inventory.o \ + objects.o \ + music.o \ + dialog.o + +# This module can be built as a plugin +ifeq ($(ENABLE_TEENAGENT), DYNAMIC_PLUGIN) + PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/teenagent/music.cpp b/engines/teenagent/music.cpp new file mode 100644 index 0000000000..ba902e571a --- /dev/null +++ b/engines/teenagent/music.cpp @@ -0,0 +1,162 @@ +/* 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/old_engine/music.cpp $ + * $Id: music.cpp 121 2009-08-02 20:04:53Z megath $ + * + */ + +#include "music.h" +#include "resources.h" + +using namespace TeenAgent; + +static uint32 noteToPeriod[3][12] = { + {855, 807, 761, 720, 678, 640, 604, 569, 537, 508, 480, 453}, + {428, 404, 381, 360, 338, 320, 301, 285, 269, 254, 239, 226}, + {214, 201, 189, 179, 170, 160, 151, 143, 135, 127, 120, 113} +}; + +MusicPlayer::MusicPlayer() : Paula(false, 44100, 5000), _id(0) { +} + +MusicPlayer::~MusicPlayer() { +} + +bool MusicPlayer::load(int id) { + Resources * res = Resources::instance(); + + Common::SeekableReadStream *stream = res->mmm.getStream(id); + if (stream == NULL) + return false; + + char header[4]; + stream->read(header, 4); + //check header? + + memset(_samples, 0, sizeof(_samples)); + + // Load the samples + + sampleCount = stream->readByte(); + + debug(0, "sampleCount = %d", sampleCount); + + for (byte currSample = 0; currSample < sampleCount; currSample++) { + byte sample = stream->readByte(); + + // Load the sample data + byte sampleResource = ((sample >> 4) & 0x0F) * 10 + (sample & 0x0F); + debug(0, "currSample = %d, sample = 0x%02x, resource: %d", currSample, sample, sampleResource); + uint32 sampleSize = res->sam_mmm.get_size(sampleResource); + Common::SeekableReadStream *in = res->sam_mmm.getStream(sampleResource); + + if (in == 0) { + warning("load: invalid sample %d (0x%02x)", sample, sample); + _samples[sample].data = NULL; + _samples[sample].size = 0; + continue; + } + + byte *sampleData = new byte[sampleSize]; + in->read(sampleData, sampleSize); + + // Convert the sample from signed to unsigned + for (uint32 i = 0; i < sampleSize; i++) + *sampleData ^= 0x80; + + delete _samples[sample].data; + _samples[sample].data = sampleData; + _samples[sample].size = sampleSize; + } + + // Load the music data + + _rows.clear(); + + Row row; + row.channels[0].sample = 0; + row.channels[1].sample = 0; + row.channels[2].sample = 0; + + row.channels[0].volume = 64; + row.channels[1].volume = 64; + row.channels[2].volume = 64; + + while (!stream->eos()) { + + byte cmd = stream->readByte(); + + if ((cmd & 0xF0) == 0x50) { + row.channels[(cmd & 0x0F) - 1].sample = stream->readByte(); + } else if ((cmd & 0xF0) == 0x40) { + row.channels[(cmd & 0x0F) - 1].volume = (stream->readByte() + 1) * 2; + } else { + row.channels[0].note = cmd; + row.channels[1].note = stream->readByte(); + row.channels[2].note = stream->readByte(); + _rows.push_back(row); + } + + } + _currRow = 0; + _id = id; + return true; +} + +void MusicPlayer::start() { + _currRow = 0; + startPaula(); +} + +void MusicPlayer::stop() { + stopPaula(); +} + +void MusicPlayer::interrupt() { + _currRow %= _rows.size(); + + Row *row = &_rows[_currRow]; + for (int chn = 0; chn < 3; ++chn) { + setChannelVolume(chn, row->channels[chn].volume); + + //debug(0, "row->channels[%d].volume = %d", chn, row->channels[chn].volume); + + byte sample = (row->channels[chn].sample); + if (row->channels[chn].note != 0 && sample != 0) { + + //debug(0, "row->channels[%d].note = %d", chn, row->channels[chn].note); + //debug(0, "row->channels[%d].sample = %d", chn, row->channels[chn].sample); + + byte note = row->channels[chn].note; + if (_samples[sample].size == 0) { + warning("interrupt: invalid sample %u (0x%02x)", sample, sample); + continue; + } + + setChannelData(chn, (const int8*)_samples[sample].data, NULL, _samples[sample].size, 0); + setChannelPeriod(chn, noteToPeriod[((note >> 4) & 0x0F) - 1][(note & 0x0F)]); + } + } + + //debug(0, "------------------------------------------------"); + + ++_currRow; +} diff --git a/engines/teenagent/music.h b/engines/teenagent/music.h new file mode 100644 index 0000000000..b76891ae7c --- /dev/null +++ b/engines/teenagent/music.h @@ -0,0 +1,77 @@ +/* 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/old_engine/music.h $ + * $Id: music.h 121 2009-08-02 20:04:53Z megath $ + * + */ + +#ifndef TEEN_MUSIC_H +#define TEEN_MUSIC_H + +#include "sound/mods/paula.h" + +namespace TeenAgent { + +class MusicPlayer : public Audio::Paula { +public: + + MusicPlayer(); + ~MusicPlayer(); + + bool load(int id); + int getId() const { return _id; } + + void start(); + void stop(); + +protected: + int _id; + + struct Row { + struct Channel{ + byte sample; + byte volume; + byte note; + Channel(): sample(0), volume(0), note(0) {} + } channels[3]; + }; + + struct { + const byte *data; + uint32 size; + } _samples[256]; + byte sampleCount; + + struct { + byte volume; + const byte *data; + uint32 size; + } _channels[3]; + + Common::Array _rows; + uint _currRow; + + void interrupt(); +}; + +} // End of namespace Teen + +#endif // TEEN_MUSIC_H diff --git a/engines/teenagent/objects.cpp b/engines/teenagent/objects.cpp new file mode 100644 index 0000000000..2bfe4bb5d9 --- /dev/null +++ b/engines/teenagent/objects.cpp @@ -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 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/objects.h $ + * $Id: objects.h 172 2009-08-11 08:06:58Z megath $ + */ + +#include "objects.h" +#include "common/debug.h" + +using namespace TeenAgent; + +void Rect::render(Graphics::Surface *surface, uint8 color) const { + surface->hLine(left, bottom, right, color); + surface->vLine(left, bottom, top, color); + surface->hLine(left, top, right, color); + surface->vLine(right, bottom, top, color); +} + +void Walkbox::dump() { + debug(0, "walkbox %02x %02x [%d, %d, %d, %d] %02x %02x %02x %02x ", unk00, unk01, + rect.left, rect.right, rect.top, rect.bottom, + unk0a, unk0b, unk0c, unk0d); +} + +void Object::dump() { + debug(0, "object: %u %u [%u,%u,%u,%u], actor: [%u,%u,%u,%u], orientation: %u, name: %s", id, enabled, + rect.left, rect.top, rect.right, rect.bottom, + actor_rect.left, actor_rect.top, actor_rect.right, actor_rect.bottom, + actor_orientation, name + ); +} + +Common::String Object::description(const char *name) { + const char * desc = name + strlen(name) + 1; + if (*desc == 0) + return Common::String(); + + Common::String result; + + while(*desc != 1 && *desc != 0) { + Common::String line; + while(*desc != 1 && *desc != 0) { + //debug(0, "%02x ", *desc); + line += *desc++; + } + + if (line.empty()) + break; + + ++desc; + result += line; + result += '\n'; + } + if (!result.empty()) + result.deleteLastChar(); + else + result = "Cool."; + return result; +} + + +Common::String Object::description() const { + return description(name); +} + +Common::String InventoryObject::description() const { + return Object::description(name); +} diff --git a/engines/teenagent/objects.h b/engines/teenagent/objects.h new file mode 100644 index 0000000000..04f1cd335c --- /dev/null +++ b/engines/teenagent/objects.h @@ -0,0 +1,104 @@ +/* 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/objects.h $ + * $Id: objects.h 282 2009-08-30 22:12:01Z megath $ + */ + + +#ifndef TEENAGENT_OBJECTS_H__ +#define TEENAGENT_OBJECTS_H__ + +#include "common/rect.h" +#include "graphics/surface.h" + +namespace TeenAgent { + +//move into separate header: + +#include "common/pack-start.h" // START STRUCT PACKING + +struct Rect { + uint16 left, top, right, bottom; + inline bool in(const Common::Point &point) const { + return point.x >= left && point.x <= right && point.y >= top && point.y <= bottom; + } + inline Common::Point center() const { + return Common::Point((right + left) / 2, (bottom + top) / 2); + } + inline bool valid() const { + return left < 320 && right < 320 && top < 200 && bottom < 200; + } + void render(Graphics::Surface *surface, uint8 color) const; + void dump() { + debug(0, "rect[%u, %u, %u, %u]", left, top, right, bottom); + } + + void clear() { + left = top = right = bottom = 0; + } +} PACKED_STRUCT; + +struct Object { + byte id; + Rect rect; + Rect actor_rect; + byte actor_orientation; + byte enabled; + char name[1]; + + enum {ActorUp = 1, ActorRight = 2, ActorDown = 3, ActorLeft = 4 }; + + void dump(); + static Common::String description(const char *name); + Common::String description() const; +} PACKED_STRUCT; + +struct InventoryObject { + byte id; + byte animated; + char name[1]; + Common::String description() const; +} PACKED_STRUCT; + +struct UseObject { + byte inventory_id; + byte object_id; + byte unk02; + uint16 x, y; + uint16 callback; +} PACKED_STRUCT; + +struct Walkbox { + byte unk00; + byte unk01; + Rect rect; + byte unk0a; + byte unk0b; + byte unk0c; + byte unk0d; + void dump(); +} PACKED_STRUCT; + +#include "common/pack-end.h" // END STRUCT PACKING + +} + +#endif diff --git a/engines/teenagent/pack.cpp b/engines/teenagent/pack.cpp new file mode 100644 index 0000000000..a0d9bbd499 --- /dev/null +++ b/engines/teenagent/pack.cpp @@ -0,0 +1,83 @@ +/* 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/pack.cpp $ + * $Id: pack.cpp 182 2009-08-11 21:16:14Z megath $ + */ + + +#include "pack.h" +#include "common/util.h" +#include "common/debug.h" + +using namespace TeenAgent; + +Pack::Pack() : count(0), offsets(0) {} + +Pack::~Pack() { + close(); +} + + +void Pack::close() { + delete[] offsets; + offsets = NULL; + file.close(); +} + + +void Pack::open(const Common::String &filename) { + file.open(filename); + count = file.readUint32LE(); + debug(0, "opened %s, found %u entries", filename.c_str(), count); + offsets = new uint32[count + 1]; + for(uint32 i = 0; i <= count; ++i) { + offsets[i] = file.readUint32LE(); + //debug(0, "%d: %06x", i, offsets[i]); + } +/* for(uint32 i = 0; i < count; ++i) { + debug(0, "%d: len = %d", i, offsets[i + 1] - offsets[i]); + } +*/ +} + +uint32 Pack::get_size(uint32 id) const { + if (id < 1 || id > count) + return 0; + return offsets[id] - offsets[id - 1]; +} + +uint32 Pack::read(uint32 id, byte *dst, uint32 size) const { + if (id < 1 || id > count) + return 0; + + file.seek(offsets[id - 1]); + uint32 rsize = offsets[id] - offsets[id - 1]; + uint32 r = file.read(dst, MIN(rsize, size)); + //debug(0, "read(%u, %u) = %u", id, size, r); + return r; +} + +Common::SeekableReadStream * Pack::getStream(uint32 id) const { + if (id < 1 || id > count) + return 0; + debug(0, "stream: %04x-%04x", offsets[id - 1], offsets[id]); + return new Common::SeekableSubReadStream(&file, offsets[id - 1], offsets[id], false); +} diff --git a/engines/teenagent/pack.h b/engines/teenagent/pack.h new file mode 100644 index 0000000000..5765151ac9 --- /dev/null +++ b/engines/teenagent/pack.h @@ -0,0 +1,49 @@ +/* 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/pack.h $ + * $Id: pack.h 182 2009-08-11 21:16:14Z megath $ + */ + + +#ifndef TEENAGENT_PACK_H__ +#define TEENAGENT_PACK_H__ + +#include "common/file.h" + +namespace TeenAgent { +class Pack { + mutable Common::File file; + uint32 count; + uint32 *offsets; + +public: + Pack(); + ~Pack(); + void open(const Common::String &filename); + void close(); + uint32 get_size(uint32 id) const; + uint32 read(uint32 id, byte *dst, uint32 size) const; + Common::SeekableReadStream * getStream(uint32 id) const; +}; + +} + +#endif diff --git a/engines/teenagent/resources.cpp b/engines/teenagent/resources.cpp new file mode 100644 index 0000000000..94a23d14a0 --- /dev/null +++ b/engines/teenagent/resources.cpp @@ -0,0 +1,144 @@ +/* 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/resources.cpp $ + * $Id: resources.cpp 274 2009-08-25 21:04:54Z megath $ + */ + +#include "resources.h" + +using namespace TeenAgent; + +Resources::Resources() {} + +Resources * Resources::instance() { + static Resources i; + return &i; +} + +void Resources::deinit() { + varia.close(); + off.close(); + on.close(); + ons.close(); + lan000.close(); + lan500.close(); + mmm.close(); + sam_mmm.close(); + sam_sam.close(); +} + +void Resources::loadArchives() { + off.open("off.res"); + varia.open("varia.res"); + on.open("on.res"); + ons.open("ons.res"); + lan000.open("lan_000.res"); + lan500.open("lan_500.res"); + mmm.open("mmm.res"); + sam_mmm.open("sam_mmm.res"); + sam_sam.open("sam_sam.res"); + + font7.load(7); + + Common::File exe; + if (!exe.open("Teenagnt.exe")) { + error("cannot open exe file"); + return; + } + exe.seek(0x0200); + cseg.read(&exe, 0xb3b0); //code + + exe.seek(0xb5b0); + dseg.read(&exe, 0xe790); //data + + exe.seek(0x1c890); + eseg.read(&exe, 0x8be2); + + exe.close(); +} + +void Resources::loadOff(Graphics::Surface &surface, byte * palette, int id) { + uint32 size = off.get_size(id); + if (size == 0) { + error("invalid background %d", id); + return; + } + byte buf[64768]; + off.read(id, buf, sizeof(buf)); + + byte * src = buf; + byte * dst = (byte *)surface.pixels; + memcpy(dst, src, 64000); + memcpy(palette, buf + 64000, 768); +} + +Common::SeekableReadStream * Resources::loadLan(uint32 id) const { + return id <= 500? loadLan000(id): lan500.getStream(id - 500); +} + +Common::SeekableReadStream * Resources::loadLan000(uint32 id) const { + switch(id) { + + case 81: + if (dseg.get_byte(0xDBAD)) + return lan500.getStream(160); + break; + + case 137: + if (dseg.get_byte(0xDBC5) == 1) { + if (dseg.get_byte(0xDBC6) == 1) + return lan500.getStream(203); + else + return lan500.getStream(202); + } + break; + + case 25: + if (dseg.get_byte(0xDBDF) == 2) { + return lan500.getStream(332); + } + break; + + case 37: + if (dseg.get_byte(0xdbe2) == 1) { + return lan500.getStream(351); + } else if (dseg.get_byte(0xdbe2) == 2) { + return lan500.getStream(364); + } + break; + + case 29: + if (dseg.get_byte(0xDBE7) == 1) { + return lan500.getStream(380); + } + + case 30: + if (dseg.get_byte(0xDBE7) == 1) { + return lan500.getStream(381); + } + + case 42: + if (dseg.get_byte(0xDBEC) == 1) { + return lan500.getStream(400); + } + } + return lan000.getStream(id); +} diff --git a/engines/teenagent/resources.h b/engines/teenagent/resources.h new file mode 100644 index 0000000000..d3fea56e95 --- /dev/null +++ b/engines/teenagent/resources.h @@ -0,0 +1,56 @@ +/* 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/resources.h $ + * $Id: resources.h 260 2009-08-19 07:29:19Z megath $ + */ + + +#ifndef TEENAGENT_RESOURCES_H__ +#define TEENAGENT_RESOURCES_H__ + +#include "pack.h" +#include "segment.h" +#include "font.h" +#include "graphics/surface.h" + +namespace TeenAgent { + +class Resources { +protected: + Resources(); +public: + static Resources * instance(); + void loadArchives(); + void deinit(); + void loadOff(Graphics::Surface &surface, byte *palette, int id); + Common::SeekableReadStream * loadLan(uint32 id) const; + Common::SeekableReadStream * loadLan000(uint32 id) const; + //void loadOn(Graphics::Surface &surface, int id, uint16 &dst, uint16 * flags); + //void loadOns(Graphics::Surface &surface, int id, uint16 &dst); + + Pack varia, off, on, ons, lan000, lan500, mmm, sam_mmm, sam_sam; + Segment cseg, dseg, eseg; + Font font7; +}; + +} + +#endif 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(); +} diff --git a/engines/teenagent/scene.h b/engines/teenagent/scene.h new file mode 100644 index 0000000000..88427f33d8 --- /dev/null +++ b/engines/teenagent/scene.h @@ -0,0 +1,166 @@ +/* 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.h $ + * $Id: scene.h 296 2009-09-01 19:55:58Z megath $ + */ + + +#ifndef TEENAGENT_SCENE_H__ +#define TEENAGENT_SCENE_H__ + +#include "surface.h" +#include "actor.h" +#include "common/system.h" +#include "common/list.h" + +namespace TeenAgent { + +struct Walkbox; +struct Object; + +class TeenAgentEngine; +class Dialog; + +struct SceneEvent { + enum Type { + None, Message, Walk, PlayAnimation, + LoadScene, SetOn, SetLan, PlayMusic, + PlaySound, EnableObject, WaitForAnimation + } type; + + Common::String message; + byte color; + uint16 animation; + byte orientation; + Common::Point dst; + byte scene; //fixme: put some of these to the union? + byte ons; + byte lan; + byte music; + byte sound; + byte object; + + SceneEvent(Type type_) : + type(type_), message(), color(0xd1), animation(0), orientation(0), dst(), + scene(0), ons(0), lan(0), music(0), sound(0), object(0) {} + + void clear() { + type = None; + message.clear(); + color = 0xd1; + orientation = 0; + animation = 0; + dst.x = dst.y = 0; + scene = 0; + ons = 0; + lan = 0; + music = 0; + sound = 0; + object = 0; + } + + inline bool empty() const { + return type == None; + } + + void dump() const { + debug(0, "event[%d]: %s[%02x], animation: %u, dst: (%d, %d) [%u], scene: %u, ons: %u, lan: %u, object: %u, music: %u, sound: %u", + (int)type, message.c_str(), color, animation, dst.x, dst.y, orientation, scene, ons, lan, object, music, sound + ); + } +}; + +class Scene { +public: + Scene(); + + void init(TeenAgentEngine *engine, OSystem * system); + void init(int id, const Common::Point &pos); + bool render(OSystem * system); + int getId() const { return _id; } + + void warp(const Common::Point & point, byte orientation = 0); + + void moveTo(const Common::Point & point, byte orientation = 0, bool validate = 0); + Common::Point getPosition() const { return position; } + + void displayMessage(const Common::String &str); + void setOrientation(uint8 o) { orientation = o; } + void playAnimation(byte idx, uint id); + void push(const SceneEvent &event); + + bool processEvent(const Common::Event &event); + + void clear(); + + byte * getOns(int id); + byte * getLans(int id); + + bool eventRunning() const { return !current_event.empty(); } + + Walkbox *getWalkbox(byte id) { return walkbox[id]; } + Object * getObject(int id, int scene_id = 0); + +private: + void loadOns(); + void loadLans(); + + byte palette[768]; + void setPalette(OSystem *system, const byte * palette, unsigned mul = 1); + static Common::Point messagePosition(const Common::String &str, const Common::Point & position); + + bool processEventQueue(); + inline void nextEvent() { + current_event.clear(); + processEventQueue(); + } + + TeenAgentEngine *_engine; + OSystem * _system; + + int _id; + Graphics::Surface background; + Surface on; + Surface *ons; + uint32 ons_count; + Animation animations[4], custom_animations[4]; + + Actor teenagent, teenagent_idle; + Common::Point position0, position, destination; + int progress, progress_total; + uint8 orientation; + + byte walkboxes; + Walkbox * walkbox[255]; + + Common::String message; + Common::Point message_pos; + + typedef Common::List EventList; + EventList events; + SceneEvent current_event; + + byte sound_id, sound_delay; +}; +} + +#endif + diff --git a/engines/teenagent/segment.cpp b/engines/teenagent/segment.cpp new file mode 100644 index 0000000000..f6b029ae34 --- /dev/null +++ b/engines/teenagent/segment.cpp @@ -0,0 +1,37 @@ +/* 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/segment.cpp $ + * $Id: segment.cpp 188 2009-08-12 07:22:11Z megath $ + */ + + +#include "segment.h" + +void Segment::read(Common::ReadStream *stream, uint32 s) { + _size = s; + _data = new byte[_size]; + stream->read(_data, _size); +} + +Segment::~Segment() { + delete[] _data; +} + diff --git a/engines/teenagent/segment.h b/engines/teenagent/segment.h new file mode 100644 index 0000000000..42b6cc0df9 --- /dev/null +++ b/engines/teenagent/segment.h @@ -0,0 +1,80 @@ +/* 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/segment.h $ + * $Id: segment.h 188 2009-08-12 07:22:11Z megath $ + */ + + +#ifndef TEENAGENT_SEGMENT_H__ +#define TEENAGENT_SEGMENT_H__ + +#include "common/stream.h" +#include "common/endian.h" + +class Segment { + uint32 _size; + byte * _data; + +public: + Segment() : _size(0), _data(0) {} + ~Segment(); + + void read(Common::ReadStream *s, uint32 _size); + + inline byte get_byte(uint32 offset) const { + assert(offset < _size); + return _data[offset]; + } + inline uint16 get_word(uint32 offset) const { + assert(offset + 1 < _size); + return READ_LE_UINT16(_data + offset); + } + inline uint32 get_quad(uint32 offset) const { + assert(offset + 3 < _size); + return READ_LE_UINT32(_data + offset); + } + inline void set_byte(uint32 offset, byte v) const { + assert(offset < _size); + _data[offset] = v; + } + inline void set_word(uint32 offset, uint16 v) const { + assert(offset + 1 < _size); + return WRITE_LE_UINT16(_data + offset, v); + } + inline void set_quad(uint32 offset, uint32 v) const { + assert(offset + 3 < _size); + return WRITE_LE_UINT32(_data + offset, v); + } + + const byte * ptr(uint32 addr) const { + assert(addr < _size); + return _data + addr; + } + + byte * ptr(uint32 addr) { + assert(addr < _size); + return _data + addr; + } + uint size() const { return _size; } +}; + +#endif + diff --git a/engines/teenagent/surface.cpp b/engines/teenagent/surface.cpp new file mode 100644 index 0000000000..154bbdb049 --- /dev/null +++ b/engines/teenagent/surface.cpp @@ -0,0 +1,95 @@ +/* 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/surface.cpp $ + * $Id: surface.cpp 214 2009-08-14 06:09:26Z megath $ + */ + + +#include "surface.h" +#include "pack.h" +#include "common/stream.h" +#include "common/debug.h" + +using namespace TeenAgent; + +Surface::Surface() : x(0), y(0) { + memset(flags, 0, sizeof(flags)); +} + +void Surface::load(Common::SeekableReadStream *stream, Type type) { + //debug(0, "load()"); + free(); + + x = y = 0; + memset(flags, 0, sizeof(flags)); + + if (type == TypeOn) { + byte fn = stream->readByte(); + if (stream->eos()) + return; + + for(byte i = 0; i < fn; ++i) { + flags[i] = stream->readUint16LE(); + debug(0, "flags[%u] = %u (0x%04x)", i, flags[i], flags[i]); + } + } + + uint16 w_ = stream->readUint16LE(); + uint16 h_ = stream->readUint16LE(); + + if (type != TypeLan) { + uint16 pos = stream->readUint16LE(); + x = pos % 320; + y = pos / 320; + } + + //debug(0, "declared info: %ux%u (%04xx%04x) -> %u,%u", w_, h_, w_, h_, x, y); + if (stream->eos() || w_ == 0) + return; + + if (w_ * h_ > stream->size()) {//rough but working + debug(0, "invalid surface %ux%u -> %u,%u", w_, h_, x, y); + return; + } + + //debug(0, "creating surface %ux%u -> %u,%u", w_, h_, x, y); + create(w_, h_, 1); + + stream->read(pixels, w_ * h_); +} + +void Surface::render(Graphics::Surface * surface, int dx, int dy, bool mirror) { + assert(x + w <= surface->w); + assert(y + h <= surface->h); + + byte *src = (byte *)pixels; + byte *dst = (byte *)surface->getBasePtr(dx + x, dy + y); + + for(int i = 0; i < h; ++i) { + for(int j = 0; j < w; ++j) { + byte p = src[j]; + if (p != 0xff) + dst[mirror? w - j - 1: j] = p; + } + dst += surface->pitch; + src += pitch; + } +} diff --git a/engines/teenagent/surface.h b/engines/teenagent/surface.h new file mode 100644 index 0000000000..857d256c05 --- /dev/null +++ b/engines/teenagent/surface.h @@ -0,0 +1,52 @@ +/* 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/surface.h $ + * $Id: surface.h 154 2009-08-10 20:10:23Z megath $ + */ + + +#ifndef TAGET_SURFACE_H__ +#define TAGET_SURFACE_H__ + +#include "graphics/surface.h" +#include "common/stream.h" + +namespace TeenAgent { + +class Pack; +class Surface : public Graphics::Surface { +public: + enum Type {TypeOn, TypeOns, TypeLan}; + + uint16 flags[255]; + uint16 x, y; + + Surface(); + void load(Common::SeekableReadStream * stream, Type type); + void render(Graphics::Surface * surface, int dx = 0, int dy = 0, bool mirror = false); + + bool empty() const { return pixels == NULL; } +}; + +} + +#endif + diff --git a/engines/teenagent/teenagent.cpp b/engines/teenagent/teenagent.cpp new file mode 100644 index 0000000000..2d5d42ba3c --- /dev/null +++ b/engines/teenagent/teenagent.cpp @@ -0,0 +1,484 @@ +/* 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/tagent.cpp $ + * $Id: tagent.cpp 304 2009-09-03 20:10:22Z megath $ + */ + + +#include "teenagent/teenagent.h" +#include "common/system.h" +#include "common/events.h" +#include "common/debug.h" +#include "common/savefile.h" +#include "common/config-manager.h" +#include "sound/mixer.h" +#include "scene.h" +#include "objects.h" +#include "music.h" + +using namespace TeenAgent; + +TeenAgentEngine::TeenAgentEngine(OSystem * system) : Engine(system), action(ActionNone) { + music = new MusicPlayer(); +} + +void TeenAgentEngine::processObject() { + if (dst_object == NULL) + return; + + Resources * res = Resources::instance(); + switch (action) { + case ActionExamine: { + byte * dcall = res->dseg.ptr(0xb5ce); + dcall = res->dseg.ptr(READ_LE_UINT16(dcall + scene->getId() * 2 - 2)); + dcall += 2 * dst_object->id - 2; + uint16 callback = READ_LE_UINT16(dcall); + if (callback == 0) { + Common::String desc = dst_object->description(); + scene->displayMessage(desc); + //debug(0, "%s[%u]: description: %s", current_object->name, current_object->id, desc.c_str()); + break; + } + processCallback(callback); + } + break; + case ActionUse: + { + InventoryObject *inv = inventory->selectedObject(); + if (inv != NULL) { + byte * dcall = res->dseg.ptr(0xbb87); + dcall = res->dseg.ptr(READ_LE_UINT16(dcall + scene->getId() * 2 - 2)); + for(UseObject * obj = (UseObject *)dcall; obj->inventory_id != 0; ++obj) { + if (obj->inventory_id == inv->id && dst_object->id == obj->object_id) { + debug(0, "combine! %u,%u", obj->x, obj->y); + //moveTo(Common::Point(obj->x, obj->y), NULL, Examine); + processCallback(obj->callback); + inventory->resetSelectedObject(); + return; + } + } + + //error + inventory->resetSelectedObject(); + scene->displayMessage("That's no good."); + + break; + } else { + byte * dcall = res->dseg.ptr(0xb89c); + dcall = res->dseg.ptr(READ_LE_UINT16(dcall + scene->getId() * 2 - 2)); + dcall += 2 * dst_object->id - 2; + uint16 callback = READ_LE_UINT16(dcall); + processCallback(callback); + } + } + break; + + case ActionNone: + break; + } +} + + +void TeenAgentEngine::use(Object *object) { + if (object == NULL || scene->eventRunning()) + return; + + dst_object = object; + object->rect.dump(); + object->actor_rect.dump(); + if (object->actor_rect.valid()) //some objects have 0xffff in left/right + scene->moveTo(object->actor_rect.center(), object->actor_orientation); + if (object->actor_orientation > 0) + scene->setOrientation(object->actor_orientation); + action = ActionUse; +} + +void TeenAgentEngine::examine(const Common::Point &point, Object *object) { + if (scene->eventRunning()) + return; + + if (object != NULL) { + Common::Point dst = object->actor_rect.center(); + debug(0, "click %d, %d, object %d, %d", point.x, point.y, dst.x, dst.y); + if (object->actor_rect.valid()) + scene->moveTo(dst, object->actor_orientation); + action = ActionExamine; + dst_object = object; + } else { + debug(0, "click %d, %d", point.x, point.y); + scene->moveTo(point, 0, true); + dst_object = NULL; + action = ActionNone; + } +} + +void TeenAgentEngine::deinit() { + _mixer->stopAll(); + delete scene; + scene = NULL; + delete inventory; + inventory = NULL; + //delete music; + //music = NULL; + Resources::instance()->deinit(); +} + +Common::Error TeenAgentEngine::loadGameState(int slot) { + debug(0, "loading from slot %d", slot); + char slotStr[16]; + snprintf(slotStr, sizeof(slotStr), "teenagent.%d", slot); + Common::InSaveFile *in = _saveFileMan->openForLoading(slotStr); + if (in == NULL) + return Common::kReadPermissionDenied; + + Resources * res = Resources::instance(); + + assert(res->dseg.size() >= 0x6478 + 0x777a); + char data[0x777a]; + if (in->read(data, 0x777a) != 0x777a) { + delete in; + return Common::kReadingFailed; + } + + delete in; + + memcpy(res->dseg.ptr(0x6478), data, sizeof(data)); + + scene->clear(); + + setMusic(Resources::instance()->dseg.get_byte(0xDB90)); + + int id = res->dseg.get_byte(0xB4F3); + uint16 x = res->dseg.get_word(0x64AF), y = res->dseg.get_word(0x64B1); + scene->init(id, Common::Point(x, y)); + return Common::kNoError; +} + +Common::Error TeenAgentEngine::saveGameState(int slot, const char *desc) { + debug(0, "saving to slot %d", slot); + char slotStr[16]; + snprintf(slotStr, sizeof(slotStr), "teenagent.%d", slot); + Common::OutSaveFile *out = _saveFileMan->openForSaving(slotStr); + if (out == NULL) + return Common::kWritePermissionDenied; + + Resources * res = Resources::instance(); + res->dseg.set_byte(0xB4F3, scene->getId()); + Common::Point pos = scene->getPosition(); + res->dseg.set_word(0x64AF, pos.x); + res->dseg.set_word(0x64B1, pos.y); + + assert(res->dseg.size() >= 0x6478 + 0x777a); + strncpy((char *)res->dseg.ptr(0x6478), desc, 0x16); + out->write(res->dseg.ptr(0x6478), 0x777a); + delete out; + return Common::kNoError; +} + +Common::Error TeenAgentEngine::run() { + Common::EventManager * _event = _system->getEventManager(); + + initGraphics(320, 200, false); + + scene = new Scene; + inventory = new Inventory; + + Resources * res = Resources::instance(); + res->loadArchives(); + + + scene->init(this, _system); + inventory->init(this); + + //res.varia.read(6, palette, sizeof(palette)); + //14,15 - on type 2 + //scene->init(_system, 2); + //scene->init(_system, 27); + //scene->init(_system, 28); + scene->init(10, Common::Point(136, 153)); + //scene->init(_system, 1); + _system->disableCursorPalette(true); + + syncSoundSettings(); + + music->load(4); + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, music, -1, 255, 0, true, false); + music->start(); + + { + int load_slot = Common::ConfigManager::instance().getInt("save_slot"); + debug(0, "slot: %d", load_slot); + if (load_slot >= 0) + loadGameState(load_slot); + } + + uint32 frame = 0; + + Common::Event event; + Common::Point mouse; + + do { + _system->showMouse(true); + uint32 t0 = _system->getMillis(); + Object * current_object = findObject(scene->getId(), mouse); + + while (_event->pollEvent(event)) { + if (event.type == Common::EVENT_RTL) { + deinit(); + return Common::kNoError; + } + + if ((!scene_busy && inventory->processEvent(event)) || scene->processEvent(event)) + continue; + + //debug(0, "event"); + switch(event.type) { + case Common::EVENT_LBUTTONDOWN: + examine(event.mouse, current_object); + break; + case Common::EVENT_RBUTTONDOWN: + use(current_object); + break; + case Common::EVENT_MOUSEMOVE: + mouse = event.mouse; + break; + default:; + } + } + + uint32 f0 = frame * 10 / 25, f1 = (frame + 1) * 10 / 25; + if (f0 != f1) { + bool b = scene->render(_system); + scene_busy = b; + if (!inventory->active() && !scene_busy && action != ActionNone) { + processObject(); + action = ActionNone; + dst_object = NULL; + } + } + bool busy = inventory->active() || scene_busy; + + Graphics::Surface * surface = _system->lockScreen(); + + if (!busy) { + InventoryObject *selected_object = inventory->selectedObject(); + if (current_object || selected_object) { + Common::String name; + if (selected_object) { + name += selected_object->name; + name += " & "; + } + if (current_object) + name += current_object->name; + + uint w = res->font7.render(NULL, 0, 0, name); + res->font7.render(surface, (320 - w) / 2, 180, name, true); + if (current_object) { + current_object->rect.render(surface, 0x80); + current_object->actor_rect.render(surface, 0x81); + } + } + } + + inventory->render(surface); + + _system->unlockScreen(); + + _system->updateScreen(); + + uint32 dt = _system->getMillis() - t0; + if (dt < 40) + _system->delayMillis(40 - dt); + + ++frame; + } while(!_event->shouldQuit()); + + deinit(); + return Common::kNoError; +} + +Object * TeenAgentEngine::findObject(int id, const Common::Point &point) { + Resources * res = Resources::instance(); + uint16 addr = res->dseg.get_word(0x7254 + (id - 1) * 2); + //debug(0, "object base: %04x, x: %d, %d", addr, point.x, point.y); + uint16 object; + for(;(object = res->dseg.get_word(addr)) != 0; addr += 2) { + if (object == 0) + return NULL; + + Object *obj = (Object *)res->dseg.ptr(object); + //obj->dump(); + if (obj->enabled != 0 && obj->rect.in(point)) + return obj; + } + return NULL; +} + +void TeenAgentEngine::displayMessage(const Common::String &str, byte color) { + SceneEvent event(SceneEvent::Message); + event.message = str; + event.color = color; + scene->push(event); +} + + +void TeenAgentEngine::displayMessage(uint16 addr, byte color) { + Common::String message; + for ( + const char * str = (const char *)Resources::instance()->dseg.ptr(addr); + str[0] != 0 || str[1] != 0; + ++str) + { + char c = str[0]; + message += c != 0 && c != -1? c: '\n'; + } + displayMessage(message, color); +} + +void TeenAgentEngine::moveTo(const Common::Point & dst, bool warp) { + moveTo(dst.x, dst.y); +} + +void TeenAgentEngine::moveTo(uint16 x, uint16 y, bool warp) { + SceneEvent event(SceneEvent::Walk); + event.dst.x = x; + event.dst.y = y; + event.color = warp? 1: 0; + scene->push(event); +} + +void TeenAgentEngine::playAnimation(uint16 id, byte slot, bool async) { + SceneEvent event(SceneEvent::PlayAnimation); + event.animation = id; + event.color = slot; + if (async) + event.color |= 0x80; + scene->push(event); +} + +void TeenAgentEngine::loadScene(byte id, const Common::Point &pos, byte o) { + loadScene(id, pos.x, pos.y, o); +} + +void TeenAgentEngine::loadScene(byte id, uint16 x, uint16 y, byte o) { + SceneEvent event(SceneEvent::LoadScene); + event.scene = id; + event.dst.x = x; + event.dst.y = y; + event.orientation = o; + scene->push(event); +} + +void TeenAgentEngine::setOns(byte id, byte value, byte scene_id) { + SceneEvent event(SceneEvent::SetOn); + event.ons = id + 1; + event.color = value; + event.scene = scene_id; + scene->push(event); +} + +void TeenAgentEngine::setLan(byte id, byte value, byte scene_id) { + if (id == 0) + error("setting lan 0 is invalid"); + SceneEvent event(SceneEvent::SetLan); + event.lan = id; + event.color = value; + event.scene = scene_id; + scene->push(event); +} + +void TeenAgentEngine::reloadLan() { + SceneEvent event(SceneEvent::SetLan); + event.lan = 0; + scene->push(event); +} + + +void TeenAgentEngine::playMusic(byte id) { + SceneEvent event(SceneEvent::PlayMusic); + event.music = id; + scene->push(event); +} + +void TeenAgentEngine::playSound(byte id, byte skip_frames) { + SceneEvent event(SceneEvent::PlaySound); + event.sound = id; + event.color = skip_frames; + scene->push(event); +} + +void TeenAgentEngine::enableObject(byte id, byte scene_id) { + SceneEvent event(SceneEvent::EnableObject); + event.object = id + 1; + event.color = 1; + event.scene = scene_id; + scene->push(event); +} + +void TeenAgentEngine::disableObject(byte id, byte scene_id) { + SceneEvent event(SceneEvent::EnableObject); + event.object = id + 1; + event.color = 0; + event.scene = scene_id; + scene->push(event); +} + +void TeenAgentEngine::waitAnimation() { + SceneEvent event(SceneEvent::WaitForAnimation); + scene->push(event); +} + +void TeenAgentEngine::playSoundNow(byte id) { + Resources * res = Resources::instance(); + Common::SeekableReadStream * in = res->sam_sam.getStream(id); + if (in == NULL) { + debug(0, "skipping invalid sound %u", id); + return; + } + + uint size = in->size(); + char *data = new char[size]; + in->read(data, size); + debug(0, "playing %u samples...", size); + + _mixer->playRaw(Audio::Mixer::kSFXSoundType, &_soundHandle, data, size, 11025, Audio::Mixer::FLAG_AUTOFREE); +} + + +void TeenAgentEngine::setMusic(byte id) { + debug(0, "starting music %u", id); + if (!music->load(id)) + return; + *Resources::instance()->dseg.ptr(0xDB90) = id; + music->start(); +} + + +bool TeenAgentEngine::hasFeature(EngineFeature f) const { + switch(f) { + case kSupportsRTL: + case kSupportsLoadingDuringRuntime: + case kSupportsSavingDuringRuntime: + return true; + default: + return false; + } +} diff --git a/engines/teenagent/teenagent.h b/engines/teenagent/teenagent.h new file mode 100644 index 0000000000..b99d108024 --- /dev/null +++ b/engines/teenagent/teenagent.h @@ -0,0 +1,110 @@ +/* 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/tagent.h $ + * $Id: tagent.h 304 2009-09-03 20:10:22Z megath $ + */ + + +#ifndef TEENAGENT_ENGINE_H__ +#define TEENAGENT_ENGINE_H__ + +#include "engines/engine.h" +#include "pack.h" +#include "resources.h" +#include "inventory.h" +#include "sound/audiostream.h" +#include "sound/mixer.h" + +namespace TeenAgent { + +struct Object; +class Scene; +class MusicPlayer; + +class TeenAgentEngine: public Engine { +public: + enum Action { ActionNone, ActionExamine, ActionUse }; + + TeenAgentEngine(OSystem * system); + + virtual Common::Error run(); + virtual Common::Error loadGameState(int slot); + virtual Common::Error saveGameState(int slot, const char *desc); + virtual bool canLoadGameStateCurrently() { return true; } + virtual bool canSaveGameStateCurrently() { return !scene_busy; } + virtual bool hasFeature(EngineFeature f) const; + + + void deinit(); + + Object * findObject(int id, const Common::Point &point); + + void examine(const Common::Point &point, Object *object); + void use(Object *object); + + bool processCallback(uint16 addr); + inline Scene * getScene() { return scene; } + + //event driven: + void displayMessage(uint16 addr, byte color = 0xd1); + void displayMessage(const Common::String &str, byte color = 0xd1); + void moveTo(const Common::Point & dst, bool warp = false); + void moveTo(uint16 x, uint16 y, bool warp = false); + void playAnimation(uint16 id, byte slot = 0, bool async = false); + void loadScene(byte id, const Common::Point &pos, byte o = 0); + void loadScene(byte id, uint16 x, uint16 y, byte o = 0); + void setOns(byte id, byte value, byte scene_id = 0); + void setLan(byte id, byte value, byte scene_id = 0); + void reloadLan(); + void rejectMessage(); + + void playMusic(byte id); //schedules play + void playSound(byte id, byte skip_frames = 0); + void playSoundNow(byte id); + void enableObject(byte id, byte scene_id = 0); + void disableObject(byte id, byte scene_id = 0); + void waitAnimation(); + + Common::RandomSource random; + + Scene *scene; + Inventory *inventory; + MusicPlayer *music; + + void setMusic(byte id); + +private: + void processObject(); + void anotherMansionTry(); + + bool scene_busy; + Action action; + Object * dst_object; + + + Audio::AudioStream *_musicStream; + Audio::SoundHandle _musicHandle, _soundHandle; +}; + +} + +#endif + -- cgit v1.2.3