BLADERUNNER: fixed exit selection, added footstep sounds, added some debugging display (scene objects, regions, exits, walkboxes, lights?)

This commit is contained in:
Peter Kohaut 2016-09-20 00:33:06 +02:00 committed by Eugene Sandulenko
parent 7e7cf4e748
commit cfc8ffed8a
15 changed files with 325 additions and 42 deletions

View File

@ -365,7 +365,7 @@ bool Actor::tick(bool forceDraw) {
float originalZ = this->_position.z;
this->_position.x = this->_position.x + positionChange.x * cosx - positionChange.y * sinx;
this->_position.z = this->_position.z - positionChange.x * sinx - positionChange.y * cosx; //why minus?
this->_position.z = this->_position.z + positionChange.x * sinx + positionChange.y * cosx;
this->_position.y = this->_position.y + positionChange.z;
if (_vm->_sceneObjects->existsOnXZ(this->_id, this->_position.x, this->_position.z, false, false) == 1 && !this->_isImmuneToObstacles) {
@ -494,6 +494,12 @@ void Actor::setBoundingBox(Vector3 position, bool retired) {
}
}
float Actor::distanceFromView(View *view) {
float xDist = this->_position.x - view->_cameraPosition.x;
float zDist = this->_position.z - view->_cameraPosition.z;
return sqrt(xDist * xDist + zDist * zDist);
}
bool Actor::isWalking() {
return _walkInfo->isWalking();
}
@ -803,6 +809,16 @@ void Actor::copyClues(int actorId) {
}
}
int Actor::soundVolume() {
float dist = distanceFromView(_vm->_view);
return 255.0f * MAX(MIN(dist / 1200.0f, 1.0f), 0.0f);
}
int Actor::soundBalance() {
Vector2 screenPosition = _vm->_view->calculateScreenPosition(_position);
return 127.0f * (MAX(MIN(screenPosition.x / 640.0f, 1.0f), 0.0f) * 2.0f - 1.0f);
}
void Actor::countdownTimerStart(int timerId, int interval) {
assert(timerId >= 0 && timerId < 7);
_timersRemain[timerId] = interval;

View File

@ -35,6 +35,7 @@ class ActorWalk;
class BladeRunnerEngine;
class BoundingBox;
class MovementTrack;
class View;
class Actor {
friend class ScriptBase;
@ -138,6 +139,7 @@ public:
void setSetId(int setId);
BoundingBox* getBoundingBox() { return _bbox; }
Common::Rect* getScreenRectangle() { return &_screenRectangle; }
int getWalkbox() { return _walkboxId; }
bool isRetired() { return _isRetired; }
bool isTargetable() { return _isTargetable; }
void setTargetable(bool targetable);
@ -191,9 +193,13 @@ public:
void loseClue(int clueId);
bool hasClue(int clueId);
void copyClues(int actorId);
int soundVolume();
int soundBalance();
private:
void setFacing(int facing, bool halfOrSet = true);
void setBoundingBox(Vector3 position, bool retired);
float distanceFromView(View* view);
};
} // End of namespace BladeRunner

View File

