Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

2
engines/dragons/POTFILES Normal file
View File

@@ -0,0 +1,2 @@
engines/dragons/dragons.cpp
engines/dragons/metaengine.cpp

820
engines/dragons/actor.cpp Normal file
View File

@@ -0,0 +1,820 @@
/* 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 "dragons/actor.h"
#include "dragons/actorresource.h"
#include "dragons/dragons.h"
#include "dragons/dragonini.h"
#include "dragons/scene.h"
#include "dragons/screen.h"
namespace Dragons {
static const int kPathPointsCount = 32;
ActorManager::ActorManager(ActorResourceLoader *actorResourceLoader) : _actorResourceLoader(actorResourceLoader) {
for (uint16 i = 0; i < DRAGONS_ENGINE_NUM_ACTORS; i++) {
_actors.push_back(Actor(i));
}
resetDisplayOrder();
}
Actor *ActorManager::loadActor(uint32 resourceId, uint32 sequenceId, int16 x, int16 y, uint16 priorityLayer) {
Actor *actor = loadActor(resourceId, sequenceId, x, y);
if (actor) {
actor->_priorityLayer = priorityLayer;
}
return actor;
}
Actor *ActorManager::loadActor(uint32 resourceId, uint32 sequenceId, int16 x, int16 y) {
debug(1, "Load actor: resourceId: %d, SequenceId: %d, position: (%d,%d)", resourceId, sequenceId, x, y);
ActorResource *resource = _actorResourceLoader->load(resourceId);
//Actor *actor = new Actor(_actorResourceLoader->load(resourceId), x, y, sequenceId);
Actor *actor = findFreeActor((int16)resourceId);
if (actor) {
actor->init(resource, x, y, sequenceId);
} else {
//TODO run find by resource and remove from mem logic here. @0x800358c8
debug("Unable to find free actor slot!!");
delete resource;
}
resetDisplayOrder();
return actor;
}
Actor *ActorManager::findFreeActor(int16 resourceId) {
int i = 0;
for (auto &actor : _actors) {
if (i++ >= 23)
break;
if (!(actor._flags & ACTOR_FLAG_40)) {
actor._resourceID = resourceId;
actor._walkSpeed = 0x100000;
return &actor;
}
}
return nullptr;
}
Actor *ActorManager::getActor(uint16 actorId) {
assert(actorId < DRAGONS_ENGINE_NUM_ACTORS);
return &_actors[actorId];
}
void ActorManager::clearActorFlags(uint16 startingActorId) {
assert(startingActorId < DRAGONS_ENGINE_NUM_ACTORS);
for (uint16 i = startingActorId; i < DRAGONS_ENGINE_NUM_ACTORS; i++) {
_actors[i]._flags = 0;
}
}
Actor *ActorManager::loadActor(uint32 resourceId, uint16 actorId) { //TODO should we rename this. loadActorResource or updateActorResource
Actor *actor = getActor(actorId);
actor->_actorResource = _actorResourceLoader->load(resourceId);
return actor;
}
ActorResource *ActorManager::getActorResource(uint32 resourceId) {
return _actorResourceLoader->load(resourceId);
}
void ActorManager::updateActorDisplayOrder() {
bool shouldContinue = true;
while (shouldContinue) {
shouldContinue = false;
for (int i = 0; i < DRAGONS_ENGINE_NUM_ACTORS - 1; i++) {
Actor *curActor = getActor(_displayOrder[i]);
Actor *nextActor = getActor(_displayOrder[i + 1]);
int16 curY = curActor->_y_pos > 0 ? curActor->_y_pos : 0;
int16 nextY = nextActor->_y_pos > 0 ? nextActor->_y_pos : 0;
if (nextActor->_priorityLayer * 0x1000000 + nextY * 0x100 + nextActor->_actorID <
curActor->_priorityLayer * 0x1000000 + curY * 0x100 + curActor->_actorID) {
_displayOrder[i] = nextActor->_actorID;
_displayOrder[i + 1] = curActor->_actorID;
shouldContinue = true;
}
}
}
}
void ActorManager::resetDisplayOrder() {
for (uint16 i = 0; i < DRAGONS_ENGINE_NUM_ACTORS; i++) {
Actor *actor = getActor(i);
_displayOrder[i] = i;
if (!actor->isFlagSet(ACTOR_FLAG_40)) {
actor->_priorityLayer = 0;
}
}
}
Actor *ActorManager::getActorByDisplayOrder(uint16 position) {
return getActor(_displayOrder[position]);
}
Actor::Actor(uint16 id) : _actorID(id) {
_actorResource = nullptr;
_resourceID = -1;
_seqCodeIp = nullptr;
_priorityLayer = 3;
_x_pos = 160;
_y_pos = 110;
_walkDestX = 0;
_walkDestY = 0;
_walkSpeed = 0;
_flags = 0;
_frame_flags = 0;
_frame = nullptr;
_surface = nullptr;
_actorFileDictionaryIndex = 0;
_sequenceTimerMaxValue = 0;
_scale = 0x100;
_sequenceTimer = 0;
_sequenceID = 0;
_direction = 0;
_xShl16 = 0;
_yShl16 = 0;
_walkSlopeX = 0;
_walkSlopeY = 0;
_walkPointsIndex = 0;
_finalWalkDestX = 0;
_finalWalkDestY = 0;
_field_7a = 0;
}
void Actor::init(ActorResource *resource, int16 x, int16 y, uint32 sequenceID) {
debug(3, "actor %d Init", _actorID);
delete _actorResource;
_actorResource = resource;
_x_pos = x;
_y_pos = y;
_sequenceTimer = 0;
_walkDestX = x;
_walkDestY = y;
_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
_direction = 0;
_flags = (ACTOR_FLAG_40 | Dragons::ACTOR_FLAG_4);
_frame_flags = 4;
//TODO sub_80017010();
freeFrame();
updateSequence((uint16)sequenceID);
}
void Actor::updateSequence(uint16 newSequenceID) {
_sequenceID = newSequenceID;
_flags &= 0xfbf1;
_flags |= ACTOR_FLAG_1;
}
void Actor::resetSequenceIP() {
_seqCodeIp = _actorResource->getSequenceData(_sequenceID);
}
void Actor::loadFrame(uint16 frameOffset) {
freeFrame();
_frame = _actorResource->loadFrameHeader(frameOffset);
if (_frame->flags & 0x800) {
_frame_flags |= ACTOR_FRAME_FLAG_2;
} else {
_frame_flags &= ~ACTOR_FRAME_FLAG_2;
}
_surface = _actorResource->loadFrame(*_frame, nullptr); // TODO paletteId == 0xf1 ? getEngine()->getBackgroundPalette() : nullptr);
debug(5, "ActorId: %d load frame header: (%d,%d)", _actorID, _frame->width, _frame->height);
_flags |= ACTOR_FLAG_8; //TODO check if this is the right spot. engine sets it at 0x800185b0
}
void Actor::freeFrame() {
delete _frame;
delete _surface;
_frame = nullptr;
_surface = nullptr;
}
byte *Actor::getSeqIpAtOffset(uint32 offset) {
return _actorResource->getSequenceDataAtOffset(offset);
}
void Actor::reset_maybe() {
_flags = 0;
//TODO actor_find_by_resourceId_and_remove_resource_from_mem_maybe(resourceID);
freeFrame();
delete _actorResource;
_actorResource = nullptr;
}
uint32 calcDistance(int32 x1, int32 y1, int32 x2, int32 y2) {
return ABS(x2 - x1) * ABS(x2 - x1) + ABS(y2 - y1) * ABS(y2 - y1);
}
bool Actor::startWalk(int16 destX, int16 destY, uint16 flags) {
static const int kCosTbl[40] = {
// cos table
256, 251, 236, 212, 181, 142, 97, 49,
0, -49, -97, -142, -181, -212, -236, -251,
-255, -251, -236, -212, -181, -142, -97, -49,
0, 49, 97, 142, 181, 212, 236, 251,
11, 0, 0, 0, 0, 0, 0, 0
};
static const int kAdjustXTbl[8] = {
1, -1, 0, 0, 1, -1, 1, -1
};
static const int kAdjustYTbl[8] = {
0, 0, 1, -1, 1, 1, -1, -1
};
debug(1, "startWalk(%d, %d, %d)", _actorID, destX, destY);
bool wasAlreadyWalking = isFlagSet(ACTOR_FLAG_10);
clearFlag(ACTOR_FLAG_10);
// Check if the actor already is at the destination
if (_x_pos == destX && _y_pos == destY) {
if (wasAlreadyWalking) {
stopWalk();
}
return true;
}
int xorflagsl = 0;
int flag4 = 0;
int origDestX = 0, origDestY = 0;
int destPriority = 0;
if (flags < 2) {
destPriority = getEngine()->_scene->getPriorityAtPosition(Common::Point(destX, destY));
if (destPriority < 0)
destPriority = 1;
}
if ((flags == 0 && destPriority - 1 >= 8) || (flags == 1 && destPriority - 1 >= 16)) {
// Destination point is not walkable so it has to be adjusted
// Try to find a walkable destination point by testing the 32 corner points of a circle
// in increasing radius steps.
bool foundDestPos = false;
xorflagsl = 1;
origDestX = destX;
origDestY = destY;
for (int testRadius = 1; testRadius < 320 && !foundDestPos; ++testRadius) {
for (int octant = 0; octant < 32; ++octant) {
int testDestX = destX + ((testRadius * kCosTbl[octant % 32]) >> 8);
int testDestY = destY + ((testRadius * kCosTbl[(octant + 8) % 32]) >> 8);
if (testDestX >= 0 && testDestY >= 0) {
int testDestPriority = getEngine()->_scene->getPriorityAtPosition(Common::Point(testDestX, testDestY));
if ((flags == 0 && testDestPriority - 1 < 8) || (flags == 1 && testDestPriority - 1 < 16)) {
destX = testDestX;
destY = testDestY;
foundDestPos = true;
break;
}
}
}
}
if (!foundDestPos) {
if (wasAlreadyWalking) {
stopWalk();
}
return false;
}
} else {
// TODO Clean up
xorflagsl = (flags ^ 2) < 1 ? 1 : 0;
}
// Check if the actor already is at the adjusted destination
if (_x_pos == destX && _y_pos == destY) {
if (wasAlreadyWalking) {
stopWalk();
}
return true;
}
int tempDestX1 = destX, tempDestY1 = destY;
int actorX1 = _x_pos, actorY1 = _y_pos;
bool pathPointProcessed[kPathPointsCount];
for (int pointIndex = 0; pointIndex < kPathPointsCount; ++pointIndex) {
pathPointProcessed[pointIndex] = false;
}
_finalWalkDestX = destX;
_finalWalkDestY = destY;
if (!canWalkLine(actorX1, actorY1, tempDestX1, tempDestY1, flags)) {
// Adjust source/dest positions
for (int sxd = -1; sxd <= 1; ++sxd) {
for (int syd = -1; syd <= 1; ++syd) {
for (int dxd = -1; dxd <= 1; ++dxd) {
for (int dyd = -1; dyd <= 1; ++dyd) {
if (canWalkLine(actorX1 + sxd, actorY1 + syd, tempDestX1 + dxd, tempDestY1 + dyd, flags | 0x8000)) {
sxd = 2;
syd = 2;
dxd = 2;
dyd = 2;
actorX1 += sxd;
actorY1 += syd;
tempDestX1 += dxd;
tempDestY1 += dyd;
_x_pos += sxd;
_y_pos += syd;
}
}
}
}
}
}
if (flag4 == 0) {
// More adjusting of the source position
bool needAdjustSourcePoint = true;
for (int pointIndex = 0; pointIndex < kPathPointsCount; ++pointIndex) {
const Common::Point pt = getEngine()->_scene->getPoint(pointIndex);
if (pt.x != -1 && canWalkLine(actorX1, actorY1, pt.x, pt.y, flags)) {
needAdjustSourcePoint = false;
break;
}
}
if (needAdjustSourcePoint) {
for (int pointIndex = 0; needAdjustSourcePoint && pointIndex < kPathPointsCount; ++pointIndex) {
const Common::Point pt = getEngine()->_scene->getPoint(pointIndex);
for (int deltaIndex = 0; needAdjustSourcePoint && deltaIndex < 8; ++deltaIndex) {
const int deltaX = kAdjustXTbl[deltaIndex];
const int deltaY = kAdjustYTbl[deltaIndex];
if (canWalkLine(actorX1 + deltaX, actorY1 + deltaY, pt.x, pt.y, flags)) {
actorX1 += deltaX;
actorY1 += deltaY;
_x_pos += deltaX;
_y_pos += deltaY;
needAdjustSourcePoint = false;
}
}
}
}
// More adjusting of the destination position
bool needAdjustDestPoint = true;
for (int pointIndex = 0; pointIndex < kPathPointsCount; ++pointIndex) {
const Common::Point pt = getEngine()->_scene->getPoint(pointIndex);
if (pt.x != -1 && canWalkLine(destX, destY, pt.x, pt.y, flags)) {
needAdjustDestPoint = false;
break;
}
}
if (needAdjustDestPoint) {
for (int pointIndex = 0; needAdjustDestPoint && pointIndex < kPathPointsCount; ++pointIndex) {
const Common::Point pt = getEngine()->_scene->getPoint(pointIndex);
for (int deltaIndex = 0; needAdjustDestPoint && deltaIndex < 8; ++deltaIndex) {
const int deltaX = kAdjustXTbl[deltaIndex];
const int deltaY = kAdjustYTbl[deltaIndex];
if (canWalkLine(destX + deltaX, destY + deltaY, pt.x, pt.y, flags)) {
destX += deltaX;
destY += deltaY;
needAdjustDestPoint = false;
}
}
}
}
}
// Build the actual path. The path is constructed backwards from the destination to the source.
int pathPointsIndex = 0;
while (!canWalkLine(actorX1, actorY1, tempDestX1, tempDestY1, flags) && pathPointsIndex < kPathPointsCount) {
int foundPointIndex = pathfindingFindClosestPoint(actorX1, actorY1, tempDestX1, tempDestY1, flags, pathPointProcessed);
if (foundPointIndex < 0) {
if (wasAlreadyWalking) {
stopWalk();
}
return false;
}
pathPointProcessed[foundPointIndex] = true;
const Common::Point pt = getEngine()->_scene->getPoint(foundPointIndex);
tempDestX1 = pt.x;
tempDestY1 = pt.y;
if (pathPointsIndex >= 2) {
const Common::Point prevPt = getEngine()->_scene->getPoint(_walkPointsTbl[pathPointsIndex - 2]);
if (canWalkLine(pt.x, pt.y, prevPt.x, prevPt.y, flags)) {
--pathPointsIndex;
}
} else if (pathPointsIndex == 1) {
if (canWalkLine(pt.x, pt.y, destX, destY, flags)) {
--pathPointsIndex;
}
}
_walkPointsTbl[pathPointsIndex] = foundPointIndex;
++pathPointsIndex;
}
// Direction/post-processing
if (xorflagsl != 0) {
uint destDistance = calcDistance(destX, destY, tempDestX1, tempDestY1);
uint sourceDistance = calcDistance(actorX1, actorY1, destX, destY);
if (sourceDistance < 625 && ((actorX1 == destX && actorY1 == destY) || (sourceDistance < destDistance))) {
int newDirection;
int dx = origDestX - actorX1;
int dy = origDestY - actorY1;
if (dx != 0) {
int slope = dy / dx;
if (slope == 0) {
newDirection = (dx < 1) ? 4 : 0;
} else if (slope > 0) {
newDirection = (dx <= 0) ? 3 : 7;
} else {
newDirection = (dx <= 0) ? 5 : 1;
}
} else {
newDirection = (dy <= 0) ? 2 : 6;
}
_direction = newDirection;
if (wasAlreadyWalking) {
stopWalk();
}
return false;
}
}
_walkPointsIndex = pathPointsIndex - 1;
if (pathPointsIndex == 0) {
_walkDestX = tempDestX1;
_walkDestY = tempDestY1;
_finalWalkDestX = -1;
_finalWalkDestY = -1;
} else {
const Common::Point pt = getEngine()->_scene->getPoint(_walkPointsTbl[_walkPointsIndex]);
_walkDestX = pt.x;
_walkDestY = pt.y;
}
int direction = startMoveToPoint(_walkDestX, _walkDestY);
if (direction != -1 && !isFlagSet(ACTOR_FLAG_800)) {
_direction = direction;
}
if (_sequenceID != _direction + 8 && !isFlagSet(ACTOR_FLAG_800)) {
updateSequence(_direction + 8);
}
setFlag(ACTOR_FLAG_10);
return true;
}
void Actor::stopWalk() {
clearFlag(ACTOR_FLAG_10);
_walkPointsIndex = 0;
_walkDestX = _x_pos;
_walkDestY = _y_pos;
_finalWalkDestX = -1;
_finalWalkDestY = -1;
setFlag(ACTOR_FLAG_4);
if (_flags & ACTOR_FLAG_200) {
clearFlag(ACTOR_FLAG_800);
}
}
void Actor::waitUntilFlag4IsSet() {
while (!isFlagSet(ACTOR_FLAG_4) && !Engine::shouldQuit()) {
getEngine()->waitForFrames(1);
}
}
void Actor::waitUntilFlag8IsSet() {
if (_flags & ACTOR_FLAG_8) {
return;
}
while (!(_flags & ACTOR_FLAG_8) && !Engine::shouldQuit()) {
getEngine()->waitForFrames(1);
}
}
void Actor::waitUntilFlag8And4AreSet() {
waitUntilFlag8IsSet();
waitUntilFlag4IsSet();
}
void Actor::waitUntilFlag8SetThenSet1000() {
waitUntilFlag8IsSet();
setFlag(ACTOR_FLAG_1000);
}
void Actor::waitUntilFlag8SetThenSet1000AndWaitFor4() {
waitUntilFlag8SetThenSet1000();
waitUntilFlag4IsSet();
}
void Actor::clearFlag(uint32 flag) {
_flags &= ~flag;
}
void Actor::setFlag(uint32 flag) {
_flags |= flag;
}
bool Actor::isFlagSet(uint32 flag) {
return (_flags & flag) == flag;
}
uint16 Actor::canWalkLine(int16 actor_x, int16 actor_y, int16 target_x, int16 target_y, uint16 walkFlags) {
debug(1, "canWalkLine. (%X,%X) -> (%X,%X) %d", _x_pos, _y_pos, target_x, target_y, walkFlags);
if (walkFlags == 2) {
return 1;
}
uint16 width = getEngine()->_scene->getStageWidth();
uint16 height = getEngine()->_scene->getStageHeight();
if (walkFlags & 0x8000) {
if (actor_x < 0
|| width - 1 < actor_x
|| actor_y < 0
|| height - 1 < actor_y
|| target_x < 0
|| width - 1 < target_x
|| target_y < 0
|| height - 1 < target_y) {
return 0;
}
}
int32 x_increment = 0;
int32 y_increment = 0;
if (target_y == actor_y && target_x == target_y) {
return 1;
}
int16 deltaX = target_x - actor_x;
int16 deltaY = target_y - actor_y;
if (target_y != actor_y && target_x == actor_x) {
y_increment = deltaY > 0 ? 0x10000 : -0x10000;
} else {
if (target_y == actor_y) {
if (target_x == actor_x) {
x_increment = 0;
y_increment = deltaY > 0 ? 0x10000 : -0x10000;
} else {
x_increment = deltaX > 0 ? 0x10000 : -0x10000;
y_increment = 0;
}
} else {
if (ABS(deltaY) < ABS(deltaX)) {
x_increment = deltaX > 0 ? 0x10000 : -0x10000;
y_increment = ((deltaY) << 0x10) / (deltaX);
if ((deltaY > 0 && y_increment < 0) || (deltaY < 0 && y_increment > 0)) {
y_increment = -y_increment;
}
} else {
y_increment = deltaY > 0 ? 0x10000 : -0x10000;
x_increment = ((deltaX) << 0x10) / (deltaY);
if ((deltaX > 0 && x_increment < 0) || (deltaX < 0 && x_increment > 0)) {
x_increment = -x_increment;
}
}
}
}
// 0x80034d28
int32 x = actor_x << 0x10;
int32 y = actor_y << 0x10;
for (;;) {
if ((x+0x8000) >> 0x10 == target_x && (y+0x8000) >> 0x10 == target_y) {
return 1;
}
int16 priority = getEngine()->_scene->getPriorityAtPosition(Common::Point(x>>0x10, y>>0x10));
if (priority < 0) {
priority = 1;
}
if (!(walkFlags & 0x7fff) && (priority == 0 || priority >= 8)) {
return 0;
}
if ((walkFlags & 0x7fff) == 1) {
if (priority == 0 || priority >= 0x10) {
return 0;
}
}
x += x_increment;
y += y_increment;
}
}
int Actor::startMoveToPoint(int destX, int destY) {
int direction = 0;
int quadrant = 0;
int deltaX = destX - _x_pos;
int deltaY = (destY - _y_pos) * 2;
int absDeltaX = ABS(deltaX);
int absDeltaY = ABS(deltaY);
// debug("from: (%d, %d); to: (%d, %d); d: (%d, %d); actor._walkSpeed: %08X", _x_pos, actor._y, destX, destY, deltaX, deltaY, actor._walkSpeed);
_xShl16 = _x_pos << 16;
_yShl16 = _y_pos << 16;
// Walk slope is a fixed point value, where the upper 16 bits are the integral part,
// and the lower 16 bits the fractional part. 0x10000 is 1.0.
if (deltaX != 0 && deltaY != 0) {
// Walk along both X and Y axis
if (absDeltaX < absDeltaY) {
_walkSlopeX = (absDeltaX << 16) / absDeltaY;
_walkSlopeY = 0x10000;
} else {
_walkSlopeX = 0x10000;
_walkSlopeY = (absDeltaY << 16) / absDeltaX;
}
} else if (deltaX != 0) {
// Walk along X only
_walkSlopeX = 0x10000;
_walkSlopeY = 0;
} else if (deltaY != 0) {
// Walk along Y only
_walkSlopeX = 0;
_walkSlopeY = 0x10000;
} else {
// Already at dest
return -1;
}
_walkSlopeX = (_walkSlopeX / 32) * (_walkSpeed / 0x800);
_walkSlopeY = (_walkSlopeY / 32) * (_walkSpeed / 0x800);
if (deltaX < 0) {
_walkSlopeX = -_walkSlopeX;
quadrant += 2;
}
if (deltaY < 0) {
_walkSlopeY = -_walkSlopeY;
quadrant += 1;
}
switch (quadrant) {
case 0:
direction = (absDeltaX < absDeltaY) ? 2 : 0;
break;
case 1:
direction = (absDeltaX < absDeltaY) ? 6 : 0;
break;
case 2:
direction = (absDeltaX < absDeltaY) ? 2 : 4;
break;
case 3:
direction = (absDeltaX < absDeltaY) ? 6 : 4;
break;
default:
break;
}
_walkSlopeY /= 2;
_walkDestX = destX;
_walkDestY = destY;
if (getEngine()->_dragonINIResource->isFlicker(_actorID)) {
// Adjust walk slope for the main actor
_walkSlopeX = _walkSlopeX * 3 / 2;
_walkSlopeY = _walkSlopeY * 3 / 2;
}
return direction;
}
void Actor::walkPath() {
if (isFlagClear(ACTOR_FLAG_400) && isFlagSet(Dragons::ACTOR_FLAG_40) && isFlagSet(Dragons::ACTOR_FLAG_10)) {
_xShl16 += (((_scale * _walkSlopeX) / DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE) * 5) / 4;
_yShl16 += (((_scale * _walkSlopeY) / DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE) * 5) / 4;
if ((_walkSlopeX >= 0 && _walkDestX < (_xShl16 >> 0x10))
|| (_walkSlopeX < 0 && (_xShl16 >> 0x10) < _walkDestX)) {
_xShl16 = _walkDestX << 0x10;
}
if ((_walkSlopeY >= 0 && _walkDestY < (_yShl16 >> 0x10))
|| (_walkSlopeY < 0 && (_yShl16 >> 0x10) < _walkDestY)) {
_yShl16 = _walkDestY << 0x10;
}
_x_pos = _xShl16 >> 0x10;
_y_pos = _yShl16 >> 0x10;
if (_x_pos == _walkDestX && _y_pos == _walkDestY) {
if (_walkPointsIndex <= 0) {
if (_finalWalkDestX < 0) {
clearFlag(ACTOR_FLAG_10);
if (isFlagClear(ACTOR_FLAG_200)) {
clearFlag(ACTOR_FLAG_800);
}
setFlag(ACTOR_FLAG_4);
clearFlag(ACTOR_FLAG_1);
return;
} else {
_walkDestX = _finalWalkDestX;
_walkDestY = _finalWalkDestY;
_finalWalkDestX = -1;
_finalWalkDestY = -1;
}
} else {
_walkPointsIndex--;
Common::Point point = getEngine()->_scene->getPoint(_walkPointsTbl[_walkPointsIndex]);
_walkDestX = point.x;
_walkDestY = point.y;
}
// 0x8001bcc8
int direction = startMoveToPoint(_walkDestX, _walkDestY);
if (direction != -1 && !isFlagSet(ACTOR_FLAG_800)) {
_direction = direction;
}
if (_sequenceID != _direction + 8 && _direction != -1 && !isFlagSet(ACTOR_FLAG_800)) {
updateSequence(_direction + 8);
}
setFlag(ACTOR_FLAG_10);
}
}
}
// 0x80034930
int16 Actor::pathfindingFindClosestPoint(int16 actor_x, int16 actor_y, int16 target_x, int16 target_y,
int16 unkType, bool *pointsInUseTbl) {
int16 pointId = -1;
uint32 minDist = 0xffffffff;
for (int i = 0; i < kPathPointsCount; i++) {
Common::Point point = getEngine()->_scene->getPoint(i);
if (point.x != -1 && !pointsInUseTbl[i]) {
if (canWalkLine(point.x, point.y, target_x, target_y, unkType)) {
uint32 dist = abs(point.x - actor_x) * abs(point.x - actor_x) + abs(point.y - actor_y) * abs(point.y - actor_y);
if (dist < minDist) {
minDist = dist;
pointId = i;
}
}
}
}
return pointId;
}
bool Actor::actorSetSequenceAndWaitAllowSkip(uint16 newSequenceID) {
updateSequence(newSequenceID);
waitUntilFlag8IsSet();
return waitUntilFlag4IsSetAllowSkip();
}
bool Actor::waitUntilFlag4IsSetAllowSkip() {
while (!isFlagSet(ACTOR_FLAG_4) && !Engine::shouldQuit()) {
getEngine()->waitForFrames(1);
if (getEngine()->checkForActionButtonRelease()) {
return true;
}
}
return false;
}
byte *Actor::getPalette() {
if (!isFlagSet(ACTOR_FLAG_4000)) {
if (!isFlagSet(ACTOR_FLAG_8000)) {
if ((_frame_flags & 0x30) != 0) {
return _actorResource->getPalette();
}
return getEngine()->_screen->getPalette(1);
} else {
return getEngine()->_screen->getPalette(0);
}
}
return getEngine()->_screen->getPalette(4);
}
int16 Actor::getFrameYOffset() {
return _frame ? _frame->yOffset : 0;
}
void Actor::waitForWalkToFinish() {
DragonsEngine *vm = getEngine();
do {
vm->waitForFrames(1);
} while (!Engine::shouldQuit() && isFlagSet(ACTOR_FLAG_10));
}
} // End of namespace Dragons

156
engines/dragons/actor.h Normal file
View File

@@ -0,0 +1,156 @@
/* 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 DRAGONS_ACTOR_H
#define DRAGONS_ACTOR_H
#include "common/array.h"
#include "common/scummsys.h"
#include "graphics/surface.h"
namespace Dragons {
class Actor;
class ActorResourceLoader;
class ActorResource;
struct ActorFrame;
#define DRAGONS_ENGINE_NUM_ACTORS 64
enum ActorFlags {
ACTOR_FLAG_1 = 1,
ACTOR_FLAG_2 = 2,
ACTOR_FLAG_4 = 4,
ACTOR_FLAG_8 = 8,
ACTOR_FLAG_10 = 0x10, //actor is walking a path
ACTOR_FLAG_20 = 0x20,
ACTOR_FLAG_40 = 0x40,
ACTOR_FLAG_80 = 0x80,
ACTOR_FLAG_100 = 0x100,
ACTOR_FLAG_200 = 0x200, // Use screen coordinates not map coordinates.
ACTOR_FLAG_400 = 0x400, // Actor is hidden
ACTOR_FLAG_800 = 0x800,
ACTOR_FLAG_1000 = 0x1000,
ACTOR_FLAG_2000 = 0x2000,
ACTOR_FLAG_4000 = 0x4000,
ACTOR_FLAG_8000 = 0x8000 //Seems turn off semi trans mode when selected.
};
enum ActorFrameFlags {
ACTOR_FRAME_FLAG_2 = 0x2,
ACTOR_FRAME_FLAG_10 = 0x10,
ACTOR_FRAME_FLAG_20 = 0x20
};
class ActorManager {
public:
typedef Common::Array<Actor> Actors;
private:
ActorResourceLoader *_actorResourceLoader;
Actors _actors;
uint16 _displayOrder[DRAGONS_ENGINE_NUM_ACTORS];
public:
ActorManager(ActorResourceLoader *actorResourceLoader);
public:
Actor *loadActor(uint32 resourceId, uint32 sequenceId, int16 x, int16 y);
Actor *loadActor(uint32 resourceId, uint32 sequenceId, int16 x, int16 y, uint16 priorityLayer);
Actor *loadActor(uint32 resourceId, uint16 actorId);
Actor *getActor(uint16 actorId);
Actor *getActorByDisplayOrder(uint16 position);
void clearActorFlags(uint16 startingActorId);
ActorResource *getActorResource(uint32 resourceId);
void updateActorDisplayOrder();
private:
Actor *findFreeActor(int16 resourceID);
void resetDisplayOrder();
};
class Actor {
public:
uint16 _actorID;
ActorResource* _actorResource;
uint16 _actorFileDictionaryIndex;
int16 _resourceID;
byte *_seqCodeIp;
ActorFrame *_frame;
Graphics::Surface *_surface;
uint16 _sequenceTimerMaxValue;
int16 _scale; // scale factor 0x100 is 100%
uint16 _sequenceTimer;
uint16 _sequenceID;
int16 _direction;
int16 _priorityLayer;
uint16 _flags;
int16 _x_pos;
int16 _y_pos;
int16 _walkDestX;
int16 _walkDestY;
int32 _xShl16;
int32 _yShl16;
int32 _walkSlopeX;
int32 _walkSlopeY;
uint16 _walkPointsTbl[32];
int16 _walkPointsIndex;
int16 _finalWalkDestX;
int16 _finalWalkDestY;
uint16 _field_7a;
int32 _walkSpeed;
uint16 _frame_flags;
public:
Actor(uint16 id);
void init(ActorResource *resource, int16 x, int16 y, uint32 sequenceID);
void updateSequence(uint16 newSequenceID);
void resetSequenceIP();
byte *getSeqIpAtOffset(uint32 offset);
void loadFrame(uint16 frameOffset);
void freeFrame();
void reset_maybe();
bool startWalk(int16 destX, int16 destY, uint16 flags);
void walkPath();
void waitUntilFlag4IsSet();
void waitUntilFlag8IsSet();
void waitUntilFlag8And4AreSet();
void waitUntilFlag8SetThenSet1000();
void waitUntilFlag8SetThenSet1000AndWaitFor4();
void waitForWalkToFinish();
bool waitUntilFlag4IsSetAllowSkip();
bool actorSetSequenceAndWaitAllowSkip(uint16 newSequenceID);
void clearFlag(uint32 flag);
void setFlag(uint32 flag);
bool isFlagSet(uint32 flag);
bool isFlagClear(uint32 flag) { return !isFlagSet(flag); }
byte *getPalette();
int16 getFrameYOffset();
private:
void stopWalk();
uint16 canWalkLine(int16 actor_x, int16 actor_y, int16 target_x, int16 target_y, uint16 walkFlags);
int16 pathfindingFindClosestPoint(int16 actor_x, int16 actor_y, int16 target_x, int16 target_y, int16 unkType,
bool *pointsInUseTbl);
int startMoveToPoint(int destX, int destY);
};
} // End of namespace Dragons
#endif //DRAGONS_ACTOR_H

View File

@@ -0,0 +1,247 @@
/* 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 DRAGONS_ACTORFILES_H
#define DRAGONS_ACTORFILES_H
#define DRAGONS_NUM_ACTOR_FILES 219
const char actorResourceFiles[DRAGONS_NUM_ACTOR_FILES][13] = {
"cursor.act",
"invenicn.act",
"s01b1.act",
"s00f1.act",
"s01h4.act",
"s07b2.act",
"s01g6.act",
"s02d1.act",
"s02d4.act",
"s00h6.act",
"s00h8.act",
"s00h3.act",
"s03a3.act",
"s00h2.act",
"flicker.act",
"s00h4.act",
"s00h5.act",
"s00h1.act",
"s00h7.act",
"s00h9.act",
"s03a6.act",
"s00i1.act",
"s00i4.act",
"s00j2.act",
"s00j1.act",
"s00i2.act",
"s01h1.act",
"flkspec.act",
"s03a2.act",
"s03a1.act",
"s12a2.act",
"s12a1.act",
"s12a4.act",
"s01f1.act",
"s01l1.act",
"s02c4.act",
"s03a4.act",
"s12a3.act",
"s02d3.act",
"s00ha.act",
"s01j2.act",
"s01j1.act",
"s01j0.act",
"s07a1.act",
"s07a2.act",
"s02b1.act",
"s02b2.act",
"s06a1.act",
"s06a2.act",
"s12c1.act",
"s12b2.act",
"s04a1.act",
"s00i3.act",
"s04a2.act",
"s02a2.act",
"s09i1.act",
"s02a3.act",
"s02a1.act",
"s02a4.act",
"s02d2.act",
"s05a1.act",
"s02c3.act",
"s02c1.act",
"s02c2.act",
"s02c5.act",
"s02c8.act",
"s02a5.act",
"s02c9.act",
"s02c6.act",
"s02c51.act",
"s09i2.act",
"s00f2.act",
"s02ca.act",
"s02c11.act",
"s02c7.act",
"s11a1.act",
"s09b2.act",
"s09b3.act",
"s09b6.act",
"s09b7.act",
"s09b1.act",
"s09b4.act",
"shadow.act",
"s09e1.act",
"flkg.act",
"s01g4.act",
"s01g3.act",
"s01g2.act",
"s00f3.act",
"s01g7.act",
"s09h4.act",
"s09c3.act",
"s09c2.act",
"s09c1.act",
"s09c4.act",
"s00b1.act",
"s09b5.act",
"s01k2.act",
"s01k1.act",
"s10b1.act",
"s01c1.act",
"s01h5.act",
"s09a1.act",
"s13a4.act",
"s09f1.act",
"s08a1.act",
"s09f3.act",
"s08b1.act",
"s07b1.act",
"s09f2.act",
"s00f4.act",
"s06b1.act",
"s05b1.act",
"s05b2.act",
"s05b3.act",
"s05b4.act",
"s05b5.act",
"s10a3.act",
"s10a6.act",
"s10a2.act",
"s10a1.act",
"s10a5.act",
"s10a7.act",
"s10a4.act",
"s01d1.act",
"s01d2.act",
"s01d3.act",
"s12b1.act",
"s12b3.act",
"s01d4.act",
"s01d5.act",
"s13a1.act",
"s13a2.act",
"s13a0.act",
"s04a3.act",
"s13a3.act",
"s13a5.act",
"flickert.act",
"s01a1.act",
"s01d7.act",
"s01d8.act",
"s14e1.act",
"s14e2.act",
"s01d9.act",
"s07c1.act",
"s10b2.act",
"s01g1.act",
"s01g5.act",
"s01h2.act",
"s01h3.act",
"s01i1.act",
"s02b3.act",
"s03a5.act",
"s09i4.act",
"s09i3.act",
"s14a1.act",
"s14a2.act",
"s01k3.act",
"s01i2.act",
"s01b2.act",
"s01c2.act",
"s14a3.act",
"s01j3.act",
"s01f2.act",
"s01c3.act",
"s01i3.act",
"s01e1.act",
"s01h6.act",
"s07b3.act",
"s01a2.act",
"s01da.act",
"s02a6.act",
"s02d5.act",
"s07a3.act",
"s07b4.act",
"s09e2.act",
"s10b3.act",
"s10b4.act",
"s09c5.act",
"s09h5.act",
"s14d1.act",
"s02e1.act",
"s09d1.act",
"s14f1.act",
"s14g1.act",
"s14g2.act",
"s14g3.act",
"s10d1.act",
"s08a2.act",
"s09c6.act",
"s00g1.act",
"s00g2.act",
"s00g3.act",
"s04a4.act",
"s08a3.act",
"s11a2.act",
"s02cb.act",
"s11a3.act",
"s05b0.act",
"s14a5.act",
"s14a25.act",
"s14a0.act",
"s14a15.act",
"s05b6.act",
"s12a5.act",
"s12a6.act",
"s13b1.act",
"s13b2.act",
"s01g8.act",
"s01g9.act",
"s02cc.act",
"s01d20.act",
"s01d21.act",
"s01d22.act",
"s01d23.act",
"s01d24.act",
"s01d25.act",
"titles.act",
"dem11.act"
};
#endif //DRAGONS_ACTORFILES_H

View File

@@ -0,0 +1,201 @@
/* 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 "graphics/surface.h"
#include "dragons/actorfiles.h"
#include "dragons/bigfile.h"
#include "dragons/actorresource.h"
namespace Dragons {
ActorResourceLoader::ActorResourceLoader(BigfileArchive *bigFileArchive) : _bigFileArchive(bigFileArchive) {
}
ActorResource *ActorResourceLoader::load(uint32 resourceId) {
assert (resourceId < DRAGONS_NUM_ACTOR_FILES);
ActorResource *actorResource = new ActorResource();
const char *filename = actorResourceFiles[resourceId];
uint32 size;
byte *scrData = _bigFileArchive->load(filename, size);
Common::SeekableReadStream *readStream = new Common::MemoryReadStream(scrData, size, DisposeAfterUse::NO);
debug(1, "Loading '%s'", filename);
actorResource->load(resourceId, scrData, *readStream);
return actorResource;
}
bool ActorResource::load(uint32 id, byte *dataStart, Common::SeekableReadStream &stream) {
_id = id;
_data = dataStart;
_fileSize = stream.size();
stream.seek(0x6);
_sequenceTableOffset = stream.readUint16LE();
uint16 frameOffset = stream.readUint16LE();
uint16 paletteOffset = stream.readUint16LE();
stream.seek(paletteOffset);
stream.read(_palette, 512);
_palette[0] = 0;
_palette[1] = 0;
// _palette[1] = 0x80; // set alpha (bit 15) on first palette entry.
// for (int i = 1; i < 0x100; i++) {
// if (_palette[i * 2] == 0 && _palette[i * 2 + 1] == 0) {
// _palette[i * 2 + 1] = 0x80;
// }
// }
stream.seek(frameOffset);
_framesCount = (paletteOffset - stream.readUint16LE()) / 0xe;
debug(3, "Frame Count: %d", _framesCount);
_frames = new ActorFrame[_framesCount];
for (int i = 0; i < _framesCount; i++) {
stream.seek(frameOffset + i * 2);
uint16 offset = stream.readUint16LE();
stream.seek(offset);
_frames[i].xOffset = stream.readSint16LE();
_frames[i].yOffset = stream.readSint16LE();
_frames[i].width = stream.readByte() * 2; //FIXME the original checks actor->frame_flags bit 0 here at 0x80018438
_frames[i].height = stream.readByte();
uint32 frameDataOffset = stream.readUint32LE();
_frames[i].frameDataOffset = &dataStart[frameDataOffset];
_frames[i].flags = stream.readUint16LE();
_frames[i].field_c = stream.readUint16LE();
// debug(3, "Frame[%d] @%X, xOffset: %d field_2: %d (%d, %d) offset: %X, flags: %X field_c: %d",
// i, offset, _frames[i].xOffset, _frames[i].yOffset, _frames[i].width, _frames[i].height, frameDataOffset, _frames[i].flags, _frames[i].field_c);
}
return false;
}
Graphics::Surface *ActorResource::loadFrame(ActorFrame &actorFrame, byte *palette) {
if (!palette) {
palette = _palette;
}
Graphics::Surface *surface = new Graphics::Surface();
surface->create(actorFrame.width, actorFrame.height, Graphics::PixelFormat::createFormatCLUT8());
byte *pixels = (byte *)surface->getPixels();
int32 blockSize = ((actorFrame.width / 2) * actorFrame.height * 2) / 4;
debug(5, "Frame blockSize: %d width: %d height: %d", blockSize, actorFrame.width, actorFrame.height);
byte *data = actorFrame.frameDataOffset;
while (blockSize > 0) {
int32 size = READ_BE_INT32(data);
data += 4;
if (size >= 0) {
if (blockSize < size) {
size = blockSize;
}
blockSize -= size;
if (size != 0) {
memcpy(pixels, data, size * 4);
data += size * 4;
pixels += size * 4;
}
} else {
size = size & 0x7fffffff;
if (blockSize < size) {
size = blockSize;
}
blockSize -= size;
if (size != 0) {
for (int32 i = size; i != 0; i--) {
memcpy(pixels, data, 4);
pixels += 4;
}
}
data += 4;
}
}
return surface;
}
ActorFrame *ActorResource::getFrameHeader(uint16 frameNumber) {
assert (frameNumber < _framesCount);
return &_frames[frameNumber];
}
byte *ActorResource::getSequenceData(int16 sequenceId) {
uint16 offset = READ_LE_UINT16(_data + _sequenceTableOffset + (sequenceId * 2));
return &_data[offset];
}
ActorFrame *ActorResource::loadFrameHeader(uint16 frameOffset) {
Common::SeekableReadStream *stream = new Common::MemoryReadStream(_data + frameOffset, sizeof(ActorFrame), DisposeAfterUse::NO);
ActorFrame *frame = new ActorFrame;
frame->xOffset = stream->readSint16LE();
frame->yOffset = stream->readSint16LE();
frame->width = stream->readByte() * 2; //FIXME the original checks actor->frame_flags bit 0 here at 0x80018438
frame->height = stream->readByte();
uint32 frameDataOffset = stream->readUint32LE();
frame->frameDataOffset = &_data[frameDataOffset];
frame->flags = stream->readUint16LE();
frame->field_c = stream->readUint16LE();
frame->field_e = stream->readSint16LE();
frame->field_10 = stream->readSint16LE();
delete stream;
return frame;
}
const char *ActorResource::getFilename() {
return actorResourceFiles[_id];
}
byte *ActorResource::getSequenceDataAtOffset(uint32 offset) {
assert(offset < (uint32)_fileSize);
return &_data[offset];
}
byte *ActorResource::getPalette() {
return _palette;
}
ActorResource::ActorResource() : _id(0), _data(nullptr), _fileSize(0), _frames(nullptr),
_framesCount(0),
_sequenceTableOffset(0) {
memset(_palette, 0, 512);
}
ActorResource::~ActorResource() {
if (_data) {
free(_data);
}
delete _frames;
}
} // End of namespace Dragons

View File

@@ -0,0 +1,88 @@
/* 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 DRAGONS_ACTORRESOURCE_H
#define DRAGONS_ACTORRESOURCE_H
#include "common/scummsys.h"
#include "graphics/surface.h"
#include "common/stream.h"
namespace Dragons {
class BigfileArchive;
class ActorResource;
struct ActorFrame {
int16 xOffset;
int16 yOffset;
uint16 width;
uint16 height;
byte *frameDataOffset;
uint16 flags;
uint16 field_c;
int16 field_e;
int16 field_10;
};
enum FrameFlags {
FRAME_FLAG_FLIP_X = 0x800
};
class ActorResourceLoader {
private:
BigfileArchive *_bigFileArchive;
public:
ActorResourceLoader(BigfileArchive *bigFileArchive);
ActorResource *load(uint32 resourceId);
};
class ActorResource {
public:
uint32 _id;
private:
byte *_data;
int32 _fileSize;
ActorFrame *_frames;
uint16 _framesCount;
byte _palette[512];
uint16 _sequenceTableOffset;
//uint16 _sequenceCount;
public:
ActorResource();
~ActorResource();
bool load(uint32 id, byte *dataStart, Common::SeekableReadStream &stream);
Graphics::Surface *loadFrame(ActorFrame &frameNumber, byte *palette);
ActorFrame *loadFrameHeader(uint16 frameOffset);
ActorFrame *getFrameHeader(uint16 frameNumber);
byte *getSequenceData(int16 sequenceId);
byte *getSequenceDataAtOffset(uint32 offset);
const char *getFilename();
byte *getPalette();
private:
};
} // End of namespace Dragons
#endif //DRAGONS_ACTORRESOURCE_H

View File

@@ -0,0 +1,441 @@
/* 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/endian.h"
#include "dragons/background.h"
#include "dragons/screen.h"
namespace Dragons {
#define TILE_WIDTH 32
#define TILE_HEIGHT 8
#define TILE_SIZE (TILE_WIDTH * TILE_HEIGHT)
void PriorityLayer::load(TileMap &tileMap, byte *tiles) {
_width = tileMap.w * TILE_WIDTH;
_height = tileMap.h * TILE_HEIGHT;
_mapWidth = tileMap.w;
_mapHeight = tileMap.h;
size_t tileSize = (size_t)tileMap.tileIndexOffset * TILE_SIZE;
_map = new byte[tileMap.size];
_mapBase = new byte[tileMap.size];
_values = new byte[tileSize];
memcpy(_map, tileMap.map, tileMap.size);
memcpy(_mapBase, tileMap.map, tileMap.size);
memcpy(_values, tiles, tileSize);
}
int16 PriorityLayer::getPriority(Common::Point pos) {
pos.x = CLIP<int16>(pos.x, 0, _width - 1);
pos.y = CLIP<int16>(pos.y, 0, _height - 1);
const int16 tx = pos.x / TILE_WIDTH, sx = pos.x % TILE_WIDTH;
const int16 ty = pos.y / TILE_HEIGHT, sy = pos.y % TILE_HEIGHT;
uint16 mapIndex = READ_LE_UINT16(_map + 2 * (tx + ty * _mapWidth));
//
// byte priority = *(byte *)((((uint)*(uint16 *)
// (((int)pos.x / 32) * 2 +
// ((int)pos.y / 8) * (uint)_mapWidth * 2 +
// _map) * 32) * 8) +
// _values + (((int)pos.y % 8) * 32) +
// ((int)pos.x % 32));
return _values[mapIndex * TILE_WIDTH * TILE_HEIGHT + sx + sy * TILE_WIDTH] + 1;
}
void PriorityLayer::overlayTileMap(byte *data, int16 x, int16 y, int16 w, int16 h) {
byte *ptr = _map + (x + y * _mapWidth) * 2;
byte *src = data;
for (int i = 0; i < h; i++) {
memcpy(ptr, src, w * 2);
src += w * 2;
ptr += _mapWidth * 2;
}
}
void PriorityLayer::restoreTileMap(int16 x, int16 y, int16 w, int16 h) {
byte *ptr = _map + (x + y * _mapWidth) * 2;
byte *src = _mapBase + (x + y * _mapWidth) * 2;
for (int i = 0; i < h; i++) {
memcpy(ptr, src, w * 2);
src += _mapWidth * 2;
ptr += _mapWidth * 2;
}
}
Background::Background() : _priorityLayer(nullptr), _points2(nullptr), _data(nullptr) {
_layerSurface[0] = nullptr;
_layerSurface[1] = nullptr;
_layerSurface[2] = nullptr;
_layerOffset[0] = Common::Point(0, 0);
_layerOffset[1] = Common::Point(0, 0);
_layerOffset[2] = Common::Point(0, 0);
_layerAlphaMode[0] = NONE;
_layerAlphaMode[1] = NONE;
_layerAlphaMode[2] = NONE;
_tileDataOffset = nullptr;
}
Background::~Background() {
if (_data) {
delete _data;
}
for (int i = 0; i < 3; i++) {
if (_layerSurface[i]) {
_layerSurface[i]->free();
delete _layerSurface[i];
}
}
}
bool Background::load(byte *dataStart, uint32 size) {
Common::MemoryReadStream stream(dataStart, size, DisposeAfterUse::NO);
_data = dataStart;
stream.read(_palette, 512);
_palette[0] = 0x00; //FIXME update palette
_palette[1] = 0x00;
_scaleLayer.load(stream); // 0x200
_points2 = loadPoints(stream); // 0x280
stream.seek(0x305);
uint8 tileindexOffset = stream.readByte();
stream.seek(0x308);
uint32 tilemapOffset = 0x324;
for (int i = 0; i < 3; i++) {
_tileMap[i].w = stream.readUint16LE();
_tileMap[i].h = stream.readUint16LE();
_tileMap[i].size = stream.readUint32LE();
_tileMap[i].map = dataStart + tilemapOffset;
_tileMap[i].tileIndexOffset = tileindexOffset;
debug(3, "Tilemap (%d, %d) map: %X", _tileMap[i].w, _tileMap[i].h, tilemapOffset);
tilemapOffset += _tileMap[i].size;
}
uint32 finalSize = stream.readUint32LE();
TileMap priorityTilemap;
priorityTilemap.w = _tileMap[0].w;
priorityTilemap.h = _tileMap[0].h;
priorityTilemap.size = _tileMap[0].size;
priorityTilemap.map = dataStart + tilemapOffset;
priorityTilemap.tileIndexOffset = tileindexOffset;
uint32 tilesOffset = tilemapOffset + finalSize;
_tileDataOffset = _data + tilesOffset;
_priorityLayer = new PriorityLayer();
_priorityLayer->load(priorityTilemap, _tileDataOffset);
debug(3, "Tiles: %X", tilesOffset);
debug(3, "tileIndexOffset: %d", _tileMap[0].tileIndexOffset);
for (int i = 0; i < 3; i++) {
_layerSurface[i] = initGfxLayer(_tileMap[i]);
loadGfxLayer(_layerSurface[i], _tileMap[i], _tileDataOffset);
}
_layerPriority[0] = 1;
_layerPriority[1] = 2;
_layerPriority[2] = 3;
return false;
}
Common::Point *Background::loadPoints(Common::SeekableReadStream &stream) {
Common::Point *points = new Common::Point[0x20];
for (int i = 0; i < 0x20; i++) {
points[i].x = stream.readUint16LE();
points[i].y = stream.readUint16LE();
}
return points;
}
Graphics::Surface *Background::initGfxLayer(TileMap &tileMap) {
Graphics::Surface *surface = new Graphics::Surface();
surface->create(tileMap.w * TILE_WIDTH, tileMap.h * TILE_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
return surface;
}
void Background::loadGfxLayer(Graphics::Surface *surface, TileMap &tileMap, byte *tiles) {
for (int y = 0; y < tileMap.h; y++) {
for (int x = 0; x < tileMap.w; x++) {
uint16 idx = READ_LE_UINT16(&tileMap.map[(y * tileMap.w + x) * 2]) + tileMap.tileIndexOffset;
//debug("tileIdx: %d", idx);
drawTileToSurface(surface, _palette, tiles + idx * 0x100, x * TILE_WIDTH, y * TILE_HEIGHT);
}
}
}
void drawTileToSurface(Graphics::Surface *surface, byte *palette, byte *tile, uint32 x, uint32 y) {
byte *pixels = (byte *)surface->getPixels();
if (surface->format.bpp() == 16) {
for (int ty = 0; ty < TILE_HEIGHT; ty++) {
for (int tx = 0; tx < TILE_WIDTH; tx++) {
uint32 cidx = *tile;
uint32 offset = (y + ty) * surface->pitch + (x + tx) * 2;
pixels[offset] = palette[cidx * 2];
pixels[offset + 1] = palette[cidx * 2 + 1];
tile++;
}
}
} else {
for (int ty = 0; ty < TILE_HEIGHT; ty++) {
memcpy(&pixels[(y + ty) * surface->pitch + x], tile, TILE_WIDTH);
tile += TILE_WIDTH;
}
}
}
Common::Point Background::getPoint2(uint32 pointIndex) {
assert (pointIndex < 0x20);
return _points2[pointIndex];
}
uint16 Background::getWidth() {
assert (_layerSurface[1]);
return _layerSurface[1]->w;
}
uint16 Background::getHeight() {
assert (_layerSurface[1]);
return _layerSurface[1]->h;
}
int16 Background::getPriorityAtPoint(Common::Point pos) {
if (pos.x < 0 || pos.x >= getWidth() || pos.y < 0 || pos.y >= getHeight()) {
return -1;
}
int16 priority = _priorityLayer->getPriority(pos);
return priority < 0x11 ? priority : 0;
}
void Background::overlayImage(uint16 layerNum, byte *data, int16 x, int16 y, int16 w, int16 h) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int16 idx = READ_LE_UINT16(data) + _tileMap[layerNum].tileIndexOffset;
drawTileToSurface(_layerSurface[layerNum],
_palette,
_tileDataOffset + idx * 0x100,
(j + x) * TILE_WIDTH,
(i + y) * TILE_HEIGHT);
data += 2;
}
}
}
void Background::restoreTiles(uint16 layerNum, int16 x1, int16 y1, int16 w, int16 h) {
int16 tmw = x1 + w;
int16 tmh = y1 + h;
for (int y = y1; y < tmh; y++) {
for (int x = x1; x < tmw; x++) {
uint16 idx = READ_LE_UINT16(&_tileMap[layerNum].map[(y * _tileMap[layerNum].w + x) * 2]) + _tileMap[layerNum].tileIndexOffset;
//debug("tileIdx: %d", idx);
drawTileToSurface(_layerSurface[layerNum], _palette, _tileDataOffset + idx * 0x100, x * TILE_WIDTH, y * TILE_HEIGHT);
}
}
}
void Background::overlayPriorityTileMap(byte *data, int16 x, int16 y, int16 w, int16 h) {
_priorityLayer->overlayTileMap(data, x, y, w, h);
}
void Background::restorePriorityTileMap(int16 x, int16 y, int16 w, int16 h) {
_priorityLayer->restoreTileMap(x, y, w, h);
}
void Background::setPalette(byte *newPalette) {
memcpy(_palette, newPalette, 512);
for (int i = 0; i < 3; i++) {
loadGfxLayer(_layerSurface[i], _tileMap[i], _tileDataOffset);
}
}
void Background::setLayerOffset(uint8 layerNumber, Common::Point offset) {
assert(layerNumber < 4);
_layerOffset[layerNumber] = offset;
}
Common::Point Background::getLayerOffset(uint8 layerNumber) {
assert(layerNumber < 4);
return _layerOffset[layerNumber];
}
AlphaBlendMode Background::getLayerAlphaMode(uint8 layerNumber) {
assert(layerNumber < 4);
return _layerAlphaMode[layerNumber];
}
void Background::setLayerAlphaMode(uint8 layerNumber, AlphaBlendMode mode) {
assert(layerNumber < 4);
_layerAlphaMode[layerNumber] = mode;
}
BackgroundResourceLoader::BackgroundResourceLoader(BigfileArchive *bigFileArchive, DragonRMS *dragonRMS) : _bigFileArchive(
bigFileArchive), _dragonRMS(dragonRMS) {}
Background *BackgroundResourceLoader::load(uint32 sceneId) {
char filename[] = "nnnn.scr";
memcpy(filename, _dragonRMS->getSceneName(sceneId), 4);
return load(filename);
}
Background *BackgroundResourceLoader::load(const char *filename) {
debug(1, "Loading %s", filename);
uint32 size;
byte *scrData = _bigFileArchive->load(filename, size);
Background *bg = new Background();
bg->load(scrData, size);
return bg;
}
void ScaleLayer::load(Common::SeekableReadStream &stream) {
for (int i = 0; i < 32; i++) {
_bands[i]._y = stream.readSint16LE();
_bands[i]._priority = stream.readSint16LE();
}
}
uint16 ScaleLayer::getScale(uint16 y) {
short yBand;
uint uVar1;
short local_v0_368;
// int iVar3;
short lowerYBandIdx;
ScaleBand *pSVar4;
short upperYBandIdx;
uint uVar5;
ScaleBand *pSVar6;
int uVar7;
upperYBandIdx = -1;
for (int16 i = 0x1f; i >= 0; i--) {
yBand = _bands[i]._y;
if (yBand != -1 && yBand <= y) {
upperYBandIdx = i;
break;
}
}
// iVar3 = 0x1f0000;
// do {
// yBand = *(uint16 *)((int)&scaleBandTbl->y + (iVar3 >> 0xe));
// if ((yBand != 0xffff) && (yBand <= y)) break;
// i = i + -1;
// iVar3 = i * 0x10000;
// } while (-1 < i * 0x10000);
lowerYBandIdx = 32;
for (int i = 0; i < 32; i++) {
yBand = _bands[i]._y;
if (yBand != -1 && y <= yBand) {
lowerYBandIdx = i;
break;
}
}
// j = 0;
// iVar3 = 0;
// do {
// lowerYBandIdx = (short)j;
// yBand = *(uint16 *)((int)&scaleBandTbl->y + (iVar3 >> 0xe));
// if ((yBand != 0xffff) && (y <= yBand)) break;
// j = j + 1;
// lowerYBandIdx = (short)j;
// iVar3 = j * 0x10000;
// } while (j * 0x10000 >> 0x10 < 0x20);
if ((upperYBandIdx == -1) && (lowerYBandIdx == 0x20)) {
return 0x100;
}
if (upperYBandIdx < 0 || lowerYBandIdx >= 32) {
if (upperYBandIdx >= 0) {
lowerYBandIdx = upperYBandIdx;
}
upperYBandIdx = lowerYBandIdx;
}
pSVar6 = &_bands[upperYBandIdx]; //scaleBandTbl + (int)upperYBandIdx;
uVar7 = (0x21 - (uint)pSVar6->_priority) * 8;
uVar1 = uVar7;
if (y != pSVar6->_y) {
pSVar4 = &_bands[lowerYBandIdx]; //scaleBandTbl + (int)lowerYBandIdx;
uVar5 = (0x21 - (uint)pSVar4->_priority) * 8;
uVar1 = uVar5;
if ((y != pSVar4->_y) && (uVar1 = uVar7, (int)upperYBandIdx != (int)lowerYBandIdx)) {
local_v0_368 = pSVar4->_y - pSVar6->_y;
uVar1 = uVar5;
if (local_v0_368 != 0) {
uint uVar3 = ((uVar5 & 0xffffu) - (uVar7 & 0xffffu)) * (uint)(uint16)(y - pSVar6->_y);
assert(((uint16)local_v0_368 != 0xffffu) || (uVar3 != 0x80000000u));
return (uVar7 + static_cast<int>(uVar3) / (int)(uint)(uint16)local_v0_368) & 0xffff;
}
}
}
return uVar1 & 0xfff8u;
}
ScaleLayer::ScaleLayer(): _savedBands(nullptr) {
for (int i = 0; i < 32; i++) {
_bands[i]._y = -1;
_bands[i]._priority = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
}
}
ScaleLayer::~ScaleLayer() {
delete _savedBands;
}
void ScaleLayer::backup() {
delete _savedBands;
_savedBands = new ScaleBand[32];
memcpy(_savedBands, _bands, sizeof(_bands));
}
void ScaleLayer::restore() {
assert(_savedBands);
memcpy(_bands, _savedBands, sizeof(_bands));
}
void ScaleLayer::clearAll() {
for (int i = 0; i < 32; i++) {
_bands[i]._y = -1;
}
}
void ScaleLayer::setValue(uint8 index, int16 y, int16 value) {
assert(index < 32);
_bands[index]._y = y;
_bands[index]._priority = value;
}
} // End of namespace Dragons

View File

@@ -0,0 +1,153 @@
/* 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 DRAGONS_BACKGROUND_H
#define DRAGONS_BACKGROUND_H
#include "common/rect.h"
#include "common/system.h"
#include "dragons/bigfile.h"
#include "dragons/dragonrms.h"
#include "dragons/screen.h"
namespace Dragons {
class PriorityLayer;
class Background;
void drawTileToSurface(Graphics::Surface *surface, byte *palette, byte *tile, uint32 x, uint32 y);
class BackgroundResourceLoader {
private:
BigfileArchive *_bigFileArchive;
DragonRMS *_dragonRMS;
public:
BackgroundResourceLoader(BigfileArchive *bigFileArchive, DragonRMS *dragonRMS);
Background *load(uint32 sceneId);
Background *load(const char *filename);
};
typedef struct {
int16 _y;
int16 _priority;
} ScaleBand;
class ScaleLayer {
public:
ScaleLayer();
~ScaleLayer();
void load(Common::SeekableReadStream &stream);
uint16 getScale(uint16 y);
void backup();
void restore();
void clearAll();
void setValue(uint8 index, int16 y, int16 value);
private:
ScaleBand _bands[32];
ScaleBand *_savedBands;
};
struct TileMap {
uint16 w;
uint16 h;
uint32 size;
byte *map;
uint16 tileIndexOffset;
TileMap() {
w = 0;
h = 0;
size = 0;
map = nullptr;
tileIndexOffset = 0;
}
};
class Background {
private:
byte *_data;
byte *_tileDataOffset;
TileMap _tileMap[4];
PriorityLayer *_priorityLayer;
ScaleLayer _scaleLayer;
byte _palette[512];
Graphics::Surface *_layerSurface[3];
Common::Point *_points2;
uint8 _layerPriority[3];
Common::Point _layerOffset[3];
AlphaBlendMode _layerAlphaMode[3];
public:
Background();
~Background();
bool load(byte *dataStart, uint32 size);
uint16 getWidth();
uint16 getHeight();
Graphics::Surface *getBgLayer() { return _layerSurface[0]; }
Graphics::Surface *getMgLayer() { return _layerSurface[1]; }
Graphics::Surface *getFgLayer() { return _layerSurface[2]; }
uint8 getBgLayerPriority() { return _layerPriority[0]; }
uint8 getMgLayerPriority() { return _layerPriority[1]; }
uint8 getFgLayerPriority() { return _layerPriority[2]; }
void setBgLayerPriority(uint8 newPriority) { _layerPriority[0] = newPriority; }
void setMgLayerPriority(uint8 newPriority) { _layerPriority[1] = newPriority; }
void setFgLayerPriority(uint8 newPriority) { _layerPriority[2] = newPriority; }
int16 getPriorityAtPoint(Common::Point pos);
Common::Point getPoint2(uint32 pointIndex);
byte *getPalette() { return _palette; }
void overlayPriorityTileMap(byte *data, int16 x, int16 y, int16 w, int16 h);
void restorePriorityTileMap(int16 x, int16 y, int16 w, int16 h);
void overlayImage(uint16 layerNum, byte *data, int16 x, int16 y, int16 w, int16 h);
void restoreTiles(uint16 layerNum, int16 x, int16 y, int16 w, int16 h);
void setPalette(byte *newPalette);
void setLayerOffset(uint8 layerNumber, Common::Point offset);
Common::Point getLayerOffset(uint8 layerNumber);
ScaleLayer *getScaleLayer() { return &_scaleLayer; }
Dragons::AlphaBlendMode getLayerAlphaMode(uint8 layerNumber);
void setLayerAlphaMode(uint8 layerNumber, Dragons::AlphaBlendMode mode);
private:
Common::Point *loadPoints(Common::SeekableReadStream &stream);
Graphics::Surface *initGfxLayer(TileMap &tileMap);
void loadGfxLayer(Graphics::Surface *surface, TileMap &tileMap, byte *tiles);
};
class PriorityLayer {
public:
void load(TileMap &tileMap, byte *tiles);
int16 getPriority(Common::Point pos);
void overlayTileMap(byte *data, int16 x, int16 y, int16 w, int16 h);
void restoreTileMap(int16 x, int16 y, int16 w, int16 h);
protected:
int16 _width, _height;
int16 _mapWidth, _mapHeight;
byte *_map, *_values;
byte *_mapBase;
};
} // End of namespace Dragons
#endif //DRAGONS_BACKGROUND_H

100
engines/dragons/bag.cpp Normal file
View File

@@ -0,0 +1,100 @@
/* 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 "dragons/bigfile.h"
#include "dragons/screen.h"
#include "dragons/bag.h"
#include "dragons/background.h"
namespace Dragons {
#define TILEMAP_WIDTH 10
#define TILEMAP_HEIGHT 25
Bag::Bag(BigfileArchive *bigFileArchive, Screen *screen): _screen(screen) {
_surface = nullptr;
_position.x = 0;
_position.y = 0;
load(bigFileArchive);
}
Bag::~Bag() {
_surface->free();
delete _surface;
}
void Bag::updatePosition(Common::Point newPos) {
_position = newPos;
}
void Bag::draw() {
_screen->copyRectToSurface(*_surface, _position.x, _position.y, Common::Rect(_surface->w, _surface->h));
}
void Bag::load(BigfileArchive *bigFileArchive) {
byte pal[512];
byte tilemap[0x1f4];
byte *tiles;
uint32 size;
byte *scrData = bigFileArchive->load("bag.scr", size);
Common::MemoryReadStream stream(scrData, size, DisposeAfterUse::YES);
stream.seek(0x4);
stream.read(pal, 512);
pal[0] = 0x0;
pal[1] = 0x0;
for (int i = 1; i < 0x100; i++) {
uint c = READ_LE_INT16(&pal[i * 2]);
if (c == 0) {
c = 0x8000;
} else {
//c = (uint16)(((uint)c & 0x1f) << 10) | (uint16)(((uint)c & 0x7c00) >> 10) | c & 0x3e0;
}
WRITE_SCREEN(&pal[i * 2], c);
}
stream.seek(0x308);
stream.read(tilemap, 0x1f4);
stream.seek(0xadc);
size = stream.readUint32LE();
tiles = (byte *)malloc(size);
stream.read(tiles, size);
_surface = new Graphics::Surface();
Graphics::PixelFormat pixelFormat16(2, 5, 5, 5, 1, 10, 5, 0, 15); //TODO move this to a better location.
_surface->create(320, 200, pixelFormat16);
for (int y = 0; y < TILEMAP_HEIGHT; y++) {
for (int x = 0; x < TILEMAP_WIDTH; x++) {
uint16 idx = READ_LE_UINT16(&tilemap[(y * TILEMAP_WIDTH + x) * 2]);
//debug("tileIdx: %d", idx);
drawTileToSurface(_surface, pal, tiles + idx * 0x100, x * 32, y * 8);
}
}
free(tiles);
}
} // End of namespace Dragons

52
engines/dragons/bag.h Normal file
View File

@@ -0,0 +1,52 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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 DRAGONS_BAG_H
#define DRAGONS_BAG_H
#include "graphics/surface.h"
#include "common/rect.h"
namespace Dragons {
class BigfileArchive;
class Screen;
class Bag {
private:
Screen *_screen;
Graphics::Surface *_surface;
Common::Point _position;
public:
Bag(BigfileArchive *bigFileArchive, Screen *screen);
~Bag();
void updatePosition(Common::Point newPos);
void draw();
Common::Point getPosition() { return _position; }
private:
void load(BigfileArchive *bigFileArchive);
};
} // End of namespace Dragons
#endif //DRAGONS_BAG_H

View File

@@ -0,0 +1,94 @@
/* 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 "dragons/bigfile.h"
#include "dragons/dragons.h"
namespace Dragons {
uint32 BigfileArchive::getResourceId(const char *filename) {
for (uint32 i = 0; i < _totalRecords; i++) {
if (scumm_stricmp(_fileInfoTbl[i].filename.c_str(), filename) == 0) {
return i;
}
}
return _totalRecords;
}
BigfileArchive::BigfileArchive(DragonsEngine *vm, const char *filename) :_vm(vm), _fd(nullptr) {
_fd = new Common::File();
if (!_fd->open(filename)) {
error("BigfileArchive::BigfileArchive() Could not open %s", filename);
}
_totalRecords = _vm->getBigFileTotalRecords();
_fileInfoTbl.resize(_totalRecords);
loadFileInfoTbl();
}
BigfileArchive::~BigfileArchive() {
_fd->close();
delete _fd;
}
void BigfileArchive::loadFileInfoTbl() {
char filename[16];
Common::File fd;
if (!fd.open("dragon.exe")) {
error("Failed to open dragon.exe");
}
fd.seek(_vm->getBigFileInfoTblFromDragonEXE());
for (int i = 0; i < _totalRecords; i++) {
fd.read(filename, 16);
filename[15] = 0;
_fileInfoTbl[i].filename = filename;
_fileInfoTbl[i].offset = fd.readUint32LE() * 2048;
_fileInfoTbl[i].size = fd.readUint32LE();
fd.skip(4);
}
}
byte *BigfileArchive::load(const char *filename, uint32 &dataSize) {
uint32 id = getResourceId(filename);
if (id >= _totalRecords) {
error("Invalid resourceID for input filename: %s", filename);
}
dataSize = _fileInfoTbl[id].size;
_fd->seek(_fileInfoTbl[id].offset);
byte *buf = (byte *)malloc(dataSize);
if (!buf) {
error("Failed to malloc %d bytes for '%s'", dataSize, filename);
}
_fd->read(buf, dataSize);
return buf;
}
bool BigfileArchive::doesFileExist(const char *filename) {
uint32 id = getResourceId(filename);
return (id < _totalRecords);
}
} // End of namespace Dragons

63
engines/dragons/bigfile.h Normal file
View File

@@ -0,0 +1,63 @@
/* 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 DRAGONS_BIGFILE_H
#define DRAGONS_BIGFILE_H
#include "common/array.h"
#include "common/file.h"
namespace Dragons {
class DragonsEngine;
struct FileInfo {
Common::String filename;
uint32 offset;
uint32 size;
FileInfo() {
offset = 0;
size = 0;
filename = "";
}
};
class BigfileArchive {
private:
DragonsEngine *_vm;
Common::File *_fd;
uint16 _totalRecords;
Common::Array<FileInfo> _fileInfoTbl;
public:
BigfileArchive(DragonsEngine *vm, const char *filename);
virtual ~BigfileArchive();
byte *load(const char *filename, uint32 &dataSize);
bool doesFileExist(const char *filename);
private:
void loadFileInfoTbl();
uint32 getResourceId(const char *filename);
};
} // End of namespace dragons
#endif //DRAGONS_BIGFILE_H

View 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 dragons "Blazing Dragons" yes "" "" "16bit vgmtrans_audio" ""

117
engines/dragons/credits.cpp Normal file
View File

@@ -0,0 +1,117 @@
/* 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 "dragons/credits.h"
#include "dragons/bigfile.h"
#include "dragons/dragons.h"
#include "dragons/screen.h"
#include "dragons/font.h"
namespace Dragons {
void creditsUpdateFunction() {
getEngine()->_credits->update();
}
Credits::Credits(DragonsEngine *vm, FontManager *fontManager, BigfileArchive *bigfileArchive) : _vm(vm),
_fontManager(fontManager), _bigfileArchive(bigfileArchive), _surface(nullptr), _curPtr(nullptr) {
_running = false;
_updateCounter = 0;
_yOffset = 0;
_linesRemaining = 0x1a;
_creditsData = nullptr;
_dataLength = 0;
_curPosition = 0;
}
void Credits::start() {
_surface = new Graphics::Surface();
_surface->create(320, 208, Graphics::PixelFormat::createFormatCLUT8());
_updateCounter = 0x78;
_curPosition = 0;
_creditsData = _bigfileArchive->load("credits.txt", _dataLength);
_curPtr = (char *)_creditsData;
assert(_creditsData);
_vm->setVsyncUpdateFunction(creditsUpdateFunction);
_running = true;
}
bool Credits::isRunning() {
return _running;
}
void Credits::draw() {
if (_running) {
_vm->_screen->copyRectToSurface8bppWrappedY(*_surface, _vm->_screen->getPalette(2), _yOffset);
}
}
void Credits::cleanup() {
_vm->setVsyncUpdateFunction(nullptr);
_surface->free();
delete _surface;
}
void Credits::update() {
uint16 line[41];
if (_updateCounter == 0) {
_updateCounter = 2;
_yOffset = (_yOffset + 1) % 208;
if (_yOffset % 8 == 0) {
if (_curPosition < _dataLength) {
uint32 length = strlen(_curPtr);
debug(3, "Credit line: %s", _curPtr);
convertToWideChar(line, (byte *)_curPtr, 40);
_curPtr += length + 1;
_curPosition += length + 1;
} else {
if (_linesRemaining) {
_linesRemaining--;
}
convertToWideChar(line, (const byte *)" ", 40);
}
_fontManager->_fonts[0]->renderToSurface(_surface, 0, (_yOffset + 200) % 208, line, 40);
}
} else {
_updateCounter--;
}
if (_linesRemaining == 0) {
_running = false;
cleanup();
}
}
void Credits::convertToWideChar(uint16 *destBuf, const byte *text, uint16 maxLength) {
bool finished = false;
for (int i = 0; i < maxLength; i++) {
if (text[i] == 0) {
finished = true;
}
destBuf[i] = !finished ? text[i] : ' ';
}
}
} // End of namespace Dragons

62
engines/dragons/credits.h Normal file
View File

@@ -0,0 +1,62 @@
/* 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 DRAGONS_CREDITS_H
#define DRAGONS_CREDITS_H
#include "graphics/surface.h"
#include "graphics/pixelformat.h"
namespace Dragons {
class BigfileArchive;
class DragonsEngine;
class FontManager;
class Credits {
private:
DragonsEngine *_vm;
FontManager *_fontManager;
BigfileArchive *_bigfileArchive;
Graphics::Surface *_surface;
bool _running;
int16 _yOffset;
int16 _linesRemaining;
int16 _updateCounter;
byte *_creditsData;
char *_curPtr;
uint32 _dataLength;
uint32 _curPosition;
public:
Credits(DragonsEngine *vm, FontManager *fontManager, BigfileArchive *bigfileArchive);
void start();
bool isRunning();
void draw();
void update();
private:
void cleanup();
void convertToWideChar(uint16 *destBuf, const byte *text, uint16 maxLength);
};
} // End of namespace Dragons
#endif //DRAGONS_CREDITS_H

View File

@@ -0,0 +1,5 @@
begin_section("Dragons");
add_person("Eric Fry", "yuv422", "");
add_person("Benjamin Haisch", "john_doe", "Actor pathfinding");
add_person("&Aacute;ngel Eduardo Garc&iacute;a Hern&aacute;ndez", "arcnor", "Help with reverse engineering");
end_section();

356
engines/dragons/cursor.cpp Normal file
View File

@@ -0,0 +1,356 @@
/* 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 "dragons/cursor.h"
#include "dragons/actor.h"
#include "dragons/actorresource.h"
#include "dragons/dragons.h"
#include "dragons/dragonimg.h"
#include "dragons/dragonini.h"
#include "dragons/dragonobd.h"
#include "dragons/inventory.h"
#include "dragons/scene.h"
#include "dragons/scriptopcodes.h"
#include "dragons/screen.h"
namespace Dragons {
Cursor::Cursor(DragonsEngine *vm): _vm(vm), _actor(nullptr), _x(0), _y(0) {
_sequenceID = 0;
_data_800728b0_cursor_seqID = 0;
_iniUnderCursor = 0;
_performActionTargetINI = 0;
_objectInHandSequenceID = 0;
_cursorActivationSeqOffset = 0;
_iniItemInHand = 0;
_handPointerSequenceID = _vm->getCursorHandPointerSequenceID();
}
void Cursor::init(ActorManager *actorManager, DragonINIResource *dragonINIResource) {
_sequenceID = 0;
_actor = actorManager->loadActor(0, 0); //Load cursor
_actor->_x_pos = _x = 160;
_actor->_y_pos = _y = 100;
_actor->_priorityLayer = 6;
_actor->_flags = 0;
_actor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
_actor->updateSequence(_sequenceID);
_actor->_flags |= (ACTOR_FLAG_40 | Dragons::ACTOR_FLAG_80 | Dragons::ACTOR_FLAG_100 |
ACTOR_FLAG_200);
dragonINIResource->getFlickerRecord()->actor = _actor; //TODO is this correct?
dragonINIResource->getFlickerRecord()->flags |= INI_FLAG_1;
_iniUnderCursor = 0;
_iniItemInHand = 0;
_objectInHandSequenceID = 0;
_cursorActivationSeqOffset = 0;
_data_800728b0_cursor_seqID = 0;
_performActionTargetINI = 0;
}
void Cursor::update() {
if (!_vm->isFlagSet(ENGINE_FLAG_8) || _vm->isFlagSet(Dragons::ENGINE_FLAG_100)) {
return;
}
// TODO update cursor from inputs here.
// 0x800280b8
if (_sequenceID == 0 && _vm->_inventory->isOpen()) {
_sequenceID = 1;
}
_actor->_x_pos = _x;
_actor->_y_pos = _y;
// 0x80028104
if (_iniUnderCursor != 0
&& ((_iniUnderCursor & 0x8000 && _vm->_inventory->isOpen())
||(!(_iniUnderCursor & 0x8000) && _vm->getINI(_iniUnderCursor - 1)->flags & 0x80))) {
if (_actor->_sequenceID != _handPointerSequenceID) {
_actor->updateSequence(_handPointerSequenceID);
}
return;
}
int32 inventorySequenceID = _vm->_inventory->getSequenceId();
if ((_iniUnderCursor == 0x8001) && (inventorySequenceID == 1)) {
if (_actor->_sequenceID != _handPointerSequenceID) {
_actor->updateSequence(_handPointerSequenceID);
}
return;
}
if (_iniUnderCursor == 0x8002 && inventorySequenceID == 4) {//goto LAB_80028204;
if (_actor->_sequenceID != _handPointerSequenceID) {
_actor->updateSequence(_handPointerSequenceID);
}
return;
}
if (_iniUnderCursor != 0x8002 || (inventorySequenceID != 1 && inventorySequenceID != 3)) {
if ((_iniUnderCursor != 0x8001) || ((inventorySequenceID != 0 && (inventorySequenceID != 3)))) {
if (_sequenceID == 5) {
uint16 uVar1 = (uint) _objectInHandSequenceID;
if (_cursorActivationSeqOffset != 0) {
uVar1 = uVar1 + 1;
}
if (uVar1 == (uint) _actor->_sequenceID) {
return;
}
_actor->updateSequence((uint) _objectInHandSequenceID + (uint) (_cursorActivationSeqOffset != 0));
} else {
if (_sequenceID + (uint) _cursorActivationSeqOffset != (uint) _actor->_sequenceID) {
_actor->updateSequence(_sequenceID + (uint) _cursorActivationSeqOffset);
}
}
return;
}
}
if (_iniItemInHand == 0) {
if (_actor->_sequenceID != _handPointerSequenceID) {
_actor->updateSequence(_handPointerSequenceID);
}
return;
} else {
if ((uint)_actor->_sequenceID != (uint)_objectInHandSequenceID + 1) {
_actor->updateSequence((uint)_objectInHandSequenceID + 1);
}
}
// 0x_800281c0
}
void Cursor::updateVisibility() {
if (_vm->isFlagSet(ENGINE_FLAG_8) && !_vm->isUnkFlagSet(Dragons::ENGINE_UNK1_FLAG_10)) {
_actor->_priorityLayer = 9;
} else {
_actor->_priorityLayer = 0;
}
}
void Cursor::updatePosition(int16 x, int16 y) {
_x = x;
_y = y;
}
int16 Cursor::updateINIUnderCursor() {
if (_vm->isFlagSet(ENGINE_FLAG_10)) {
int16 xOffset = 0;
if (_vm->_inventory->getSequenceId() == 0 || _vm->_inventory->getSequenceId() == 2) {
if (_vm->_inventory->getPositionIndex() == 1 || _vm->_inventory->getPositionIndex() == 3) {
xOffset = 0x32;
}
}
Common::Point inventoryPosition = _vm->_inventory->getPosition();
if (_x >= inventoryPosition.x + 0xa + xOffset
&& _x < inventoryPosition.x + 0x35 + xOffset
&& _y >= inventoryPosition.y + 0xa
&& _y < inventoryPosition.y + 0x25) {
_iniUnderCursor = 0x8001;
return _iniUnderCursor;
}
if (_x >= inventoryPosition.x + 0x36
&& _x < inventoryPosition.x + 0x5f
&& _y >= inventoryPosition.y + 0xa
&& _y < inventoryPosition.y + 0x25
&& _vm->_inventory->getPositionIndex() != 0
&& _vm->_inventory->getPositionIndex() != 2) {
_iniUnderCursor = 0x8002;
return _iniUnderCursor;
}
}
// TODO 0x80028940
if (_vm->_inventory->getState() == InventoryOpen) {
_iniUnderCursor = _vm->_inventory->getIniAtPosition(_x, _y);
return _iniUnderCursor;
}
return updateIniFromScene();
}
int16 Cursor::updateIniFromScene() {
int16 cursorX = _x + _vm->_scene->_camera.x;
int16 cursorY = _y + _vm->_scene->_camera.y;
int16 cursorTileX = cursorX / 32;
int16 cursorTileY = cursorY / 8;
int16 data_80072890_orig = _performActionTargetINI;
int16 data_800728b0_cursor_seqID_orig = _data_800728b0_cursor_seqID;
for (int i = 0; i <_vm->_dragonINIResource->totalRecords(); i++) {
DragonINI *ini = _vm->_dragonINIResource->getRecord(i);
if (ini->sceneId != _vm->_scene->getSceneId()) {
// 0x80028be4
} else if (!_vm->_dragonINIResource->isFlicker(ini) && !(ini->flags & 0x40)) {
int16 cursorOverIni = 0;
// 0x80028a10
if (ini->flags & 1) {
// 0x80028b18
if (ini->actor->isFlagSet(ACTOR_FLAG_40) && ini->actor->isFlagSet(ACTOR_FLAG_8)) {
int16 iniActorXPosition = ini->actor->_x_pos - ini->actor->_frame->xOffset;
int16 iniActorYPosition = ini->actor->_y_pos - ini->actor->_frame->yOffset;
if (cursorX >= iniActorXPosition && cursorX < iniActorXPosition + ini->actor->_frame->width
&& cursorY >= iniActorYPosition && cursorY < iniActorYPosition + ini->actor->_frame->height) {
cursorOverIni = i + 1;
}
}
} else {
// 0x80028a24
if (ini->imgId != -1) {
Img *img = _vm->_dragonImg->getImg((uint32)ini->imgId);
if (img->field_e - 1 >= 1) { // TODO this is >= 2 in the original.
if (cursorTileX >= img->x && cursorTileX < img->x + img->w && cursorTileY >= img->y && cursorTileY < img->y + img->h) {
cursorOverIni = i + 1;
}
} else {
// 0x80028ac4
if (cursorX >= img->x && cursorX < img->x + img->w && cursorY >= img->y && cursorY < img->y + img->h) {
cursorOverIni = i + 1;
}
}
}
}
if (cursorOverIni != 0) {
// 0x80028bf0
// _iniUnderCursor = cursorOverIni;
_performActionTargetINI = _iniUnderCursor;
_data_800728b0_cursor_seqID = _sequenceID;
if (ini->flags & 0x800) {
_performActionTargetINI = cursorOverIni;
uint32 newSeqId = 1;
for (int idx = 0; idx < 5; idx++) {
_data_800728b0_cursor_seqID = idx;
byte *obd = _vm->_dragonOBD->getFromOpt(cursorOverIni - 1); //_dragonRMS->getAfterSceneLoadedScript(sceneId);
ScriptOpCall scriptOpCall(obd + 8, READ_LE_UINT32(obd));
// uVar17 = uVar15;
// local_58 = dragon_Obd_Offset + *(int *)(uVar16 * 8 + dragon_Opt_Offset + -8) + 8;
// data_800728b0 = idx;
// local_54 = read_int32();
// local_54 = local_54 + local_58;
// uVar6 = ;
if (executeScript(scriptOpCall, 0)) {
newSeqId = idx;
break;
}
}
_sequenceID = newSeqId;
_iniUnderCursor = cursorOverIni;
_performActionTargetINI = _iniUnderCursor;
_data_800728b0_cursor_seqID = _sequenceID;
return _iniUnderCursor;
}
if (_sequenceID != 0) {
_iniUnderCursor = cursorOverIni;
_performActionTargetINI = data_80072890_orig;
_data_800728b0_cursor_seqID = data_800728b0_cursor_seqID_orig;
return _iniUnderCursor;
}
byte *obd = _vm->_dragonOBD->getFromOpt(cursorOverIni - 1); //_dragonRMS->getAfterSceneLoadedScript(sceneId);
ScriptOpCall scriptOpCall(obd + 8, READ_LE_UINT32(obd));
// local_48 = dragon_Obd_Offset + *(int *)(uVar16 * 8 + dragon_Opt_Offset + -8) + 8;
// local_44 = read_int32();
// local_44 = local_44 + local_48;
if (executeScript(scriptOpCall, 0)) {
_iniUnderCursor = cursorOverIni;
_performActionTargetINI = data_80072890_orig;
_data_800728b0_cursor_seqID = data_800728b0_cursor_seqID_orig;
return _iniUnderCursor;
}
}
}
}
_iniUnderCursor = 0;
_performActionTargetINI = data_80072890_orig;
_data_800728b0_cursor_seqID = data_800728b0_cursor_seqID_orig;
return 0;
}
int16 Cursor::executeScript(ScriptOpCall &scriptOpCall, uint16 unkFlag) {
int16 temp = _vm->_scriptOpcodes->_scriptTargetINI;
byte *codeStart = scriptOpCall._code;
scriptOpCall._field8 = 1;
scriptOpCall._result = 0;
_vm->_scriptOpcodes->_numDialogStackFramesToPop = 0;
_vm->_scriptOpcodes->executeScriptLoop(scriptOpCall);
if (!(scriptOpCall._result & 1) && _data_800728b0_cursor_seqID == 5 && unkFlag != 0) {
_vm->_scriptOpcodes->_scriptTargetINI = -1;
scriptOpCall._code = codeStart;
scriptOpCall._field8 = 1;
scriptOpCall._result = 0;
_vm->_scriptOpcodes->_numDialogStackFramesToPop = 0;
_vm->_scriptOpcodes->executeScriptLoop(scriptOpCall);
_vm->_scriptOpcodes->_scriptTargetINI = temp;
if (scriptOpCall._result & 1) {
scriptOpCall._result |= 2;
}
}
return scriptOpCall._result & 3;
}
void Cursor::selectPreviousCursor() {
int16 newSequenceID = _sequenceID - 1;
InventoryState inventoryType = _vm->_inventory->getState();
if (newSequenceID == 0 && (inventoryType == InventoryOpen || inventoryType == InventionBookOpen)) {
newSequenceID = _sequenceID - 2;
}
_sequenceID = newSequenceID;
if (_sequenceID == 3 && inventoryType == InventoryOpen) {
_sequenceID = 1;
}
if (_sequenceID == 2) {
_sequenceID = 1;
}
if (_sequenceID == -1) {
_sequenceID = _iniItemInHand == 0 ? 4 : 5;
}
}
void Cursor::updateSequenceID(int16 sequenceID) {
_sequenceID = sequenceID;
_actor->updateSequence(_sequenceID);
}
void Cursor::setActorFlag400() {
_actor->setFlag(ACTOR_FLAG_400);
}
void Cursor::clearActorFlag400() {
_actor->clearFlag(ACTOR_FLAG_400);
}
byte *Cursor::getPalette() {
return _actor->_actorResource->getPalette();
}
void Cursor::updateActorPosition(int16 x, int16 y) {
updatePosition(x, y);
_actor->_x_pos = _x;
_actor->_y_pos = _y;
}
} // End of namespace Dragons

72
engines/dragons/cursor.h Normal file
View File

@@ -0,0 +1,72 @@
/* 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 DRAGONS_CURSOR_H
#define DRAGONS_CURSOR_H
#include "dragons/scriptopcodes.h"
namespace Dragons {
class Actor;
class ActorManager;
class DragonsEngine;
class DragonINIResource;
class Cursor {
public:
int16 _data_800728b0_cursor_seqID;
uint16 _iniUnderCursor;
int32 _sequenceID;
int16 _performActionTargetINI;
int16 _x;
int16 _y;
int16 _objectInHandSequenceID;
int16 _cursorActivationSeqOffset;
uint16 _iniItemInHand;
uint16 _handPointerSequenceID;
private:
DragonsEngine *_vm;
Actor *_actor;
public:
Cursor(DragonsEngine *vm);
void init(ActorManager *actorManager, DragonINIResource *dragonINIResource);
void update();
void updateSequenceID(int16 sequenceID);
void updateVisibility();
void updatePosition(int16 x, int16 y);
void updateActorPosition(int16 x, int16 y);
int16 updateINIUnderCursor();
int16 executeScript(ScriptOpCall &scriptOpCall, uint16 unkFlag);
void selectPreviousCursor();
void selectNextCursor();
void setActorFlag400();
void clearActorFlag400();
byte *getPalette();
private:
int16 updateIniFromScene();
};
} // End of namespace Dragons
#endif //DRAGONS_CURSOR_H

View File

@@ -0,0 +1,968 @@
/* 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 "dragons/cutscene.h"
#include "dragons/dragons.h"
#include "dragons/actor.h"
#include "dragons/actorresource.h"
#include "dragons/background.h"
#include "dragons/inventory.h"
#include "dragons/cursor.h"
#include "dragons/dragonini.h"
#include "dragons/scene.h"
#include "dragons/screen.h"
#include "dragons/talk.h"
namespace Dragons {
CutScene::CutScene(DragonsEngine *vm): _vm(vm) {
loadPalettes();
}
CutScene::~CutScene() {
if (_palettes) {
free(_palettes);
}
}
void CutScene::scene1() {
// TODO spcLoadScene1 knights around the table.
bool isFlag10Set = _vm->isFlagSet(ENGINE_FLAG_10);
DragonINI *flicker = _vm->_dragonINIResource->getFlickerRecord();
_actor_80063514 = 0xb00;
_vm->_dragonINIResource->setFlickerRecord(nullptr);
_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
_vm->fadeToBlack();
_vm->clearFlags(ENGINE_FLAG_10);
_vm->_inventory->setActorFlag400();
_vm->_cursor->setActorFlag400();
// scr_tilemap1_w = 0x28;
// _actor_8006a3f0 = _actor_8006a3ec;
// load_actor_file(0x81);
// load_actor_file(0x7d);
// load_actor_file(0x7e);
// load_actor_file(0x8f);
// load_actor_file(0xaa);
_vm->setFlags(ENGINE_FLAG_20000);
wideAngleEveryoneAtTable();
_vm->waitForFrames(0x5a);
closeUpShotOnActor(0xd3, 0, 0x233, 0x17a); //close up on king
//playSoundFromTxtIndex(0x4e26);
while (1) { // In order to avoid gotos
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 4, 0, 0x4e26, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd8, 0, 0xfd, 0x60); // cut to flicker
//playSoundFromTxtIndex(0x4ea2);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 2, 0, 0x4ea2, 0x701) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd3, 0, 0x233, 0x17a); //close up on king
//playSoundFromTxtIndex(0x4eec);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 5, 0, 0x4eec, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
wideAngleEveryoneAtTable(); // shot of whole room
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 4, 0, 0x5000, 0x2e01) == 2 ||
_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_800830c0, 0x1d, 0x1c, 0x5074, 0x501) == 2 ||
_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072df0, 9, 5, 0x511c, 0xc01) == 2 ||
_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_800830c0, 0x1d, 0x1c, 0x5138, 0x501) == 2)
break;
closeUpShotOnActor(0xd7, 0, 0x312, 0x260); //close up on flame
//playSoundFromTxtIndex(0x5152);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 2, 0, 0x5152, 0x3e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd8, 0, 0xfd, 0x60); //close up flicker
//playSoundFromTxtIndex(0x51fc);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 3, 0, 0x51fc, 0x701) == 2)
break;
_vm->playOrStopSound(0x8004);
_vm->waitForFrames(0x28);
_vm->playOrStopSound(0x8003);
fadeScreenAndResetActor(_actor_80072de8);
_actor_80063514 = _actor_80063514 | 0x40;
fun_8003d8e8(0xd6, 0, 0x37a, 0x280);
_actor_80072dec = _vm->_actorManager->loadActor(0xd5, 0, 0x2d6, 0xc6, 3); //load humans
_actor_80072df0 = _vm->_actorManager->loadActor(0xd3, 2, 0x87, 199, 3);
_vm->waitForFramesAllowSkip(4);
_vm->fadeFromBlack();
if (fun_8003dab8(0x52d6, 0, 0, 0x701, 1) == 2)
break;
_vm->clearAllText();
//playSoundFromTxtIndex(0x530c);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 2, 0, 0x530c, 0x3c01) == 2)
break;
while (0x10 < _vm->_scene->_camera.x) {
_vm->_scene->_camera.x = _vm->_scene->_camera.x + -0x10;
_vm->waitForFrames(1);
}
_vm->_scene->_camera.x = 0;
//playSoundFromTxtIndex(0x54dc);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072df0, 6, 2, 0x54dc, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
fadeScreenAndResetActor(_actor_80072dec);
fadeScreenAndResetActor(_actor_80072df0);
wideAngleEveryoneAtTable();
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072e08, 3, 2, 0x55d4, 0xc01) == 2)
break;
closeUpShotOnActor(0xd4, 0, 0x8a, 0); //close up chancellor
//playSoundFromTxtIndex(0x562c);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 2, 0, 0x562c, 0xc01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
fun_8003d8e8(0xd6, 0, 0x37a, 0x280);
_actor_80072dec = _vm->_actorManager->loadActor(0xd5, 4, 0x2d6, 0xc6, 3);
_vm->waitForFramesAllowSkip(4);
_vm->fadeFromBlack();
if (fun_8003dab8(0x5780, 0x14, 0, 0xc01, 1) == 2)
break;
_actor_80063514 = _actor_80063514 | 0x40;
fadeScreenAndResetActor(_actor_80072de8);
fadeScreenAndResetActor(_actor_80072dec);
closeUpShotOnActor(0xd7, 0, 0x312, 0x260); // close up flame
//playSoundFromTxtIndex(0x581c);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 3, 0, 0x581c, 0x3e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd4, 0, 0x8a, 0); //close up chancellor
//playSoundFromTxtIndex(0x5942);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 4, 0, 0x5942, 0xc01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd3, 2, 0x87, 0); // close up king
//playSoundFromTxtIndex(0x5aaa);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 7, 2, 0x5aaa, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
fun_8003d8e8(0xd6, 0, 0x37a, 0x280);
_actor_80072dec = _vm->_actorManager->loadActor(0xd5, 0, 0x2d6, 0xc6, 3);
_vm->waitForFramesAllowSkip(4);
_vm->fadeFromBlack();
//playSoundFromTxtIndex(0x5afc);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 3, 0, 0x5afc, 0x3c01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
fadeScreenAndResetActor(_actor_80072dec);
_actor_80063514 = _actor_80063514 & 0xffbf;
closeUpKnightsAtTable(); // close up of knights at table.
_vm->playOrStopSound(0x8003);
//playSoundFromTxtIndex(0x5b96);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 8, 4, 0x5b96, 0xc01) == 2)
break;
//playSoundFromTxtIndex(0x5c4a);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 2, 0, 0x5c4a, 0x2e01) == 2)
break;
//playSoundFromTxtIndex(0x5dc8);
_actor_80072df0->updateSequence(0xf);
_actor_80072df4->updateSequence(0xd);
_actor_80072df8->updateSequence(0xe);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 0xc, 4, 0x5dc8, 0xc01) == 2)
break;
_actor_80072df0->updateSequence(6);
_actor_80072df4->updateSequence(0);
_actor_80072df8->updateSequence(2);
fun_8003d8e8(0xd3, 2, 0x28d, 0x250);
_actor_80072dec = _vm->_actorManager->loadActor(0xd7, 0, 0x348, 199, 3);
_vm->waitForFramesAllowSkip(4); // close up of king and flame
_vm->fadeFromBlack();
//playSoundFromTxtIndex(0x5ef2);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 4, 0, 0x5ef2, 0x3e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
fadeScreenAndResetActor(_actor_80072dec);
closeUpShotOnActor(0xd3, 0, 0x233, 0x17a); // close up of king
//playSoundFromTxtIndex(0x6000);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 8, 0, 0x6000, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpKnightsAtTable(); // close up knights at table
//playSoundFromTxtIndex(0x7dcc);
_actor_80072df0->updateSequence(0x13);
_actor_80072df4->updateSequence(0x10);
_actor_80072df8->updateSequence(0x11);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 0x12, 6, 0x7dcc, 0xc01) == 2)
break;
wideAngleEveryoneAtTable(); //whole room shot
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 0x17, 0x16, 0x60ee, 0x701) == 2)
break;
closeUpKnightsAtTable();
_actor_80072df0->updateSequence(6);
_actor_80072df4->updateSequence(0);
_actor_80072df8->updateSequence(2);
_actor_80072dec->updateSequence(4);
//playSoundFromTxtIndex(0x5de8);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072df8, 0xb, 2, 0x5de8, 0xc01) == 2)
break;
wideAngleEveryoneAtTable();
_vm->playOrStopSound(1);
_actor_80072df0->updateSequence(8);
_actor_80072df4->updateSequence(0xd);
_actor_80072df8->updateSequence(0x11);
_actor_80072dfc->updateSequence(0x15);
_actor_80072df0->waitUntilFlag8And4AreSet();
_actor_80072df4->waitUntilFlag8And4AreSet();
_actor_80072df8->waitUntilFlag8And4AreSet();
_actor_80072dfc->waitUntilFlag8And4AreSet();
// DisableVSyncEvent();
// TODO load_actor_file(0x82);
// EnableVSyncEvent();
_vm->waitForFramesAllowSkip(0x3b);
_vm->clearFlags(ENGINE_FLAG_20000);
_vm->fadeToBlack();
// DisableVSyncEvent();
_vm->_scene->getScaleLayer()->clearAll();
_vm->_scene->getScaleLayer()->setValue(0, 0, 17);
_vm->_scene->getScaleLayer()->setValue(1, 199, 1);
// EnableVSyncEvent();
changeBackgroundPosition(2, 0);
_vm->_actorManager->clearActorFlags(2);
_actor_80072de8 = _vm->_actorManager->loadActor(0x82, 0, 0x60, 0x114, 1);
_actor_80072dec = _vm->_actorManager->loadActor(0x82, 2, 0x91, 0x113, 1);
_actor_80072df0 = _vm->_actorManager->loadActor(0x82, 1, 0xd0, 199, 1);
_actor_80072df4 = _vm->_actorManager->loadActor(0x82, 3, 0xb6, 0x113, 1);
_actor_80072df8 = _vm->_actorManager->loadActor(0x82, 4, 0x98, 0x40, 1);
_actor_80072de8->setFlag(ACTOR_FLAG_100);
_actor_80072de8->setFlag(ACTOR_FLAG_800);
_actor_80072de8->setFlag(ACTOR_FLAG_8000);
_actor_80072de8->_walkSpeed = 0x20000;
_actor_80072de8->_priorityLayer = 3;
_actor_80072dec->setFlag(ACTOR_FLAG_100);
_actor_80072dec->setFlag(ACTOR_FLAG_800);
_actor_80072dec->setFlag(ACTOR_FLAG_8000);
_actor_80072dec->_walkSpeed = 0x18000;
_actor_80072dec->_priorityLayer = 3;
_actor_80072df0->setFlag(ACTOR_FLAG_100);
_actor_80072df0->setFlag(ACTOR_FLAG_800);
_actor_80072df0->setFlag(ACTOR_FLAG_8000);
_actor_80072df0->_walkSpeed = 0x14000;
_actor_80072df0->_priorityLayer = 3;
_actor_80072df4->setFlag(ACTOR_FLAG_100);
_actor_80072df4->setFlag(ACTOR_FLAG_800);
_actor_80072df4->setFlag(ACTOR_FLAG_8000);
_actor_80072df4->_walkSpeed = 0x1c000;
_actor_80072df4->_priorityLayer = 3;
_actor_80072df8->setFlag(ACTOR_FLAG_80);
_actor_80072df8->setFlag(ACTOR_FLAG_100);
_actor_80072df8->setFlag(ACTOR_FLAG_800);
_actor_80072df8->setFlag(ACTOR_FLAG_8000);
_actor_80072df8->_priorityLayer = 3;
_vm->waitForFramesAllowSkip(0xe);
_vm->fadeFromBlack();
_actor_80072df0->startWalk(0xe8, 0xa8, 2);
_actor_80072df0->waitForWalkToFinish();
_actor_80072de8->startWalk(0x97, 0x37, 2);
_actor_80072dec->startWalk(0x97, 0x37, 2);
_actor_80072df4->startWalk(0x97, 0x37, 2);
_actor_80072df0->waitUntilFlag8SetThenSet1000AndWaitFor4();
_actor_80072df0->updateSequence(6);
uint16 dialog[2000];
dialog[0] = 0;
_vm->_talk->loadText(_vm->getDialogTextId(0x5ea2), dialog, 2000);
_vm->_talk->displayDialogAroundPoint(dialog, 0x27, 0xc, 0xc01, 0, _vm->getDialogTextId(0x5ea2));
_actor_80072df0->waitUntilFlag8And4AreSet();
_actor_80072df0->_x_pos = 0xcf;
_actor_80072df0->_y_pos = 0x90;
_actor_80072df0->startWalk(0x97, 0x37, 2);
_actor_80072df0->updateSequence(7);
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
dialog[0] = 0;
_vm->_talk->loadText(_vm->getDialogTextId(0x5ecc), dialog, 2000);
_vm->_talk->displayDialogAroundPoint(dialog, 0x14, 6, 0xc01, 0, _vm->getDialogTextId(0x5ecc));
_vm->waitForFrames(0x3c);
break; // we do not need to loop in fact
}
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
_vm->fadeToBlack();
_vm->clearFlags(ENGINE_FLAG_20000);
// DisableVSyncEvent();
//file_read_to_buffer(s_cursor.act_80011c44, actor_dictionary);
// EnableVSyncEvent();
if (isFlag10Set) {
_vm->setFlags(ENGINE_FLAG_10);
} else {
_vm->clearFlags(ENGINE_FLAG_10);
}
_vm->_dragonINIResource->setFlickerRecord(flicker);
cursorInventoryClearFlag400();
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
}
//fadeScreenAndResetActor
void CutScene::fadeScreenAndResetActor(Actor *actor) {
_vm->fadeToBlack();
//DisableVSyncEvent();
actor->reset_maybe();
//EnableVSyncEvent();
}
void CutScene::closeUpShotOnActor(uint16 resourceId, uint16 sequenceId, int16 x, uint32 param_4) {
fun_8003d8e8(resourceId, sequenceId, x, param_4);
_vm->waitForFrames(5);
_vm->fadeFromBlack();
}
void CutScene::fun_8003d8e8(uint16 resourceId, uint16 sequenceId, int16 x, uint32 param_4) {
_vm->fadeToBlack();
_vm->_actorManager->clearActorFlags(2);
//DisableVSyncEvent();
_actor_80072de8 = _vm->_actorManager->loadActor(resourceId, sequenceId, x, 199, 3);
//EnableVSyncEvent();
changeBackgroundPosition(3, param_4);
}
void CutScene::wideAngleEveryoneAtTable() {
fun_8003d388();
_vm->fadeFromBlack();
}
void CutScene::fun_8003d388() {
uint sequenceId;
_vm->fadeToBlack();
_vm->_actorManager->clearActorFlags(2);
if ((_actor_80063514 & 0x80) == 0) {
_actor_80072de8 = _vm->_actorManager->loadActor(0x7e, 0x16, 0x40, 0xa0, 1);
}
_actor_80072dec = _vm->_actorManager->loadActor(0x7e, 0, 0xbf, 0xba, 1);
if ((_actor_80063514 & 8) == 0) {
_actor_80072df0 = _vm->_actorManager->loadActor(0x7e, 5, 0x94, 0x82, 1);
}
if ((_actor_80063514 & 0x10) == 0) {
_actor_80072df4 = _vm->_actorManager->loadActor(0x7e, 10, 0x6f, 0x95, 1);
}
if ((_actor_80063514 & 4) == 0) {
_actor_80072df8 = _vm->_actorManager->loadActor(0x7e, 0xe, 0xa9, 0x87, 1);
}
if ((_actor_80063514 & 0x20) == 0) {
_actor_80072dfc = _vm->_actorManager->loadActor(0x7e, 0x12, 0xcd, 0x8e, 1);
}
if ((_actor_80063514 & 1) == 0) {
_flameActor = _vm->_actorManager->loadActor(0x7e, 0x19, 0x10e, 0x89, 1);
}
if ((_actor_80063514 & 2) == 0) {
_actor_80072e08 = _vm->_actorManager->loadActor(0x8f, 2, 100, 0xbc, 1);
}
if ((_actor_80063514 & 0x40) != 0) {
_actor_80072e0c = _vm->_actorManager->loadActor(0x8f, 0, 0xd2, 100, 1);
_actor_800830a0 = _vm->_actorManager->loadActor(0x8f, 1, 0xe6, 0x6e, 1);
}
_actor_800830b8 = _vm->_actorManager->loadActor(0xaa, 0, 0x2e, 0x2d, 1);
_actor_800830b8->setFlag(ACTOR_FLAG_8000);
_actor_800830bc = _vm->_actorManager->loadActor(0xaa, 1, 0x115, 0x22, 1);
_actor_800830bc->setFlag(ACTOR_FLAG_100);
_actor_800830bc->setFlag(ACTOR_FLAG_8000);
_actor_800830bc->_priorityLayer = 4;
if ((_actor_80063514 & 0x100) != 0) {
_actor_800830c0 = _vm->_actorManager->loadActor(0x7e, 0x1c, 0x21, 0x87, 1);
}
if ((_actor_80063514 & 0x200) != 0) {
if ((_actor_80063514 & 0x800) == 0) {
sequenceId = 2;
} else {
sequenceId = 4;
}
_actor_800830d4 = _vm->_actorManager->loadActor(0xaa, sequenceId, 0xf4, 199, 1);
_actor_800830d4->setFlag(ACTOR_FLAG_8000);
}
if ((_actor_80063514 & 0x400) != 0) {
_actor_800830dc = _vm->_actorManager->loadActor(0xaa, 3, 0xf4, 199, 1);
_actor_800830dc->setFlag(ACTOR_FLAG_8000);
}
changeBackgroundPosition(0, 0);
_vm->waitForFramesAllowSkip(0xe);
}
void CutScene::closeUpKnightsAtTable() {
_vm->fadeToBlack();
_vm->_actorManager->clearActorFlags(2);
_actor_80072de8 = _vm->_actorManager->loadActor(0x7d, 0, 2, 199, 1);
_actor_80072dec = _vm->_actorManager->loadActor(0x81, 4, 2, 199, 1);
_actor_80072df0 = _vm->_actorManager->loadActor(0x81, 6, 2, 199, 1);
_actor_80072df4 = _vm->_actorManager->loadActor(0x81, 0, 2, 199, 1);
_actor_80072df8 = _vm->_actorManager->loadActor(0x81, 2, 2, 199, 1);
changeBackgroundPosition(1, 0);
_vm->waitForFrames(0xf);
_vm->fadeFromBlack();
}
uint16 CutScene::fun_8003dab8(uint32 textId, uint16 x, uint16 y, uint16 param_4, int16 param_5) {
uint16 dialog[2000];
dialog[0] = 0;
textId = _vm->getDialogTextId(textId);
_vm->_talk->loadText(textId, dialog, 2000);
_vm->_talk->displayDialogAroundPoint(dialog, x, y, param_4, param_5, textId);
return 1; //TODO this should return (uint)dialogText & 0xffff;
}
void CutScene::cursorInventoryClearFlag400() {
_vm->_cursor->clearActorFlag400();
_vm->_inventory->clearActorFlag400();
}
void CutScene::changeBackgroundPosition(uint16 newPosition, int16 sParm2) {
switch (newPosition) {
case 0:
_vm->_screen->loadPalette(0, _palettes + 0 * 512);
_vm->_scene->setMgLayerPriority(0);
_vm->_scene->setFgLayerPriority(0);
_vm->_scene->_camera.x = 0;
_vm->_scene->setBgLayerPriority(1);
break;
case 1:
_vm->_scene->setBgLayerPriority(0); //TODO investigate why this is 0 not 1
_vm->_scene->setMgLayerPriority(1); //TODO investigate why this is 1 not 2
_vm->_scene->_camera.x = sParm2 + 0x3c0;
_vm->_scene->setFgLayerPriority(0);
_vm->_screen->loadPalette(0, _palettes + 2 * 512);
for (int i = 2; i < 0x17; i++) {
Actor *actor = _vm->_actorManager->getActor(i);
actor->_x_pos += 0x3c0;
}
break;
case 2:
_vm->_screen->loadPalette(0, _palettes + 3 * 512);
_vm->_scene->setMgLayerPriority(2);
_vm->_scene->setFgLayerPriority(3);
_vm->_scene->_camera.x = 0;
_vm->_scene->setBgLayerPriority(1);
break;
case 3:
_vm->_screen->loadPalette(0, _palettes + 1 * 512);
_vm->_scene->setMgLayerPriority(2);
_vm->_scene->setFgLayerPriority(0);
_vm->_scene->_camera.x = sParm2;
_vm->_scene->setBgLayerPriority(1);
break;
default:
break;
}
}
void CutScene::diamondScene() {
Actor *actorId;
Actor *actorId_00;
Actor *actorId_01;
Actor *actorId_02;
Actor *actorId_03;
byte palette[512];
_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
actorId = _vm->getINI(0x257)->actor;
actorId_03 = _vm->getINI(0x259)->actor;
actorId_01 = _vm->getINI(0x258)->actor;
actorId_03->setFlag(ACTOR_FLAG_100);
actorId_03->_priorityLayer = 4;
actorId_00 = _vm->getINI(0x256)->actor;
_vm->setFlags(ENGINE_FLAG_20000);
actorId_02 = _vm->getINI(0x25a)->actor;
if ((_vm->_talk->somethingTextAndSpeechAndAnimRelated(actorId_02, 1, 0, 0x4294a, 0x2601) != 2) && !actorId->actorSetSequenceAndWaitAllowSkip(2)) {
actorId->updateSequence(3);
if (!actorId_01->actorSetSequenceAndWaitAllowSkip(0x18)) {
_vm->waitForFramesAllowSkip(0x2c);
_vm->fadeToBlack();
memcpy(palette, _vm->_scene->getPalette(), 512);
_vm->_screen->loadPalette(0, actorId_00->_actorResource->getPalette());
_vm->_scene->_camera.x = 0x140;
_vm->fadeFromBlack();
if (!actorId_00->actorSetSequenceAndWaitAllowSkip(0)) {
// TODO is this needed playSoundFromTxtIndex(0x42A66);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(actorId_00, 1, 2, 0x42a66, 0x3c01) != 2) {
_vm->waitForFramesAllowSkip(0x13);
_vm->fadeToBlack();
_vm->_screen->loadPalette(0, palette);
_vm->_scene->_camera.x = 0;
_vm->fadeFromBlack();
actorId_01->updateSequence(0x19);
_vm->waitForFramesAllowSkip(0xf);
actorId->updateSequence(4);
_vm->waitForFramesAllowSkip(0x17);
actorId_03->updateSequence(9);
actorId_03->_x_pos = 0x82;
actorId_03->_y_pos = 0xc4;
actorId_03->_priorityLayer = 4;
if (!actorId->waitUntilFlag4IsSetAllowSkip()) {
actorId->updateSequence(5);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(actorId_01, 0x10, 2, 0x42ac2, 0x3c01) != 2 &&
_vm->_talk->somethingTextAndSpeechAndAnimRelated(actorId_02, 1, 0, 0x42b56, 0x2601) != 2) {
_vm->waitForFramesAllowSkip(0x3b);
}
}
}
}
}
}
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
_vm->clearFlags(ENGINE_FLAG_20000);
}
void CutScene::knightsSavedBackAtCastle() {
DragonINI *uVar1;
uint actorId;
bool isFlag0x10Set;
uVar1 = _vm->_dragonINIResource->getFlickerRecord();
_actor_80063514 = 0xa00;
_vm->_dragonINIResource->setFlickerRecord(nullptr);
_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
isFlag0x10Set = _vm->isFlagSet(ENGINE_FLAG_10);
_vm->fadeToBlack();
_vm->clearFlags(ENGINE_FLAG_10);
_vm->_inventory->setActorFlag400();
_vm->_cursor->setActorFlag400();
// scr_tilemap1_w = 0x28;
// _actor_8006a3f0 = _actor_8006a3ec;
// load_actor_file(0x81);
// load_actor_file(0x7d);
// load_actor_file(0x7e);
// load_actor_file(0x8f);
// load_actor_file(0xaa);
_vm->setFlags(ENGINE_FLAG_20000);
closeUpKnightsAtTable();
// playSoundFromTxtIndex(0x7854);
while (1) { // In order to avoid gotos
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 10, 4, 0x7854, 0xc01) == 2)
break;
closeUpShotOnActor(0xd8, 0, 0xfd, 0x60);
//playSoundFromTxtIndex(0x78c6);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 4, 0, 0x78c6, 0x701) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpKnightsAtTable();
//playSoundFromTxtIndex(0x78e8);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 3, 0, 0x78e8, 0x2e01) == 2)
break;
wideAngleEveryoneAtTable();
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_flameActor, 0x1a, 0x19, 0x7a1e, 0x3e01) == 2)
break;
_flameActor->_walkSpeed = 0x10000;
_flameActor->setFlag(ACTOR_FLAG_800);
_flameActor->updateSequence(0x21);
_flameActor->startWalk(0x13f, 0x6e, 2);
// wait for pathfinding to complete
_flameActor->waitForWalkToFinish();
_actor_80063514 = _actor_80063514 | 1;
closeUpShotOnActor(0xd3, 0, 0x233, 0x17a);
//playSoundFromTxtIndex(0x7aba);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 9, 0, 0x7aba, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd8, 0, 0xfd, 0x60);
//playSoundFromTxtIndex(0x7b60);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 5, 0, 0x7b60, 0x701) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
wideAngleEveryoneAtTable();
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072df0, 9, 5, 0x7c20, 0xc01) == 2 ||
_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 0x17, 0x16, 0x7c9c, 0x701) == 2)
break;
_vm->playOrStopSound(0x800f);
_vm->waitForFrames(10);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 0x17, 0x16, 0x7cf2, 0x701) == 2)
break;
closeUpKnightsAtTable();
//playSoundFromTxtIndex(0x7dcc);
_actor_80072df0->updateSequence(0x13);
_actor_80072df4->updateSequence(0x10);
_actor_80072df8->updateSequence(0x11);
actorId = _vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 0x12, 6, 0x7dcc, 0xc01);
if ((actorId & 0xffff) == 2)
break;
closeUpShotOnActor(0xd3, 0, 0x233, 0x17a);
//playSoundFromTxtIndex(0x7e1a);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 10, 0, 0x7e1a, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
wideAngleEveryoneAtTable();
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 4, 0, 0x7e96, 0x2e01) == 2)
break;
_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 0x17, 0x16, 0x7f0a, 0x701);
break; // we do not want to loop
}
_vm->fadeToBlack();
//DisableVSyncEvent();
// file_read_to_buffer(s_cursor.act_80011c44, actor_dictionary);
//EnableVSyncEvent();
if (isFlag0x10Set) {
_vm->setFlags(ENGINE_FLAG_10);
}
_vm->clearFlags(ENGINE_FLAG_20000);
_vm->_dragonINIResource->setFlickerRecord(uVar1);
cursorInventoryClearFlag400();
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
}
void CutScene::loadPalettes() {
Common::File fd;
if (!fd.open("dragon.exe")) {
error("Failed to open dragon.exe");
}
fd.seek(_vm->getCutscenePaletteOffsetFromDragonEXE());
_palettes = (byte *)malloc(256 * 2 * 4);
fd.read(_palettes, 256 * 2 * 4);
}
void CutScene::flameReturnsCutScene() {
DragonINI *uVar1;
uint engineFlag10Set;
uVar1 = _vm->_dragonINIResource->getFlickerRecord();
_actor_80063514 = 0x3f;
_vm->_dragonINIResource->setFlickerRecord(nullptr);
_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
engineFlag10Set = _vm->isFlagSet(ENGINE_FLAG_10);
_vm->fadeToBlack();
_vm->clearFlags(ENGINE_FLAG_10);
_vm->_cursor->setActorFlag400();
_vm->_inventory->setActorFlag400();
// scr_tilemap1_w = 0x28;
// _actor_8006a3f0 = _actor_8006a3ec;
// load_actor_file(0x81);
// load_actor_file(0x7d);
// load_actor_file(0x7e);
// load_actor_file(0x8f);
// load_actor_file(0xaa);
_actor_80063514 = (_actor_80063514 & 0xfffe) | 0x600;
fun_8003d388();
_actor_80072de8->updateSequence(0x1f);
_flameActor->_x_pos = 0x10b;
_flameActor->_y_pos = 99;
_actor_80072de8->_x_pos = 0x10a;
_actor_80072de8->_y_pos = 0x5a;
_actor_80072de8->_walkSpeed = 0x10000;
_flameActor->_walkSpeed = 0x10000;
_actor_80072de8->setFlag(ACTOR_FLAG_800);
_flameActor->setFlag(ACTOR_FLAG_800);
_vm->fadeFromBlack();
_vm->setFlags(ENGINE_FLAG_20000);
while (1) { // In order to avoid gotos
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 4, 0, 0x8ab2, 0x2e01) == 2)
break;
_actor_80072de8->updateSequence(0x1e);
_actor_80072de8->startWalk(0xb0, 0x6b, 2);
_actor_80072de8->waitForWalkToFinish();
_actor_80072de8->updateSequence(0x1f);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 4, 0, 0x8b40, 0x2e01) == 2)
break;
_flameActor->updateSequence(0x1b);
_flameActor->startWalk(0xd5, 0x6b, 2);
_flameActor->waitForWalkToFinish();
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_flameActor, 0x1a, 0x19, 0x8bb6, 0x3e01) == 2 ||
_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 4, 0, 0x8bd8, 0x2e01) == 2)
break;
closeUpShotOnActor(0xd8, 0, 0xfd, 0x60);
//playSoundFromTxtIndex(0x8c70);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 7, 0, 0x8c70, 0x701) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd3, 0, 0x233, 0x17a);
//playSoundFromTxtIndex(0x8cd2);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 0xc, 0, 0x8cd2, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd7, 0, 0x312, 0x260);
//playSoundFromTxtIndex(0x8e1e);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 5, 0, 0x8e1e, 0x3e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
break; // We do not want to loop
}
_vm->fadeToBlack();
// DisableVSyncEvent();
// file_read_to_buffer(s_cursor.act_80011c44, actor_dictionary);
// EnableVSyncEvent();
_vm->clearFlags(ENGINE_FLAG_20000);
if (engineFlag10Set) {
_vm->setFlags(ENGINE_FLAG_10);
}
_vm->_dragonINIResource->setFlickerRecord(uVar1);
cursorInventoryClearFlag400();
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
}
void CutScene::knightsSavedAgain() {
DragonINI *flicker;
bool engineFlag10Set;
flicker = _vm->_dragonINIResource->getFlickerRecord();
_actor_80063514 = 0;
_vm->_dragonINIResource->setFlickerRecord(nullptr);
_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
engineFlag10Set = _vm->isFlagSet(ENGINE_FLAG_10);
_vm->fadeToBlack();
_vm->clearFlags(ENGINE_FLAG_10);
_vm->_cursor->setActorFlag400();
_vm->_inventory->setActorFlag400();
// scr_tilemap1_w = 0x28;
//TODO what is this? _actor_8006a3f0 = _actor_8006a3ec;
// load_actor_file(0x81);
// load_actor_file(0x7d);
// load_actor_file(0x7e);
// load_actor_file(0x8f);
// load_actor_file(0xaa);
wideAngleEveryoneAtTable();
_vm->setFlags(ENGINE_FLAG_20000);
_vm->waitForFramesAllowSkip(0x3b);
closeUpShotOnActor(0xd3, 0, 0x233, 0x17a);
//playSoundFromTxtIndex(0x9000);
while (1) { // In order to avoid gotos
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 0xd, 0, 0x9000, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpKnightsAtTable();
//playSoundFromTxtIndex(0x90de);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 4, 0, 0x90de, 0x2e01) == 2)
break;
closeUpShotOnActor(0xd8, 0, 0xfd, 0x60);
//playSoundFromTxtIndex(0x921c);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 8, 0, 0x921c, 0x701) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpKnightsAtTable();
//playSoundFromTxtIndex(0x92aa);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 9, 4, 0x92aa, 0xc01) == 2)
break;
closeUpShotOnActor(0xd7, 0, 0x312, 0x260);
//playSoundFromTxtIndex(0x932c);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 6, 0, 0x932c, 0x3e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpShotOnActor(0xd3, 2, 0x87, 0);
//playSoundFromTxtIndex(0x93d6);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 0xe, 2, 0x93d6, 0x2e01) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
closeUpKnightsAtTable();
//playSoundFromTxtIndex(0x7dcc);
_actor_80072df0->updateSequence(0x13);
_actor_80072df4->updateSequence(0x10);
_actor_80072df8->updateSequence(0x11);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072dec, 0x12, 6, 0x7dcc, 0xc01) == 2)
break;
closeUpShotOnActor(0xd8, 0, 0xfd, 0x60);
//playSoundFromTxtIndex(0x948c);
if (_vm->_talk->somethingTextAndSpeechAndAnimRelated(_actor_80072de8, 9, 0, 0x948c, 0x701) == 2)
break;
fadeScreenAndResetActor(_actor_80072de8);
_vm->waitForFramesAllowSkip(0x3b);
break; // We do not want to loop
}
_vm->fadeToBlack();
// DisableVSyncEvent();
// file_read_to_buffer(s_cursor.act_80011c44, actor_dictionary);
// EnableVSyncEvent();
_vm->clearFlags(ENGINE_FLAG_20000);
if (engineFlag10Set) {
_vm->setFlags(ENGINE_FLAG_10);
}
_vm->_dragonINIResource->setFlickerRecord(flicker);
cursorInventoryClearFlag400();
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
}
static uint16 tournamentUpdateCameraX = 0;
void tournamentUpdateFunction() {
tournamentUpdateCameraX++;
if (tournamentUpdateCameraX > 0x280) {
return;
}
getEngine()->_scene->_camera.x = tournamentUpdateCameraX;
}
void CutScene::tournamentCutScene() {
uint16 dialogText[1000];
tournamentUpdateCameraX = 0x140;
_vm->setVsyncUpdateFunction(tournamentUpdateFunction);
_vm->_talk->loadText(_vm->getDialogTextId(0x4C40C), dialogText, 1000);
_vm->_talk->displayDialogAroundPoint(dialogText, 0, 0, 0x1e01, 1, _vm->getDialogTextId(0x4C40C));
_vm->_talk->loadText(_vm->getDialogTextId(0x4C530), dialogText, 1000);
_vm->_talk->displayDialogAroundPoint(dialogText, 0, 0, 0xc01, 1, _vm->getDialogTextId(0x4C530));
_vm->_talk->loadText(_vm->getDialogTextId(0x4C588), dialogText, 1000);
_vm->_talk->displayDialogAroundPoint(dialogText, 0, 0, 0x1e01, 1, _vm->getDialogTextId(0x4C588));
_vm->_talk->loadText(_vm->getDialogTextId(0x4C6B0), dialogText, 1000);
_vm->_talk->displayDialogAroundPoint(dialogText, 0, 0, 0xc01, 1, _vm->getDialogTextId(0x4C6B0));
_vm->_talk->loadText(_vm->getDialogTextId(0x4C6E8), dialogText, 1000);
_vm->_talk->displayDialogAroundPoint(dialogText, 0, 0, 0x1e01, 1, _vm->getDialogTextId(0x4C6E8));
_vm->setVsyncUpdateFunction(nullptr);
_vm->setFlags(ENGINE_FLAG_20000);
_vm->fadeToBlack();
Actor *actor = _vm->_dragonINIResource->getRecord(0x02BE)->actor;
_vm->_screen->loadPalette(0, actor->_actorResource->getPalette());
_vm->_scene->_camera.x = 0;
_vm->playOrStopSound(0);
_vm->fadeFromBlack();
_vm->waitForFrames(300);
actor->setFlag(ACTOR_FLAG_1000);
actor->waitUntilFlag8And4AreSet();
_vm->waitForFrames(0x3c);
_vm->fadeToBlack();
_vm->_screen->loadPalette(0, _vm->_scene->getPalette());
_vm->playOrStopSound(0x4000);
_vm->_scene->_camera.x = 0x3c0;
_vm->fadeFromBlack();
_vm->_talk->loadText(_vm->getDialogTextId(0x4C814), dialogText, 1000);
_vm->_talk->displayDialogAroundPoint(dialogText, 0, 0, 0xc01, 1, _vm->getDialogTextId(0x4C814));
_vm->_talk->loadText(_vm->getDialogTextId(0x4C852), dialogText, 1000);
_vm->_talk->displayDialogAroundPoint(dialogText, 0, 0, 0x1e01, 1, _vm->getDialogTextId(0x4C852));
_vm->setFlags(ENGINE_FLAG_20000);
_vm->fadeToBlack();
}
} // End of namespace Dragons

View File

@@ -0,0 +1,82 @@
/* 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 DRAGONS_CUTSCENE_H
#define DRAGONS_CUTSCENE_H
#include "common/scummsys.h"
namespace Dragons {
class Actor;
class DragonsEngine;
class CutScene {
private:
DragonsEngine *_vm;
Actor *_actor_80072de8;
Actor *_actor_80072dec;
Actor *_actor_800830c0;
Actor *_actor_80072df0;
Actor *_actor_80072e08;
Actor *_actor_80072df4;
Actor *_actor_80072df8;
Actor *_actor_80072dfc;
Actor *_actor_800830bc;
Actor *_actor_800830b8;
Actor *_actor_80072e0c;
Actor *_actor_800830a0;
Actor *_actor_800830d4;
Actor *_actor_800830dc;
Actor *_flameActor;
uint16 _actor_80063514; //flags
byte *_palettes;
public:
CutScene(DragonsEngine *vm);
virtual ~CutScene();
void scene1();
void diamondScene();
void knightsSavedBackAtCastle();
void flameReturnsCutScene();
void knightsSavedAgain();
void tournamentCutScene();
private:
//Scene 1 related functions
void fadeScreenAndResetActor(Actor *actor);
void closeUpShotOnActor(uint16 resourceId, uint16 sequenceId, int16 x, uint32 param_4);
void fun_8003d8e8(uint16 resourceId, uint16 sequenceId, int16 x, uint32 param_4);
void wideAngleEveryoneAtTable();
void fun_8003d388();
void closeUpKnightsAtTable();
uint16 fun_8003dab8(uint32 textId, uint16 x, uint16 y, uint16 param_4, int16 param_5);
void cursorInventoryClearFlag400();
void changeBackgroundPosition(uint16 newPosition, int16 sParm2);
void loadPalettes();
};
} // End of namespace Dragons
#endif //DRAGONS_CUTSCENE_H

View File

@@ -0,0 +1,142 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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 "base/plugins.h"
#include "dragons/detection.h"
static const PlainGameDescriptor dragonsGames[] = {
{ "dragons", "Blazing Dragons" },
{ nullptr, nullptr }
};
namespace Dragons {
static const DragonsGameDescription gameDescriptions[] = {
{
{
"dragons",
nullptr,
AD_ENTRY1s("bigfile.dat", "02c26712bee57266f28235fdc0207725", 44990464),
Common::EN_USA,
Common::kPlatformPSX,
ADGF_DROPPLATFORM,
GUIO0()
},
kGameIdDragons
},
{
{
"dragons",
nullptr,
AD_ENTRY1s("bigfile.dat", "02c26712bee57266f28235fdc0207725", 44992512),
Common::EN_GRB,
Common::kPlatformPSX,
ADGF_DROPPLATFORM,
GUIO0()
},
kGameIdDragons
},
{
{
"dragons",
nullptr,
AD_ENTRY1s("bigfile.dat", "9854fed0d2b48522a62973e99b52a0be", 45099008),
Common::DE_DEU,
Common::kPlatformPSX,
ADGF_DROPPLATFORM,
GUIO0()
},
kGameIdDragons
},
{
{
"dragons",
nullptr,
AD_ENTRY1s("bigfile.dat", "9854fed0d2b48522a62973e99b52a0be", 45107200),
Common::FR_FRA,
Common::kPlatformPSX,
ADGF_DROPPLATFORM,
GUIO0()
},
kGameIdDragons
},
// Russian localization by Russian Versions
{
{
"dragons",
nullptr,
AD_ENTRY2s("bigfile.dat", "02c26712bee57266f28235fdc0207725", 44990464,
"dtspeech.xa", "7f7ace860e5dd3696b51eace20215274", 182138880),
Common::RU_RUS,
Common::kPlatformPSX,
ADGF_DROPPLATFORM,
GUIO0()
},
kGameIdDragons
},
// BAD EXTRACTIONS
{
{
"dragons",
nullptr,
AD_ENTRY1s("bigfile.dat", "92b938703611789e1a007d6dfac7ef7e", 51668736),
Common::EN_USA,
Common::kPlatformPSX,
ADGF_DROPPLATFORM,
GUIO0()
},
kGameIdDragonsBadExtraction
},
{ AD_TABLE_END_MARKER, 0 }
};
} // End of namespace Dragons
static const char * const directoryGlobs[] = {
"resource",
nullptr
};
class DragonsMetaEngineDetection : public AdvancedMetaEngineDetection<Dragons::DragonsGameDescription> {
public:
DragonsMetaEngineDetection() : AdvancedMetaEngineDetection(Dragons::gameDescriptions, dragonsGames) {
_maxScanDepth = 2;
_directoryGlobs = directoryGlobs;
}
const char *getName() const override {
return "dragons";
}
const char *getEngineName() const override {
return "Blazing Dragons";
}
const char *getOriginalCopyright() const override {
return "(C) 1996 The Illusions Gaming Company";
}
};
REGISTER_PLUGIN_STATIC(DRAGONS_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, DragonsMetaEngineDetection);

View File

@@ -0,0 +1,43 @@
/* 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 DRAGONS_DETECTION_H
#define DRAGONS_DETECTION_H
#include "engines/advancedDetector.h"
namespace Dragons {
enum {
kGameIdDragons = 1,
kGameIdDragonsBadExtraction = 2
};
struct DragonsGameDescription {
AD_GAME_DESCRIPTION_HELPERS(desc);
ADGameDescription desc;
int gameId;
};
} // End of namespace Dragons
#endif // DRAGONS_DETECTION_H

View File

@@ -0,0 +1,133 @@
/* 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 "dragons/dragonflg.h"
#include "dragons/bigfile.h"
namespace Dragons {
// Properties
Properties::Properties(uint count) : _count(count) {
_properties = (byte *)malloc(getSize());
if (!_properties) {
error("Failed to allocate mem for properties");
}
memset(_properties, 0, getSize());
}
Properties::~Properties() {
free(_properties);
}
void Properties::init(uint count, byte *properties) {
assert(count <= getSize());
memcpy(_properties, properties, count);
}
void Properties::clear() {
uint32 size = getSize();
for (uint32 i = 0; i < size; ++i) {
_properties[i] = 0;
}
}
bool Properties::get(uint32 propertyId) {
uint index;
byte mask;
getProperyPos(propertyId, index, mask);
return (_properties[index] & mask) != 0;
}
void Properties::set(uint32 propertyId, bool value) {
uint index;
byte mask;
getProperyPos(propertyId, index, mask);
if (value)
_properties[index] |= mask;
else
_properties[index] &= ~mask;
}
uint32 Properties::getSize() {
return (_count >> 3) + 1;
}
void Properties::getProperyPos(uint32 propertyId, uint &index, byte &mask) {
assert(propertyId < _count);
index = propertyId / 8;
mask = 1 << (propertyId % 8);
}
void Properties::save(uint numberToWrite, Common::WriteStream *out) {
assert(numberToWrite % 8 == 0);
assert(numberToWrite <= _count);
out->write(_properties, numberToWrite / 8);
}
void Properties::print(char *prefix) {
char *str = new char[_count + 1];
uint i = 0;
for (; i < _count; i++) {
str[i] = get(i) ? '1' : '0';
}
str[i] = 0;
debug(3, "%s: props = %s", prefix, str);
delete[] str;
}
DragonFLG::DragonFLG(BigfileArchive *bigfileArchive) {
_data = bigfileArchive->load("dragon.flg", _dataSize);
_properties = new Properties(288);
_properties->init(_dataSize, _data);
}
DragonFLG::~DragonFLG() {
delete _data;
delete _properties;
}
bool DragonFLG::get(uint32 propertyId) {
return _properties->get(propertyId);
}
void DragonFLG::set(uint32 propertyId, bool value) {
_properties->set(propertyId, value);
}
void DragonFLG::saveState(Common::WriteStream *out) {
//properties->print("save");
_properties->save(128, out); // save first 80 flags.
}
void DragonFLG::loadState(Common::ReadStream *in) {
byte savedState[0x10];
_properties->init(_dataSize, _data);
in->read(savedState, 0x10);
_properties->init(0x10, savedState);
//properties->print("load");
}
} // End of namespace Dragons

View File

@@ -0,0 +1,67 @@
/* 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 DRAGONS_DRAGONFLG_H
#define DRAGONS_DRAGONFLG_H
#include "common/stream.h"
namespace Dragons {
class BigfileArchive;
class Properties {
public:
Properties(uint count);
~Properties();
void init(uint count, byte *properties);
void clear();
bool get(uint32 propertyId);
void set(uint32 propertyId, bool value);
void save(uint numberToWrite, Common::WriteStream *out);
void print(char *prefix);
private:
uint _count;
byte *_properties;
uint32 getSize();
void getProperyPos(uint32 propertyId, uint &index, byte &mask);
};
class DragonFLG {
private:
byte *_data;
uint32 _dataSize;
Properties *_properties;
public:
virtual ~DragonFLG();
DragonFLG(BigfileArchive *bigfileArchive);
bool get(uint32 propertyId);
void set(uint32 propertyId, bool value);
void saveState(Common::WriteStream *out);
void loadState(Common::ReadStream *in);
};
} // End of namespace Dragons
#endif //DRAGONS_DRAGONFLG_H

View File

@@ -0,0 +1,68 @@
/* 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 "dragons/dragonimg.h"
#include "dragons/bigfile.h"
namespace Dragons {
DragonImg::DragonImg(BigfileArchive *bigfileArchive) {
uint32 fileSize;
byte *iptData = bigfileArchive->load("dragon.ipt", fileSize);
Common::SeekableReadStream *iptReadStream = new Common::MemoryReadStream(iptData, fileSize, DisposeAfterUse::YES);
_count = fileSize / 4;
_imgData = bigfileArchive->load("dragon.img", fileSize);
Common::SeekableReadStream *imgReadStream = new Common::MemoryReadStream(_imgData, fileSize, DisposeAfterUse::NO);
_imgObjects = new Img[_count];
for (int i = 0; i < _count; i++) {
imgReadStream->seek(iptReadStream->readUint32LE());
_imgObjects[i].x = imgReadStream->readUint16LE();
_imgObjects[i].y = imgReadStream->readUint16LE();
_imgObjects[i].w = imgReadStream->readUint16LE();
_imgObjects[i].h = imgReadStream->readUint16LE();
_imgObjects[i].layerNum = imgReadStream->readUint16LE();
_imgObjects[i].field_a = imgReadStream->readUint16LE();
_imgObjects[i].field_c = imgReadStream->readUint16LE();
_imgObjects[i].field_e = imgReadStream->readUint16LE();
_imgObjects[i].data = _imgData + imgReadStream->pos();
}
delete iptReadStream;
delete imgReadStream;
}
DragonImg::~DragonImg() {
delete _imgData;
delete[] _imgObjects;
}
Img *DragonImg::getImg(uint32 iptId) {
iptId &= 0xffff;
assert(iptId < _count);
return &_imgObjects[iptId];
}
} // End of namespace Dragons

View File

@@ -0,0 +1,54 @@
/* 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 DRAGONS_DRAGONImg_H
#define DRAGONS_DRAGONImg_H
namespace Dragons {
struct Img {
uint16 x;
uint16 y;
uint16 w;
uint16 h;
uint16 layerNum;
uint16 field_a;
uint16 field_c;
uint16 field_e;
byte *data;
};
class BigfileArchive;
class DragonImg {
private:
uint16 _count;
Img *_imgObjects;
byte *_imgData;
public:
DragonImg(BigfileArchive *bigfileArchive);
~DragonImg();
Img *getImg(uint32 iptId);
};
} // End of namespace Dragons
#endif //DRAGONS_DRAGONImg_H

View 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/>.
*
*/
#include "common/debug.h"
#include "common/memstream.h"
#include "dragons/dragonini.h"
namespace Dragons {
#define DRAGON_INI_STRUCT_SIZE 0x22
DragonINIResource::DragonINIResource(BigfileArchive *bigfileArchive): _bigfileArchive(bigfileArchive), _dragonINI(nullptr) {
reset();
}
void DragonINIResource::reset() {
uint32 fileSize;
byte *data = _bigfileArchive->load("dragon.ini", fileSize);
Common::SeekableReadStream *readStream = new Common::MemoryReadStream(data, fileSize, DisposeAfterUse::YES);
if (!_dragonINI) {
_count = fileSize / DRAGON_INI_STRUCT_SIZE;
_dragonINI = new DragonINI[_count];
}
for (int i = 0; i < _count; i++) {
_dragonINI[i].id = (uint16)i;
_dragonINI[i].iptIndex_maybe = readStream->readSint16LE();
_dragonINI[i].imgId = readStream->readSint16LE();
_dragonINI[i].actorResourceId = readStream->readSint16LE();
_dragonINI[i].sequenceId = readStream->readSint16LE();
_dragonINI[i].inventorySequenceId = readStream->readSint16LE();
uint16 v = readStream->readUint16LE();
assert(v == 0); // actorId
_dragonINI[i].actor = nullptr;
_dragonINI[i].sceneId = readStream->readUint16LE();
_dragonINI[i].direction = readStream->readSint16LE();
_dragonINI[i].counter = readStream->readSint16LE();
_dragonINI[i].objectState = readStream->readSint16LE();
_dragonINI[i].objectState2 = readStream->readSint16LE();
_dragonINI[i].x = readStream->readSint16LE();
_dragonINI[i].y = readStream->readSint16LE();
_dragonINI[i].flags = readStream->readUint16LE();
_dragonINI[i].baseXOffset = readStream->readSint16LE();
_dragonINI[i].baseYOffset = readStream->readSint16LE();
_dragonINI[i].direction2 = readStream->readUint16LE();
}
_flickerINI = &_dragonINI[0];
delete readStream;
}
DragonINI *DragonINIResource::getRecord(uint16 index) {
assert (index < _count);
return &_dragonINI[index];
}
void DragonINIResource::setFlickerRecord(DragonINI *dragonINI) {
_flickerINI = dragonINI;
}
bool DragonINIResource::isFlicker(uint16 index) {
return _flickerINI && _flickerINI->id == index;
}
} // End of namespace Dragons

View File

@@ -0,0 +1,88 @@
/* 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 DRAGONS_DRAGONINI_H
#define DRAGONS_DRAGONINI_H
#include "dragons/bigfile.h"
namespace Dragons {
class Actor;
enum IniFlags {
INI_FLAG_1 = 0x1,
INI_FLAG_2 = 0x2,
INI_FLAG_4 = 0x4,
INI_FLAG_8 = 0x8,
INI_FLAG_10 = 0x10,
INI_FLAG_20 = 0x20,
INI_FLAG_40 = 0x40,
INI_FLAG_80 = 0x80
};
struct DragonINI {
uint16 id;
int16 iptIndex_maybe;
int16 imgId;
int16 actorResourceId;
uint16 sequenceId;
int16 inventorySequenceId;
Actor *actor;
uint16 sceneId;
int16 direction;
int16 counter;
int16 objectState;
uint16 objectState2;
int16 x;
int16 y;
uint16 flags;
int16 baseXOffset;
int16 baseYOffset;
int16 direction2;
};
class DragonINIResource {
private:
BigfileArchive *_bigfileArchive;
DragonINI *_dragonINI;
uint16 _count;
DragonINI *_flickerINI;
public:
DragonINIResource(BigfileArchive *bigfileArchive);
void reset();
uint16 totalRecords() { return _count; }
DragonINI *getRecord(uint16 index);
void setFlickerRecord(DragonINI *dragonINI);
DragonINI *getFlickerRecord() {
return _flickerINI;
}
bool isFlicker(uint16 index);
bool isFlicker(DragonINI *ini) {
return isFlicker(ini->id);
}
};
} // End of namespace Dragons
#endif //DRAGONS_DRAGONINI_H

View File

@@ -0,0 +1,62 @@
/* 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 "dragons/dragonobd.h"
#include "dragons/bigfile.h"
namespace Dragons {
DragonOBD::DragonOBD(BigfileArchive *bigfileArchive) {
uint32 size;
byte *optData = bigfileArchive->load("dragon.opt", size);
_optReadStream = new Common::MemoryReadStream(optData, size, DisposeAfterUse::YES);
byte *sptData = bigfileArchive->load("dragon.spt", size);
_sptReadStream = new Common::MemoryReadStream(sptData, size, DisposeAfterUse::YES);
_data = bigfileArchive->load("dragon.obd", _dataSize);
}
byte *DragonOBD::getObdAtOffset(uint32 offset) {
assert(_data);
assert(offset < _dataSize);
return &_data[offset];
}
DragonOBD::~DragonOBD() {
if (_data) {
delete _data;
}
delete _optReadStream;
delete _sptReadStream;
}
byte *DragonOBD::getFromOpt(uint32 index) {
_optReadStream->seek(index * 8);
return getObdAtOffset(_optReadStream->readUint32LE());
}
byte *DragonOBD::getFromSpt(uint32 index) {
_sptReadStream->seek(index * 4);
return getObdAtOffset(_sptReadStream->readUint32LE());
}
} // End of namespace Dragons

View File

@@ -0,0 +1,46 @@
/* 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 DRAGONS_DRAGONOBD_H
#define DRAGONS_DRAGONOBD_H
namespace Dragons {
class BigfileArchive;
class DragonOBD {
private:
byte *_data;
uint32 _dataSize;
Common::SeekableReadStream *_optReadStream;
Common::SeekableReadStream *_sptReadStream;
public:
virtual ~DragonOBD();
DragonOBD(BigfileArchive *bigfileArchive);
byte *getObdAtOffset(uint32 offset);
byte *getFromOpt(uint32 index);
byte *getFromSpt(uint32 index);
};
} // End of namespace Dragons
#endif //DRAGONS_DRAGONOBD_H

View File

@@ -0,0 +1,83 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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 "dragons/dragonrms.h"
#include "dragons/dragonobd.h"
#include "dragons/bigfile.h"
namespace Dragons {
#define DRAGON_RMS_STRUCT_SIZE 0x1c
DragonRMS::DragonRMS(BigfileArchive *bigfileArchive, DragonOBD *dragonOBD) : _dragonOBD(dragonOBD) {
uint32 fileSize;
byte *data = bigfileArchive->load("dragon.rms", fileSize);
Common::SeekableReadStream *readStream = new Common::MemoryReadStream(data, fileSize, DisposeAfterUse::YES);
_count = fileSize / DRAGON_RMS_STRUCT_SIZE;
_rmsObjects = new RMS[_count];
for (int i = 0; i < _count; i++) {
_rmsObjects[i]._field0 = readStream->readSint32LE();
readStream->read(_rmsObjects[i]._sceneName, 4);
_rmsObjects[i]._afterDataLoadScript = readStream->readSint32LE();
_rmsObjects[i]._afterSceneLoadScript = readStream->readSint32LE();
_rmsObjects[i]._beforeLoadScript = readStream->readSint32LE();
_rmsObjects[i]._inventoryBagPosition = readStream->readSint16LE();
_rmsObjects[i]._field16 = readStream->readSint32LE();
_rmsObjects[i]._field1a = readStream->readSint16LE();
}
delete readStream;
}
DragonRMS::~DragonRMS() {
delete[] _rmsObjects;
}
char *DragonRMS::getSceneName(uint32 sceneId) {
return getRMS(sceneId)->_sceneName;
}
byte *DragonRMS::getBeforeSceneDataLoadedScript(uint32 sceneId) {
return _dragonOBD->getObdAtOffset(getRMS(sceneId)->_beforeLoadScript);
}
byte *DragonRMS::getAfterSceneDataLoadedScript(uint32 sceneId) {
return _dragonOBD->getObdAtOffset(getRMS(sceneId)->_afterDataLoadScript);
}
byte *DragonRMS::getAfterSceneLoadedScript(uint32 sceneId) {
return _dragonOBD->getObdAtOffset(getRMS(sceneId)->_afterSceneLoadScript);
}
int16 DragonRMS::getInventoryPosition(uint32 sceneId) {
return getRMS(sceneId)->_inventoryBagPosition;
}
RMS *DragonRMS::getRMS(uint32 sceneId) {
sceneId &= 0x7fff;
assert(sceneId > 1);
assert(sceneId - 2 < _count);
return &_rmsObjects[sceneId - 2];
}
} // End of namespace Dragons

View File

@@ -0,0 +1,60 @@
/* 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 DRAGONS_DRAGONRMS_H
#define DRAGONS_DRAGONRMS_H
namespace Dragons {
struct RMS {
int32 _field0;
char _sceneName[4];
uint32 _afterDataLoadScript;
int32 _afterSceneLoadScript;
uint32 _beforeLoadScript;
int16 _inventoryBagPosition;
int32 _field16;
int16 _field1a;
};
class BigfileArchive;
class DragonOBD;
class DragonRMS {
private:
uint16 _count;
RMS *_rmsObjects;
DragonOBD *_dragonOBD;
public:
DragonRMS(BigfileArchive *bigfileArchive, DragonOBD *dragonOBD);
~DragonRMS();
char *getSceneName(uint32 sceneId);
byte *getAfterSceneDataLoadedScript(uint32 sceneId);
byte *getBeforeSceneDataLoadedScript(uint32 sceneId);
byte *getAfterSceneLoadedScript(uint32 sceneId);
int16 getInventoryPosition(uint32 sceneId);
private:
RMS *getRMS(uint32 sceneId);
};
} // End of namespace Dragons
#endif //DRAGONS_DRAGONRMS_H

2529
engines/dragons/dragons.cpp Normal file

File diff suppressed because it is too large Load Diff

402
engines/dragons/dragons.h Normal file
View File

@@ -0,0 +1,402 @@
/* 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 DRAGONS_DRAGONS_H
#define DRAGONS_DRAGONS_H
#include "engines/engine.h"
#include "dragons/detection.h"
#include "common/rect.h"
namespace Dragons {
struct SaveHeader {
Common::String description;
uint32 version;
uint32 flags;
uint32 saveDate;
uint32 saveTime;
uint32 playTime;
Graphics::Surface *thumbnail;
};
enum kReadSaveHeaderError {
kRSHENoError = 0,
kRSHEInvalidType = 1,
kRSHEInvalidVersion = 2,
kRSHEIoError = 3
};
enum Flags : uint {
ENGINE_FLAG_1 = 1,
ENGINE_FLAG_2 = 2,
ENGINE_FLAG_4 = 4,
ENGINE_FLAG_8 = 8,
ENGINE_FLAG_10 = 0x10,
ENGINE_FLAG_20 = 0x20,
ENGINE_FLAG_40 = 0x40,
ENGINE_FLAG_80 = 0x80, // Inventory bag visible
ENGINE_FLAG_100 = 0x100,
ENGINE_FLAG_200 = 0x200,
ENGINE_FLAG_400 = 0x400,
ENGINE_FLAG_800 = 0x800,
ENGINE_FLAG_1000_SUBTITLES_DISABLED = 0x1000,
ENGINE_FLAG_8000 = 0x8000, // speech dialog is playing.
ENGINE_FLAG_10000 = 0x10000,
ENGINE_FLAG_20000 = 0x20000,
ENGINE_FLAG_80000 = 0x80000,
ENGINE_FLAG_100000 = 0x100000,
ENGINE_FLAG_200000 = 0x200000,
ENGINE_FLAG_400000 = 0x400000,
ENGINE_FLAG_2000000 = 0x2000000,
ENGINE_FLAG_4000000 = 0x4000000,
ENGINE_FLAG_8000000 = 0x8000000,
ENGINE_FLAG_20000000 = 0x20000000,
ENGINE_FLAG_80000000 = 0x80000000 //Flicker idle animation running.
};
enum UnkFlags {
ENGINE_UNK1_FLAG_1 = 1,
ENGINE_UNK1_FLAG_2 = 2,
ENGINE_UNK1_FLAG_4 = 4,
ENGINE_UNK1_FLAG_8 = 8,
ENGINE_UNK1_FLAG_10 = 0x10,
ENGINE_UNK1_FLAG_20 = 0x20,
ENGINE_UNK1_FLAG_40 = 0x40,
ENGINE_UNK1_FLAG_80 = 0x80
};
enum MouseWheel {
MOUSE_WHEEL_NO_EVENT,
MOUSE_WHEEL_DOWN,
MOUSE_WHEEL_UP
};
struct PaletteCyclingInstruction {
int16 paletteType;
int16 startOffset;
int16 endOffset;
int16 updateInterval;
int16 updateCounter;
};
enum DragonsAction {
kDragonsActionNone,
kDragonsActionUp,
kDragonsActionDown,
kDragonsActionLeft,
kDragonsActionRight,
kDragonsActionSquare,
kDragonsActionTriangle,
kDragonsActionCircle,
kDragonsActionCross,
kDragonsActionL1,
kDragonsActionR1,
kDragonsActionSelect,
kDragonsActionChangeCommand,
kDragonsActionInventory,
kDragonsActionEnter,
kDragonsActionMenu,
kDragonsActionPause,
kDragonsActionDebug,
kDragonsActionDebugGfx,
kDragonsActionQuit
};
class BigfileArchive;
class BackgroundResourceLoader;
class Cursor;
class Credits;
class DragonFLG;
class DragonImg;
class DragonOBD;
class DragonRMS;
class DragonVAR;
class DragonINIResource;
class FontManager;
class Inventory;
class Scene;
class Screen;
class ActorManager;
class Actor;
class SequenceOpcodes;
class ScriptOpcodes;
class Talk;
class SoundManager;
class StrPlayer;
struct DragonINI;
struct LoadingScreenState {
Actor *flames[10];
uint16 quads[10];
int16 baseYOffset;
int16 flameOffsetIdx;
int16 loadingFlamesUpdateCounter;
int16 loadingFlamesRiseCounter;
LoadingScreenState() {
baseYOffset = 0;
flameOffsetIdx = 0;
loadingFlamesUpdateCounter = 0;
loadingFlamesRiseCounter = 0;
memset(flames, 0, ARRAYSIZE(flames)*sizeof(flames[0]));
memset(quads, 0, ARRAYSIZE(quads)*sizeof(quads[0]));
}
};
class DragonsEngine : public Engine {
public:
DragonOBD *_dragonOBD;
DragonImg *_dragonImg;
DragonRMS *_dragonRMS;
ActorManager *_actorManager;
DragonINIResource *_dragonINIResource;
FontManager *_fontManager;
ScriptOpcodes *_scriptOpcodes;
Scene *_scene;
uint16 _flickerInitialSceneDirection;
Inventory *_inventory;
Cursor *_cursor;
Credits *_credits;
Talk *_talk;
SoundManager *_sound;
StrPlayer *_strPlayer;
PaletteCyclingInstruction _paletteCyclingTbl[8];
bool _isLoadingDialogAudio;
uint16 _videoFlags; // TODO move to screen?
void loadCurrentSceneMsf();
Screen *_screen;
uint16 _sceneId1; //TODO wire this up. I think it might be where to restore save game from?
private:
Common::Language _language;
BigfileArchive *_bigfileArchive;
DragonFLG *_dragonFLG;
DragonVAR *_dragonVAR;
BackgroundResourceLoader *_backgroundResourceLoader;
SequenceOpcodes *_sequenceOpcodes;
uint32 _nextUpdatetime;
uint32 _flags;
uint32 _unkFlags1;
Common::Point _cursorPosition;
uint32 _flickerIdleCounter;
uint32 _bit_flags_8006fbd8;
//unk
uint16 _run_func_ptr_unk_countdown_timer;
uint32 _randomState;
LoadingScreenState *_loadingScreenState;
// input
bool _leftMouseButtonUp;
bool _leftMouseButtonDown;
bool _rightMouseButtonUp;
bool _iKeyUp;
bool _downKeyDown;
bool _downKeyUp;
bool _upKeyDown;
bool _upKeyUp;
bool _enterKeyUp;
bool _leftKeyDown;
bool _leftKeyUp;
bool _rightKeyDown;
bool _rightKeyUp;
bool _wKeyDown;
bool _aKeyDown;
bool _sKeyDown;
bool _dKeyDown;
bool _oKeyDown;
bool _pKeyDown;
MouseWheel _mouseWheel;
bool _debugMode;
bool _isGamePaused;
bool _inMenu;
void (*_sceneUpdateFunction)();
void (*_vsyncUpdateFunction)();
protected:
bool hasFeature(EngineFeature f) const override;
public:
DragonsEngine(OSystem *syst, const DragonsGameDescription *desc);
~DragonsEngine();
void updateEvents();
Common::Error run() override;
Common::String getSavegameFilename(int num);
static Common::String getSavegameFilename(const Common::String &target, int num);
static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail = true);
Common::Error loadGameState(int slot) override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
void syncSoundSettings() override;
void updateActorSequences();
void setFlags(uint32 flags);
void clearFlags(uint32 flags);
uint32 getMultipleFlags(uint32 flags);
uint32 getAllFlags();
void setAllFlags(uint32 flags);
bool isFlagSet(uint32 flag);
bool isUnkFlagSet(uint32 flag);
void setUnkFlags(uint32 flags);
void clearUnkFlags(uint32 flags);
byte *getBackgroundPalette();
DragonINI *getINI(uint32 index);
uint16 getVar(uint16 offset);
void setVar(uint16 offset, uint16 value);
uint16 getCurrentSceneId() const;
void waitForFrames(uint16 numFrames);
void waitForFramesAllowSkip(uint16 numFrames);
void playOrStopSound(uint16 soundId);
void fadeFromBlack();
void fadeFromBlackExcludingFont();
void fadeFromBlack(uint32 flags);
void fadeToBlack();
void fadeToBlackExcludingFont();
void fadeToBlack(uint32 flags);
uint16 ipt_img_file_related();
void performAction();
void reset_screen_maybe();
void init();
void loadScene(uint16 sceneId);
void reset();
void runSceneUpdaterFunction();
void setSceneUpdateFunction(void (*newUpdateFunction)());
void clearSceneUpdateFunction();
void (*getSceneUpdateFunction())();
void setVsyncUpdateFunction(void (*newUpdateFunction)());
bool isVsyncUpdaterFunctionRunning();
void runVsyncUpdaterFunction();
bool isActionButtonPressed();
bool isLeftKeyPressed();
bool isRightKeyPressed();
bool isUpKeyPressed();
bool isDownKeyPressed();
bool isSquareButtonPressed();
bool isTriangleButtonPressed();
bool isCircleButtonPressed();
bool isCrossButtonPressed();
bool isL1ButtonPressed();
bool isR1ButtonPressed();
bool checkForActionButtonRelease();
bool checkForDownKeyRelease();
bool checkForUpKeyRelease();
bool checkForWheelUp();
bool checkForWheelDown();
bool isDebugMode();
uint16 getRand(uint16 max);
void setupPalette1();
bool isInMenu();
void loadingScreenUpdate();
void clearAllText();
//TODO this logic should probably go in its own class.
uint16 getBigFileTotalRecords();
uint32 getBigFileInfoTblFromDragonEXE();
uint32 getFontOffsetFromDragonEXE();
uint32 getSpeechTblOffsetFromDragonEXE();
uint32 getCutscenePaletteOffsetFromDragonEXE();
uint32 defaultResponseOffsetFromDragonEXE();
uint16 getCursorHandPointerSequenceID();
uint32 getMiniGame3StartingDialog();
uint32 getMiniGame3PickAHatDialog();
uint32 getMiniGame3DataOffset();
uint32 getDialogTextId(uint32 textId);
private:
bool savegame(const char *filename, const char *description);
bool loadgame(const char *filename);
void gameLoop();
void updateHandler();
void updatePathfindingActors();
void updatePaletteCycling();
void updateFlickerIdleAnimation();
void updateCamera();
uint32 calulateTimeLeft();
void wait();
uint16 getIniFromImg();
void runINIScripts();
void engineFlag0x20UpdateFunction();
bool isInputEnabled();
bool checkForInventoryButtonRelease();
void walkFlickerToObject();
void seedRandom(int32 seed);
uint32 shuffleRandState();
void initializeSound();
void SomeInitSound_fun_8003f64c();
void initSubtitleFlag();
void loadingScreen();
void mainMenu();
bool checkAudioVideoFiles();
bool validateAVFile(const char *filename);
uint32 getDialogTextIdGrb(uint32 textId);
uint32 getDialogTextIdDe(uint32 textId);
uint32 getDialogTextIdFr(uint32 textId);
};
DragonsEngine *getEngine();
} // End of namespace Dragons
#endif //DRAGONS_DRAGONS_H

View 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/>.
*
*/
#include "dragons/dragonvar.h"
#include "dragons/bigfile.h"
namespace Dragons {
DragonVAR::DragonVAR(BigfileArchive *bigfileArchive): _bigfileArchive(bigfileArchive), _data(nullptr) {
reset();
}
DragonVAR::~DragonVAR() {
delete _data;
}
uint16 DragonVAR::getVar(uint16 offset) {
assert(_data);
assert(offset < 15);
return READ_LE_UINT16(_data + offset * 2);
}
void DragonVAR::setVar(uint16 offset, uint16 value) {
assert(_data);
assert(offset < 15);
WRITE_LE_INT16(_data + offset * 2, value);
}
void DragonVAR::reset() {
delete _data;
uint32 size;
_data = _bigfileArchive->load("dragon.var", size);
assert(size == 30);
}
} // End of namespace Dragons

View File

@@ -0,0 +1,46 @@
/* 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 DRAGONS_DRAGONVAR_H
#define DRAGONS_DRAGONVAR_H
#include "common/scummsys.h"
namespace Dragons {
class BigfileArchive;
class DragonVAR {
private:
byte *_data;
BigfileArchive *_bigfileArchive;
public:
virtual ~DragonVAR();
DragonVAR(BigfileArchive *bigfileArchive);
void reset();
uint16 getVar(uint16 offset);
void setVar(uint16 offset, uint16 value);
};
} // End of namespace Dragons
#endif //DRAGONS_DRAGONVAR_H

270
engines/dragons/font.cpp Normal file
View File

@@ -0,0 +1,270 @@
/* 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/textconsole.h"
#include "dragons/bigfile.h"
#include "dragons/cursor.h"
#include "dragons/font.h"
#include "dragons/scene.h"
#include "dragons/screen.h"
#include "dragons/dragons.h"
namespace Dragons {
Font::Font(Common::SeekableReadStream &stream, uint32 mapSize, uint32 pixelOffset, uint32 pixelSize) {
_size = mapSize / 2;
_map = (uint16 *)malloc(mapSize);
if (!_map) {
error("Allocating memory for font map.");
}
for (uint i = 0; i < _size; i++) {
_map[i] = stream.readUint16LE();
}
_pixels = (byte *)malloc(pixelSize);
if (!_pixels) {
error("Allocating memory for font pixels.");
}
stream.seek(pixelOffset);
stream.read(_pixels, pixelSize);
_numChars = pixelSize / 64;
}
Font::~Font() {
free(_map);
free(_pixels);
}
uint16 Font::mapChar(uint16 in) {
return _map[in - _map[0x03] + 0x05];
}
Graphics::Surface *Font::render(uint16 *text, uint16 length) {
Graphics::Surface *surface = new Graphics::Surface();
surface->create(length * 8, 8, Graphics::PixelFormat::createFormatCLUT8());
renderToSurface(surface, 0, 0, text, length);
return surface;
}
void Font::renderToSurface(Graphics::Surface *surface, int16 x, int16 y, uint16 *text, uint16 length) {
if (x < 0 || y < 0 || x + length * 8 > surface->w || y + 8 > surface->h) {
return;
}
byte *startPixelOffset = (byte *)surface->getPixels() + y * surface->pitch + x * surface->format.bytesPerPixel;
for (int i = 0; i < length; i++) {
byte *pixels = startPixelOffset;
pixels += i * 8;
byte *data = _pixels + mapChar(text[i]) * 64;
for (int j = 0; j < 8; j++) {
memcpy(pixels, data, 8);
data += 8;
pixels += surface->pitch;
}
}
}
FontManager::FontManager(DragonsEngine *vm, Screen *screen, BigfileArchive *bigfileArchive): _vm(vm), _screen(screen), _numTextEntries(0) {
uint32 fileSize;
byte *data = bigfileArchive->load("fntfiles.dat", fileSize);
Common::SeekableReadStream *readStream = new Common::MemoryReadStream(data, fileSize, DisposeAfterUse::YES);
_fonts[0] = loadFont(0, *readStream);
_fonts[1] = loadFont(1, *readStream);
_fonts[2] = loadFont(2, *readStream);
delete readStream;
_dat_80086f48_fontColor_flag = 0;
_surface = new Graphics::Surface();
_surface->create(DRAGONS_SCREEN_WIDTH, DRAGONS_SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
clearText(); //clear backing surface.
_boxFontChr = bigfileArchive->load("boxfont.chr", fileSize);
}
FontManager::~FontManager() {
delete _fonts[0];
delete _fonts[1];
delete _fonts[2];
_surface->free();
delete _surface;
free(_boxFontChr);
}
void FontManager::addText(int16 x, int16 y, uint16 *text, uint16 length, uint8 fontType) {
assert(length < 1024);
assert(fontType < 4);
_fonts[fontType]->renderToSurface(_surface, x, y, text, length);
++_numTextEntries;
}
void FontManager::draw() {
if(_numTextEntries > 0) {
_screen->copyRectToSurface8bpp(*_surface, _screen->getPalette(2), 0, 0, Common::Rect(_surface->w, _surface->h), false, NORMAL);
}
}
void FontManager::clearText() {
_numTextEntries = 0;
_surface->fillRect(Common::Rect(_surface->w, _surface->h), 0);
}
Font *FontManager::loadFont(uint16 index, Common::SeekableReadStream &stream) {
Common::File fd;
if (!fd.open("dragon.exe")) {
error("Failed to open dragon.exe");
}
fd.seek(_vm->getFontOffsetFromDragonEXE());
fd.skip((index * 2) * 28);
fd.skip(16); //filename
uint32 mapOffset = fd.readUint32LE();
uint32 mapSize = fd.readUint32LE();
fd.skip(4); //unk
fd.skip(16); //filename
uint32 pixelsOffset = fd.readUint32LE();
uint32 pixelsSize = fd.readUint32LE();
fd.close();
stream.seek(mapOffset);
return new Font(stream, mapSize, pixelsOffset, pixelsSize);
}
void updatePalEntry(uint16 *pal, uint16 index, uint16 newValue) {
newValue = (uint16)(((uint16)newValue & 0x1f) << 10) | (uint16)(((uint16)newValue & 0x7c00) >> 10) |
(newValue & 0x3e0) | (newValue & 0x8000);
WRITE_LE_INT16(pal + index, newValue);
}
void FontManager::updatePalette() {
uint16 *palette_f2_font_maybe = (uint16 *)_screen->getPalette(2);
const uint16 cursor3 = 0x14a5 | 0x8000;
if (_vm->isInMenu() || _vm->isFlagSet(ENGINE_FLAG_200)) {
updatePalEntry(palette_f2_font_maybe, 3, cursor3); //TODO move this to palette initialisation
if (!_vm->isUnkFlagSet(ENGINE_UNK1_FLAG_1)) {
updatePalEntry(palette_f2_font_maybe, 16, cursor3);
} else {
updatePalEntry(palette_f2_font_maybe, 16, 0);
}
if (_vm->isUnkFlagSet(ENGINE_UNK1_FLAG_4) && _dat_80086f48_fontColor_flag != 0) {
updatePalEntry(palette_f2_font_maybe, 17, 0x421);
} else {
updatePalEntry(palette_f2_font_maybe, 17, 0xfff);
}
updatePalEntry(palette_f2_font_maybe, 18, 0x421);
updatePalEntry(palette_f2_font_maybe, 19, 0x3def);
updatePalEntry(palette_f2_font_maybe, 32, cursor3);
updatePalEntry(palette_f2_font_maybe, 49, 0xfff);
updatePalEntry(palette_f2_font_maybe, 1, 0x8000);
updatePalEntry(palette_f2_font_maybe, 34, 0x421);
updatePalEntry(palette_f2_font_maybe, 35, 0x3def);
updatePalEntry(palette_f2_font_maybe, 48, cursor3);
updatePalEntry(palette_f2_font_maybe, 50, 0x421);
updatePalEntry(palette_f2_font_maybe, 51, 0x3def);
//TODO WRITE_LE_INT16(&palette_f2_font_maybe[33], READ_LE_INT16(&palette_f0[_dat_80084f58 >> 8]) & 0x7fff); //_dat_80084f58 is set in ActuallyShowMessage()
updatePalEntry(palette_f2_font_maybe, 33, 0x3def); //temporarily put in standard gray
if (_vm->isUnkFlagSet(ENGINE_UNK1_FLAG_1)) {
updatePalEntry(palette_f2_font_maybe, 17, 0x3bee);
updatePalEntry(palette_f2_font_maybe, 33, 0x3bee);
updatePalEntry(palette_f2_font_maybe, 49, 0x3bee);
}
}
}
void FontManager::drawTextDialogBox(uint32 x1, uint32 y1, uint32 x2, uint32 y2) {
const uint16 kTileBaseIndex = 1;
const uint16 kTileIndexTop = kTileBaseIndex + 10;
const uint16 kTileIndexBottom = kTileBaseIndex + 16;
const uint16 kTileIndexLeft = kTileBaseIndex + 12;
const uint16 kTileIndexRight = kTileBaseIndex + 14;
const uint16 kTileIndexBackground = kTileBaseIndex + 13;
const uint16 kTileIndexTopLeft = kTileBaseIndex + 9;
const uint16 kTileIndexTopRight = kTileBaseIndex + 11;
const uint16 kTileIndexBottomLeft = kTileBaseIndex + 15;
const uint16 kTileIndexBottomRight = kTileBaseIndex + 17;
// Fill background
for (uint yc = y1 + 1; yc <= y2 - 1; ++yc) {
for (uint xc = x1 + 1; xc <= x2 - 1; ++xc) {
drawBoxChar(xc, yc, kTileIndexBackground);
}
}
// Fill top and bottom rows
for (uint xc = x1 + 1; xc <= x2 - 1; ++xc) {
drawBoxChar(xc, y1, kTileIndexTop);
drawBoxChar(xc, y2, kTileIndexBottom);
}
// Fill left and right columns
for (uint yc = y1 + 1; yc <= y2 - 1; ++yc) {
drawBoxChar(x1, yc, kTileIndexLeft);
drawBoxChar(x2, yc, kTileIndexRight);
}
// Fill corners
drawBoxChar(x1, y1, kTileIndexTopLeft);
drawBoxChar(x2, y1, kTileIndexTopRight);
drawBoxChar(x1, y2, kTileIndexBottomLeft);
drawBoxChar(x2, y2, kTileIndexBottomRight);
_numTextEntries++;
}
void FontManager::clearTextDialog(uint32 x1, uint32 y1, uint32 x2, uint32 y2) {
debug(3, "Clear text (%d,%d) -> (%d,%d)", x1, y1, x2, y2);
// assert(x1 > 0);
// assert(y1 > 0);
_surface->fillRect(Common::Rect((x1-1) * 8, (y1-1) * 8, (x2 + 1) * 8 + 1, (y2 + 1) * 8 + 1), 0);
if (_numTextEntries > 0) {
_numTextEntries--; //TODO need a better way to check if we should still draw the font surface.
}
}
void FontManager::drawBoxChar(uint32 x, uint32 y, uint8 tileIndex) {
byte *pixels = (byte *)_surface->getBasePtr(x * 8, y * 8);
byte *data = _boxFontChr + tileIndex * 64;
for (int j = 0; j < 8; j++) {
memcpy(pixels, data, 8);
data += 8;
pixels += _surface->pitch;
}
}
void FontManager::addAsciiText(int16 x, int16 y, const char *text, uint16 length, uint8 fontType) {
uint16 wText[41];
memset(wText, 0, sizeof(wText));
if (length > 40) {
length = 40;
}
for (int i = 0; i < length; i++) {
wText[i] = text[i] & 0xFFU;
}
addText(x, y, wText, length, fontType);
}
} // End of namespace Dragons

82
engines/dragons/font.h Normal file
View File

@@ -0,0 +1,82 @@
/* 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 DRAGONS_FONT_H
#define DRAGONS_FONT_H
#include "common/scummsys.h"
#include "common/stream.h"
#include "graphics/surface.h"
namespace Dragons {
class DragonsEngine;
class BigfileArchive;
class Screen;
class Font {
private:
uint32 _size;
uint16 *_map;
byte *_pixels;
uint32 _numChars;
public:
Font(Common::SeekableReadStream &stream, uint32 mapSize, uint32 pixelOffset, uint32 pixelSize);
~Font();
Graphics::Surface *render(uint16 *text, uint16 length);
void renderToSurface(Graphics::Surface *surface, int16 x, int16 y, uint16 *text, uint16 length);
private:
uint16 mapChar(uint16 in);
};
class FontManager {
public:
Font *_fonts[3];
private:
uint16 _dat_80086f48_fontColor_flag;
DragonsEngine *_vm;
Screen *_screen;
Graphics::Surface *_surface;
byte *_boxFontChr;
int _numTextEntries;
public:
FontManager(DragonsEngine *vm, Screen *screen, BigfileArchive *bigfileArchive);
~FontManager();
void addText(int16 x, int16 y, uint16 *text, uint16 length, uint8 fontType);
void addAsciiText(int16 x, int16 y, const char *text, uint16 length, uint8 fontType);
void draw();
void clearText();
void updatePalette();
void drawTextDialogBox(uint32 x1, uint32 y1, uint32 x2, uint32 y2);
void clearTextDialog(uint32 x1, uint32 y1, uint32 x2, uint32 y2);
private:
Font *loadFont(uint16 index, Common::SeekableReadStream &stream);
void drawBoxChar(uint32 x, uint32 y, uint8 tileIndex);
};
} // End of namespace Dragons
#endif //DRAGONS_FONT_H

View File

@@ -0,0 +1,444 @@
/* 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 "dragons/actor.h"
#include "dragons/dragons.h"
#include "dragons/dragonini.h"
#include "dragons/background.h"
#include "dragons/inventory.h"
#include "dragons/bag.h"
#include "dragons/scene.h"
#include "dragons/talk.h"
#include "dragons/screen.h"
namespace Dragons {
static const struct {
int x, y;
} positionTable[4] = {
{ 2, 0 },
{ 206, 0 },
{ 2, 158 },
{ 206, 158 }
};
static const int16 bagBounceTable[4] = {
-5, -0xa, -5, 0
};
static const int16 invXPosTable[41] = {
0x0080, 0x00a0, 0x00c0, 0x0060, 0x0080, 0x00a0, 0x00c0, 0x00e0,
0x0100, 0x0020, 0x0040, 0x0060, 0x0080, 0x00a0, 0x00c0, 0x00e0,
0x0100, 0x0020, 0x0040, 0x0060, 0x0080, 0x00a0, 0x00c0, 0x00e0,
0x0100, 0x0020, 0x0040, 0x0060, 0x0080, 0x00a0, 0x00c0, 0x00e0,
0x0100, 0x0020, 0x0040, 0x0060, 0x0080, 0x00a0, 0x00c0, 0x00e0,
0x0100
};
static const int16 invYPosTable[41] = {
0x0028, 0x0028, 0x0028, 0x0040, 0x0040, 0x0040, 0x0040, 0x0040,
0x0040, 0x0058, 0x0058, 0x0058, 0x0058, 0x0058, 0x0058, 0x0058,
0x0058, 0x0070, 0x0070, 0x0070, 0x0070, 0x0070, 0x0070, 0x0070,
0x0070, 0x0088, 0x0088, 0x0088, 0x0088, 0x0088, 0x0088, 0x0088,
0x0088, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0, 0x00a0,
0x00a0
};
Inventory::Inventory(DragonsEngine *vm) : _vm(vm) {
_state = Closed;
_sequenceId = 0;
_screenPositionIndex = 0;
_previousState = Closed;
_bag = nullptr;
_actor = nullptr;
_inventionBookPrevSceneUpdateFunc = nullptr;
_inventionBookPrevSceneId = 0;
_inventionBookPrevFlickerINISceneId = 0;
_inventionBookPrevFlickerINIPosition = Common::Point(0, 0);
}
void Inventory::init(ActorManager *actorManager, BackgroundResourceLoader *backgroundResourceLoader, Bag *bag, DragonINIResource *dragonIniResource) {
_actor = actorManager->loadActor(1, 1); //Load inventory
_actor->_x_pos = 2;
_actor->_y_pos = 0;
_actor->_priorityLayer = 6;
_actor->_flags = 0;
_actor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
_actor->updateSequence(0);
_actor->_flags |= (ACTOR_FLAG_40 | Dragons::ACTOR_FLAG_80 | Dragons::ACTOR_FLAG_100 |
ACTOR_FLAG_200);
_sequenceId = 0;
_state = Closed;
_previousState = Closed;
_bag = bag;
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
actorManager->loadActor(0, i + ACTOR_INVENTORY_OFFSET); // TODO need to share resource between inventory item actors.
}
loadInventoryItemsFromSave();
}
void Inventory::loadScene(uint32 sceneId) {
if (_state == Closed) {
_sequenceId = _vm->isFlagSet(ENGINE_FLAG_400000) ? 1 : 0;
}
if (_sequenceId == 0 && _vm->getVar(7) == 1) {
_actor->updateSequence(5);
} else {
_actor->updateSequence(_sequenceId);
}
setPositionFromSceneId(sceneId);
}
void Inventory::updateVisibility() {
_actor->_priorityLayer = _vm->isFlagSet(ENGINE_FLAG_10) ? (int16)6 : (int16)0;
}
Common::Point Inventory::getPosition() {
return Common::Point(positionTable[_screenPositionIndex].x, positionTable[_screenPositionIndex].y);
}
void Inventory::setActorFlag400() {
_actor->setFlag(ACTOR_FLAG_400);
}
void Inventory::clearActorFlag400() {
_actor->clearFlag(ACTOR_FLAG_400);
}
void Inventory::setPriority(uint16 priority) {
_actor->_priorityLayer = priority;
}
void Inventory::setActorSequenceId(int32 sequenceId) {
if (isActorSet()) {
_actor->_sequenceID = sequenceId;
}
}
void Inventory::updateActorSequenceId(int32 sequenceId) {
if (isActorSet()) {
_actor->updateSequence(sequenceId);
}
}
void Inventory::resetSequenceId() {
_actor->updateSequence(_sequenceId);
}
void Inventory::openInventory() {
//TODO 0x80030e8c
_sequenceId = 4;
if (!_vm->isFlagSet(ENGINE_FLAG_400000)) {
_sequenceId = 2;
}
_actor->updateSequence(_sequenceId);
_screenPositionIndex = 1;
_actor->_x_pos = positionTable[_screenPositionIndex].x;
if ((_sequenceId == 0) || (_sequenceId == 2)) {
_actor->_x_pos = positionTable[_screenPositionIndex].x + 0x32;
}
_actor->_y_pos = positionTable[_screenPositionIndex].y;
animateBagIn();
//TODO 0x800310e0 update cursor position.
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
Actor *item = _vm->_actorManager->getActor(i + ACTOR_INVENTORY_OFFSET);
item->_x_pos = item->_walkDestX = invXPosTable[i] + 0x10;
item->_y_pos = item->_walkDestY = invYPosTable[i] + 0xc;
if (_inventoryItemTbl[i]) {
item->_flags = 0; //clear all flags
item->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
item->_priorityLayer = 0;
item->updateSequence(_vm->getINI(_inventoryItemTbl[i] - 1)->inventorySequenceId * 2 + 10);
item->setFlag(ACTOR_FLAG_200);
item->setFlag(ACTOR_FLAG_100);
item->setFlag(ACTOR_FLAG_80);
item->setFlag(ACTOR_FLAG_40);
item->_priorityLayer = 6;
}
}
}
void Inventory::animateBagIn() {
_vm->clearFlags(ENGINE_FLAG_8);
_vm->setFlags(ENGINE_FLAG_80);
Common::Point pos = _bag->getPosition();
pos.y = -228;
int16 accel = 8;
// Drop bag down into position.
while (pos.y < 0) {
pos.y += accel;
_bag->updatePosition(pos);
_vm->waitForFrames(1);
accel += 2;
}
_vm->playOrStopSound(0x8001);
// Shake bag at the end.
for (int i = 0; i < 4; i++) {
pos.y = bagBounceTable[i];
_bag->updatePosition(pos);
_vm->waitForFrames(2);
}
_vm->setFlags(ENGINE_FLAG_8);
_vm->setFlags(ENGINE_FLAG_10);
}
void Inventory::animateBagOut() {
_vm->playOrStopSound(0x8000);
Common::Point pos = _bag->getPosition();
if (pos.y != 0xc8) {
for (; pos.y != 0xc8; pos.y += 0x19) {
_bag->updatePosition(pos);
_vm->waitForFrames(1);
}
}
_vm->clearFlags(ENGINE_FLAG_80);
}
void Inventory::closeInventory() {
_vm->_actorManager->clearActorFlags(ACTOR_INVENTORY_OFFSET);
_screenPositionIndex = _vm->_dragonRMS->getInventoryPosition(_vm->getCurrentSceneId());
if (!_vm->isFlagSet(ENGINE_FLAG_400000)) {
_sequenceId = 0;
} else {
if (_previousState == InventionBookOpen) {
_sequenceId = 3;
} else {
_sequenceId = 1;
}
}
_actor->updateSequence(_sequenceId);
_actor->_x_pos = positionTable[_screenPositionIndex].x;
if (((_sequenceId == 0) || (_sequenceId == 2)) && ((_screenPositionIndex == 1 || (_screenPositionIndex == 3)))) {
_actor->_x_pos += 0x32;
}
_actor->_y_pos = positionTable[_screenPositionIndex].y;
animateBagOut();
}
void Inventory::draw() {
if (_bag) {
_bag->draw();
}
}
uint16 Inventory::getIniAtPosition(int16 x, int16 y) {
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
if (_inventoryItemTbl[i]) {
Actor *item = _vm->_actorManager->getActor(i + ACTOR_INVENTORY_OFFSET);
if (item->_x_pos - 0x10 <= x && x < item->_x_pos + 0x10
&& item->_y_pos - 0xc <= y && y < item->_y_pos + 0xc) {
return _inventoryItemTbl[i];
}
}
}
return 0;
}
void Inventory::loadInventoryItemsFromSave() {
memset(_inventoryItemTbl, 0, sizeof(_inventoryItemTbl));
int j = 0;
for (int i = 0; i < _vm->_dragonINIResource->totalRecords() && j < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
DragonINI *ini = _vm->_dragonINIResource->getRecord(i);
if (ini->sceneId == 1) {
_inventoryItemTbl[j++] = i + 1;
}
}
}
void Inventory::openInventionBook() {
_inventionBookPrevSceneUpdateFunc = _vm->getSceneUpdateFunction();
_vm->clearSceneUpdateFunction();
_vm->fadeToBlack();
_sequenceId = 2;
_actor->updateSequence(2);
_inventionBookPrevSceneId = _vm->getCurrentSceneId();
DragonINI *flicker = _vm->_dragonINIResource->getFlickerRecord();
if (flicker && flicker->actor) {
_inventionBookPrevFlickerINISceneId = flicker->sceneId;
_inventionBookPrevFlickerINIPosition = Common::Point(flicker->actor->_x_pos, flicker->actor->_y_pos);
flicker->sceneId = 0;
}
_vm->_scene->setSceneId(2);
_vm->_scene->loadScene(2, 0);
}
void Inventory::closeInventionBook() {
uint sceneId;
_vm->fadeToBlack();
DragonINI *flicker = _vm->_dragonINIResource->getFlickerRecord();
if (flicker) {
flicker->x = _inventionBookPrevFlickerINIPosition.x;
flicker->y = _inventionBookPrevFlickerINIPosition.y;
flicker->sceneId = _inventionBookPrevFlickerINISceneId;
}
_vm->_scene->setSceneId(_inventionBookPrevSceneId);
_sequenceId = 0;
setActorSequenceId(0);
setPositionFromSceneId(_inventionBookPrevSceneId);
sceneId = _vm->_scene->getSceneId();
if (((((sceneId == 0x23) || (sceneId == 0x2d)) || (sceneId == 0x2e)) || ((sceneId == 0x31 || (sceneId == 0x32)))) || (sceneId == 0x28)) {
if ((uint)_vm->_scene->getSceneId() == 0x27) {
_vm->getINI(0x206)->sceneId = 0;
}
} else {
if (sceneId != 0x27) {
if (sceneId != 0x1c && sceneId != 0x1d && sceneId != 0x21) {
_vm->_scene->loadScene(sceneId | 0x8000u, 0x1e);
_vm->setSceneUpdateFunction(_inventionBookPrevSceneUpdateFunc);
return;
}
if ((uint)_vm->_scene->getSceneId() == 0x27) {
_vm->getINI(0x206)->sceneId = 0;
}
} else {
_vm->getINI(0x206)->sceneId = 0;
}
}
_vm->_scene->loadScene(_vm->_scene->getSceneId(), 0x1e);
_vm->setSceneUpdateFunction(_inventionBookPrevSceneUpdateFunc);
}
void Inventory::setPositionFromSceneId(uint32 sceneId) {
_screenPositionIndex = _vm->_dragonRMS->getInventoryPosition(sceneId);
_actor->_x_pos = positionTable[_screenPositionIndex].x;
if ((_sequenceId == 0 || _sequenceId == 2) && (_screenPositionIndex == 1 || _screenPositionIndex == 3)) {
_actor->_x_pos += 0x32;
}
_actor->_y_pos = positionTable[_screenPositionIndex].y;
}
bool Inventory::addItem(uint16 initId) {
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
if (_inventoryItemTbl[i] == 0) {
_inventoryItemTbl[i] = initId;
return true;
}
}
return false;
}
Actor *Inventory::getInventoryItemActor(uint16 iniId) {
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
if (_inventoryItemTbl[i] == iniId) {
return _vm->_actorManager->getActor(i + ACTOR_INVENTORY_OFFSET);
}
}
error("getInventoryItemActor(%d) not found", iniId);
}
void Inventory::replaceItem(uint16 existingIniId, uint16 newIniId) {
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
if (_inventoryItemTbl[i] == existingIniId) {
_inventoryItemTbl[i] = newIniId;
return;
}
}
}
bool Inventory::addItemIfPositionIsEmpty(uint16 iniId, uint16 x, uint16 y) {
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
Actor *actor = _vm->_actorManager->getActor(i + ACTOR_INVENTORY_OFFSET);
if ((((actor->_x_pos - 0x10 <= x) &&
(x < actor->_x_pos + 0x10)) &&
(actor->_y_pos - 0xc <= y)) &&
(y < actor->_y_pos + 0xc)) {
_inventoryItemTbl[i] = iniId;
return true;
}
}
return false;
}
bool Inventory::clearItem(uint16 iniId) {
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
if (_inventoryItemTbl[i] == iniId) {
_inventoryItemTbl[i] = 0;
return true;
}
}
return false;
}
void Inventory::inventoryMissing() {
bool flag8Set;
uint32 textIndex;
static uint16 counter = 0;
DragonINI *flicker = _vm->_dragonINIResource->getFlickerRecord();
if (flicker->actor != nullptr) {
flicker->actor->clearFlag(ACTOR_FLAG_10);
if ((_vm->getCurrentSceneId() != 0x2e) || (flicker->actor->_resourceID != 0x91)) {
flicker->actor->setFlag(ACTOR_FLAG_4);
}
}
flag8Set = _vm->isFlagSet(ENGINE_FLAG_8);
_vm->clearFlags(ENGINE_FLAG_8);
if (counter == 0) {
textIndex = 0x114FA; //Hey! My bag is missing!
} else {
textIndex = 0x11538; //The Chancellor snaked my bag!
}
counter = counter + 1;
_vm->_talk->talkFromIni(0, textIndex);
if (flag8Set) {
_vm->setFlags(ENGINE_FLAG_8);
}
}
void Inventory::setPreviousState() {
InventoryState tmpState = _state;
setState(_previousState);
_previousState = tmpState;
}
bool Inventory::hasItem(uint16 iniId) {
for (int i = 0; i < DRAGONS_MAX_INVENTORY_ITEMS; i++) {
if (_inventoryItemTbl[i] == iniId) {
return true;
}
}
return false;
}
} // End of namespace Dragons

121
engines/dragons/inventory.h Normal file
View File

@@ -0,0 +1,121 @@
/* 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 DRAGONS_INVENTORY_H
#define DRAGONS_INVENTORY_H
namespace Dragons {
class Actor;
class ActorManager;
class BackgroundResourceLoader;
class Background;
class Bag;
class DragonINIResource;
#define DRAGONS_MAX_INVENTORY_ITEMS 0x29
#define ACTOR_INVENTORY_OFFSET 0x17
enum InventoryState {
Closed = 0,
InventoryOpen = 1,
InventionBookOpen = 2
};
class Inventory {
public:
InventoryState _previousState;
private:
DragonsEngine *_vm;
int32 _sequenceId;
int16 _screenPositionIndex;
Actor *_actor;
InventoryState _state;
Bag *_bag;
void (*_inventionBookPrevSceneUpdateFunc)();
uint16 _inventionBookPrevSceneId;
uint16 _inventionBookPrevFlickerINISceneId;
Common::Point _inventionBookPrevFlickerINIPosition;
uint16 _inventoryItemTbl[DRAGONS_MAX_INVENTORY_ITEMS];
public:
Inventory(DragonsEngine *vm);
void init(ActorManager *actorManager, BackgroundResourceLoader *backgroundResourceLoader, Bag *bag, DragonINIResource *dragonIniResource);
void loadScene(uint32 sceneId);
bool isActorSet() { return true; }
int32 getSequenceId() {
return _sequenceId;
}
void setActorSequenceId(int32 sequenceId);
void updateActorSequenceId(int32 sequenceId);
void resetSequenceId();
InventoryState getState() { return _state; }
void setState(InventoryState newState) { _state = newState; }
void setPreviousState();
int16 getPositionIndex() { return _screenPositionIndex; }
Common::Point getPosition();
bool isOpen() {
return _state != Closed;
}
void close() { _state = Closed; }
void updateVisibility();
void setActorFlag400();
void clearActorFlag400();
void setPriority(uint16 priority);
void openInventory();
void closeInventory();
void draw();
uint16 getIniAtPosition(int16 x, int16 y);
void loadInventoryItemsFromSave();
void openInventionBook();
void closeInventionBook();
bool addItem(uint16 iniId);
bool addItemIfPositionIsEmpty(uint16 iniId, uint16 x, uint16 y);
void replaceItem(uint16 existingIniId, uint16 newIniId);
bool clearItem(uint16 iniId);
bool hasItem(uint16 iniId);
Actor *getInventoryItemActor(uint16 iniId);
void inventoryMissing();
private:
void setPositionFromSceneId(uint32 sceneId);
void animateBagIn();
void animateBagOut();
};
} // End of namespace Dragons
#endif //DRAGONS_INVENTORY_H

View File

@@ -0,0 +1,235 @@
/* 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 "dragons/dragons.h"
#include "engines/advancedDetector.h"
#include "common/savefile.h"
#include "common/system.h"
#include "common/translation.h"
#include "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
#include "base/plugins.h"
class DragonsMetaEngine : public AdvancedMetaEngine<Dragons::DragonsGameDescription> {
public:
const char *getName() const override {
return "dragons";
}
bool hasFeature(MetaEngineFeature f) const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const Dragons::DragonsGameDescription *desc) const override;
int getMaximumSaveSlot() const override;
SaveStateList listSaves(const char *target) const override;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
bool removeSaveState(const char *target, int slot) const override;
Common::KeymapArray initKeymaps(const char *target) const override;
};
bool DragonsMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsListSaves) ||
(f == kSupportsDeleteSave) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSimpleSavesNames) ||
(f == kSavesSupportCreationDate);
}
bool DragonsMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
return g_system->getSavefileManager()->removeSavefile(fileName);
}
int DragonsMetaEngine::getMaximumSaveSlot() const {
return 999;
}
SaveStateList DragonsMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Dragons::SaveHeader header;
Common::String pattern = target;
pattern += ".###";
Common::StringArray filenames = saveFileMan->listSavefiles(pattern.c_str());
SaveStateList saveList;
for (const auto &filename : filenames) {
// Obtain the last 3 digits of the filename, since they correspond to the save slot
int slotNum = atoi(filename.c_str() + filename.size() - 3);
if (slotNum >= 0 && slotNum <= 999) {
Common::InSaveFile *in = saveFileMan->openForLoading(filename.c_str());
if (in) {
if (Dragons::DragonsEngine::readSaveHeader(in, header) == Dragons::kRSHENoError) {
saveList.push_back(SaveStateDescriptor(this, slotNum, header.description));
}
delete in;
}
}
}
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
SaveStateDescriptor DragonsMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String filename = Dragons::DragonsEngine::getSavegameFilename(target, slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
if (in) {
Dragons::SaveHeader header;
Dragons::kReadSaveHeaderError error;
error = Dragons::DragonsEngine::readSaveHeader(in, header, false);
delete in;
if (error == Dragons::kRSHENoError) {
SaveStateDescriptor desc(this, slot, header.description);
desc.setThumbnail(header.thumbnail);
desc.setSaveDate(header.saveDate & 0xFFFF, (header.saveDate >> 16) & 0xFF, (header.saveDate >> 24) & 0xFF);
desc.setSaveTime((header.saveTime >> 16) & 0xFF, (header.saveTime >> 8) & 0xFF);
desc.setPlayTime(header.playTime * 1000);
return desc;
}
}
return SaveStateDescriptor();
}
Common::Error DragonsMetaEngine::createInstance(OSystem *syst, Engine **engine, const Dragons::DragonsGameDescription *gd) const {
const char* urlForRequiredDataFiles = "https://wiki.scummvm.org/index.php?title=Blazing_Dragons#Required_data_files";
switch (gd->gameId) {
case Dragons::kGameIdDragons:
*engine = new Dragons::DragonsEngine(syst, gd);
break;
case Dragons::kGameIdDragonsBadExtraction:
GUIErrorMessageWithURL(Common::U32String::format(_("Error: It appears that the game data files were extracted incorrectly.\n\nYou should only extract STR and XA files using the special method. The rest should be copied normally from your game CD.\n\n See %s"), urlForRequiredDataFiles), urlForRequiredDataFiles);
break;
default:
return Common::kUnsupportedGameidError;
}
return Common::kNoError;
}
Common::KeymapArray DragonsMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "dragons", "Blazing Dragons");
Action *act;
act = new Action(kStandardActionLeftClick, _("Action"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionSelect);
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
engineKeyMap->addAction(act);
act = new Action("CHANGECOMMAND", _("Change command"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionChangeCommand);
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
engineKeyMap->addAction(act);
act = new Action("INVENTORY", _("Inventory"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionInventory);
act->addDefaultInputMapping("i");
engineKeyMap->addAction(act);
act = new Action("ENTER", _("Enter"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionEnter);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("KP_ENTER");
engineKeyMap->addAction(act);
act = new Action(kStandardActionMoveUp, _("Up"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionUp);
act->addDefaultInputMapping("UP");
act->addDefaultInputMapping("JOY_UP");
engineKeyMap->addAction(act);
act = new Action(kStandardActionMoveDown, _("Down"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionDown);
act->addDefaultInputMapping("DOWN");
act->addDefaultInputMapping("JOY_DOWN");
engineKeyMap->addAction(act);
act = new Action(kStandardActionMoveLeft, _("Left"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionLeft);
act->addDefaultInputMapping("LEFT");
act->addDefaultInputMapping("JOY_LEFT");
engineKeyMap->addAction(act);
act = new Action(kStandardActionMoveRight, _("Right"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionRight);
act->addDefaultInputMapping("RIGHT");
act->addDefaultInputMapping("JOY_RIGHT");
engineKeyMap->addAction(act);
act = new Action("SQUARE", _("Square"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionSquare);
act->addDefaultInputMapping("a");
act->addDefaultInputMapping("JOY_X");
engineKeyMap->addAction(act);
act = new Action("TRIANGLE", _("Triangle"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionTriangle);
act->addDefaultInputMapping("w");
act->addDefaultInputMapping("JOY_Y");
engineKeyMap->addAction(act);
act = new Action("CIRCLE", _("Circle"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionCircle);
act->addDefaultInputMapping("d");
act->addDefaultInputMapping("JOY_B");
engineKeyMap->addAction(act);
act = new Action("CROSS", _("Cross"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionCross);
act->addDefaultInputMapping("s");
act->addDefaultInputMapping("JOY_A");
engineKeyMap->addAction(act);
act = new Action("L1", _("Left shoulder"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionL1);
act->addDefaultInputMapping("o");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
engineKeyMap->addAction(act);
act = new Action("R1", _("Right shoulder"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionR1);
act->addDefaultInputMapping("p");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
engineKeyMap->addAction(act);
act = new Action("DEBUGGFX", _("Debug graphics"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionDebugGfx);
act->addDefaultInputMapping("TAB");
engineKeyMap->addAction(act);
act = new Action("QUIT", _("Quit game"));
act->setCustomEngineActionEvent(Dragons::kDragonsActionQuit);
act->addDefaultInputMapping("C+q");
engineKeyMap->addAction(act);
return Keymap::arrayOf(engineKeyMap);
}
#if PLUGIN_ENABLED_DYNAMIC(DRAGONS)
REGISTER_PLUGIN_DYNAMIC(DRAGONS, PLUGIN_TYPE_ENGINE, DragonsMetaEngine);
#else
REGISTER_PLUGIN_STATIC(DRAGONS, PLUGIN_TYPE_ENGINE, DragonsMetaEngine);
#endif

View File

@@ -0,0 +1,185 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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 "common/stream.h"
#include "audio/midiparser.h"
#include "audio/soundfont/rawfile.h"
#include "audio/soundfont/vab/vab.h"
#include "audio/soundfont/vgmcoll.h"
#include "midimusicplayer.h"
namespace Dragons {
MidiMusicPlayer::MidiMusicPlayer(BigfileArchive *bigFileArchive): _midiDataSize(0) {
_midiData = nullptr;
MidiPlayer::createDriver(MDT_PREFER_FLUID | MDT_SUPPLIED_SOUND_FONT | MDT_MIDI);
if (_driver->acceptsSoundFontData()) {
_driver->setEngineSoundFont(loadSoundFont(bigFileArchive));
} else {
//If the selected driver doesn't support loading soundfont we should assume we got a fluid Synth V1 and reload
delete _driver;
MidiPlayer::createDriver();
}
int ret = _driver->open();
if (ret == 0) {
if (_nativeMT32)
_driver->sendMT32Reset();
else
_driver->sendGMReset();
_driver->setTimerCallback(this, &timerCallback);
}
}
MidiMusicPlayer::~MidiMusicPlayer() {
if (isPlaying()) {
stop();
}
}
void MidiMusicPlayer::playSong(Common::SeekableReadStream *seqData) {
Common::StackLock lock(_mutex);
if (isPlaying()) {
stop();
}
if (seqData->readUint32LE() != MKTAG('S', 'E', 'Q', 'p'))
error("Failed to find SEQp tag");
// Make sure we don't have a SEP file (with multiple SEQ's inside)
if (seqData->readUint32BE() != 1)
error("Can only play SEQ files, not SEP");
uint16 ppqn = seqData->readUint16BE();
uint32 tempo = seqData->readUint16BE() << 8;
tempo |= seqData->readByte();
/* uint16 beat = */ seqData->readUint16BE();
// SEQ is directly based on SMF and we'll use that to our advantage here
// and convert to SMF and then use the SMF MidiParser.
// Calculate the SMF size we'll need
uint32 dataSize = seqData->size() - 15;
uint32 actualSize = dataSize + 7 + 22;
// Resize the buffer if necessary
byte *midiData = resizeMidiBuffer(actualSize);
// Now construct the header
WRITE_BE_UINT32(midiData, MKTAG('M', 'T', 'h', 'd'));
WRITE_BE_UINT32(midiData + 4, 6); // header size
WRITE_BE_UINT16(midiData + 8, 0); // type 0
WRITE_BE_UINT16(midiData + 10, 1); // one track
WRITE_BE_UINT16(midiData + 12, ppqn);
WRITE_BE_UINT32(midiData + 14, MKTAG('M', 'T', 'r', 'k'));
WRITE_BE_UINT32(midiData + 18, dataSize + 7); // SEQ data size + tempo change event size
// Add in a fake tempo change event
WRITE_BE_UINT32(midiData + 22, 0x00FF5103); // no delta, meta event, tempo change, param size = 3
WRITE_BE_UINT16(midiData + 26, tempo >> 8);
midiData[28] = tempo & 0xFF;
// Now copy in the rest of the events
seqData->read(midiData + 29, dataSize);
MidiParser *parser = MidiParser::createParser_SMF();
if (parser->loadMusic(midiData, actualSize)) {
parser->setTrack(0);
parser->setMidiDriver(this);
parser->setTimerRate(getBaseTempo());
parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
_parser = parser;
_isLooping = true;
_isPlaying = true;
} else {
delete parser;
}
}
byte *MidiMusicPlayer::resizeMidiBuffer(uint32 desiredSize) {
if (_midiData == nullptr) {
_midiData = (byte *)malloc(desiredSize);
_midiDataSize = desiredSize;
} else {
if (desiredSize > _midiDataSize) {
_midiData = (byte *)realloc(_midiData, desiredSize);
_midiDataSize = desiredSize;
}
}
return _midiData;
}
void MidiMusicPlayer::setVolume(int volume) {
// _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume); TODO do we need this?
MidiPlayer::setVolume(volume);
}
void MidiMusicPlayer::sendToChannel(byte channel, uint32 b) {
if (!_channelsTable[channel]) {
_channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
// If a new channel is allocated during the playback, make sure
// its volume is correctly initialized.
if (_channelsTable[channel])
_channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255);
}
if (_channelsTable[channel])
_channelsTable[channel]->send(b);
}
Common::SeekableReadStream *MidiMusicPlayer::loadSoundFont(BigfileArchive *bigFileArchive) {
uint32 headSize, bodySize;
byte *headData = bigFileArchive->load("musx.vh", headSize);
byte *bodyData = bigFileArchive->load("musx.vb", bodySize);
byte *vabData = (byte *)malloc(headSize + bodySize);
memcpy(vabData, headData, headSize);
memcpy(vabData + headSize, bodyData, bodySize);
free(headData);
free(bodyData);
MemFile *memFile = new MemFile(vabData, headSize + bodySize);
debug("Loading soundfont2 from musx vab file.");
Vab *vab = new Vab(memFile, 0);
vab->LoadVGMFile();
VGMColl vabCollection;
SF2File *file = vabCollection.CreateSF2File(vab);
const byte *bytes = (const byte *)file->SaveToMem();
uint32 size = file->GetSize();
delete file;
delete vab;
delete memFile;
return new Common::MemoryReadStream(bytes, size, DisposeAfterUse::YES);
}
} // End of namespace Dragons

View 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 DRAGONS_MIDIMUSICPLAYER_H
#define DRAGONS_MIDIMUSICPLAYER_H
#include "audio/midiplayer.h"
#include "dragons/vabsound.h"
#include "dragons/bigfile.h"
namespace Dragons {
class MidiMusicPlayer : public Audio::MidiPlayer {
private:
uint32 _midiDataSize;
public:
MidiMusicPlayer(BigfileArchive *bigFileArchive);
~MidiMusicPlayer();
void setVolume(int volume) override;
void playSong(Common::SeekableReadStream *seqData);
// The original sets the "sequence timing" to 109 Hz, whatever that
// means. The default is 120.
uint32 getBaseTempo() { return _driver ? (109 * _driver->getBaseTempo()) / 120 : 0; }
void sendToChannel(byte channel, uint32 b) override;
private:
byte *resizeMidiBuffer(uint32 desiredSize);
Common::SeekableReadStream *loadSoundFont(BigfileArchive *bigFileArchive);
};
} // End of namespace Dragons
#endif //DRAGONS_MIDIMUSICPLAYER_H

View File

@@ -0,0 +1,868 @@
/* 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 "dragons/minigame1.h"
#include "dragons/actor.h"
#include "dragons/dragons.h"
#include "dragons/dragonini.h"
#include "dragons/talk.h"
#include "dragons/screen.h"
namespace Dragons {
#define DAT_80063a48 0x12d
#define DAT_80063a40 0x12f
Minigame1::Minigame1(DragonsEngine *vm) : _vm(vm) {}
void Minigame1::run() {
const uint32 dialogIdTbl[17] = {
0x21312, 0x2134C, 0x21386, 0x213C0,
0x213E2, 0x21428, 0x2146C, 0x214B4,
0x214E4, 0x21514, 0x21540, 0x21590,
0x215E2, 0x2164E, 0x216AA, 0x216D2,
0x217D8
};
/* WARNING: Could not reconcile some variable overlaps */
/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */
Actor *uVar1;
short sVar2;
bool bVar3;
uint16 uVar5;
uint savedEngineFlags;
uint16 flickerXPos;
uint16 auStack1008 [200];
DragonINI *originalFlickerIniID;
uint16 local_25c;
uint16 local_25a = 0;
uint16 catFieldE_scaleMaybe;
uint16 hitCounter;
uint16 local_254;
short local_252;
short local_250;
uint16 local_246;
uint16 local_242;
uint16 local_240;
uint16 local_23e;
short local_23c = 0;
short local_23a;
short local_238;
short gameState;
uint16 local_234 = 0;
short local_232 = 0;
uint16 local_22e;
uint16 local_22c;
Actor *targetActorIdTbl [5];
short local_21e;
uint16 auStack536 [72];
short local_188 [8];
uint16 auStack378 [4];
uint16 i;
uint16 local_16e;
short local_16a;
uint32 local_168;
uint16 auStack352 [24];
uint16 local_130 [10];
int32 local_118 [22];
uint32 local_c0 [22];
uint16 actorSequenceTimerStartValue;
Actor *catActor;
Actor *pusherActor;
Actor *flickerActor;
Actor *wheelsActor;
Actor *dustSpriteActor;
Common::File *fd = new Common::File();
if (!fd->open("arc1.bin")) {
error("Failed to open arc1.bin");
}
for (i = 0; i < 0x42; i++) {
auStack536[i] = fd->readUint16LE();
}
fd->seek(132);
for (i = 0; i < 0x18; i++) {
auStack352[i] = fd->readUint16LE();
}
for (i = 0; i < 10; i++) {
local_130[i] = fd->readUint16LE();
}
fd->close();
delete fd;
// local_130._0_4_ = DAT_8008e940;
// local_130._4_4_ = DAT_8008e944;
// local_130._8_4_ = DAT_8008e948;
// local_130._12_4_ = DAT_8008e94c;
// local_130[8] = DAT_8008e950;
local_c0[0] = dialogIdTbl[0];
local_c0[1] = 0x1e;
local_c0[2] = dialogIdTbl[1];
local_c0[3] = 0x23;
local_c0[4] = dialogIdTbl[2];
local_c0[5] = 0x1e;
local_c0[6] = dialogIdTbl[3];
local_c0[7] = 0x1e;
local_c0[8] = dialogIdTbl[4];
local_c0[9] = 0x28;
local_c0[10] = dialogIdTbl[5];
local_c0[11] = 0x1e;
local_c0[12] = dialogIdTbl[6];
local_c0[13] = 0x28;
local_c0[14] = dialogIdTbl[7];
local_c0[15] = 0x23;
local_c0[16] = dialogIdTbl[8];
local_c0[17] = 0x23;
local_c0[18] = dialogIdTbl[9];
local_c0[19] = 0x1e;
local_c0[20] = dialogIdTbl[10];
local_c0[21] = 0x32;
memcpy(local_118, local_c0, 0x58);
local_c0[0] = dialogIdTbl[11];
local_c0[1] = 0x3c;
local_c0[2] = dialogIdTbl[12];
local_c0[3] = 0x3c;
local_c0[12] = dialogIdTbl[13];
local_c0[13] = 0x3c;
local_c0[8] = dialogIdTbl[13];
local_c0[9] = 0x3c;
local_c0[14] = dialogIdTbl[14];
local_c0[15] = 0x3c;
local_c0[10] = dialogIdTbl[14];
local_c0[11] = 0x3c;
local_c0[4] = dialogIdTbl[13];
local_c0[5] = 0x3c;
local_c0[6] = dialogIdTbl[14];
local_c0[7] = 0x3c;
originalFlickerIniID = _vm->_dragonINIResource->getFlickerRecord();
originalFlickerIniID->actor->setFlag(ACTOR_FLAG_100);
originalFlickerIniID->actor->_priorityLayer = 0;
savedEngineFlags = _vm->getMultipleFlags(ENGINE_FLAG_8 | ENGINE_FLAG_10 | ENGINE_FLAG_20 | ENGINE_FLAG_80);
_vm->clearFlags(ENGINE_FLAG_8);
_vm->clearFlags(ENGINE_FLAG_10);
_vm->clearFlags(ENGINE_FLAG_20);
_vm->clearFlags(ENGINE_FLAG_80);
_vm->_dragonINIResource->setFlickerRecord(_vm->getINI(DAT_80063a40 - 1));
flickerActor = _vm->getINI(DAT_80063a40 - 1)->actor;
flickerActor->_flags = flickerActor->_flags | 0x380;
flickerActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
flickerActor->_priorityLayer = 4;
flickerActor->_direction = -1;
flickerActor->updateSequence(0x15);
hitCounter = 0;
local_254 = 0;
local_252 = 0;
flickerXPos = flickerActor->_x_pos;
local_25c = 0;
pusherActor = _vm->_actorManager->loadActor(0x26, 1, flickerXPos,
(int)(((uint)(uint16)flickerActor->_y_pos + 5) * 0x10000) >> 0x10);
// if (pusherActorId == -1) {
// ProbablyShowASCIIMessage(s_couldn't_alloc_pusher_8008e954, 2, 4, 0, 0xffffffff);
// }
pusherActor->_flags = pusherActor->_flags | 0x380;
pusherActor->_x_pos = flickerActor->_x_pos + -0xe;
pusherActor->_y_pos = flickerActor->_y_pos + 7;
pusherActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
pusherActor->_priorityLayer = 6;
wheelsActor = _vm->_actorManager->loadActor(7, 0x11, 0, 0);
// if (wheelsActorId == -1) {
// ProbablyShowASCIIMessage(s_couldn't_alloc_wheels_8008e96c, 2, 4, 0, 0xffffffff);
// }
wheelsActor->_flags = wheelsActor->_flags | 0x380;
wheelsActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
wheelsActor->_x_pos = flickerActor->_x_pos;
wheelsActor->_y_pos = flickerActor->_y_pos;
wheelsActor->_priorityLayer = 5;
wheelsActor->updateSequence(0x11);
local_242 = 0;
catActor = _vm->_actorManager->loadActor(7, 9, 0, 0);
// if (catActorId == -1) {
// ProbablyShowASCIIMessage(s_couldn't_alloc-cat_8008e984, 2, 4, 0, 0xffffffff);
// }
catActor->_flags = catActor->_flags | 0x380;
catActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
catActor->_priorityLayer = 0;
i = 0;
while (i < 3) {
targetActorIdTbl[(uint)i + 1] = _vm->_actorManager->loadActor(8, 1, 0, 0, 0);
// if (targetActorIdTbl[(uint)i + 1] == -1) {
// ProbablyShowASCIIMessage(s_couldn't_alloc_target!_8008e998, 2, 4, 0, 0xffffffff);
// }
targetActorIdTbl[(uint)i + 1]->_flags = targetActorIdTbl[(uint)i + 1]->_flags | 0x380;
targetActorIdTbl[(uint)i + 1]->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
auStack378[(uint)i] = 0;
//TODO FUN_80017010_update_actor_texture_maybe(1);
i = i + 1;
}
for (i = 0; i < 8; i++) {
local_188[i] = 0;
}
dustSpriteActor = _vm->_actorManager->loadActor(8, 8, 100, 100, 0);
// if (dustSpriteActorId == 0xffff) {
// ProbablyShowASCIIMessage(s_couldn't_alloc_dust_sprite!_8008e9b0, 2, 5, 0, 0xffffffff);
// }
dustSpriteActor->_flags = dustSpriteActor->_flags | 0x380;
dustSpriteActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
uVar1 = _vm->getINI(DAT_80063a48 - 1)->actor; //dragon_ini_pointer[DAT_80063a48 + -1].actorId;
local_21e = 0;
actorSequenceTimerStartValue = uVar1->_sequenceTimerMaxValue;
_vm->setFlags(ENGINE_FLAG_4000000);
local_23e = 0x3700;
local_23a = 0x100;
local_240 = 0x4a80;
local_238 = 0;
catFieldE_scaleMaybe = 0x30;
catActor->_y_pos = 0x6e;
catActor->_x_pos = 0x95;
catActor->_scale = 0x30;
catActor->_priorityLayer = 2;
catActor->updateSequence(0xb);
gameState = 5;
local_246 = 1;
bVar3 = false;
local_22e = 0;
local_22c = 0;
local_250 = 0;
LAB_8008fa78:
do {
do {
_vm->waitForFrames(1);
if ((local_250 != 0) && (local_250 = local_250 + -1, local_250 == 0)) {
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
}
if ((local_21e == 1) && (local_252 == 0)) {
uVar1->_sequenceTimerMaxValue = actorSequenceTimerStartValue;
}
if (local_21e != 0) {
local_21e = local_21e + -1;
}
switch (gameState) {
case 0:
break;
case 1: //cat in the catapult ready to fire.
if (local_252 == 0) {
if (local_246 != 8) {
local_246 = 0;
}
// iVar6 = IsButtonBeingPressed((uint)DAT_800728ac, 0);
if (!_vm->isActionButtonPressed()) {
if (local_25c == 0) {
if ((((flickerActor->_sequenceID != 0) &&
(flickerActor->_sequenceID != 5)) &&
(flickerActor->_sequenceID != 6)) ||
((flickerActor->_flags & 4) != 0)) {
flickerActor->updateSequence(0);
}
} else {
local_246 = 1;
bVar3 = false;
pusherActor->updateSequence(1);
gameState = 2;
if (local_25c < 0x14) {
local_25a = 1;
} else {
if (local_25c < 0x2d) {
local_25a = 2;
} else {
if (local_25c < 0x169) {
local_25a = 3;
}
}
}
}
local_25c = 0;
} else {
pusherActor->_x_pos = flickerActor->_x_pos + -0xe;
pusherActor->_y_pos = flickerActor->_y_pos + 7;
if (local_25c < 0x168) {
local_25c = local_25c + 1;
if (local_25c < 0x14) {
if (((pusherActor->_sequenceID != 4) &&
(pusherActor->_sequenceID != 2)) &&
(pusherActor->_sequenceID != 3)) {
pusherActor->updateSequence(4);
}
if (flickerActor->_sequenceID != 1) {
flickerActor->updateSequence(1);
_vm->playOrStopSound(2);
}
} else {
if (local_25c < 0x2d) {
if (((pusherActor->_sequenceID != 5) &&
(pusherActor->_sequenceID != 2)) &&
(pusherActor->_sequenceID != 3)) {
pusherActor->updateSequence(5);
}
if (flickerActor->_sequenceID != 2) {
flickerActor->updateSequence(2);
_vm->playOrStopSound(3);
}
} else {
if (local_25c < 0x169) {
if (((pusherActor->_sequenceID != 6) &&
(pusherActor->_sequenceID != 2)) &&
(pusherActor->_sequenceID != 3)) {
pusherActor->updateSequence(6);
}
if (flickerActor->_sequenceID != 3) {
flickerActor->updateSequence(3);
_vm->playOrStopSound(4);
}
}
}
}
} else {
if (pusherActor->_sequenceID != 6) {
pusherActor->updateSequence(6);
}
if (flickerActor->_sequenceID != 3) {
flickerActor->updateSequence(3);
}
}
}
}
break;
case 2: // initial release of cat.
if (flickerActor->_sequenceID == 7) {
if ((flickerActor->_flags & 4) != 0) {
i = 1;
while ((i < 8 && ((((int)(uint)flickerXPos < (int)((uint)auStack352[(uint)i * 3] - 6) ||
((uint)auStack352[(uint)i * 3 + 1] + 6 < (uint)flickerXPos)) ||
(local_25a != auStack352[(uint)i * 3 + 2]))))) {
i = i + 1;
}
local_23c = 0;
if ((i != 8) && ((flickerXPos < auStack352[(uint)i * 3] || (auStack352[(uint)i * 3] < flickerXPos)))) {
local_23c = (short)((int)(((uint)auStack352[(uint)i * 3] + 8) * 0x80) / 0x2a) -
(short)((int)((uint)flickerXPos << 7) / 0x2a);
}
local_240 = flickerXPos << 7;
catActor->_x_pos = flickerXPos & 0x1ff;
local_23e = 0x2d00;
local_23a = (local_25a + 3) * 0x80;
catActor->_y_pos = 0x5a;
catFieldE_scaleMaybe = 0x100;
catActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
catActor->updateSequence(0xc);
_vm->playOrStopSound(5);
catActor->_priorityLayer = 3;
flickerActor->updateSequence(8);
gameState = 3;
}
} else {
flickerActor->updateSequence(7);
_vm->playOrStopSound(1);
}
break;
case 3: // cat flying through the air
local_240 = local_240 + local_23c;
if ((uint)local_25a * 2 + 0xb4 < (uint)catFieldE_scaleMaybe) {
local_23e = local_23e - local_23a;
local_23a = local_23a - local_130[((uint)local_25a - 1) * 3];
if (local_23a < 0) {
local_23a = 0;
}
} else {
if ((int)(uint)catFieldE_scaleMaybe < (int)((uint)local_25a * -4 + 0xba)) {
local_23e = local_23e + local_23a;
local_23a = local_23a + local_130[((uint)local_25a - 1) * 3 + 2];
} else {
local_23a = 0;
}
}
catActor->_x_pos = local_240 >> 7;
catActor->_y_pos = local_23e >> 7;
catFieldE_scaleMaybe = catFieldE_scaleMaybe - 3;
catActor->_scale = catFieldE_scaleMaybe;
if (catFieldE_scaleMaybe == 0x7f) {
i = 0;
while ((i < 8 && (((local_240 >> 7 < auStack352[(uint)i * 3] ||
(auStack352[(uint)i * 3 + 1] < local_240 >> 7)) ||
(local_25a != auStack352[(uint)i * 3 + 2]))))) {
i = i + 1;
}
if ((i != 8) && (local_188[(uint)i] != 0)) {
uVar1->_sequenceTimerMaxValue = 2;
local_21e = 0x3c;
if (local_250 != 0) {
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
local_250 = 0;
}
hitCounter = hitCounter + 1;
catActor->updateSequence(0xd);
if ((i == 0) && (9 < hitCounter)) {
local_22c = 0x16;
local_252 = 2;
catActor->updateSequence(0xd);
gameState = 4;
} else {
catActor->updateSequence(0xd);
_vm->playOrStopSound(6);
gameState = 8;
local_234 = 0;
}
if (local_252 == 0) { //successful hit maybe?
uint32 textId = _vm->getDialogTextId(local_118[((uint)hitCounter - 1) * 2]);
_vm->_talk->loadText(textId, auStack1008, 200);
_vm->_talk->displayDialogAroundPoint(auStack1008, (int)(short)(flickerXPos >> 3), 0xc, 0, 0, textId);
local_250 = *(short *)(local_118 + ((uint)hitCounter - 1) * 2 + 1);
}
targetActorIdTbl[(uint)(uint16)local_188[(uint)i]]->_priorityLayer = 3;
if (i == 0) {
targetActorIdTbl[(uint)local_188[0]]->updateSequence(7);
} else {
targetActorIdTbl[(uint)(uint16)local_188[(uint)i]]->_y_pos -= 3;
targetActorIdTbl[(uint)(uint16)local_188[(uint)i]]->updateSequence(6);
}
auStack378[(uint)(uint16)local_188[(uint)i] - 1] = 0;
local_188[(uint)i] = 0;
break;
}
if ((i == 8) &&
((((local_25a == 1 && (local_240 >> 7 < 0x10e)) ||
((local_25a == 2 &&
((((0x7f < local_240 >> 7 && (local_240 >> 7 < 0xad)) ||
((0x30 < local_240 >> 7 && (local_240 >> 7 < 0x4a)))) ||
((0xf8 < local_240 >> 7 && (local_240 >> 7 < 0x10f)))))))) ||
((local_25a == 3 &&
(((0x3c < local_240 >> 7 && (local_240 >> 7 < 0x46)) ||
((0x101 < local_240 >> 7 && (local_240 >> 7 < 0x10a)))))))))) {
dustSpriteActor->_x_pos = catActor->_x_pos;
dustSpriteActor->_y_pos = catActor->_y_pos + 2;
dustSpriteActor->updateSequence(8);
catActor->_priorityLayer = 4;
dustSpriteActor->_priorityLayer = 3;
catActor->updateSequence(0xd);
gameState = 4;
_vm->playOrStopSound(6);
}
}
if (catFieldE_scaleMaybe < 0x7f) {
catActor->_priorityLayer = 2;
}
if ((0xc < catFieldE_scaleMaybe) && (catFieldE_scaleMaybe < 0x41)) {
catActor->_priorityLayer = 0;
}
if ((short)catFieldE_scaleMaybe < 2) {
local_23e = 0x3700;
local_23a = 0x100;
local_240 = 0x4a80;
catFieldE_scaleMaybe = 0x30;
catActor->_y_pos = 0x6e;
catActor->_x_pos = 0x95;
catActor->_scale = 0x30;
catActor->updateSequence(0xb);
gameState = 5;
}
break;
case 4: // cat sliding down wall.
if (((catActor->_flags & 4) != 0) &&
((dustSpriteActor->_flags & 4) != 0)) {
if (catActor->_sequenceID == 0xe) {
if (local_23e < 0x4300) {
local_23e = local_23e + local_23a;
local_23a = local_23a + 0x18;
catActor->_y_pos = local_23e >> 7;
} else {
catActor->updateSequence(0xf);
_vm->playOrStopSound(7);
gameState = 6;
}
} else {
dustSpriteActor->_priorityLayer = 0;
catActor->_priorityLayer = 3;
catActor->updateSequence(0xe);
_vm->playOrStopSound(8);
local_23a = 0x40;
}
}
break;
case 5: // cat behind portcullis
if (local_23e >> 7 < 0x86) {
local_23e = local_23e + local_23a;
catFieldE_scaleMaybe = catFieldE_scaleMaybe + 8;
catActor->_y_pos = local_23e >> 7;
catActor->_scale = catFieldE_scaleMaybe;
} else {
gameState = 6;
catActor->_sequenceID = 0x10;
catActor->_flags = catActor->_flags | 4;
}
break;
case 6: // cat run across field
catActor->_priorityLayer = 3;
if (local_252 == 0) {
if (catActor->_sequenceID == 0xf) {
if ((catActor->_flags & 4) != 0) {
catActor->updateSequence(0x10);
}
} else {
if (catActor->_sequenceID == 0x10) {
if ((catActor->_flags & 4) != 0) {
catFieldE_scaleMaybe = 0x80;
local_23e = 0x4300;
local_23a = 0x100;
catActor->_y_pos = 0x86;
catActor->_scale = 0x80;
catActor->updateSequence(0xb);
if (flickerXPos < local_240 >> 7) {
sVar2 = flickerXPos + 0x32;
} else {
sVar2 = flickerXPos - 0x32;
}
local_16e = sVar2 * 0x80;
local_23c = (short)(((int)(((uint)local_16e - (uint)local_240) * 0x10000) >> 0x10) /
0x1c);
}
} else {
if (local_23e < 0x5f00) {
if (local_238 == 0) {
local_23e = local_23e + local_23a;
local_240 = local_240 + local_23c;
catFieldE_scaleMaybe = catFieldE_scaleMaybe + 6;
if (0x100 < catFieldE_scaleMaybe) {
catFieldE_scaleMaybe = 0x100;
}
catActor->_scale = catFieldE_scaleMaybe;
catActor->_y_pos = local_23e >> 7;
catActor->_x_pos = local_240 >> 7;
local_238 = 1;
} else {
local_238 = local_238 + -1;
}
} else {
if ((int)(uint)(local_240 >> 7) < (int)((uint)flickerXPos - 0x32)) {
if (catActor->_sequenceID != 9) {
catActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
catActor->updateSequence(9);
}
local_240 = local_240 + 0x180;
catActor->_x_pos = local_240 >> 7;
} else {
if ((uint)flickerXPos + 0x32 < (uint)(local_240 >> 7)) {
if (catActor->_sequenceID != 10) {
catActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
catActor->updateSequence(10);
}
local_240 = local_240 - 0x180;
catActor->_x_pos = local_240 >> 7;
} else {
gameState = 7;
}
}
}
}
}
}
break;
case 7: // cat jumping into catapult
if (catActor->_priorityLayer == 0) {
gameState = 1;
} else {
catActor->_priorityLayer = 0;
if (local_240 >> 7 < flickerXPos) {
flickerActor->updateSequence(5);
} else {
flickerActor->updateSequence(6);
}
}
break;
case 8: // cat hit target.
if (local_234 == 1) {
if (local_23a < 1) {
local_234 = 2;
} else {
local_23a--;
catActor->_y_pos = catActor->_y_pos + 2;
}
} else {
if (local_234 < 2) {
if ((local_234 == 0) && ((catActor->_flags & 4) != 0)) {
local_234 = 3;
local_232 = 0;
}
} else {
if (local_234 == 2) {
local_23e = 0x4100;
local_240 = 0x4a80;
catActor->_y_pos = 0x82;
catActor->_x_pos = 0x95;
catActor->_priorityLayer = 3;
catActor->_scale = 0x80;
catActor->updateSequence(0x10);
gameState = 6;
} else {
if (local_234 == 3) {
if (local_232 == 0) {
catActor->_priorityLayer = 2;
local_23a = 8;
local_234 = 1;
} else {
local_232 = local_232 + -1;
}
}
}
}
}
break;
default:
//ProbablyShowASCIIMessage(s_undefined_state!_8008e9cc, 2, 3, 0, 0xffffffff);
gameState = 1;
catActor->_priorityLayer = 0;
flickerActor->updateSequence(0);
}
if ((local_252 == 0) && (gameState != 2)) {
if (!_vm->isLeftKeyPressed() || (flickerXPos < 0x37)) {
if (!_vm->isRightKeyPressed() || (0x107 < flickerXPos)) {
if ((pusherActor->_sequenceID != local_246) &&
(((pusherActor->_sequenceID != 4 &&
(pusherActor->_sequenceID != 5)) &&
(pusherActor->_sequenceID != 6)))) {
pusherActor->updateSequence((uint)local_246);
if (bVar3) {
pusherActor->_x_pos = flickerActor->_x_pos + 2;
pusherActor->_y_pos = flickerActor->_y_pos;
} else {
pusherActor->_x_pos = flickerActor->_x_pos - 0xe;
pusherActor->_y_pos = flickerActor->_y_pos + 7;
}
}
} else {
bVar3 = true;
local_246 = 8;
if (pusherActor->_sequenceID != 2) {
pusherActor->updateSequence(2);
}
flickerXPos = flickerXPos + 2;
if (flickerXPos < 0x109) {
if (flickerXPos < 0x36) {
flickerXPos = 0x36;
}
} else {
flickerXPos = 0x108;
}
if (local_242 == 0) {
local_242 = 0xb;
} else {
local_242 = local_242 - 1;
}
flickerActor->_x_pos = flickerXPos;
wheelsActor->_x_pos = flickerXPos;
if ((uint)wheelsActor->_sequenceID != (uint)local_242 / 3 + 0x11)
{
wheelsActor->updateSequence((uint)local_242 / 3 + 0x11);
}
pusherActor->_x_pos = flickerActor->_x_pos + 2;
pusherActor->_y_pos = flickerActor->_y_pos;
}
} else {
bVar3 = false;
local_246 = (uint16)(gameState != 1);
if (pusherActor->_sequenceID != 3) {
pusherActor->updateSequence(3);
}
flickerXPos = flickerXPos - 2;
if (flickerXPos < 0x109) {
if (flickerXPos < 0x36) {
flickerXPos = 0x36;
}
} else {
flickerXPos = 0x108;
}
local_242 = (short)((uint)local_242 + 1) +
(short)((int)((uint)local_242 + 1) / 6 >> 1) * -0xc;
flickerActor->_x_pos = flickerXPos;
wheelsActor->_x_pos = flickerXPos;
if ((uint)wheelsActor->_sequenceID != (uint)local_242 / 3 + 0x11) {
wheelsActor->updateSequence((uint)local_242 / 3 + 0x11);
}
pusherActor->_x_pos = flickerActor->_x_pos + -2;
pusherActor->_y_pos = flickerActor->_y_pos;
}
}
if ((local_22c < 0x16) && (auStack536[(uint)local_22c * 3 + 2] <= local_22e)) {
if ((local_22c == 0x14) && (hitCounter < 9)) {
local_252 = 1;
local_22c = 0x16;
} else {
if (auStack536[(uint)local_22c * 3 + 1] == 1) {
i = 0;
while ((i < 3 && (auStack378[(uint)i] != 0))) {
i = i + 1;
}
if (i == 3) {
debug("too many targets");
// ProbablyShowASCIIMessage(s_too_many_targets!_8008e9e0, 2, 4, 0, 0xffffffff);
}
if (auStack536[(uint)local_22c * 3] == 0) {
targetActorIdTbl[(uint)i + 1]->_x_pos = auStack352[(uint)auStack536[(uint)local_22c * 3] * 3] + 0xd;
} else {
targetActorIdTbl[(uint)i + 1]->_x_pos = auStack352[(uint)auStack536[(uint)local_22c * 3] * 3] + 8;
}
targetActorIdTbl[(uint)i + 1]->_y_pos = (4 - auStack352[(uint)auStack536[(uint)local_22c * 3] * 3 + 2]) * 0x20;
targetActorIdTbl[(uint)i + 1]->_priorityLayer = 2;
if (auStack536[(uint)local_22c * 3] == 0) {
targetActorIdTbl[(uint)i + 1]->updateSequence(3);
} else {
targetActorIdTbl[(uint)i + 1]->updateSequence(0);
}
targetActorIdTbl[(uint)i + 1]->_priorityLayer = 2;
local_188[(uint)auStack536[(uint)local_22c * 3]] = i + 1;
auStack378[(uint)i] = auStack536[(uint)local_22c * 3] + 1;
} else {
if ((auStack536[(uint)local_22c * 3 + 1] == 2) &&
(i = auStack536[(uint)local_22c * 3], local_188[(uint)i] != 0)) {
if (auStack536[(uint)local_22c * 3] == 0) {
targetActorIdTbl[(uint)(uint16)local_188[(uint)i]]->updateSequence(5);
} else {
targetActorIdTbl[(uint)(uint16)local_188[(uint)i]]->updateSequence(2);
}
if (local_250 != 0) {
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
local_250 = 0;
}
if ((local_254 == 0) && (local_252 == 0)) {
if (auStack536[(uint)local_22c * 3] == 0) {
uVar5 = _vm->getRand(2);
local_168 = local_c0[(uint)uVar5 * 2 + 4];
local_16a = *(short *)(local_c0 + (uint)uVar5 * 2 + 5);
} else {
uVar5 = _vm->getRand(2);
local_168 = local_c0[(uint)uVar5 * 2];
local_16a = *(short *)(local_c0 + (uint)uVar5 * 2 + 1);
}
} else {
uVar5 = _vm->getRand(2);
local_168 = local_c0[(uint)uVar5 * 2 + 4];
local_16a = *(short *)(local_c0 + (uint)uVar5 * 2 + 5);
}
if ((local_252 == 0) || ((auStack536[(uint)local_22c * 3] == 0 && (local_254 == 0)))) {
uint32 textId = _vm->getDialogTextId(local_168);
_vm->_talk->loadText(textId, auStack1008, 200);
_vm->_talk->displayDialogAroundPoint(auStack1008, (int)(short)(flickerXPos >> 3), 0xc, 0, 0, textId);
local_250 = local_16a;
}
if (local_254 < 2) {
local_254 = local_254 + 1;
}
auStack378[(uint)(uint16)local_188[(uint)i] - 1] = 0;
local_188[(uint)i] = 0;
if ((1 < local_254) || (auStack536[(uint)local_22c * 3] == 0)) {
local_252 = 1;
}
}
}
}
local_22e = 0;
local_22c = local_22c + 1;
}
i = 0;
while (i < 3) {
if ((targetActorIdTbl[(uint)i + 1]->_sequenceID == 1) ||
(targetActorIdTbl[(uint)i + 1]->_sequenceID == 4)) {
local_188[(uint)auStack378[(uint)i]] = 0;
auStack378[(uint)i] = 0;
}
i = i + 1;
}
local_22e = local_22e + 1;
} while (local_252 == 0);
if (flickerActor->_x_pos < 0x118) {
flickerActor->_x_pos = flickerActor->_x_pos + 2;
if (pusherActor->_sequenceID != 2) {
pusherActor->updateSequence(2);
}
pusherActor->_x_pos = flickerActor->_x_pos + 2;
pusherActor->_y_pos = flickerActor->_y_pos;
wheelsActor->_x_pos = wheelsActor->_x_pos + 2;
if (local_242 == 0) {
local_242 = 0xb;
} else {
local_242--;
}
if ((uint)wheelsActor->_sequenceID != (uint)local_242 / 3 + 0x11) {
wheelsActor->updateSequence((uint)local_242 / 3 + 0x11);
}
goto LAB_8008fa78;
}
if ((local_252 == 1) && ((gameState == 6 || (gameState == 1)))) {
pusherActor->updateSequence(9);
_vm->waitForFrames(0xf);
if (local_250 != 0) {
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
}
_vm->waitForFrames(0x3c);
_vm->getINI(DAT_80063a40 - 1)->actor->clearFlag(ACTOR_FLAG_100);
break;
}
if ((local_252 == 2) && (gameState == 6)) {
_vm->getINI(DAT_80063a40 - 1)->objectState2 = 2;
if (local_250 != 0) {
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
}
pusherActor->updateSequence(7);
_vm->_talk->loadText(_vm->getDialogTextId(0x216D2), auStack1008, 200);
_vm->_talk->displayDialogAroundPoint(auStack1008, 0x19, 0xc, 0, 1, _vm->getDialogTextId(0x216D2));
pusherActor->updateSequence(1);
_vm->waitForFrames(0x1e);
_vm->getINI(DAT_80063a40 - 1)->actor->clearFlag(ACTOR_FLAG_100);
break;
}
} while (true);
_vm->clearAllText();
flickerActor->updateSequence(0x15);
// DisableVSyncEvent();
catActor->reset_maybe();
wheelsActor->reset_maybe();
i = 0;
while (i < 3) {
targetActorIdTbl[(uint)i + 1]->reset_maybe();
i = i + 1;
}
pusherActor->reset_maybe();
dustSpriteActor->reset_maybe();
// EnableVSyncEvent();
_vm->_dragonINIResource->getFlickerRecord()->actor->clearFlag(ACTOR_FLAG_100);
_vm->_dragonINIResource->setFlickerRecord(originalFlickerIniID);
flickerActor = originalFlickerIniID->actor;
flickerActor->clearFlag(ACTOR_FLAG_100);
flickerActor->_priorityLayer = 6; //TODO this is 2 in the original but that leave flicker invisible.
_vm->clearFlags(ENGINE_FLAG_4000000);
_vm->setFlags(savedEngineFlags);
uVar1->_sequenceTimerMaxValue = actorSequenceTimerStartValue;
return;
}
} // End of namespace Dragons

View 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/>.
*
*/
#ifndef DRAGONS_MINIGAME1_H
#define DRAGONS_MINIGAME1_H
namespace Dragons {
class DragonsEngine;
class Minigame1 {
private:
DragonsEngine *_vm;
public:
Minigame1(DragonsEngine *vm);
void run();
};
} // End of namespace Dragons
#endif //DRAGONS_MINIGAME1_H

View File

@@ -0,0 +1,911 @@
/* 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/scummsys.h"
#include "dragons/minigame2.h"
#include "dragons/actor.h"
#include "dragons/actorresource.h"
#include "dragons/dragons.h"
#include "dragons/dragonini.h"
#include "dragons/font.h"
#include "dragons/talk.h"
#include "dragons/inventory.h"
#include "dragons/scene.h"
#include "dragons/screen.h"
#include "dragons/cursor.h"
#include "dragons/sound.h"
namespace Dragons {
Minigame2::Minigame2(DragonsEngine *vm) : _vm(vm), _dat_80093c70(false), _dat_80093c72(false), _dat_80093c74(0), _dat_80093ca8(false) {
_dat_80093cb4 = 0;
_dat_80093cbc = 0;
_dat_80093cb8 = 0;
_dat_80093cc0 = 0;
_dat_80093ca4 = 0;
_dat_80093c90 = 0;
_dat_80093c94 = 0;
_dat_80093cac = 0;
_dat_80093cb0 = false;
_dat_80093c9c = 0;
_dat_80093c98 = 0;
_dat_80093ca0 = 0;
_dat_80093cc4 = 0;
_dat_80093cc8 = 0;
}
static const uint16 unkArray[5] = {
0xC, 0xA, 0x8, 0x6, 0x4
};
void Minigame2::run(int16 param_1, uint16 param_2, int16 param_3) {
short sVar2;
short sVar3;
bool bVar4;
DragonINI *flicker;
uint32 origEngineFlags;
Actor *loungealotBigPunchActor;
Actor *loungealotHeadActor;
Actor *loungealotLeftUpperArm;
Actor *loungealotLegActor;
Actor *loungealotRightArm;
Actor *flickerArm;
Actor *loungealotThumb;
Actor *uVar12;
Actor *uVar13;
Actor *flickerPortrait;
Actor *loungealotPortrait;
uint uVar18;
//uint uVar19;
//int iVar20;
bool shouldShakeScreen;
uint16 local_2e6;
int16 actorSequenceIdTbl [15];
uint32 textIdTbl [4];
uint16 local_2b0 [8];
uint16 local_288;
uint16 local_286;
uint16 local_284;
uint16 local_282;
uint16 local_27a;
uint16 local_278;
short local_272;
short local_26c;
uint16 local_268;
uint16 local_264;
uint16 local_262;
short local_260;
short local_258;
short local_256;
int16 screenShakeTbl [10];
uint16 screenShakeCounter;
uint8 paletteData [0x200];
uint16 local_28;
InventoryState originalInventoryType;
origEngineFlags = _vm->getAllFlags();
originalInventoryType = _vm->_inventory->getState();
flicker = _vm->_dragonINIResource->getFlickerRecord();
Common::File *fd = new Common::File();
if (!fd->open("arc2.bin")) {
error("Failed to open arc2.bin");
}
for (int i = 0; i < 15; i++) {
actorSequenceIdTbl[i] = fd->readSint16LE();
}
fd->skip(2);
for (int i = 0; i < 6; i++) {
local_2b0[i] = fd->readSint16LE();
}
for (int i = 0; i < 9; i++) {
screenShakeTbl[i] = fd->readSint16LE();
}
fd->close();
textIdTbl[0] = _vm->getDialogTextId(0x4500);
textIdTbl[1] = _vm->getDialogTextId(0x454A);
textIdTbl[2] = _vm->getDialogTextId(0x4576);
bVar4 = false;
local_27a = 0;
local_278 = 0;
local_272 = 0;
local_26c = 0x1e;
shouldShakeScreen = false;
local_264 = 0;
local_262 = 0;
local_260 = 300;
local_258 = 0;
local_256 = 0;
screenShakeCounter = 0;
local_2e6 = param_2;
if (param_2 > 4) {
local_2e6 = 4;
}
_dat_80093ca4 = unkArray[local_2e6];
_dat_80093c90 = unkArray[local_2e6];
_dat_80093c94 = 0;
_vm->_inventory->setState(Closed);
_dat_80093cb4 = 2;
_dat_80093cbc = 0;
_dat_80093cb8 = 2;
_dat_80093cc0 = 0;
_dat_80093cac = 0;
_dat_80093cb0 = false;
_dat_80093c9c = 0;
_vm->_talk->_dat_8008e874_dialogBox_y2 = 0;
_vm->_talk->_dat_8008e844_dialogBox_y1 = 0;
_vm->_talk->_dat_8008e848_dialogBox_x2 = 0;
_vm->_talk->_dat_8008e7e8_dialogBox_x1 = 0;
_dat_80093c98 = _dat_80093c90;
_dat_80093ca0 = param_1;
_dat_80093cc4 = _dat_80093ca4;
_dat_80093cc8 = _dat_80093ca4;
_vm->fadeToBlack();
_vm->reset_screen_maybe();
_vm->_inventory->setState(Closed);
flicker->sceneId = 0;
_vm->_dragonINIResource->setFlickerRecord(nullptr);
_vm->setFlags(ENGINE_FLAG_800);
_vm->_scene->setSceneId(5);
_vm->_scene->loadSceneData(5 | 0x8000, 0);
//DisableVSyncEvent();
_vm->clearFlags(ENGINE_FLAG_8);
_vm->clearFlags(ENGINE_FLAG_10);
_vm->clearFlags(ENGINE_FLAG_20);
_vm->clearFlags(ENGINE_FLAG_80);
memcpy(paletteData, _vm->_scene->getPalette() + 0x180, 0x80);
memcpy(paletteData + 0x80, _vm->_scene->getPalette() + 0x180, 0x80);
_vm->_screen->loadPalette(1, paletteData);
_vm->_screen->updatePaletteTransparency(1, 0x40, 0x7f, true);
loungealotBigPunchActor = _vm->_actorManager->loadActor(0x11, 0, 0, 0, 6);
loungealotHeadActor = _vm->_actorManager->loadActor(0xd, 0, 0x7d, 199, 4);
loungealotLeftUpperArm = _vm->_actorManager->loadActor(0xb, 2, 0x7d, 199, 4);
loungealotLegActor = _vm->_actorManager->loadActor(0xf, 0, 0x7d, 199, 4);
loungealotRightArm = _vm->_actorManager->loadActor(0x10, 0, 0x7d, 199, 4);
flickerArm = _vm->_actorManager->loadActor(9, (uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb4 * 3 + (uint)_dat_80093cbc],
loungealotLeftUpperArm->_x_pos,
loungealotLeftUpperArm->_y_pos, 4);
loungealotThumb = _vm->_actorManager->loadActor(0x12, (uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb4 * 3 + (uint)_dat_80093cbc],
loungealotLeftUpperArm->_x_pos,
loungealotLeftUpperArm->_y_pos, 4);
uVar12 = _vm->_actorManager->loadActor(10, (uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb8 * 3 + (uint)_dat_80093cc0],
flickerArm->_x_pos,
flickerArm->_y_pos, 4);
uVar13 = _vm->_actorManager->loadActor(0x13, (uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb8 * 3 + (uint)_dat_80093cc0],
flickerArm->_x_pos,
flickerArm->_y_pos, 4);
flickerPortrait = _vm->_actorManager->loadActor(0x27, 0, 0x10, 0xac, 4);
loungealotPortrait = _vm->_actorManager->loadActor(0x27, 1, 0x10, 0x8c, 4);
loungealotBigPunchActor->setFlag(ACTOR_FLAG_100);
loungealotHeadActor->setFlag(ACTOR_FLAG_100);
loungealotLeftUpperArm->setFlag(ACTOR_FLAG_100);
loungealotLegActor->setFlag(ACTOR_FLAG_100);
loungealotRightArm->setFlag(ACTOR_FLAG_100);
flickerArm->setFlag(ACTOR_FLAG_100);
loungealotThumb->setFlag(ACTOR_FLAG_100);
uVar12->setFlag(ACTOR_FLAG_100);
uVar13->setFlag(ACTOR_FLAG_100);
flickerPortrait->setFlag(ACTOR_FLAG_100);
loungealotPortrait->setFlag(ACTOR_FLAG_100);
loungealotBigPunchActor->_priorityLayer = 6;
flickerArm->_priorityLayer = 5;
uVar12->_priorityLayer = 5;
loungealotThumb->_priorityLayer = 4;
uVar13->_priorityLayer = 3;
loungealotRightArm->_priorityLayer = 3;
loungealotLeftUpperArm->_priorityLayer = 2;
loungealotHeadActor->_priorityLayer = 2;
loungealotLegActor->_priorityLayer = 1;
flickerPortrait->_priorityLayer = 0;
loungealotPortrait->_priorityLayer = 0;
FlatQuad *flickerPowerMeter = _vm->_screen->getFlatQuad(_vm->_screen->addFlatQuad(0x28, 0xa8, 0x67, 0xa8, 0x67, 0xaf, 0x28, 0xaf, 0x1f, 7, 0));
FlatQuad *loungealotPowerMeter = _vm->_screen->getFlatQuad(_vm->_screen->addFlatQuad(0x28, 0x88, 0x67, 0x88, 0x67, 0x8f, 0x28, 0x8f, 0x3e0, 7, 0));
flickerPowerMeter->flags &= ~1u;
loungealotPowerMeter->flags &= ~1u;
// EnableVSyncEvent();
loungealotHeadActor->setFlag(ACTOR_FLAG_1);
loungealotLeftUpperArm->setFlag(ACTOR_FLAG_1);
loungealotLegActor->setFlag(ACTOR_FLAG_1);
loungealotRightArm->setFlag(ACTOR_FLAG_1);
flickerArm->setFlag(ACTOR_FLAG_1);
loungealotThumb->setFlag(ACTOR_FLAG_1);
uVar12->setFlag(ACTOR_FLAG_1);
uVar13->setFlag(ACTOR_FLAG_1);
flickerArm->waitUntilFlag8And4AreSet();
uVar12->waitUntilFlag8And4AreSet();
loungealotThumb->waitUntilFlag8And4AreSet();
uVar13->waitUntilFlag8And4AreSet();
loungealotLeftUpperArm->waitUntilFlag8And4AreSet();
loungealotRightArm->waitUntilFlag8And4AreSet();
loungealotHeadActor->waitUntilFlag8And4AreSet();
loungealotLegActor->waitUntilFlag8And4AreSet();
loungealotBigPunchActor->setFlag(ACTOR_FLAG_400);
flickerArm->_x_pos = loungealotLeftUpperArm->_x_pos - loungealotLeftUpperArm->_frame->field_e;
flickerArm->_y_pos = loungealotLeftUpperArm->_y_pos - loungealotLeftUpperArm->_frame->field_10;
loungealotThumb->_x_pos = loungealotLeftUpperArm->_x_pos - loungealotLeftUpperArm->_frame->field_e;
loungealotThumb->_y_pos = loungealotLeftUpperArm->_y_pos - loungealotLeftUpperArm->_frame->field_10;
uVar12->_x_pos = loungealotLeftUpperArm->_x_pos - flickerArm->_frame->field_e;
uVar12->_y_pos = loungealotLeftUpperArm->_y_pos - flickerArm->_frame->field_10;
uVar13->_x_pos = loungealotLeftUpperArm->_x_pos - flickerArm->_frame->field_e;
uVar13->_y_pos = loungealotLeftUpperArm->_y_pos - flickerArm->_frame->field_10;
_vm->waitForFrames(2);
_vm->fadeFromBlack();
do {
_vm->waitForFrames(1);
if ((_dat_80093c9c != 0) && !_vm->isFlagSet(ENGINE_FLAG_8000)) {
loungealotHeadActor->updateSequence(0);
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
_dat_80093c9c = 0;
}
if (_dat_80093c94 != 0) {
local_264 = 0;
}
if (loungealotLegActor->_field_7a == 1) {
shouldShakeScreen = true;
loungealotLegActor->_field_7a = 0;
screenShakeCounter = 0;
}
if (shouldShakeScreen) {
_vm->_screen->setScreenShakeOffset(0, screenShakeTbl[screenShakeCounter]);
if (screenShakeTbl[screenShakeCounter] == 0) {
shouldShakeScreen = false;
}
screenShakeCounter = screenShakeCounter + 1;
}
if (_dat_80093ca4 == 0) {
_dat_80093ca4 = _dat_80093cc8;
} else {
_dat_80093ca4 = _dat_80093ca4 - 1;
}
if (_dat_80093c90 == 0) {
_dat_80093c90 = _dat_80093c98;
} else {
_dat_80093c90 = _dat_80093c90 - 1;
}
if (_dat_80093cc4 == 0) {
_dat_80093cc4 = _dat_80093cc8;
} else {
_dat_80093cc4 = _dat_80093cc4 - 1;
}
if (local_27a == 0) {
flickerPowerMeter->flags &= ~1u;
} else {
flickerPowerMeter->points[1].x = local_27a + 0x27;
flickerPowerMeter->points[3].x = local_27a + 0x27;
flickerPowerMeter->colour = (uint16)(((int)((uint)local_27a - 1) >> 1) << 5) |
(uint16)(((int)(0x40 - (uint)local_27a) >> 1) << 10);
flickerPowerMeter->flags |= 1;
}
if (local_278 == 0) {
loungealotPowerMeter->flags &= ~1u;
if ((local_27a != 0) || (local_258 != 0)) goto LAB_800907c4;
} else {
loungealotPowerMeter->points[1].x = local_278 + 0x27;
loungealotPowerMeter->points[3].x = local_278 + 0x27;
loungealotPowerMeter->colour = (uint16)(((int)((uint)local_278 - 1) >> 1) << 5) |
(uint16)(((int)(0x40 - (uint)local_278) >> 1) << 10);
loungealotPowerMeter->flags |= 1;
LAB_800907c4:
if (!bVar4) {
_vm->_fontManager->drawTextDialogBox(4, 0x14, 0xd, 0x16);
_vm->_fontManager->drawTextDialogBox(4, 0x10, 0xd, 0x12);
flickerPortrait->_priorityLayer = 6;
loungealotPortrait->_priorityLayer = 6;
bVar4 = true;
}
}
if ((((local_278 == 0) && (local_27a == 0)) && (local_258 == 0)) && (bVar4)) {
_vm->_fontManager->clearTextDialog(4, 0x14, 0xd, 0x16);
_vm->_fontManager->clearTextDialog(4, 0x10, 0xd, 0x12);
flickerPortrait->_priorityLayer = 0;
loungealotPortrait->_priorityLayer = 0;
bVar4 = false;
}
//DisableVSyncEvent();
loungealotThumb->_x_pos = loungealotLeftUpperArm->_x_pos - loungealotLeftUpperArm->_frame->field_e;
flickerArm->_x_pos = loungealotThumb->_x_pos;
sVar2 = flickerArm->_x_pos;
loungealotThumb->_y_pos = loungealotLeftUpperArm->_y_pos - loungealotLeftUpperArm->_frame->field_10;
flickerArm->_y_pos = loungealotThumb->_y_pos;
sVar3 = flickerArm->_y_pos;
uVar13->_x_pos = sVar2 - flickerArm->_frame->field_e;
uVar12->_x_pos = uVar13->_x_pos;
uVar13->_y_pos = sVar3 - flickerArm->_frame->field_10;
uVar12->_y_pos = uVar13->_y_pos;
// EnableVSyncEvent();
local_282 = _dat_80093cc0;
local_286 = _dat_80093cbc;
local_284 = _dat_80093cb8;
local_288 = _dat_80093cb4;
if (_dat_80093c94 != 1) {
if (_dat_80093c94 < 2) {
if (_dat_80093c94 == 0) {
if (((local_264 < 300) || (_dat_80093ca0 != 0)) || (_dat_80093cbc == 2)) {
if ((local_260 != 0) && (local_260 = local_260 + -1, local_260 == 0)) {
if (local_262 != 0) {
local_262 = local_262 - 1;
}
local_260 = 300;
}
} else {
local_264 = 0;
local_260 = 300;
// playSoundFromTxtIndex(textIdTbl[local_262]);
loungealotHeadActor->updateSequence((uint)local_2b0[(uint)local_262 * 2]);
uVar18 = (uint)local_262;
local_262 = local_262 + 1;
fun_80093aec_dialog(textIdTbl[uVar18], 0x14, 1);
if (local_262 == 3) {
while (((_dat_80093cb4 != 2 || (_dat_80093cbc != 0)) ||
((_dat_80093cb8 != 2 || (_dat_80093cc0 != 0))))) {
_vm->waitForFrames(1);
if (flickerArm->isFlagSet(ACTOR_FLAG_4)) {
if (_dat_80093cbc != 0) {
_dat_80093cbc = _dat_80093cbc - 1;
}
if (2 < _dat_80093cb4) {
_dat_80093cb4 = _dat_80093cb4 - 1;
}
if (_dat_80093cb4 < 2) {
_dat_80093cb4 = _dat_80093cb4 + 1;
}
}
if ((uVar12->_flags & 4) != 0) {
if (_dat_80093cc0 != 0) {
_dat_80093cc0 = _dat_80093cc0 - 1;
}
if (2 < _dat_80093cb8) {
_dat_80093cb8 = _dat_80093cb8 - 1;
}
if (_dat_80093cb8 < 2) {
_dat_80093cb8 = _dat_80093cb8 + 1;
}
}
if (flickerArm->_sequenceID != actorSequenceIdTbl[(uint)_dat_80093cb4 * 3 + (uint)_dat_80093cbc]) {
flickerArm->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb4 * 3 + (uint)_dat_80093cbc]);
loungealotThumb->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb4 * 3 + (uint)_dat_80093cbc]);
}
if (uVar12->_sequenceID !=
actorSequenceIdTbl[(uint)_dat_80093cb8 * 3 + (uint)_dat_80093cc0]) {
uVar12->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb8 * 3 + (uint)_dat_80093cc0]);
uVar13->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb8 * 3 + (uint)_dat_80093cc0]);
}
}
_vm->waitForFrames(2 * 0x3c);
// DisableVSyncEvent();
memset(paletteData, 0, 0x200);
loungealotBigPunchActor->_flags = loungealotBigPunchActor->_flags & 0xfbff;
loungealotHeadActor->setFlag(ACTOR_FLAG_400);
loungealotLeftUpperArm->setFlag(ACTOR_FLAG_400);
loungealotRightArm->setFlag(ACTOR_FLAG_400);
loungealotLegActor->_flags = loungealotLegActor->_flags | 0x400;
flickerArm->setFlag(ACTOR_FLAG_400);
loungealotThumb->setFlag(ACTOR_FLAG_400);
uVar12->setFlag(ACTOR_FLAG_400);
uVar13->setFlag(ACTOR_FLAG_400);
// EnableVSyncEvent();
_vm->waitForFrames(6);
loungealotBigPunchActor->updateSequence(1);
loungealotBigPunchActor->waitUntilFlag4IsSet();
_vm->waitForFrames(1);
_vm->_screen->loadPalette(0, paletteData);
_vm->_screen->loadPalette(1, paletteData);
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
//punched in the face.
break;
}
}
if (local_26c != 0) {
local_26c = local_26c + -1;
}
if (local_278 != 0) {
local_278 = local_278 - 1;
}
if (local_27a != 0) {
local_27a = local_27a - 1;
}
local_268 = 2;
if (_vm->isLeftKeyPressed()) {
local_268 = 1;
}
if (fun_80093520()) {
local_268 = local_268 - 1;
}
if (_vm->isRightKeyPressed()) {
local_268 = local_268 + 1;
}
if (fun_80093248()) {
local_268 = local_268 + 1;
}
if (loungealotLeftUpperArm->_sequenceID != local_268) {
loungealotLeftUpperArm->updateSequence(local_268);
}
if ((flickerArm->_flags & 4) != 0) {
if (_vm->isRightKeyPressed() && (local_288 != 0)) {
local_288 = local_288 - 1;
}
if (_vm->isLeftKeyPressed() && (local_288 < 4)) {
local_288 = local_288 + 1;
}
if ((!_vm->isLeftKeyPressed() && !_vm->isRightKeyPressed()) && (local_288 != 2)) {
if (local_288 < 2) {
local_288 = local_288 + 1;
} else {
local_288 = local_288 - 1;
}
}
if (!_vm->isActionButtonPressed() || (local_26c != 0)) {
if (local_286 != 0) {
local_286 = local_286 - 1;
}
} else {
if (local_286 < 2) {
local_286 = local_286 + 1;
}
}
}
if (local_286 == 2) {
if (local_256 < 0x14) {
local_256 = local_256 + 1;
} else {
local_256 = 0;
}
}
if (local_256 < 0x14) {
local_264 = local_264 + 1;
} else {
local_264 = 0;
}
if ((uVar12->_flags & 4) != 0) {
if (fun_80093248() && (local_284 != 0)) {
local_284 = local_284 - 1;
}
if (fun_80093520() && (local_284 < 4)) {
local_284 = local_284 + 1;
}
if ((!fun_80093520() && !fun_80093248()) && (local_284 != 2)) {
if (local_284 < 2) {
local_284 = local_284 + 1;
} else {
local_284 = local_284 - 1;
}
}
if (!fun_80093800() || (local_26c != 0)) {
if (local_282 != 0) {
local_282 = local_282 - 1;
}
} else {
if (local_282 < 2) {
local_282 = local_282 + 1;
}
}
}
if (((local_286 == 2) && (local_282 == 2)) && (local_288 == local_284)) {
if ((_dat_80093cbc == 2) && (_dat_80093cc0 != 2)) {
local_258 = 2;
} else {
if ((_dat_80093cbc == 2) || (_dat_80093cc0 != 2)) {
local_288 = _dat_80093cb4;
local_286 = _dat_80093cbc;
local_284 = _dat_80093cb8;
local_282 = _dat_80093cc0;
} else {
local_258 = 1;
}
}
}
if (local_258 == 0) {
if ((local_286 != _dat_80093cbc) || (local_288 != _dat_80093cb4)) {
_dat_80093cb4 = local_288;
_dat_80093cbc = local_286;
flickerArm->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)local_288 * 3 + (uint)local_286]);
loungealotThumb->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb4 * 3 + (uint)_dat_80093cbc]);
}
if ((local_282 != _dat_80093cc0) || (local_284 != _dat_80093cb8)) {
_dat_80093cb8 = local_284;
_dat_80093cc0 = local_282;
uVar12->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)local_284 * 3 + (uint)local_282]);
uVar13->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb8 * 3 + (uint)_dat_80093cc0]);
}
} else {
if (local_258 == 1) {
loungealotHeadActor->updateSequence(1);
loungealotLegActor->updateSequence(1);
if (local_288 == 2) {
local_28 = 1;
} else {
if (local_288 < 3) {
if (local_288 == 0) {
local_28 = 0;
} else {
LAB_800926a4:
local_28 = 2;
}
} else {
if (local_288 != 4) goto LAB_800926a4;
local_28 = 2;
}
}
} else {
loungealotHeadActor->updateSequence(3);
loungealotRightArm->updateSequence(1);
if (local_284 == 2) {
local_28 = 4;
} else {
if (local_284 < 3) {
if (local_284 == 0) {
local_28 = 3;
} else {
LAB_80092754:
local_28 = 4;
}
} else {
if (local_284 != 4) goto LAB_80092754;
local_28 = 5;
}
}
}
uVar12->_flags = uVar12->_flags | 0x400;
uVar13->_flags = uVar13->_flags | 0x400;
flickerArm->updateSequence((uint)local_28 + 0xf);
loungealotThumb->updateSequence((uint)local_28 + 0xf);
_dat_80093c94 = 1;
_dat_80093c90 = 0x1e;
}
}
} else {
if (_dat_80093c94 == 2) { // Flicker loses by being pinned
uVar12->_flags = uVar12->_flags | 0x1000;
uVar13->_flags = uVar13->_flags | 0x1000;
flickerArm->_flags = flickerArm->_flags | 0x1000;
loungealotThumb->_flags = loungealotThumb->_flags | 0x1000;
_vm->_screen->setScreenShakeOffset(0, 0);
if (local_258 == 1) {
// playSoundFromTxtIndex(DAT_80063ad0);
loungealotHeadActor->updateSequence(9);
fun_80093aec_dialog(_vm->getDialogTextId(0x46BC), 0x14, 1);
do {
_vm->waitForFrames(1);
} while (_vm->isFlagSet(ENGINE_FLAG_8000));
loungealotHeadActor->updateSequence(2);
loungealotRightArm->updateSequence(3);
} else {
// playSoundFromTxtIndex(DAT_80063ad4);
loungealotHeadActor->updateSequence(10);
fun_80093aec_dialog(_vm->getDialogTextId(0x4718), 0x14, 1);
loungealotRightArm->updateSequence(2);
do {
_vm->waitForFrames(1);
} while (_vm->isFlagSet(ENGINE_FLAG_8000));
loungealotHeadActor->updateSequence(4);
}
_vm->waitForFrames(2 * 0x3c);
break;
}
}
continue;
}
if (local_272 == 0) {
local_272 = 1;
if (local_27a != 0) {
local_27a = local_27a - 1;
}
if (local_278 != 0) {
local_278 = local_278 - 1;
}
} else {
local_272 = local_272 + -1;
}
if (_vm->isR1ButtonPressed()) { //TODO || _vm->isR2ButtonPressed()) {
local_27a = local_27a + 4;
}
if (_vm->isL1ButtonPressed()) { //TODO || _vm->isL2ButtonPressed()) {
local_27a = local_27a + 4;
}
if (fun_80093990()) {
if (param_1 == 1) {
local_278 = local_278 + 4;
} else {
local_278 = local_278 + 6;
}
}
if (fun_80093a30()) {
if (param_1 == 1) {
local_278 = local_278 + 4;
} else {
local_278 = local_278 + 6;
}
}
if ((0x3f < local_278) || (0x3f < local_27a)) {
loungealotHeadActor->setFlag(ACTOR_FLAG_1000);
loungealotLegActor->setFlag(ACTOR_FLAG_1000);
loungealotRightArm->setFlag(ACTOR_FLAG_1000);
if (0x40 < local_27a) {
local_27a = 0x40;
}
if (0x40 < local_278) {
local_278 = 0x40;
}
if (((local_278 == local_27a) || ((local_258 == 2 && (local_278 < local_27a)))) ||
((local_258 == 1 && (local_27a < local_278)))) {
if (local_258 == 1) {
// playSoundFromTxtIndex(DAT_80063ad8);
loungealotHeadActor->updateSequence(0xb);
fun_80093aec_dialog(_vm->getDialogTextId(0x475E), 0x14, 1);
} else {
// playSoundFromTxtIndex(DAT_80063adc);
loungealotHeadActor->updateSequence(0xc);
fun_80093aec_dialog(_vm->getDialogTextId(0x4774), 0x14, 1);
}
local_258 = 0;
_dat_80093cb4 = 2;
_dat_80093cbc = 1;
_dat_80093cb8 = 0;
_dat_80093cc0 = 1;
uVar12->_flags = uVar12->_flags & 0xfbff;
uVar13->_flags = uVar13->_flags & 0xfbff;
flickerArm->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb4 * 3 + (uint)_dat_80093cbc]);
loungealotThumb->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb4 * 3 + (uint)_dat_80093cbc]);
uVar12->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb8 * 3 + (uint)_dat_80093cc0]);
uVar13->updateSequence((uint)(uint16)actorSequenceIdTbl[(uint)_dat_80093cb8 * 3 + (uint)_dat_80093cc0]);
_dat_80093c94 = 0;
local_26c = 0x1e;
} else {
_dat_80093c94 = 2;
}
}
} while (true);
_vm->fadeToBlack();
_vm->_fontManager->clearText();
_vm->_sound->resumeMusic();
// DisableVSyncEvent();
_vm->_dragonINIResource->getRecord(0)->x = 0x91;
_vm->_dragonINIResource->getRecord(0)->y = 0x9b;
_vm->_dragonINIResource->getRecord(0x123)->x = 0xc3;
_vm->_dragonINIResource->getRecord(0x123)->y = 0x9b;
_vm->_screen->loadPalette(1, _vm->_cursor->getPalette());
_vm->setupPalette1();
_vm->_screen->clearAllFlatQuads();
_vm->_dragonINIResource->setFlickerRecord(flicker);
_vm->_inventory->setState(originalInventoryType);
flicker->objectState = local_258 + -1;
if (flicker->objectState == 0) {
_vm->setVar(0xb, 1);
flicker->actorResourceId = 0xd2; //TODO is this correct?
_vm->_actorManager->loadActor(0xd2, flicker->actor->_actorID);
_vm->_dragonINIResource->getRecord(0x120)->sceneId = 0x17;
}
loungealotHeadActor->clearFlag(ACTOR_FLAG_40);
loungealotLeftUpperArm->clearFlag(ACTOR_FLAG_40);
loungealotLegActor->clearFlag(ACTOR_FLAG_40);
loungealotRightArm->clearFlag(ACTOR_FLAG_40);
flickerArm->clearFlag(ACTOR_FLAG_40);
loungealotThumb->clearFlag(ACTOR_FLAG_40);
uVar12->clearFlag(ACTOR_FLAG_40);
uVar13->clearFlag(ACTOR_FLAG_40);
// EnableVSyncEvent();
if (param_3 == 0) {
_vm->fadeToBlack();
_vm->_screen->clearAllFlatQuads();
flickerPortrait->clearFlag(ACTOR_FLAG_40);
loungealotPortrait->clearFlag(ACTOR_FLAG_40);
_vm->reset_screen_maybe();
} else {
_vm->reset_screen_maybe();
_vm->_scene->setSceneId(0x17);
flicker->sceneId = 0x17;
_vm->_scene->loadSceneData((uint)(0x17 | 0x8000), 0);
_vm->setAllFlags((origEngineFlags & 0xfefdffff) | (_vm->getAllFlags() & 0x1000000) | 0x40);
_vm->fadeFromBlack();
}
_vm->_fontManager->clearText();
}
void Minigame2::fun_80093aec_dialog(uint32 textId, int16 x, int16 y) {
uint16 auStack4024 [2000];
_vm->_talk->FUN_8001a7c4_clearDialogBoxMaybe();
_vm->_talk->loadText(textId, auStack4024, 2000);
_vm->_talk->displayDialogAroundPoint(auStack4024, x, y, 0, 0, textId);
_dat_80093c9c = 1;
}
bool Minigame2::fun_80093520() {
bool uVar2;
if (_dat_80093ca0 == 0) {
if (!_dat_80093c70) {
if (!_dat_80093c72 || (3 < _dat_80093cb8)) {
_dat_80093c72 = false;
_dat_80093c74 = _dat_80093c74 + 1;
if (_dat_80093c74 < 2) {
_dat_80093c70 = true;
_dat_80093cac = 0;
uVar2 = false;
} else {
if (_dat_80093ca4 == 0) {
_dat_80093cac = 0;
if (_dat_80093cb8 == _dat_80093cb4) {
if (_dat_80093cbc < _dat_80093cc0) {
_dat_80093cac = (uint16)(_dat_80093cb8 < 4);
} else {
if (!_dat_80093cb0 && _vm->getRand(8) < 3) {
if (_vm->getRand(8) < 3) {
_dat_80093c72 = 1;
_dat_80093c74 = 0;
_dat_80093cac = 1;
} else {
_dat_80093ca4 = _dat_80093cc8 + _vm->getRand(10);
_dat_80093cac = 1;
}
return true;
}
if (_dat_80093cb4 == 4) {
_dat_80093cac = 1;
}
}
} else {
if ((_dat_80093cb8 < _dat_80093cb4) && (_dat_80093cb4 != 2)) {
_dat_80093cac = 1;
}
}
}
uVar2 = (uint)_dat_80093cac;
}
} else {
_dat_80093cac = 1;
uVar2 = true;
}
} else {
_dat_80093cac = 0;
uVar2 = false;
}
} else {
uVar2 = _vm->isLeftKeyPressed();
}
return uVar2;
}
bool Minigame2::fun_80093248() {
bool uVar2;
if (_dat_80093ca0 == 0) {
if (!_dat_80093c72) {
if (!_dat_80093c70 || (_dat_80093cb8 == 0)) {
_dat_80093c70 = false;
_dat_80093c74 = _dat_80093c74 + 1;
if (_dat_80093c74 < 2) {
_dat_80093c72 = true;
_dat_80093cb0 = false;
uVar2 = false;
} else {
if (_dat_80093ca4 == 0) {
_dat_80093cb0 = false;
if (_dat_80093cb8 == _dat_80093cb4) {
if (_dat_80093cbc < _dat_80093cc0) {
_dat_80093cb0 = (bool)(_dat_80093cb8 != 0);
} else {
if ((_dat_80093cac == 0) && _vm->getRand(8) < 3) {
if (_vm->getRand(8) < 3) {
_dat_80093c70 = true;
_dat_80093c74 = 0;
_dat_80093cb0 = true;
} else {
_dat_80093ca4 = _dat_80093cc8 + _vm->getRand(10);
_dat_80093cb0 = true;
}
return true;
}
if (_dat_80093cb4 == 0) {
_dat_80093cb0 = true;
}
}
} else {
if ((_dat_80093cb4 < _dat_80093cb8) && (_dat_80093cb4 != 2)) {
_dat_80093cb0 = true;
}
}
}
uVar2 = _dat_80093cb0;
}
} else {
_dat_80093cb0 = true;
uVar2 = true;
}
} else {
_dat_80093cb0 = false;
uVar2 = false;
}
} else {
uVar2 = _vm->isRightKeyPressed();
}
return uVar2;
}
bool Minigame2::fun_80093800() {
bool uVar2;
if (_dat_80093ca0 == 0) {
if (_dat_80093ca4 == 0) {
_dat_80093ca8 = false;
if ((_dat_80093cb8 == _dat_80093cb4) && (_dat_80093cc0 < _dat_80093cbc)) {
_dat_80093ca8 = true;
} else {
if (_vm->getRand(8) < 3) {
_dat_80093ca4 = _vm->getRand(10);
_dat_80093ca4 = _dat_80093cc8 + _dat_80093ca4;
_dat_80093ca8 = true;
}
}
}
uVar2 = _dat_80093ca8;
} else {
uVar2 = false;
if (_vm->isSquareButtonPressed() || _vm->isCrossButtonPressed() ||
_vm->isCircleButtonPressed() ||
_vm->isTriangleButtonPressed()) {
uVar2 = true;
}
}
return uVar2;
}
bool Minigame2::fun_80093a30() {
bool uVar1;
if (_dat_80093ca0 == 0) {
uVar1 = (uint) _dat_80093c90 == (uint) _dat_80093cc8 / 3;
} else {
uVar1 = _vm->isL1ButtonPressed(); // TODO || _vm->isL2ButtonPressed();
}
return uVar1;
}
bool Minigame2::fun_80093990() {
bool uVar1;
if (_dat_80093ca0 == 0) {
uVar1 = _dat_80093c90 == 0;
} else {
uVar1 = _vm->isR1ButtonPressed(); // TODO || _vm->isR2ButtonPressed();
}
return uVar1;
}
} // End of namespace Dragons

View File

@@ -0,0 +1,68 @@
/* 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 DRAGONS_MINIGAME2_H
#define DRAGONS_MINIGAME2_H
namespace Dragons {
class DragonsEngine;
class Minigame2 {
private:
DragonsEngine *_vm;
uint16 _dat_80093cb4;
uint16 _dat_80093cbc;
uint16 _dat_80093cb8;
uint16 _dat_80093cc0;
uint16 _dat_80093ca4;
uint16 _dat_80093c90;
uint16 _dat_80093c94;
uint16 _dat_80093cac;
bool _dat_80093cb0;
uint16 _dat_80093c9c;
uint16 _dat_80093c98;
uint16 _dat_80093ca0;
uint16 _dat_80093cc4;
uint16 _dat_80093cc8;
bool _dat_80093c70;
bool _dat_80093c72;
uint16 _dat_80093c74;
bool _dat_80093ca8;
public:
Minigame2(DragonsEngine *vm);
void run(int16 param_1, uint16 param_2, int16 param_3);
private:
void fun_80093aec_dialog(uint32 textId, int16 x, int16 y);
bool fun_80093520();
bool fun_80093a30();
bool fun_80093248();
bool fun_80093800();
bool fun_80093990();
};
} // End of namespace Dragons
#endif //DRAGONS_MINIGAME2_H

View File

@@ -0,0 +1,769 @@
/* 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/scummsys.h"
#include "common/rect.h"
#include "dragons/actor.h"
#include "dragons/font.h"
#include "dragons/minigame3.h"
#include "dragons/dragonini.h"
#include "dragons/inventory.h"
#include "dragons/scene.h"
#include "dragons/screen.h"
#include "dragons/sound.h"
#include "dragons/talk.h"
#include "dragons/dragons.h"
namespace Dragons {
struct BunnyStruct {
uint32 positionIdx;
uint32 x;
uint32 y;
uint32 field_0xc;
uint32 field_0x10;
};
struct TearInfo {
uint16 x;
uint16 y;
uint16 unk;
uint16 yRelated;
};
struct UnkStruct {
uint16 position1;
uint16 position2;
uint32 unk4;
uint32 unk8;
uint32 unk12;
uint32 unk16;
uint32 field_0x14;
};
Minigame3::Minigame3(DragonsEngine *vm) : _vm(vm) {}
void Minigame3::run() {
bool bVar1;
Actor *handActorId;
//uint16 actorId;
int16 sVar2;
//int iVar3;
uint tmpValue;
int iVar4;
DragonINI *flicker;
uint16 origSceneId;
//byte auStack1584_palette[512]; //[126];
//uint16 local_5b2;
//byte auStack1072_palette[512];
Actor *bunnyActorTbl[4];
uint16 local_228 = 0;
//uint16 local_226;
int16 local_224;
Actor *tearActorTbl[8];
uint16 local_210;
int16 local_208[16];
uint local_1e8;
uint oldEngineFlags;
uint16 local_1e0;
uint16 local_1de;
Actor *tearBlinkActorTbl2[4];
Actor *tearBlinkActorTbl[4];
int16 local_1c8 = 0;
int16 local_1c6 = 0;
uint16 local_1c2;
int16 local_1c0;
int16 local_1be;
int16 local_1bc;
int16 local_1ba;
uint16 local_1b8;
int16 eyeBgYOffsetTbl[21];
TearInfo tearInfo[30];
Common::Point bunnyPositionsTbl[4];
Common::Point handPositionsTbl[4];
uint16 goodRabbitPositionTbl[4];
uint16 bunnyPositionTbl[4];
int16 currentState;
uint16 flags;
int16 local_5c;
int16 local_5a;
int16 local_58;
int16 local_56;
int16 hopCounter;
uint16 local_50 = 0;
BunnyStruct bunnyInfo[2];
uint16 local_20 = 0;
uint16 local_1e = 0;
uint16 local_1c = 0;
uint16 local_1a = 0;
int16 local_14;
InventoryState origInventoryType;
int16 local_10;
int16 local_e;
UnkStruct UnkStruct_ARRAY_800931a0[4];
int16 unkXPosTbl[20];
Common::File *fd = new Common::File();
if (!fd->open("arc3.bin")) {
error("Failed to open arc3.bin");
}
for (int i = 0; i < 21; i++) {
eyeBgYOffsetTbl[i] = fd->readUint16LE();
}
fd->seek(0x2c);
for (int i = 0; i < 30; i++) {
tearInfo[i].x = fd->readUint16LE();
tearInfo[i].y = fd->readUint16LE();
tearInfo[i].unk = fd->readUint16LE();
tearInfo[i].yRelated = fd->readUint16LE();
}
for (int i = 0; i < 4; i++) {
bunnyPositionsTbl[i].x = fd->readUint16LE();
bunnyPositionsTbl[i].y = fd->readUint16LE();
}
for (int i = 0; i < 4; i++) {
handPositionsTbl[i].x = fd->readUint16LE();
handPositionsTbl[i].y = fd->readUint16LE();
}
fd->seek(_vm->getMiniGame3DataOffset());
for (int i = 0; i < 4; i++) {
UnkStruct_ARRAY_800931a0[i].position1 = fd->readUint16LE();
UnkStruct_ARRAY_800931a0[i].position2 = fd->readUint16LE();
UnkStruct_ARRAY_800931a0[i].unk4 = fd->readUint32LE();
UnkStruct_ARRAY_800931a0[i].unk8 = fd->readUint32LE();
UnkStruct_ARRAY_800931a0[i].unk12 = fd->readUint32LE();
UnkStruct_ARRAY_800931a0[i].unk16 = fd->readUint32LE();
UnkStruct_ARRAY_800931a0[i].field_0x14 = fd->readUint32LE();
}
for (int i = 0; i < 20; i++) {
unkXPosTbl[i] = fd->readSint16LE();
}
fd->close();
delete fd;
origInventoryType = _vm->_inventory->getState();
_vm->fadeToBlack();
_vm->_inventory->setState(Closed);
_vm->reset_screen_maybe();
flicker = _vm->_dragonINIResource->getFlickerRecord();
flicker->sceneId = 0;
_vm->_dragonINIResource->setFlickerRecord(nullptr);
origSceneId = _vm->getCurrentSceneId();
_vm->_scene->setSceneId(6);
_vm->_scene->loadScene(6 | 0x8000, 0);
_vm->_scene->setFgLayerPriority(4);
// TODO
_vm->_screen->loadPalette(1, _vm->_scene->getPalette());
_vm->_screen->loadPalette(4, _vm->_scene->getPalette());
_vm->_screen->updatePaletteTransparency(4, 1, 0xff, true);
fun_80017ef0();
oldEngineFlags = _vm->getAllFlags();
_vm->clearFlags(ENGINE_FLAG_80);
_vm->clearFlags(ENGINE_FLAG_20);
_vm->clearFlags(ENGINE_FLAG_10);
_vm->clearFlags(ENGINE_FLAG_8);
_vm->clearFlags(ENGINE_FLAG_1);
_vm->setFlags(ENGINE_FLAG_100);
_vm->setFlags(ENGINE_FLAG_1000_SUBTITLES_DISABLED);
// TODO
// memcpy2(auStack1584_palette, scrFileData_maybe, 0x200);
// memcpy2(auStack1072_palette, scrFileData_maybe, 0x200);
// local_5b2 = 0x7fff;
// DisableVSyncEvent();
int i = 0;
while ((int16)i < 4) {
bunnyActorTbl[(int16)i] = _vm->_actorManager->loadActor(0x15, 4, 0, 0);
if (bunnyActorTbl[(int16)i] == nullptr) {
error("Couldn't_alloc_bunny");
}
bunnyActorTbl[(int16)i]->setFlag(ACTOR_FLAG_80);
bunnyActorTbl[(int16)i]->setFlag(ACTOR_FLAG_100);
bunnyActorTbl[(int16)i]->setFlag(ACTOR_FLAG_200);
bunnyActorTbl[(int16)i]->setFlag(ACTOR_FLAG_4000);
bunnyActorTbl[(int16)i]->_priorityLayer = 0;
bunnyActorTbl[(int16)i]->_x_pos = bunnyPositionsTbl[(int16)i].x;
bunnyActorTbl[(int16)i]->_y_pos = bunnyPositionsTbl[(int16)i].y;
i = i + 1;
}
i = 0;
while ((int16)i < 8) {
tearActorTbl[(int16)i] = _vm->_actorManager->loadActor(0x15, 0x13, 0, 0);
if (tearActorTbl[(int16)i] == nullptr) {
error("Couldn't alloc tear");
}
tearActorTbl[(int16)i]->_flags = tearActorTbl[(int16)i]->_flags | 0x380;
tearActorTbl[(int16)i]->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
tearActorTbl[(int16)i]->_priorityLayer = 0;
local_208[(int16)i] = -1;
local_208[(int)(int16)i + 8] = 0;
i = i + 1;
}
local_1e0 = 0;
local_1e8 = 0;
handActorId = _vm->_actorManager->loadActor(0x19, 0, 0, 0);
if (handActorId == nullptr) {
error("Couldn't alloc hand");
}
handActorId->setFlag(ACTOR_FLAG_80);
handActorId->setFlag(ACTOR_FLAG_100);
handActorId->setFlag(ACTOR_FLAG_200);
handActorId->setFlag(ACTOR_FLAG_800);
handActorId->setFlag(ACTOR_FLAG_2000);
handActorId->setFlag(ACTOR_FLAG_4000);
handActorId->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
handActorId->_priorityLayer = 0;
handActorId->_walkSpeed = 0x40000;
i = 0;
while ((int16)i < 2) {
tearBlinkActorTbl[(int16)i] = _vm->_actorManager->loadActor(0x34, (uint)i, 0, 0);
if (tearBlinkActorTbl[(int16)i] == nullptr) {
error("Couldn't alloc tear blink");
}
tearBlinkActorTbl[(int16)i]->_flags = tearBlinkActorTbl[(int16)i]->_flags | 0x4384;
tearBlinkActorTbl[(int16)i]->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
tearBlinkActorTbl[(int16)i]->_priorityLayer = 0;
i = i + 1;
}
i = 0;
while ((int16)i < 2) {
tearBlinkActorTbl2[(int16)i] = _vm->_actorManager->loadActor(0x16, (uint)i, 0, 0);
if (tearBlinkActorTbl2[(int16)i] == nullptr) {
error("Couldn't alloc tear blink");
}
tearBlinkActorTbl2[(int16)i]->setFlag(ACTOR_FLAG_100);
tearBlinkActorTbl2[(int16)i]->setFlag(ACTOR_FLAG_800);
tearBlinkActorTbl2[(int16)i]->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
tearBlinkActorTbl2[(int16)i]->_priorityLayer = 0;
i = i + 1;
}
tearBlinkActorTbl2[0]->_x_pos = 0x56;
tearBlinkActorTbl2[0]->_y_pos = 0x8c;
tearBlinkActorTbl2[1]->_x_pos = 0xf0;
tearBlinkActorTbl2[1]->_y_pos = 0x8c;
tearBlinkActorTbl[0]->_x_pos = 0x23; //DAT_80093228_23;
tearBlinkActorTbl[1]->_x_pos = 0xbf; //DAT_8009322a_bf;
tearBlinkActorTbl[0]->_y_pos = 0xcc;
tearBlinkActorTbl[1]->_y_pos = 0xcc;
// EnableVSyncEvent();
i = 0;
while ((int16)i < 4) {
goodRabbitPositionTbl[(int16)i] = 0;
i = i + 1;
}
int16 goodRabbitStartingPosition = _vm->getRand(4);
goodRabbitPositionTbl[goodRabbitStartingPosition] = 1;
i = 0;
while ((int16)i < 4) {
bunnyPositionTbl[(int16)i] = i;
bunnyActorTbl[(int16)i]->_priorityLayer = 2;
bunnyActorTbl[(int16)i]->updateSequence(4);
i = i + 1;
}
_vm->waitForFrames(1);
updateBackgroundLayerOffset(2, 0x280, 0);
updateBackgroundLayerOffset(1, 0, 0);
updateBackgroundLayerOffset(0, 0, 0);
_vm->fadeFromBlack();
_vm->waitForFrames(0xf);
_vm->_talk->loadAndDisplayDialogAroundPoint(_vm->getMiniGame3StartingDialog(), 0x14, 3, 0x1e01, 0);
_vm->waitForFrames(0x1e);
// TODO clearTextDialog((uint)DAT_8008e7e8, (uint)DAT_8008e844, (uint)DAT_8008e848, (uint)DAT_8008e874);
i = 0;
while ((int16)i < 4) {
if (goodRabbitPositionTbl[(int16)i] == 0) {
bunnyActorTbl[(int16)i]->updateSequence(1);
}
i = i + 1;
}
bunnyActorTbl[(goodRabbitStartingPosition + 1) % 4]->waitUntilFlag4IsSet(); // wait for a rabid rabbit to complete its display sequence.
bunnyActorTbl[goodRabbitStartingPosition]->updateSequence(0);
bunnyActorTbl[goodRabbitStartingPosition]->waitUntilFlag4IsSet();
i = 0;
while ((int16)i < 4) {
bunnyActorTbl[(int16)i]->updateSequence(4);
i = i + 1;
}
_vm->waitForFrames(0x1e);
_vm->waitForFrames(0x1e);
// TODO clearTextDialog((uint)DAT_8008e7e8, (uint)DAT_8008e844, (uint)DAT_8008e848, (uint)DAT_8008e874);
local_56 = 0;
local_1c0 = 0;
currentState = 2;
flags = 0;
local_58 = 0x1e;
hopCounter = 0;
local_210 = 0;
local_1de = 0;
local_5a = 0;
local_5c = _vm->getRand(2);
local_5c = local_5c + 5;
local_1be = 1;
local_1bc = _vm->getRand(3);
local_1bc = local_1bc + 3;
local_1ba = 10;
local_1b8 = 0;
local_10 = 0;
local_e = 0;
tearBlinkActorTbl[0]->_priorityLayer = 3;
tearBlinkActorTbl[1]->_priorityLayer = 3;
tearBlinkActorTbl[0]->updateSequence(0);
tearBlinkActorTbl[1]->updateSequence(1);
local_1c2 = 0;
while (true) {
_vm->waitForFrames(1);
switch (currentState) {
case 1:
if ((bunnyActorTbl[local_1a]->_sequenceID != 5) || ((bunnyActorTbl[local_1a]->_flags & 4) != 0)) {
if ((local_56 < 1) ||
(((int)bunnyInfo[local_20].x >> 9 <= (int)(uint)(uint16)bunnyPositionsTbl[bunnyInfo[local_1e].positionIdx].x ||
((int)(uint)(uint16)bunnyPositionsTbl[bunnyInfo[local_20].positionIdx].x <= (int)bunnyInfo[local_1e].x >> 9)))) {
bunnyActorTbl[local_1c]->_x_pos = bunnyPositionsTbl[bunnyInfo[local_1e].positionIdx].x;
bunnyActorTbl[local_1a]->_x_pos = bunnyPositionsTbl[bunnyInfo[local_20].positionIdx].x;
bunnyActorTbl[local_1c]->_y_pos = bunnyPositionsTbl[bunnyInfo[local_1e].positionIdx].y;
bunnyActorTbl[local_1a]->_y_pos = bunnyPositionsTbl[bunnyInfo[local_20].positionIdx].y;
currentState = 5;
} else {
if (bunnyActorTbl[local_1a]->_sequenceID == 5) {
bunnyActorTbl[local_1a]->updateSequence(6);
bunnyActorTbl[local_1c]->updateSequence(0xd);
} else {
local_56 = local_56 - *(int16 *)&UnkStruct_ARRAY_800931a0[local_50].field_0x14;
bunnyInfo[local_20].x = bunnyInfo[local_20].x + UnkStruct_ARRAY_800931a0[local_50].field_0x14 * -0x200;
bunnyInfo[local_20].y = bunnyInfo[local_20].y - bunnyInfo[local_20].field_0xc;
bunnyInfo[local_20].field_0xc = bunnyInfo[local_20].field_0xc + bunnyInfo[local_20].field_0x10;
bunnyActorTbl[local_1c]->_x_pos = (int16)((int)bunnyInfo[local_20].x >> 9);
bunnyActorTbl[local_1c]->_y_pos = (int16)((int)bunnyInfo[local_20].y >> 9);
bunnyInfo[local_1e].x = bunnyInfo[local_1e].x + UnkStruct_ARRAY_800931a0[local_50].field_0x14 * 0x200;
bunnyInfo[local_1e].y = bunnyInfo[local_1e].y - bunnyInfo[local_1e].field_0xc;
bunnyInfo[local_1e].field_0xc = bunnyInfo[local_1e].field_0xc + bunnyInfo[local_1e].field_0x10;
bunnyActorTbl[local_1a]->_x_pos = (int16)((int)bunnyInfo[local_1e].x >> 9);
bunnyActorTbl[local_1a]->_y_pos = (int16)((int)bunnyInfo[local_1e].y >> 9);
if ((local_228 < 4) && unkXPosTbl[local_50 * 4 + local_228] < bunnyActorTbl[local_1a]->_x_pos) {
local_228 = local_228 + 1;
bunnyActorTbl[local_1a]->updateSequence(((uint)local_228 + 6) & 0xffff);
bunnyActorTbl[local_1c]->updateSequence(((uint)local_228 + 0xd) & 0xffff);
}
}
}
}
break;
case 2:
if (local_58 == 0) {
currentState = 4;
}
break;
case 3:
if (local_58 == 0) {
currentState = 4;
}
break;
case 4:
local_50 = _vm->getRand(4);
if (local_50 < 2) {
i = _vm->getRand(2);
} else {
i = 0;
}
bunnyInfo[(int16)i].positionIdx = (uint)UnkStruct_ARRAY_800931a0[local_50].position1;
bunnyInfo[(int16)i].x = (uint)(uint16)bunnyPositionsTbl[bunnyInfo[(int16)i].positionIdx].x << 9;
bunnyInfo[(int16)i].y = (uint)(uint16)bunnyPositionsTbl[bunnyInfo[(int16)i].positionIdx].y << 9;
bunnyInfo[(int16)i].field_0xc = UnkStruct_ARRAY_800931a0[local_50].unk4;
bunnyInfo[(int16)i].field_0x10 = UnkStruct_ARRAY_800931a0[local_50].unk8;
i = i ^ 1;
bunnyInfo[(int16)i].positionIdx = (uint)UnkStruct_ARRAY_800931a0[local_50].position2;
bunnyInfo[(int16)i].x = (uint)(uint16)bunnyPositionsTbl[bunnyInfo[(int16)i].positionIdx].x << 9;
bunnyInfo[(int16)i].y = (uint)(uint16)bunnyPositionsTbl[bunnyInfo[(int16)i].positionIdx].y << 9;
bunnyInfo[(int16)i].field_0xc = UnkStruct_ARRAY_800931a0[local_50].unk12;
bunnyInfo[(int16)i].field_0x10 = UnkStruct_ARRAY_800931a0[local_50].unk16;
local_56 = bunnyPositionsTbl[UnkStruct_ARRAY_800931a0[local_50].position2].x - bunnyPositionsTbl[UnkStruct_ARRAY_800931a0[local_50].position1].x;
local_1e = (uint16)((int)bunnyInfo[1].x <= (int)bunnyInfo[0].x);
local_20 = (int16)((uint)local_1e + 1) + (int16)((int)((uint)local_1e + 1) / 2) * -2;
local_1a = bunnyPositionTbl[bunnyInfo[local_1e].positionIdx];
local_1c = bunnyPositionTbl[bunnyInfo[local_20].positionIdx];
bunnyActorTbl[local_1a]->updateSequence(5);
bunnyActorTbl[local_1c]->updateSequence(0xc);
if (hopCounter == 0x1d) {
_vm->playOrStopSound(2);
} else {
_vm->playOrStopSound((uint)local_1c2);
local_1c2 = 1 - local_1c2;
}
local_228 = 0;
i = goodRabbitPositionTbl[bunnyInfo[local_1e].positionIdx];
goodRabbitPositionTbl[bunnyInfo[local_1e].positionIdx] = goodRabbitPositionTbl[bunnyInfo[local_20].positionIdx];
goodRabbitPositionTbl[bunnyInfo[local_20].positionIdx] = i;
i = bunnyPositionTbl[bunnyInfo[local_1e].positionIdx];
bunnyPositionTbl[bunnyInfo[local_1e].positionIdx] = bunnyPositionTbl[bunnyInfo[local_20].positionIdx];
bunnyPositionTbl[bunnyInfo[local_20].positionIdx] = i;
currentState = 1;
break;
case 5:
hopCounter = hopCounter + 1;
local_5a = local_5a + 1;
bunnyActorTbl[local_1a]->updateSequence(0xb);
bunnyActorTbl[local_1c]->updateSequence(0x12);
if (local_5a == local_5c) {
local_5a = 0;
local_5c = _vm->getRand(2);
local_5c = local_5c + 5;
currentState = 3;
local_58 = 0x3c;
} else {
currentState = 2;
local_58 = 2;
}
break;
case 6:
local_10 = 0;
if (local_1e8 == 0) {
flags = flags | 8;
}
break;
default:
error("Unknown state");
}
i = 0;
while ((int16)i < 8) {
if (local_208[(int16)i] != -1) {
tearActorTbl[(int16)i]->_y_pos = tearActorTbl[(int16)i]->_y_pos + ((uint16)local_208[(int)(int16)i + 8] >> 6);
if (tearActorTbl[(int16)i]->_y_pos < (int16)tearInfo[local_208[(int16)i]].yRelated) {
local_208[(int)(int16)i + 8] = local_208[(int)(int16)i + 8] + 8;
} else {
tearActorTbl[(int16)i]->_priorityLayer = 0;
local_1e8 = local_1e8 & ~(1 << ((int)local_208[(int16)i] & 0x1fU));
local_208[(int16)i] = -1;
local_1e0 = local_1e0 - 1;
}
}
i = i + 1;
}
if (((local_1e0 < local_1de) && (currentState != 6)) && (sVar2 = _vm->getRand(2), sVar2 == 0)) {
if ((local_1e8 & 0x7fff) < local_1e8 >> 0xf) {
local_14 = 0;
} else {
local_14 = 0xf;
}
do {
sVar2 = _vm->getRand(0xf);
sVar2 = sVar2 + local_14;
} while ((1 << ((int)sVar2 & 0x1fU) & local_1e8) != 0);
local_1e8 = local_1e8 | 1 << ((int)sVar2 & 0x1fU);
local_14 = 0;
while ((local_14 < 8 && (local_208[local_14] != -1))) {
local_14 = local_14 + 1;
}
local_208[local_14] = sVar2;
tearActorTbl[local_14]->_x_pos = tearInfo[sVar2].x;
tearActorTbl[local_14]->_y_pos = tearInfo[sVar2].y;
local_208[(int)local_14 + 8] = 0x20;
tearActorTbl[local_14]->updateSequence(0x13);
tearActorTbl[local_14]->_priorityLayer = 3;
local_1e0 = local_1e0 + 1;
}
if ((flags & 1) == 0) {
if ((flags & 2) == 0) {
if ((flags & 4) == 0) {
if (_vm->isActionButtonPressed()) {
local_1c8 = 1;
flags = flags | 1;
local_1c6 = 3;
updateBackgroundLayerOffset(2, 0x640, 0);
if (((currentState != 3) && (currentState != 6)) && (local_e == 0)) {
local_10 = 0x5a;
local_e = 1;
}
}
} else {
if (local_1c6 == 0) {
if (local_1c8 == 2) {
local_1c6 = 3;
local_1c8 = 1;
updateBackgroundLayerOffset(2, 0x640, 0);
} else {
if (local_1c8 == 1) {
local_1c8 = 0;
local_1ba = 0;
flags = flags & 0xfffb;
tearBlinkActorTbl2[0]->_priorityLayer = 0;
tearBlinkActorTbl2[1]->_priorityLayer = 0;
tearBlinkActorTbl2[0]->updateSequence(0);
tearBlinkActorTbl2[1]->updateSequence(1);
}
}
} else {
local_1c6 = local_1c6 + -1;
}
}
} else {
if (local_1c6 == 0) {
i = 0;
while ((int16)i < 8) {
tearActorTbl[(int16)i]->_priorityLayer = 0;
local_208[(int16)i] = -1;
i = i + 1;
}
local_210 = 0;
local_1e0 = 0;
local_1de = 0;
local_1e8 = 0;
fun_80017f70_paletteRelated(0);
local_1b8 = 0;
flags = (flags & 0xfffd) | 4;
local_1c8 = 2;
local_1c6 = 3;
updateBackgroundLayerOffset(2, 0x780, 0);
tearBlinkActorTbl[0]->_y_pos = 0xcc;
tearBlinkActorTbl[1]->_y_pos = 0xcc;
} else {
local_1c6 = local_1c6 + -1;
}
}
} else {
if (local_1c6 == 0) {
if (local_1c8 == 1) {
local_1c6 = 3;
local_1c8 = 2;
updateBackgroundLayerOffset(2, 0x780, 0);
tearBlinkActorTbl2[0]->updateSequence(0);
tearBlinkActorTbl2[1]->updateSequence(1);
tearBlinkActorTbl2[0]->_priorityLayer = 4;
tearBlinkActorTbl2[1]->_priorityLayer = 4;
} else {
if (local_1c8 == 2) {
local_1c6 = 0x14;
local_1c8 = 3;
updateBackgroundLayerOffset(2, 0x8c0, 0);
tearBlinkActorTbl2[0]->updateSequence(2);
tearBlinkActorTbl2[1]->updateSequence(3);
flags = (flags & 0xfffe) | 2;
}
}
} else {
local_1c6 = local_1c6 + -1;
}
}
if ((local_e != 0) && (local_10 == 0)) {
//TODO implement this. clearTextDialog((uint)DAT_8008e7e8, (uint)DAT_8008e844, (uint)DAT_8008e848, (uint)DAT_8008e874);
local_e = 0;
}
if ((local_e != 0) && (local_10 != 0)) {
local_10 = local_10 + -1;
}
if (local_58 != 0) {
local_58 = local_58 + -1;
}
local_210 = local_210 + 1;
if (((uint)local_210 % 0x14 == 0) && (local_1de < 8)) {
local_1de = local_1de + 1;
}
if (((uint)local_210 % 10 == 0) && (0x1d < local_210)) {
if ((int16)local_1b8 < 0x1e) {
local_1b8 = local_1b8 + 1;
fun_80017f70_paletteRelated((uint)local_1b8);
}
if (100 < tearBlinkActorTbl[0]->_y_pos) {
tearBlinkActorTbl[0]->_y_pos = tearBlinkActorTbl[0]->_y_pos + -3;
tearBlinkActorTbl[1]->_y_pos = tearBlinkActorTbl[1]->_y_pos + -3;
}
}
if (hopCounter == 0x1e) {
currentState = 6;
}
if ((flags & 8) != 0) break;
if (local_1c8 == 0) {
if (local_1ba == 0) {
if (local_1bc == 0) {
tmpValue = _vm->getRand(2);
if ((tmpValue & 0xffff) == 0) {
local_1be = 1;
} else {
local_1be = -1;
}
local_1bc = _vm->getRand(3);
local_1bc = local_1bc + 3;
local_1ba = _vm->getRand(10);
local_1ba = local_1ba + 10;
} else {
if (((local_1be < 0) && (-10 < local_1c0)) || ((0 < local_1be && (local_1c0 < 10)))) {
local_1c0 = local_1c0 + local_1be;
}
local_1ba = 2;
local_1bc = local_1bc + -1;
iVar4 = (int)local_1c0 + 10;
if (iVar4 < 0) {
iVar4 = (int)local_1c0 + 0xd;
}
local_14 = (int16)(iVar4 >> 2);
if (local_14 == 5) {
local_14 = 4;
}
updateBackgroundLayerOffset(2, (int) local_14 * 0x140, 0);
updateBackgroundLayerOffset(1, (int) -local_1c0, (int) eyeBgYOffsetTbl[local_1c0 + 10]);
updateBackgroundLayerOffset(0, (int) -local_1c0, (int) eyeBgYOffsetTbl[local_1c0 + 10]);
}
} else {
local_1ba = local_1ba + -1;
}
}
}
_vm->waitForFrames(1);
i = 0;
while ((int16)i < 3) {
int16 local_16 = 0;
while (local_16 < 3) {
updateBackgroundLayerOffset(2, ((int) local_16 * 0x140 + 0x640) * 0x10000 >> 0x10, 0);
_vm->waitForFrames(5);
local_16 = local_16 + 1;
}
local_1b8 = local_1b8 - 0xb;
if ((int16)local_1b8 < 0) {
local_1b8 = 0;
}
fun_80017f70_paletteRelated((uint)local_1b8);
tearBlinkActorTbl[0]->_y_pos = tearBlinkActorTbl[0]->_y_pos + 0x1e;
if (199 < tearBlinkActorTbl[0]->_y_pos) {
tearBlinkActorTbl[0]->_y_pos = 199;
}
tearBlinkActorTbl[1]->_y_pos = tearBlinkActorTbl[1]->_y_pos + 0x1e;
if (199 < tearBlinkActorTbl[1]->_y_pos) {
tearBlinkActorTbl[1]->_y_pos = 199;
}
_vm->waitForFrames(0xf);
local_16 = 1;
while (-1 < local_16) {
updateBackgroundLayerOffset(2, ((int) local_16 * 0x140 + 0x640) * 0x10000 >> 0x10, 0);
_vm->waitForFrames(5);
local_16 = local_16 + -1;
}
i = i + 1;
}
tearBlinkActorTbl[0]->_flags = tearBlinkActorTbl[0]->_flags | 4;
tearBlinkActorTbl[1]->_flags = tearBlinkActorTbl[1]->_flags | 4;
updateBackgroundLayerOffset(2, 0x280, 0);
updateBackgroundLayerOffset(1, 0, 0);
updateBackgroundLayerOffset(0, 0, 0);
local_224 = _vm->getRand(2);
handActorId->updateSequence(0);
handActorId->_x_pos = handPositionsTbl[local_224].x;
handActorId->_y_pos = handPositionsTbl[local_224].y;
handActorId->_priorityLayer = 2;
bVar1 = false;
//pick a hat flicker.
_vm->_talk->loadAndDisplayDialogAroundPoint(_vm->getMiniGame3PickAHatDialog(), 0x14, 3, 0x1e01, 0);
while (_vm->isFlagSet(ENGINE_FLAG_8000)) {
_vm->waitForFrames(1);
}
while (_vm->waitForFrames(1), handActorId->isFlagSet(ACTOR_FLAG_10) || !_vm->isActionButtonPressed()) {
if (_vm->isLeftKeyPressed() && ((local_224 == 1 || (local_224 == 3)))) {
local_224 = local_224 + -1;
bVar1 = true;
}
if (_vm->isRightKeyPressed() && ((local_224 == 0 || (local_224 == 2)))) {
local_224 = local_224 + 1;
bVar1 = true;
}
if (_vm->isUpKeyPressed() && ((local_224 == 2 || (local_224 == 3)))) {
local_224 = local_224 + -2;
bVar1 = true;
}
if (_vm->isDownKeyPressed() && ((local_224 == 0 || (local_224 == 1)))) {
local_224 = local_224 + 2;
bVar1 = true;
}
if (bVar1) {
handActorId->startWalk((int)handPositionsTbl[local_224].x, (int)handPositionsTbl[local_224].y, 2);
bVar1 = false;
}
}
handActorId->updateSequence(1);
handActorId->waitUntilFlag4IsSet();
_vm->_dragonINIResource->getRecord(0x178)->objectState = local_224 + 1;
if (goodRabbitPositionTbl[local_224] == 1) {
bunnyActorTbl[bunnyPositionTbl[local_224]]->updateSequence(2);
_vm->_dragonINIResource->getRecord(0x178)->objectState2 = 1;
} else {
bunnyActorTbl[bunnyPositionTbl[local_224]]->updateSequence(3);
i = 0;
while (((int16)i < 4 && (goodRabbitPositionTbl[(int16)i] != 1))) {
i = i + 1;
}
_vm->waitForFrames(0x1e);
bunnyActorTbl[bunnyPositionTbl[i]]->updateSequence(2);
_vm->_dragonINIResource->getRecord(0x178)->objectState2 = 0;
}
_vm->waitForFrames(0x3c * 2);
_vm->_sound->resumeMusic();
_vm->fadeToBlack();
// fun_80017f28_noop();
// DAT_80093234 = DAT_80093234 + 1;
_vm->_dragonINIResource->setFlickerRecord(flicker);
flicker->sceneId = 1;
_vm->setAllFlags(oldEngineFlags);
_vm->setFlags(ENGINE_FLAG_40);
// _vm->_screen->loadPalette(1, (uint)*(uint16 *)(*(int *)(&DAT_80071c30 + (uint)actors[0].actorFileDictionaryIndex * 8) + 10) +
// *(int *)(&DAT_80071c30 + (uint)actors[0].actorFileDictionaryIndex * 8));
_vm->setupPalette1();
// _vm->_screen->loadPalette(4, (uint)*(uint16 *)(*(int *)(&DAT_80071c30 + (uint)actors[0].actorFileDictionaryIndex * 8) + 10) +
// *(int *)(&DAT_80071c30 + (uint)actors[0].actorFileDictionaryIndex * 8));
_vm->_screen->updatePaletteTransparency(4, 1, 0xff, true);
_vm->_inventory->setState(origInventoryType);
_vm->_scene->setSceneId(origSceneId);
_vm->_scene->loadScene(origSceneId, 0);
}
void Minigame3::updateBackgroundLayerOffset(uint32 layerNumber, int16 xOffset, int16 yOffset) {
_vm->_scene->setLayerOffset(layerNumber, Common::Point(xOffset, yOffset));
}
void Minigame3::fun_80017f70_paletteRelated(uint16 param_1) {
if (param_1 > 0x1f) {
param_1 = 0x1f;
}
// uVar1 = IsVSyncEventEnabled & 1;
// DisableVSyncEvent();
_vm->_screen->loadPalette(0, _vm->_scene->getPalette());
_vm->_screen->setPaletteRecord(0, 0x3f, param_1 * 0x421);
// load_palette_into_frame_buffer(0, abStack528);
_vm->_screen->updatePaletteTransparency(0, 0x3f, 0x3f, param_1 == 0x1e ? false : true);
// if (uVar1 != 0) {
// EnableVSyncEvent();
// }
}
void Minigame3::fun_80017ef0() {
//TODO BgLayerGsSprite[2].attribute = BgLayerGsSprite[2].attribute | 0x50000000;
// this sets the FG layer to additive colour blending (100% x Back + 100% x Sprite)
fun_80017f70_paletteRelated(0);
}
} // End of namespace Dragons

View File

@@ -0,0 +1,44 @@
/* 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 DRAGONS_MINIGAME3_H
#define DRAGONS_MINIGAME3_H
namespace Dragons {
class DragonsEngine;
class Minigame3 {
private:
DragonsEngine *_vm;
public:
Minigame3(DragonsEngine *vm);
void run();
private:
void updateBackgroundLayerOffset(uint32 layerNumber, int16 xOffset, int16 yOffset);
void fun_80017f70_paletteRelated(uint16 unk);
void fun_80017ef0();
};
} // End of namespace Dragons
#endif //DRAGONS_MINIGAME3_H

View File

@@ -0,0 +1,333 @@
/* 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/scummsys.h"
#include "dragons/minigame4.h"
#include "dragons/actor.h"
#include "dragons/dragons.h"
#include "dragons/dragonini.h"
#include "dragons/font.h"
#include "dragons/talk.h"
#include "dragons/inventory.h"
#include "dragons/scene.h"
#include "dragons/screen.h"
#include "dragons/sound.h"
namespace Dragons {
static void videoUpdaterFunction();
Minigame4::Minigame4(DragonsEngine *vm) : _vm(vm) {
_flickerActor = nullptr;
_bruteActor = nullptr;
_ps1ControllerActor = nullptr;
_dat_80090438 = nullptr;
_dat_8009043c = nullptr;
_layer2XOffset = 0;
}
void Minigame4::run() {
uint16 uVar1;
DragonINI *flicker;
uint uVar4;
uint16 result;
InventoryState uVar3;
uVar4 = _vm->getAllFlags();
uVar3 = _vm->_inventory->getState();
flicker = _vm->_dragonINIResource->getFlickerRecord();
uVar1 = _vm->getCurrentSceneId();
_vm->fadeToBlack();
_vm->reset_screen_maybe();
_vm->_dragonINIResource->getFlickerRecord()->sceneId = 0;
_vm->_dragonINIResource->setFlickerRecord(nullptr);
_vm->_inventory->setState(Closed);
_vm->_scene->setSceneId(7);
_vm->_scene->loadSceneData(0x8007, 0);
_vm->clearFlags(ENGINE_FLAG_8);
_vm->clearFlags(ENGINE_FLAG_10);
_vm->clearFlags(ENGINE_FLAG_20);
_vm->clearFlags(ENGINE_FLAG_80);
// DisableVSyncEvent();
_vm->clearFlags(ENGINE_FLAG_1);
_layer2XOffset = 0;
_vm->setVsyncUpdateFunction(videoUpdaterFunction);
_vm->_screen->loadPalette(4, _vm->_scene->getPalette());
_vm->_screen->updatePaletteTransparency(4, 1, 0xff, true);
_vm->_videoFlags |= 4;
_vm->_scene->setBgLayerPriority(2);
_vm->_scene->setMgLayerPriority(1);
_flickerActor = _vm->_actorManager->loadActor(0x18, 0, 0xcb, 0x79, 1);
_bruteActor = _vm->_actorManager->loadActor(0x17, 0, 0x68, 0x7b, 1);
_ps1ControllerActor = _vm->_actorManager->loadActor(0x17, 0x16, 0x9f, 0x19, 1);
_dat_80090438 = _vm->_actorManager->loadActor(0x17, 0xb, 400, 400, 1);
_dat_8009043c = _vm->_actorManager->loadActor(0x17, 0xb, 400, 400, 1);
//EnableVSyncEvent();
_flickerActor->setFlag(ACTOR_FLAG_80);
_flickerActor->setFlag(ACTOR_FLAG_100);
_flickerActor->setFlag(ACTOR_FLAG_200);
_flickerActor->_priorityLayer = 3;
_bruteActor->setFlag(ACTOR_FLAG_80);
_bruteActor->setFlag(ACTOR_FLAG_100);
_bruteActor->setFlag(ACTOR_FLAG_200);
_bruteActor->_priorityLayer = 3;
_vm->_sound->playMusic(0xf);
_vm->fadeFromBlack();
if (_vm->_dragonINIResource->getRecord(0x1f5)->objectState == 3) {
actorTalk(_bruteActor, 0x3321, 0x4A84);
} else {
actorTalk(_bruteActor, 0x3321, 0x49A2);
actorTalk(_flickerActor, 0, 0x4A56);
}
result = runDanceBattle();
/* field_0x12 */
_vm->_dragonINIResource->getRecord(0)->objectState = result ^ 1;
if (_vm->_dragonINIResource->getRecord(0)->objectState == 1) {
_vm->_dragonINIResource->getRecord(0x1f5)->sceneId = 0;
}
_vm->waitForFrames(2 * 0x3c);
_vm->fadeToBlack();
//DisableVSyncEvent();
_vm->setVsyncUpdateFunction(nullptr);
_vm->setFlags(ENGINE_FLAG_1);
_vm->_videoFlags &= ~(uint16)4;
// EnableVSyncEvent();
_vm->_dragonINIResource->setFlickerRecord(flicker);
_vm->_inventory->setState(uVar3);
// _vm->_screen->loadPalette(4, (uint)*(uint16 *)
// (*(int *)(&DAT_80071c30 + (uint)actors[0].actorFileDictionaryIndex * 8) + 10)
// + *(int *)(&DAT_80071c30 + (uint)actors[0].actorFileDictionaryIndex * 8));
_vm->_screen->updatePaletteTransparency(4, 1, 0xff, true);
_vm->_scene->setSceneId(uVar1);
_vm->setAllFlags(uVar4);
flicker->sceneId = uVar1;
_vm->_scene->loadScene(uVar1, 0x1e);
}
void Minigame4::actorTalk(Actor *actorId, uint16 param_2, uint32 textIndex) {
actorId->waitUntilFlag8SetThenSet1000AndWaitFor4();
if (actorId == _bruteActor) {
_bruteActor->updateSequence(9);
} else {
_flickerActor->updateSequence(9);
}
actorDialog(actorId, (uint)param_2, _vm->getDialogTextId(textIndex));
actorId->waitUntilFlag8SetThenSet1000AndWaitFor4();
if (actorId == _bruteActor) {
_bruteActor->updateSequence(0);
} else {
_flickerActor->updateSequence(0);
}
}
void Minigame4::actorDialog(Actor *actorId, uint16 param_2, uint32 textIndex) {
uint16 buf[1000];
_vm->_talk->loadText(textIndex, buf, 1000);
_vm->_talk->displayDialogAroundActor(actorId, param_2, buf, textIndex);
}
uint16 Minigame4::runDanceBattle() {
uint16 auStack2192 [1000];
uint16 currentStep;
uint16 round1StepPositionTbl [12];
uint16 round1DurationTbl [12];
uint16 round2StepPositionTbl [12];
uint16 round2DurationTbl [12];
uint16 round3StepPositionTbl [20];
uint16 round3DurationTbl [20];
Common::File *fd = new Common::File();
if (!fd->open("arc4.bin")) {
error("Failed to open arc4.bin");
}
for (int i = 0; i < 0xc; i++) {
round1StepPositionTbl[i] = fd->readUint16LE();
}
for (int i = 0; i < 0xc; i++) {
round1DurationTbl[i] = fd->readUint16LE();
}
for (int i = 0; i < 0xc; i++) {
round2StepPositionTbl[i] = fd->readUint16LE();
}
for (int i = 0; i < 0xc; i++) {
round2DurationTbl[i] = fd->readUint16LE();
}
for (int i = 0; i < 0x12; i++) {
round3StepPositionTbl[i] = fd->readUint16LE();
}
for (int i = 0; i < 0x12; i++) {
round3DurationTbl[i] = fd->readUint16LE();
}
fd->close();
delete fd;
currentStep = 0;
while (currentStep < 0xc) {
if (singleDanceRound(round1StepPositionTbl[(uint)currentStep], round1DurationTbl[(uint)currentStep])) {
actorTalk(_bruteActor, 0x3321, 0x4D50);
return 1;
}
currentStep = currentStep + 1;
}
resetActors();
actorTalk(_bruteActor, 0x3321, 0x4ADE);
currentStep = 0;
while (currentStep < 0xc) {
if (singleDanceRound(round2StepPositionTbl[(uint)currentStep], round2DurationTbl[(uint)currentStep])) {
actorTalk(_bruteActor, 0x3321, 0x4DD4);
return 1;
}
currentStep = currentStep + 1;
}
resetActors();
actorTalk(_bruteActor, 0x3321, 0x4B6A);
currentStep = 0;
while (true) {
if (0x11 < currentStep) {
uint32 textId = _vm->getDialogTextId(0x4C0C);
_vm->_talk->loadText(textId, auStack2192, 1000);
_vm->_talk->displayDialogAroundPoint(auStack2192, 0x27, 0xc, 0x3321, 0, textId);
_vm->waitForFrames(0x10a);
_bruteActor->updateSequence(8);
_vm->_fontManager->clearText();
_flickerActor->waitUntilFlag8SetThenSet1000AndWaitFor4();
_flickerActor->updateSequence(7);
actorTalk(_flickerActor, 0, 0x4CC8);
return 0;
}
if (singleDanceRound(round3StepPositionTbl[(uint)currentStep], round3DurationTbl[(uint)currentStep])) {
break;
}
currentStep = currentStep + 1;
}
actorTalk(_bruteActor, 0x3321, 0x4DEE);
return 1;
}
const static uint16 xDancePosTbl[6] = { 0xAC, 0xB5, 0xBC, 0xB3, 0xB4, 0xAF };
const static uint16 yDancePosTbl[6] = { 0x1C, 0x23, 0x1A, 0x14, 0x12, 0xF };
const static uint16 uint16_ARRAY_80090400[6] = { 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };
const static uint16 uint16_ARRAY_800903e8[6] = { 1, 2, 3, 4, 5, 6 };
uint16 Minigame4::singleDanceRound(uint16 currentDancePosition, uint16 duration) {
_dat_80090438->_x_pos = xDancePosTbl[(uint)currentDancePosition];
_dat_80090438->_y_pos = yDancePosTbl[(uint)currentDancePosition];
_dat_80090438->updateSequence(10);
_ps1ControllerActor->updateSequence(uint16_ARRAY_80090400[(uint)currentDancePosition]);
_bruteActor->updateSequence(uint16_ARRAY_800903e8[(uint)currentDancePosition]);
while ((_flickerActor->_sequenceID != uint16_ARRAY_800903e8[(uint)currentDancePosition] &&
(duration = duration + -1, duration != 0))) {
_vm->waitForFrames(1);
updateFlickerFromInput();
}
if (_flickerActor->_sequenceID == uint16_ARRAY_800903e8[(uint)currentDancePosition]) {
while (duration = duration + -1, duration != 0) {
_vm->waitForFrames(1);
}
_dat_80090438->_x_pos = xDancePosTbl[(uint)currentDancePosition];
_dat_8009043c->_x_pos = _dat_80090438->_x_pos;
_dat_80090438->_y_pos = yDancePosTbl[(uint)currentDancePosition];
_dat_8009043c->_y_pos = _dat_80090438->_y_pos;
_dat_8009043c->updateSequence(0xb);
_ps1ControllerActor->updateSequence(0x16);
return 0;
}
return fun_8009009c(1);
}
void Minigame4::resetActors() {
_bruteActor->waitUntilFlag8SetThenSet1000();
_flickerActor->waitUntilFlag8SetThenSet1000();
while (_bruteActor->_sequenceID != 0 || _flickerActor->_sequenceID != 0) {
_vm->waitForFrames(1);
if (_bruteActor->_sequenceID != 0 &&
_bruteActor->isFlagSet(ACTOR_FLAG_4) &&
_bruteActor->isFlagSet(ACTOR_FLAG_8)) {
_bruteActor->updateSequence(0);
}
if (_flickerActor->_sequenceID != 0 &&
_flickerActor->isFlagSet(ACTOR_FLAG_4) &&
_flickerActor->isFlagSet(ACTOR_FLAG_8)) {
_flickerActor->updateSequence(0);
}
}
}
void Minigame4::updateFlickerFromInput() {
if (_vm->isSquareButtonPressed() && _flickerActor->_sequenceID != 1) {
_flickerActor->updateSequence(1);
}
if (_vm->isCrossButtonPressed() && _flickerActor->_sequenceID != 2) {
_flickerActor->updateSequence(2);
}
if (_vm->isCircleButtonPressed() && _flickerActor->_sequenceID != 3) {
_flickerActor->updateSequence(3);
}
if (_vm->isTriangleButtonPressed() && _flickerActor->_sequenceID != 4) {
_flickerActor->updateSequence(4);
}
if (_vm->isR1ButtonPressed() && _flickerActor->_sequenceID != 5) {
_flickerActor->updateSequence(5);
}
if (_vm->isL1ButtonPressed() && _flickerActor->_sequenceID != 6) {
_flickerActor->updateSequence(6);
}
}
uint16 Minigame4::fun_8009009c(uint16 unk) {
resetActors();
if (unk == 0) {
_bruteActor->updateSequence(8);
_flickerActor->updateSequence(7);
} else {
_bruteActor->updateSequence(7);
_flickerActor->updateSequence(8);
}
do {
do {
} while (_bruteActor->isFlagSet(ACTOR_FLAG_4));
} while (_flickerActor->isFlagSet(ACTOR_FLAG_4));
return (uint)unk;
}
void videoUpdaterFunction() {
static uint16 layer2XOffset = 0;
static uint16 layer0XOffset = 0;
DragonsEngine *vm = getEngine();
vm->_scene->setLayerOffset(2, Common::Point(layer2XOffset, 0));
layer2XOffset = (layer2XOffset + 3) % 512;
vm->_scene->setLayerOffset(0, Common::Point(layer0XOffset, 0));
layer0XOffset = (layer0XOffset + 4) % 512;
}
} // End of namespace Dragons

View File

@@ -0,0 +1,59 @@
/* 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 DRAGONS_MINIGAME4_H
#define DRAGONS_MINIGAME4_H
namespace Dragons {
class DragonsEngine;
class Actor;
class Minigame4 {
private:
DragonsEngine *_vm;
Actor *_flickerActor;
Actor *_bruteActor;
Actor *_ps1ControllerActor;
Actor *_dat_80090438;
Actor *_dat_8009043c;
public:
uint16 _layer2XOffset;
Minigame4(DragonsEngine *vm);
void run();
private:
void actorTalk(Actor *actorId,uint16 param_2,uint32 textIndex);
void actorDialog(Actor *actorId,uint16 param_2,uint32 textIndex);
uint16 runDanceBattle();
uint16 singleDanceRound(uint16 desiredPosition, uint16 duration);
void resetActors();
void updateFlickerFromInput();
uint16 fun_8009009c(uint16 unk);
};
} // End of namespace Dragons
#endif //DRAGONS_MINIGAME4_H

View File

@@ -0,0 +1,523 @@
/* 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/scummsys.h"
#include "dragons/minigame5.h"
#include "dragons/actor.h"
#include "dragons/dragons.h"
#include "dragons/dragonini.h"
#include "dragons/talk.h"
#include "dragons/scene.h"
#include "dragons/screen.h"
namespace Dragons {
#define DAT_80063a48 0x12d
#define DAT_80063a40 0x12f
#define DAT_80063bd0 0x133
Minigame5::Minigame5(DragonsEngine *vm) : _vm(vm), _dat_800633e6(0) {}
void Minigame5::run() {
uint16 uVar1;
//int iVar2;
//byte *local_v0_7008;
//void *local_v0_7256;
//byte *uVar3;
//uint uVar4;
uint16 local_850;
uint16 auStack2120 [1000];
DragonINI*local_78;
//uint16 local_76;
uint16 local_74;
uint16 local_72 = 0;
uint16 bombScale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
Actor *bombActor;
Actor *flickerActor;
Actor *pusherActor;
Actor *dustActor;
uint16 local_66;
Actor *wheelsActor;
uint16 local_62;
uint16 local_60 = 0;
uint16 local_5e = 0;
short local_5c = 0;
short local_5a = 0;
uint16 currentState;
short local_50;
Actor *local_4e;
//uint16 local_4c;
//uint16 local_4a;
//uint16 local_48;
int16 local_46;
//int16 local_44;
short local_42;
uint16 local_30 [4];
//uint16 uStack42;
uint16 local_28 [10];
short local_10;
uint32 savedEngineFlags;
Common::File *fd = new Common::File();
if (!fd->open("arc5.bin")) {
error("Failed to open arc5.bin");
}
for (int i = 0; i < 4; i++) {
local_30[i] = fd->readUint16LE();
}
for (int i = 0; i < 10; i++) {
local_28[i] = fd->readUint16LE();
}
fd->close();
//local_48 = 0;
//local_76 = _vm->_scene->getSceneId();
local_78 = _vm->_dragonINIResource->getFlickerRecord();
local_78->actor->setFlag(ACTOR_FLAG_100);
local_78->actor->_priorityLayer = 0;
savedEngineFlags = _vm->getMultipleFlags(ENGINE_FLAG_8 | ENGINE_FLAG_10 | ENGINE_FLAG_20 | ENGINE_FLAG_80);
_vm->clearFlags(ENGINE_FLAG_8);
_vm->clearFlags(ENGINE_FLAG_10);
_vm->clearFlags(ENGINE_FLAG_20);
_vm->clearFlags(ENGINE_FLAG_80);
_vm->_dragonINIResource->setFlickerRecord(_vm->_dragonINIResource->getRecord(DAT_80063a40 - 1));
flickerActor = _vm->_dragonINIResource->getFlickerRecord()->actor;
flickerActor->_flags = flickerActor->_flags | 0x380;
flickerActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
flickerActor->_priorityLayer = 4;
flickerActor->_direction = -1;
flickerActor->updateSequence(0x19);
currentState = 0;
local_10 = 0;
local_850 = flickerActor->_x_pos;
uVar1 = flickerActor->_y_pos;
local_74 = 0;
// DisableVSyncEvent();
pusherActor = _vm->_actorManager->loadActor
(0x26, 0, (int)(short)local_850, (int)(((uint)uVar1 + 5) * 0x10000) >> 0x10);
// EnableVSyncEvent();
if (pusherActor == nullptr) {
error("Couldn't alloc pusher!");
}
pusherActor->_flags = pusherActor->_flags | 0x380;
pusherActor->_x_pos = flickerActor->_x_pos + -0xe;
pusherActor->_y_pos = flickerActor->_y_pos + 7;
pusherActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
pusherActor->_priorityLayer = 6;
// DisableVSyncEvent();
wheelsActor = _vm->_actorManager->loadActor(7, 0x11, 0, 0);
// EnableVSyncEvent();
if (wheelsActor == nullptr) {
error("Couldn't alloc wheels!");
}
wheelsActor->_flags = wheelsActor->_flags | 0x380;
wheelsActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
wheelsActor->_x_pos = flickerActor->_x_pos;
wheelsActor->_y_pos = flickerActor->_y_pos;
wheelsActor->_priorityLayer = 5;
wheelsActor->updateSequence(0x11);
local_62 = 0;
// DisableVSyncEvent();
bombActor = _vm->_actorManager->loadActor(7, 0x1c, 0, 0);
// EnableVSyncEvent();
if (bombActor == nullptr) {
error("Couldn't alloc bomb!");
}
bombActor->_flags = bombActor->_flags | 0x380;
bombActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
bombActor->_priorityLayer = 0;
// DisableVSyncEvent();
dustActor = _vm->_actorManager->loadActor(8, 8, 100, 100, 0);
// EnableVSyncEvent();
if (dustActor == nullptr) {
error("Couldn't alloc dust sprite!");
}
dustActor->_flags = dustActor->_flags | 0x380;
dustActor->_scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
local_4e = _vm->_dragonINIResource->getRecord(DAT_80063a48 + -1)->actor;
//local_4c = 0;
//local_4a = local_4e->_sequenceTimerMaxValue;
_vm->setFlags(ENGINE_FLAG_4000000);
currentState = 1;
local_66 = 0;
local_50 = 0;
while (true) {
while (true) {
do {
_vm->waitForFrames(1);
switch (currentState) {
case 1:
if (local_66 != 8) {
local_66 = 0;
}
//iVar2 = IsButtonBeingPressed((uint)DAT_800728ac, 0);
if (!_vm->isActionButtonPressed()) {
if (local_74 == 0) {
if ((((flickerActor->_sequenceID != 0) &&
(flickerActor->_sequenceID != 5)) &&
(flickerActor->_sequenceID != 6)) ||
((flickerActor->_flags & 4) != 0)) {
flickerActor->updateSequence(0x19);
}
} else {
local_66 = 1;
local_50 = 0;
pusherActor->updateSequence(1);
currentState = 2;
if (local_74 < 0x14) {
local_72 = 1;
} else {
if (local_74 < 0x2d) {
local_72 = 2;
} else {
if (local_74 < 0x169) {
local_72 = 3;
}
}
}
}
local_74 = 0;
} else {
pusherActor->_x_pos = flickerActor->_x_pos + -0xe;
pusherActor->_y_pos = flickerActor->_y_pos + 7;
if (local_74 < 0x168) {
local_74 = local_74 + 1;
if (local_74 < 0x14) {
if (((pusherActor->_sequenceID != 4) &&
(pusherActor->_sequenceID != 2)) &&
(pusherActor->_sequenceID != 3)) {
pusherActor->updateSequence(4);
}
if (flickerActor->_sequenceID != 0x1a) {
flickerActor->updateSequence(0x1a);
_vm->playOrStopSound(2);
}
} else {
if (local_74 < 0x2d) {
if (((pusherActor->_sequenceID != 5) &&
(pusherActor->_sequenceID != 2)) &&
(pusherActor->_sequenceID != 3)) {
pusherActor->updateSequence(5);
}
if (flickerActor->_sequenceID != 0x1e) {
flickerActor->updateSequence(0x1e);
_vm->playOrStopSound(3);
}
} else {
if (local_74 < 0x169) {
if (((pusherActor->_sequenceID != 6) &&
(pusherActor->_sequenceID != 2)) &&
(pusherActor->_sequenceID != 3)) {
pusherActor->updateSequence(6);
}
if (flickerActor->_sequenceID != 0x1f) {
flickerActor->updateSequence(0x1f);
_vm->playOrStopSound(4);
}
}
}
}
} else {
if (pusherActor->_sequenceID != 6) {
pusherActor->updateSequence(6);
}
if (flickerActor->_sequenceID != 0x1f) {
flickerActor->updateSequence(0x1f);
}
}
}
break;
case 2:
if (flickerActor->_sequenceID == 0x1b) {
if ((flickerActor->_flags & 4) != 0) {
if ((((int)(uint)local_850 < (int)((local_30[0]) - 6)) ||
((uint)local_30[1] + 6 < (uint)local_850)) || (local_72 != local_30[2])) {
local_42 = 8;
} else {
local_42 = 0;
}
local_5c = 0;
if ((local_42 != 8) && ((local_850 < local_30[0] || (local_30[1] < local_850)))) {
local_5c = (short)((int)(((local_30[0]) + 0x17) * 0x80) / 0x2a) -
(short)((int)((uint)local_850 << 7) / 0x2a);
}
local_60 = local_850 << 7;
bombActor->_x_pos = local_850 & 0x1ff;
local_5e = 0x2d00;
local_5a = (local_72 + 3) * 0x80;
bombActor->_y_pos = 0x5a;
bombScale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE;
bombActor->_scale = bombScale;
_vm->playOrStopSound(10);
bombActor->_priorityLayer = 3;
flickerActor->updateSequence(8);
currentState = 3;
}
} else {
flickerActor->updateSequence(0x1b);
_vm->playOrStopSound(1);
}
break;
case 3:
local_60 = local_60 + local_5c;
if ((uint)local_72 * 2 + 0xb4 < (uint)bombScale) {
local_5e = local_5e - local_5a;
local_5a = local_5a - local_28[((uint)local_72 - 1) * 3];
if (local_5a < 0) {
local_5a = 0;
}
} else {
if ((int)(uint)bombScale < (int)((uint)local_72 * -4 + 0xba)) {
local_5e = local_5e + local_5a;
local_5a = local_5a + local_28[((uint)local_72 - 1) * 3 + 2];
} else {
local_5a = 0;
}
}
bombActor->_x_pos = local_60 >> 7;
bombActor->_y_pos = local_5e >> 7;
bombScale = bombScale - 3;
bombActor->_scale = bombScale;
if (bombScale == 0x7f) {
if (((local_60 >> 7 < local_30[0]) || (local_30[1] < local_60 >> 7)) ||
(local_72 != local_30[2])) {
local_42 = 8;
} else {
local_42 = 0;
}
if (local_42 == 8) {
if ((((local_72 == 1) && (local_60 >> 7 < 0x10e)) ||
((local_72 == 2 &&
((((0x7f < local_60 >> 7 && (local_60 >> 7 < 0xad)) ||
((0x30 < local_60 >> 7 && (local_60 >> 7 < 0x4a)))) ||
((0xf8 < local_60 >> 7 && (local_60 >> 7 < 0x10f)))))))) ||
((local_72 == 3 &&
(((0x3c < local_60 >> 7 && (local_60 >> 7 < 0x46)) ||
((0x101 < local_60 >> 7 && (local_60 >> 7 < 0x10a)))))))) {
bombActor->_priorityLayer = 0;
dustActor->_priorityLayer = 4;
dustActor->_x_pos = bombActor->_x_pos;
dustActor->_y_pos = bombActor->_y_pos;
dustActor->updateSequence(9);
currentState = 4;
}
} else {
local_4e->_sequenceTimerMaxValue = 2;
//local_4c = 0x3c;
bombActor->_priorityLayer = 0;
currentState = 8;
}
}
if (bombScale < 0x7f) {
bombActor->_priorityLayer = 2;
}
if ((0xc < bombScale) && (bombScale < 0x41)) {
bombActor->_priorityLayer = 0;
}
if ((short)bombScale < 2) {
currentState = 5;
}
break;
case 4:
pusherActor->updateSequence(9);
_vm->waitForFrames(0x3c);
pusherActor->updateSequence(0xb);
if (_dat_800633e6 == 0) {
uint32 textId = _vm->getDialogTextId(0x21BF0);
_vm->_talk->loadText(textId, auStack2120, 1000);
_vm->_talk->displayDialogAroundPoint(auStack2120, (int)(short)(local_850 >> 3), 0xc, 0, 1, textId);
_dat_800633e6 = 1;
} else {
uint32 textId = _vm->getDialogTextId(0x21DAE);
_vm->_talk->loadText(textId, auStack2120, 1000);
_vm->_talk->displayDialogAroundPoint(auStack2120, (int)(short)(local_850 >> 3), 0xc, 0, 1, textId);
}
_vm->waitForFrames(10);
local_10 = 1;
currentState = 6;
break;
case 5:
currentState = 4;
break;
case 6:
currentState = 7;
break;
case 7:
break;
case 8:
bombActor->_priorityLayer = 0;
pusherActor->updateSequence(0);
_vm->_dragonINIResource->getRecord(DAT_80063bd0 + -1)->actor->updateSequence(2);
_vm->waitForFrames(0x12);
_vm->_talk->loadText(_vm->getDialogTextId(0x21E3E), auStack2120, 1000);
_vm->_talk->displayDialogAroundPoint(auStack2120, 0xf, 2, 0x501, 0, _vm->getDialogTextId(0x21E3E));
_vm->clearAllText();
_vm->_dragonINIResource->getRecord(DAT_80063bd0 + -1)->actor->updateSequence(3);
_vm->_dragonINIResource->getRecord(DAT_80063bd0 + -1)->actor->waitUntilFlag8And4AreSet();
pusherActor->updateSequence(7);
_vm->_talk->loadText(_vm->getDialogTextId(0x475DA), auStack2120, 1000);
_vm->_talk->displayDialogAroundPoint(auStack2120, (int)(short)(local_850 >> 3), 0xc, 0, 1, _vm->getDialogTextId(0x475DA));
pusherActor->_flags = pusherActor->_flags | 0x1000;
local_10 = 2;
//local_48 = 1;
currentState = 6;
break;
default:
debug("undefined state!");
currentState = 1;
bombActor->_priorityLayer = 0;
break;
}
if ((local_10 == 0) && (currentState != 2)) {
if (!_vm->isLeftKeyPressed() || (local_850 < 0x37)) {
if (!_vm->isRightKeyPressed() || (0x107 < local_850)) {
if ((pusherActor->_sequenceID != local_66) &&
(((pusherActor->_sequenceID != 4 && (pusherActor->_sequenceID != 5))
&& (pusherActor->_sequenceID != 6)))) {
pusherActor->updateSequence((uint)local_66);
if (local_50 == 0) {
pusherActor->_x_pos = flickerActor->_x_pos + -0xe;
pusherActor->_y_pos = flickerActor->_y_pos + 7;
} else {
pusherActor->_x_pos = flickerActor->_x_pos + 2;
pusherActor->_y_pos = flickerActor->_y_pos;
}
}
} else {
local_50 = 1;
local_66 = 8;
if (pusherActor->_sequenceID != 2) {
pusherActor->updateSequence(2);
}
local_850 = local_850 + 2;
if (local_850 < 0x109) {
if (local_850 < 0x36) {
local_850 = 0x36;
}
} else {
local_850 = 0x108;
}
if (local_62 == 0) {
local_62 = 0xb;
} else {
local_62 = local_62 - 1;
}
flickerActor->_x_pos = local_850;
wheelsActor->_x_pos = local_850;
if ((uint)wheelsActor->_sequenceID != (uint)local_62 / 3 + 0x11) {
wheelsActor->updateSequence((uint)local_62 / 3 + 0x11);
}
pusherActor->_x_pos = flickerActor->_x_pos + 2;
pusherActor->_y_pos = flickerActor->_y_pos;
}
} else {
local_50 = 0;
local_66 = (uint16)(currentState != 1);
if (pusherActor->_sequenceID != 3) {
pusherActor->updateSequence(3);
}
local_850 = local_850 - 2;
if (local_850 < 0x109) {
if (local_850 < 0x36) {
local_850 = 0x36;
}
} else {
local_850 = 0x108;
}
local_62 = (short)((uint)local_62 + 1) +
(short)((int)((uint)local_62 + 1) / 6 >> 1) * -0xc;
flickerActor->_x_pos = local_850;
wheelsActor->_x_pos = local_850;
if ((uint)wheelsActor->_sequenceID != (uint)local_62 / 3 + 0x11) {
wheelsActor->updateSequence((uint)local_62 / 3 + 0x11);
}
pusherActor->_x_pos = flickerActor->_x_pos + -2;
pusherActor->_y_pos = flickerActor->_y_pos;
}
}
} while (local_10 == 0);
if ((local_10 == 2) || (0x117 < flickerActor->_x_pos)) break;
flickerActor->_x_pos = flickerActor->_x_pos + 2;
if (pusherActor->_sequenceID != 2) {
pusherActor->updateSequence(2);
}
pusherActor->_x_pos = flickerActor->_x_pos + 2;
pusherActor->_y_pos = flickerActor->_y_pos;
wheelsActor->_x_pos = wheelsActor->_x_pos + 2;
if (local_62 == 0) {
local_62 = 0xb;
} else {
local_62 = local_62 - 1;
}
if ((uint)wheelsActor->_sequenceID != (uint)local_62 / 3 + 0x11) {
wheelsActor->updateSequence((uint)local_62 / 3 + 0x11);
}
}
if (local_10 == 1) break;
if (local_10 == 2) {
_vm->_dragonINIResource->getRecord(DAT_80063a40 + -1)->objectState2 = 2;
pusherActor->updateSequence(7);
_vm->waitForFrames(0x3c);
pusherActor->updateSequence(1);
_vm->waitForFrames(0x1e);
_vm->_dragonINIResource->getRecord(DAT_80063a40 + -1)->actor->clearFlag(ACTOR_FLAG_100);
LAB_8009157c:
_vm->clearAllText();
flickerActor->updateSequence(0x15);
local_46 = 0;
//local_44 = 0;
if (local_10 == 2) {
// DisableVSyncEvent();
local_46 = pusherActor->_x_pos;
//local_44 = pusherActor->_y_pos;
pusherActor->reset_maybe();
// EnableVSyncEvent();
} else {
// DisableVSyncEvent();
dustActor->reset_maybe();
bombActor->reset_maybe();
wheelsActor->reset_maybe();
pusherActor->reset_maybe();
// EnableVSyncEvent();
}
_vm->_dragonINIResource->setFlickerRecord(local_78);
if (local_10 == 2) {
local_78->actor->_x_pos = local_46;
local_78->actor->setFlag(ACTOR_FLAG_100);
local_78->actor->_priorityLayer = 5;
} else {
local_78->actor->clearFlag(ACTOR_FLAG_100);
local_78->actor->_priorityLayer = 2;
}
_vm->clearFlags(ENGINE_FLAG_4000000);
_vm->setFlags(savedEngineFlags);
return;
}
}
_vm->_dragonINIResource->getRecord(DAT_80063a40 + -1)->actor->clearFlag(ACTOR_FLAG_100);
_vm->_dragonINIResource->getRecord(DAT_80063a40 + -1)->objectState2 = 0;
goto LAB_8009157c;
}
} // End of namespace Dragons

View File

@@ -0,0 +1,40 @@
/* 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 DRAGONS_MINIGAME5_H
#define DRAGONS_MINIGAME5_H
namespace Dragons {
class DragonsEngine;
class Minigame5 {
private:
DragonsEngine *_vm;
uint16 _dat_800633e6;
public:
Minigame5(DragonsEngine *vm);
void run();
};
} // End of namespace Dragons
#endif //DRAGONS_MINIGAME5_H

48
engines/dragons/module.mk Normal file
View File

@@ -0,0 +1,48 @@
MODULE := engines/dragons
MODULE_OBJS := \
actor.o \
actorresource.o \
background.o \
bag.o \
bigfile.o \
credits.o \
cursor.o \
cutscene.o \
dragonflg.o \
dragonimg.o \
dragonini.o \
dragonobd.o \
dragonrms.o \
dragonvar.o \
dragons.o \
font.o \
inventory.o \
metaengine.o \
midimusicplayer.o \
minigame1.o \
minigame2.o \
minigame3.o \
minigame4.o \
minigame5.o \
saveload.o \
scene.o \
screen.o \
scriptopcodes.o \
sequenceopcodes.o \
specialopcodes.o \
sound.o \
talk.o \
vabsound.o \
strplayer.o
# This module can be built as a plugin
ifeq ($(ENABLE_DRAGONS), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

View File

@@ -0,0 +1,164 @@
/* 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/savefile.h"
#include "graphics/thumbnail.h"
#include "dragons/dragons.h"
#include "dragons/dragonflg.h"
#include "dragons/dragonini.h"
#include "dragons/dragonvar.h"
#include "dragons/scene.h"
#include "dragons/cursor.h"
namespace Dragons {
#define ILLUSIONS_SAVEGAME_VERSION 0
kReadSaveHeaderError DragonsEngine::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) {
header.version = in->readUint32LE();
if (header.version > ILLUSIONS_SAVEGAME_VERSION)
return kRSHEInvalidVersion;
byte descriptionLen = in->readByte();
header.description = "";
while (descriptionLen--) {
header.description += (char)in->readByte();
}
if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return kRSHEIoError;
}
// Not used yet, reserved for future usage
// header.gameID = in->readByte();
header.flags = in->readUint32LE();
header.saveDate = in->readUint32LE();
header.saveTime = in->readUint32LE();
header.playTime = in->readUint32LE();
return ((in->eos() || in->err()) ? kRSHEIoError : kRSHENoError);
}
bool DragonsEngine::savegame(const char *filename, const char *description) {
Common::OutSaveFile *out;
if (!(out = g_system->getSavefileManager()->openForSaving(filename))) {
warning("Can't create file '%s', game not saved", filename);
return false;
}
TimeDate curTime;
g_system->getTimeAndDate(curTime);
// Header start
out->writeUint32LE(ILLUSIONS_SAVEGAME_VERSION);
byte descriptionLen = strlen(description);
out->writeByte(descriptionLen);
out->write(description, descriptionLen);
// TODO Probably pre-generate the thumbnail before the internal menu system is
// called to have a thumbnail without the menu system itself on it.
// Use the automatic thumbnail generation only when the ScummVM save dialog is used.
Graphics::saveThumbnail(*out);
// Not used yet, reserved for future usage
//out->writeByte(0);
out->writeUint32LE(0);
uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
uint32 saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
uint32 playTime = g_engine->getTotalPlayTime() / 1000;
out->writeUint32LE(saveDate);
out->writeUint32LE(saveTime);
out->writeUint32LE(playTime);
// Header end
//TODO save gamestate here. _gameState->write(out);
out->writeByte((int8)getCurrentSceneId());
_dragonFLG->saveState(out);
out->finalize();
delete out;
return true;
}
bool DragonsEngine::loadgame(const char *filename) {
Common::InSaveFile *in;
if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
warning("Can't open file '%s', game not loaded", filename);
return false;
}
SaveHeader header;
kReadSaveHeaderError errorCode = readSaveHeader(in, header);
if (errorCode != kRSHENoError) {
warning("Error loading savegame '%s'", filename);
delete in;
return false;
}
g_engine->setTotalPlayTime(header.playTime * 1000);
reset();
// TODO load game state here. _gameState->read(in);
uint16 newSceneId = (uint16)in->readByte();
_dragonFLG->loadState(in);
//_dragonFLG->set(165, true); //TODO check why this is needed to load save games properly.
_dragonFLG->set(125, false); //TODO check why this is needed to load save games properly.
_dragonVAR->reset();
_dragonINIResource->reset();
init();
loadScene(newSceneId);
setFlags(ENGINE_FLAG_8); //Re-enable cursor TODO should we need to do this?
delete in;
return true;
}
Common::Error DragonsEngine::loadGameState(int slot) {
if (!loadgame(getSavegameFilename(slot).c_str()))
return Common::kReadingFailed;
return Common::kNoError;
}
Common::Error DragonsEngine::saveGameState(int slot, const Common::String &description, bool isAutoSave) {
if (!savegame(getSavegameFilename(slot).c_str(), description.c_str()))
return Common::kWritingFailed;
return Common::kNoError;
}
Common::String DragonsEngine::getSavegameFilename(int num) {
return getSavegameFilename(_targetName, num);
}
Common::String DragonsEngine::getSavegameFilename(const Common::String &target, int num) {
assert(num >= 0 && num <= 999);
return Common::String::format("%s.%03d", target.c_str(), num);
}
} // End of namespace Illusions

534
engines/dragons/scene.cpp Normal file
View File

@@ -0,0 +1,534 @@
/* 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 "dragons/scene.h"
#include "dragons/dragons.h"
#include "dragons/actor.h"
#include "dragons/background.h"
#include "dragons/cursor.h"
#include "dragons/credits.h"
#include "dragons/dragonini.h"
#include "dragons/dragonimg.h"
#include "dragons/font.h"
#include "dragons/inventory.h"
#include "dragons/screen.h"
#include "dragons/actorresource.h"
#include "dragons/scriptopcodes.h"
namespace Dragons {
Scene::Scene(DragonsEngine *vm, Screen *screen, ScriptOpcodes *scriptOpcodes, ActorManager *actorManager, DragonRMS *dragonRMS, DragonINIResource *dragonINIResource, BackgroundResourceLoader *backgroundResourceLoader)
: _vm(vm), _screen(screen), _scriptOpcodes(scriptOpcodes), _stage(nullptr), _actorManager(actorManager), _dragonRMS(dragonRMS), _dragonINIResource(dragonINIResource), _backgroundLoader(backgroundResourceLoader) {
_mapTransitionEffectSceneID = 2;
_data_800633ee = 0;
_currentSceneId = -1;
}
void Scene::loadScene(uint32 sceneId, uint32 cameraPointId) {
if (!_vm->isFlagSet(ENGINE_FLAG_40)) {
_vm->fadeToBlack();
}
bool unkFlag2Set = _vm->isUnkFlagSet(ENGINE_UNK1_FLAG_2);
bool flag8set = _vm->isFlagSet(ENGINE_FLAG_8);
_vm->clearFlags(ENGINE_FLAG_8);
_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
for (int i = 0; i < 8; i++) {
_vm->_paletteCyclingTbl[i].updateInterval = 0;
}
// TODO
_vm->reset_screen_maybe();
loadSceneData(sceneId, cameraPointId);
if (flag8set) {
_vm->setFlags(ENGINE_FLAG_8);
}
if (!_vm->isFlagSet(ENGINE_FLAG_8000000) && sceneId != 4) {
_vm->_cursor->updateSequenceID((int16)_vm->_cursor->_sequenceID);
}
_vm->waitForFrames(2);
_vm->fadeFromBlack();
if (!unkFlag2Set) {
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
}
_data_800633ee = 0;
if (!(sceneId & 0x8000)) {
byte *obd = _dragonRMS->getAfterSceneLoadedScript(sceneId);
ScriptOpCall scriptOpCall(obd + 4, READ_LE_UINT32(obd));
_scriptOpcodes->runScript(scriptOpCall);
}
DragonINI *ini = _dragonINIResource->getRecord(0xc4);
ini->objectState = 0;
}
void Scene::loadSceneData(uint32 sceneId, uint32 cameraPointId) {
bool isUnkFlag2Set = _vm->isUnkFlagSet(ENGINE_UNK1_FLAG_2);
_vm->setUnkFlags(ENGINE_UNK1_FLAG_2 | Dragons::ENGINE_UNK1_FLAG_8);
for (int i = 0; i < _dragonINIResource->totalRecords(); i++) {
DragonINI *ini = _dragonINIResource->getRecord(i);
ini->counter = -1;
ini->flags &= ~INI_FLAG_10;
}
uint16 sceneIdStripped = (uint16)sceneId & ~0x8000;
if (sceneIdStripped == 0x18 || sceneIdStripped == 0x26 || sceneIdStripped == 0x7 ||
sceneIdStripped == 0x17 || sceneIdStripped == 0x5 || sceneIdStripped == 0x19 ||
sceneIdStripped == 0x34 || sceneIdStripped == 0x1d || sceneIdStripped == 0x6) {
// buf2048bytes = buf2048bytes + 0x1800;
// error("0x8002f404"); //TODO do we need this logic?
}
_screen->setScreenShakeOffset(0, 0);
if (!(sceneId & 0x8000)) {
byte *obd = _dragonRMS->getBeforeSceneDataLoadedScript(sceneId);
ScriptOpCall scriptOpCall(obd + 4, READ_LE_UINT32(obd));
uint16 oldSceneId = _currentSceneId;
_currentSceneId = -1;
_scriptOpcodes->runScript(scriptOpCall);
_currentSceneId = oldSceneId;
}
_actorManager->clearActorFlags(2);
//TODO stopAndCloseSceneVab()
_vm->_cursor->setActorFlag400();
_vm->_inventory->setActorFlag400();
_vm->clearFlags(ENGINE_FLAG_200);
resetActorFrameFlags();
// Loading animation logic would go here. 0x8002f538
_vm->clearFlags(ENGINE_FLAG_20);
_vm->setUnkFlags(ENGINE_UNK1_FLAG_10);
_vm->fadeFromBlack();
// TODO 0x8002f7c4
_vm->_cursor->updatePosition(160, 100);
_vm->clearFlags(ENGINE_FLAG_100000);
_vm->clearFlags(ENGINE_FLAG_200000);
DragonINI *flicker = _vm->_dragonINIResource->getFlickerRecord();
if (flicker == nullptr || flicker->sceneId == 0) {
_vm->getINI(1)->sceneId = 0;
} else {
_currentSceneId = (uint16)(sceneId & 0x7fff);
flicker->sceneId = _currentSceneId;
_vm->getINI(1)->sceneId = _currentSceneId;
}
_vm->loadCurrentSceneMsf();
_stage = _backgroundLoader->load(sceneId);
if (!_vm->isFlagSet(ENGINE_FLAG_800)) {
byte *cursorPalette = _vm->_cursor->getPalette();
byte *stagePalette = _stage->getPalette();
for (int i = 0xc0; i < 0x100; i++) {
stagePalette[i * 2] = cursorPalette[(i-0xc0) * 2];
stagePalette[i * 2 + 1] = cursorPalette[(i-0xc0) * 2 + 1];
}
}
for (int i = 1; i < 0x100; i ++) {
byte *stagePalette = _stage->getPalette();
uint16 c = READ_LE_INT16(stagePalette + i * 2);
if ((c & 0x7fff) == 0) {
stagePalette[i * 2 + 1] |= 0x80;
}
}
_screen->loadPalette(0, _stage->getPalette());
for (int i = 1; i < 0x100; i ++) {
byte *stagePalette = _stage->getPalette();
uint16 c = READ_LE_INT16(stagePalette + i * 2);
if ((c & 0x7fff) == 0) {
stagePalette[i * 2] = 1;
stagePalette[i * 2 + 1] = 0;
}
}
_camera = _stage->getPoint2(cameraPointId);
if (flicker && !(sceneId & 0x8000)) {
flicker->x = _camera.x;
flicker->y = _camera.y;
_vm->getINI(1)->x = _camera.x;
_vm->getINI(1)->y = _camera.y;
}
debug(3, "Flicker: (%X, %X)", _camera.x, _camera.y);
if (_camera.x > 160) {
_camera.x -= 160;
} else {
_camera.x = 0;
}
if (_camera.y > 100) {
_camera.y -= 100;
} else {
_camera.y = 0;
}
if (_camera.x + 320 >= _stage->getWidth()) {
_camera.x = _stage->getWidth() - 320;
}
if (_camera.y + 200 >= _stage->getHeight()) {
_camera.y = _stage->getHeight() - 200;
}
debug(3, "Camera: (%d, %d)", _camera.x, _camera.y);
// 0x8002ff80
_vm->fadeToBlack();
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_10);
_vm->setFlags(ENGINE_FLAG_20);
// TODO reset vsync_updater_function
_vm->setFlags(ENGINE_FLAG_200);
_actorManager->clearActorFlags(2);
_vm->_isLoadingDialogAudio = false;
// TODO 0x8002fff0
for (int i = 0; i < _dragonINIResource->totalRecords(); i++) {
DragonINI *ini = _dragonINIResource->getRecord(i);
if (ini->sceneId == sceneIdStripped) {
if (ini->flags & 1) {
Actor *actor = _actorManager->loadActor(ini->actorResourceId, ini->sequenceId, ini->x, ini->y, 0);
if (actor) {
ini->actor = actor;
if (ini->flags & 0x1000) {
actor->_frame_flags |= 0x10;
} else {
if (ini->flags & 0x2000) {
actor->_frame_flags |= 0x20;
} else {
actor->_frame_flags &= ~0x10;
}
}
actor->_direction = ini->direction2;
if (ini->flags & 2) {
actor->_flags |= ACTOR_FLAG_80;
} else {
actor->_flags &= 0xfeff;
}
if (ini->flags & 0x20) {
actor->_flags |= ACTOR_FLAG_100;
} else {
actor->_flags &= 0xfeff;
}
if (ini->flags & 4) {
actor->_flags |= ACTOR_FLAG_8000;
} else {
actor->_flags &= 0x7fff;
}
if (ini->flags & 0x100) {
actor->_flags |= ACTOR_FLAG_4000;
} else {
actor->_flags &= 0xbfff;
}
//
// Graphics::Surface *s = actor->getCurrentFrame();
// int x = ini->x - actor->_frame_vram_x;
// int y = ini->y - actor->_frame_vram_y;
// if (x >= 0 && y >= 0 && x + s->w < 320 && y + s->h < 200) {
// debug("Actor %d, %d %d (%d, %d)", actor->_actorID, ini->actorResourceId, ini->flags, ini->x, ini->y);
// _stage->getFgLayer()->copyRectToSurface(*s, x, y, Common::Rect(s->w, s->h));
// }
}
// _stage->getFgLayer()->drawLine(ini->x, ini->y, ini->x + 8, ini->y + 8, 0x7c00);
//break;
} else {
if (ini->iptIndex_maybe != -1) {
loadImageOverlay(ini->iptIndex_maybe);
}
}
}
}
// 0x80030458
DragonINI *ini = _vm->getINI(1);
if (ini->actor && _vm->_dragonINIResource->getFlickerRecord() && _vm->_dragonINIResource->getFlickerRecord()->sceneId == _currentSceneId) {
ini->actor->setFlag(ACTOR_FLAG_100);
ini->actor->_priorityLayer = 0;
}
if (flicker && flicker->sceneId != 0) {
flicker->direction2 = _vm->_flickerInitialSceneDirection;
if (flicker->actor) {
flicker->actor->_direction = _vm->_flickerInitialSceneDirection;
flicker->actor->setFlag(ACTOR_FLAG_4);
}
}
// 0x800305bc
_vm->_inventory->loadScene(_currentSceneId);
// 0x8003070c
// TODO sub_80013b3c(); // palette related.
if (_vm->_inventory->isOpen()) {
_vm->_inventory->close();
}
if (!_vm->isFlagSet(ENGINE_FLAG_10000)) {
_vm->setFlags(ENGINE_FLAG_10);
}
_vm->setFlags(ENGINE_FLAG_1);
_vm->setFlags(ENGINE_FLAG_200);
_vm->setFlags(ENGINE_FLAG_4000000);
if (flicker && flicker->sceneId == _currentSceneId) {
flicker->actor->updateSequence((uint16)flicker->actor->_direction);
}
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_2);
_vm->clearUnkFlags(ENGINE_UNK1_FLAG_8);
if (isUnkFlag2Set) {
_vm->setUnkFlags(ENGINE_UNK1_FLAG_2);
}
if (!(sceneId & 0x8000)) {
byte *obd = _dragonRMS->getAfterSceneDataLoadedScript(sceneId);
ScriptOpCall scriptOpCall(obd + 4, READ_LE_UINT32(obd));
_scriptOpcodes->runScript(scriptOpCall);
}
}
void Scene::draw() {
Common::Rect rect(_camera.x, _camera.y, _camera.x + 320, _camera.y + 200);
_vm->_screen->clearScreen();
for (uint16 priority = 1; priority < 16; priority++) {
if (_vm->isInMenu() || (priority == 7 && _vm->isFlagSet(ENGINE_FLAG_200))) {
_vm->_fontManager->updatePalette();
_vm->_fontManager->draw();
}
if (_vm->isFlagSet(ENGINE_FLAG_200)) {
if (priority == 5) {
if (_vm->isFlagSet(ENGINE_FLAG_80)) {
_vm->_inventory->draw();
}
}
if (priority == _stage->getFgLayerPriority()) {
drawBgLayer(2, rect, _stage->getFgLayer());
}
if (priority == _stage->getMgLayerPriority()) {
drawBgLayer(1, rect, _stage->getMgLayer());
}
if (priority == _stage->getBgLayerPriority()) {
drawBgLayer(0, rect, _stage->getBgLayer());
}
}
_screen->drawFlatQuads(priority);
for (int16 i = 0; i < DRAGONS_ENGINE_NUM_ACTORS; i++) {
Actor *actor = _actorManager->getActorByDisplayOrder(i);
if (actor->_x_pos == -100 && actor->_y_pos == 100) {
actor->_priorityLayer = 0;
continue;
}
if (actor->_flags & ACTOR_FLAG_40 &&
!(actor->_flags & ACTOR_FLAG_400) &&
actor->_surface &&
actor->_frame->width != 0 &&
actor->_frame->height != 0) {
Graphics::Surface *s = actor->_surface;
if (actor->_priorityLayer == priority) { //} && x + s->w < 320 && y + s->h < 200) {
if (!actor->isFlagSet(ACTOR_FLAG_80)) {
actor->_scale = _stage->getScaleLayer()->getScale(actor->_y_pos);
}
int x = actor->_x_pos - (actor->_frame->xOffset * actor->_scale / DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE) - (actor->isFlagSet(ACTOR_FLAG_200) ? 0 : _camera.x);
int y = actor->_y_pos - (actor->_frame->yOffset * actor->_scale / DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE) - (actor->isFlagSet(ACTOR_FLAG_200) ? 0 : _camera.y);
debug(5, "Actor %d %s (%d, %d) w:%d h:%d Priority: %d Scale: %d", actor->_actorID, actor->_actorResource->getFilename(), x,
y,
s->w, s->h, actor->_priorityLayer, actor->_scale);
_screen->copyRectToSurface8bpp(*s, actor->getPalette(), x, y, Common::Rect(s->w, s->h), (bool)(actor->_frame->flags & FRAME_FLAG_FLIP_X), actor->isFlagSet(ACTOR_FLAG_8000) ? NONE : NORMAL, actor->_scale);
if (_vm->isDebugMode()) {
_screen->drawRect(0x7fff, Common::Rect(x, y, x + s->w, y + s->h), actor->_actorID);
drawActorNumber(x + s->w, y + 8, actor->_actorID);
}
}
}
}
}
if (_vm->_credits->isRunning()) {
_vm->_credits->draw();
}
if (_vm->isDebugMode()) {
_vm->_fontManager->clearText();
}
}
int16 Scene::getPriorityAtPosition(Common::Point pos) {
return _stage->getPriorityAtPoint(pos);
}
bool Scene::contains(DragonINI *ini) {
assert(ini);
return ini->sceneId == _currentSceneId;
}
byte *Scene::getPalette() {
assert(_stage);
return _stage->getPalette();
}
uint16 Scene::getSceneId() {
return (uint16)_currentSceneId;
}
Common::Point Scene::getPoint(uint32 pointIndex) {
return _stage->getPoint2(pointIndex);
}
uint16 Scene::getStageWidth() {
return _stage->getWidth();
}
uint16 Scene::getStageHeight() {
return _stage->getHeight();
}
void Scene::loadImageOverlay(uint16 iptId) {
Img *img =_vm->_dragonImg->getImg(iptId);
if (img->h != 0) {
if (img->field_e <= 2) {
_stage->overlayImage(img->layerNum - 1, img->data, img->x, img->y, img->w, img->h);
}
if (img->field_e == 2 || img->field_e == 0) {
_stage->overlayPriorityTileMap(img->data + img->w * img->h * 2, img->x, img->y, img->w, img->h);
}
}
}
void Scene::removeImageOverlay(uint16 iptId) {
Img *img =_vm->_dragonImg->getImg(iptId);
_stage->restoreTiles(img->layerNum - 1, img->x, img->y, img->w, img->h);
_stage->restorePriorityTileMap(img->x, img->y, img->w, img->h);
}
void Scene::setSceneId(int16 newSceneId) {
_currentSceneId = newSceneId;
}
void Scene::resetActorFrameFlags() {
for (int i = 0; i < 0x17; i++) {
Actor *actor = _vm->_actorManager->getActor(i);
actor->_frame_flags &= ~ACTOR_FRAME_FLAG_10;
actor->_frame_flags &= ~ACTOR_FRAME_FLAG_20;
}
}
void Scene::setBgLayerPriority(uint8 newPriority) {
_stage->setBgLayerPriority(newPriority);
}
void Scene::setMgLayerPriority(uint8 newPriority) {
_stage->setMgLayerPriority(newPriority);
}
void Scene::setFgLayerPriority(uint8 newPriority) {
_stage->setFgLayerPriority(newPriority);
}
void Scene::setStagePalette(byte *newPalette) {
_stage->setPalette(newPalette);
}
void Scene::drawActorNumber(int16 x, int16 y, uint16 actorId) {
uint16 text[30];
char text8[15];
Common::sprintf_s(text8, "%d", actorId);
for (uint i = 0; i < strlen(text8); i++) {
text[i] = text8[i];
}
_vm->_fontManager->addText(x, y, text, strlen(text8), 1);
}
void Scene::setLayerOffset(uint8 layerNumber, Common::Point offset) {
_stage->setLayerOffset(layerNumber, offset);
}
Common::Point Scene::getLayerOffset(uint8 layerNumber) {
return _stage->getLayerOffset(layerNumber);
}
void Scene::drawBgLayer(uint8 layerNumber, Common::Rect rect, Graphics::Surface *surface) {
Common::Point offset = _stage->getLayerOffset(layerNumber);
// Common::Rect clippedRect = _screen->clipRectToRect(offset.x, offset.y, rect, Common::Rect(_stage->getBgLayer()->w, _stage->getBgLayer()->h));
rect.left += rect.left + offset.x < 0 ? -(rect.left + offset.x) : offset.x;
if (rect.right + offset.x > surface->w) {
rect.right = surface->w - 1;
} else {
rect.right += offset.x;
}
// clippedRect.right += offset.x < 0 ? -offset.x : 0;
rect.top += rect.top + offset.y < 0 ? -(rect.top + offset.y) : offset.y;
if (rect.bottom + offset.y > surface->h) {
rect.bottom = surface->h - 1;
} else {
rect.bottom += offset.y;
}
// clippedRect.bottom += offset.y < 0 ? -offset.y : 0;
_screen->copyRectToSurface8bppWrappedX(*surface, _screen->getPalette(0), rect, _stage->getLayerAlphaMode(layerNumber));
}
ScaleLayer *Scene::getScaleLayer() {
return _stage->getScaleLayer();
}
void Scene::setLayerAlphaMode(uint8 layerNumber, AlphaBlendMode mode) {
_stage->setLayerAlphaMode(layerNumber, mode);
}
} // End of namespace Dragons

93
engines/dragons/scene.h Normal file
View File

@@ -0,0 +1,93 @@
/* 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 DRAGONS_SCENE_H
#define DRAGONS_SCENE_H
#include "common/rect.h"
#include "common/system.h"
#include "dragons/screen.h"
namespace Dragons {
class DragonsEngine;
class ActorManager;
class Background;
class DragonRMS;
class BackgroundResourceLoader;
class DragonINIResource;
class Screen;
class ScriptOpcodes;
class ScaleLayer;
struct DragonINI;
class Scene {
public:
Common::Point _camera;
int16 _mapTransitionEffectSceneID;
private:
DragonsEngine *_vm;
Screen *_screen;
ActorManager *_actorManager;
Background *_stage;
DragonRMS *_dragonRMS;
DragonINIResource *_dragonINIResource;
BackgroundResourceLoader *_backgroundLoader;
ScriptOpcodes *_scriptOpcodes;
int16 _currentSceneId;
int16 _data_800633ee; //TODO this isn't referenced. Is it needed?
public:
Scene(DragonsEngine *vm, Screen *screen, ScriptOpcodes *scriptOpcodes, ActorManager *actorManager, DragonRMS *_dragonRMS, DragonINIResource *_dragonINIResource, BackgroundResourceLoader *backgroundResourceLoader);
void loadScene(uint32 sceneId, uint32 cameraPointId);
void loadSceneData(uint32 sceneId, uint32 cameraPointId);
int16 getPriorityAtPosition(Common::Point pos);
void draw();
bool contains(DragonINI *ini);
byte *getPalette();
void setStagePalette(byte *newPalette);
uint16 getSceneId();
void setSceneId(int16 newSceneId);
Common::Point getPoint(uint32 pointIndex);
uint16 getStageWidth();
uint16 getStageHeight();
void loadImageOverlay(uint16 iptId);
void removeImageOverlay(uint16 iptId);
void setBgLayerPriority(uint8 newPriority);
void setMgLayerPriority(uint8 newPriority);
void setFgLayerPriority(uint8 newPriority);
void setLayerOffset(uint8 layerNumber, Common::Point offset);
Common::Point getLayerOffset(uint8 layerNumber);
ScaleLayer *getScaleLayer();
void setLayerAlphaMode(uint8 layerNumber, AlphaBlendMode mode);
private:
void resetActorFrameFlags();
void drawActorNumber(int16 x, int16 y, uint16 actorId);
void drawBgLayer(uint8 layerNumber, Common::Rect rect, Graphics::Surface *surface);
};
} // End of namespace Dragons
#endif //DRAGONS_SCENE_H

493
engines/dragons/screen.cpp Normal file
View File

@@ -0,0 +1,493 @@
/* 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/endian.h"
#include "common/system.h"
#include "common/rect.h"
#include "engines/util.h"
#include "dragons/dragons.h"
#include "dragons/scene.h"
#include "dragons/screen.h"
namespace Dragons {
Screen::Screen() {
//TODO add support for more video modes like RGB565 and RGBA555
_pixelFormat = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0);
initGraphics(320, 200, &_pixelFormat);
_backSurface = new Graphics::Surface();
_backSurface->create(320, 200, _pixelFormat);
_screenShakeOffset = Common::Point();
}
void Screen::updateScreen() {
if (_screenShakeOffset.x != 0 || _screenShakeOffset.y != 0) {
g_system->fillScreen(0); //TODO this is meant for 8bit screens. we should use system shake here.
}
Common::Rect clipRect = clipRectToScreen(_screenShakeOffset.x, _screenShakeOffset.y, Common::Rect(_backSurface->w, _backSurface->h));
g_system->copyRectToScreen((byte*)_backSurface->getBasePtr(clipRect.left, clipRect.top),
_backSurface->pitch,
_screenShakeOffset.x < 0 ? 0 : _screenShakeOffset.x, _screenShakeOffset.y < 0 ? 0 : _screenShakeOffset.y,
clipRect.width(), clipRect.height());
// if (_screenShakeOffset < 0) {
// _backSurface->fillRect(Common::Rect(0, _backSurface->h + _screenShakeOffset - 1, _backSurface->w - 1, _backSurface->h - 1), 0);
// }
// if (_screenShakeOffset > 0) {
// _backSurface->fillRect(Common::Rect(0, 0, _backSurface->w - 1, _screenShakeOffset - 1), 0);
// }
g_system->updateScreen();
}
Screen::~Screen() {
_backSurface->free();
delete _backSurface;
}
void Screen::copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY) {
copyRectToSurface(srcSurface.getBasePtr(0, 0), srcSurface.pitch, srcSurface.w, 0, destX, destY, srcSurface.w, srcSurface.h, false, NONE);
}
void Screen::copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect &srcRect, bool flipX, AlphaBlendMode alpha) {
Common::Rect clipRect = clipRectToScreen(destX, destY, srcRect);
if (clipRect.width() == 0 || clipRect.height() == 0) {
return;
}
if (destX < 0) {
destX = 0;
}
if (destY < 0) {
destY = 0;
}
copyRectToSurface(srcSurface.getBasePtr(clipRect.left, clipRect.top), srcSurface.pitch, srcSurface.w, clipRect.left, destX, destY, clipRect.width(), clipRect.height(), flipX, alpha);
}
void Screen::copyRectToSurface8bpp(const Graphics::Surface &srcSurface, const byte *palette, int destX, int destY, const Common::Rect &srcRect, bool flipX, AlphaBlendMode alpha, uint16 scale) {
if (scale != DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE) {
drawScaledSprite(_backSurface, (const byte *)srcSurface.getBasePtr(0, 0),
srcRect.width(), srcRect.height(),
destX, destY,
srcRect.width() * scale / DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE, srcRect.height() * scale / DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE,
palette, flipX, alpha);
return;
}
Common::Rect clipRect = clipRectToScreen(destX, destY, srcRect);
if (clipRect.width() == 0 || clipRect.height() == 0) {
return;
}
if (destX < 0) {
destX = 0;
}
if (destY < 0) {
destY = 0;
}
//TODO should we have different methods for alpha modes?
copyRectToSurface8bpp(srcSurface.getBasePtr(clipRect.left, clipRect.top), palette, srcSurface.pitch, srcSurface.w, clipRect.left, destX, destY, clipRect.width(), clipRect.height(), flipX, alpha);
}
/**
* Fast RGB555 pixel blending
* @param fg The foreground color in uint16 RGB565 format
* @param bg The background color in uint16 RGB565 format
* @param alpha The alpha in range 0-255
**/
uint16 alphaBlendRGB555(uint32 fg, uint32 bg, uint8 alpha){
alpha = (alpha + 4) >> 3;
bg = (bg | (bg << 16)) & 0x3e07c1f;
fg = (fg | (fg << 16)) & 0x3e07c1f;
uint32 result = ((((fg - bg) * alpha) >> 5) + bg) & 0x3e07c1f;
return (uint16)((result >> 16) | result);
}
uint16 alphaBlendAdditiveRGB555(uint32 fg, uint32 bg){
bg = (bg | (bg << 16)) & 0x3e07c1f;
fg = (fg | (fg << 16)) & 0x3e07c1f;
uint32 result = bg + fg;
//clip r g b values to 565.
if (result & (0x3f << 26)) {
result &= 0x1fffff;
result |= 0x3E00000;
}
if (result & 0x1F8000) {
result &= 0x3e07fff;
result |= 0x7C00;
}
if (result & 0x3E0) {
result &= 0x3e07c1f;
result |= 0x1f;
}
return (uint16)((result >> 16) | result);
}
void Screen::copyRectToSurface(const void *buffer, int srcPitch, int srcWidth, int srcXOffset, int destX, int destY, int width, int height, bool flipX, AlphaBlendMode alpha) {
assert(buffer);
assert(destX >= 0 && destX < _backSurface->w);
assert(destY >= 0 && destY < _backSurface->h);
assert(height > 0 && destY + height <= _backSurface->h);
assert(width > 0 && destX + width <= _backSurface->w);
// Copy buffer data to internal buffer
const byte *src = (const byte *)buffer;
byte *dst = (byte *)_backSurface->getBasePtr(destX, destY);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int32 srcIdx = flipX ? srcWidth - (srcXOffset * 2) - j - 1 : j;
if (src[srcIdx * 2] != 0 || src[srcIdx * 2 + 1] != 0) {
if ((src[srcIdx * 2 + 1] & 0x80) == 0 || alpha == NONE) {
// only copy opaque pixels
dst[j * 2] = src[srcIdx * 2];
dst[j * 2 + 1] = src[srcIdx * 2 + 1];
} else {
WRITE_SCREEN(&dst[j * 2], alphaBlendRGB555(READ_SCREEN(&src[srcIdx * 2]), READ_SCREEN(&dst[j * 2]), 128));
// semi-transparent pixels.
}
}
}
src += srcPitch;
dst += _backSurface->pitch;
}
}
void Screen::copyRectToSurface8bpp(const void *buffer, const byte* palette, int srcPitch, int srcWidth, int srcXOffset, int destX, int destY, int width, int height, bool flipX, AlphaBlendMode alpha) {
assert(buffer);
assert(destX >= 0 && destX < _backSurface->w);
assert(destY >= 0 && destY < _backSurface->h);
assert(height > 0 && destY + height <= _backSurface->h);
assert(width > 0 && destX + width <= _backSurface->w);
// Copy buffer data to internal buffer
const byte *src = (const byte *)buffer;
byte *dst = (byte *)_backSurface->getBasePtr(destX, destY);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int32 srcIdx = flipX ? srcWidth - (srcXOffset * 2) - j - 1 : j;
uint16 c = READ_LE_UINT16(&palette[src[srcIdx] * 2]);
if (c != 0) {
if (!(c & 0x8000) || alpha == NONE) {
// only copy opaque pixels
WRITE_SCREEN(&dst[j * 2], c & ~0x8000);
} else {
// semi-transparent pixels.
WRITE_SCREEN(&dst[j * 2], alpha == NORMAL
? alphaBlendRGB555(c & 0x7fff, READ_SCREEN(&dst[j * 2]) & 0x7fff, 128)
: alphaBlendAdditiveRGB555(c & 0x7fff, READ_SCREEN(&dst[j * 2]) & 0x7fff));
}
}
}
src += srcPitch;
dst += _backSurface->pitch;
}
}
void Screen::drawScaledSprite(Graphics::Surface *destSurface, const byte *source, int sourceWidth, int sourceHeight,
int destX, int destY, int destWidth, int destHeight, const byte *palette, bool flipX, AlphaBlendMode alpha) {
//TODO this logic is pretty messy. It should probably be re-written. It is trying to scale, clip, flip and blend at once.
// Based on the GNAP engine scaling code
if (destWidth == 0 || destHeight == 0) {
return;
}
const int xs = ((sourceWidth - 1) << 16) / destWidth;
const int ys = ((sourceHeight -1) << 16) / destHeight;
int clipX = 0, clipY = 0;
const int destPitch = destSurface->pitch;
if (destX < 0) {
clipX = -destX;
destX = 0;
destWidth -= clipX;
}
if (destY < 0) {
clipY = -destY;
destY = 0;
destHeight -= clipY;
}
if (destY + destHeight >= destSurface->h) {
destHeight = destSurface->h - destY;
}
if (destWidth < 0 || destHeight < 0)
return;
byte *dst = (byte *)destSurface->getBasePtr(destX, destY);
int yi = ys * clipY;
const byte *hsrc = source + sourceWidth * ((yi + 0x8000) >> 16);
for (int yc = 0; yc < destHeight; ++yc) {
byte *wdst = flipX ? dst + (destWidth - 1) * 2 : dst;
int16 currX = flipX ? destX + (destWidth - 1) : destX;
int xi = flipX ? xs : xs * clipX;
const byte *wsrc = hsrc + ((xi + 0x8000) >> 16);
for (int xc = 0; xc < destWidth; ++xc) {
if (currX >= 0 && currX < destSurface->w) {
byte colorIndex = *wsrc;
uint16 c = READ_LE_UINT16(&palette[colorIndex * 2]);
if (c != 0) {
if (!(c & 0x8000u) || alpha == NONE) {
// only copy opaque pixels
WRITE_SCREEN(wdst, c & ~0x8000);
} else {
WRITE_SCREEN(wdst, alphaBlendRGB555(c & 0x7fffu, READ_SCREEN(wdst) & 0x7fffu, 128));
// semi-transparent pixels.
}
}
}
currX += (flipX ? -1 : 1);
wdst += (flipX ? -2 : 2);
xi += xs;
wsrc = hsrc + ((xi + 0x8000) >> 16);
}
dst += destPitch;
yi += ys;
hsrc = source + sourceWidth * ((yi + 0x8000) >> 16);
}
}
Common::Rect Screen::clipRectToScreen(int destX, int destY, const Common::Rect &rect) {
return clipRectToRect(destX, destY, rect, Common::Rect(320, 200));
}
Common::Rect Screen::clipRectToRect(int destX, int destY, const Common::Rect &rect, const Common::Rect &containerRect) {
int16 x, y, w, h;
x = rect.left;
y = rect.top;
w = rect.width();
h = rect.height();
if (destX >= containerRect.width()) {
w = 0;
}
if (destY >= containerRect.height()) {
h = 0;
}
if (destX < 0) {
w += destX;
x += -destX;
}
if (destY < 0) {
h += destY;
y += -destY;
}
if (w > 0 && destX + w >= containerRect.width()) {
w -= (destX + w) - containerRect.width();
}
if (h > 0 && destY + h >= containerRect.height()) {
h -= (destY + h) - containerRect.height();
}
if (w < 0) {
w = 0;
}
if (h < 0) {
h = 0;
}
return Common::Rect(x, y, x + w, y + h);
}
void Screen::updatePaletteTransparency(uint16 paletteNum, uint16 startOffset, uint16 endOffset, bool isTransparent) {
assert(paletteNum < DRAGONS_NUM_PALETTES);
assert(startOffset < 256);
assert(endOffset < 256);
if (paletteNum == 0) {
// set all layers to pixel addition blending (100% back + 100% sprite)
DragonsEngine *vm = getEngine();
vm->_scene->setLayerAlphaMode(0, ADDITIVE);
vm->_scene->setLayerAlphaMode(1, ADDITIVE);
vm->_scene->setLayerAlphaMode(2, ADDITIVE);
}
for (int i = startOffset; i <= endOffset; i++) {
if (isTransparent) {
_palettes[paletteNum][i * 2 + 1] |= 0x80;
} else {
_palettes[paletteNum][i * 2 + 1] &= ~0x80;
}
}
}
void Screen::loadPalette(uint16 paletteNum, const byte *palette) {
bool isTransPalette = (paletteNum & 0x8000);
paletteNum &= ~0x8000;
assert(paletteNum < DRAGONS_NUM_PALETTES);
if (paletteNum == 0) {
memcpy(&_palettes[paletteNum][0], palette, 512);
} else {
memcpy(&_palettes[paletteNum][0], palette, 512);
if (paletteNum == 2 || paletteNum == 4 || paletteNum == 5) {
_palettes[paletteNum][2] = 0;
_palettes[paletteNum][3] = 0;
}
if (paletteNum == 1) {
_palettes[paletteNum][2] = 1;
_palettes[paletteNum][3] = 0;
}
}
for (int i =1 ; i < 0x100; i++) {
uint16 c = READ_LE_INT16(&_palettes[paletteNum][i * 2]);
if ((c & ~0x8000) == 0) {
if (!isTransPalette) {
WRITE_SCREEN(&_palettes[paletteNum][i * 2], 0x8000);
}
} else {
//TODO is this needed? see load_palette_into_frame_buffer()
// c = (uint16)(((uint)c & 0x1f) << 10) | (uint16)(((uint)c & 0x7c00) >> 10) |
// (c & 0x3e0) | (c & 0x8000);
}
}
WRITE_SCREEN(&_palettes[paletteNum][0], 0);
}
void Screen::setPaletteRecord(uint16 paletteNum, uint16 offset, uint16 newValue) {
assert(paletteNum < DRAGONS_NUM_PALETTES);
assert(offset < 256);
WRITE_SCREEN(&_palettes[paletteNum][offset * 2], newValue);
}
byte *Screen::getPalette(uint16 paletteNum) {
assert(paletteNum < DRAGONS_NUM_PALETTES);
return _palettes[paletteNum];
}
void Screen::clearScreen() {
_backSurface->fillRect(Common::Rect(0, 0, _backSurface->w, _backSurface->h), 0);
}
void Screen::drawRect(uint16 colour, Common::Rect rect, int id) {
Common::Rect clippedRect = clipRectToScreen(0, 0, rect);
//top
_backSurface->drawLine(clippedRect.left, clippedRect.top, clippedRect.right, clippedRect.top, colour);
//right
_backSurface->drawLine(clippedRect.right, clippedRect.top, clippedRect.right, clippedRect.bottom, colour);
//bottom
_backSurface->drawLine(clippedRect.left, clippedRect.bottom, clippedRect.right, clippedRect.bottom, colour);
//left
_backSurface->drawLine(clippedRect.left, clippedRect.top, clippedRect.left, clippedRect.bottom, colour);
}
void Screen::setScreenShakeOffset(int16 x, int16 y) {
_screenShakeOffset.x = x;
_screenShakeOffset.y = y;
}
void Screen::copyRectToSurface8bppWrappedY(const Graphics::Surface &srcSurface, const byte *palette, int yOffset) {
byte *dst = (byte *)_backSurface->getBasePtr(0, 0);
for (int i = 0; i < DRAGONS_SCREEN_HEIGHT; i++) {
const byte *src = (const byte *)srcSurface.getPixels() + ((yOffset + i) % srcSurface.h) * srcSurface.pitch;
for (int j = 0; j < DRAGONS_SCREEN_WIDTH; j++) {
uint16 c = READ_LE_UINT16(&palette[src[j] * 2]);
if (c != 0) {
WRITE_SCREEN(&dst[j * 2], c & ~0x8000);
}
}
dst += _backSurface->pitch;
}
}
void Screen::copyRectToSurface8bppWrappedX(const Graphics::Surface &srcSurface, const byte *palette, const Common::Rect &srcRect,
AlphaBlendMode alpha) {
// Copy buffer data to internal buffer
const byte *src = (const byte *)srcSurface.getBasePtr(0, 0);
int width = srcSurface.w > DRAGONS_SCREEN_WIDTH ? DRAGONS_SCREEN_WIDTH : srcSurface.w;
int height = srcRect.height();
byte *dst = (byte *)_backSurface->getBasePtr(0, 0);
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int32 srcIdx = (i + srcRect.top) * srcSurface.w + ((j + srcRect.left) % srcSurface.w);
uint16 c = READ_LE_UINT16(&palette[src[srcIdx] * 2]);
if (c != 0) {
if (!(c & 0x8000) || alpha == NONE) {
// only copy opaque pixels
WRITE_SCREEN(&dst[j * 2], c & ~0x8000);
} else {
WRITE_SCREEN(&dst[j * 2], alpha == NORMAL ? alphaBlendRGB555(c, READ_SCREEN(&dst[j * 2]), 128) : alphaBlendAdditiveRGB555(c, READ_SCREEN(&dst[j * 2])));
// semi-transparent pixels.
}
}
}
dst += _backSurface->pitch;
}
}
int16 Screen::addFlatQuad(int16 x0, int16 y0, int16 x1, int16 y1, int16 x3, int16 y3, int16 x2, int16 y2, uint16 colour,
int16 priorityLayer, uint16 flags) {
assert(x0 == x2 && x1 == x3 && y0 == y1 && y2 == y3); //make sure this is a rectangle
for (int i = 0; i < DRAGONS_NUM_FLAT_QUADS; i++) {
if (!(_flatQuads[i].flags & 1u)) {
_flatQuads[i].flags = flags | 1u;
_flatQuads[i].points[0].x = x0;
_flatQuads[i].points[0].y = y0;
_flatQuads[i].points[1].x = x1;
_flatQuads[i].points[1].y = y1;
_flatQuads[i].points[2].x = x2;
_flatQuads[i].points[2].y = y2;
_flatQuads[i].points[3].x = x3;
_flatQuads[i].points[3].y = y3;
_flatQuads[i].colour = colour;
_flatQuads[i].priorityLayer = priorityLayer;
return i;
}
}
return -1;
}
void Screen::drawFlatQuads(uint16 priorityLayer) {
for (int i = 0; i < DRAGONS_NUM_FLAT_QUADS; i++) {
if (_flatQuads[i].flags & 1u && _flatQuads[i].priorityLayer == priorityLayer) {
//TODO need to support semitrans mode.
//TODO check if we need to support non-rectangular quads.
fillRect(_flatQuads[i].colour, Common::Rect(_flatQuads[i].points[0].x, _flatQuads[i].points[0].y, _flatQuads[i].points[3].x + 1, _flatQuads[i].points[3].y + 1));
}
}
}
void Screen::fillRect(uint16 colour, Common::Rect rect) {
_backSurface->fillRect(rect, colour);
}
void Screen::clearAllFlatQuads() {
for (int i = 0; i < DRAGONS_NUM_FLAT_QUADS; i++) {
_flatQuads[i].flags = 0;
}
}
FlatQuad *Screen::getFlatQuad(uint16 quadId) {
assert(quadId < DRAGONS_NUM_FLAT_QUADS);
return &_flatQuads[quadId];
}
} // End of namespace Dragons

112
engines/dragons/screen.h Normal file
View File

@@ -0,0 +1,112 @@
/* 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 DRAGONS_SCREEN_H
#define DRAGONS_SCREEN_H
#include "graphics/surface.h"
#include "graphics/pixelformat.h"
#include "common/scummsys.h"
#include "common/rect.h"
namespace Dragons {
#define DRAGONS_NUM_PALETTES 5
#define DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE 256
#define DRAGONS_SCREEN_WIDTH 320
#define DRAGONS_SCREEN_HEIGHT 200
#define DRAGONS_NUM_FLAT_QUADS 0xf
#ifdef SCUMM_BIG_ENDIAN
#define WRITE_SCREEN WRITE_BE_UINT16
#define READ_SCREEN READ_BE_INT16
#else
#define WRITE_SCREEN WRITE_LE_UINT16
#define READ_SCREEN READ_LE_INT16
#endif
enum AlphaBlendMode {
NONE,
NORMAL, // 50% x Back + 50% x Sprite
ADDITIVE, // 100% x Back + 100% x Sprite
ADDITIVE_50, // 100% x Back + 50% x Sprite
SUBTRACTIVE // 100% x Back - 100% x Sprite
};
struct FlatQuad {
uint16 flags;
uint16 priorityLayer;
Common::Point points[4];
uint16 colour;
FlatQuad() {
flags = 0;
priorityLayer = 0;
colour = 0;
}
};
class Screen {
private:
Graphics::PixelFormat _pixelFormat;
Graphics::Surface *_backSurface;
byte _palettes[DRAGONS_NUM_PALETTES][512];
Common::Point _screenShakeOffset;
FlatQuad _flatQuads[DRAGONS_NUM_FLAT_QUADS];
public:
virtual ~Screen();
Screen();
Graphics::PixelFormat getPixelFormat() { return _pixelFormat; }
void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY);
void copyRectToSurface(const Graphics::Surface &srcSurface, int destX, int destY, const Common::Rect &srcRect, bool flipX = false, AlphaBlendMode alpha = NONE);
void copyRectToSurface8bpp(const Graphics::Surface &srcSurface, const byte *palette, int destX, int destY, const Common::Rect &srcRect, bool flipX = false, AlphaBlendMode alpha = NONE, uint16 scale = DRAGONS_ENGINE_SPRITE_100_PERCENT_SCALE);
void copyRectToSurface8bppWrappedX(const Graphics::Surface &srcSurface, const byte *palette, const Common::Rect &srcRect, AlphaBlendMode alpha = NONE);
void updateScreen();
void loadPalette(uint16 paletteNum, const byte *palette);
byte *getPalette(uint16 paletteNum);
void setPaletteRecord(uint16 paletteNum, uint16 offset, uint16 newValue);
void updatePaletteTransparency(uint16 paletteNum, uint16 startOffset, uint16 endOffset, bool isTransparent);
void clearScreen();
void drawRect(uint16 colour, Common::Rect rect, int id);
void fillRect(uint16 colour, Common::Rect rect);
Common::Rect clipRectToScreen(int destX, int destY, const Common::Rect &rect);
Common::Rect clipRectToRect(int destX, int destY, const Common::Rect &rect, const Common::Rect &containerRect);
void setScreenShakeOffset(int16 x, int16 y);
void copyRectToSurface8bppWrappedY(const Graphics::Surface &srcSurface, const byte *palette, int yOffset);
int16 addFlatQuad(int16 x0, int16 y0, int16 x1, int16 y1, int16 x3, int16 y3, int16 x2, int16 y2, uint16 colour, int16 priorityLayer, uint16 flags);
void drawFlatQuads(uint16 priorityLayer);
FlatQuad *getFlatQuad(uint16 quadId);
void clearAllFlatQuads();
private:
void copyRectToSurface(const void *buffer, int srcPitch, int srcWidth, int srcXOffset, int destX, int destY, int width, int height, bool flipX, AlphaBlendMode alpha);
void copyRectToSurface8bpp(const void *buffer, const byte* palette, int srcPitch, int srcWidth, int srcXOffset, int destX, int destY, int width, int height, bool flipX, AlphaBlendMode alpha);
void drawScaledSprite(Graphics::Surface *destSurface, const byte *source, int sourceWidth, int sourceHeight, int destX, int destY, int destWidth, int destHeight, const byte *palette, bool flipX, AlphaBlendMode alpha);
};
} // End of namespace Dragons
#endif //DRAGONS_SCREEN_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,128 @@
/* 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 DRAGONS_SCRIPTOPCODES_H
#define DRAGONS_SCRIPTOPCODES_H
#include "common/func.h"
#include "common/str.h"
namespace Dragons {
#define DRAGONS_NUM_SCRIPT_OPCODES 0x23
class DragonsEngine;
struct ScriptOpCall {
byte _op;
byte *_base;
byte *_code;
byte *_codeEnd;
int _field8;
int _result;
ScriptOpCall(byte *start, uint32 length);
void skip(uint size);
byte readByte();
int16 readSint16();
uint32 readUint32();
};
typedef Common::Functor1<ScriptOpCall&, void> ScriptOpcode;
class DragonFLG;
class SpecialOpcodes;
class ScriptOpcodes {
public:
ScriptOpcodes(DragonsEngine *vm, DragonFLG *dragonFLG);
~ScriptOpcodes();
void runScript(ScriptOpCall &scriptOpCall);
void runScript3(ScriptOpCall &scriptOpCall);
bool runScript4(ScriptOpCall &scriptOpCall);
void execOpcode(ScriptOpCall &scriptOpCall);
void executeScriptLoop(ScriptOpCall &scriptOpCall);
void loadTalkDialogEntries(ScriptOpCall &scriptOpCall);
int16 _numDialogStackFramesToPop;
int16 _scriptTargetINI;
SpecialOpcodes *_specialOpCodes;
protected:
DragonsEngine *_vm;
DragonFLG *_dragonFLG;
ScriptOpcode *_opcodes[DRAGONS_NUM_SCRIPT_OPCODES];
Common::String _opcodeNames[DRAGONS_NUM_SCRIPT_OPCODES];
void initOpcodes();
void freeOpcodes();
void updateReturn(ScriptOpCall &scriptOpCall, uint16 size);
// Opcodes
void opUnk1(ScriptOpCall &scriptOpCall);
void opAddDialogChoice(ScriptOpCall &scriptOpCall);
void opPopDialogStack(ScriptOpCall &scriptOpCall);
void opExecuteScript(ScriptOpCall &scriptOpCall); //op 4
void opSetActorDirection(ScriptOpCall &scriptOpCall); //op 5
void opPerformActionOnObject(ScriptOpCall &scriptOpCall);
void opMoveObjectToScene(ScriptOpCall &scriptOpCall);
void opActorLoadSequence(ScriptOpCall &scriptOpCall);
void opSetVariable(ScriptOpCall &scriptOpCall);
void opRunSpecialOpCode(ScriptOpCall &scriptOpCall); //op B
void opPlayOrStopSound(ScriptOpCall &scriptOpCall);
void opDelay(ScriptOpCall &scriptOpCall); //op D
void opMoveActorToPoint(ScriptOpCall &scriptOpCall);
void opMoveActorToXY(ScriptOpCall &scriptOpCall);
void opMoveActorToObject(ScriptOpCall &scriptOpCall);
void opUnk11FlickerTalk(ScriptOpCall &scriptOpCall);
void opLoadScene(ScriptOpCall &scriptOpCall);
void opIfStatement(ScriptOpCall &scriptOpCall);
void opIfElseStatement(ScriptOpCall &scriptOpCall);
void opUnk15PropertiesRelated(ScriptOpCall &scriptOpCall);
void opUnk16(ScriptOpCall &scriptOpCall);
void opWaitForActorSequenceToFinish(ScriptOpCall &scriptOpCall);
void opDialogAtPoint(ScriptOpCall &scriptOpCall);
void opExecuteObjectSceneScript(ScriptOpCall &scriptOpCall);
void opUpdatePaletteCycling(ScriptOpCall &scriptOpCall);
void opWaitForActorToFinishWalking(ScriptOpCall &scriptOpCall);
void opShowActor(ScriptOpCall &scriptOpCall);
void opHideActor(ScriptOpCall &scriptOpCall);
void opSetActorFlag0x1000(ScriptOpCall &scriptOpCall);
void opPlayMusic(ScriptOpCall &scriptOpCall);
void opPreLoadSceneData(ScriptOpCall &scriptOpCall);
void opPauseCurrentSpeechAndFetchNextDialog(ScriptOpCall &scriptOpCall);
bool evaluateExpression(ScriptOpCall &scriptOpCall);
void setVariable(ScriptOpCall &scriptOpCall);
void opCode_Unk7(ScriptOpCall &scriptOpCall);
void opCodeActorTalk(ScriptOpCall &scriptOpCall); // 0x22
// misc
uint16 getINIField(uint32 iniIndex, uint16 fieldOffset);
void setINIField(uint32 iniIndex, uint16 fieldOffset, uint16 value);
};
} // End of namespace Dragons
#endif // DRAGONS_SCRIPTOPCODES_H

View File

@@ -0,0 +1,242 @@
/* 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 "dragons/dragons.h"
#include "dragons/sequenceopcodes.h"
#include "dragons/actor.h"
namespace Dragons {
// OpCall
void OpCall::skip(uint size) {
_code += size;
}
byte OpCall::readByte() {
return *_code++;
}
int16 OpCall::readSint16() {
int16 value = READ_LE_UINT16(_code);
_code += 2;
return value;
}
uint32 OpCall::readUint32() {
uint32 value = READ_LE_UINT32(_code);
_code += 4;
return value;
}
// SequenceOpcodes
SequenceOpcodes::SequenceOpcodes(DragonsEngine *vm)
: _vm(vm) {
initOpcodes();
}
SequenceOpcodes::~SequenceOpcodes() {
freeOpcodes();
}
void SequenceOpcodes::execOpcode(Actor *control, OpCall &opCall) {
assert(opCall._op < DRAGONS_NUM_SEQ_OPCODES);
if (!_opcodes[opCall._op])
error("SequenceOpcodes::execOpcode() Unimplemented opcode %d", opCall._op);
debug(4, "execSequenceOpcode(%d) %s", opCall._op, _opcodeNames[opCall._op].c_str());
(*_opcodes[opCall._op])(control, opCall);
}
typedef Common::Functor2Mem<Actor*, OpCall&, void, SequenceOpcodes> SequenceOpcodeI;
#define OPCODE(op, func) \
_opcodes[op] = new SequenceOpcodeI(this, &SequenceOpcodes::func); \
_opcodeNames[op] = #func;
void SequenceOpcodes::initOpcodes() {
// First clear everything
for (uint i = 0; i < DRAGONS_NUM_SEQ_OPCODES; ++i) {
_opcodes[i] = nullptr;
}
// Register opcodes
OPCODE(1, opSetFramePointer);
OPCODE(2, opSetFramePointerAndStop);
OPCODE(3, opJmp);
OPCODE(4, opSetSequenceTimerStartValue);
OPCODE(5, opSetSequenceTimer);
OPCODE(6, opUpdateXYResetSeqTimer);
OPCODE(7, opUpdateXYResetSeqTimerAndStop);
// unused
OPCODE(9, opSetActorFlag4AndStop);
// unused
OPCODE(11, opSetActorFlags404);
OPCODE(12, opClearActorFlag400);
OPCODE(13, opChangeSequence);
// unused
OPCODE(15, opSetField7a);
OPCODE(16, opUpdateFlags);
OPCODE(17, opPlaySound);
OPCODE(18, opSetXY);
OPCODE(19, opSetXYAndStop);
}
#undef OPCODE
void SequenceOpcodes::freeOpcodes() {
for (uint i = 0; i < DRAGONS_NUM_SEQ_OPCODES; ++i) {
delete _opcodes[i];
}
}
void SequenceOpcodes::updateReturn(OpCall &opCall, uint16 size) {
opCall._deltaOfs = size * 2 + 2;
}
// Opcodes
void SequenceOpcodes::opSetFramePointer(Actor *actor, OpCall &opCall) {
ARG_INT16(framePointer);
debug(4, "set frame pointer %X", framePointer);
actor->loadFrame((uint16)framePointer);
actor->_flags |= ACTOR_FLAG_2;
actor->_sequenceTimer = actor->_sequenceTimerMaxValue;
updateReturn(opCall, 1);
}
void SequenceOpcodes::opSetFramePointerAndStop(Actor *actor, OpCall &opCall) {
opSetFramePointer(actor, opCall);
opCall._result = 0;
}
void SequenceOpcodes::opJmp(Actor *actor, OpCall &opCall) {
ARG_INT16(newIp);
if (!(actor->_flags & ACTOR_FLAG_1000)) {
byte *newOffset = actor->getSeqIpAtOffset((uint32)newIp);
opCall._deltaOfs = (int32)(newOffset - actor->_seqCodeIp); //opCall._code);
debug(5, "opJump delta: %d", opCall._deltaOfs);
} else {
updateReturn(opCall, 1);
}
}
void SequenceOpcodes::opSetSequenceTimerStartValue(Actor *actor, OpCall &opCall) {
ARG_INT16(startValue);
actor->_sequenceTimerMaxValue = (uint16)startValue;
debug(5, "set sequenceTimerStartValue: %d", startValue);
updateReturn(opCall, 1);
}
void SequenceOpcodes::opSetSequenceTimer(Actor *actor, OpCall &opCall) {
ARG_INT16(newSeqTimer);
actor->_sequenceTimer = (uint16)newSeqTimer;
debug(5, "set _sequenceTimer: %d", newSeqTimer);
updateReturn(opCall, 1);
opCall._result = 0;
}
void SequenceOpcodes::opUpdateXYResetSeqTimer(Actor *actor, OpCall &opCall) {
ARG_INT8(xOffset);
ARG_INT8(yOffset);
actor->_x_pos += xOffset;
actor->_y_pos += yOffset;
actor->_sequenceTimer = actor->_sequenceTimerMaxValue;
debug(5, "update actor %d XY offset (%d, %d) new values (%d, %d) %d", actor->_actorID, xOffset, yOffset, actor->_x_pos, actor->_y_pos, actor->_sequenceTimer);
updateReturn(opCall, 1);
}
void SequenceOpcodes::opUpdateXYResetSeqTimerAndStop(Actor *actor, OpCall &opCall) {
opUpdateXYResetSeqTimer(actor, opCall);
opCall._result = 0;
}
void SequenceOpcodes::opSetActorFlag4AndStop(Actor *actor, OpCall &opCall) {
actor->_flags |= ACTOR_FLAG_4;
opCall._deltaOfs = 0;
opCall._result = 0;
//updateReturn(opCall, 1);
}
void SequenceOpcodes::opSetActorFlags404(Actor *actor, OpCall &opCall) {
actor->_flags |= (ACTOR_FLAG_4 | Dragons::ACTOR_FLAG_400);
updateReturn(opCall, 1);
}
void SequenceOpcodes::opClearActorFlag400(Actor *actor, OpCall &opCall) {
actor->_flags &= ~ACTOR_FLAG_400;
updateReturn(opCall, 1);
}
void SequenceOpcodes::opChangeSequence(Actor *actor, OpCall &opCall) {
ARG_INT16(newValue);
actor->_sequenceID = (uint16)newValue;
updateReturn(opCall, 1);
}
void SequenceOpcodes::opSetField7a(Actor *actor, OpCall &opCall) {
ARG_INT16(newValue);
actor->_field_7a = (uint16)newValue;
updateReturn(opCall, 1);
}
void SequenceOpcodes::opUpdateFlags(Actor *actor, OpCall &opCall) {
if (actor->isFlagSet(ACTOR_FLAG_1000)) {
actor->setFlag(ACTOR_FLAG_4);
}
updateReturn(opCall, 0);
}
void SequenceOpcodes::opPlaySound(Actor *actor, OpCall &opCall) {
ARG_INT16(soundId);
debug(5, "opPlaySound actorId: %d soundId: %d", actor->_actorID, soundId);
_vm->playOrStopSound((uint16) soundId);
updateReturn(opCall, 1);
}
void SequenceOpcodes::opSetXY(Actor *actor, OpCall &opCall) {
ARG_INT16(x);
ARG_INT16(y);
actor->_x_pos = x;
actor->_y_pos = y;
updateReturn(opCall, 2);
}
void SequenceOpcodes::opSetXYAndStop(Actor *actor, OpCall &opCall) {
opSetXY(actor, opCall);
opCall._result = 0;
}
//void SequenceOpcodes::opYield(Control *control, OpCall &opCall) {
// opCall._result = 2;
//}
//
//void SequenceOpcodes::opStopSubSequence(Control *control, OpCall &opCall) {
// ARG_INT16(linkIndex);
// control->stopSubSequence(linkIndex);
//}
} // End of namespace Dragons

View File

@@ -0,0 +1,95 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 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 DRAGONS_SEQUENCEOPCODES_H
#define DRAGONS_SEQUENCEOPCODES_H
#include "common/func.h"
#include "common/str.h"
namespace Dragons {
#define DRAGONS_NUM_SEQ_OPCODES 22
class DragonsEngine;
class Actor;
struct OpCall {
byte _op;
byte _opSize;
int32 _deltaOfs;
byte *_code;
int _result;
void skip(uint size);
byte readByte();
int16 readSint16();
uint32 readUint32();
};
// Convenience macros
#define ARG_SKIP(x) opCall.skip(x);
#define ARG_BYTE(name) byte name = opCall.readByte(); debug(5, "ARG_BYTE(" #name " = %d)", name);
#define ARG_INT8(name) int8 name = opCall.readByte(); debug(5, "ARG_INT8(" #name " = %d)", name);
#define ARG_INT16(name) int16 name = opCall.readSint16(); debug(5, "ARG_INT16(" #name " = %d)", name);
#define ARG_UINT32(name) uint32 name = opCall.readUint32(); debug(5, "ARG_UINT32(" #name " = %08X)", name);
typedef Common::Functor2<Actor*, OpCall&, void> SequenceOpcode;
class SequenceOpcodes {
public:
SequenceOpcodes(DragonsEngine *vm);
~SequenceOpcodes();
void execOpcode(Actor *actor, OpCall &opCall);
protected:
DragonsEngine *_vm;
SequenceOpcode *_opcodes[DRAGONS_NUM_SEQ_OPCODES];
Common::String _opcodeNames[DRAGONS_NUM_SEQ_OPCODES];
void initOpcodes();
void freeOpcodes();
void updateReturn(OpCall &opCall, uint16 size);
// Opcodes
void opSetFramePointer(Actor *actor, OpCall &opCall);
void opSetFramePointerAndStop(Actor *actor, OpCall &opCall);
void opJmp(Actor *actor, OpCall &opCall);
void opSetSequenceTimerStartValue(Actor *actor, OpCall &opCall);
void opSetSequenceTimer(Actor *actor, OpCall &opCall);
void opUpdateXYResetSeqTimer(Actor *actor, OpCall &opCall);
void opUpdateXYResetSeqTimerAndStop(Actor *actor, OpCall &opCall);
void opSetActorFlag4AndStop(Actor *actor, OpCall &opCall);
void opSetActorFlags404(Actor *actor, OpCall &opCall);
void opClearActorFlag400(Actor *actor, OpCall &opCall);
void opChangeSequence(Actor *actor, OpCall &opCall);
void opSetField7a(Actor *actor, OpCall &opCall);
void opUpdateFlags(Actor *actor, OpCall &opCall);
void opPlaySound(Actor *actor, OpCall &opCall);
void opSetXY(Actor *actor, OpCall &opCall);
void opSetXYAndStop(Actor *actor, OpCall &opCall);
};
} // End of namespace Dragons
#endif // DRAGONS_SEQUENCEOPCODES_H

544
engines/dragons/sound.cpp Normal file
View File

@@ -0,0 +1,544 @@
/* 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 "audio/soundfont/rawfile.h"
#include "audio/soundfont/vab/vab.h"
#include "audio/soundfont/vgmcoll.h"
#include "audio/mixer.h"
#include "audio/audiostream.h"
#include "audio/decoders/raw.h"
#include "audio/decoders/xa.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/memstream.h"
#include "dragons/dragons.h"
#include "dragons/sound.h"
#include "dragons/bigfile.h"
#include "dragons/dragonrms.h"
#include "dragons/vabsound.h"
#define RAW_CD_SECTOR_SIZE 2352
#define CDXA_TYPE_MASK 0x0E
#define CDXA_TYPE_DATA 0x08
#define CDXA_TYPE_AUDIO 0x04
namespace Dragons {
struct SpeechLocation {
uint32 talkId;
uint16 sectorStart;
int8 startOffset;
uint16 sectorEnd;
} SpeechLocation;
void CdIntToPos_0(uint32 param_1) { //, byte *param_2)
int iVar1;
int iVar2;
int iVar3;
uint8 minute;
uint8 second;
uint8 sector;
iVar3 = (param_1 + 0x96) / 0x4b;
iVar2 = (param_1 + 0x96) % 0x4b;
iVar1 = iVar3 / 0x3c;
iVar3 = iVar3 % 0x3c;
second = (char)iVar3 + (char)(iVar3 / 10) * 6;
sector = (char)iVar2 + (char)(iVar2 / 10) * 6;
minute = (char)iVar1 + (char)(iVar1 / 10) * 6;
uint32 out = (((uint)(minute >> 4) * 10 + ((uint)minute & 0xf)) * 0x3c +
(uint)(second >> 4) * 10 + ((uint)second & 0xf)) * 0x4b +
(uint)(sector >> 4) * 10 + ((uint)sector & 0xf) + -0x96;
debug(3, "Seek Audio %2X:%2X:%2X in: %d out %d", minute, second, sector, param_1, out);
return;
}
void SoundManager::playSpeech(uint32 textIndex) {
if (isSpeechPlaying()) {
_vm->_mixer->stopHandle(_speechHandle);
}
// Reduce music volume while playing dialog.
_midiPlayer->setVolume(_musicVolume / 2);
struct SpeechLocation speechLocation;
if (!getSpeechLocation(textIndex, &speechLocation)) {
return;
}
Common::File *fd = new Common::File();
if (!fd->open("dtspeech.xa")) {
error("Failed to open dtspeech.xa");
}
CdIntToPos_0(speechLocation.sectorStart * 32);
PSXAudioTrack *_audioTrack = new PSXAudioTrack();
_vm->setFlags(ENGINE_FLAG_8000);
_vm->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, _audioTrack->createNewAudioStream(fd, speechLocation.sectorStart, speechLocation.startOffset, speechLocation.sectorEnd), -1, _speechVolume);
fd->close();
delete fd;
delete _audioTrack;
}
bool SoundManager::isSpeechPlaying() {
return _vm->_mixer->isSoundHandleActive(_speechHandle);
}
bool SoundManager::getSpeechLocation(uint32 talkId, struct SpeechLocation *location) {
Common::File *fd = new Common::File();
if (!fd->open("dragon.exe")) {
error("Failed to open dragon.exe");
}
fd->seek(_vm->getSpeechTblOffsetFromDragonEXE());
bool foundId = false;
for (int i = 0; i < 2272; i++) { //TODO check that the number of speech audio tracks is the same across game variants
uint32 id = (fd->readUint32LE() & 0xffffff);
fd->seek(-1, SEEK_CUR);
int8 startOffset = fd->readSByte();
uint16 start = fd->readUint16LE();
uint16 end = fd->readUint16LE();
if (id == talkId) {
location->talkId = id;
location->sectorStart = start;
location->startOffset = startOffset;
location->sectorEnd = end;
foundId = true;
debug(3, "sectors [%d-%d] unk byte = %d", start * 32, end * 32, startOffset);
break;
}
}
fd->close();
delete fd;
return foundId;
}
void SoundManager::resumeMusic() {
if (isSpeechPlaying()) {
_vm->_mixer->stopHandle(_speechHandle);
_vm->clearFlags(ENGINE_FLAG_8000);
}
if (_currentSong != -1) {
_midiPlayer->resume();
}
}
SoundManager::PSXAudioTrack::PSXAudioTrack() {
memset(&_adpcmStatus, 0, sizeof(_adpcmStatus));
}
// Ha! It's palindromic!
#define AUDIO_DATA_CHUNK_SIZE 2304
#define AUDIO_DATA_SAMPLE_COUNT 4032
static const int s_xaTable[5][2] = {
{ 0, 0 },
{ 60, 0 },
{ 115, -52 },
{ 98, -55 },
{ 122, -60 }
};
void SoundManager::PSXAudioTrack::queueAudioFromSector(Audio::QueuingAudioStream *audStream, Common::SeekableReadStream *sector) {
sector->skip(24);
// This XA audio is different (yet similar) from normal XA audio! Watch out!
// TODO: It's probably similar enough to normal XA that we can merge it somehow...
// TODO: RTZ PSX needs the same audio code in a regular AudioStream class. Probably
// will do something similar to QuickTime and creating a base class 'ISOMode2Parser'
// or something similar.
byte *buf = new byte[AUDIO_DATA_CHUNK_SIZE];
sector->read(buf, AUDIO_DATA_CHUNK_SIZE);
int channels = audStream->isStereo() ? 2 : 1;
int16 *dst = new int16[AUDIO_DATA_SAMPLE_COUNT];
int16 *leftChannel = dst;
int16 *rightChannel = dst + 1;
for (byte *src = buf; src < buf + AUDIO_DATA_CHUNK_SIZE; src += 128) {
for (int i = 0; i < 4; i++) {
int shift = 12 - (src[4 + i * 2] & 0xf);
int filter = src[4 + i * 2] >> 4;
int f0 = s_xaTable[filter][0];
int f1 = s_xaTable[filter][1];
int16 s_1 = _adpcmStatus[0].sample[0];
int16 s_2 = _adpcmStatus[0].sample[1];
for (int j = 0; j < 28; j++) {
byte d = src[16 + i + j * 4];
int t = (int8)(d << 4) >> 4;
int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
s_2 = s_1;
s_1 = CLIP<int>(s, -32768, 32767);
*leftChannel = s_1;
leftChannel += channels;
}
if (channels == 2) {
_adpcmStatus[0].sample[0] = s_1;
_adpcmStatus[0].sample[1] = s_2;
s_1 = _adpcmStatus[1].sample[0];
s_2 = _adpcmStatus[1].sample[1];
}
shift = 12 - (src[5 + i * 2] & 0xf);
filter = src[5 + i * 2] >> 4;
f0 = s_xaTable[filter][0];
f1 = s_xaTable[filter][1];
for (int j = 0; j < 28; j++) {
byte d = src[16 + i + j * 4];
int t = (int8)d >> 4;
int s = (t << shift) + ((s_1 * f0 + s_2 * f1 + 32) >> 6);
s_2 = s_1;
s_1 = CLIP<int>(s, -32768, 32767);
if (channels == 2) {
*rightChannel = s_1;
rightChannel += 2;
} else {
*leftChannel++ = s_1;
}
}
if (channels == 2) {
_adpcmStatus[1].sample[0] = s_1;
_adpcmStatus[1].sample[1] = s_2;
} else {
_adpcmStatus[0].sample[0] = s_1;
_adpcmStatus[0].sample[1] = s_2;
}
}
}
int flags = Audio::FLAG_16BITS;
if (audStream->isStereo())
flags |= Audio::FLAG_STEREO;
#ifdef SCUMM_LITTLE_ENDIAN
flags |= Audio::FLAG_LITTLE_ENDIAN;
#endif
audStream->queueBuffer((byte *)dst, AUDIO_DATA_SAMPLE_COUNT * 2, DisposeAfterUse::YES, flags);
delete[] buf;
}
Audio::QueuingAudioStream *SoundManager::PSXAudioTrack::createNewAudioStream(Common::File *fd, uint16 sectorStart, int8 startOffset, uint16 sectorEnd) {
fd->seek(((sectorStart * 32) + startOffset) * RAW_CD_SECTOR_SIZE);
fd->skip(19);
byte format = fd->readByte();
bool stereo = (format & (1 << 0)) != 0;
uint rate = (format & (1 << 2)) ? 18900 : 37800;
Audio::QueuingAudioStream *audStream = Audio::makeQueuingAudioStream(rate, stereo);
for (int i = 0x0; i < sectorEnd - sectorStart; i++) {
fd->seek(((sectorStart * 32) + startOffset + i * 32) * RAW_CD_SECTOR_SIZE);
queueAudioFromSector(audStream, fd);
}
audStream->finish();
return audStream;
}
SoundManager::SoundManager(DragonsEngine *vm, BigfileArchive *bigFileArchive, DragonRMS *dragonRMS)
: _vm(vm),
_sfxVolume(0),
_musicVolume(0),
_speechVolume(0),
_bigFileArchive(bigFileArchive),
_dragonRMS(dragonRMS) {
_dat_8006bb60_sound_related = 0;
_currentSong = -1;
bool allSoundIsMuted = false;
if (ConfMan.hasKey("mute")) {
allSoundIsMuted = ConfMan.getBool("mute");
}
if (ConfMan.hasKey("speech_mute") && !allSoundIsMuted) {
_vm->_mixer->muteSoundType(_vm->_mixer->kSpeechSoundType, ConfMan.getBool("speech_mute"));
}
if (ConfMan.hasKey("sfx_mute") && !allSoundIsMuted) {
_vm->_mixer->muteSoundType(_vm->_mixer->kSFXSoundType, ConfMan.getBool("sfx_mute"));
}
if (ConfMan.hasKey("music_mute") && !allSoundIsMuted) {
_vm->_mixer->muteSoundType(_vm->_mixer->kMusicSoundType, ConfMan.getBool("music_mute"));
}
SomeInitSound_FUN_8003f64c();
initVabData();
_midiPlayer = new MidiMusicPlayer(_bigFileArchive);
syncSoundSettings();
}
SoundManager::~SoundManager() {
if (isSpeechPlaying()) {
_vm->_mixer->stopHandle(_speechHandle);
}
stopAllVoices();
_midiPlayer->stop();
delete _midiPlayer;
delete _vabMusx;
delete _vabMsf;
delete _vabGlob;
}
void SoundManager::SomeInitSound_FUN_8003f64c() {
// TODO: Check if this changes on different game versions?
memset(_sfxVolumeTbl, 0x10, sizeof(_sfxVolumeTbl));
_sfxVolumeTbl[192] = 0x0b;
_sfxVolumeTbl[193] = 0x0b;
_sfxVolumeTbl[226] = _sfxVolumeTbl[226] | 0x80u;
_sfxVolumeTbl[229] = 0x0b;
_sfxVolumeTbl[230] = 0x0b;
_sfxVolumeTbl[450] = 0x0b;
_sfxVolumeTbl[451] = 0x0b;
_sfxVolumeTbl[514] = 0x8b;
_sfxVolumeTbl[515] = 0x0b;
_sfxVolumeTbl[516] = 0x0b;
_sfxVolumeTbl[578] = 0x0b;
_sfxVolumeTbl[579] = 0x0b;
_sfxVolumeTbl[580] = 0x0b;
_sfxVolumeTbl[611] = 0x0b;
_sfxVolumeTbl[674] = 0x8b;
_sfxVolumeTbl[675] = 0x88;
_sfxVolumeTbl[711] = 0x08;
_sfxVolumeTbl[866] = 0x0b;
_sfxVolumeTbl[896] = 0x0b;
_sfxVolumeTbl[897] = _sfxVolumeTbl[897] | 0x80u;
_sfxVolumeTbl[930] = _sfxVolumeTbl[930] | 0x80u;
_sfxVolumeTbl[934] = 0x8b;
_sfxVolumeTbl[935] = 0x8b;
_sfxVolumeTbl[936] = 0x0b;
_sfxVolumeTbl[937] = 0x88;
_sfxVolumeTbl[941] = 0x0b;
_sfxVolumeTbl[964] = 0x0b;
_sfxVolumeTbl[995] = _sfxVolumeTbl[995] | 0x80u;
_sfxVolumeTbl[1027] = 0x08;
_sfxVolumeTbl[1056] = 0x8b;
_sfxVolumeTbl[1059] = _sfxVolumeTbl[1059] | 0x80u;
_sfxVolumeTbl[1122] = 0x0b;
_sfxVolumeTbl[1250] = 0x08;
_sfxVolumeTbl[1252] = 0x0b;
_sfxVolumeTbl[1256] = 0x0b;
_sfxVolumeTbl[1257] = 0x08;
_sfxVolumeTbl[1258] = 0x0b;
_sfxVolumeTbl[1284] = 0x0b;
_sfxVolumeTbl[1378] = 0x0b;
_sfxVolumeTbl[1379] = _sfxVolumeTbl[1379] | 0x80u;
_sfxVolumeTbl[1380] = 0x0b;
_sfxVolumeTbl[1385] = 0x0b;
_sfxVolumeTbl[1443] = 0x8b;
_sfxVolumeTbl[1444] = _sfxVolumeTbl[1444] | 0x80u;
_sfxVolumeTbl[1445] = _sfxVolumeTbl[1445] | 0x80u;
_sfxVolumeTbl[1446] = 0x8b;
_sfxVolumeTbl[1472] = 0x8b;
_sfxVolumeTbl[1508] = _sfxVolumeTbl[1508] | 0x80u;
_sfxVolumeTbl[1575] = 0x08;
_sfxVolumeTbl[1576] = 0x08;
_sfxVolumeTbl[1577] = 0x08;
_sfxVolumeTbl[1604] = 0x08;
_sfxVolumeTbl[1605] = 0x08;
_sfxVolumeTbl[1610] = 0x0b;
_sfxVolumeTbl[1611] = 0x0b;
_sfxVolumeTbl[1612] = 0x0b;
}
void SoundManager::initVabData() {
_vabMusx = loadVab("musx.vh", "musx.vb");
_vabMsf = loadVab("musx.vh", "musx.vb");
_vabGlob = loadVab("glob.vh", "glob.vb");
}
VabSound * SoundManager::loadVab(const char *headerFilename, const char *bodyFilename) {
uint32 headSize, bodySize;
byte *headData = _bigFileArchive->load(headerFilename, headSize);
byte *bodyData = _bigFileArchive->load(bodyFilename, bodySize);
Common::SeekableReadStream *headStream = new Common::MemoryReadStream(headData, headSize, DisposeAfterUse::YES);
Common::SeekableReadStream *bodyStream = new Common::MemoryReadStream(bodyData, bodySize, DisposeAfterUse::YES);
return new VabSound(headStream, bodyStream);
}
/**
*
* @param soundId Bit 0x4000 set indicates STOP SOUND, bit 0x8000 set indicates SOUND IS GLOBAL (comes from glob.v[hb])
*/
void SoundManager::playOrStopSound(uint16 soundId) {
uint16 volumeId;
if ((soundId & 0x8000u) == 0) {
volumeId = (soundId & ~0x4000u) + _vm->getCurrentSceneId() * 0x20;
} else {
volumeId = soundId & ~(0x4000u | 0x8000u);
}
if ((soundId & 0x4000u) == 0) {
playSound(soundId, volumeId);
} else {
stopSound(soundId, volumeId);
}
}
void SoundManager::playSound(uint16 soundId, uint16 volumeId) {
byte volume = 0;
volume = _sfxVolumeTbl[volumeId] & 0x1fu;
_sfxVolumeTbl[volumeId] = _sfxVolumeTbl[volumeId] | 0x40u; // Set bit 0x40
VabSound *vabSound = ((soundId & 0x8000u) != 0) ? _vabGlob : _vabMsf;
uint16 realId = soundId & 0x7fffu;
uint16 program = realId >> 4u;
uint16 key = ((realId & 0xfu) << 1u | 0x40u);
if (isVoicePlaying(soundId)) {
stopVoicePlaying(soundId);
}
if (vabSound->hasSound(program, key)) {
Audio::SoundHandle *handle = getVoiceHandle(soundId);
if (handle) {
uint8 adjustedVolume = (uint8)((float)_sfxVolume * ((float)volume / 31));
debug(3, "Playing SFX: Master Volume %d Adjusted Volume %d diff %f%%", _sfxVolume, adjustedVolume, 100 * ((float)volume / 31));
Audio::AudioStream *audioStream = vabSound->getAudioStream(program, key);
if (audioStream) {
_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, handle, audioStream, -1, adjustedVolume);
}
}
} else {
warning("Sound not found Program: %d, key %d", program, key);
}
}
void SoundManager::stopSound(uint16 soundId, uint16 volumeId) {
_sfxVolumeTbl[volumeId] = _sfxVolumeTbl[volumeId] & 0xbfu; // Clear bit 0x40
// uint16 vabId = getVabFromSoundId(soundId);
stopVoicePlaying(soundId & ~0x4000u);
}
uint16 SoundManager::getVabFromSoundId(uint16 soundId) {
// TODO
return 0;
}
void SoundManager::loadMsf(uint32 sceneId) {
char msfFileName[] = "XXXX.MSF";
memcpy(msfFileName, _dragonRMS->getSceneName(sceneId), 4);
debug(3, "Loading SFX file %s", msfFileName);
if (_bigFileArchive->doesFileExist(msfFileName)) {
uint32 msfSize;
byte *msfData = _bigFileArchive->load(msfFileName, msfSize);
Common::SeekableReadStream *msfStream = new Common::MemoryReadStream(msfData, msfSize, DisposeAfterUse::YES);
stopAllVoices();
delete _vabMsf;
_vabMsf = new VabSound(msfStream, _vm);
}
}
bool SoundManager::isVoicePlaying(uint16 soundID) {
for (int i = 0; i < NUM_VOICES; i++) {
if (_voice[i].soundID == soundID && _vm->_mixer->isSoundHandleActive(_voice[i].handle)) {
return true;
}
}
return false;
}
Audio::SoundHandle *SoundManager::getVoiceHandle(uint16 soundID) {
for (int i = 0; i < NUM_VOICES; i++) {
if (!_vm->_mixer->isSoundHandleActive(_voice[i].handle)) {
_voice[i].soundID = soundID & ~0x4000u;
return &_voice[i].handle;
}
}
return nullptr;
}
void SoundManager::stopVoicePlaying(uint16 soundID) {
for (int i = 0; i < NUM_VOICES; i++) {
if (_voice[i].soundID == soundID) {
_vm->_mixer->stopHandle(_voice[i].handle);
return;
}
}
}
void SoundManager::stopAllVoices() {
for (int i = 0; i < NUM_VOICES; i++) {
_vm->_mixer->stopHandle(_voice[i].handle);
}
}
void SoundManager::playMusic(int16 song) {
if (_currentSong == song) {
return;
}
_currentSong = song;
// Music filenames have format "xxxxznn.msq" where xxxx is the four character scene name and nn is the two digit song number
Common::String filename = Common::String(_vm->_dragonRMS->getSceneName(_vm->getCurrentSceneId()), 4);
filename += Common::String::format("z%02d.msq", song);
debug(1, "Load music file %s", filename.c_str());
if (!_bigFileArchive->doesFileExist(filename.c_str())) {
warning("Could not find music file %s", filename.c_str());
return;
}
uint32 dataSize;
byte *seqData = _bigFileArchive->load(filename.c_str(), dataSize);
Common::MemoryReadStream *seq = new Common::MemoryReadStream(seqData, dataSize, DisposeAfterUse::YES);
_midiPlayer->playSong(seq);
delete seq;
}
void SoundManager::syncSoundSettings() {
_musicVolume = CLIP<int>(ConfMan.getInt("music_volume"), 0, 255);
_sfxVolume = CLIP<int>(ConfMan.getInt("sfx_volume"), 0, 255);
_speechVolume = CLIP<int>(ConfMan.getInt("speech_volume"), 0, 255);
_midiPlayer->setVolume(_musicVolume);
}
} // End of namespace Dragons

125
engines/dragons/sound.h Normal file
View File

@@ -0,0 +1,125 @@
/* 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 DRAGONS_SOUND_H
#define DRAGONS_SOUND_H
#include "common/scummsys.h"
#include "audio/mixer.h"
#include "audio/audiostream.h"
#include "dragons/midimusicplayer.h"
namespace Dragons {
class DragonsEngine;
class BigfileArchive;
class DragonRMS;
class VabSound;
struct SpeechLocation;
typedef struct Voice {
int16 soundID;
Audio::SoundHandle handle;
Voice() {
soundID = -1;
}
} Voice;
#define NUM_VOICES 25
class SoundManager {
public:
SoundManager(DragonsEngine *vm, BigfileArchive* bigFileArchive, DragonRMS *dragonRms);
~SoundManager();
void loadMsf(uint32 sceneId);
void playOrStopSound(uint16 soundId);
void playMusic(int16 song);
void playSpeech(uint32 textIndex);
bool isSpeechPlaying();
void resumeMusic();
void syncSoundSettings();
public:
uint16 _dat_8006bb60_sound_related;
private:
DragonsEngine *_vm;
BigfileArchive *_bigFileArchive;
DragonRMS *_dragonRMS;
uint8 _speechVolume;
uint8 _sfxVolume;
uint8 _musicVolume;
uint8 _sfxVolumeTbl[0x780];
VabSound* _vabMusx;
VabSound* _vabMsf;
VabSound* _vabGlob;
Audio::SoundHandle _speechHandle;
MidiMusicPlayer *_midiPlayer;
Voice _voice[NUM_VOICES];
int16 _currentSong;
private:
void SomeInitSound_FUN_8003f64c();
void initVabData();
void playSound(uint16 soundId, uint16 i);
void stopSound(uint16 id, uint16 i);
uint16 getVabFromSoundId(uint16 id);
VabSound * loadVab(const char *headerFilename, const char *bodyFilename);
bool getSpeechLocation(uint32 talkId, struct SpeechLocation *location);
bool isVoicePlaying(uint16 soundID);
Audio::SoundHandle *getVoiceHandle(uint16 soundID);
void stopVoicePlaying(uint16 soundID);
void stopAllVoices();
private:
class PSXAudioTrack {
private:
struct ADPCMStatus {
int16 sample[2];
} _adpcmStatus[2];
public:
PSXAudioTrack();
Audio::QueuingAudioStream *createNewAudioStream(Common::File *fd, uint16 sectorStart, int8 startOffset, uint16 sectorEnd);
private:
void queueAudioFromSector(Audio::QueuingAudioStream *audStream, Common::SeekableReadStream *sector);
};
};
} // End of namespace Dragons
#endif //DRAGONS_SOUND_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,247 @@
/* 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 DRAGONS_SPECIALOPCODES_H
#define DRAGONS_SPECIALOPCODES_H
#include "common/func.h"
#include "common/str.h"
namespace Dragons {
#define DRAGONS_NUM_SPECIAL_OPCODES 0x8c
class DragonsEngine;
typedef Common::Functor0<void> SpecialOpcode;
class SpecialOpcodes {
public:
SpecialOpcodes(DragonsEngine *vm);
~SpecialOpcodes();
void run(int16 opcode);
struct SceneUpdater {
void *tbl;
uint16 counter;
int16 iniID;
int16 sequenceID;
uint32 curSequence;
uint32 curSequenceIndex;
uint32 numTotalSequences;
uint32 sequenceDuration;
uint16 numSteps[8];
uint16 iniIDTbl[8][5];
uint16 sequenceIDTbl[8][5];
uint32 textTbl[8][5];
SceneUpdater() {
tbl = nullptr;
iniID = sequenceID = 0;
counter = 0;
curSequence = curSequenceIndex = numTotalSequences = sequenceDuration = 0;
for (uint i = 0; i < 8; i++) {
numSteps[i] = 0;
for (int j = 0; j < 5; j++) {
iniIDTbl[i][j] = 0;
sequenceIDTbl[i][j] = 0;
textTbl[i][j] = 0;
}
}
}
} sceneUpdater;
protected:
DragonsEngine *_vm;
SpecialOpcode *_opcodes[DRAGONS_NUM_SPECIAL_OPCODES];
Common::String _opcodeNames[DRAGONS_NUM_SPECIAL_OPCODES];
int16 _specialOpCounter;
uint8 _dat_80083148;
uint16 _uint16_t_80083154;
public:
int16 getSpecialOpCounter();
void setSpecialOpCounter(int16 newValue);
protected:
void initOpcodes();
void freeOpcodes();
// Opcodes
void spcCatapultMiniGame(); // 1
void spcThumbWrestlingMiniGame(); // 2
void spcClearEngineFlag10(); // 3
void spcSetEngineFlag10(); // 4
void spcRabbitsMiniGame(); //6
void spcDancingMiniGame(); // 7
void spcCastleGardenLogic(); // 8
void spcUnk9();
void spcUnkA();
void spcUnkC();
void spcFadeScreen(); // 0xd
void spcLadyOfTheLakeCapturedSceneLogic(); // 0xe, 0xf
void spcStopLadyOfTheLakeCapturedSceneLogic(); // 0x10
void spc11ShakeScreen(); //0x11
void spcHandleInventionBookTransition(); // 0x12
void spcUnk13InventionBookCloseRelated(); //0x13
void spcClearEngineFlag8(); // 0x14
void spcSetEngineFlag8(); // 0x15
void spcKnightPoolReflectionLogic(); //0x17
void spcWalkOnStilts(); //0x19
void spcActivatePizzaMakerActor(); // 0x1a
void spcDeactivatePizzaMakerActor(); // 0x1b
void spcPizzaMakerActorStopWorking(); // 0x1c
void spcDragonArrivesAtTournament(); // 0x1d
void spcDragonCatapultMiniGame(); // 0x1e
void spcStGeorgeDragonLanded(); // 0x1f
void spcSetEngineFlag0x20000(); // 0x21
void spcClearEngineFlag0x20000(); // 0x22
void spcSetEngineFlag0x200000(); // 0x23
void spcClearEngineFlag0x200000(); // 0x24
void spcFlickerSetPriority2(); // 0x25
void spcMenInMinesSceneLogic(); //0x26
void spcStopMenInMinesSceneLogic(); //0x27
void spcMonksAtBarSceneLogic(); //0x28
void spcStopMonksAtBarSceneLogic(); //0x29
void spcFlameBedroomEscapeSceneLogic(); // 0x2b
void spcStopFlameBedroomEscapeSceneLogic(); // 0x2c
void spcCastleMoatFull(); //0x2e
void spcCastleRestoreScalePoints(); //0x2f
void spcCastleMoatUpdateActorSceneScalePoints(); //0x30
void spcCastleGateMoatDrainedSceneLogic(); //0x31
void spcUnk34(); //0x34 pitchfork mole.
void spcFlickerClearFlag0x80(); //0x36
void spcNoop1(); // 0x38
void spcTownAngryVillagersSceneLogic(); //0x39
void spcBlackDragonCrashThroughGate(); //0x3a
void spcSetEngineFlag0x2000000(); // 0x3b
void spcClearEngineFlag0x2000000(); // 0x3c
void spcZigmondFraudSceneLogic(); // 0x3e
void spcZigmondFraudSceneLogic1(); // 0x40
void spcBrokenBlackDragonSceneLogic(); // 0x41
void spcDodoUnderAttackSceneLogic(); //0x42
void spcForestWithoutDodoSceneLogic(); //0x43
void spcBlackDragonOnHillSceneLogic(); //0x46
void spcHedgehogTest(); // 0x48
void spcLoadScene1(); // 0x49
void spcKnightsSavedCastleCutScene(); //0x4b
void spcFlickerReturnsCutScene(); // 0x4c
void spcKnightsSavedAgainCutScene(); //0c4d
void spcUnk4e();
void spcUnk4f();
void spcCloseInventory(); // 0x50
void spcOpenInventionBook(); // 0x51
void spcCloseInventionBook(); // 0x52
void spcClearEngineFlag0x4000000(); // 0x53
void spcSetEngineFlag0x4000000(); // 0x54
void spcSetCursorSequenceIdToZero(); // 0x55
void spcFlickerSetFlag0x80(); // 0x5b
void spcUnk5d();
void spcUnk5e();
void spcUnk5f();
void spcCastleBuildBlackDragonSceneLogic(); //0x61
void spcStopSceneUpdateFunction(); //0x62
void spcSetInventorySequenceTo5(); // 0x63
void spcResetInventorySequence(); // 0x64
void spcUnk65ScenePaletteRelated(); // 0x65;
void spcUnk66();
void spcTournamentSetCamera(); // 0x67
void spcTournamentCutScene(); // 0x68
void spcInsideBlackDragonUpdatePalette(); // 0x69
void spcCastleGateSceneLogic(); // 0x6a
void spcTransitionToMap(); // 0x6b
void spcTransitionFromMap(); // 0x6c
void spcCaveOfDilemmaSceneLogic(); // 0x6d
void spcLoadLadyOfTheLakeActor(); //0x70
void spcFadeCreditsToBackStageScene(); //0x71
void spcRunCredits(); //0x72
void spcEndCreditsAndRestartGame(); //0x73
void spcUseClickerOnLever(); // 0x74
void spcJesterInLibrarySceneLogic(); // 0x77
void spcBlackDragonDialogForCamelhot(); // 0x7a
void spcSetCameraXToZero(); //0x7b
void spcDiamondIntroSequenceLogic(); //0x7c
void spcLoadFileS10a6act(); //0x7d
void spcLoadFileS10a7act(); //0x7e
void spcFlickerPutOnStGeorgeArmor(); //0x7f
void spcUnk80FlickerArmorOn(); //0x80
void spcShakeScreenSceneLogic(); //0x81
void spcClearTextFromScreen(); // 0x82
void spcStopScreenShakeUpdater(); // 0x83
void spcInsideBlackDragonScreenShake(); // 0x84
void spc85SetScene1To0x35(); //0x85
void spc86SetScene1To0x33(); //0x86
void spc87SetScene1To0x17(); //0x87
void spc88SetScene1To0x16(); //0x88
void spcSetUnkFlag2(); // 0x89
void spcClearUnkFlag2(); //0x8a
void spcUnk8b(); //0x8b
void setupTableBasedSceneUpdateFunction(uint16 initialCounter, uint16 numSequences, uint16 sequenceDuration);
private:
void panCamera(int16 mode);
void pizzaMakerStopWorking();
void clearSceneUpdateFunction();
void mapTransition(uint16 mode);
};
// update functions
void castleFogUpdateFunction();
void menInMinesSceneUpdateFunction();
void monksAtBarSceneUpdateFunction();
void flameEscapeSceneUpdateFunction();
void pizzaUpdateFunction();
void tableBasedSceneUpdateFunction();
void castleBuildingBlackDragon2UpdateFunction();
void shakeScreenUpdateFunction();
void ladyOfTheLakeCapturedUpdateFunction();
void caveOfDilemmaUpdateFunction();
void moatDrainedSceneUpdateFunction();
} // End of namespace Dragons
#endif // DRAGONS_SPECIALOPCODES_H

View File

@@ -0,0 +1,69 @@
/* 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/events.h"
#include "video/psx_decoder.h"
#include "dragons/dragons.h"
#include "dragons/screen.h"
#include "dragons/strplayer.h"
namespace Dragons {
StrPlayer::StrPlayer(DragonsEngine *vm, Screen *screen) : _vm(vm), _screen(screen) {
_decoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x);
}
void StrPlayer::playVideo(const Common::Path &filename) {
bool skipped = false;
if (!_decoder->loadFile(filename)) {
error("Error playing video from %s", filename.toString(Common::Path::kNativeSeparator).c_str());
}
_decoder->start();
while (!_vm->shouldQuit() && !_decoder->endOfVideo() && !skipped) {
if (_decoder->needsUpdate()) {
const Graphics::Surface *frame = _decoder->decodeNextFrame();
if (frame) {
_screen->clearScreen();
_screen->copyRectToSurface(*frame, 0, 0, Common::Rect(frame->w, frame->h));
_screen->updateScreen();
}
}
Common::Event event;
while (_vm->_system->getEventManager()->pollEvent(event)) {
if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END
&& (event.customType == Dragons::kDragonsActionSelect || event.customType == Dragons::kDragonsActionEnter)) {
skipped = true;
}
}
_vm->_system->delayMillis(10);
}
_screen->clearScreen();
_decoder->close();
}
StrPlayer::~StrPlayer() {
delete _decoder;
}
} // End of namespace Dragons

View File

@@ -0,0 +1,45 @@
/* 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 DRAGONS_STRPLAYER_H
#define DRAGONS_STRPLAYER_H
#include "video/psx_decoder.h"
namespace Dragons {
class DragonsEngine;
class Screen;
class StrPlayer {
private:
DragonsEngine *_vm;
Screen *_screen;
Video::VideoDecoder *_decoder;
public:
StrPlayer(DragonsEngine *vm, Screen *screen);
~StrPlayer();
void playVideo(const Common::Path &filename);
private:
};
} // End of namespace Dragons
#endif //DRAGONS_STRPLAYER_H

1138
engines/dragons/talk.cpp Normal file

File diff suppressed because it is too large Load Diff

113
engines/dragons/talk.h Normal file
View File

@@ -0,0 +1,113 @@
/* 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 DRAGONS_TALK_H
#define DRAGONS_TALK_H
#include "common/str.h"
#include "dragons/scriptopcodes.h"
namespace Dragons {
class BigfileArchive;
class Actor;
class DragonsEngine;
struct TalkDialogEntry {
char dialogText[600];
uint32 textIndex;
uint32 textIndex1;
byte *scriptCodeStartPtr;
byte *scriptCodeEndPtr;
uint16 flags;
uint8 xPosMaybe;
uint8 yPosMaybe;
int16 field_26c;
uint16 iniId;
bool hasText;
};
class Talk {
public:
uint32 _dat_8008e7e8_dialogBox_x1;
uint32 _dat_8008e844_dialogBox_y1;
uint32 _dat_8008e848_dialogBox_x2;
uint32 _dat_8008e874_dialogBox_y2;
private:
DragonsEngine *_vm;
BigfileArchive *_bigfileArchive;
Common::Array<TalkDialogEntry*> _dialogEntries;
uint32 _defaultResponseTbl[45];
uint8 _dat_800726ec_tfont_field0;
uint8 _dat_800726f0_tfont_field2;
uint8 _dat_800633f8_talkDialogFlag;
public:
Talk(DragonsEngine *vm, BigfileArchive *bigfileArchive);
void init();
bool loadText(uint32 textIndex, uint16 *textBuffer, uint16 bufferLength);
void printWideText(byte *text);
void talkFromIni(uint32 iniId, uint32 textIndex);
void flickerRandomDefaultResponse();
void loadAndDisplayDialogAroundPoint(uint32 textId, uint16 x, uint16 y, uint16 param_4, int16 param_5);
uint32 displayDialogAroundINI(uint32 iniId, uint16 *dialogText, uint32 textIndex);
void displayDialogAroundPoint(uint16 *dialogText, uint16 x, uint16 y, uint16 param_4, int16 param_5, uint32 textId);
void displayDialogAroundActor(Actor *actor, uint16 param_2, uint16 *dialogText, uint32 textIndex);
void FUN_8003239c(uint16 *dialog, int16 x, int16 y, int32 param_4, uint16 param_5, Actor *actor, uint16 startSequenceId, uint16 endSequenceId, uint32 textId);
uint8 conversation_related_maybe(uint16 *dialogText, uint16 x, uint16 y, uint16 param_4, int16 param_5, uint32 textId, int16 param_7);
void addTalkDialogEntry(TalkDialogEntry *talkDialogEntry);
void clearDialogEntries();
bool talkToActor(ScriptOpCall &scriptOpCall);
uint somethingTextAndSpeechAndAnimRelated(Actor *actor, int16 sequenceId1, int16 sequenceId2, uint32 textIndex, uint16 param_5);
void FUN_8001a7c4_clearDialogBoxMaybe(); //clear box maybe?
void playDialogAudioDontWait(uint32 textIndex);
private:
void copyTextToBuffer(uint16 *destBuffer, byte *src, uint32 destBufferLength);
uint32 wideStrLen(uint16 *text);
TalkDialogEntry *displayTalkDialogMenu(Common::Array<TalkDialogEntry*> dialogEntries);
void exitTalkMenu(bool isFlag8Set, bool isFlag100Set, Common::Array<TalkDialogEntry*> dialogEntries);
uint32 getDefaultResponseTextIndex();
void initDefaultResponseTable();
uint32 strlenUTF16(uint16 *text);
uint16 *findCharInU16Str(uint16 *text, uint16 chr);
void drawDialogBox(uint32 x1, uint32 y1, uint32 x2, uint32 y2, uint16 unk);
uint16 *UTF16ToUTF16Z(uint16 *dest, uint16 *src);
uint16 findLastPositionOf5cChar(uint16 *text);
uint32 truncateDialogText(uint16 *srcText, uint16 *destText, uint32 srcLength, uint16 destLength);
uint32 extractTextIndex(Common::File *fd, uint16 offset);
};
} // End of namespace Dragons
#endif //DRAGONS_TALK_H

View File

@@ -0,0 +1,204 @@
/* 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/textconsole.h"
#include "common/debug.h"
#include "audio/decoders/xa.h"
#include "audio/audiostream.h"
#include "audio/mixer.h"
#include "common/memstream.h"
#include "dragons/vabsound.h"
#include "dragons/dragons.h"
namespace Dragons {
VabSound::VabSound(Common::SeekableReadStream *msfData, const DragonsEngine *_vm): _toneAttrs(nullptr), _vbData(nullptr) {
loadHeader(msfData);
int32 dataSize = msfData->size() - msfData->pos();
_vbData = new byte[dataSize];
msfData->read(_vbData, dataSize);
// _vbData = new Common::MemoryReadStream(newData, dataSize, DisposeAfterUse::YES);
//
// Audio::AudioStream *str = Audio::makeXAStream(_vbData, 11025);
// Audio::SoundHandle _speechHandle;
// _vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_speechHandle, str);
delete msfData;
}
VabSound::VabSound(Common::SeekableReadStream *vhData, Common::SeekableReadStream *vbData): _toneAttrs(nullptr), _vbData(nullptr) {
loadHeader(vhData);
assert(vhData->pos() == vhData->size());
_vbData = new byte[vbData->size()];
vbData->read(_vbData, vbData->size());
delete vhData;
delete vbData;
}
void VabSound::loadHeader(Common::SeekableReadStream *vhData) {
vhData->seek(0);
vhData->read(&_header.magic, 4);
_header.version = vhData->readUint32LE();
_header.vabId = vhData->readUint32LE();
_header.waveformSize = vhData->readUint32LE();
_header.reserved0 = vhData->readUint16LE();
_header.numPrograms = vhData->readUint16LE();
_header.numTones = vhData->readUint16LE();
_header.numVAG = vhData->readUint16LE();
_header.masterVolume = vhData->readByte();
_header.masterPan = vhData->readByte();
_header.bankAttr1 = vhData->readByte();
_header.bankAttr2 = vhData->readByte();
_header.reserved1 = vhData->readUint32LE();
if (strncmp(_header.magic, "pBAV", 4) != 0) {
error("Invalid VAB file");
}
loadProgramAttributes(vhData);
loadToneAttributes(vhData);
uint16 tempOffsets[0x100];
for (int i = 0; i < 0x100; i++) {
tempOffsets[i] = vhData->readUint16LE();
}
_vagOffsets[0] = tempOffsets[0] << 3u;
for (int j = 1; j < 0x100; ++j) {
const int vagSize = tempOffsets[j] << 3u;
_vagSizes[j - 1] = vagSize;
_vagOffsets[j] = vagSize + _vagOffsets[j - 1];
}
}
VabSound::~VabSound() {
delete _toneAttrs;
delete[] _vbData;
}
Audio::AudioStream *VabSound::getAudioStream(uint16 program, uint16 key) {
int16 vagID = getVagID(program, key);
if (vagID < 0) {
return nullptr;
}
int16 baseKey = getBaseToneKey(program, key);
int sampleRate = getAdjustedSampleRate(key, baseKey);
debug(3, "Playing program %d, Key %d, numTones: %d, vagID %d, vagOffset: %x, size: %x adjustedSampleRate: %d",
program, key, _programAttrs[program].tones, vagID, _vagOffsets[vagID], _vagSizes[vagID], sampleRate);
Audio::AudioStream *str = Audio::makeXAStream(
new Common::MemoryReadStream(&_vbData[_vagOffsets[vagID]], _vagSizes[vagID], DisposeAfterUse::NO),
sampleRate,
DisposeAfterUse::YES);
return str;
}
void VabSound::loadProgramAttributes(Common::SeekableReadStream *vhData) {
for (int i = 0; i < DRAGONS_VAB_NUM_PROG_ATTRS; i++) {
_programAttrs[i].tones = vhData->readByte();
_programAttrs[i].mvol = vhData->readByte();
_programAttrs[i].prior = vhData->readByte();
_programAttrs[i].mode = vhData->readByte();
_programAttrs[i].mpan = vhData->readByte();
_programAttrs[i].reserved0 = vhData->readByte();
_programAttrs[i].attr = vhData->readUint16LE();
_programAttrs[i].reserved1 = vhData->readUint32LE();
_programAttrs[i].reserved2 = vhData->readUint32LE();
}
}
void VabSound::loadToneAttributes(Common::SeekableReadStream *vhData) {
const int numTones = 16 * _header.numPrograms;
_toneAttrs = new VabToneAttr[numTones];
VabToneAttr *pVabToneAttr = _toneAttrs;
for (int i = 0; i < numTones; i++, pVabToneAttr++) {
pVabToneAttr->prior = vhData->readByte();
pVabToneAttr->mode = vhData->readByte();
pVabToneAttr->vol = vhData->readByte();
pVabToneAttr->pan = vhData->readByte();
pVabToneAttr->center = vhData->readByte();
pVabToneAttr->shift = vhData->readByte();
pVabToneAttr->min = vhData->readByte();
pVabToneAttr->max = vhData->readByte();
pVabToneAttr->vibW = vhData->readByte();
pVabToneAttr->vibT = vhData->readByte();
pVabToneAttr->porW = vhData->readByte();
pVabToneAttr->porT = vhData->readByte();
pVabToneAttr->pbmin = vhData->readByte();
pVabToneAttr->pbmax = vhData->readByte();
pVabToneAttr->reserved1 = vhData->readByte();
pVabToneAttr->reserved2 = vhData->readByte();
pVabToneAttr->adsr1 = vhData->readUint16LE();
pVabToneAttr->adsr2 = vhData->readUint16LE();
pVabToneAttr->prog = vhData->readSint16LE();
pVabToneAttr->vag = vhData->readSint16LE();
for (int j = 0; j < 4; j++) {
pVabToneAttr->reserved[j] = vhData->readSint16LE();
}
}
}
int16 VabSound::getVagID(uint16 program, uint16 key) {
if (program < _header.numVAG) {
for (int i = 0; i < _programAttrs[program].tones; i++) {
if (_toneAttrs[i].prog == program && _toneAttrs[i].min <= key && _toneAttrs[i].max >= key) {
return _toneAttrs[i].vag - 1;
}
}
} else {
warning("program >= _header.numVAG %d %d", program, _header.numVAG);
}
return -1;
}
int16 VabSound::getBaseToneKey(uint16 program, uint16 key) {
if (program < _header.numVAG) {
for (int i = 0; i < _programAttrs[program].tones; i++) {
if (_toneAttrs[i].prog == program && _toneAttrs[i].min <= key && _toneAttrs[i].max >= key) {
debug(3, "tone key %d center %d mode %d shift %d min %d, max %d adsr 1 %d adsr 2 %d pbmin %d pbmax %d",
key, _toneAttrs[i].center, _toneAttrs[i].mode, _toneAttrs[i].shift, _toneAttrs[i].min, _toneAttrs[i].max,
_toneAttrs[i].adsr1, _toneAttrs[i].adsr2, _toneAttrs[i].pbmin, _toneAttrs[i].pbmax);
return _toneAttrs[i].center;
}
}
}
return -1;
}
bool VabSound::hasSound(uint16 program, uint16 key) {
return getVagID(program, key) != -1;
}
int VabSound::getAdjustedSampleRate(int16 desiredKey, int16 baseToneKey) {
if (desiredKey == baseToneKey) {
return 44100;
}
float diff = pow(2, (float)(desiredKey - baseToneKey) / 12);
return (int)((float)44100 * diff);
}
} // End of namespace Dragons

139
engines/dragons/vabsound.h Normal file
View File

@@ -0,0 +1,139 @@
/* 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 DRAGONS_VABSOUND_H
#define DRAGONS_VABSOUND_H
#include "common/scummsys.h"
namespace Common {
class SeekableReadStream;
}
namespace Audio {
class AudioStream;
}
namespace Dragons {
class DragonsEngine;
#define DRAGONS_VAB_NUM_PROG_ATTRS 128
struct VabHeader {
char magic[4];
uint32 version;
uint32 vabId;
uint32 waveformSize;
uint16 reserved0;
uint16 numPrograms;
uint16 numTones;
uint16 numVAG;
uint8 masterVolume;
uint8 masterPan;
uint8 bankAttr1;
uint8 bankAttr2;
uint32 reserved1;
};
struct VabProgramAttr {
uint8 tones;
uint8 mvol;
uint8 prior;
uint8 mode;
uint8 mpan;
uint8 reserved0;
uint16 attr;
uint32 reserved1;
uint32 reserved2;
};
struct VabToneAttr {
uint8 prior;
uint8 mode;
uint8 vol;
uint8 pan;
uint8 center;
uint8 shift;
uint8 min;
uint8 max;
uint8 vibW;
uint8 vibT;
uint8 porW;
uint8 porT;
uint8 pbmin;
uint8 pbmax;
uint8 reserved1;
uint8 reserved2;
uint16 adsr1;
uint16 adsr2;
int16 prog;
int16 vag;
int16 reserved[4];
};
class VabSound {
public:
/**
* Creates a VAB file with both header and body (*.MSF). VabSound will dispose msfData
* @param data
*/
VabSound(Common::SeekableReadStream* msfData, const DragonsEngine *_vm);
/**
* Creates a VAB file with separate header and body (*.VH and *.VB). VabSound will dispose vhData & vbData
*
* @param dataHeader
* @param dataBody
*/
VabSound(Common::SeekableReadStream* vhData, Common::SeekableReadStream* vbData);
~VabSound();
bool hasSound(uint16 program, uint16 key);
Audio::AudioStream *getAudioStream(uint16 program, uint16 key);
private:
byte *_vbData;
VabHeader _header;
VabProgramAttr _programAttrs[DRAGONS_VAB_NUM_PROG_ATTRS];
VabToneAttr *_toneAttrs;
uint32 _vagSizes[0x100];
uint32 _vagOffsets[0x100];
void loadHeader(Common::SeekableReadStream *vhData);
void loadProgramAttributes(Common::SeekableReadStream *vhData);
void loadToneAttributes(Common::SeekableReadStream *vhData);
int16 getVagID(uint16 program, uint16 key);
int16 getBaseToneKey(uint16 program, uint16 key);
int getAdjustedSampleRate(int16 desiredKey, int16 baseToneKey);
};
} // End of namespace Dragons
#endif //DRAGONS_VABSOUND_H