/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "common/config-manager.h"
#include "common/debug.h"
#include "common/events.h"
#include "common/algorithm.h"
#include "common/ptr.h"
#include "common/textconsole.h"
#include "graphics/paletteman.h"
#include "teenagent/scene.h"
#include "teenagent/inventory.h"
#include "teenagent/resources.h"
#include "teenagent/surface.h"
#include "teenagent/objects.h"
#include "teenagent/teenagent.h"
#include "teenagent/music.h"
namespace TeenAgent {
Scene::Scene(TeenAgentEngine *vm) : _vm(vm), intro(false), _id(0), ons(0),
orientation(kActorRight), actorTalking(false), teenagent(vm), teenagentIdle(vm),
messageTimer(0), messageFirstFrame(0), messageLastFrame(0), messageAnimation(NULL),
currentEvent(SceneEvent::kNone), hideActor(false), callback(0), callbackTimer(0), _idleTimer(0) {
_fadeTimer = 0;
_fadeOld = 0;
onEnabled = true;
memset(palette, 0, sizeof(palette));
FilePack varia;
varia.open("varia.res");
Common::ScopedPtr s(varia.getStream(1));
if (!s)
error("invalid resource data");
teenagent.load(*s, Animation::kTypeVaria);
if (teenagent.empty())
error("invalid mark animation");
s.reset(varia.getStream(2));
if (!s)
error("invalid resource data");
teenagentIdle.load(*s, Animation::kTypeVaria);
if (teenagentIdle.empty())
error("invalid mark animation");
varia.close();
loadObjectData();
_onsCount = 0;
_messageColor = 0;
_voiceId = 0;
}
Scene::~Scene() {
background.free();
delete[] ons;
ons = 0;
}
void Scene::warp(const Common::Point &_point, byte o) {
Common::Point point(_point);
position = point;
path.clear();
if (o)
orientation = o;
}
bool Scene::findPath(Scene::Path &p, const Common::Point &src, const Common::Point &dst) const {
const Common::Array &scene_walkboxes = walkboxes[_id - 1];
if (dst.x < 0 || dst.x >= kScreenWidth || dst.y < 0 || dst.y >= kScreenHeight)
return false;
debugC(1, kDebugScene, "findPath %d,%d -> %d,%d", src.x, src.y, dst.x, dst.y);
p.clear();
p.push_back(src);
p.push_back(dst);
Common::List boxes;
for (uint i = 0; i < scene_walkboxes.size(); ++i) {
const Walkbox &w = scene_walkboxes[i];
if (!w.rect.in(src) && !w.rect.in(dst))
boxes.push_back(i);
}
for (Path::iterator i = p.begin(); i != p.end() && !boxes.empty();) {
Path::iterator next = i;
++next;
if (next == p.end())
break;
const Common::Point &p1 = *i, &p2 = *next;
debugC(1, kDebugScene, "%d,%d -> %d,%d", p1.x, p1.y, p2.x, p2.y);
Common::List::iterator wi;
for (wi = boxes.begin(); wi != boxes.end(); ++wi) {
const Walkbox &w = scene_walkboxes[*wi];
int mask = w.rect.intersects_line(p1, p2);
if (mask == 0) {
continue;
}
w.dump(1);
debugC(1, kDebugScene, "%u: intersection mask 0x%04x, searching hints", *wi, mask);
int dx = p2.x - p1.x, dy = p2.y - p1.y;
if (dx >= 0) {
if ((mask & 8) != 0 && w.sideHint[3] != 0) {
debugC(1, kDebugScene, "hint left: %u", w.sideHint[3]);
Common::Point w1, w2;
w.rect.side(w1, w2, w.sideHint[3], p1);
debugC(1, kDebugScene, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
p.insert(next, w1);
if (mask & 2)
p.insert(next, w2);
boxes.erase(wi);
break;
}
} else {
if ((mask & 2) != 0 && w.sideHint[1] != 0) {
debugC(1, kDebugScene, "hint right: %u", w.sideHint[1]);
Common::Point w1, w2;
w.rect.side(w1, w2, w.sideHint[1], p1);
debugC(1, kDebugScene, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
p.insert(next, w1);
if (mask & 8)
p.insert(next, w2);
boxes.erase(wi);
break;
}
}
if (dy >= 0) {
if ((mask & 1) != 0 && w.sideHint[0] != 0) {
debugC(1, kDebugScene, "hint top: %u", w.sideHint[0]);
Common::Point w1, w2;
w.rect.side(w1, w2, w.sideHint[0], p1);
debugC(1, kDebugScene, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
p.insert(next, w1);
if (mask & 4)
p.insert(next, w2);
boxes.erase(wi);
break;
}
} else {
if ((mask & 4) != 0 && w.sideHint[2] != 0) {
debugC(1, kDebugScene, "hint bottom: %u", w.sideHint[2]);
Common::Point w1, w2;
w.rect.side(w1, w2, w.sideHint[2], p1);
debugC(1, kDebugScene, "hint: %d,%d-%d,%d", w1.x, w1.y, w2.x, w2.y);
p.insert(next, w1);
if (mask & 1)
p.insert(next, w2);
boxes.erase(wi);
break;
}
}
}
if (wi == boxes.end())
++i;
}
p.pop_front();
return true;
}
void Scene::moveTo(const Common::Point &_point, byte orient, bool validate) {
Common::Point point(_point);
debugC(0, kDebugScene, "moveTo(%d, %d, %u)", point.x, point.y, orient);
const Common::Array &scene_walkboxes = walkboxes[_id - 1];
for (byte i = 0; i < scene_walkboxes.size(); ++i) {
const Walkbox &w = scene_walkboxes[i];
if (w.rect.in(point)) {
debugC(0, kDebugScene, "bumped into walkbox %u", i);
w.dump();
byte o = w.orientation;
switch (o) {
case 1:
point.y = w.rect.top - 1;
break;
case 2:
point.x = w.rect.right + 1;
break;
case 3:
point.y = w.rect.bottom + 1;
break;
case 4:
point.x = w.rect.left - 1;
break;
default:
if (validate)
return;
}
}
}
if (point == position) {
if (orient != 0)
orientation = orient;
nextEvent();
return;
}
path.clear();
if (scene_walkboxes.empty()) {
path.push_back(point);
return;
}
if (!findPath(path, position, point)) {
_vm->cancel();
return;
}
orientation = orient;
}
void Scene::loadObjectData() {
//loading objects & walkboxes
objects.resize(42);
walkboxes.resize(42);
fades.resize(42);
uint16 voiceStartIndx = 334;
for (byte i = 0; i < 42; ++i) {
Common::Array