Initial commit
This commit is contained in:
3
engines/teenagent/POTFILES
Normal file
3
engines/teenagent/POTFILES
Normal file
@@ -0,0 +1,3 @@
|
||||
engines/teenagent/detection.cpp
|
||||
engines/teenagent/resources.cpp
|
||||
engines/teenagent/metaengine.cpp
|
||||
151
engines/teenagent/actor.cpp
Normal file
151
engines/teenagent/actor.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/actor.h"
|
||||
#include "teenagent/objects.h"
|
||||
#include "teenagent/resources.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
#include "common/random.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
Actor::Actor(TeenAgentEngine *vm) : _vm(vm), headIndex(0), idleType(0) {}
|
||||
|
||||
Common::Rect Actor::renderIdle(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int deltaFrame, uint zoom, Common::RandomSource &rnd) {
|
||||
if (index == 0) {
|
||||
idleType = rnd.getRandomNumber(2);
|
||||
debugC(kDebugActor, "switched to idle animation %u", idleType);
|
||||
}
|
||||
|
||||
byte *framesIdle;
|
||||
do {
|
||||
framesIdle = _vm->res->dseg.ptr(_vm->res->dseg.get_word(dsAddr_idleAnimationListPtr + idleType * 2)) + index;
|
||||
index += deltaFrame;
|
||||
if (*framesIdle == 0) {
|
||||
idleType = rnd.getRandomNumber(2);
|
||||
debugC(kDebugActor, "switched to idle animation %u[loop]", idleType);
|
||||
index = 3; //put 4th frame (base 1) if idle animation loops
|
||||
}
|
||||
} while (*framesIdle == 0);
|
||||
|
||||
bool mirror = orientation == kActorLeft;
|
||||
Surface *s = frames + *framesIdle - 1;
|
||||
|
||||
//TODO: remove copy-paste here and below
|
||||
int xp = position.x - s->w * zoom / 512 - s->x, yp = position.y - 62 * zoom / 256 - s->y; //hardcoded in original game
|
||||
return s->render(surface, xp, yp, mirror, Common::Rect(), zoom);
|
||||
}
|
||||
|
||||
Common::Rect Actor::render(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int deltaFrame, bool renderHead, uint zoom) {
|
||||
const uint8 framesLeftRight[] = {0, 1, 2, 3, 4, 5, /* step */ 6, 7, 8, 9};
|
||||
const uint8 framesUp[] = {18, 19, 20, 21, 22, 23, 24, 25, };
|
||||
const uint8 framesDown[] = {10, 11, 12, 13, 14, 15, 16, 17, };
|
||||
|
||||
const uint8 framesHeadLeftRight[] = {
|
||||
0x27, 0x1a, 0x1b,
|
||||
0x27, 0x1c, 0x1d,
|
||||
0x27, 0x1a,
|
||||
0x27, 0x1e, 0x1f,
|
||||
0x27, 0x1a, 0x1b,
|
||||
0x27, 0x1c,
|
||||
0x27, 0x1e,
|
||||
0x27, 0x1a,
|
||||
};
|
||||
|
||||
const uint8 framesHeadUp[] = {
|
||||
0x29, 0x25, 0x29, 0x29,
|
||||
0x26, 0x29, 0x26, 0x29,
|
||||
0x29, 0x25, 0x29, 0x25,
|
||||
0x29, 0x29, 0x29, 0x25,
|
||||
0x25, 0x29, 0x29, 0x26
|
||||
};
|
||||
const uint8 framesHeadDown[] = {
|
||||
0x20, 0x21, 0x22, 0x23,
|
||||
0x28, 0x24, 0x28, 0x28,
|
||||
0x24, 0x28, 0x20, 0x21,
|
||||
0x20, 0x23, 0x28, 0x20,
|
||||
0x28, 0x28, 0x20, 0x28
|
||||
};
|
||||
|
||||
Surface *s = NULL, *head = NULL;
|
||||
|
||||
bool mirror = orientation == kActorLeft;
|
||||
index += deltaFrame;
|
||||
|
||||
switch (orientation) {
|
||||
case kActorLeft:
|
||||
case kActorRight:
|
||||
if (renderHead) {
|
||||
if (headIndex >= ARRAYSIZE(framesHeadLeftRight))
|
||||
headIndex = 0;
|
||||
head = frames + framesHeadLeftRight[headIndex];
|
||||
++headIndex;
|
||||
}
|
||||
|
||||
if (index >= ARRAYSIZE(framesLeftRight))
|
||||
index = 1;
|
||||
s = frames + framesLeftRight[index];
|
||||
break;
|
||||
case kActorUp:
|
||||
if (renderHead) {
|
||||
if (headIndex >= ARRAYSIZE(framesHeadUp))
|
||||
headIndex = 0;
|
||||
head = frames + framesHeadUp[headIndex];
|
||||
++headIndex;
|
||||
}
|
||||
|
||||
if (index >= ARRAYSIZE(framesUp))
|
||||
index = 1;
|
||||
s = frames + framesUp[index];
|
||||
break;
|
||||
case kActorDown:
|
||||
if (renderHead) {
|
||||
if (headIndex >= ARRAYSIZE(framesHeadDown))
|
||||
headIndex = 0;
|
||||
head = frames + framesHeadDown[headIndex];
|
||||
++headIndex;
|
||||
}
|
||||
|
||||
if (index >= ARRAYSIZE(framesDown))
|
||||
index = 1;
|
||||
s = frames + framesDown[index];
|
||||
break;
|
||||
default:
|
||||
return Common::Rect();
|
||||
}
|
||||
|
||||
Common::Rect dirty;
|
||||
Common::Rect clip(0, 0, s->w, s->h);
|
||||
if (head != NULL)
|
||||
clip.top = head->h;
|
||||
|
||||
int xp = position.x - s->w * zoom / 512 - s->x, yp = position.y - s->h * zoom / 256 - s->y;
|
||||
dirty = s->render(surface, xp, yp + clip.top * zoom / 256, mirror, clip, zoom);
|
||||
|
||||
if (head != NULL)
|
||||
dirty.extend(head->render(surface, xp, yp, orientation == kActorLeft, Common::Rect(), zoom));
|
||||
|
||||
return dirty;
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
47
engines/teenagent/actor.h
Normal file
47
engines/teenagent/actor.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/animation.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Common {
|
||||
class RandomSource;
|
||||
}
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
class TeenAgentEngine;
|
||||
|
||||
class Actor : public Animation {
|
||||
private:
|
||||
TeenAgentEngine *_vm;
|
||||
|
||||
uint headIndex;
|
||||
uint idleType;
|
||||
|
||||
public:
|
||||
Actor(TeenAgentEngine *vm);
|
||||
|
||||
Common::Rect render(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int deltaFrame, bool renderHead, uint zoom);
|
||||
Common::Rect renderIdle(Graphics::Surface *surface, const Common::Point &position, uint8 orientation, int deltaFrame, uint zoom, Common::RandomSource &rnd);
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
209
engines/teenagent/animation.cpp
Normal file
209
engines/teenagent/animation.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/teenagent.h"
|
||||
#include "teenagent/animation.h"
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
Animation::Animation() : id(0), x(0), y(0), loop(true), paused(false), ignore(false), data(0), dataSize(0), framesCount(0), frames(0), index(0) {
|
||||
}
|
||||
|
||||
Animation::~Animation() {
|
||||
free();
|
||||
}
|
||||
|
||||
Surface *Animation::firstFrame() {
|
||||
if (frames == NULL || framesCount == 0)
|
||||
return NULL;
|
||||
|
||||
Surface *r = frames;
|
||||
uint16 pos = READ_LE_UINT16(data + 1);
|
||||
if (pos != 0) {
|
||||
r->x = pos % kScreenWidth;
|
||||
r->y = pos / kScreenWidth;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
Surface *Animation::currentFrame(int dt) {
|
||||
if (paused)
|
||||
return firstFrame();
|
||||
|
||||
if (frames == NULL || framesCount == 0)
|
||||
return NULL;
|
||||
|
||||
Surface *r;
|
||||
|
||||
if (data != NULL) {
|
||||
uint32 frame = 3 * index;
|
||||
debugC(2, kDebugAnimation, "%u/%u", index, dataSize / 3);
|
||||
index += dt;
|
||||
|
||||
if (!loop && index >= dataSize / 3) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data[frame] - 1 >= framesCount) {
|
||||
warning("invalid frame %u(0x%x) (max %u) index %u, mod %u", frame, frame, framesCount, index - 1, dataSize / 3);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r = frames + data[frame] - 1;
|
||||
uint16 pos = READ_LE_UINT16(data + frame + 1);
|
||||
index %= (dataSize / 3);
|
||||
|
||||
if (pos != 0) {
|
||||
x = r->x = pos % kScreenWidth;
|
||||
y = r->y = pos / kScreenWidth;
|
||||
}
|
||||
} else {
|
||||
debugC(2, kDebugAnimation, "index %u", index);
|
||||
r = frames + index;
|
||||
index += dt;
|
||||
index %= framesCount;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void Animation::restart() {
|
||||
paused = false;
|
||||
ignore = false;
|
||||
index = 0;
|
||||
}
|
||||
|
||||
void Animation::free() {
|
||||
id = 0;
|
||||
x = y = 0;
|
||||
loop = true;
|
||||
paused = false;
|
||||
ignore = false;
|
||||
|
||||
delete[] data;
|
||||
data = NULL;
|
||||
dataSize = 0;
|
||||
|
||||
framesCount = 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.size() <= 1) {
|
||||
debugC(1, kDebugAnimation, "empty animation");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16 pos = 0;
|
||||
int off = 0;
|
||||
switch (type) {
|
||||
case kTypeLan:
|
||||
dataSize = s.readUint16LE();
|
||||
if (s.eos()) {
|
||||
debugC(1, kDebugAnimation, "empty animation");
|
||||
return;
|
||||
}
|
||||
|
||||
dataSize -= 2;
|
||||
data = new byte[dataSize];
|
||||
dataSize = s.read(data, dataSize);
|
||||
for (int i = 0; i < dataSize; ++i)
|
||||
debugC(2, kDebugAnimation, "%02x ", data[i]);
|
||||
debugC(2, kDebugAnimation, ", %u frames", dataSize / 3);
|
||||
framesCount = s.readByte();
|
||||
debugC(1, kDebugAnimation, "%u physical frames", framesCount);
|
||||
if (framesCount == 0)
|
||||
return;
|
||||
|
||||
frames = new Surface[framesCount];
|
||||
|
||||
s.skip(framesCount * 2 - 2); //sizes
|
||||
pos = s.readUint16LE();
|
||||
debugC(3, kDebugAnimation, "pos?: 0x%04x", pos);
|
||||
|
||||
for (uint16 i = 0; i < framesCount; ++i) {
|
||||
frames[i].load(s, Surface::kTypeLan);
|
||||
frames[i].x = 0;
|
||||
frames[i].y = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case kTypeInventory: {
|
||||
dataSize = 3 * s.readByte();
|
||||
data = new byte[dataSize];
|
||||
|
||||
framesCount = 0;
|
||||
for (byte i = 0; i < dataSize / 3; ++i) {
|
||||
int idx = i * 3;
|
||||
byte unk = s.readByte();
|
||||
debugC(3, kDebugAnimation, "unk?: 0x%02x", unk);
|
||||
data[idx] = s.readByte();
|
||||
if (data[idx] == 0)
|
||||
data[idx] = 1; //fixme: investigate
|
||||
if (data[idx] > framesCount)
|
||||
framesCount = data[idx];
|
||||
data[idx + 1] = 0;
|
||||
data[idx + 2] = 0;
|
||||
debugC(2, kDebugAnimation, "frame #%u", data[idx]);
|
||||
}
|
||||
|
||||
frames = new Surface[framesCount];
|
||||
|
||||
for (uint16 i = 0; i < framesCount; ++i) {
|
||||
frames[i].load(s, Surface::kTypeOns);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case kTypeVaria:
|
||||
framesCount = s.readByte();
|
||||
debugC(1, kDebugAnimation, "loading varia resource, %u physical frames", framesCount);
|
||||
uint16 offset[255];
|
||||
for (byte i = 0; i < framesCount; ++i) {
|
||||
offset[i] = s.readUint16LE();
|
||||
debugC(0, kDebugAnimation, "%u: %04x", i, offset[i]);
|
||||
}
|
||||
frames = new Surface[framesCount];
|
||||
for (uint16 i = 0; i < framesCount; ++i) {
|
||||
debugC(0, kDebugAnimation, "%04x", offset[i]);
|
||||
s.seek(offset[i] + off);
|
||||
frames[i].load(s, Surface::kTypeOns);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
debugC(2, kDebugAnimation, "%u frames", dataSize / 3);
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
65
engines/teenagent/animation.h
Normal file
65
engines/teenagent/animation.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_ANIMATION_H
|
||||
#define TEENAGENT_ANIMATION_H
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "teenagent/surface.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
class Animation {
|
||||
public:
|
||||
uint16 id, x, y;
|
||||
bool loop, paused, ignore;
|
||||
|
||||
enum Type {kTypeLan, kTypeVaria, kTypeInventory};
|
||||
|
||||
Animation();
|
||||
~Animation();
|
||||
|
||||
void load(Common::SeekableReadStream &, Type type = kTypeLan);
|
||||
void free();
|
||||
|
||||
Surface *firstFrame();
|
||||
Surface *currentFrame(int dt);
|
||||
uint16 currentIndex() const { return index; }
|
||||
void resetIndex() { index = 0; }
|
||||
|
||||
bool empty() const { return frames == NULL; }
|
||||
void restart();
|
||||
|
||||
//uint16 width() const { return frames? frames[0].w: 0; }
|
||||
//uint16 height() const { return frames? frames[0].h: 0; }
|
||||
|
||||
protected:
|
||||
byte *data;
|
||||
uint16 dataSize;
|
||||
|
||||
uint16 framesCount;
|
||||
Surface *frames;
|
||||
uint16 index;
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
4960
engines/teenagent/callbacks.cpp
Normal file
4960
engines/teenagent/callbacks.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3
engines/teenagent/configure.engine
Normal file
3
engines/teenagent/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine teenagent "Teen Agent" yes
|
||||
202
engines/teenagent/console.cpp
Normal file
202
engines/teenagent/console.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/console.h"
|
||||
#include "teenagent/resources.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
Console::Console(TeenAgentEngine *engine) : _engine(engine) {
|
||||
registerCmd("enable_object", WRAP_METHOD(Console, enableObject));
|
||||
registerCmd("disable_object", WRAP_METHOD(Console, enableObject));
|
||||
registerCmd("set_ons", WRAP_METHOD(Console, setOns));
|
||||
registerCmd("set_music", WRAP_METHOD(Console, setMusic));
|
||||
registerCmd("animation", WRAP_METHOD(Console, playAnimation));
|
||||
registerCmd("actor_animation", WRAP_METHOD(Console, playActorAnimation));
|
||||
registerCmd("call", WRAP_METHOD(Console, call));
|
||||
registerCmd("playSound", WRAP_METHOD(Console, playSound));
|
||||
registerCmd("playVoice", WRAP_METHOD(Console, playVoice));
|
||||
}
|
||||
|
||||
bool Console::enableObject(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("usage: %s object_id [scene_id]\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int id = atoi(argv[1]);
|
||||
if (id < 0) {
|
||||
debugPrintf("object id %d is invalid\n", id);
|
||||
return true;
|
||||
}
|
||||
|
||||
int scene_id = 0;
|
||||
if (argc > 2) {
|
||||
scene_id = atoi(argv[2]);
|
||||
if (scene_id < 0) {
|
||||
debugPrintf("scene id %d is invalid\n", scene_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(argv[0], "disable_object") == 0)
|
||||
_engine->disableObject(id, scene_id);
|
||||
else
|
||||
_engine->enableObject(id, scene_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::setOns(int argc, const char **argv) {
|
||||
if (argc < 3) {
|
||||
debugPrintf("usage: %s index(0-3) value [scene_id]\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int index = atoi(argv[1]);
|
||||
if (index < 0 || index > 3) {
|
||||
debugPrintf("index %d is invalid\n", index);
|
||||
return true;
|
||||
}
|
||||
|
||||
int value = 0;
|
||||
value = atoi(argv[2]);
|
||||
if (value < 0) {
|
||||
debugPrintf("invalid value\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int scene_id = 0;
|
||||
if (argc > 3) {
|
||||
scene_id = atoi(argv[3]);
|
||||
if (scene_id < 0) {
|
||||
debugPrintf("scene id %d is invalid\n", scene_id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
_engine->setOns(index, value, scene_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::setMusic(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("usage: %s index(1-11)\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int index = atoi(argv[1]);
|
||||
if (index <= 0 || index > 11) {
|
||||
debugPrintf("invalid value\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
_engine->setMusic(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::playAnimation(int argc, const char **argv) {
|
||||
if (argc < 3) {
|
||||
debugPrintf("usage: %s id slot(0-3)\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int id = atoi(argv[1]);
|
||||
int slot = atoi(argv[2]);
|
||||
if (id < 0 || slot < 0 || slot > 3) {
|
||||
debugPrintf("invalid slot or animation id\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
_engine->playAnimation(id, slot);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::playActorAnimation(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("usage: %s id\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
int id = atoi(argv[1]);
|
||||
if (id < 0) {
|
||||
debugPrintf("invalid animation id\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
_engine->playActorAnimation(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::call(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("usage: %s 0xHEXADDR\n", argv[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint addr;
|
||||
if (sscanf(argv[1], "0x%x", &addr) != 1) {
|
||||
debugPrintf("invalid address\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_engine->processCallback(addr))
|
||||
debugPrintf("calling callback %04x failed\n", addr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::playSound(int argc, const char **argv) {
|
||||
uint32 fileCount = _engine->res->sam_sam.fileCount();
|
||||
if (argc < 2) {
|
||||
debugPrintf("usage: %s index(1-%d)\n", argv[0], fileCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint index = atoi(argv[1]);
|
||||
if (index <= 0 || index > fileCount) {
|
||||
debugPrintf("invalid value\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
_engine->playSoundNow(&_engine->res->sam_sam, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Console::playVoice(int argc, const char **argv) {
|
||||
uint32 fileCount = _engine->res->voices.fileCount();
|
||||
if (argc < 2) {
|
||||
debugPrintf("usage: %s index(1-%d)\n", argv[0], fileCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint index = atoi(argv[1]);
|
||||
if (index <= 0 || index > fileCount) {
|
||||
debugPrintf("invalid value\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
_engine->playSoundNow(&_engine->res->voices, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
50
engines/teenagent/console.h
Normal file
50
engines/teenagent/console.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_CONSOLE_H
|
||||
#define TEENAGENT_CONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
class TeenAgentEngine;
|
||||
|
||||
class Console : public GUI::Debugger {
|
||||
public:
|
||||
Console(TeenAgentEngine *engine);
|
||||
|
||||
private:
|
||||
bool enableObject(int argc, const char **argv);
|
||||
bool setOns(int argc, const char **argv);
|
||||
bool setMusic(int argc, const char **argv);
|
||||
bool playAnimation(int argc, const char **argv);
|
||||
bool playActorAnimation(int argc, const char **argv);
|
||||
bool call(int argc, const char **argv);
|
||||
bool playSound(int argc, const char **argv);
|
||||
bool playVoice(int argc, const char **argv);
|
||||
|
||||
TeenAgentEngine *_engine;
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
4
engines/teenagent/credits.pl
Normal file
4
engines/teenagent/credits.pl
Normal file
@@ -0,0 +1,4 @@
|
||||
begin_section("TeenAgent");
|
||||
add_person("Robert Megone", "sanguine", "Help with callback rewriting");
|
||||
add_person("Vladimir Menshakov", "whoozle", "");
|
||||
end_section();
|
||||
249
engines/teenagent/detection.cpp
Normal file
249
engines/teenagent/detection.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/algorithm.h"
|
||||
|
||||
#include "base/plugins.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
#include "teenagent/detection.h"
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{TeenAgent::kDebugActor, "Actor", "Enable Actor Debug"},
|
||||
{TeenAgent::kDebugAnimation, "Animation", "Enable Animation Debug"},
|
||||
{TeenAgent::kDebugCallbacks, "Callbacks", "Enable Callbacks Debug"},
|
||||
{TeenAgent::kDebugDialog, "Dialog", "Enable Dialog Debug"},
|
||||
{TeenAgent::kDebugFont, "Font", "Enable Font Debug"},
|
||||
{TeenAgent::kDebugInventory, "Inventory", "Enable Inventory Debug"},
|
||||
{TeenAgent::kDebugMusic, "Music", "Enable Music Debug"},
|
||||
{TeenAgent::kDebugObject, "Object", "Enable Object Debug"},
|
||||
{TeenAgent::kDebugPack, "Pack", "Enable Pack Debug"},
|
||||
{TeenAgent::kDebugScene, "Scene", "Enable Scene Debug"},
|
||||
{TeenAgent::kDebugSurface, "Surface", "Enable Surface Debug"},
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
static const PlainGameDescriptor teenAgentGames[] = {
|
||||
{ "teenagent", "Teen Agent" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static const ADGameDescription teenAgentGameDescriptions[] = {
|
||||
{
|
||||
"teenagent",
|
||||
"",
|
||||
{
|
||||
{"off.res", 0, "c5263a726d038bb6780a40eb3b83cc87", 2720432},
|
||||
{"on.res", 0, "a0d5e5bbf6fab4bdc7f4094ed85f9639", 153907},
|
||||
{"ons.res", 0, "a7e2e8def1f0fb46644c20686af0d91a", 173077},
|
||||
{"varia.res", 0, "b5ba6925029c7bc285283da8c2d3042d", 209315},
|
||||
{"lan_000.res", 0, "06e409b0a43ff0ced014b93fb8f5dd5b", 535599},
|
||||
{"lan_500.res", 0, "c098cc17cc27a1cad4319fb6789aa5a7", 9538457},
|
||||
{"mmm.res", 0, "d25033d9bc88662d680b56825e892e5c", 42104},
|
||||
{"sam_mmm.res", 0, "a0878ad9a1af39d515e2e0471222f080", 229636},
|
||||
{"sam_sam.res", 0, "547a48cc1be9cf30744de8b0b47838f2", 769552},
|
||||
{"sdr.res", 0, "434c62c1f43b7aa4def62ff276163edb", 14672},
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
|
||||
},
|
||||
{
|
||||
"teenagent",
|
||||
"Alt version",
|
||||
{
|
||||
{"off.res", 0, "c5263a726d038bb6780a40eb3b83cc87", 2720432},
|
||||
{"on.res", 0, "a0d5e5bbf6fab4bdc7f4094ed85f9639", 153907},
|
||||
{"ons.res", 0, "a7e2e8def1f0fb46644c20686af0d91a", 173077},
|
||||
{"varia.res", 0, "b786c48e160e1981b496a30acd3deff9", 216683},
|
||||
{"lan_000.res", 0, "06e409b0a43ff0ced014b93fb8f5dd5b", 535599},
|
||||
{"lan_500.res", 0, "c098cc17cc27a1cad4319fb6789aa5a7", 9538457},
|
||||
{"mmm.res", 0, "d25033d9bc88662d680b56825e892e5c", 42104},
|
||||
{"sam_mmm.res", 0, "a0878ad9a1af39d515e2e0471222f080", 229636},
|
||||
{"sam_sam.res", 0, "547a48cc1be9cf30744de8b0b47838f2", 769552},
|
||||
{"sdr.res", 0, "434c62c1f43b7aa4def62ff276163edb", 14665},
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
|
||||
},
|
||||
{ // Russian fan translation
|
||||
"teenagent",
|
||||
"",
|
||||
{
|
||||
{"off.res", 0, "c5263a726d038bb6780a40eb3b83cc87", 2720432},
|
||||
{"on.res", 0, "a0d5e5bbf6fab4bdc7f4094ed85f9639", 153907},
|
||||
{"ons.res", 0, "a7e2e8def1f0fb46644c20686af0d91a", 173077},
|
||||
{"varia.res", 0, "b786c48e160e1981b496a30acd3deff9", 216683},
|
||||
{"lan_000.res", 0, "06e409b0a43ff0ced014b93fb8f5dd5b", 535599},
|
||||
{"lan_500.res", 0, "c098cc17cc27a1cad4319fb6789aa5a7", 9538457},
|
||||
{"mmm.res", 0, "d25033d9bc88662d680b56825e892e5c", 42104},
|
||||
{"sam_mmm.res", 0, "a0878ad9a1af39d515e2e0471222f080", 229636},
|
||||
{"sam_sam.res", 0, "547a48cc1be9cf30744de8b0b47838f2", 769552},
|
||||
{"cdlogo.res", 0, "d1aacbb7deb718f9d946ba9deec6271d", 64768},
|
||||
{"sdr.res", 0, "434c62c1f43b7aa4def62ff276163edb", 14665},
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
|
||||
},
|
||||
{ // Czech Floppy
|
||||
"teenagent",
|
||||
"",
|
||||
{
|
||||
{"off.res", 0, "c5263a726d038bb6780a40eb3b83cc87", 2720432},
|
||||
{"on.res", 0, "a0d5e5bbf6fab4bdc7f4094ed85f9639", 153907},
|
||||
{"ons.res", 0, "a7e2e8def1f0fb46644c20686af0d91a", 173077},
|
||||
{"varia.res", 0, "b786c48e160e1981b496a30acd3deff9", 216683},
|
||||
{"lan_000.res", 0, "06e409b0a43ff0ced014b93fb8f5dd5b", 535599},
|
||||
{"lan_500.res", 0, "c098cc17cc27a1cad4319fb6789aa5a7", 9538457},
|
||||
{"mmm.res", 0, "d25033d9bc88662d680b56825e892e5c", 42104},
|
||||
{"sam_mmm.res", 0, "a0878ad9a1af39d515e2e0471222f080", 229636},
|
||||
{"sam_sam.res", 0, "547a48cc1be9cf30744de8b0b47838f2", 769552},
|
||||
{"sdr.res", 0, "434c62c1f43b7aa4def62ff276163edb", 14672},
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::CS_CZE,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
|
||||
},
|
||||
{ // Polish CD
|
||||
"teenagent",
|
||||
"CD",
|
||||
{
|
||||
{"off.res", 0, "aaac839a6ef639d68ebc97bc42faa42d", 2720432},
|
||||
{"on.res", 0, "a0d5e5bbf6fab4bdc7f4094ed85f9639", 153907},
|
||||
{"ons.res", 0, "a7e2e8def1f0fb46644c20686af0d91a", 173077},
|
||||
{"varia.res", 0, "b786c48e160e1981b496a30acd3deff9", 216683},
|
||||
{"lan_000.res", 0, "06e409b0a43ff0ced014b93fb8f5dd5b", 535599},
|
||||
{"lan_500.res", 0, "c098cc17cc27a1cad4319fb6789aa5a7", 9538457},
|
||||
{"sam_sam.res", 0, "547a48cc1be9cf30744de8b0b47838f2", 769552},
|
||||
{"voices.res", 0, "955aa04517a2b0499adf17d9b7c6f4a1", 37306128},
|
||||
{"cdlogo.res", 0, "6bf95a48f366bdf8af3a198c7b723c77", 64768},
|
||||
{"sdr.res", 0, "d0b1398c78dc82571ddef5877c9a3a06", 14993},
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::PL_POL,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_CD,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_TTS_OBJECTS)
|
||||
},
|
||||
{ // Polish Floppy
|
||||
"teenagent",
|
||||
"",
|
||||
{
|
||||
{"off.res", 0, "aaac839a6ef639d68ebc97bc42faa42d", 2720432},
|
||||
{"on.res", 0, "a0d5e5bbf6fab4bdc7f4094ed85f9639", 153907},
|
||||
{"ons.res", 0, "a7e2e8def1f0fb46644c20686af0d91a", 173077},
|
||||
{"varia.res", 0, "b786c48e160e1981b496a30acd3deff9", 216683},
|
||||
{"lan_000.res", 0, "06e409b0a43ff0ced014b93fb8f5dd5b", 535599},
|
||||
{"lan_500.res", 0, "c098cc17cc27a1cad4319fb6789aa5a7", 9538457},
|
||||
{"sam_sam.res", 0, "547a48cc1be9cf30744de8b0b47838f2", 769552},
|
||||
{"voices.res", 0, "955aa04517a2b0499adf17d9b7c6f4a1", 19376128},
|
||||
{"cdlogo.res", 0, "6bf95a48f366bdf8af3a198c7b723c77", 64768},
|
||||
{"sdr.res", 0, "d0b1398c78dc82571ddef5877c9a3a06", 14993},
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::PL_POL,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO2(GUIO_NOMIDI, GAMEOPTION_TTS_OBJECTS)
|
||||
},
|
||||
{ // Demo
|
||||
"teenagent",
|
||||
"Demo",
|
||||
{
|
||||
{"off.res", 0, "441b7dde82ca84a829fc7fe9743e9b78", 906956},
|
||||
{"on.res", 0, "25dbb6eed0a80d98edff3c24f09f1ee0", 37654},
|
||||
{"ons.res", 0, "394fbd9418e43942127c45a326d10ee1", 50596},
|
||||
{"varia.res", 0, "b786c48e160e1981b496a30acd3deff9", 216683},
|
||||
{"lan_000.res", 0, "c7241846ec67dd249fe02610cb9b8425", 91729},
|
||||
{"lan_500.res", 0, "791e4058a4742abd7c03dc82272623a9", 2109796},
|
||||
{"mmm.res", 0, "afbab0a454860f4ccf23005d8d2f4a70", 27073},
|
||||
{"sam_mmm.res", 0, "85fcdd0d49062577acf4a9ddafc53283", 148783},
|
||||
{"sam_sam.res", 0, "dc39c65ec57ed70612670b7e780f3408", 342219},
|
||||
{"sdr.res", 0, "434c62c1f43b7aa4def62ff276163edb", 14672},
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
|
||||
},
|
||||
{ // Demo alt
|
||||
"teenagent",
|
||||
"Alt Demo",
|
||||
{
|
||||
{"off.res", 0, "441b7dde82ca84a829fc7fe9743e9b78", 906956},
|
||||
{"on.res", 0, "25dbb6eed0a80d98edff3c24f09f1ee0", 37654},
|
||||
{"ons.res", 0, "394fbd9418e43942127c45a326d10ee1", 50596},
|
||||
{"varia.res", 0, "8ffe0a75b7299b44a34fdd3831cecacb", 217003},
|
||||
{"lan_000.res", 0, "c7241846ec67dd249fe02610cb9b8425", 91729},
|
||||
{"lan_500.res", 0, "791e4058a4742abd7c03dc82272623a9", 2109796},
|
||||
{"mmm.res", 0, "afbab0a454860f4ccf23005d8d2f4a70", 27073},
|
||||
{"sam_mmm.res", 0, "85fcdd0d49062577acf4a9ddafc53283", 148783},
|
||||
{"sam_sam.res", 0, "dc39c65ec57ed70612670b7e780f3408", 342219},
|
||||
{"sdr.res", 0, "434c62c1f43b7aa4def62ff276163edb", 14672},
|
||||
AD_LISTEND
|
||||
},
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO4(GUIO_NOSPEECH, GUIO_NOMIDI, GAMEOPTION_TTS_OBJECTS, GAMEOPTION_TTS_SPEECH)
|
||||
},
|
||||
|
||||
AD_TABLE_END_MARKER,
|
||||
};
|
||||
|
||||
|
||||
|
||||
class TeenAgentMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
public:
|
||||
TeenAgentMetaEngineDetection() : AdvancedMetaEngineDetection(teenAgentGameDescriptions, teenAgentGames) {
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "teenagent";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "TeenAgent";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "TEENAGENT (C) 1994 Metropolis";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(TEENAGENT_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, TeenAgentMetaEngineDetection);
|
||||
28
engines/teenagent/detection.h
Normal file
28
engines/teenagent/detection.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_DETECTION_H
|
||||
#define TEENAGENT_DETECTION_H
|
||||
|
||||
#define GAMEOPTION_TTS_OBJECTS GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_TTS_SPEECH GUIO_GAMEOPTIONS2
|
||||
|
||||
#endif // TEENAGENT_DETECTION_H
|
||||
171
engines/teenagent/dialog.cpp
Normal file
171
engines/teenagent/dialog.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/dialog.h"
|
||||
#include "teenagent/resources.h"
|
||||
#include "teenagent/scene.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
void Dialog::show(uint16 dialogNum, Scene *scene, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2) {
|
||||
uint32 addr = _vm->res->getDialogAddr(dialogNum);
|
||||
// WORKAROUND: For Dialog 163, The usage of this in the engine overlaps the previous dialog i.e. the
|
||||
// starting offset used is two bytes early, thus implicitly changing the first command of this dialog
|
||||
// from NEW_LINE to CHANGE_CHARACTER.
|
||||
// FIXME: Unsure if this is correct behaviour or if this is a regression from the original. Check this.
|
||||
// Similar issue occurs with Dialog 190 which is used from dialogue stack at 0x7403, rather than start of 0x7405
|
||||
// Similar issue occurs with Dialog 0 which is used from dialogue stack at 0x0001, rather than start of 0x0000
|
||||
if (dialogNum == 163)
|
||||
addr -= 2;
|
||||
show(scene, addr, animation1, animation2, character1ID, character2ID, slot1, slot2);
|
||||
}
|
||||
|
||||
void Dialog::show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2) {
|
||||
debugC(0, kDebugDialog, "Dialog::show(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
|
||||
int n = 0;
|
||||
uint16 voiceId = 0;
|
||||
Common::String message;
|
||||
byte color = characterDialogData[character1ID].textColor;
|
||||
byte color1 = color;
|
||||
byte color2 = characterDialogData[character2ID].textColor;
|
||||
|
||||
if (animation1 != 0) {
|
||||
SceneEvent e1(SceneEvent::kPlayAnimation);
|
||||
e1.animation = animation1;
|
||||
e1.slot = 0xc0 | slot1; //looped, paused
|
||||
scene->push(e1);
|
||||
}
|
||||
|
||||
if (animation2 != 0) {
|
||||
SceneEvent e2(SceneEvent::kPlayAnimation);
|
||||
e2.animation = animation2;
|
||||
e2.slot = 0xc0 | slot2; //looped, paused
|
||||
scene->push(e2);
|
||||
}
|
||||
|
||||
// Number of ANIM_WAIT (0xff) bytes.
|
||||
// Used to correctly find voice index.
|
||||
uint numOfAnimWaits = 0;
|
||||
|
||||
while (n < 4) {
|
||||
byte c = _vm->res->eseg.get_byte(addr++);
|
||||
debugC(1, kDebugDialog, "%02x: %c", c, c > 0x20? c: '.');
|
||||
|
||||
switch (c) {
|
||||
case 0:
|
||||
++n;
|
||||
switch (n) {
|
||||
case 1:
|
||||
debugC(1, kDebugDialog, "new line\n");
|
||||
if (!message.empty())
|
||||
message += '\n';
|
||||
break;
|
||||
case 2:
|
||||
debugC(1, kDebugDialog, "displaymessage %s", message.c_str());
|
||||
if (color == color2) {
|
||||
//pause animation in other slot
|
||||
SceneEvent e1(SceneEvent::kPauseAnimation);
|
||||
e1.slot = 0x80 | slot1;
|
||||
scene->push(e1);
|
||||
|
||||
SceneEvent e2(SceneEvent::kPlayAnimation);
|
||||
e2.animation = animation2;
|
||||
e2.slot = 0x80 | slot2;
|
||||
scene->push(e2);
|
||||
} else if (color == color1) {
|
||||
//pause animation in other slot
|
||||
SceneEvent e2(SceneEvent::kPauseAnimation);
|
||||
e2.slot = 0x80 | slot2;
|
||||
scene->push(e2);
|
||||
|
||||
SceneEvent e1(SceneEvent::kPlayAnimation);
|
||||
e1.animation = animation1;
|
||||
e1.slot = 0x80 | slot1;
|
||||
scene->push(e1);
|
||||
}
|
||||
|
||||
message.trim();
|
||||
voiceId = _vm->res->getVoiceIndex(addr - message.size() - numOfAnimWaits - 2); // -2 for '\n'
|
||||
if (!message.empty()) {
|
||||
SceneEvent em(SceneEvent::kMessage);
|
||||
em.message = message;
|
||||
em.color = color;
|
||||
if (color == color1) {
|
||||
em.slot = slot1;
|
||||
em.characterID = character1ID;
|
||||
}
|
||||
if (color == color2) {
|
||||
em.slot = slot2;
|
||||
em.characterID = character2ID;
|
||||
}
|
||||
em.voiceId = voiceId;
|
||||
scene->push(em);
|
||||
message.clear();
|
||||
numOfAnimWaits = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
color = (color == color1) ? color2 : color1;
|
||||
debugC(1, kDebugDialog, "changing color to %02x", color);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xff:
|
||||
numOfAnimWaits++;
|
||||
//FIXME : wait for the next cycle of the animation
|
||||
break;
|
||||
|
||||
default:
|
||||
message += c;
|
||||
n = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SceneEvent ec(SceneEvent::kClearAnimations);
|
||||
scene->push(ec);
|
||||
}
|
||||
|
||||
uint16 Dialog::pop(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2) {
|
||||
debugC(0, kDebugDialog, "Dialog::pop(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
|
||||
uint16 next;
|
||||
do {
|
||||
next = _vm->res->dseg.get_word(addr);
|
||||
addr += 2;
|
||||
} while (next == 0);
|
||||
uint16 next2 = _vm->res->dseg.get_word(addr);
|
||||
if (next2 != 0xffff)
|
||||
_vm->res->dseg.set_word(addr - 2, 0);
|
||||
|
||||
// Dialog addresses popped from stack are relative
|
||||
// to dialog start offset. So we add that offset first
|
||||
uint32 dialogAddr = _vm->res->getDialogStartPos() + next;
|
||||
show(scene, dialogAddr, animation1, animation2, character1ID, character2ID, slot1, slot2);
|
||||
return next;
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
143
engines/teenagent/dialog.h
Normal file
143
engines/teenagent/dialog.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_DIALOG_H
|
||||
#define TEENAGENT_DIALOG_H
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
// Text Color Symbols
|
||||
enum {
|
||||
textColorJohnNoty = 0xd0,
|
||||
textColorCampGuard = 0xd0,
|
||||
textColorShockedCaptain = 0xd0,
|
||||
textColorMark = 0xd1,
|
||||
textColorCredits = 0xd1,
|
||||
textColorBankGuard = 0xd7,
|
||||
textColorGrandpa = 0xd8,
|
||||
textColorMansionGuard = 0xd9,
|
||||
textColorMarkEnd = 0xe3,
|
||||
textColorProfessor = 0xe5,
|
||||
textColorOldLady = 0xe5,
|
||||
textColorAnne = 0xe5,
|
||||
textColorWellEcho = 0xe5,
|
||||
textColorSonny = 0xe5,
|
||||
textColorEskimo = 0xe5,
|
||||
textColorRGBBoss = 0xe7,
|
||||
textColorGoldDriver = 0xe7,
|
||||
textColorFortuneTeller = 0xeb,
|
||||
textColorCaptain = 0xec,
|
||||
textColorMike = 0xef,
|
||||
textColorCook = 0xef,
|
||||
textColorBarman = 0xef
|
||||
};
|
||||
|
||||
enum CharacterID {
|
||||
kMark = 0,
|
||||
kGoldDriver = 1,
|
||||
kBankGuard = 2,
|
||||
kRGBBoss = 3,
|
||||
kFortuneTeller = 4,
|
||||
kCampGuard = 5,
|
||||
kCaptain = 6,
|
||||
kShockedCaptain = 7,
|
||||
kBarman = 8,
|
||||
kSonny = 9,
|
||||
kGrandpa = 10,
|
||||
kAnne = 11,
|
||||
kWellEcho = 12,
|
||||
kOldLady = 13,
|
||||
kMansionGuard = 14,
|
||||
kJohnNoty = 15,
|
||||
kProfessor = 16,
|
||||
kCook = 17,
|
||||
kEskimo = 18,
|
||||
kMike = 19,
|
||||
kMarkEnd = 20,
|
||||
kCreditsText = 21
|
||||
};
|
||||
|
||||
struct CharacterDialogData {
|
||||
int voiceID;
|
||||
bool male;
|
||||
byte textColor;
|
||||
};
|
||||
|
||||
static const CharacterDialogData characterDialogData[] = {
|
||||
{ 0, true, textColorMark },
|
||||
{ 1, true, textColorGoldDriver },
|
||||
{ 2, true, textColorBankGuard },
|
||||
{ 3, true, textColorRGBBoss },
|
||||
{ 0, false, textColorFortuneTeller },
|
||||
{ 4, true, textColorCampGuard },
|
||||
{ 5, true, textColorCaptain },
|
||||
{ 5, true, textColorShockedCaptain }, // Same voice as captain
|
||||
{ 6, true, textColorBarman },
|
||||
{ 7, true, textColorSonny, },
|
||||
{ 8, true, textColorGrandpa },
|
||||
{ 1, false, textColorAnne },
|
||||
{ 9, true, textColorWellEcho },
|
||||
{ 2, false, textColorOldLady },
|
||||
{ 10, true, textColorMansionGuard },
|
||||
{ 11, true, textColorJohnNoty },
|
||||
{ 12, true, textColorProfessor },
|
||||
{ 13, true, textColorCook },
|
||||
{ 14, true, textColorEskimo },
|
||||
{ 15, true, textColorMike },
|
||||
{ 0, true, textColorMarkEnd }, // Same voice as Mark
|
||||
{ 0, true, textColorCredits } // Same voice as Mark
|
||||
};
|
||||
|
||||
class Scene;
|
||||
class TeenAgentEngine;
|
||||
|
||||
class Dialog {
|
||||
public:
|
||||
Dialog(TeenAgentEngine *vm) : _vm(vm) { }
|
||||
|
||||
uint16 pop(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2);
|
||||
|
||||
uint16 popMark(Scene *scene, uint16 addr) {
|
||||
return pop(scene, addr, 0, 0, kMark, kMark, 0, 0);
|
||||
}
|
||||
|
||||
void show(uint16 dialogNum, Scene *scene, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2);
|
||||
|
||||
void showMono(uint16 dialogNum, Scene *scene, uint16 animation, CharacterID characterID, byte slot) {
|
||||
show(dialogNum, scene, animation, animation, characterID, characterID, slot, slot);
|
||||
}
|
||||
|
||||
void showMark(uint16 dialogNum, Scene *scene) {
|
||||
show(dialogNum, scene, 0, 0, kMark, kMark, 0, 0);
|
||||
}
|
||||
|
||||
private:
|
||||
TeenAgentEngine *_vm;
|
||||
|
||||
void show(Scene *scene, uint32 addr, uint16 animation1, uint16 animation2, CharacterID character1ID, CharacterID character2ID, byte slot1, byte slot2);
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
169
engines/teenagent/font.cpp
Normal file
169
engines/teenagent/font.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/font.h"
|
||||
|
||||
#include "teenagent/pack.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/ptr.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
Font::Font() : _gridColor(0xd0), _shadowColor(0), _height(0), _widthPack(0), _data(0) {
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
void Font::load(const Pack &pack, int id, byte height, byte widthPack) {
|
||||
delete[] _data;
|
||||
_data = NULL;
|
||||
|
||||
Common::ScopedPtr<Common::SeekableReadStream> s(pack.getStream(id));
|
||||
if (!s)
|
||||
error("loading font %d failed", id);
|
||||
|
||||
_data = new byte[s->size()];
|
||||
s->read(_data, s->size());
|
||||
debugC(0, kDebugFont, "font size: %d", (int)s->size());
|
||||
|
||||
_height = height;
|
||||
_widthPack = widthPack;
|
||||
}
|
||||
|
||||
uint Font::render(Graphics::Surface *surface, int x, int y, char c, byte color) {
|
||||
unsigned idx = (unsigned char)c;
|
||||
if (idx < 0x20 || idx >= 0x81) {
|
||||
debugC(0, kDebugFont, "unhandled char 0x%02x", idx);
|
||||
return 0;
|
||||
}
|
||||
idx -= 0x20;
|
||||
byte *glyph = _data + READ_LE_UINT16(_data + idx * 2);
|
||||
|
||||
int h = glyph[0], w = glyph[1];
|
||||
if (surface == NULL || surface->getPixels() == NULL || y + h <= 0 || y >= kScreenHeight || x + w <= 0 || x >= kScreenWidth)
|
||||
return w - _widthPack;
|
||||
|
||||
int i0 = 0, j0 = 0;
|
||||
if (x < 0) {
|
||||
j0 = -x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) {
|
||||
i0 = -y;
|
||||
y = 0;
|
||||
}
|
||||
debugC(0, kDebugFont, "char %c, width: %dx%d", c, w, h);
|
||||
glyph += 2;
|
||||
glyph += i0 * w + j0;
|
||||
byte *dst = (byte *)surface->getBasePtr(x, y);
|
||||
byte *end = (byte *)surface->getBasePtr(0, surface->h);
|
||||
for (int i = i0; i < h && dst < end; ++i) {
|
||||
for (int j = j0; j < w; ++j) {
|
||||
byte v = *glyph++;
|
||||
switch (v) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
dst[j] = _shadowColor;
|
||||
break;
|
||||
case 2:
|
||||
dst[j] = color;
|
||||
break;
|
||||
default:
|
||||
dst[j] = v;
|
||||
}
|
||||
}
|
||||
dst += surface->pitch;
|
||||
}
|
||||
return w - _widthPack;
|
||||
}
|
||||
|
||||
static uint findInStr(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, byte color, bool showGrid) {
|
||||
if (surface != NULL) {
|
||||
uint maxW = render(NULL, 0, 0, str, false);
|
||||
if (showGrid)
|
||||
grid(surface, x - 4, y - 2, maxW + 8, 8 + 6, _gridColor);
|
||||
|
||||
uint i = 0, j;
|
||||
do {
|
||||
j = findInStr(str, '\n', i);
|
||||
Common::String line(str.c_str() + i, j - i);
|
||||
debugC(0, kDebugFont, "line: %s", line.c_str());
|
||||
|
||||
if (y + (int)_height >= 0) {
|
||||
uint w = render(NULL, 0, 0, line, false);
|
||||
int xp = x + (maxW - w) / 2;
|
||||
for (uint k = 0; k < line.size(); ++k) {
|
||||
xp += render(surface, xp, y, line[k], color);
|
||||
}
|
||||
} else if (y >= kScreenHeight)
|
||||
break;
|
||||
|
||||
y += _height;
|
||||
i = j + 1;
|
||||
} while (i < str.size());
|
||||
return maxW;
|
||||
} else {
|
||||
// surface == NULL;
|
||||
uint w = 0, maxW = 0;
|
||||
for (uint i = 0; i < str.size(); ++i) {
|
||||
char c = str[i];
|
||||
if (c == '\n') {
|
||||
y += _height;
|
||||
if (w > maxW)
|
||||
maxW = w;
|
||||
w = 0;
|
||||
continue;
|
||||
}
|
||||
w += render(NULL, 0, 0, c, color);
|
||||
}
|
||||
if (w > maxW)
|
||||
maxW = w;
|
||||
|
||||
return maxW;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
53
engines/teenagent/font.h
Normal file
53
engines/teenagent/font.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_FONT_H
|
||||
#define TEENAGENT_FONT_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
class Pack;
|
||||
|
||||
class Font {
|
||||
public:
|
||||
Font();
|
||||
~Font();
|
||||
|
||||
void load(const Pack &pack, int id, byte height, byte widthPack);
|
||||
uint render(Graphics::Surface *surface, int x, int y, const Common::String &str, byte color, bool showGrid = false);
|
||||
uint render(Graphics::Surface *surface, int x, int y, char c, byte color);
|
||||
static void grid(Graphics::Surface *surface, int x, int y, int w, int h, byte color);
|
||||
|
||||
byte getHeight() { return _height; }
|
||||
void setShadowColor(byte color) { _shadowColor = color; }
|
||||
private:
|
||||
byte *_data;
|
||||
|
||||
byte _gridColor, _shadowColor;
|
||||
byte _height, _widthPack;
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
372
engines/teenagent/inventory.cpp
Normal file
372
engines/teenagent/inventory.cpp
Normal file
@@ -0,0 +1,372 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "common/ptr.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "teenagent/inventory.h"
|
||||
|
||||
#include "teenagent/resources.h"
|
||||
#include "teenagent/objects.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
#include "teenagent/scene.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
Inventory::Inventory(TeenAgentEngine *vm) : _vm(vm) {
|
||||
_active = false;
|
||||
|
||||
FilePack varia;
|
||||
varia.open("varia.res");
|
||||
|
||||
Common::ScopedPtr<Common::SeekableReadStream> s(varia.getStream(3));
|
||||
if (!s)
|
||||
error("no inventory background");
|
||||
debugC(0, kDebugInventory, "loading inventory background...");
|
||||
_background.load(*s, Surface::kTypeOns);
|
||||
|
||||
uint32 itemsSize = varia.getSize(4);
|
||||
if (itemsSize == 0)
|
||||
error("invalid inventory items size");
|
||||
debugC(0, kDebugInventory, "loading items, size: %u", itemsSize);
|
||||
_items = new byte[itemsSize];
|
||||
varia.read(4, _items, itemsSize);
|
||||
|
||||
byte offsets = _items[0];
|
||||
assert(offsets == kNumInventoryItems);
|
||||
for (byte i = 0; i < offsets; ++i) {
|
||||
_offset[i] = READ_LE_UINT16(_items + i * 2 + 1);
|
||||
}
|
||||
_offset[kNumInventoryItems] = itemsSize;
|
||||
|
||||
InventoryObject ioBlank;
|
||||
_objects.push_back(ioBlank);
|
||||
for (byte i = 0; i < kNumInventoryItems; ++i) {
|
||||
InventoryObject io;
|
||||
uint32 objAddr = vm->res->getItemAddr(i);
|
||||
io.load(vm->res->eseg.ptr(objAddr));
|
||||
_objects.push_back(io);
|
||||
}
|
||||
|
||||
_inventory = vm->res->dseg.ptr(dsAddr_inventory);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
varia.close();
|
||||
_hoveredObj = _selectedObj = NULL;
|
||||
}
|
||||
|
||||
Inventory::~Inventory() {
|
||||
delete[] _items;
|
||||
}
|
||||
|
||||
bool Inventory::has(byte item) const {
|
||||
for (int i = 0; i < kInventorySize; ++i) {
|
||||
if (_inventory[i] == item)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Inventory::remove(byte item) {
|
||||
debugC(0, kDebugInventory, "removing %u from inventory", item);
|
||||
int i;
|
||||
for (i = 0; i < kInventorySize; ++i) {
|
||||
if (_inventory[i] == item) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; i < (kInventorySize - 1); ++i) {
|
||||
_inventory[i] = _inventory[i + 1];
|
||||
_graphics[i].free();
|
||||
}
|
||||
_inventory[kInventorySize - 1] = kInvItemNoItem;
|
||||
_graphics[kInventorySize - 1].free();
|
||||
}
|
||||
|
||||
void Inventory::clear() {
|
||||
debugC(0, kDebugInventory, "clearing inventory");
|
||||
for (int i = 0; i < kInventorySize; ++i) {
|
||||
_inventory[i] = kInvItemNoItem;
|
||||
_graphics[i].free();
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::reload() {
|
||||
for (int i = 0; i < kInventorySize; ++i) {
|
||||
_graphics[i].free();
|
||||
uint item = _inventory[i];
|
||||
if (item != kInvItemNoItem)
|
||||
_graphics[i].load(this, item);
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::add(byte item) {
|
||||
if (has(item))
|
||||
return;
|
||||
debugC(0, kDebugInventory, "adding %u to inventory", item);
|
||||
for (int i = 0; i < kInventorySize; ++i) {
|
||||
if (_inventory[i] == kInvItemNoItem) {
|
||||
_inventory[i] = item;
|
||||
return;
|
||||
}
|
||||
}
|
||||
error("no room for item %u", item);
|
||||
}
|
||||
|
||||
bool Inventory::tryObjectCallback(InventoryObject *obj) {
|
||||
byte objId = obj->id;
|
||||
for (uint i = 0; i < 7; ++i) {
|
||||
byte tableId = _vm->res->dseg.get_byte(dsAddr_objCallbackTablePtr + (3 * i));
|
||||
uint16 callbackAddr = _vm->res->dseg.get_word(dsAddr_objCallbackTablePtr + (3 * i) + 1);
|
||||
if (tableId == objId) {
|
||||
resetSelectedObject();
|
||||
activate(false);
|
||||
if (_vm->processCallback(callbackAddr))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Inventory::processEvent(const Common::Event &event) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
|
||||
if (!_active) {
|
||||
if (event.mouse.y < 5)
|
||||
activate(true);
|
||||
_mouse = event.mouse;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.mouse.x < 17 || event.mouse.x >= 303 || (event.mouse.y - _mouse.y > 0 && event.mouse.y >= 153)) {
|
||||
activate(false);
|
||||
_mouse = event.mouse;
|
||||
return false;
|
||||
}
|
||||
|
||||
_mouse = event.mouse;
|
||||
_hoveredObj = NULL;
|
||||
|
||||
for (int i = 0; i < kInventorySize; ++i) {
|
||||
byte item = _inventory[i];
|
||||
if (item == kInvItemNoItem)
|
||||
continue;
|
||||
|
||||
_graphics[i]._hovered = _graphics[i]._rect.in(_mouse);
|
||||
if (_graphics[i]._hovered)
|
||||
_hoveredObj = &_objects[item];
|
||||
}
|
||||
return true;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN: {
|
||||
//check combine
|
||||
if (!_active)
|
||||
return false;
|
||||
|
||||
if (_hoveredObj == NULL)
|
||||
return true;
|
||||
|
||||
debugC(0, kDebugInventory, "lclick on %u:%s", _hoveredObj->id, _hoveredObj->name.c_str());
|
||||
|
||||
if (_selectedObj == NULL) {
|
||||
if (tryObjectCallback(_hoveredObj))
|
||||
return true;
|
||||
//activate(false);
|
||||
int w = _vm->res->font7.render(NULL, 0, 0, _hoveredObj->description, textColorMark);
|
||||
uint16 voiceIndex = _vm->res->getVoiceIndex(_vm->res->getItemAddr(_hoveredObj->id - 1));
|
||||
_vm->scene->displayMessage(_hoveredObj->description, voiceIndex, textColorMark, Common::Point((kScreenWidth - w) / 2, 162));
|
||||
return true;
|
||||
}
|
||||
|
||||
int id1 = _selectedObj->id;
|
||||
int id2 = _hoveredObj->id;
|
||||
if (id1 == id2)
|
||||
return true;
|
||||
|
||||
debugC(0, kDebugInventory, "combine(%u, %u)!", id1, id2);
|
||||
for (uint i = 0; i < kNumCombinations; i++) {
|
||||
uint32 addr = _vm->res->getCombinationAddr(i);
|
||||
byte *table = _vm->res->eseg.ptr(addr);
|
||||
|
||||
if ((id1 == table[0] && id2 == table[1]) || (id2 == table[0] && id1 == table[1])) {
|
||||
byte newObj = table[2];
|
||||
if (newObj != 0) {
|
||||
remove(id1);
|
||||
remove(id2);
|
||||
debugC(0, kDebugInventory, "adding object %u", newObj);
|
||||
add(newObj);
|
||||
_vm->playSoundNow(&_vm->res->sam_sam, 69);
|
||||
}
|
||||
Common::String msg = Object::parseDescription((const char *)(table + 3));
|
||||
_vm->displayMessage(msg, _vm->res->getVoiceIndex(addr));
|
||||
activate(false);
|
||||
resetSelectedObject();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_vm->displayMessage(_vm->res->getMessageAddr(kObjCombineErrorMsg));
|
||||
activate(false);
|
||||
resetSelectedObject();
|
||||
return true;
|
||||
}
|
||||
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
if (!_active)
|
||||
return false;
|
||||
|
||||
if (_hoveredObj != NULL) {
|
||||
debugC(0, kDebugInventory, "rclick object %u:%s", _hoveredObj->id, _hoveredObj->name.c_str());
|
||||
// do not process callback for banknote on r-click
|
||||
if (_hoveredObj->id != kInvItemBanknote && tryObjectCallback(_hoveredObj))
|
||||
return true;
|
||||
}
|
||||
|
||||
_selectedObj = _hoveredObj;
|
||||
if (_selectedObj)
|
||||
debugC(0, kDebugInventory, "selected object %s", _selectedObj->name.c_str());
|
||||
return true;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (_active && event.customType == kActionCloseInventory) {
|
||||
activate(false);
|
||||
return true;
|
||||
}
|
||||
if (event.customType == kActionToggleInventory) {
|
||||
activate(!_active);
|
||||
return true;
|
||||
}
|
||||
if (event.customType == kActionSkipDialog)
|
||||
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::backgroundEffect(Graphics::Surface *s) {
|
||||
uint w = _rect.right - _rect.left, h = _rect.bottom - _rect.top;
|
||||
byte *line = (byte *)s->getBasePtr(_rect.left, _rect.top);
|
||||
for (uint y = 0; y < h; ++y, line += s->pitch) {
|
||||
byte *dst = line;
|
||||
for (uint x = 0; x < w; ++x, ++dst) {
|
||||
*dst = (*dst == 232) ? 214 : 224;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::Item::load(Inventory *inventory, uint itemId) {
|
||||
InventoryObject *obj = &inventory->_objects[itemId];
|
||||
if (obj->animated) {
|
||||
if (_animation.empty()) {
|
||||
debugC(0, kDebugInventory, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]);
|
||||
Common::MemoryReadStream s(inventory->_items + inventory->_offset[obj->id - 1], inventory->_offset[obj->id] - inventory->_offset[obj->id - 1]);
|
||||
_animation.load(s, Animation::kTypeInventory);
|
||||
}
|
||||
} else {
|
||||
if (_surface.empty()) {
|
||||
debugC(0, kDebugInventory, "loading item %d from offset %x", obj->id, inventory->_offset[obj->id - 1]);
|
||||
Common::MemoryReadStream s(inventory->_items + inventory->_offset[obj->id - 1], inventory->_offset[obj->id] - inventory->_offset[obj->id - 1]);
|
||||
_surface.load(s, Surface::kTypeOns);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::Item::render(Inventory *inventory, uint itemId, Graphics::Surface *dst, int delta) {
|
||||
InventoryObject *obj = &inventory->_objects[itemId];
|
||||
|
||||
backgroundEffect(dst);
|
||||
_rect.render(dst, _hovered ? 233 : 234);
|
||||
load(inventory, itemId);
|
||||
if (obj->animated) {
|
||||
if (_hovered) {
|
||||
Surface *s = _animation.currentFrame(delta);
|
||||
if (_animation.currentIndex() == 0)
|
||||
s = _animation.currentFrame(1); //force index to be 1 here
|
||||
if (s != NULL)
|
||||
s->render(dst, _rect.left + 1, _rect.top + 1);
|
||||
} else {
|
||||
Surface *s = _animation.firstFrame();
|
||||
if (s != NULL)
|
||||
s->render(dst, _rect.left + 1, _rect.top + 1);
|
||||
}
|
||||
} else {
|
||||
_surface.render(dst, _rect.left + 1, _rect.top + 1);
|
||||
}
|
||||
|
||||
Common::String name;
|
||||
if (inventory->_selectedObj) {
|
||||
name = inventory->_selectedObj->name;
|
||||
name += " & ";
|
||||
}
|
||||
if (inventory->_selectedObj != inventory->_hoveredObj)
|
||||
name += obj->name;
|
||||
|
||||
if (_hovered && inventory->_vm->scene->getMessage().empty()) {
|
||||
int w = inventory->_vm->res->font7.render(NULL, 0, 0, name, textColorMark, true);
|
||||
inventory->_vm->res->font7.render(dst, (kScreenWidth - w) / 2, 180, name, textColorMark, true);
|
||||
|
||||
inventory->_vm->sayText(name);
|
||||
} else if (!inventory->_hoveredObj && inventory->_vm->scene->getMessage().empty()) {
|
||||
inventory->_vm->_previousSaid.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::render(Graphics::Surface *surface, int delta) {
|
||||
if (!_active)
|
||||
return;
|
||||
debugC(0, kDebugInventory, "Inventory::render()");
|
||||
|
||||
_background.render(surface);
|
||||
|
||||
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) {
|
||||
debugC(0, kDebugInventory, "\t(x, y): %d,%d -> item: %u", x, y, item);
|
||||
_graphics[idx].render(this, item, surface, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
197
engines/teenagent/inventory.h
Normal file
197
engines/teenagent/inventory.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_INVENTORY_H
|
||||
#define TEENAGENT_INVENTORY_H
|
||||
|
||||
#include "teenagent/surface.h"
|
||||
#include "teenagent/animation.h"
|
||||
#include "common/events.h"
|
||||
#include "common/array.h"
|
||||
#include "teenagent/objects.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
struct InventoryObject;
|
||||
class TeenAgentEngine;
|
||||
|
||||
// Maximum number of items found within game
|
||||
const uint8 kNumInventoryItems = 92;
|
||||
|
||||
const uint kNumCombinations = 34;
|
||||
|
||||
// Inventory Item Ids
|
||||
enum {
|
||||
kInvItemNoItem = 0, // No item i.e. empty inventory slot
|
||||
kInvItemFeather = 1,
|
||||
kInvItemShotgun = 2,
|
||||
kInvItemToolboxFull = 3, // Contains Car Jack and Spanner
|
||||
kInvItemToolboxHalfEmpty = 4, // Contains Spanner
|
||||
kInvItemSpanner = 5,
|
||||
kInvItemComb = 6,
|
||||
kInvItemFan = 7,
|
||||
kInvItemBrokenPaddle = 8,
|
||||
kInvItemPaddle = 9, // Repaired - BrokenPaddle combined with Branch (with Glue)
|
||||
kInvItemFirstFlower = 10, // Smells nice
|
||||
kInvItemSecondFlower = 11, // Really beautiful
|
||||
kInvItemFeatherDusterClean = 12,
|
||||
kInvItemChainsaw = 13, // Unfueled
|
||||
kInvItemDrunkenChainsaw = 14, // Fueled with Whisky (Chainsaw combined with Whiskey)
|
||||
kInvItemBranch = 15,
|
||||
kInvItemWhisky = 16,
|
||||
kInvItemNeedle = 17,
|
||||
kInvItemWrapper = 18,
|
||||
kInvItemChocCandy = 19,
|
||||
kInvItemPotato = 20,
|
||||
kInvItemRakeBroken = 21,
|
||||
kInvItemHeartShapedCandy = 22,
|
||||
kInvItemWrappedCandy = 23, // HeartShapedCandy combined with Wrapper
|
||||
kInvItemRibbon = 24,
|
||||
kInvItemRakeFixed = 25, // Rake combined with Ribbon
|
||||
kInvItemNut = 26,
|
||||
kInvItemPlasticApple = 27,
|
||||
kInvItemCone = 28,
|
||||
kInvItemSuperGlue = 29,
|
||||
kInvItemConeAndNeedle = 30, // Cone combined with Needle
|
||||
kInvItemConeAndFeather = 31, // Cone combined with Feather
|
||||
kInvItemDart = 32, // Needle combined with ConeAndFeather or Feather combined with ConeAndNeedle
|
||||
kInvItemFeatherDusterDirty = 33,
|
||||
kInvItemPaintedPotato = 34, // Potato combined with Dirty Feather Duster (Soot)
|
||||
kInvItemCarJack = 35,
|
||||
kInvItemBone = 36,
|
||||
kInvItemShovelAct2 = 37,
|
||||
kInvItemRopeAct2 = 38,
|
||||
kInvItemMask = 39,
|
||||
kInvItemFins = 40,
|
||||
kInvItemDiveEquipment = 41, // Mask combined with Fins
|
||||
kInvItemAnchor = 42,
|
||||
kInvItemGrapplingHook = 43,
|
||||
kInvItemSickleBlunt = 44,
|
||||
kInvItemCheese = 45,
|
||||
kInvItemSickleSharp = 46,
|
||||
kInvItemHandkerchief = 47,
|
||||
kInvItemMouse = 48,
|
||||
kInvItemRock = 49,
|
||||
kInvItemNugget = 50,
|
||||
kInvItemBanknote = 51,
|
||||
kInvItemDictaphoneNoBatteries = 52,
|
||||
kInvItemPolaroidCamera = 53,
|
||||
kInvItemVideoTape = 54,
|
||||
kInvItemSheetOfPaper = 55,
|
||||
kInvItemCognac = 56,
|
||||
kInvItemRemoteControl = 57,
|
||||
kInvItemIceTongs = 58,
|
||||
kInvItemCork = 59,
|
||||
kInvItemWrappedCork = 60, // Cork combined with Sheet Of Paper
|
||||
kInvItemPhoto = 61,
|
||||
kInvItemChilliWithLabel = 62,
|
||||
kInvItemPastryRoller = 63,
|
||||
kInvItemFakeChilli = 64,
|
||||
kInvItemLabel = 65,
|
||||
kInvItemBatteries = 66,
|
||||
kInvItemDictaphoneWithBatteries = 67, // Dictaphone combined with Batteries
|
||||
kInvItemBurningPaper = 68,
|
||||
kInvItemMeat = 69,
|
||||
kInvItemPlasticBag = 70,
|
||||
kInvItemSocks = 71,
|
||||
kInvItemTimePills = 72,
|
||||
kInvItemHandle = 73,
|
||||
kInvItemChilliNoLabel = 74,
|
||||
kInvItemPass = 75,
|
||||
kInvItemBulb = 76,
|
||||
kInvItemJailKey = 77,
|
||||
kInvItemDelicatePlant = 78,
|
||||
kInvItemSwissArmyKnife = 79,
|
||||
kInvItemSpring = 80,
|
||||
kInvItemShovelAct1 = 81,
|
||||
kInvItemKaleidoscope = 82,
|
||||
kInvItemSoldierNews = 83,
|
||||
kInvItemGrenade = 84,
|
||||
kInvItemMug = 85, // Empty
|
||||
kInvItemMugOfMud = 86, // Full of mud
|
||||
kInvItemCrumbs = 87,
|
||||
kInvItemRopeAct1 = 88,
|
||||
kInvItemRopeAndGrenade = 89, // Rope combined with Grenade
|
||||
kInvItemMedicine = 90,
|
||||
kInvItemDruggedFood = 91, // Crumbs combined with Medicine
|
||||
kInvItemBird = 92
|
||||
};
|
||||
|
||||
// Maximum number of inventory items held by Ego (Mark)
|
||||
const uint8 kInventorySize = 24;
|
||||
|
||||
class Inventory {
|
||||
public:
|
||||
Inventory(TeenAgentEngine *vm);
|
||||
~Inventory();
|
||||
|
||||
void render(Graphics::Surface *surface, int delta);
|
||||
|
||||
void clear();
|
||||
void reload();
|
||||
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 _selectedObj; }
|
||||
void resetSelectedObject() { _selectedObj = NULL; }
|
||||
|
||||
private:
|
||||
TeenAgentEngine *_vm;
|
||||
Surface _background;
|
||||
byte *_items;
|
||||
uint _offset[kNumInventoryItems+1];
|
||||
|
||||
Common::Array<InventoryObject> _objects;
|
||||
byte *_inventory;
|
||||
|
||||
struct Item {
|
||||
Animation _animation;
|
||||
Surface _surface;
|
||||
Rect _rect;
|
||||
bool _hovered;
|
||||
|
||||
Item() : _hovered(false) {}
|
||||
void free();
|
||||
void load(Inventory *inventory, uint itemId);
|
||||
void backgroundEffect(Graphics::Surface *s);
|
||||
void render(Inventory *inventory, uint itemId, Graphics::Surface *surface, int delta);
|
||||
};
|
||||
|
||||
Item _graphics[kInventorySize];
|
||||
|
||||
bool _active;
|
||||
Common::Point _mouse;
|
||||
|
||||
bool tryObjectCallback(InventoryObject *obj);
|
||||
|
||||
InventoryObject *_hoveredObj;
|
||||
InventoryObject *_selectedObj;
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
252
engines/teenagent/metaengine.cpp
Normal file
252
engines/teenagent/metaengine.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/algorithm.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "base/plugins.h"
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "teenagent/resources.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
#include "teenagent/detection.h"
|
||||
#include "graphics/thumbnail.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
enum {
|
||||
MAX_SAVES = 20
|
||||
};
|
||||
|
||||
#ifdef USE_TTS
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_TTS_OBJECTS,
|
||||
{
|
||||
_s("Enable Text to Speech for Objects and Options"),
|
||||
_s("Use TTS to read the descriptions (if TTS is available)"),
|
||||
"tts_enabled_objects",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
GAMEOPTION_TTS_SPEECH,
|
||||
{
|
||||
_s("Enable Text to Speech for Subtitles"),
|
||||
_s("Use TTS to read the subtitles (if TTS is available)"),
|
||||
"tts_enabled_speech",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class TeenAgentMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "teenagent";
|
||||
}
|
||||
|
||||
bool hasFeature(MetaEngineFeature f) const override {
|
||||
switch (f) {
|
||||
case kSupportsListSaves:
|
||||
case kSupportsDeleteSave:
|
||||
case kSupportsLoadingDuringStartup:
|
||||
case kSavesSupportMetaInfo:
|
||||
case kSavesSupportThumbnail:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_TTS
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
|
||||
return optionsList;
|
||||
}
|
||||
#endif
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override {
|
||||
*engine = new TeenAgent::TeenAgentEngine(syst, desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::String getSavegameFile(int saveGameIdx, const char *target) const override {
|
||||
if (!target)
|
||||
target = getName();
|
||||
if (saveGameIdx == kSavegameFilePattern)
|
||||
return Common::String::format("%s.##", target);
|
||||
else
|
||||
return Common::String::format("%s.%02d", target, saveGameIdx);
|
||||
}
|
||||
|
||||
SaveStateList listSaves(const char *target) const override {
|
||||
Common::String pattern = target;
|
||||
pattern += ".##";
|
||||
|
||||
Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
|
||||
|
||||
SaveStateList saveList;
|
||||
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
|
||||
int slot = atoi(file->c_str() + file->size() - 2);
|
||||
if (slot >= 0 && slot < MAX_SAVES) {
|
||||
Common::ScopedPtr<Common::InSaveFile> in(g_system->getSavefileManager()->openForLoading(*file));
|
||||
if (!in)
|
||||
continue;
|
||||
|
||||
char buf[25];
|
||||
in->seek(0);
|
||||
in->read(buf, 24);
|
||||
buf[24] = 0;
|
||||
saveList.push_back(SaveStateDescriptor(this, slot, buf));
|
||||
}
|
||||
}
|
||||
// Sort saves based on slot number.
|
||||
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
|
||||
return saveList;
|
||||
}
|
||||
|
||||
int getMaximumSaveSlot() const override {
|
||||
return MAX_SAVES - 1;
|
||||
}
|
||||
|
||||
bool removeSaveState(const char *target, int slot) const override {
|
||||
return g_system->getSavefileManager()->removeSavefile(getSavegameFile(slot, target));
|
||||
}
|
||||
|
||||
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override {
|
||||
Common::String filename = getSavegameFile(slot, target);
|
||||
Common::ScopedPtr<Common::InSaveFile> in(g_system->getSavefileManager()->openForLoading(filename));
|
||||
if (!in)
|
||||
return SaveStateDescriptor();
|
||||
|
||||
char buf[25];
|
||||
in->seek(0);
|
||||
in->read(buf, 24);
|
||||
buf[24] = 0;
|
||||
|
||||
Common::String desc = buf;
|
||||
|
||||
in->seek(TeenAgent::saveStateSize);
|
||||
|
||||
uint32 tag = in->readUint32BE();
|
||||
if (tag == MKTAG('T', 'N', 'G', 'T')) {
|
||||
// Skip save version
|
||||
in->skip(1);
|
||||
|
||||
// Skip scene object data
|
||||
uint32 size = in->readUint32LE();
|
||||
in->skip(size);
|
||||
} else {
|
||||
in->seek(-4, SEEK_CUR);
|
||||
}
|
||||
|
||||
if (!Graphics::checkThumbnailHeader(*in))
|
||||
return SaveStateDescriptor(this, slot, desc);
|
||||
|
||||
SaveStateDescriptor ssd(this, slot, desc);
|
||||
|
||||
//checking for the thumbnail
|
||||
Graphics::Surface *thumbnail;
|
||||
if (!Graphics::loadThumbnail(*in, thumbnail)) {
|
||||
return SaveStateDescriptor();
|
||||
}
|
||||
ssd.setThumbnail(thumbnail);
|
||||
|
||||
return ssd;
|
||||
}
|
||||
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
Common::KeymapArray TeenAgentMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace TeenAgent;
|
||||
|
||||
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "teenagent-default", _("Default keymappings"));
|
||||
|
||||
Common::Action *act;
|
||||
|
||||
act = new Common::Action(kStandardActionLeftClick, _("Move / Examine"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Common::Action(kStandardActionRightClick, _("Interact"));
|
||||
act->setRightClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Common::Action("SKIPDLG", _("Skip dialog"));
|
||||
act->setCustomEngineActionEvent(kActionSkipDialog);
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("SPACE");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Common::Action("CLOSEINV", _("Close inventory"));
|
||||
act->setCustomEngineActionEvent(kActionCloseInventory);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Common::Action("TOGGLEINV", _("Toggle inventory"));
|
||||
act->setCustomEngineActionEvent(kActionToggleInventory);
|
||||
act->addDefaultInputMapping("RETURN");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Common::Action("SKIPINTRO", _("Skip intro"));
|
||||
act->setCustomEngineActionEvent(kActionSkipIntro);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
// I18N: Speeds up the game to twice its normal speed
|
||||
act = new Common::Action("FASTMODE", _("Toggle fast mode"));
|
||||
act->setCustomEngineActionEvent(kActionFastMode);
|
||||
act->addDefaultInputMapping("C+f");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
return Keymap::arrayOf(engineKeyMap);
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(TEENAGENT)
|
||||
REGISTER_PLUGIN_DYNAMIC(TEENAGENT, PLUGIN_TYPE_ENGINE, TeenAgentMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(TEENAGENT, PLUGIN_TYPE_ENGINE, TeenAgentMetaEngine);
|
||||
#endif
|
||||
31
engines/teenagent/module.mk
Normal file
31
engines/teenagent/module.mk
Normal file
@@ -0,0 +1,31 @@
|
||||
MODULE := engines/teenagent
|
||||
|
||||
MODULE_OBJS := \
|
||||
actor.o \
|
||||
animation.o \
|
||||
callbacks.o \
|
||||
console.o \
|
||||
dialog.o \
|
||||
font.o \
|
||||
inventory.o \
|
||||
metaengine.o \
|
||||
music.o \
|
||||
objects.o \
|
||||
pack.o \
|
||||
resources.o \
|
||||
scene.o \
|
||||
segment.o \
|
||||
surface.o \
|
||||
surface_list.o \
|
||||
teenagent.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_TEENAGENT), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
152
engines/teenagent/music.cpp
Normal file
152
engines/teenagent/music.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/music.h"
|
||||
#include "teenagent/resources.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/ptr.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
static const 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(TeenAgentEngine *vm) : Paula(false, 44100, 5000), _vm(vm), _id(0), _currRow(0) {
|
||||
}
|
||||
|
||||
MusicPlayer::~MusicPlayer() {
|
||||
stop();
|
||||
}
|
||||
|
||||
bool MusicPlayer::load(int id) {
|
||||
debugC(0, kDebugMusic, "MusicPlayer::load(%d)", id);
|
||||
Common::ScopedPtr<Common::SeekableReadStream> stream(_vm->res->mmm.getStream(id));
|
||||
if (!stream)
|
||||
return false;
|
||||
|
||||
char header[4];
|
||||
stream->read(header, 4);
|
||||
// check header?
|
||||
|
||||
Common::StackLock lock(_mutex);
|
||||
// Load the samples
|
||||
byte sampleCount = stream->readByte();
|
||||
|
||||
debugC(0, kDebugMusic, "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);
|
||||
debugC(0, kDebugMusic, "currSample = %d, sample = 0x%02x, resource: %d", currSample, sample, sampleResource);
|
||||
uint32 sampleSize = _vm->res->sam_mmm.getSize(sampleResource);
|
||||
if (sampleSize == 0) {
|
||||
warning("load: invalid sample %d (0x%02x)", sample, sample);
|
||||
_samples[sample].clear();
|
||||
continue;
|
||||
}
|
||||
|
||||
_samples[sample].resize(sampleSize);
|
||||
_vm->res->sam_mmm.read(sampleResource, _samples[sample].data, sampleSize);
|
||||
}
|
||||
|
||||
// Load the music data
|
||||
_rows.clear();
|
||||
|
||||
Row row;
|
||||
while (!stream->eos()) {
|
||||
|
||||
byte cmd = stream->readByte();
|
||||
|
||||
if (cmd < 0x40) {
|
||||
row.channels[0].note = cmd;
|
||||
row.channels[1].note = stream->readByte();
|
||||
row.channels[2].note = stream->readByte();
|
||||
_rows.push_back(row);
|
||||
} else if ((cmd & 0xf0) == 0x50) {
|
||||
byte sample = stream->readByte();
|
||||
debugC(1, kDebugMusic, "%02x: set sample %02x", cmd, sample);
|
||||
row.channels[(cmd & 0x0f) - 1].sample = sample;
|
||||
} else if ((cmd & 0xf0) == 0x40) {
|
||||
byte vol = stream->readByte();
|
||||
debugC(1, kDebugMusic, "%02x: set volume %02x -> %02x", cmd, row.channels[(cmd & 0x0f) - 1].volume, vol);
|
||||
// channel volume 0x40 * music volume 0x40 mixed with high bytes
|
||||
row.channels[(cmd & 0x0f) - 1].volume = vol * 16;
|
||||
} else {
|
||||
debugC(0, kDebugMusic, "unhandled music command %02x", cmd);
|
||||
}
|
||||
}
|
||||
_currRow = 0;
|
||||
_id = id;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MusicPlayer::start() {
|
||||
_currRow = 0;
|
||||
startPaula();
|
||||
}
|
||||
|
||||
void MusicPlayer::stop() {
|
||||
stopPaula();
|
||||
}
|
||||
|
||||
void MusicPlayer::interrupt() {
|
||||
if (_rows.empty())
|
||||
return;
|
||||
|
||||
_currRow %= _rows.size();
|
||||
|
||||
Row *row = &_rows[_currRow];
|
||||
for (int chn = 0; chn < 3; ++chn) {
|
||||
setChannelVolume(chn, row->channels[chn].volume);
|
||||
|
||||
debugC(2, kDebugMusic, "row->channels[%d].volume = %d", chn, row->channels[chn].volume);
|
||||
|
||||
byte sample = (row->channels[chn].sample);
|
||||
if (row->channels[chn].note != 0 && sample != 0) {
|
||||
|
||||
debugC(2, kDebugMusic, "row->channels[%d].note = %d", chn, row->channels[chn].note);
|
||||
debugC(2, kDebugMusic, "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)]);
|
||||
}
|
||||
}
|
||||
|
||||
debugC(2, kDebugMusic, "------------------------------------------------");
|
||||
|
||||
++_currRow;
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
85
engines/teenagent/music.h
Normal file
85
engines/teenagent/music.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEEN_MUSIC_H
|
||||
#define TEEN_MUSIC_H
|
||||
|
||||
#include "audio/mods/paula.h"
|
||||
#include "common/array.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
class TeenAgentEngine;
|
||||
|
||||
class MusicPlayer : public Audio::Paula {
|
||||
public:
|
||||
MusicPlayer(TeenAgentEngine *vm);
|
||||
~MusicPlayer() override;
|
||||
|
||||
bool load(int id);
|
||||
int getId() const { return _id; }
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
TeenAgentEngine *_vm;
|
||||
|
||||
int _id;
|
||||
|
||||
struct Row {
|
||||
struct Channel {
|
||||
byte sample;
|
||||
byte volume;
|
||||
byte note;
|
||||
Channel(): sample(0), volume(0x40), note(0) {}
|
||||
} channels[3];
|
||||
};
|
||||
|
||||
struct Sample {
|
||||
byte *data;
|
||||
uint size;
|
||||
Sample(): data(0), size(0) {}
|
||||
~Sample() { delete[] data; }
|
||||
|
||||
void resize(uint s) {
|
||||
if (s != size) {
|
||||
delete[] data;
|
||||
data = new byte[s];
|
||||
size = s;
|
||||
}
|
||||
}
|
||||
void clear() {
|
||||
delete[] data;
|
||||
data = 0;
|
||||
size = 0;
|
||||
}
|
||||
} _samples[256];
|
||||
|
||||
Common::Array<Row> _rows;
|
||||
uint _currRow;
|
||||
|
||||
void interrupt() override;
|
||||
};
|
||||
|
||||
} // End of namespace Teen
|
||||
|
||||
#endif // TEEN_MUSIC_H
|
||||
200
engines/teenagent/objects.cpp
Normal file
200
engines/teenagent/objects.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
#include "teenagent/objects.h"
|
||||
#include "teenagent/resources.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
void Rect::load(byte *src) {
|
||||
_base = src;
|
||||
Common::MemoryReadStream ins(src, 8);
|
||||
left = ins.readUint16LE();
|
||||
top = ins.readUint16LE();
|
||||
right = ins.readUint16LE();
|
||||
bottom = ins.readUint16LE();
|
||||
}
|
||||
|
||||
void Rect::save() const {
|
||||
assert(_base != NULL);
|
||||
Common::MemoryWriteStream outs(_base, 8);
|
||||
outs.writeUint16LE(left);
|
||||
outs.writeUint16LE(top);
|
||||
outs.writeUint16LE(right);
|
||||
outs.writeUint16LE(bottom);
|
||||
}
|
||||
|
||||
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 Object::load(byte *src, byte sceneId) {
|
||||
_base = src;
|
||||
_addr = src - g_engine->res->eseg.ptr(0);
|
||||
|
||||
id = *src++;
|
||||
|
||||
rect.load(src);
|
||||
src += 8;
|
||||
actorRect.load(src);
|
||||
src += 8;
|
||||
|
||||
actorOrientation = *src++;
|
||||
enabled = *src++;
|
||||
name = (const char *)src;
|
||||
_nameSize = name.size() + 1;
|
||||
src += _nameSize;
|
||||
|
||||
bool hasRealName = (sceneId == 6 && id == 4) ||
|
||||
(sceneId == 23 && id == 2) ||
|
||||
(sceneId == 20 && id == 13) ||
|
||||
(sceneId == 32 && id == 1);
|
||||
// Skip free space (if any) made for objects that have newName
|
||||
if (hasRealName) {
|
||||
while (*src == 0)
|
||||
src++;
|
||||
}
|
||||
|
||||
if (*src == 1)
|
||||
_hasDefaultDescription = true;
|
||||
|
||||
description = parseDescription((const char *)src);
|
||||
|
||||
if (hasRealName) {
|
||||
src += description.size() + 2;
|
||||
_realName = (const char *)src;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::save() const {
|
||||
assert(_base != NULL);
|
||||
|
||||
rect.save();
|
||||
actorRect.save();
|
||||
_base[17] = actorOrientation;
|
||||
_base[18] = enabled;
|
||||
}
|
||||
|
||||
void Object::setRealName() {
|
||||
assert(_base != 0);
|
||||
Common::strcpy_s((char *)(_base + 19), _nameSize, _realName.c_str());
|
||||
name = _realName;
|
||||
}
|
||||
|
||||
void Object::dump(int level) const {
|
||||
debugC(level, kDebugObject, "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,
|
||||
actorRect.left, actorRect.top, actorRect.right, actorRect.bottom,
|
||||
actorOrientation, name.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
Common::String Object::parseDescription(const char *desc) {
|
||||
if (*desc == 0)
|
||||
return Common::String();
|
||||
|
||||
Common::String result;
|
||||
|
||||
while (*desc != 1 && *desc != 0) {
|
||||
Common::String line;
|
||||
while (*desc != 1 && *desc != 0) {
|
||||
debugC(2, kDebugObject, "%02x ", *desc);
|
||||
line += *desc++;
|
||||
}
|
||||
|
||||
if (line.empty())
|
||||
break;
|
||||
|
||||
++desc;
|
||||
result += line;
|
||||
result += '\n';
|
||||
}
|
||||
if (!result.empty())
|
||||
result.deleteLastChar();
|
||||
else
|
||||
result = g_engine->parseMessage(g_engine->res->getMessageAddr(kCoolMsg));
|
||||
return result;
|
||||
}
|
||||
|
||||
void InventoryObject::load(byte *src) {
|
||||
_base = src;
|
||||
id = *src++;
|
||||
animated = *src++;
|
||||
name = (const char *)src;
|
||||
description = Object::parseDescription((const char *)src);
|
||||
}
|
||||
|
||||
void UseHotspot::load(byte *src) {
|
||||
Common::MemoryReadStream in(src, 9);
|
||||
inventoryId = in.readByte();
|
||||
objectId = in.readByte();
|
||||
orientation = in.readByte();
|
||||
actorX = in.readUint16LE();
|
||||
actorY = in.readUint16LE();
|
||||
callback = in.readUint16LE();
|
||||
}
|
||||
|
||||
void UseHotspot::dump(int level) const {
|
||||
debugC(level, kDebugObject,
|
||||
"hotspot: invId: %02x, objId: %02x, orientation: %02x, actor position: (%d,%d), callback: %04x",
|
||||
inventoryId, objectId, orientation, actorX, actorY, callback
|
||||
);
|
||||
}
|
||||
|
||||
void Walkbox::dump(int level) const {
|
||||
debugC(level, kDebugObject, "walkbox %02x %02x [%d, %d, %d, %d] top: %u, right: %u, bottom: %u, left: %u",
|
||||
type, orientation,
|
||||
rect.left, rect.top, rect.right, rect.bottom,
|
||||
sideHint[0], sideHint[1], sideHint[2], sideHint[3]);
|
||||
}
|
||||
|
||||
void Walkbox::load(byte *src) {
|
||||
_base = src;
|
||||
|
||||
type = *src++;
|
||||
orientation = *src++;
|
||||
rect.load(src);
|
||||
src += 8;
|
||||
for (byte i = 0; i < 4; ++i)
|
||||
sideHint[i] = *src++;
|
||||
}
|
||||
|
||||
void Walkbox::save() const {
|
||||
assert(_base != NULL);
|
||||
_base[0] = type;
|
||||
_base[1] = orientation;
|
||||
rect.save();
|
||||
}
|
||||
|
||||
void FadeType::load(byte *src) {
|
||||
rect.load(src);
|
||||
src += 8;
|
||||
value = *src;
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
246
engines/teenagent/objects.h
Normal file
246
engines/teenagent/objects.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TEENAGENT_OBJECTS_H
|
||||
#define TEENAGENT_OBJECTS_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
enum {kActorUp = 1, kActorRight = 2, kActorDown = 3, kActorLeft = 4 };
|
||||
|
||||
struct Rect {
|
||||
int16 left, top, right, bottom;
|
||||
|
||||
inline Rect() : left(0), top(0), right(0), bottom(0), _base(NULL) {}
|
||||
inline Rect(const Common::Rect &r) : left(r.left), top(r.top), right(r.right), bottom(r.bottom), _base(NULL) {}
|
||||
inline Rect(uint16 l, uint16 t, uint16 r, uint16 b) : left(l), top(t), right(r), bottom(b), _base(NULL) {}
|
||||
|
||||
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 >= 0 && left < kScreenWidth && right >= 0 && right < kScreenWidth && top >= 0 && top < kScreenHeight && bottom >= 0 && bottom < kScreenHeight;
|
||||
}
|
||||
|
||||
void render(Graphics::Surface *surface, uint8 color) const;
|
||||
|
||||
void dump(int level = 0) const {
|
||||
debugC(level, kDebugObject, "rect[%u, %u, %u, %u]", left, top, right, bottom);
|
||||
}
|
||||
|
||||
inline void clear() {
|
||||
left = top = right = bottom = 0;
|
||||
}
|
||||
|
||||
void load(byte *src); //8 bytes
|
||||
void save() const;
|
||||
|
||||
inline bool intersects_hline(int x1, int x2, int y) const {
|
||||
if (x1 > x2)
|
||||
SWAP(x1, x2);
|
||||
return y >= top && y <= bottom && x1 <= right && x2 >= left;
|
||||
}
|
||||
|
||||
inline bool intersects_vline(int x, int y1, int y2) const {
|
||||
if (y1 > y2)
|
||||
SWAP(y1, y2);
|
||||
return x >= left && x <= right && y1 <= bottom && y2 >= top;
|
||||
}
|
||||
|
||||
inline bool contains(const Rect &rect) const {
|
||||
return rect.left >= left && rect.right <= right && rect.top >= top && rect.bottom <= bottom;
|
||||
}
|
||||
|
||||
static inline bool inside(int x, int a, int b) {
|
||||
if (a > b)
|
||||
SWAP(a, b);
|
||||
return x >= a && x <= b;
|
||||
}
|
||||
|
||||
int intersects_line(const Common::Point &a, const Common::Point &b) const {
|
||||
int dy = b.y - a.y, dx = b.x - a.x;
|
||||
|
||||
int mask = 0; //orientation bitmask: 1 - top, 2 - right, 3 - bottom, 4 - left
|
||||
|
||||
if (dx != 0) {
|
||||
int yl = (left - a.x) * dy / dx + a.y;
|
||||
if (yl > top && yl < bottom && inside(yl, a.y, b.y) && inside(left, a.x, b.x)) {
|
||||
//c[idx++] = Common::Point(left, yl);
|
||||
mask |= 8;
|
||||
}
|
||||
int yr = (right - a.x) * dy / dx + a.y;
|
||||
if (yr > top && yr < bottom && inside(yr, a.y, b.y) && inside(right, a.x, b.x)) {
|
||||
//c[idx++] = Common::Point(right, yr);
|
||||
mask |= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (dy != 0) {
|
||||
int xt = (top - a.y) * dx / dy + a.x;
|
||||
if (xt > left && xt < right && inside(xt, a.x, b.x) && inside(top, a.y, b.y)) {
|
||||
//assert(idx < 2);
|
||||
//c[idx++] = Common::Point(xt, top);
|
||||
mask |= 1;
|
||||
}
|
||||
int xb = (bottom - a.y) * dx / dy + a.x;
|
||||
if (xb > left && xb < right && inside(xb, a.x, b.x) && inside(bottom, a.y, b.y)) {
|
||||
//assert(idx < 2);
|
||||
//c[idx++] = Common::Point(xb, bottom);
|
||||
mask |= 4;
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
void side(Common::Point &p1, Common::Point &p2, int o, const Common::Point &nearest) const {
|
||||
switch (o) {
|
||||
case kActorLeft:
|
||||
p1 = Common::Point(left, top);
|
||||
p2 = Common::Point(left, bottom);
|
||||
break;
|
||||
|
||||
case kActorRight:
|
||||
p1 = Common::Point(right, top);
|
||||
p2 = Common::Point(right, bottom);
|
||||
break;
|
||||
|
||||
case kActorUp:
|
||||
p1 = Common::Point(left, top);
|
||||
p2 = Common::Point(right, top);
|
||||
break;
|
||||
|
||||
case kActorDown:
|
||||
p1 = Common::Point(left, bottom);
|
||||
p2 = Common::Point(right, bottom);
|
||||
break;
|
||||
|
||||
default:
|
||||
p1 = Common::Point();
|
||||
p2 = Common::Point();
|
||||
}
|
||||
if (p1.sqrDist(nearest) >= p2.sqrDist(nearest))
|
||||
SWAP(p1, p2);
|
||||
}
|
||||
|
||||
protected:
|
||||
byte *_base;
|
||||
};
|
||||
|
||||
struct Object {
|
||||
byte id; //0
|
||||
Rect rect; //1
|
||||
Rect actorRect; //9
|
||||
byte actorOrientation; //17
|
||||
byte enabled; //18
|
||||
//19
|
||||
Common::String name, description;
|
||||
|
||||
Object(): _base(NULL), _nameSize(0) { id = 0; actorOrientation = 0; enabled = 0; _hasDefaultDescription = false; }
|
||||
void dump(int level = 0) const;
|
||||
void setRealName();
|
||||
void load(byte *addr, byte sceneId = 0);
|
||||
void save() const;
|
||||
|
||||
bool hasDefaultDescription() { return _hasDefaultDescription; }
|
||||
uint32 getAddr() { return _addr; };
|
||||
|
||||
static Common::String parseDescription(const char *desc);
|
||||
|
||||
protected:
|
||||
byte *_base;
|
||||
size_t _nameSize;
|
||||
|
||||
// New name that will be set when certain event is triggered
|
||||
Common::String _realName;
|
||||
|
||||
bool _hasDefaultDescription;
|
||||
uint32 _addr = 0; // Address inside eseg
|
||||
};
|
||||
|
||||
struct InventoryObject {
|
||||
byte id;
|
||||
byte animated;
|
||||
Common::String name, description;
|
||||
|
||||
InventoryObject(): id(0), animated(0), _base(0) {}
|
||||
void load(byte *addr);
|
||||
|
||||
protected:
|
||||
byte *_base;
|
||||
};
|
||||
|
||||
struct UseHotspot {
|
||||
byte inventoryId;
|
||||
byte objectId;
|
||||
byte orientation;
|
||||
uint16 actorX, actorY;
|
||||
uint16 callback;
|
||||
void load(byte *src);
|
||||
void dump(int level = 0) const;
|
||||
};
|
||||
|
||||
struct Walkbox {
|
||||
byte type;
|
||||
byte orientation;
|
||||
Rect rect;
|
||||
byte sideHint[4];
|
||||
|
||||
Walkbox() {
|
||||
_base = nullptr;
|
||||
type = 0;
|
||||
orientation = 0;
|
||||
// rect cleared by Rect constructor
|
||||
for (uint i = 0; i < ARRAYSIZE(sideHint); i++) {
|
||||
sideHint[i] = 0;
|
||||
}
|
||||
}
|
||||
void dump(int level = 0) const;
|
||||
void load(byte *src);
|
||||
void save() const;
|
||||
|
||||
protected:
|
||||
byte *_base;
|
||||
};
|
||||
|
||||
struct FadeType {
|
||||
Rect rect;
|
||||
byte value;
|
||||
|
||||
void load(byte *src);
|
||||
};
|
||||
|
||||
//\todo move it to util.h?
|
||||
template<typename T> inline T SIGN(T x) { return (x > 0) ? 1 : ((x < 0) ? -1 : 0); }
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
202
engines/teenagent/pack.cpp
Normal file
202
engines/teenagent/pack.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/pack.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
#include "common/util.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/substream.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
FilePack::FilePack() : offsets(0) {}
|
||||
|
||||
FilePack::~FilePack() {
|
||||
close();
|
||||
}
|
||||
|
||||
void FilePack::close() {
|
||||
delete[] offsets;
|
||||
offsets = NULL;
|
||||
file.close();
|
||||
}
|
||||
|
||||
bool FilePack::open(const Common::Path &filename) {
|
||||
if (!file.exists(filename) || !file.open(filename))
|
||||
return false;
|
||||
|
||||
_fileCount = file.readUint32LE();
|
||||
debugC(0, kDebugPack, "opened %s, found %u entries", filename.toString().c_str(), _fileCount);
|
||||
offsets = new uint32[_fileCount + 1];
|
||||
for (uint32 i = 0; i <= _fileCount; ++i) {
|
||||
offsets[i] = file.readUint32LE();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 FilePack::getSize(uint32 id) const {
|
||||
if (id < 1 || id > _fileCount)
|
||||
return 0;
|
||||
return offsets[id] - offsets[id - 1];
|
||||
}
|
||||
|
||||
uint32 FilePack::read(uint32 id, byte *dst, uint32 size) const {
|
||||
if (id < 1 || id > _fileCount)
|
||||
return 0;
|
||||
|
||||
file.seek(offsets[id - 1]);
|
||||
uint32 rsize = offsets[id] - offsets[id - 1];
|
||||
uint32 r = file.read(dst, MIN(rsize, size));
|
||||
debugC(0, kDebugPack, "read(%u, %u) = %u", id, size, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *FilePack::getStream(uint32 id) const {
|
||||
if (id < 1 || id > _fileCount)
|
||||
return NULL;
|
||||
debugC(0, kDebugPack, "stream: %04x-%04x", offsets[id - 1], offsets[id]);
|
||||
return new Common::SeekableSubReadStream(&file, offsets[id - 1], offsets[id]);
|
||||
}
|
||||
|
||||
TransientFilePack::TransientFilePack() : offsets(0) {}
|
||||
|
||||
TransientFilePack::~TransientFilePack() {
|
||||
close();
|
||||
}
|
||||
|
||||
void TransientFilePack::close() {
|
||||
delete[] offsets;
|
||||
offsets = NULL;
|
||||
_filename.clear();
|
||||
}
|
||||
|
||||
bool TransientFilePack::open(const Common::Path &filename) {
|
||||
_filename = filename;
|
||||
|
||||
Common::File file;
|
||||
if (!file.exists(filename) || !file.open(filename))
|
||||
return false;
|
||||
|
||||
_fileCount = file.readUint32LE();
|
||||
debugC(0, kDebugPack, "opened %s, found %u entries", filename.toString().c_str(), _fileCount);
|
||||
offsets = new uint32[_fileCount + 1];
|
||||
for (uint32 i = 0; i <= _fileCount; ++i) {
|
||||
offsets[i] = file.readUint32LE();
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 TransientFilePack::getSize(uint32 id) const {
|
||||
if (id < 1 || id > _fileCount)
|
||||
return 0;
|
||||
return offsets[id] - offsets[id - 1];
|
||||
}
|
||||
|
||||
uint32 TransientFilePack::read(uint32 id, byte *dst, uint32 size) const {
|
||||
if (id < 1 || id > _fileCount)
|
||||
return 0;
|
||||
|
||||
Common::File file;
|
||||
if (!file.open(_filename))
|
||||
return 0;
|
||||
|
||||
file.seek(offsets[id - 1]);
|
||||
uint32 rsize = offsets[id] - offsets[id - 1];
|
||||
uint32 r = file.read(dst, MIN(rsize, size));
|
||||
file.close();
|
||||
debugC(0, kDebugPack, "read(%u, %u) = %u", id, size, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *TransientFilePack::getStream(uint32 id) const {
|
||||
if (id < 1 || id > _fileCount)
|
||||
return NULL;
|
||||
debugC(0, kDebugPack, "stream: %04x-%04x", offsets[id - 1], offsets[id]);
|
||||
Common::File file;
|
||||
if (!file.open(_filename))
|
||||
return NULL;
|
||||
|
||||
file.seek(offsets[id - 1]);
|
||||
uint32 size = offsets[id] - offsets[id - 1];
|
||||
byte *ptr = (byte *)malloc(size);
|
||||
if (ptr == NULL)
|
||||
return NULL;
|
||||
uint32 r = file.read(ptr, size);
|
||||
file.close();
|
||||
return new Common::MemoryReadStream(ptr, r, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
void MemoryPack::close() {
|
||||
chunks.clear();
|
||||
}
|
||||
|
||||
bool MemoryPack::open(const Common::Path &filename) {
|
||||
Common::File file;
|
||||
if (!file.exists(filename) || !file.open(filename))
|
||||
return false;
|
||||
|
||||
uint32 count = file.readUint32LE();
|
||||
debugC(0, kDebugPack, "opened %s, found %u entries [memory]", filename.toString().c_str(), count);
|
||||
for (uint32 i = 0; i < count; ++i) {
|
||||
uint32 offset = file.readUint32LE();
|
||||
int32 pos = file.pos();
|
||||
uint32 next_offset = file.readUint32LE();
|
||||
uint32 size = next_offset - offset;
|
||||
Chunk chunk;
|
||||
if (size != 0) {
|
||||
file.seek(offset);
|
||||
chunk.data = new byte[size];
|
||||
chunk.size = size;
|
||||
file.read(chunk.data, size);
|
||||
file.seek(pos);
|
||||
}
|
||||
chunks.push_back(chunk);
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 MemoryPack::getSize(uint32 id) const {
|
||||
--id;
|
||||
return id < chunks.size() ? chunks[id].size : 0;
|
||||
}
|
||||
|
||||
uint32 MemoryPack::read(uint32 id, byte *dst, uint32 size) const {
|
||||
--id;
|
||||
if (id >= chunks.size())
|
||||
return 0;
|
||||
const Chunk &c = chunks[id];
|
||||
memcpy(dst, c.data, c.size);
|
||||
return c.size;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *MemoryPack::getStream(uint32 id) const {
|
||||
--id;
|
||||
if (id >= chunks.size())
|
||||
return 0;
|
||||
const Chunk &c = chunks[id];
|
||||
return new Common::MemoryReadStream(c.data, c.size, DisposeAfterUse::NO);
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
115
engines/teenagent/pack.h
Normal file
115
engines/teenagent/pack.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TEENAGENT_PACK_H
|
||||
#define TEENAGENT_PACK_H
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/array.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
class Pack {
|
||||
protected:
|
||||
uint32 _fileCount;
|
||||
public:
|
||||
Pack(): _fileCount(0) {}
|
||||
virtual ~Pack() {}
|
||||
virtual bool open(const Common::Path &filename) = 0;
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual uint32 fileCount() const { return _fileCount; }
|
||||
virtual uint32 getSize(uint32 id) const = 0;
|
||||
virtual uint32 read(uint32 id, byte *dst, uint32 size) const = 0;
|
||||
virtual Common::SeekableReadStream *getStream(uint32 id) const = 0;
|
||||
};
|
||||
|
||||
///FilePack keeps opened file and returns substream for each request.
|
||||
class FilePack : public Pack {
|
||||
mutable Common::File file;
|
||||
uint32 *offsets;
|
||||
|
||||
public:
|
||||
FilePack();
|
||||
~FilePack() override;
|
||||
|
||||
bool open(const Common::Path &filename) override;
|
||||
void close() override;
|
||||
|
||||
uint32 getSize(uint32 id) const override;
|
||||
uint32 read(uint32 id, byte *dst, uint32 size) const override;
|
||||
Common::SeekableReadStream *getStream(uint32 id) const override;
|
||||
};
|
||||
|
||||
/** Pack file which reopens file each request. Do not keep file descriptor open.
|
||||
** Useful for minimizing file descriptors opened at the same time. Critical for PSP backend.
|
||||
**/
|
||||
class TransientFilePack : public Pack {
|
||||
uint32 *offsets;
|
||||
Common::Path _filename;
|
||||
|
||||
public:
|
||||
TransientFilePack();
|
||||
~TransientFilePack() override;
|
||||
|
||||
bool open(const Common::Path &filename) override;
|
||||
void close() override;
|
||||
|
||||
uint32 getSize(uint32 id) const override;
|
||||
uint32 read(uint32 id, byte *dst, uint32 size) const override;
|
||||
Common::SeekableReadStream *getStream(uint32 id) const override;
|
||||
};
|
||||
|
||||
///MemoryPack loads whole pack in memory, currently unused.
|
||||
class MemoryPack : public Pack {
|
||||
struct Chunk {
|
||||
byte *data;
|
||||
uint32 size;
|
||||
inline Chunk(): data(0), size(0) {}
|
||||
inline Chunk(const Chunk &c) : data(c.data), size(c.size) { c.reset(); }
|
||||
inline Chunk &operator=(const Chunk &c) {
|
||||
data = c.data;
|
||||
size = c.size;
|
||||
c.reset();
|
||||
return *this;
|
||||
}
|
||||
inline ~Chunk() { delete[] data; }
|
||||
inline void reset() const {
|
||||
Chunk *c = const_cast<Chunk *>(this);
|
||||
c->data = 0;
|
||||
c->size = 0;
|
||||
}
|
||||
};
|
||||
Common::Array<Chunk> chunks;
|
||||
|
||||
public:
|
||||
bool open(const Common::Path &filename) override;
|
||||
void close() override;
|
||||
|
||||
uint32 getSize(uint32 id) const override;
|
||||
uint32 read(uint32 id, byte *dst, uint32 size) const override;
|
||||
Common::SeekableReadStream *getStream(uint32 id) const override;
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
491
engines/teenagent/resources.cpp
Normal file
491
engines/teenagent/resources.cpp
Normal file
@@ -0,0 +1,491 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "teenagent/resources.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/translation.h"
|
||||
#include "common/compression/deflate.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
Resources::Resources() {
|
||||
_dialogsStartOffset = 0;
|
||||
_sceneObjectsStartOffset = 0;
|
||||
_sceneObjectsBlockSize = 0;
|
||||
}
|
||||
|
||||
Resources::~Resources() {
|
||||
off.close();
|
||||
on.close();
|
||||
ons.close();
|
||||
lan000.close();
|
||||
lan500.close();
|
||||
mmm.close();
|
||||
sam_mmm.close();
|
||||
sam_sam.close();
|
||||
voices.close();
|
||||
}
|
||||
|
||||
/*
|
||||
quick note on varia resources:
|
||||
1: Mark's animations (with head)
|
||||
2: Mark's idle animation
|
||||
3: Inventory background
|
||||
4: Inventory items
|
||||
5: Metropolis palette
|
||||
6: TEENAGENT logo (flames)
|
||||
7: Small font
|
||||
8: Bigger font
|
||||
9: Metropolis software house
|
||||
10: quit registered
|
||||
11: quit shareware
|
||||
*/
|
||||
|
||||
#define CSEG_SIZE 46000 // 0xb3b0
|
||||
#define DSEG_SIZE 59280 // 0xe790
|
||||
#define ESEG_SIZE 35810 // 0x8be2
|
||||
|
||||
void Resources::precomputeResourceOffsets(const ResourceInfo &resInfo, Common::Array<uint32> &offsets, uint numTerminators) {
|
||||
offsets.push_back(resInfo._offset);
|
||||
uint n = 0;
|
||||
uint8 current, last = 0xff;
|
||||
for (uint32 i = resInfo._offset; i < resInfo._offset + resInfo._size; i++) {
|
||||
current = eseg.get_byte(i);
|
||||
|
||||
if (n == numTerminators) {
|
||||
offsets.push_back(i);
|
||||
n = 0;
|
||||
}
|
||||
|
||||
if (current != 0x00 && last == 0x00)
|
||||
n = 0;
|
||||
|
||||
if (current == 0x00)
|
||||
n++;
|
||||
|
||||
last = current;
|
||||
}
|
||||
}
|
||||
|
||||
void Resources::precomputeDialogOffsets(const ResourceInfo &resInfo) {
|
||||
precomputeResourceOffsets(resInfo, dialogOffsets, 4);
|
||||
|
||||
debug(1, "Resources::precomputeDialogOffsets() - Found %d dialogs", dialogOffsets.size());
|
||||
for (uint i = 0; i < dialogOffsets.size(); i++)
|
||||
debug(1, "\tDialog #%d: Offset 0x%04x", i, dialogOffsets[i]);
|
||||
}
|
||||
|
||||
void Resources::precomputeCreditsOffsets(const ResourceInfo &resInfo) {
|
||||
precomputeResourceOffsets(resInfo, creditsOffsets);
|
||||
|
||||
debug(1, "Resources::precomputeCreditsOffsets() - Found %d credits", creditsOffsets.size());
|
||||
for (uint i = 0; i < creditsOffsets.size(); i++)
|
||||
debug(1, "\tCredit #%d: Offset 0x%04x", i, creditsOffsets[i]);
|
||||
}
|
||||
|
||||
void Resources::precomputeItemOffsets(const ResourceInfo &resInfo) {
|
||||
precomputeResourceOffsets(resInfo, itemOffsets);
|
||||
|
||||
debug(1, "Resources::precomputeItemOffsets() - Found %d items", itemOffsets.size());
|
||||
for (uint i = 0; i < itemOffsets.size(); i++)
|
||||
debug(1, "\tItem #%d: Offset 0x%04x", i, itemOffsets[i]);
|
||||
}
|
||||
|
||||
void Resources::precomputeMessageOffsets(const ResourceInfo &resInfo) {
|
||||
precomputeResourceOffsets(resInfo, messageOffsets);
|
||||
}
|
||||
|
||||
void Resources::precomputeCombinationOffsets(const ResourceInfo &resInfo) {
|
||||
precomputeResourceOffsets(resInfo, combinationOffsets);
|
||||
|
||||
debug(1, "Resources::precomputeCombinationOffsets() - Found %d combination items", combinationOffsets.size());
|
||||
for (uint i = 0; i < combinationOffsets.size(); i++)
|
||||
debug(1, "\tCombination #%d: Offset 0x%04x", i, combinationOffsets[i]);
|
||||
}
|
||||
|
||||
void Resources::readDialogStacks(byte *src) {
|
||||
uint16 base = dsAddr_dialogStackPleadingToMansionGuard;
|
||||
|
||||
byte dialogStackWritten = 0;
|
||||
uint i = 0;
|
||||
|
||||
while (dialogStackWritten < kNumDialogStacks) {
|
||||
uint16 word = READ_LE_UINT16(src + i * 2);
|
||||
dseg.set_word(base + i * 2, word);
|
||||
if (word == 0xFFFF)
|
||||
dialogStackWritten++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Resources::precomputeAllOffsets(const Common::Array<ResourceInfo> &resourceInfos) {
|
||||
for (const auto &resInfo : resourceInfos) {
|
||||
switch ((ResourceType)resInfo._id) {
|
||||
case kResCombinations:
|
||||
precomputeCombinationOffsets(resInfo);
|
||||
break;
|
||||
case kResCredits:
|
||||
precomputeCreditsOffsets(resInfo);
|
||||
break;
|
||||
case kResDialogs:
|
||||
_dialogsStartOffset = resInfo._offset;
|
||||
precomputeDialogOffsets(resInfo);
|
||||
break;
|
||||
case kResItems:
|
||||
precomputeItemOffsets(resInfo);
|
||||
break;
|
||||
case kResMessages:
|
||||
precomputeMessageOffsets(resInfo);
|
||||
break;
|
||||
case kResSceneObjects:
|
||||
_sceneObjectsStartOffset = resInfo._offset;
|
||||
_sceneObjectsBlockSize = resInfo._size;
|
||||
break;
|
||||
case kResDialogStacks:
|
||||
// fall through
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Resources::isVoiceIndexEmpty(uint16 index) {
|
||||
uint size = voices.getSize(index);
|
||||
if (size == 4 || size == 5)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Resources::precomputeVoiceIndices(const Common::Array<ResourceInfo>& resourceInfos) {
|
||||
byte numTerminators = 0;
|
||||
uint16 voiceIndex = 0;
|
||||
|
||||
for (auto &resInfo : resourceInfos) {
|
||||
switch ((ResourceType)resInfo._id) {
|
||||
case kResMessages:
|
||||
voiceIndex = 1;
|
||||
numTerminators = 2;
|
||||
break;
|
||||
case kResCombinations:
|
||||
voiceIndex = 567;
|
||||
numTerminators = 2;
|
||||
break;
|
||||
case kResItems:
|
||||
voiceIndex = 592;
|
||||
numTerminators = 2;
|
||||
break;
|
||||
case kResDialogs:
|
||||
voiceIndex = 902;
|
||||
numTerminators = 4;
|
||||
break;
|
||||
case kResCredits:
|
||||
case kResDialogStacks:
|
||||
case kResSceneObjects:
|
||||
// There are no voiceovers for credits and dialog stacks.
|
||||
// For scene objects, voice indices calculated separately
|
||||
// in Scene::loadObjectData()
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_addrToVoiceIndx[resInfo._offset] = voiceIndex++;
|
||||
|
||||
uint16 currentNum = 1;
|
||||
uint n = 0; // number of consecutive zero bytes
|
||||
byte current, last = 0xff;
|
||||
|
||||
bool setNoIMessage = false;
|
||||
|
||||
for (uint32 i = resInfo._offset; i < resInfo._offset + resInfo._size; i++) {
|
||||
current = eseg.get_byte(i);
|
||||
|
||||
if (n == numTerminators) {
|
||||
currentNum++;
|
||||
n = 0;
|
||||
|
||||
if ((ResourceType)resInfo._id == kResCombinations) {
|
||||
uint16 nthCombination = currentNum - 1;
|
||||
// For dublicate combination messages don't increment voice index
|
||||
if (nthCombination == 3 || nthCombination == 5 ||
|
||||
nthCombination == 15 || nthCombination == 16 || nthCombination == 17 ||
|
||||
nthCombination == 18 || nthCombination == 22 || nthCombination == 26) {
|
||||
_addrToVoiceIndx[i] = voiceIndex - 1;
|
||||
} else if (nthCombination == 28) {
|
||||
_addrToVoiceIndx[i] = voiceIndex - 2;
|
||||
} else {
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
}
|
||||
} else if ((ResourceType)resInfo._id == kResDialogs) {
|
||||
if (voiceIndex == 1416) {
|
||||
// "Dzie= dobry, panie robocie." starts at 1418
|
||||
voiceIndex += 2;
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
} else if (voiceIndex == 1864) {
|
||||
// "Jak ju< powiedzia%em, nasza organizacja" starts at 1867
|
||||
voiceIndex += 3;
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
} else if (isVoiceIndexEmpty(voiceIndex)) {
|
||||
voiceIndex += 1;
|
||||
if (current != 0x00)
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
} else if (voiceIndex == 1801) {
|
||||
_addrToVoiceIndx[i] = 2041; // "]adna pogoda."
|
||||
} else if (voiceIndex == 1809) {
|
||||
_addrToVoiceIndx[i] = 2042; // "Sir, mamy sygna%y, <e..."
|
||||
} else {
|
||||
if (current != 0x00)
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
}
|
||||
} else if ((ResourceType)resInfo._id == kResMessages) {
|
||||
if (currentNum == 334) { // Combination error message
|
||||
// HACK: Use most good sounding (sigh) version
|
||||
// TODO: Find the correct voice index used in the original
|
||||
_addrToVoiceIndx[i] = 1304;
|
||||
} else
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
} else {
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (current != 0x00 && last == 0x00) {
|
||||
if ((ResourceType)resInfo._id == kResDialogs) {
|
||||
if (n == 2 || n == 3) {
|
||||
// "...to czemu nie u<y^ dziwnych" at 1886
|
||||
// "Sze$^ miesi#cy temu z%oto i got*wka" at 1921
|
||||
if (voiceIndex == 1885 || voiceIndex == 1920 || isVoiceIndexEmpty(voiceIndex)) {
|
||||
voiceIndex += 1;
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
} else if (voiceIndex == 1923 && !setNoIMessage) {
|
||||
_addrToVoiceIndx[i] = 1885; // "No i?..."
|
||||
setNoIMessage = true;
|
||||
} else {
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
}
|
||||
} else if (n == 1 && (voiceIndex == 1720 || voiceIndex == 1852)) {
|
||||
// Because of the rare case with
|
||||
// NEW_LINE at the beginning of dialogs 163, 190
|
||||
// we have to assign voiceIndex here
|
||||
_addrToVoiceIndx[i] = voiceIndex++;
|
||||
}
|
||||
}
|
||||
n = 0;
|
||||
}
|
||||
|
||||
if (current == 0x00)
|
||||
n++;
|
||||
|
||||
last = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Resources::loadArchives(const ADGameDescription *gd) {
|
||||
Common::File *dat_file = new Common::File();
|
||||
Common::String filename = "teenagent.dat";
|
||||
if (!dat_file->open(filename.c_str())) {
|
||||
delete dat_file;
|
||||
|
||||
const char *msg = _s("Unable to locate the '%s' engine data file.");
|
||||
Common::U32String errorMessage = Common::U32String::format(_(msg), filename.c_str());
|
||||
warning(msg, filename.c_str());
|
||||
GUIErrorMessage(errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
// teenagent.dat used to be compressed with zlib compression. The usage of
|
||||
// zlib here is no longer needed, and it's maintained only for backwards
|
||||
// compatibility.
|
||||
Common::SeekableReadStream *dat = Common::wrapCompressedReadStream(dat_file);
|
||||
|
||||
byte tempBuffer[256];
|
||||
dat->read(tempBuffer, 9);
|
||||
tempBuffer[9] = '\0';
|
||||
|
||||
if (strcmp((char *)tempBuffer, "TEENAGENT") != 0) {
|
||||
const char *msg = _s("The '%s' engine data file is corrupt.");
|
||||
Common::U32String errorMessage = Common::U32String::format(_(msg), filename.c_str());
|
||||
GUIErrorMessage(errorMessage);
|
||||
warning(msg, filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
byte version = dat->readByte();
|
||||
if (version != TEENAGENT_DAT_VERSION) {
|
||||
const char *msg = _s("Incorrect version of the '%s' engine data file found. Expected %d but got %d.");
|
||||
Common::U32String errorMessage = Common::U32String::format(_(msg), filename.c_str(), TEENAGENT_DAT_VERSION, version);
|
||||
GUIErrorMessage(errorMessage);
|
||||
warning(msg, filename.c_str(), TEENAGENT_DAT_VERSION, version);
|
||||
return false;
|
||||
}
|
||||
|
||||
dat->skip(CSEG_SIZE);
|
||||
dseg.read(dat, DSEG_SIZE);
|
||||
|
||||
// Locate the correct language block
|
||||
bool found = false;
|
||||
|
||||
while (!found) {
|
||||
dat->read(tempBuffer, 5);
|
||||
if (tempBuffer[0] == 0xff) {
|
||||
error("Could not locate correct language block");
|
||||
}
|
||||
|
||||
if (gd->language == tempBuffer[0]) {
|
||||
found = true;
|
||||
uint32 dataOffset = READ_LE_UINT32(&tempBuffer[1]);
|
||||
dat->seek(dataOffset);
|
||||
}
|
||||
}
|
||||
|
||||
Common::Array<ResourceInfo> resourceInfos(kNumResources);
|
||||
uint32 allResourcesSize = 0;
|
||||
|
||||
for (auto &resInfo : resourceInfos) {
|
||||
resInfo._id = dat->readByte();
|
||||
resInfo._offset = dat->readUint32LE();
|
||||
resInfo._size = dat->readUint32LE();
|
||||
|
||||
// Don't count Dialog stack's size
|
||||
// since it will be stored in dseg, not eseg
|
||||
if ((ResourceType)resInfo._id != kResDialogStacks)
|
||||
allResourcesSize += resInfo._size;
|
||||
}
|
||||
|
||||
// Dialog stack data
|
||||
dat->read(tempBuffer, resourceInfos[(uint)kResDialogStacks]._size);
|
||||
readDialogStacks((byte *)tempBuffer);
|
||||
|
||||
// Store rest of the resources to eseg
|
||||
eseg.read(dat, allResourcesSize);
|
||||
|
||||
delete dat;
|
||||
|
||||
precomputeAllOffsets(resourceInfos);
|
||||
|
||||
FilePack varia;
|
||||
varia.open("varia.res");
|
||||
font7.load(varia, 7, 11, 1);
|
||||
font8.load(varia, 8, 31, 0);
|
||||
varia.close();
|
||||
|
||||
off.open("off.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");
|
||||
voices.open("voices.res");
|
||||
|
||||
if (gd->language == Common::PL_POL)
|
||||
precomputeVoiceIndices(resourceInfos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Resources::loadOff(Graphics::Surface &surface, byte *palette, int id) {
|
||||
uint32 size = off.getSize(id);
|
||||
if (size == 0) {
|
||||
error("invalid background %d", id);
|
||||
return;
|
||||
}
|
||||
|
||||
const uint bufferSize = 64768;
|
||||
byte *buf = (byte *)malloc(bufferSize);
|
||||
if (!buf)
|
||||
error("[Resources::loadOff] Cannot allocate buffer");
|
||||
|
||||
off.read(id, buf, bufferSize);
|
||||
|
||||
byte *src = buf;
|
||||
byte *dst = (byte *)surface.getPixels();
|
||||
memcpy(dst, src, 64000);
|
||||
memcpy(palette, buf + 64000, 768);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
||||
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(dsAddr_dogHasBoneFlag))
|
||||
return lan500.getStream(160);
|
||||
break;
|
||||
|
||||
case 137:
|
||||
if (dseg.get_byte(dsAddr_mansionTVOnFlag) == 1) {
|
||||
if (dseg.get_byte(dsAddr_mansionVCRPlayingTapeFlag) == 1)
|
||||
return lan500.getStream(203);
|
||||
else
|
||||
return lan500.getStream(202);
|
||||
}
|
||||
break;
|
||||
|
||||
case 25:
|
||||
if (dseg.get_byte(dsAddr_FirstActTrialState) == 2) {
|
||||
return lan500.getStream(332);
|
||||
}
|
||||
break;
|
||||
|
||||
case 37:
|
||||
if (dseg.get_byte(dsAddr_act1GuardState) == 1) {
|
||||
return lan500.getStream(351);
|
||||
} else if (dseg.get_byte(dsAddr_act1GuardState) == 2) {
|
||||
return lan500.getStream(364);
|
||||
}
|
||||
break;
|
||||
|
||||
case 29:
|
||||
if (dseg.get_byte(dsAddr_birdOnBarRadioAntennaFlag) == 1) {
|
||||
return lan500.getStream(380);
|
||||
}
|
||||
break;
|
||||
|
||||
case 30:
|
||||
if (dseg.get_byte(dsAddr_birdOnBarRadioAntennaFlag) == 1) {
|
||||
return lan500.getStream(381);
|
||||
}
|
||||
break;
|
||||
|
||||
case 42:
|
||||
if (dseg.get_byte(dsAddr_johnNotyOutsideMansionDoorFlag) == 1) {
|
||||
return lan500.getStream(400);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return lan000.getStream(id);
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
1600
engines/teenagent/resources.h
Normal file
1600
engines/teenagent/resources.h
Normal file
File diff suppressed because it is too large
Load Diff
1310
engines/teenagent/scene.cpp
Normal file
1310
engines/teenagent/scene.cpp
Normal file
File diff suppressed because it is too large
Load Diff
267
engines/teenagent/scene.h
Normal file
267
engines/teenagent/scene.h
Normal file
@@ -0,0 +1,267 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_SCENE_H
|
||||
#define TEENAGENT_SCENE_H
|
||||
|
||||
#include "teenagent/surface.h"
|
||||
#include "teenagent/actor.h"
|
||||
#include "teenagent/objects.h"
|
||||
#include "teenagent/surface.h"
|
||||
#include "teenagent/surface_list.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/list.h"
|
||||
|
||||
namespace Common {
|
||||
struct Event;
|
||||
}
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
class TeenAgentEngine;
|
||||
|
||||
struct SceneEvent {
|
||||
enum Type {
|
||||
kNone, //0
|
||||
kMessage,
|
||||
kWalk,
|
||||
kPlayAnimation,
|
||||
kPlayActorAnimation, //4
|
||||
kPauseAnimation,
|
||||
kClearAnimations,
|
||||
kLoadScene,
|
||||
kSetOn, //8
|
||||
kSetLan,
|
||||
kPlayMusic,
|
||||
kPlaySound,
|
||||
kEnableObject, //12
|
||||
kHideActor,
|
||||
kWaitForAnimation,
|
||||
kWaitLanAnimationFrame,
|
||||
kCreditsMessage, //16
|
||||
kCredits,
|
||||
kTimer,
|
||||
kEffect,
|
||||
kFade,
|
||||
kWait,
|
||||
kSetFlag,
|
||||
kQuit
|
||||
} type;
|
||||
|
||||
Common::String message;
|
||||
uint16 voiceId;
|
||||
byte color;
|
||||
byte slot;
|
||||
union {
|
||||
uint16 animation;
|
||||
uint16 callback;
|
||||
};
|
||||
uint16 timer;
|
||||
byte orientation;
|
||||
Common::Point dst;
|
||||
byte scene; //fixme: put some of these to the union?
|
||||
byte ons;
|
||||
byte lan;
|
||||
union {
|
||||
byte music;
|
||||
byte firstFrame;
|
||||
};
|
||||
union {
|
||||
byte sound;
|
||||
byte lastFrame;
|
||||
};
|
||||
byte object;
|
||||
int characterID;
|
||||
|
||||
SceneEvent(Type type_) :
|
||||
type(type_), message(), color(textColorMark), slot(0), animation(0), timer(0), orientation(0), dst(),
|
||||
scene(0), ons(0), lan(0), music(0), sound(0), object(0) {}
|
||||
|
||||
void clear() {
|
||||
type = kNone;
|
||||
message.clear();
|
||||
voiceId = 0;
|
||||
color = textColorMark;
|
||||
slot = 0;
|
||||
orientation = 0;
|
||||
animation = 0;
|
||||
timer = 0;
|
||||
dst.x = dst.y = 0;
|
||||
scene = 0;
|
||||
ons = 0;
|
||||
lan = 0;
|
||||
music = 0;
|
||||
sound = 0;
|
||||
object = 0;
|
||||
}
|
||||
|
||||
inline bool empty() const {
|
||||
return type == kNone;
|
||||
}
|
||||
|
||||
void dump() const {
|
||||
debugC(0, kDebugScene, "event[%d]: \"%s\"[%02x], slot: %d, animation: %u, timer: %u, dst: (%d, %d) [%u], scene: %u, ons: %u, lan: %u, object: %u, music: %u, sound: %u",
|
||||
(int)type, message.c_str(), color, slot, animation, timer, dst.x, dst.y, orientation, scene, ons, lan, object, music, sound
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
class Scene {
|
||||
public:
|
||||
Scene(TeenAgentEngine *engine);
|
||||
~Scene();
|
||||
|
||||
bool intro;
|
||||
|
||||
void init(int id, const Common::Point &pos);
|
||||
bool render(bool tickGame, bool tickMark, uint32 messageDelta);
|
||||
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 = false);
|
||||
Common::Point getPosition() const { return position; }
|
||||
|
||||
void displayMessage(const Common::String &str, uint16 voiceIndex, byte color = textColorMark, const Common::Point &pos = Common::Point());
|
||||
void setOrientation(uint8 o) { orientation = o; }
|
||||
void push(const SceneEvent &event);
|
||||
byte peekFlagEvent(uint16 addr) const;
|
||||
SceneEvent::Type last_event_type() const { return !events.empty() ? events.back().type : SceneEvent::kNone; }
|
||||
|
||||
bool processEvent(const Common::Event &event);
|
||||
|
||||
void clear();
|
||||
|
||||
byte *getOns(int id);
|
||||
byte *getLans(int id);
|
||||
|
||||
bool eventRunning() const { return !currentEvent.empty(); }
|
||||
|
||||
Walkbox *getWalkbox(byte id) { return &walkboxes[_id - 1][id]; }
|
||||
Object *getObject(int id, int sceneId = 0);
|
||||
Object *findObject(const Common::Point &point);
|
||||
|
||||
void loadObjectData();
|
||||
Animation *getAnimation(byte slot);
|
||||
inline Animation *getActorAnimation() { return &actorAnimation; }
|
||||
inline const Common::String &getMessage() const { return message; }
|
||||
void setPalette(unsigned mul);
|
||||
int lookupZoom(uint y) const;
|
||||
|
||||
private:
|
||||
void loadOns();
|
||||
void loadLans();
|
||||
|
||||
void playAnimation(byte idx, uint id, bool loop, bool paused, bool ignore);
|
||||
void playActorAnimation(uint id, bool loop, bool ignore);
|
||||
|
||||
byte palette[3 * 256];
|
||||
void paletteEffect(byte step);
|
||||
byte findFade() const;
|
||||
|
||||
Common::Point messagePosition(const Common::String &str, Common::Point pos);
|
||||
uint messageDuration(const Common::String &str);
|
||||
|
||||
bool processEventQueue();
|
||||
inline bool nextEvent() {
|
||||
currentEvent.clear();
|
||||
return processEventQueue();
|
||||
}
|
||||
void clearMessage();
|
||||
|
||||
TeenAgentEngine *_vm;
|
||||
|
||||
int _id;
|
||||
Graphics::Surface background;
|
||||
SurfaceList on;
|
||||
bool onEnabled;
|
||||
Surface *ons;
|
||||
uint32 _onsCount;
|
||||
Animation actorAnimation, animation[4], customAnimation[4];
|
||||
Common::Rect actorAnimationPosition, animationPosition[4];
|
||||
|
||||
Actor teenagent, teenagentIdle;
|
||||
Common::Point position;
|
||||
|
||||
typedef Common::List<Common::Point> Path;
|
||||
Path path;
|
||||
uint8 orientation;
|
||||
bool actorTalking;
|
||||
|
||||
bool findPath(Path &p, const Common::Point &src, const Common::Point &dst) const;
|
||||
|
||||
Common::Array<Common::Array<Object> > objects;
|
||||
Common::Array<Common::Array<Walkbox> > walkboxes;
|
||||
Common::Array<Common::Array<FadeType> > fades;
|
||||
|
||||
Common::String message;
|
||||
Common::Point messagePos;
|
||||
byte _messageColor;
|
||||
uint messageTimer;
|
||||
byte messageFirstFrame;
|
||||
byte messageLastFrame;
|
||||
Animation *messageAnimation;
|
||||
|
||||
uint16 _voiceId;
|
||||
|
||||
typedef Common::List<SceneEvent> EventList;
|
||||
EventList events;
|
||||
SceneEvent currentEvent;
|
||||
bool hideActor;
|
||||
|
||||
uint16 callback, callbackTimer;
|
||||
|
||||
int _fadeTimer;
|
||||
byte _fadeOld;
|
||||
|
||||
uint _idleTimer;
|
||||
|
||||
struct Sound {
|
||||
byte id, delay;
|
||||
Sound(byte i, byte d): id(i), delay(d) {}
|
||||
};
|
||||
typedef Common::List<Sound> Sounds;
|
||||
Sounds sounds;
|
||||
|
||||
struct DebugFeatures {
|
||||
enum {
|
||||
kShowBack,
|
||||
kShowLan,
|
||||
kShowOns,
|
||||
kShowOn,
|
||||
kHidePath,
|
||||
kMax
|
||||
};
|
||||
bool feature[kMax];
|
||||
|
||||
DebugFeatures() {
|
||||
for (uint i = 0; i < kMax; ++i) {
|
||||
feature[i] = true;
|
||||
}
|
||||
}
|
||||
} debugFeatures;
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
39
engines/teenagent/segment.cpp
Normal file
39
engines/teenagent/segment.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/segment.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
void Segment::read(Common::ReadStream *stream, uint32 s) {
|
||||
_size = s;
|
||||
_data = new byte[_size];
|
||||
if (stream->read(_data, _size) != _size)
|
||||
error("Segment::read: corrupted data");
|
||||
}
|
||||
|
||||
Segment::~Segment() {
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
75
engines/teenagent/segment.h
Normal file
75
engines/teenagent/segment.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_SEGMENT_H
|
||||
#define TEENAGENT_SEGMENT_H
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/endian.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
124
engines/teenagent/surface.cpp
Normal file
124
engines/teenagent/surface.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/surface.h"
|
||||
#include "teenagent/pack.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
Surface::Surface() : x(0), y(0) {
|
||||
}
|
||||
|
||||
Surface::~Surface() {
|
||||
free();
|
||||
}
|
||||
|
||||
void Surface::load(Common::SeekableReadStream &stream, Type type) {
|
||||
debugC(0, kDebugSurface, "load()");
|
||||
free();
|
||||
|
||||
x = y = 0;
|
||||
|
||||
uint16 w_ = stream.readUint16LE();
|
||||
uint16 h_ = stream.readUint16LE();
|
||||
|
||||
if (type != kTypeLan) {
|
||||
uint16 pos = stream.readUint16LE();
|
||||
x = pos % kScreenWidth;
|
||||
y = pos / kScreenWidth;
|
||||
}
|
||||
|
||||
debugC(0, kDebugSurface, "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()) {
|
||||
debugC(0, kDebugSurface, "invalid surface %ux%u -> %u,%u", w_, h_, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
debugC(0, kDebugSurface, "creating surface %ux%u -> %u,%u", w_, h_, x, y);
|
||||
create(w_, h_, Graphics::PixelFormat::createFormatCLUT8());
|
||||
|
||||
stream.read(pixels, w_ * h_);
|
||||
}
|
||||
|
||||
Common::Rect Surface::render(Graphics::Surface *surface, int dx, int dy, bool mirror, Common::Rect srcRect, uint zoom) const {
|
||||
if (srcRect.isEmpty()) {
|
||||
srcRect = Common::Rect(0, 0, w, h);
|
||||
}
|
||||
Common::Rect dstRect(x + dx, y + dy, x + dx + zoom * srcRect.width() / 256, y + dy + zoom * srcRect.height() / 256);
|
||||
if (dstRect.left < 0) {
|
||||
srcRect.left = -dstRect.left;
|
||||
dstRect.left = 0;
|
||||
}
|
||||
if (dstRect.right > surface->w) {
|
||||
srcRect.right -= dstRect.right - surface->w;
|
||||
dstRect.right = surface->w;
|
||||
}
|
||||
if (dstRect.top < 0) {
|
||||
srcRect.top -= dstRect.top;
|
||||
dstRect.top = 0;
|
||||
}
|
||||
if (dstRect.bottom > surface->h) {
|
||||
srcRect.bottom -= dstRect.bottom - surface->h;
|
||||
dstRect.bottom = surface->h;
|
||||
}
|
||||
if (srcRect.isEmpty() || dstRect.isEmpty())
|
||||
return Common::Rect();
|
||||
|
||||
if (zoom == 256) {
|
||||
const byte *src = (const byte *)getBasePtr(0, srcRect.top);
|
||||
byte *dstBase = (byte *)surface->getBasePtr(dstRect.left, dstRect.top);
|
||||
|
||||
for (int i = srcRect.top; i < srcRect.bottom; ++i) {
|
||||
byte *dst = dstBase;
|
||||
for (int j = srcRect.left; j < srcRect.right; ++j) {
|
||||
byte p = src[(mirror ? w - j - 1 : j)];
|
||||
if (p != 0xff)
|
||||
*dst++ = p;
|
||||
else
|
||||
++dst;
|
||||
}
|
||||
dstBase += surface->pitch;
|
||||
src += pitch;
|
||||
}
|
||||
} else {
|
||||
byte *dst = (byte *)surface->getBasePtr(dstRect.left, dstRect.top);
|
||||
for (int i = 0; i < dstRect.height(); ++i) {
|
||||
for (int j = 0; j < dstRect.width(); ++j) {
|
||||
int px = j * 256 / zoom;
|
||||
const byte *src = (const byte *)getBasePtr(srcRect.left + (mirror ? w - px - 1 : px), srcRect.top + i * 256 / zoom);
|
||||
byte p = *src;
|
||||
if (p != 0xff)
|
||||
dst[j] = p;
|
||||
}
|
||||
dst += surface->pitch;
|
||||
}
|
||||
}
|
||||
return dstRect;
|
||||
}
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
51
engines/teenagent/surface.h
Normal file
51
engines/teenagent/surface.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_SURFACE_H
|
||||
#define TEENAGENT_SURFACE_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
class Surface : public Graphics::Surface {
|
||||
public:
|
||||
Surface();
|
||||
~Surface();
|
||||
|
||||
enum Type {kTypeOns, kTypeLan};
|
||||
|
||||
void load(Common::SeekableReadStream &, Type type);
|
||||
Common::Rect render(Graphics::Surface *surface, int dx = 0, int dy = 0, bool mirror = false, Common::Rect srcRect = Common::Rect(), uint zoom = 256) const;
|
||||
|
||||
bool empty() const { return pixels == NULL; }
|
||||
|
||||
uint16 x, y;
|
||||
};
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
78
engines/teenagent/surface_list.cpp
Normal file
78
engines/teenagent/surface_list.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "teenagent/surface_list.h"
|
||||
#include "teenagent/surface.h"
|
||||
#include "teenagent/objects.h"
|
||||
#include "teenagent/teenagent.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
|
||||
SurfaceList::SurfaceList() : surfaces(NULL), surfacesCount(0) {}
|
||||
|
||||
SurfaceList::~SurfaceList() {
|
||||
free();
|
||||
}
|
||||
|
||||
void SurfaceList::load(Common::SeekableReadStream &stream, int subHack) {
|
||||
free();
|
||||
|
||||
byte fn = stream.readByte();
|
||||
if (stream.eos())
|
||||
return;
|
||||
|
||||
surfacesCount = fn - subHack;
|
||||
debugC(0, kDebugSurface, "loading %u surfaces from list (skip %d)", surfacesCount, subHack);
|
||||
|
||||
if (surfacesCount == 0)
|
||||
return;
|
||||
|
||||
surfaces = new Surface[surfacesCount];
|
||||
|
||||
for (byte i = 0; i < surfacesCount; ++i) {
|
||||
uint offset = stream.readUint16LE();
|
||||
uint pos = stream.pos();
|
||||
stream.seek(offset);
|
||||
surfaces[i].load(stream, Surface::kTypeOns);
|
||||
stream.seek(pos);
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceList::free() {
|
||||
delete[] surfaces;
|
||||
surfaces = NULL;
|
||||
surfacesCount = 0;
|
||||
}
|
||||
|
||||
void SurfaceList::render(Graphics::Surface *surface, const Common::Rect &clip) const {
|
||||
for (uint i = 0; i < surfacesCount; ++i) {
|
||||
const Surface &s = surfaces[i];
|
||||
Common::Rect r(s.x, s.y, s.x + s.w, s.y + s.h);
|
||||
if (r.bottom < clip.bottom || !clip.intersects(r))
|
||||
continue;
|
||||
|
||||
r.clip(clip);
|
||||
r.translate(-s.x, -s.y);
|
||||
s.render(surface, r.left, r.top, false, r);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
engines/teenagent/surface_list.h
Normal file
47
engines/teenagent/surface_list.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_SURFACE_LIST_H__
|
||||
#define TEENAGENT_SURFACE_LIST_H__
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace TeenAgent {
|
||||
class Surface;
|
||||
|
||||
class SurfaceList {
|
||||
public:
|
||||
SurfaceList();
|
||||
~SurfaceList();
|
||||
|
||||
void load(Common::SeekableReadStream &, int subHack = 0);
|
||||
void free();
|
||||
void render(Graphics::Surface *surface, const Common::Rect &clip) const;
|
||||
|
||||
protected:
|
||||
Surface *surfaces;
|
||||
uint surfacesCount;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
1332
engines/teenagent/teenagent.cpp
Normal file
1332
engines/teenagent/teenagent.cpp
Normal file
File diff suppressed because it is too large
Load Diff
238
engines/teenagent/teenagent.h
Normal file
238
engines/teenagent/teenagent.h
Normal file
@@ -0,0 +1,238 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEENAGENT_TEENAGENT_H
|
||||
#define TEENAGENT_TEENAGENT_H
|
||||
|
||||
#include "engines/engine.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "common/random.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
#include "teenagent/console.h"
|
||||
#include "teenagent/dialog.h"
|
||||
|
||||
struct ADGameDescription;
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
struct Point;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the namespace of the TeenAgent engine.
|
||||
*
|
||||
* Status of this engine: Complete
|
||||
*
|
||||
* Games using this engine:
|
||||
* - Teen Agent
|
||||
*/
|
||||
namespace TeenAgent {
|
||||
|
||||
struct Object;
|
||||
struct UseHotspot;
|
||||
class Scene;
|
||||
class MusicPlayer;
|
||||
class Resources;
|
||||
class Inventory;
|
||||
class Pack;
|
||||
|
||||
#define TEENAGENT_DAT_VERSION 6
|
||||
#define TEENAGENT_SAVEGAME_VERSION 1
|
||||
|
||||
// Engine Debug Flags
|
||||
enum {
|
||||
kDebugActor = 1,
|
||||
kDebugAnimation,
|
||||
kDebugCallbacks,
|
||||
kDebugDialog,
|
||||
kDebugFont,
|
||||
kDebugInventory,
|
||||
kDebugMusic,
|
||||
kDebugObject,
|
||||
kDebugPack,
|
||||
kDebugScene,
|
||||
kDebugSurface,
|
||||
};
|
||||
|
||||
enum TEENAGENTActions {
|
||||
kActionSkipIntro,
|
||||
kActionSkipDialog,
|
||||
kActionCloseInventory,
|
||||
kActionToggleInventory,
|
||||
kActionFastMode,
|
||||
};
|
||||
|
||||
const uint16 kScreenWidth = 320;
|
||||
const uint16 kScreenHeight = 200;
|
||||
|
||||
class TeenAgentEngine : public Engine {
|
||||
public:
|
||||
TeenAgentEngine(OSystem *system, const ADGameDescription *gd);
|
||||
~TeenAgentEngine();
|
||||
|
||||
Common::Error run() override;
|
||||
Common::String getSaveStateName(int slot) const override;
|
||||
Common::Error loadGameState(int slot) override;
|
||||
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override { return true; }
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override { return !_sceneBusy; }
|
||||
bool hasFeature(EngineFeature f) const override;
|
||||
|
||||
void init();
|
||||
|
||||
enum Action { kActionNone, kActionExamine, kActionUse };
|
||||
|
||||
void examine(const Common::Point &point, Object *object);
|
||||
void use(Object *object);
|
||||
inline void cancel() { _action = kActionNone; }
|
||||
|
||||
bool processCallback(uint16 addr);
|
||||
inline Scene *getScene() { return scene; }
|
||||
|
||||
bool showLogo();
|
||||
bool showCDLogo();
|
||||
bool showMetropolis();
|
||||
int skipEvents() const;
|
||||
|
||||
Common::String parseMessage(uint32 addr);
|
||||
|
||||
//event driven:
|
||||
void displayMessage(uint32 addr, CharacterID characterID = kMark, uint16 x = 0, uint16 y = 0);
|
||||
void displayMessage(const Common::String &str, uint16 voiceIndex, CharacterID characterID = kMark, uint16 x = 0, uint16 y = 0);
|
||||
void displayAsyncMessage(uint32 addr, uint16 x, uint16 y, uint16 firstFrame, uint16 lastFrame, CharacterID characterID = kMark);
|
||||
void displayAsyncMessageInSlot(uint32 addr, byte slot, uint16 firstFrame, uint16 lastFrame, byte color = textColorMark);
|
||||
void displayCredits(uint32 addr, uint16 timer = 0);
|
||||
void displayCutsceneMessage(uint32 addr, uint16 x, uint16 y);
|
||||
void moveTo(const Common::Point &dst, byte o, bool warp = false);
|
||||
void moveTo(uint16 x, uint16 y, byte o, bool warp = false);
|
||||
void moveTo(Object *obj);
|
||||
void moveRel(int16 x, int16 y, byte o, bool warp = false);
|
||||
void playActorAnimation(uint16 id, bool async = false, bool ignore = false);
|
||||
void playAnimation(uint16 id, byte slot, bool async = false, bool ignore = false, bool loop = false);
|
||||
void loadScene(byte id, const Common::Point &pos, byte o = 0);
|
||||
void loadScene(byte id, uint16 x, uint16 y, byte o = 0);
|
||||
void enableOn(bool enable = true);
|
||||
void setOns(byte id, byte value, byte sceneId = 0);
|
||||
void setLan(byte id, byte value, byte sceneId = 0);
|
||||
void setFlag(uint16 addr, byte value);
|
||||
byte getFlag(uint16 addr);
|
||||
void reloadLan();
|
||||
void rejectMessage();
|
||||
void bookColorMessage();
|
||||
|
||||
void playMusic(byte id); //schedules play
|
||||
void playSound(byte id, byte skipFrames);
|
||||
void playSoundNow(Pack *pack, uint32 id);
|
||||
void playVoiceNow(Pack *pack, uint32 id);
|
||||
void stopVoice();
|
||||
void enableObject(byte id, byte sceneId = 0);
|
||||
void disableObject(byte id, byte sceneId = 0);
|
||||
void hideActor();
|
||||
void showActor();
|
||||
void waitAnimation();
|
||||
void waitLanAnimationFrame(byte slot, uint16 frame);
|
||||
void setTimerCallback(uint16 addr, uint16 frames);
|
||||
void shakeScreen();
|
||||
void displayCredits();
|
||||
void fadeIn();
|
||||
void fadeOut();
|
||||
void wait(uint16 frames);
|
||||
|
||||
Common::RandomSource _rnd;
|
||||
|
||||
Resources *res;
|
||||
Scene *scene;
|
||||
Inventory *inventory;
|
||||
MusicPlayer *music;
|
||||
Dialog *dialog;
|
||||
|
||||
void setMusic(byte id);
|
||||
|
||||
void sayText(const Common::String &text, bool isSubtitle = false);
|
||||
void stopTextToSpeech();
|
||||
void setTTSVoice(CharacterID characterID) const;
|
||||
#ifdef USE_TTS
|
||||
Common::U32String convertText(const Common::String &text) const;
|
||||
#endif
|
||||
|
||||
Common::String _previousSaid;
|
||||
uint16 _previousVoiceId;
|
||||
|
||||
private:
|
||||
void processObject();
|
||||
bool trySelectedObject();
|
||||
|
||||
bool _sceneBusy;
|
||||
Action _action;
|
||||
Object *_dstObject;
|
||||
|
||||
Audio::AudioStream *_musicStream;
|
||||
Audio::SoundHandle _musicHandle, _soundHandle, _voiceHandle;
|
||||
const ADGameDescription *_gameDescription;
|
||||
|
||||
uint _markDelay, _gameDelay;
|
||||
|
||||
Common::Array<Common::Array<UseHotspot> > _useHotspots;
|
||||
|
||||
void fnIntro();
|
||||
void fnPoleClimbFail();
|
||||
void fnGotAnchor();
|
||||
void fnGetOutOfLake();
|
||||
void fnGuardDrinking();
|
||||
void fnEgoDefaultPosition();
|
||||
void fnEnterCave();
|
||||
void fnEgoScaredBySpider();
|
||||
void fnMoveToLadderAndLeaveCellar();
|
||||
void fnLeaveCellar();
|
||||
void fnPutRockInHole();
|
||||
void fnEgoBottomRightTurn();
|
||||
bool fnCheckingDrawers();
|
||||
void fnDrawerOpenMessage();
|
||||
bool fnRobotSafeAlreadyUnlockedCheck();
|
||||
void fnRobotSafeUnlockCheck();
|
||||
bool fnMansionIntrusionAttempt();
|
||||
void fnSecondMansionIntrusion();
|
||||
void fnThirdMansionIntrusion();
|
||||
void fnFourthMansionIntrusion();
|
||||
void fnFifthMansionIntrusion();
|
||||
void fnSixthMansionIntrusion();
|
||||
void fnTooDark();
|
||||
bool fnIsCookGone();
|
||||
void fnEgoSuspiciousPosition();
|
||||
void fnGivingFlowerToOldLady();
|
||||
void fnGiveAnotherFlowerToOldLady();
|
||||
void fnGivingFlowerToAnne();
|
||||
void fnGiveAnotherFlowerToAnne();
|
||||
};
|
||||
|
||||
extern TeenAgentEngine *g_engine;
|
||||
|
||||
} // End of namespace TeenAgent
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user