NEVERHOOD: Split sprites from their scenes in module 1600

This commit is contained in:
Filippos Karapetis 2013-10-05 14:52:48 +03:00
parent b963fcbfa8
commit b408b94bf1
9 changed files with 977 additions and 912 deletions

View File

@ -21,6 +21,7 @@ MODULE_OBJS = \
modules/module1400.o \
modules/module1500.o \
modules/module1600.o \
modules/module1600_sprites.o \
modules/module1700.o \
modules/module1700_sprites.o \
modules/module1800.o \

View File

@ -20,9 +20,10 @@
*
*/
#include "neverhood/modules/module1600.h"
#include "neverhood/gamemodule.h"
#include "neverhood/modules/module1200.h"
#include "neverhood/modules/module1600.h"
#include "neverhood/modules/module1600_sprites.h"
#include "neverhood/modules/module2200_sprites.h"
#include "neverhood/modules/module3000_sprites.h"
@ -184,825 +185,6 @@ void Module1600::updateScene() {
}
}
AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
: AnimatedSprite(vm, 1000), _parentScene(parentScene) {
createSurface(200, 556, 328);
_x = x;
_y = y;
_inMainArea = false;
_exitDirection = 0;
_currPointIndex = 0;
_hasAgainDestPoint = false;
_stepError = 0;
_hasAgainDestPointIndex = false;
_steps = 0;
_isBraking = false;
_yMoveTotalSteps = 0;
_isBusy = false;
_isIdle = false;
_isMoving = true;
_rectFlag = false;
_newDeltaXType = -1;
_soundCounter = 0;
_pathPoints = NULL;
_currMoveDirection = 0;
startAnimation(0xD4220027, 0, -1);
setDoDeltaX(getGlobalVar(V_CAR_DELTA_X));
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::handleMessage);
SetSpriteUpdate(NULL);
}
AsCommonCar::~AsCommonCar() {
if (_finalizeStateCb == AnimationCallback(&AsCommonCar::evTurnCarDone))
setGlobalVar(V_CAR_DELTA_X, !getGlobalVar(V_CAR_DELTA_X));
}
void AsCommonCar::setPathPoints(NPointArray *pathPoints) {
_pathPoints = pathPoints;
}
void AsCommonCar::update() {
if (_newDeltaXType >= 0) {
setDoDeltaX(_newDeltaXType);
_newDeltaXType = -1;
}
AnimatedSprite::update();
if (_hasAgainDestPoint && _yMoveTotalSteps == 0 && !_isBusy) {
_hasAgainDestPoint = false;
_hasAgainDestPointIndex = false;
sendPointMessage(this, 0x2004, _againDestPoint);
} else if (_hasAgainDestPointIndex && _yMoveTotalSteps == 0 && !_isBusy) {
_hasAgainDestPointIndex = false;
sendMessage(this, 0x2003, _againDestPointIndex);
}
updateMovement();
updateSound();
}
void AsCommonCar::upIdle() {
update();
if (++_idleCounter >= _idleCounterMax)
stIdleBlink();
updateSound();
}
uint32 AsCommonCar::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
switch (messageNum) {
case 0x1019:
SetSpriteUpdate(NULL);
break;
case 0x2002:
// Set the current position without moving
_currPointIndex = param.asInteger();
_stepError = 0;
_x = pathPoint(_currPointIndex).x;
_y = pathPoint(_currPointIndex).y;
break;
case 0x2003:
// Move to a point by its index
{
int newPointIndex = param.asInteger();
if (_yMoveTotalSteps <= 0 && !_isBusy) {
_destX = pathPoint(newPointIndex).x;
_destY = pathPoint(newPointIndex).y;
if (_currPointIndex < newPointIndex) {
moveToNextPoint();
} else if (_currPointIndex == newPointIndex && _stepError == 0) {
if (_currPointIndex == 0) {
_yMoveTotalSteps = 0;
sendMessage(_parentScene, 0x2005, 0);
} else if (_currPointIndex == (int)_pathPoints->size()) {
_yMoveTotalSteps = 0;
sendMessage(_parentScene, 0x2006, 0);
}
} else {
moveToPrevPoint();
}
} else {
_hasAgainDestPointIndex = true;
_againDestPointIndex = newPointIndex;
}
}
break;
case 0x2004:
// Move to the point closest to the parameter point
{
int minMatchIndex = -1;
int minMatchDistance, distance;
NPoint pt = param.asPoint();
if (_yMoveTotalSteps <= 0 && !_isBusy) {
// Check if we're already exiting (or something)
if ((pt.x <= 20 && _exitDirection == 1) ||
(pt.x >= 620 && _exitDirection == 3) ||
(pt.y <= 20 && _exitDirection == 2) ||
(pt.y >= 460 && _exitDirection == 4))
break;
_destX = pt.x;
_destY = pt.y;
minMatchDistance = calcDistance(_destX, _destY, _x, _y) + 1;
for (int i = _currPointIndex + 1; i < (int)_pathPoints->size(); i++) {
distance = calcDistance(_destX, _destY, pathPoint(i).x, pathPoint(i).y);
if (distance >= minMatchDistance)
break;
minMatchDistance = distance;
minMatchIndex = i;
}
for (int i = _currPointIndex; i >= 0; i--) {
distance = calcDistance(_destX, _destY, pathPoint(i).x, pathPoint(i).y);
if (distance >= minMatchDistance)
break;
minMatchDistance = distance;
minMatchIndex = i;
}
if (minMatchIndex == -1) {
if (_currPointIndex == 0)
moveToPrevPoint();
else
SetSpriteUpdate(NULL);
} else {
if (minMatchIndex > _currPointIndex)
moveToNextPoint();
else
moveToPrevPoint();
}
} else {
_hasAgainDestPoint = true;
_againDestPoint = pt;
}
}
break;
case 0x2007:
_yMoveTotalSteps = param.asInteger();
_steps = 0;
_isBraking = false;
_lastDistance = 640;
SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint);
break;
case 0x2008:
_yMoveTotalSteps = param.asInteger();
_steps = 0;
_isBraking = false;
_lastDistance = 640;
SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint);
break;
case 0x2009:
stEnterCar();
break;
case 0x200A:
stLeaveCar();
break;
case 0x200E:
stTurnCar();
break;
case 0x200F:
stCarAtHome();
_newDeltaXType = param.asInteger();
break;
}
return messageResult;
}
uint32 AsCommonCar::hmAnimation(int messageNum, const MessageParam &param, Entity *sender) {
uint32 messageResult = AsCommonCar::handleMessage(messageNum, param, sender);
switch (messageNum) {
case 0x100D:
if (_isBusy && param.asInteger() == 0x025424A2)
gotoNextState();
break;
case 0x3002:
gotoNextState();
break;
}
return messageResult;
}
uint32 AsCommonCar::hmLeaveCar(int messageNum, const MessageParam &param, Entity *sender) {
switch (messageNum) {
case 0x2009:
stEnterCar();
break;
case 0x3002:
sendMessage(_parentScene, 0x200A, 0);
SetMessageHandler(&AsCommonCar::handleMessage);
break;
}
return 0;
}
void AsCommonCar::stCarAtHome() {
bool doDeltaX = _doDeltaX;
SetSpriteUpdate(NULL);
_hasAgainDestPoint = false;
_hasAgainDestPointIndex = false;
_isBraking = false;
_isBusy = false;
_isIdle = false;
_isMoving = false;
_rectFlag = false;
NextState(&AsCommonCar::stLeanForwardIdle);
startAnimation(0x35698F78, 0, -1);
setDoDeltaX(doDeltaX ? 1 : 0);
_currMoveDirection = 0;
_newMoveDirection = 0;
_steps = 0;
_idleCounter = 0;
_idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
SetUpdateHandler(&AsCommonCar::upIdle);
SetMessageHandler(&AsCommonCar::handleMessage);
FinalizeState(&AsCommonCar::evIdleDone);
}
void AsCommonCar::updateTurnMovement() {
if (_turnMoveStatus == 1) {
_lastDistance = 640;
_isIdle = false;
_isBraking = false;
SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint);
} else if (_turnMoveStatus == 2) {
_lastDistance = 640;
_isIdle = false;
_isBraking = false;
SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint);
}
}
void AsCommonCar::updateMovement() {
if (_isBraking && !_isIdle && !_isBusy) {
gotoNextState();
_isMoving = false;
_isIdle = true;
startAnimation(0x192ADD30, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stLeanForwardIdle);
} else if (!_isBraking && _steps && _isIdle) {
gotoNextState();
_isIdle = false;
startAnimation(0x9966B138, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stUpdateMoveDirection);
} else if (_newMoveDirection != _currMoveDirection && _isMoving && !_isBusy) {
gotoNextState();
_currMoveDirection = _newMoveDirection;
stUpdateMoveDirection();
}
}
void AsCommonCar::stEnterCar() {
startAnimation(0xA86A9538, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stLeanForwardIdle);
}
void AsCommonCar::stLeaveCar() {
startAnimation(0xA86A9538, -1, -1);
_playBackwards = true;
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmLeaveCar);
}
void AsCommonCar::stLeanForwardIdle() {
startAnimation(0x35698F78, 0, -1);
_currMoveDirection = 0;
_newMoveDirection = 0;
_steps = 0;
_idleCounter = 0;
_idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
SetUpdateHandler(&AsCommonCar::upIdle);
SetMessageHandler(&AsCommonCar::handleMessage);
FinalizeState(&AsCommonCar::evIdleDone);
}
void AsCommonCar::evIdleDone() {
SetUpdateHandler(&AsCommonCar::update);
}
void AsCommonCar::stIdleBlink() {
startAnimation(0xB579A77C, 0, -1);
_idleCounter = 0;
_idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stLeanForwardIdle);
}
void AsCommonCar::stUpdateMoveDirection() {
_isMoving = true;
if (_currMoveDirection == 1)
startAnimation(0xD4AA03A4, 0, -1);
else if (_currMoveDirection == 3)
startAnimation(0xD00A1364, 0, -1);
else if ((_currMoveDirection == 2 && _doDeltaX) || (_currMoveDirection == 4 && !_doDeltaX))
stTurnCar();
else
startAnimation(0xD4220027, 0, -1);
setGlobalVar(V_CAR_DELTA_X, _doDeltaX ? 1 : 0);
}
void AsCommonCar::moveToNextPoint() {
if (_currPointIndex >= (int)_pathPoints->size() - 1) {
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2006, 0);
} else {
NPoint nextPt = pathPoint(_currPointIndex + 1);
NPoint currPt = pathPoint(_currPointIndex);
if (ABS(nextPt.y - currPt.y) <= ABS(nextPt.x - currPt.x) &&
((_currMoveDirection == 2 && nextPt.x < currPt.x) ||
(_currMoveDirection == 4 && nextPt.x >= currPt.x))) {
if (_currMoveDirection == 2)
_currMoveDirection = 4;
else if (_currMoveDirection == 4)
_currMoveDirection = 2;
if (_isIdle)
stTurnCarMoveToNextPoint();
else
stBrakeMoveToNextPoint();
} else {
if (_steps == 0) {
gotoNextState();
_isIdle = false;
startAnimation(0x9966B138, 0, -1);
SetMessageHandler(&AsCommonCar::hmAnimation);
SetUpdateHandler(&AsCommonCar::update);
NextState(&AsCommonCar::stUpdateMoveDirection);
}
_isBraking = false;
SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint);
_lastDistance = 640;
}
}
}
void AsCommonCar::stBrakeMoveToNextPoint() {
gotoNextState();
_isBusy = true;
_isBraking = true;
startAnimation(0x192ADD30, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stTurnCarMoveToNextPoint);
}
void AsCommonCar::stTurnCar() {
// Turn to left/right #1
gotoNextState();
_isBusy = true;
startAnimation(0xF46A0324, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
FinalizeState(&AsCommonCar::evTurnCarDone);
_turnMoveStatus = 0;
updateTurnMovement();
}
void AsCommonCar::stTurnCarMoveToNextPoint() {
// Turn to left/right #2
gotoNextState();
_isBusy = true;
startAnimation(0xF46A0324, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
FinalizeState(&AsCommonCar::evTurnCarDone);
_turnMoveStatus = 1;
updateTurnMovement();
}
void AsCommonCar::stTurnCarMoveToPrevPoint() {
// Turn to left/right #3
FinalizeState(NULL);
_isBusy = true;
startAnimation(0xF46A0324, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
FinalizeState(&AsCommonCar::evTurnCarDone);
_turnMoveStatus = 2;
updateTurnMovement();
}
void AsCommonCar::moveToPrevPoint() {
if (_currPointIndex == 0 && _stepError == 0) {
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2005, 0);
} else {
NPoint prevPt;
NPoint currPt;
if (_stepError == 0) {
prevPt = pathPoint(_currPointIndex - 1);
currPt = pathPoint(_currPointIndex);
} else {
prevPt = pathPoint(_currPointIndex);
currPt = pathPoint(_currPointIndex + 1);
}
if (ABS(prevPt.y - currPt.y) <= ABS(prevPt.x - currPt.x) &&
((_currMoveDirection == 2 && prevPt.x < currPt.x) ||
(_currMoveDirection == 4 && prevPt.x >= currPt.x))) {
if (_currMoveDirection == 2)
_currMoveDirection = 4;
else if (_currMoveDirection == 4)
_currMoveDirection = 2;
if (_isIdle)
stTurnCarMoveToPrevPoint();
else
stBrakeMoveToPrevPoint();
} else {
if (_steps == 0) {
gotoNextState();
_isIdle = false;
startAnimation(0x9966B138, 0, -1);
SetMessageHandler(&AsCommonCar::hmAnimation);
SetUpdateHandler(&AsCommonCar::update);
NextState(&AsCommonCar::stUpdateMoveDirection);
}
_isBraking = false;
SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint);
_lastDistance = 640;
}
}
}
void AsCommonCar::stBrakeMoveToPrevPoint() {
FinalizeState(NULL);
_isBusy = true;
_isBraking = true;
startAnimation(0x192ADD30, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stTurnCarMoveToPrevPoint);
}
void AsCommonCar::evTurnCarDone() {
_isBusy = false;
setDoDeltaX(2);
_newMoveDirection = 0;
stUpdateMoveDirection();
}
void AsCommonCar::suMoveToNextPoint() {
int16 newX = _x, newY = _y;
if (_currPointIndex >= (int)_pathPoints->size()) {
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2006, 0);
return;
}
if (_isBraking) {
if (_steps <= 0) {
sendMessage(this, 0x1019, 0);
return;
} else
_steps--;
} else if (_steps < 11)
_steps++;
bool firstTime = true;
_ySteps = _steps;
int stepsCtr = _steps;
while (stepsCtr > 0) {
NPoint pt1;
NPoint pt2 = pathPoint(_currPointIndex);
if (_currPointIndex + 1 >= (int)_pathPoints->size())
pt1 = pathPoint(0);
else
pt1 = pathPoint(_currPointIndex + 1);
int16 deltaX = ABS(pt1.x - pt2.x);
int16 deltaY = ABS(pt1.y - pt2.y);
if (deltaX >= deltaY) {
_newMoveDirection = 2;
if (pt1.x < pt2.x)
_newMoveDirection = 4;
if (stepsCtr + _stepError >= deltaX) {
stepsCtr -= deltaX;
stepsCtr += _stepError;
_stepError = 0;
_currPointIndex++;
if (_currPointIndex == (int)_pathPoints->size() - 1)
stepsCtr = 0;
newX = pathPoint(_currPointIndex).x;
newY = pathPoint(_currPointIndex).y;
} else {
_stepError += stepsCtr;
if (pt1.x >= pt2.x)
newX += stepsCtr;
else
newX -= stepsCtr;
if (pt1.y >= pt2.y)
newY = pt2.y + (deltaY * _stepError) / deltaX;
else
newY = pt2.y - (deltaY * _stepError) / deltaX;
stepsCtr = 0;
}
} else {
_newMoveDirection = 3;
if (pt1.y < pt2.y)
_newMoveDirection = 1;
if (firstTime) {
if (pt1.y >= pt2.y)
stepsCtr += 7;
else {
stepsCtr -= 4;
if (stepsCtr < 0)
stepsCtr = 0;
}
_ySteps = stepsCtr;
}
if (stepsCtr + _stepError >= deltaY) {
stepsCtr -= deltaY;
stepsCtr += _stepError;
_stepError = 0;
_currPointIndex++;
if (_currPointIndex == (int)_pathPoints->size() - 1)
stepsCtr = 0;
newX = pathPoint(_currPointIndex).x;
newY = pathPoint(_currPointIndex).y;
} else {
_stepError += stepsCtr;
if (pt1.x >= pt2.x)
newX = pt2.x + (deltaX * _stepError) / deltaY;
else
newX = pt2.x - (deltaX * _stepError) / deltaY;
if (pt1.y >= pt2.y)
newY += stepsCtr;
else
newY -= stepsCtr;
stepsCtr = 0;
}
}
firstTime = false;
}
if (_yMoveTotalSteps != 0) {
_x = newX;
_y = newY;
_yMoveTotalSteps -= _ySteps;
if (_yMoveTotalSteps <= 0) {
_isBraking = true;
_yMoveTotalSteps = 0;
}
} else {
int distance = calcDistance(_destX, _destY, _x, _y);
_x = newX;
_y = newY;
if (newX > 20 && newX < 620 && newY > 20 && newY < 460) {
_exitDirection = 0;
_inMainArea = true;
} else if (_inMainArea) {
_destX = pathPoint(_pathPoints->size() - 1).x;
_destY = pathPoint(_pathPoints->size() - 1).y;
_inMainArea = false;
if (_x <= 20)
_exitDirection = 1;
else if (_x >= 620)
_exitDirection = 3;
else if (_y <= 20)
_exitDirection = 2;
else if (_y >= 460)
_exitDirection = 4;
if (_exitDirection != 0 && _isBraking) {
_isBraking = false;
_steps = 11;
}
}
if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) ||
(_exitDirection == 0 && _lastDistance + 20 < distance))
_isBraking = true;
if (distance < _lastDistance)
_lastDistance = distance;
if (_currPointIndex == (int)_pathPoints->size() - 1) {
_isBraking = true;
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2006, 0);
}
}
}
void AsCommonCar::suMoveToPrevPoint() {
int16 newX = _x, newY = _y;
if (_currPointIndex == 0 && _stepError == 0) {
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2005, 0);
return;
}
if (_isBraking) {
if (_steps <= 0) {
sendMessage(this, 0x1019, 0);
return;
} else
_steps--;
} else if (_steps < 11)
_steps++;
bool firstTime = true;
_ySteps = _steps;
int stepsCtr = _steps;
while (stepsCtr > 0) {
if (_stepError == 0)
_currPointIndex--;
NPoint pt1;
NPoint pt2 = pathPoint(_currPointIndex);
if (_currPointIndex + 1 >= (int)_pathPoints->size())
pt1 = pathPoint(0);
else
pt1 = pathPoint(_currPointIndex + 1);
int16 deltaX = ABS(pt1.x - pt2.x);
int16 deltaY = ABS(pt1.y - pt2.y);
if (deltaX >= deltaY) {
_newMoveDirection = 4;
if (pt1.x < pt2.x)
_newMoveDirection = 2;
if (_stepError == 0)
_stepError = deltaX;
if (stepsCtr > _stepError) {
stepsCtr -= _stepError;
_stepError = 0;
if (_currPointIndex == 0)
stepsCtr = 0;
newX = pathPoint(_currPointIndex).x;
newY = pathPoint(_currPointIndex).y;
} else {
_stepError -= stepsCtr;
if (pt1.x >= pt2.x)
newX -= stepsCtr;
else
newX += stepsCtr;
if (pt1.y >= pt2.y)
newY = pt2.y + (deltaY * _stepError) / deltaX;
else
newY = pt2.y - (deltaY * _stepError) / deltaX;
stepsCtr = 0;
}
} else {
_newMoveDirection = 1;
if (pt1.y < pt2.y)
_newMoveDirection = 3;
if (firstTime) {
if (pt1.y >= pt2.y) {
stepsCtr -= 4;
if (stepsCtr < 0)
stepsCtr = 0;
} else {
stepsCtr += 7;
}
_ySteps = stepsCtr;
}
if (_stepError == 0)
_stepError = deltaY;
if (stepsCtr > _stepError) {
stepsCtr -= _stepError;
_stepError = 0;
if (_currPointIndex == 0)
stepsCtr = 0;
newX = pathPoint(_currPointIndex).x;
newY = pathPoint(_currPointIndex).y;
} else {
_stepError -= stepsCtr;
if (pt1.x >= pt2.x)
newX = pt2.x + (deltaX * _stepError) / deltaY;
else
newX = pt2.x - (deltaX * _stepError) / deltaY;
if (pt1.y >= pt2.y)
newY -= stepsCtr;
else
newY += stepsCtr;
stepsCtr = 0;
}
}
firstTime = false;
}
if (_yMoveTotalSteps != 0) {
_x = newX;
_y = newY;
_yMoveTotalSteps -= _ySteps;
if (_yMoveTotalSteps <= 0) {
_isBraking = true;
_yMoveTotalSteps = 0;
}
} else {
int distance = calcDistance(_destX, _destY, _x, _y);
_x = newX;
_y = newY;
if (newX > 20 && newX < 620 && newY > 20 && newY < 460) {
_exitDirection = 0;
_inMainArea = true;
} else if (_inMainArea) {
_destX = pathPoint(0).x;
_destY = pathPoint(0).y;
_inMainArea = false;
if (_x <= 20)
_exitDirection = 1;
else if (_x >= 620)
_exitDirection = 3;
else if (_y <= 20)
_exitDirection = 2;
else if (_y >= 460)
_exitDirection = 4;
if (_exitDirection != 0 && _isBraking) {
_isBraking = false;
_steps = 11;
}
}
if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) ||
(_exitDirection == 0 && _lastDistance + 20 < distance))
_isBraking = true;
if (distance < _lastDistance)
_lastDistance = distance;
if (_currPointIndex == 0 && _stepError == 0) {
_isBraking = true;
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2005, 0);
}
}
}
void AsCommonCar::updateSound() {
int maxSoundCounter = 0;
_soundCounter++;
if (_steps != 0 && !_isIdle) {
if (_currMoveDirection == 1)
maxSoundCounter = 18 - _steps;
else if (_currMoveDirection == 3) {
maxSoundCounter = 5 - _steps;
if (maxSoundCounter < 1)
maxSoundCounter = 1;
} else
maxSoundCounter = 14 - _steps;
} else
maxSoundCounter = 21;
if (_soundCounter >= maxSoundCounter) {
sendMessage(_parentScene, 0x200D, 0);
_soundCounter = 0;
}
}
AsCommonIdleCarLower::AsCommonIdleCarLower(NeverhoodEngine *vm, int16 x, int16 y)
: AnimatedSprite(vm, 0x1209E09F, 1100, x, y) {
setDoDeltaX(1);
startAnimation(0x1209E09F, 1, -1);
_newStickFrameIndex = 1;
}
AsCommonIdleCarFull::AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y)
: AnimatedSprite(vm, 0x1209E09F, 100, x, y) {
setDoDeltaX(1);
_newStickFrameIndex = 0;
}
AsCommonCarConnector::AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar)
: AnimatedSprite(vm, 1100), _asCar(asCar) {
createSurface1(0x60281C10, 150);
startAnimation(0x60281C10, -1, -1);
_newStickFrameIndex = STICK_LAST_FRAME;
SetUpdateHandler(&AsCommonCarConnector::update);
}
void AsCommonCarConnector::update() {
_x = _asCar->getX();
_y = _asCar->getY();
AnimatedSprite::update();
}
void Tracks::findTrackPoint(NPoint pt, int &minMatchTrackIndex, int &minMatchDistance,
DataResource &dataResource) {
const uint trackCount = size();
minMatchTrackIndex = -1;
minMatchDistance = 640;
for (uint trackIndex = 0; trackIndex < trackCount; trackIndex++) {
NPointArray *pointList = dataResource.getPointArray((*this)[trackIndex]->trackPointsName);
for (uint pointIndex = 0; pointIndex < pointList->size(); pointIndex++) {
NPoint testPt = (*pointList)[pointIndex];
int distance = calcDistance(testPt.x, testPt.y, pt.x, pt.y);
if (distance < minMatchDistance) {
minMatchTrackIndex = trackIndex;
minMatchDistance = distance;
}
}
}
}
Scene1608::Scene1608(NeverhoodEngine *vm, Module *parentModule, int which)
: Scene(vm, parentModule), _asCar(NULL), _countdown1(0) {

View File

@ -26,12 +26,9 @@
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
#include "neverhood/console.h"
namespace Neverhood {
// Module1600
class Module1600 : public Module {
public:
Module1600(NeverhoodEngine *vm, Module *parentModule, int which);
@ -42,90 +39,7 @@ protected:
void updateScene();
};
class AsCommonCar : public AnimatedSprite {
public:
AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y);
~AsCommonCar();
void setPathPoints(NPointArray *pathPoints);
protected:
Scene *_parentScene;
NPointArray *_pathPoints;
int _newMoveDirection;
int _currMoveDirection;
int _exitDirection;
int _currPointIndex;
bool _hasAgainDestPoint;
NPoint _againDestPoint;
bool _hasAgainDestPointIndex;
int _againDestPointIndex;
bool _inMainArea;
bool _isBraking;
bool _isBusy;
bool _isIdle;
bool _isMoving;
bool _rectFlag;
int _idleCounter;
int _idleCounterMax;
int _steps;
int _stepError;
int _lastDistance;
int _yMoveTotalSteps;
int _ySteps;
int _newDeltaXType;
int _soundCounter;
int _turnMoveStatus;
int16 _destX, _destY;
NPoint pathPoint(uint index) { return (*_pathPoints)[index]; }
void update();
void upIdle();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmAnimation(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmLeaveCar(int messageNum, const MessageParam &param, Entity *sender);
void stCarAtHome();
void updateTurnMovement();
void updateMovement();
void stEnterCar();
void stLeaveCar();
void stLeanForwardIdle();
void evIdleDone();
void stIdleBlink();
void stUpdateMoveDirection();
void stTurnCar();
void moveToNextPoint();
void stBrakeMoveToNextPoint();
void stTurnCarMoveToNextPoint();
void moveToPrevPoint();
void stBrakeMoveToPrevPoint();
void stTurnCarMoveToPrevPoint();
void evTurnCarDone();
void suMoveToNextPoint();
void suMoveToPrevPoint();
void updateSound();
};
class AsCommonIdleCarLower : public AnimatedSprite {
public:
AsCommonIdleCarLower(NeverhoodEngine *vm, int16 x, int16 y);
};
class AsCommonIdleCarFull : public AnimatedSprite {
public:
AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y);
};
class AsCommonCarConnector : public AnimatedSprite {
public:
AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar);
protected:
AsCommonCar *_asCar;
void update();
};
class Tracks : public Common::Array<TrackInfo*> {
public:
void findTrackPoint(NPoint pt, int &minMatchTrackIndex, int &minMatchDistance,
DataResource &dataResource);
};
class AsCommonCar;
class Scene1608 : public Scene {
public:

View File

@ -0,0 +1,850 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "neverhood/gamemodule.h"
#include "neverhood/modules/module1200.h"
#include "neverhood/modules/module1600_sprites.h"
#include "neverhood/modules/module2200_sprites.h"
#include "neverhood/modules/module3000_sprites.h"
namespace Neverhood {
AsCommonCar::AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
: AnimatedSprite(vm, 1000), _parentScene(parentScene) {
createSurface(200, 556, 328);
_x = x;
_y = y;
_inMainArea = false;
_exitDirection = 0;
_currPointIndex = 0;
_hasAgainDestPoint = false;
_stepError = 0;
_hasAgainDestPointIndex = false;
_steps = 0;
_isBraking = false;
_yMoveTotalSteps = 0;
_isBusy = false;
_isIdle = false;
_isMoving = true;
_rectFlag = false;
_newDeltaXType = -1;
_soundCounter = 0;
_pathPoints = NULL;
_currMoveDirection = 0;
startAnimation(0xD4220027, 0, -1);
setDoDeltaX(getGlobalVar(V_CAR_DELTA_X));
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::handleMessage);
SetSpriteUpdate(NULL);
}
AsCommonCar::~AsCommonCar() {
if (_finalizeStateCb == AnimationCallback(&AsCommonCar::evTurnCarDone))
setGlobalVar(V_CAR_DELTA_X, !getGlobalVar(V_CAR_DELTA_X));
}
void AsCommonCar::setPathPoints(NPointArray *pathPoints) {
_pathPoints = pathPoints;
}
void AsCommonCar::update() {
if (_newDeltaXType >= 0) {
setDoDeltaX(_newDeltaXType);
_newDeltaXType = -1;
}
AnimatedSprite::update();
if (_hasAgainDestPoint && _yMoveTotalSteps == 0 && !_isBusy) {
_hasAgainDestPoint = false;
_hasAgainDestPointIndex = false;
sendPointMessage(this, 0x2004, _againDestPoint);
} else if (_hasAgainDestPointIndex && _yMoveTotalSteps == 0 && !_isBusy) {
_hasAgainDestPointIndex = false;
sendMessage(this, 0x2003, _againDestPointIndex);
}
updateMovement();
updateSound();
}
void AsCommonCar::upIdle() {
update();
if (++_idleCounter >= _idleCounterMax)
stIdleBlink();
updateSound();
}
uint32 AsCommonCar::handleMessage(int messageNum, const MessageParam &param, Entity *sender) {
uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
switch (messageNum) {
case 0x1019:
SetSpriteUpdate(NULL);
break;
case 0x2002:
// Set the current position without moving
_currPointIndex = param.asInteger();
_stepError = 0;
_x = pathPoint(_currPointIndex).x;
_y = pathPoint(_currPointIndex).y;
break;
case 0x2003:
// Move to a point by its index
{
int newPointIndex = param.asInteger();
if (_yMoveTotalSteps <= 0 && !_isBusy) {
_destX = pathPoint(newPointIndex).x;
_destY = pathPoint(newPointIndex).y;
if (_currPointIndex < newPointIndex) {
moveToNextPoint();
} else if (_currPointIndex == newPointIndex && _stepError == 0) {
if (_currPointIndex == 0) {
_yMoveTotalSteps = 0;
sendMessage(_parentScene, 0x2005, 0);
} else if (_currPointIndex == (int)_pathPoints->size()) {
_yMoveTotalSteps = 0;
sendMessage(_parentScene, 0x2006, 0);
}
} else {
moveToPrevPoint();
}
} else {
_hasAgainDestPointIndex = true;
_againDestPointIndex = newPointIndex;
}
}
break;
case 0x2004:
// Move to the point closest to the parameter point
{
int minMatchIndex = -1;
int minMatchDistance, distance;
NPoint pt = param.asPoint();
if (_yMoveTotalSteps <= 0 && !_isBusy) {
// Check if we're already exiting (or something)
if ((pt.x <= 20 && _exitDirection == 1) ||
(pt.x >= 620 && _exitDirection == 3) ||
(pt.y <= 20 && _exitDirection == 2) ||
(pt.y >= 460 && _exitDirection == 4))
break;
_destX = pt.x;
_destY = pt.y;
minMatchDistance = calcDistance(_destX, _destY, _x, _y) + 1;
for (int i = _currPointIndex + 1; i < (int)_pathPoints->size(); i++) {
distance = calcDistance(_destX, _destY, pathPoint(i).x, pathPoint(i).y);
if (distance >= minMatchDistance)
break;
minMatchDistance = distance;
minMatchIndex = i;
}
for (int i = _currPointIndex; i >= 0; i--) {
distance = calcDistance(_destX, _destY, pathPoint(i).x, pathPoint(i).y);
if (distance >= minMatchDistance)
break;
minMatchDistance = distance;
minMatchIndex = i;
}
if (minMatchIndex == -1) {
if (_currPointIndex == 0)
moveToPrevPoint();
else
SetSpriteUpdate(NULL);
} else {
if (minMatchIndex > _currPointIndex)
moveToNextPoint();
else
moveToPrevPoint();
}
} else {
_hasAgainDestPoint = true;
_againDestPoint = pt;
}
}
break;
case 0x2007:
_yMoveTotalSteps = param.asInteger();
_steps = 0;
_isBraking = false;
_lastDistance = 640;
SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint);
break;
case 0x2008:
_yMoveTotalSteps = param.asInteger();
_steps = 0;
_isBraking = false;
_lastDistance = 640;
SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint);
break;
case 0x2009:
stEnterCar();
break;
case 0x200A:
stLeaveCar();
break;
case 0x200E:
stTurnCar();
break;
case 0x200F:
stCarAtHome();
_newDeltaXType = param.asInteger();
break;
}
return messageResult;
}
uint32 AsCommonCar::hmAnimation(int messageNum, const MessageParam &param, Entity *sender) {
uint32 messageResult = AsCommonCar::handleMessage(messageNum, param, sender);
switch (messageNum) {
case 0x100D:
if (_isBusy && param.asInteger() == 0x025424A2)
gotoNextState();
break;
case 0x3002:
gotoNextState();
break;
}
return messageResult;
}
uint32 AsCommonCar::hmLeaveCar(int messageNum, const MessageParam &param, Entity *sender) {
switch (messageNum) {
case 0x2009:
stEnterCar();
break;
case 0x3002:
sendMessage(_parentScene, 0x200A, 0);
SetMessageHandler(&AsCommonCar::handleMessage);
break;
}
return 0;
}
void AsCommonCar::stCarAtHome() {
bool doDeltaX = _doDeltaX;
SetSpriteUpdate(NULL);
_hasAgainDestPoint = false;
_hasAgainDestPointIndex = false;
_isBraking = false;
_isBusy = false;
_isIdle = false;
_isMoving = false;
_rectFlag = false;
NextState(&AsCommonCar::stLeanForwardIdle);
startAnimation(0x35698F78, 0, -1);
setDoDeltaX(doDeltaX ? 1 : 0);
_currMoveDirection = 0;
_newMoveDirection = 0;
_steps = 0;
_idleCounter = 0;
_idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
SetUpdateHandler(&AsCommonCar::upIdle);
SetMessageHandler(&AsCommonCar::handleMessage);
FinalizeState(&AsCommonCar::evIdleDone);
}
void AsCommonCar::updateTurnMovement() {
if (_turnMoveStatus == 1) {
_lastDistance = 640;
_isIdle = false;
_isBraking = false;
SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint);
} else if (_turnMoveStatus == 2) {
_lastDistance = 640;
_isIdle = false;
_isBraking = false;
SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint);
}
}
void AsCommonCar::updateMovement() {
if (_isBraking && !_isIdle && !_isBusy) {
gotoNextState();
_isMoving = false;
_isIdle = true;
startAnimation(0x192ADD30, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stLeanForwardIdle);
} else if (!_isBraking && _steps && _isIdle) {
gotoNextState();
_isIdle = false;
startAnimation(0x9966B138, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stUpdateMoveDirection);
} else if (_newMoveDirection != _currMoveDirection && _isMoving && !_isBusy) {
gotoNextState();
_currMoveDirection = _newMoveDirection;
stUpdateMoveDirection();
}
}
void AsCommonCar::stEnterCar() {
startAnimation(0xA86A9538, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stLeanForwardIdle);
}
void AsCommonCar::stLeaveCar() {
startAnimation(0xA86A9538, -1, -1);
_playBackwards = true;
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmLeaveCar);
}
void AsCommonCar::stLeanForwardIdle() {
startAnimation(0x35698F78, 0, -1);
_currMoveDirection = 0;
_newMoveDirection = 0;
_steps = 0;
_idleCounter = 0;
_idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
SetUpdateHandler(&AsCommonCar::upIdle);
SetMessageHandler(&AsCommonCar::handleMessage);
FinalizeState(&AsCommonCar::evIdleDone);
}
void AsCommonCar::evIdleDone() {
SetUpdateHandler(&AsCommonCar::update);
}
void AsCommonCar::stIdleBlink() {
startAnimation(0xB579A77C, 0, -1);
_idleCounter = 0;
_idleCounterMax = _vm->_rnd->getRandomNumber(64 - 1) + 24;
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stLeanForwardIdle);
}
void AsCommonCar::stUpdateMoveDirection() {
_isMoving = true;
if (_currMoveDirection == 1)
startAnimation(0xD4AA03A4, 0, -1);
else if (_currMoveDirection == 3)
startAnimation(0xD00A1364, 0, -1);
else if ((_currMoveDirection == 2 && _doDeltaX) || (_currMoveDirection == 4 && !_doDeltaX))
stTurnCar();
else
startAnimation(0xD4220027, 0, -1);
setGlobalVar(V_CAR_DELTA_X, _doDeltaX ? 1 : 0);
}
void AsCommonCar::moveToNextPoint() {
if (_currPointIndex >= (int)_pathPoints->size() - 1) {
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2006, 0);
} else {
NPoint nextPt = pathPoint(_currPointIndex + 1);
NPoint currPt = pathPoint(_currPointIndex);
if (ABS(nextPt.y - currPt.y) <= ABS(nextPt.x - currPt.x) &&
((_currMoveDirection == 2 && nextPt.x < currPt.x) ||
(_currMoveDirection == 4 && nextPt.x >= currPt.x))) {
if (_currMoveDirection == 2)
_currMoveDirection = 4;
else if (_currMoveDirection == 4)
_currMoveDirection = 2;
if (_isIdle)
stTurnCarMoveToNextPoint();
else
stBrakeMoveToNextPoint();
} else {
if (_steps == 0) {
gotoNextState();
_isIdle = false;
startAnimation(0x9966B138, 0, -1);
SetMessageHandler(&AsCommonCar::hmAnimation);
SetUpdateHandler(&AsCommonCar::update);
NextState(&AsCommonCar::stUpdateMoveDirection);
}
_isBraking = false;
SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint);
_lastDistance = 640;
}
}
}
void AsCommonCar::stBrakeMoveToNextPoint() {
gotoNextState();
_isBusy = true;
_isBraking = true;
startAnimation(0x192ADD30, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stTurnCarMoveToNextPoint);
}
void AsCommonCar::stTurnCar() {
// Turn to left/right #1
gotoNextState();
_isBusy = true;
startAnimation(0xF46A0324, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
FinalizeState(&AsCommonCar::evTurnCarDone);
_turnMoveStatus = 0;
updateTurnMovement();
}
void AsCommonCar::stTurnCarMoveToNextPoint() {
// Turn to left/right #2
gotoNextState();
_isBusy = true;
startAnimation(0xF46A0324, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
FinalizeState(&AsCommonCar::evTurnCarDone);
_turnMoveStatus = 1;
updateTurnMovement();
}
void AsCommonCar::stTurnCarMoveToPrevPoint() {
// Turn to left/right #3
FinalizeState(NULL);
_isBusy = true;
startAnimation(0xF46A0324, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
FinalizeState(&AsCommonCar::evTurnCarDone);
_turnMoveStatus = 2;
updateTurnMovement();
}
void AsCommonCar::moveToPrevPoint() {
if (_currPointIndex == 0 && _stepError == 0) {
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2005, 0);
} else {
NPoint prevPt;
NPoint currPt;
if (_stepError == 0) {
prevPt = pathPoint(_currPointIndex - 1);
currPt = pathPoint(_currPointIndex);
} else {
prevPt = pathPoint(_currPointIndex);
currPt = pathPoint(_currPointIndex + 1);
}
if (ABS(prevPt.y - currPt.y) <= ABS(prevPt.x - currPt.x) &&
((_currMoveDirection == 2 && prevPt.x < currPt.x) ||
(_currMoveDirection == 4 && prevPt.x >= currPt.x))) {
if (_currMoveDirection == 2)
_currMoveDirection = 4;
else if (_currMoveDirection == 4)
_currMoveDirection = 2;
if (_isIdle)
stTurnCarMoveToPrevPoint();
else
stBrakeMoveToPrevPoint();
} else {
if (_steps == 0) {
gotoNextState();
_isIdle = false;
startAnimation(0x9966B138, 0, -1);
SetMessageHandler(&AsCommonCar::hmAnimation);
SetUpdateHandler(&AsCommonCar::update);
NextState(&AsCommonCar::stUpdateMoveDirection);
}
_isBraking = false;
SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint);
_lastDistance = 640;
}
}
}
void AsCommonCar::stBrakeMoveToPrevPoint() {
FinalizeState(NULL);
_isBusy = true;
_isBraking = true;
startAnimation(0x192ADD30, 0, -1);
SetUpdateHandler(&AsCommonCar::update);
SetMessageHandler(&AsCommonCar::hmAnimation);
NextState(&AsCommonCar::stTurnCarMoveToPrevPoint);
}
void AsCommonCar::evTurnCarDone() {
_isBusy = false;
setDoDeltaX(2);
_newMoveDirection = 0;
stUpdateMoveDirection();
}
void AsCommonCar::suMoveToNextPoint() {
int16 newX = _x, newY = _y;
if (_currPointIndex >= (int)_pathPoints->size()) {
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2006, 0);
return;
}
if (_isBraking) {
if (_steps <= 0) {
sendMessage(this, 0x1019, 0);
return;
} else
_steps--;
} else if (_steps < 11)
_steps++;
bool firstTime = true;
_ySteps = _steps;
int stepsCtr = _steps;
while (stepsCtr > 0) {
NPoint pt1;
NPoint pt2 = pathPoint(_currPointIndex);
if (_currPointIndex + 1 >= (int)_pathPoints->size())
pt1 = pathPoint(0);
else
pt1 = pathPoint(_currPointIndex + 1);
int16 deltaX = ABS(pt1.x - pt2.x);
int16 deltaY = ABS(pt1.y - pt2.y);
if (deltaX >= deltaY) {
_newMoveDirection = 2;
if (pt1.x < pt2.x)
_newMoveDirection = 4;
if (stepsCtr + _stepError >= deltaX) {
stepsCtr -= deltaX;
stepsCtr += _stepError;
_stepError = 0;
_currPointIndex++;
if (_currPointIndex == (int)_pathPoints->size() - 1)
stepsCtr = 0;
newX = pathPoint(_currPointIndex).x;
newY = pathPoint(_currPointIndex).y;
} else {
_stepError += stepsCtr;
if (pt1.x >= pt2.x)
newX += stepsCtr;
else
newX -= stepsCtr;
if (pt1.y >= pt2.y)
newY = pt2.y + (deltaY * _stepError) / deltaX;
else
newY = pt2.y - (deltaY * _stepError) / deltaX;
stepsCtr = 0;
}
} else {
_newMoveDirection = 3;
if (pt1.y < pt2.y)
_newMoveDirection = 1;
if (firstTime) {
if (pt1.y >= pt2.y)
stepsCtr += 7;
else {
stepsCtr -= 4;
if (stepsCtr < 0)
stepsCtr = 0;
}
_ySteps = stepsCtr;
}
if (stepsCtr + _stepError >= deltaY) {
stepsCtr -= deltaY;
stepsCtr += _stepError;
_stepError = 0;
_currPointIndex++;
if (_currPointIndex == (int)_pathPoints->size() - 1)
stepsCtr = 0;
newX = pathPoint(_currPointIndex).x;
newY = pathPoint(_currPointIndex).y;
} else {
_stepError += stepsCtr;
if (pt1.x >= pt2.x)
newX = pt2.x + (deltaX * _stepError) / deltaY;
else
newX = pt2.x - (deltaX * _stepError) / deltaY;
if (pt1.y >= pt2.y)
newY += stepsCtr;
else
newY -= stepsCtr;
stepsCtr = 0;
}
}
firstTime = false;
}
if (_yMoveTotalSteps != 0) {
_x = newX;
_y = newY;
_yMoveTotalSteps -= _ySteps;
if (_yMoveTotalSteps <= 0) {
_isBraking = true;
_yMoveTotalSteps = 0;
}
} else {
int distance = calcDistance(_destX, _destY, _x, _y);
_x = newX;
_y = newY;
if (newX > 20 && newX < 620 && newY > 20 && newY < 460) {
_exitDirection = 0;
_inMainArea = true;
} else if (_inMainArea) {
_destX = pathPoint(_pathPoints->size() - 1).x;
_destY = pathPoint(_pathPoints->size() - 1).y;
_inMainArea = false;
if (_x <= 20)
_exitDirection = 1;
else if (_x >= 620)
_exitDirection = 3;
else if (_y <= 20)
_exitDirection = 2;
else if (_y >= 460)
_exitDirection = 4;
if (_exitDirection != 0 && _isBraking) {
_isBraking = false;
_steps = 11;
}
}
if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) ||
(_exitDirection == 0 && _lastDistance + 20 < distance))
_isBraking = true;
if (distance < _lastDistance)
_lastDistance = distance;
if (_currPointIndex == (int)_pathPoints->size() - 1) {
_isBraking = true;
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2006, 0);
}
}
}
void AsCommonCar::suMoveToPrevPoint() {
int16 newX = _x, newY = _y;
if (_currPointIndex == 0 && _stepError == 0) {
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2005, 0);
return;
}
if (_isBraking) {
if (_steps <= 0) {
sendMessage(this, 0x1019, 0);
return;
} else
_steps--;
} else if (_steps < 11)
_steps++;
bool firstTime = true;
_ySteps = _steps;
int stepsCtr = _steps;
while (stepsCtr > 0) {
if (_stepError == 0)
_currPointIndex--;
NPoint pt1;
NPoint pt2 = pathPoint(_currPointIndex);
if (_currPointIndex + 1 >= (int)_pathPoints->size())
pt1 = pathPoint(0);
else
pt1 = pathPoint(_currPointIndex + 1);
int16 deltaX = ABS(pt1.x - pt2.x);
int16 deltaY = ABS(pt1.y - pt2.y);
if (deltaX >= deltaY) {
_newMoveDirection = 4;
if (pt1.x < pt2.x)
_newMoveDirection = 2;
if (_stepError == 0)
_stepError = deltaX;
if (stepsCtr > _stepError) {
stepsCtr -= _stepError;
_stepError = 0;
if (_currPointIndex == 0)
stepsCtr = 0;
newX = pathPoint(_currPointIndex).x;
newY = pathPoint(_currPointIndex).y;
} else {
_stepError -= stepsCtr;
if (pt1.x >= pt2.x)
newX -= stepsCtr;
else
newX += stepsCtr;
if (pt1.y >= pt2.y)
newY = pt2.y + (deltaY * _stepError) / deltaX;
else
newY = pt2.y - (deltaY * _stepError) / deltaX;
stepsCtr = 0;
}
} else {
_newMoveDirection = 1;
if (pt1.y < pt2.y)
_newMoveDirection = 3;
if (firstTime) {
if (pt1.y >= pt2.y) {
stepsCtr -= 4;
if (stepsCtr < 0)
stepsCtr = 0;
} else {
stepsCtr += 7;
}
_ySteps = stepsCtr;
}
if (_stepError == 0)
_stepError = deltaY;
if (stepsCtr > _stepError) {
stepsCtr -= _stepError;
_stepError = 0;
if (_currPointIndex == 0)
stepsCtr = 0;
newX = pathPoint(_currPointIndex).x;
newY = pathPoint(_currPointIndex).y;
} else {
_stepError -= stepsCtr;
if (pt1.x >= pt2.x)
newX = pt2.x + (deltaX * _stepError) / deltaY;
else
newX = pt2.x - (deltaX * _stepError) / deltaY;
if (pt1.y >= pt2.y)
newY -= stepsCtr;
else
newY += stepsCtr;
stepsCtr = 0;
}
}
firstTime = false;
}
if (_yMoveTotalSteps != 0) {
_x = newX;
_y = newY;
_yMoveTotalSteps -= _ySteps;
if (_yMoveTotalSteps <= 0) {
_isBraking = true;
_yMoveTotalSteps = 0;
}
} else {
int distance = calcDistance(_destX, _destY, _x, _y);
_x = newX;
_y = newY;
if (newX > 20 && newX < 620 && newY > 20 && newY < 460) {
_exitDirection = 0;
_inMainArea = true;
} else if (_inMainArea) {
_destX = pathPoint(0).x;
_destY = pathPoint(0).y;
_inMainArea = false;
if (_x <= 20)
_exitDirection = 1;
else if (_x >= 620)
_exitDirection = 3;
else if (_y <= 20)
_exitDirection = 2;
else if (_y >= 460)
_exitDirection = 4;
if (_exitDirection != 0 && _isBraking) {
_isBraking = false;
_steps = 11;
}
}
if ((distance < 20 && _exitDirection == 0 && _lastDistance < distance) ||
(_exitDirection == 0 && _lastDistance + 20 < distance))
_isBraking = true;
if (distance < _lastDistance)
_lastDistance = distance;
if (_currPointIndex == 0 && _stepError == 0) {
_isBraking = true;
_yMoveTotalSteps = 0;
sendMessage(this, 0x1019, 0);
sendMessage(_parentScene, 0x2005, 0);
}
}
}
void AsCommonCar::updateSound() {
int maxSoundCounter = 0;
_soundCounter++;
if (_steps != 0 && !_isIdle) {
if (_currMoveDirection == 1)
maxSoundCounter = 18 - _steps;
else if (_currMoveDirection == 3) {
maxSoundCounter = 5 - _steps;
if (maxSoundCounter < 1)
maxSoundCounter = 1;
} else
maxSoundCounter = 14 - _steps;
} else
maxSoundCounter = 21;
if (_soundCounter >= maxSoundCounter) {
sendMessage(_parentScene, 0x200D, 0);
_soundCounter = 0;
}
}
AsCommonIdleCarLower::AsCommonIdleCarLower(NeverhoodEngine *vm, int16 x, int16 y)
: AnimatedSprite(vm, 0x1209E09F, 1100, x, y) {
setDoDeltaX(1);
startAnimation(0x1209E09F, 1, -1);
_newStickFrameIndex = 1;
}
AsCommonIdleCarFull::AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y)
: AnimatedSprite(vm, 0x1209E09F, 100, x, y) {
setDoDeltaX(1);
_newStickFrameIndex = 0;
}
AsCommonCarConnector::AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar)
: AnimatedSprite(vm, 1100), _asCar(asCar) {
createSurface1(0x60281C10, 150);
startAnimation(0x60281C10, -1, -1);
_newStickFrameIndex = STICK_LAST_FRAME;
SetUpdateHandler(&AsCommonCarConnector::update);
}
void AsCommonCarConnector::update() {
_x = _asCar->getX();
_y = _asCar->getY();
AnimatedSprite::update();
}
void Tracks::findTrackPoint(NPoint pt, int &minMatchTrackIndex, int &minMatchDistance,
DataResource &dataResource) {
const uint trackCount = size();
minMatchTrackIndex = -1;
minMatchDistance = 640;
for (uint trackIndex = 0; trackIndex < trackCount; trackIndex++) {
NPointArray *pointList = dataResource.getPointArray((*this)[trackIndex]->trackPointsName);
for (uint pointIndex = 0; pointIndex < pointList->size(); pointIndex++) {
NPoint testPt = (*pointList)[pointIndex];
int distance = calcDistance(testPt.x, testPt.y, pt.x, pt.y);
if (distance < minMatchDistance) {
minMatchTrackIndex = trackIndex;
minMatchDistance = distance;
}
}
}
}
} // End of namespace Neverhood