@ -500,6 +500,36 @@ void BladeRunnerEngine::gameLoop() {
} while (_gameIsRunning);
}
#if _DEBUG
void drawBBox(Vector3 start, Vector3 end, View* view, Graphics::Surface *surface, int color) {
Vector2 bfl = view->calculateScreenPosition(Vector3(start.x, start.y, start.z));
Vector2 bfr = view->calculateScreenPosition(Vector3(start.x, end.y, start.z));
Vector2 bbr = view->calculateScreenPosition(Vector3(end.x, end.y, start.z));
Vector2 bbl = view->calculateScreenPosition(Vector3(end.x, start.y, start.z));
Vector2 tfl = view->calculateScreenPosition(Vector3(start.x, start.y, end.z));
Vector2 tfr = view->calculateScreenPosition(Vector3(start.x, end.y, end.z));
Vector2 tbr = view->calculateScreenPosition(Vector3(end.x, end.y, end.z));
Vector2 tbl = view->calculateScreenPosition(Vector3(end.x, start.y, end.z));
surface->drawLine(bfl.x, bfl.y, bfr.x, bfr.y, color);
surface->drawLine(bfr.x, bfr.y, bbr.x, bbr.y, color);
surface->drawLine(bbr.x, bbr.y, bbl.x, bbl.y, color);
surface->drawLine(bbl.x, bbl.y, bfl.x, bfl.y, color);
surface->drawLine(tfl.x, tfl.y, tfr.x, tfr.y, color);
surface->drawLine(tfr.x, tfr.y, tbr.x, tbr.y, color);
surface->drawLine(tbr.x, tbr.y, tbl.x, tbl.y, color);
surface->drawLine(tbl.x, tbl.y, tfl.x, tfl.y, color);
surface->drawLine(bfl.x, bfl.y, tfl.x, tfl.y, color);
surface->drawLine(bfr.x, bfr.y, tfr.x, tfr.y, color);
surface->drawLine(bbr.x, bbr.y, tbr.x, tbr.y, color);
surface->drawLine(bbl.x, bbl.y, tbl.x, tbl.y, color);
}
#endif
void BladeRunnerEngine::gameTick() {
handleEvents();
@ -554,11 +584,10 @@ void BladeRunnerEngine::gameTick() {
// TODO: Tick Actor AI and Timers
if (_settings->getNewScene() == -1 || _script->_inScriptCounter /* || in_ai */) {
_sliceRenderer->setView(*_view);
// Tick and draw all actors in current set
int setId = _scene->_setId;
//int setId = _scene->_setId;
for (int i = 0, end = _gameInfo->getActorCount(); i != end; ++i) {
//if (_actors[i]->getSetId() == setId) {
if (i == 0 || i == 23){ // Currently limited to McCoy and Officer Leroy
@ -577,6 +606,98 @@ void BladeRunnerEngine::gameTick() {
// TODO: Process AUD
// TODO: Footstep sound
if (_walkSoundId >= 0)
{
const char *name = _gameInfo->getSfxTrack(_walkSoundId);
_audioPlayer->playAud(name, _walkSoundVolume, _walkSoundBalance, _walkSoundBalance, 50, 0);
_walkSoundId = -1;
}
#if _DEBUG
//draw scene objects
int count = _sceneObjects->_count;
if (count > 0) {
for (int i = 0; i < count; i++) {
SceneObject *sceneObject = &_sceneObjects->_sceneObjects[_sceneObjects->_sceneObjectsSortedByDistance[i]];
BoundingBox *bbox = &sceneObject->_boundingBox;
Vector3 a, b;
bbox->getXYZ(&a.x, &a.y, &a.z, &b.x, &b.y, &b.z);
int color = 0b111111111111111;
if (sceneObject->_sceneObjectType == SceneObjectTypeActor) {
color = 0b111110000000000;
}
if (sceneObject->_sceneObjectType == SceneObjectTypeObject) {
color = 0b011110111101111;
//if (sceneObject->_isObstacle)
// color += 0b100000000000000;
if (sceneObject->_isClickable)
color = 0b000001111100000;
//if (sceneObject->_isTarget)
// color += 0b000000000010000;
}
sceneObject->_sceneObjectId;
drawBBox(a, b, _view, &_surface2, color);
}
}
//draw regions
for (int i = 0; i < 10; i++) {
Region* region = &_scene->_regions->_regions[i];
if (!region->_present) continue;
_surface2.frameRect(region->_rectangle, 0b000000000011111);
}
for (int i = 0; i < 10; i++) {
Region* region = &_scene->_exits->_regions[i];
if (!region->_present) continue;
_surface2.frameRect(region->_rectangle, 0b111111111111111);
}
for (int i = 0; i < _scene->_set->_walkboxCount; i++) {
Walkbox *walkbox = &_scene->_set->_walkboxes[i];
for(int j = 0; j < walkbox->_vertexCount; j++) {
Vector2 start = _view->calculateScreenPosition(walkbox->_vertices[j]);
Vector2 end = _view->calculateScreenPosition(walkbox->_vertices[(j+1) % walkbox->_vertexCount]);
//debug("walkbox[%i][%i] = x=%f y=%f x=%f y=%f", i, j, start.x, start.y, end.x, end.y);
_surface2.drawLine(start.x, start.y, end.x, end.y, 0b111111111100000);
}
}
for (Light* light = _lights->_lights; light != nullptr; light->_next) {
Matrix4x3 matrix = light->_matrix;
// this is all wrong
// matrix = matrix * rotationMatrixX(float(M_PI) / 2.0f);
// Matrix4x3 a(
// -1.0f, 0.0f, 0.0f, 0.0f,
// 0.0f, -1.0f, 0.0f, 0.0f,
// 0.0f, 0.0f, 1.0f, 0.0f);
//matrix = a * matrix;
// matrix = invertMatrix(matrix);
int colorR = (light->_color.r * 31.0f);
int colorG = (light->_color.g * 31.0f);
int colorB = (light->_color.b * 31.0f);
int color = (colorR << 10) + (colorG << 5) + colorB;
drawBBox(
Vector3(matrix(0, 3) - 5.0f, matrix(1, 3) - 5.0f, matrix(2, 3) - 5.0f),
Vector3(matrix(0, 3) + 5.0f, matrix(1, 3) + 5.0f, matrix(2, 3) + 5.0f),
_view, &_surface2, color
);
light = light->_next;
}
#endif
_system->copyRectToScreen((const byte *)_surface2.getBasePtr(0, 0), _surface2.pitch, 0, 0, 640, 480);
_system->updateScreen();
_system->delayMillis(10);
@ -614,7 +735,7 @@ void BladeRunnerEngine::handleMouseClick(int x, int y) {
int isTarget;
int sceneObjectId = _sceneObjects->findByXYZ(&isClickable, &isObstacle, &isTarget, mousePosition.x, mousePosition.y, mousePosition.z, 1, 0, 1);
int exitIndex = _scene->_exits->getTypeAtXY(x, y);
int exitIndex = _scene->_exits->getRegionAtXY(x, y);
debug("%d %d", sceneObjectId, exitIndex);

View File

@ -120,6 +120,10 @@ public:
bool _gameIsLoading;
bool _sceneIsLoading;
int _walkSoundId = -1;
int _walkSoundVolume = 0;
int _walkSoundBalance = 0;
private:
static const int kArchiveCount = 10;
MIXArchive _archives[kArchiveCount];

View File

@ -38,6 +38,9 @@ class Lights;
class Light
{
#if _DEBUG
friend class BladeRunnerEngine;
#endif
friend class Lights;
char _name[20];

View File

@ -10,7 +10,7 @@ Lights::Lights(BladeRunnerEngine *vm)
_ambientLightColor.g = 0.0;
_ambientLightColor.b = 0.0;
_lights = NULL;
_lights = nullptr;
_frame = 0;
}

View File

@ -32,6 +32,9 @@
namespace BladeRunner {
class Lights {
#if _DEBUG
friend class BladeRunnerEngine;
#endif
BladeRunnerEngine *_vm;
Color _ambientLightColor;

View File

@ -38,6 +38,10 @@ struct Region
class Regions
{
#ifdef _DEBUG
friend class BladeRunnerEngine;
#endif
private:
Region* _regions;
bool _enabled;

View File

@ -62,6 +62,9 @@ struct SceneObject
};
class SceneObjects {
#if _DEBUG
friend class BladeRunnerEngine;
#endif
BladeRunnerEngine *_vm;
private:

View File

@ -25,10 +25,14 @@
namespace BladeRunner {
void ScriptRC01::InitializeScene() {
#if _DEBUG
//TODO: not part of game, remove
Game_Flag_Set(24); // force skip intro
// Game_Flag_Set(9); // Force flag 9 so McCoy will be in view
Footstep_Sound_Override_On(0);
#endif
if (!Game_Flag_Query(24)) {
Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
Ambient_Sounds_Remove_All_Looping_Sounds(1);

View File

@ -52,7 +52,13 @@ namespace BladeRunner {
bool Script::open(const Common::String &name) {
delete _currentScript;
if (name == "RC01") { _currentScript = new ScriptRC01(_vm); return true; }
if (name == "RC02") { _currentScript = new ScriptRC02(_vm); return true; }
if (name == "RC03") { _currentScript = new ScriptRC03(_vm); return true; }
if (name == "RC04") { _currentScript = new ScriptRC04(_vm); return true; }
if (name == "RC51") { _currentScript = new ScriptRC51(_vm); return true; }
return false;
}
@ -792,40 +798,61 @@ void ScriptBase::Sound_Play_Speech_Line(int actorId, int speechId, int a3, int a
}
void ScriptBase::Sound_Left_Footstep_Walk(int actorId) {
//TODO
warning("Sound_Left_Footstep_Walk(%d)", actorId);
int walkboxId = _vm->_actors[actorId]->getWalkbox();
if (walkboxId < 0) {
walkboxId = 0;
}
_vm->_walkSoundId = _vm->_scene->_set->getWalkboxSoundWalkLeft(walkboxId);
_vm->_walkSoundVolume = _vm->_actors[actorId]->soundVolume();
_vm->_walkSoundBalance = _vm->_actors[actorId]->soundBalance();
}
void ScriptBase::Sound_Right_Footstep_Walk(int actorId) {
//TODO
warning("Sound_Right_Footstep_Walk(%d)", actorId);
int walkboxId = _vm->_actors[actorId]->getWalkbox();
if (walkboxId < 0) {
walkboxId = 0;
}
_vm->_walkSoundId = _vm->_scene->_set->getWalkboxSoundWalkRight(walkboxId);
_vm->_walkSoundVolume = _vm->_actors[actorId]->soundVolume();
_vm->_walkSoundBalance = _vm->_actors[actorId]->soundBalance();
}
void ScriptBase::Sound_Left_Footstep_Run(int actorId) {
//TODO
warning("Sound_Left_Footstep_Run(%d)", actorId);
int walkboxId = _vm->_actors[actorId]->getWalkbox();
if (walkboxId < 0) {
walkboxId = 0;
}
_vm->_walkSoundId = _vm->_scene->_set->getWalkboxSoundRunLeft(walkboxId);
_vm->_walkSoundVolume = _vm->_actors[actorId]->soundVolume();
_vm->_walkSoundBalance = _vm->_actors[actorId]->soundBalance();
}
void ScriptBase::Sound_Right_Footstep_Run(int actorId) {
//TODO
warning("Sound_Right_Footstep_Run(%d)", actorId);
int walkboxId = _vm->_actors[actorId]->getWalkbox();
if (walkboxId < 0) {
walkboxId = 0;
}
_vm->_walkSoundId = _vm->_scene->_set->getWalkboxSoundRunRight(walkboxId);
_vm->_walkSoundVolume = _vm->_actors[actorId]->soundVolume();
_vm->_walkSoundBalance = _vm->_actors[actorId]->soundBalance();
}
// ScriptBase::Sound_Walk_Shuffle_Stop
void ScriptBase::Footstep_Sounds_Set(int walkboxId, int stepSound) {
//TODO
warning("Footstep_Sounds_Set(%d, %d)", walkboxId, stepSound);
_vm->_scene->_set->setWalkboxStepSound(walkboxId, stepSound);
}
void ScriptBase::Footstep_Sound_Override_On(int footstepSoundOverride) {
//TODO
warning("Footstep_Sound_Override_On(%d)", footstepSoundOverride);
_vm->_scene->_set->setFoodstepSoundOverride(footstepSoundOverride);
}
void ScriptBase::Footstep_Sound_Override_Off() {
//TODO
warning("Footstep_Sound_Override_Off()");
_vm->_scene->_set->resetFoodstepSoundOverride();
}
bool ScriptBase::Music_Play(int a1, int a2, int a3, int a4, int a5, int a6, int a7) {

View File

@ -44,6 +44,7 @@ Set::Set(BladeRunnerEngine *vm) : _vm(vm) {
_walkboxes = new Walkbox[95];
_footstepSoundOverride = -1;
_effects = new SetEffects(vm);
_loaded = false;
}
Set::~Set() {
@ -64,7 +65,7 @@ bool Set::open(const Common::String &name) {
_objectCount = s->readUint32LE();
assert(_objectCount <= 85);
for (uint32 i = 0; i != _objectCount; ++i) {
for (int i = 0; i < _objectCount; ++i) {
s->read(_objects[i]._name, 20);
float x0, y0, z0, x1, y1, z1;
@ -89,7 +90,7 @@ bool Set::open(const Common::String &name) {
_walkboxCount = s->readUint32LE();
assert(_walkboxCount <= 95);
for (uint32 i = 0; i != _walkboxCount; ++i) {
for (int i = 0; i < _walkboxCount; ++i) {
float x, y, z;
s->read(_walkboxes[i]._name, 20);
@ -98,7 +99,7 @@ bool Set::open(const Common::String &name) {
assert(_walkboxes[i]._vertexCount <= 8);
for (uint32 j = 0; j != _walkboxes[i]._vertexCount; ++j) {
for (int j = 0; j < _walkboxes[i]._vertexCount; ++j) {
x = s->readFloatLE();
z = s->readFloatLE();
@ -115,13 +116,18 @@ bool Set::open(const Common::String &name) {
_effects->read(s.get(), framesCount);
_vm->_sliceRenderer->setSetEffects(_effects);
// _vm->_sliceRenderer->set_setColors(&this->colors);
_loaded = true;
for (int i = 0; i < _walkboxCount; ++i) {
this->setWalkboxStepSound(i, 0);
}
return true;
}
void Set::addObjectsToScene(SceneObjects* sceneObjects)
{
uint32 i;
for (i = 0; i < _objectCount; i++) {
void Set::addObjectsToScene(SceneObjects *sceneObjects) {
for (int i = 0; i < _objectCount; i++) {
sceneObjects->addObject(i + SCENE_OBJECTS_OBJECTS_OFFSET, &_objects[i]._bbox, _objects[i]._isClickable, _objects[i]._isObstacle, _objects[i]._unknown1, _objects[i]._isTarget);
}
}
@ -146,14 +152,12 @@ bool pointInWalkbox(float x, float z, const Walkbox &w)
}
*/
static
bool isXZInWalkbox(float x, float z, const Walkbox &walkbox) {
static bool isXZInWalkbox(float x, float z, const Walkbox &walkbox) {
int found = 0;
int i;
float lastX = walkbox._vertices[walkbox._vertexCount - 1].x;
float lastZ = walkbox._vertices[walkbox._vertexCount - 1].z;
for (i = 0; i < (int)walkbox._vertexCount; i++) {
for (int i = 0; i < walkbox._vertexCount; i++) {
float currentX = walkbox._vertices[i].x;
float currentZ = walkbox._vertices[i].z;
@ -171,7 +175,7 @@ float Set::getAltitudeAtXZ(float x, float z, bool *inWalkbox) {
float altitude = _walkboxes[0]._altitude;
*inWalkbox = false;
for (uint32 i = 0; i != _walkboxCount; ++i) {
for (int i = 0; i < _walkboxCount; ++i) {
const Walkbox &w = _walkboxes[i];
if (isXZInWalkbox(x, z, w)) {
@ -188,7 +192,7 @@ float Set::getAltitudeAtXZ(float x, float z, bool *inWalkbox) {
int Set::findWalkbox(float x, float z) {
int result = -1;
for (uint32 i = 0; i != _walkboxCount; ++i) {
for (int i = 0; i < _walkboxCount; ++i) {
const Walkbox &w = _walkboxes[i];
if (isXZInWalkbox(x, z, w)) {
@ -215,7 +219,7 @@ int Set::findObject(const char *objectName) {
}
bool Set::objectSetHotMouse(int objectId) {
if(!_objects || objectId < 0 || objectId >= (int)_objectCount) {
if (!_objects || objectId < 0 || objectId >= (int)_objectCount) {
return false;
}
@ -254,4 +258,71 @@ const char *Set::objectGetName(int objectId) {
return _objects[objectId]._name;
}
void Set::setWalkboxStepSound(int walkboxId, int stepSound) {
this->_walkboxStepSound[walkboxId] = stepSound;
}
void Set::setFoodstepSoundOverride(int soundId) {
_footstepSoundOverride = soundId;
}
void Set::resetFoodstepSoundOverride() {
_footstepSoundOverride = -1;
}
int Set::getWalkboxSoundWalkLeft(int walkboxId) {
int soundId;
if (this->_footstepSoundOverride >= 0) {
soundId = this->_footstepSoundOverride;
} else {
soundId = this->_walkboxStepSound[walkboxId];
}
if (soundId == 0) { //stone floor
return _vm->_rnd.getRandomNumberRng(160, 164);
}
if (soundId == 1) { //gravel floor
return _vm->_rnd.getRandomNumberRng(164, 170);
}
if (soundId == 2) { //wooden floor
return _vm->_rnd.getRandomNumberRng(476, 480);
}
if (soundId == 3) { //metal floor
return _vm->_rnd.getRandomNumberRng(466, 470);
}
return -1;
}
int Set::getWalkboxSoundWalkRight(int walkboxId) {
int soundId;
if (this->_footstepSoundOverride >= 0) {
soundId = this->_footstepSoundOverride;
} else {
soundId = this->_walkboxStepSound[walkboxId];
}
if (soundId == 0) { //stone floor
return _vm->_rnd.getRandomNumberRng(165, 169);
}
if (soundId == 1) { //gravel floor
return _vm->_rnd.getRandomNumberRng(169, 175);
}
if (soundId == 2) { //wooden floor
return _vm->_rnd.getRandomNumberRng(481, 485);
}
if (soundId == 3) { //metal floor
return _vm->_rnd.getRandomNumberRng(471, 475);
}
return -1;
}
int Set::getWalkboxSoundRunLeft(int walkboxId) {
return getWalkboxSoundWalkLeft(walkboxId);
}
int Set::getWalkboxSoundRunRight(int walkboxId) {
return getWalkboxSoundWalkRight(walkboxId);
}
} // End of namespace BladeRunner

View File

@ -49,15 +49,20 @@ struct Object {
struct Walkbox {
char _name[20];
float _altitude;
uint32 _vertexCount;
int _vertexCount;
Vector3 _vertices[8];
};
class Set {
#if _DEBUG
friend class BladeRunnerEngine;
#endif
BladeRunnerEngine *_vm;
uint32 _objectCount;
uint32 _walkboxCount;
bool _loaded;
int _objectCount;
int _walkboxCount;
Object *_objects;
Walkbox *_walkboxes;
int _walkboxStepSound[85];
@ -86,6 +91,15 @@ public:
void objectSetIsObstacle(int objectId, bool isObstacle);
void objectSetIsTarget(int objectId, bool isTarget);
const char *objectGetName(int objectId);
void setWalkboxStepSound(int walkboxId, int soundId);
void setFoodstepSoundOverride(int soundId);
void resetFoodstepSoundOverride();
int getWalkboxSoundWalkLeft(int walkboxId);
int getWalkboxSoundWalkRight(int walkboxId);
int getWalkboxSoundRunLeft(int walkboxId);
int getWalkboxSoundRunRight(int walkboxId);
};
} // End of namespace BladeRunner

View File

@ -49,7 +49,7 @@ bool View::read(Common::ReadStream *stream) {
void View::setFovX(float fovX) {
_fovX = fovX;
_viewportHalfWidth = 320.0f;
_viewportHalfWidth = 320.0f;
_viewportHalfHeight = 240.0f;
_viewportDistance = 320.0f / tanf(_fovX / 2.0f);
@ -60,17 +60,16 @@ void View::calculateSliceViewMatrix() {
m = m * rotationMatrixX(float(M_PI) / 2.0f);
Matrix4x3 a( -1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f);
Matrix4x3 a(-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f);
m = a * m;
_sliceViewMatrix = m;
}
void View::calculateCameraPosition()
{
void View::calculateCameraPosition() {
Matrix4x3 invertedMatrix = invertMatrix(_sliceViewMatrix);
_cameraPosition.x = invertedMatrix(0, 3);
@ -78,5 +77,12 @@ void View::calculateCameraPosition()
_cameraPosition.z = invertedMatrix(2, 3);
}
Vector2 View::calculateScreenPosition(Vector3 worldPosition) {
Vector3 viewPosition = _frameViewMatrix * worldPosition;
return Vector2(
this->_viewportHalfWidth - viewPosition.x / viewPosition.z * _viewportDistance,
this->_viewportHalfHeight - viewPosition.y / viewPosition.z * _viewportDistance
);
}
} // End of namespace BladeRunner

View File

@ -45,6 +45,7 @@ public:
float _viewportDistance;
bool read(Common::ReadStream *stream);
Vector2 calculateScreenPosition(Vector3 worldPosition);
private:
void setFovX(float fovX);