View File

@ -0,0 +1,119 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef NEVERHOOD_MODULES_MODULE1600_SPRITES_H
#define NEVERHOOD_MODULES_MODULE1600_SPRITES_H
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
namespace Neverhood {
class AsCommonCar : public AnimatedSprite {
public:
AsCommonCar(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y);
~AsCommonCar();
void setPathPoints(NPointArray *pathPoints);
protected:
Scene *_parentScene;
NPointArray *_pathPoints;
int _newMoveDirection;
int _currMoveDirection;
int _exitDirection;
int _currPointIndex;
bool _hasAgainDestPoint;
NPoint _againDestPoint;
bool _hasAgainDestPointIndex;
int _againDestPointIndex;
bool _inMainArea;
bool _isBraking;
bool _isBusy;
bool _isIdle;
bool _isMoving;
bool _rectFlag;
int _idleCounter;
int _idleCounterMax;
int _steps;
int _stepError;
int _lastDistance;
int _yMoveTotalSteps;
int _ySteps;
int _newDeltaXType;
int _soundCounter;
int _turnMoveStatus;
int16 _destX, _destY;
NPoint pathPoint(uint index) { return (*_pathPoints)[index]; }
void update();
void upIdle();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmAnimation(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmLeaveCar(int messageNum, const MessageParam &param, Entity *sender);
void stCarAtHome();
void updateTurnMovement();
void updateMovement();
void stEnterCar();
void stLeaveCar();
void stLeanForwardIdle();
void evIdleDone();
void stIdleBlink();
void stUpdateMoveDirection();
void stTurnCar();
void moveToNextPoint();
void stBrakeMoveToNextPoint();
void stTurnCarMoveToNextPoint();
void moveToPrevPoint();
void stBrakeMoveToPrevPoint();
void stTurnCarMoveToPrevPoint();
void evTurnCarDone();
void suMoveToNextPoint();
void suMoveToPrevPoint();
void updateSound();
};
class AsCommonIdleCarLower : public AnimatedSprite {
public:
AsCommonIdleCarLower(NeverhoodEngine *vm, int16 x, int16 y);
};
class AsCommonIdleCarFull : public AnimatedSprite {
public:
AsCommonIdleCarFull(NeverhoodEngine *vm, int16 x, int16 y);
};
class AsCommonCarConnector : public AnimatedSprite {
public:
AsCommonCarConnector(NeverhoodEngine *vm, AsCommonCar *asCar);
protected:
AsCommonCar *_asCar;
void update();
};
class Tracks : public Common::Array<TrackInfo*> {
public:
void findTrackPoint(NPoint pt, int &minMatchTrackIndex, int &minMatchDistance,
DataResource &dataResource);
};
} // End of namespace Neverhood
#endif /* NEVERHOOD_MODULES_MODULE1600_SPRITES_H */

View File

@ -21,6 +21,7 @@
*/
#include "neverhood/modules/module1600.h"
#include "neverhood/modules/module1600_sprites.h"
#include "neverhood/modules/module2500.h"
#include "neverhood/modules/module2500_sprites.h"
#include "neverhood/modules/module2700.h"

View File

@ -26,11 +26,10 @@
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
#include "neverhood/modules/module1600_sprites.h" // for Tracks
namespace Neverhood {
// Module2500
class Module2500 : public Module {
public:
Module2500(NeverhoodEngine *vm, Module *parentModule, int which);
@ -45,7 +44,6 @@ protected:
};
class AsCommonCar;
class Tracks;
class Scene2501 : public Scene {
public:

View File

@ -22,7 +22,7 @@
#include "neverhood/gamemodule.h"
#include "neverhood/modules/module1000.h"
#include "neverhood/modules/module1600.h"
#include "neverhood/modules/module1600_sprites.h"
#include "neverhood/modules/module2700.h"
#include "neverhood/modules/module2700_sprites.h"

View File

@ -26,6 +26,7 @@
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
#include "neverhood/modules/module1600_sprites.h" // for Tracks
namespace Neverhood {
@ -49,7 +50,6 @@ protected:
};
class AsCommonCar;
class Tracks;
class Scene2701 : public Scene {
public: