mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
944 lines
25 KiB
C++
944 lines
25 KiB
C++
/* 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 "neverhood/modules/module1600_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;
|
|
_destX = x;
|
|
_destY = 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 = nullptr;
|
|
_currMoveDirection = 0;
|
|
_newMoveDirection = 0;
|
|
|
|
startAnimation(0xD4220027, 0, -1);
|
|
setDoDeltaX(getGlobalVar(V_CAR_DELTA_X));
|
|
|
|
SetUpdateHandler(&AsCommonCar::update);
|
|
SetMessageHandler(&AsCommonCar::handleMessage);
|
|
SetSpriteUpdate(nullptr);
|
|
}
|
|
|
|
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 ¶m, Entity *sender) {
|
|
uint32 messageResult = Sprite::handleMessage(messageNum, param, sender);
|
|
switch (messageNum) {
|
|
case NM_SCENE_LEAVE:
|
|
SetSpriteUpdate(nullptr);
|
|
break;
|
|
case NM_POSITION_CHANGE:
|
|
// 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, NM_KLAYMEN_CLIMB_LADDER, 0);
|
|
} else if (_currPointIndex == (int)_pathPoints->size()) {
|
|
_yMoveTotalSteps = 0;
|
|
sendMessage(_parentScene, NM_KLAYMEN_STOP_CLIMBING, 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(nullptr);
|
|
} else {
|
|
if (minMatchIndex > _currPointIndex)
|
|
moveToNextPoint();
|
|
else
|
|
moveToPrevPoint();
|
|
}
|
|
} else {
|
|
_hasAgainDestPoint = true;
|
|
_againDestPoint = pt;
|
|
}
|
|
}
|
|
break;
|
|
case NM_CAR_MOVE_TO_PREV_POINT:
|
|
_yMoveTotalSteps = param.asInteger();
|
|
_steps = 0;
|
|
_isBraking = false;
|
|
_lastDistance = 640;
|
|
SetSpriteUpdate(&AsCommonCar::suMoveToPrevPoint);
|
|
break;
|
|
case NM_CAR_MOVE_TO_NEXT_POINT:
|
|
_yMoveTotalSteps = param.asInteger();
|
|
_steps = 0;
|
|
_isBraking = false;
|
|
_lastDistance = 640;
|
|
SetSpriteUpdate(&AsCommonCar::suMoveToNextPoint);
|
|
break;
|
|
case NM_CAR_ENTER:
|
|
stEnterCar();
|
|
break;
|
|
case NM_CAR_LEAVE:
|
|
stLeaveCar();
|
|
break;
|
|
case NM_CAR_TURN:
|
|
stTurnCar();
|
|
break;
|
|
case NM_CAR_AT_HOME:
|
|
stCarAtHome();
|
|
_newDeltaXType = param.asInteger();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return messageResult;
|
|
}
|
|
|
|
uint32 AsCommonCar::hmAnimation(int messageNum, const MessageParam ¶m, Entity *sender) {
|
|
uint32 messageResult = AsCommonCar::handleMessage(messageNum, param, sender);
|
|
switch (messageNum) {
|
|
case NM_ANIMATION_START:
|
|
if (_isBusy && param.asInteger() == 0x025424A2)
|
|
gotoNextState();
|
|
break;
|
|
case NM_ANIMATION_STOP:
|
|
gotoNextState();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return messageResult;
|
|
}
|
|
|
|
uint32 AsCommonCar::hmLeaveCar(int messageNum, const MessageParam ¶m, Entity *sender) {
|
|
switch (messageNum) {
|
|
case NM_CAR_ENTER:
|
|
stEnterCar();
|
|
break;
|
|
case NM_ANIMATION_STOP:
|
|
sendMessage(_parentScene, NM_CAR_LEAVE, 0);
|
|
SetMessageHandler(&AsCommonCar::handleMessage);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void AsCommonCar::stCarAtHome() {
|
|
bool doDeltaX = _doDeltaX;
|
|
SetSpriteUpdate(nullptr);
|
|
_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, NM_SCENE_LEAVE, 0);
|
|
sendMessage(_parentScene, NM_KLAYMEN_STOP_CLIMBING, 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(nullptr);
|
|
_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, NM_SCENE_LEAVE, 0);
|
|
sendMessage(_parentScene, NM_KLAYMEN_CLIMB_LADDER, 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(nullptr);
|
|
_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, NM_SCENE_LEAVE, 0);
|
|
sendMessage(_parentScene, NM_KLAYMEN_STOP_CLIMBING, 0);
|
|
return;
|
|
}
|
|
|
|
if (_isBraking) {
|
|
if (_steps <= 0) {
|
|
sendMessage(this, NM_SCENE_LEAVE, 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, NM_SCENE_LEAVE, 0);
|
|
sendMessage(_parentScene, NM_KLAYMEN_STOP_CLIMBING, 0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void AsCommonCar::suMoveToPrevPoint() {
|
|
int16 newX = _x, newY = _y;
|
|
|
|
if (_currPointIndex == 0 && _stepError == 0) {
|
|
_yMoveTotalSteps = 0;
|
|
sendMessage(this, NM_SCENE_LEAVE, 0);
|
|
sendMessage(_parentScene, NM_KLAYMEN_CLIMB_LADDER, 0);
|
|
return;
|
|
}
|
|
|
|
if (_isBraking) {
|
|
if (_steps <= 0) {
|
|
sendMessage(this, NM_SCENE_LEAVE, 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, NM_SCENE_LEAVE, 0);
|
|
sendMessage(_parentScene, NM_KLAYMEN_CLIMB_LADDER, 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
KmScene1608::KmScene1608(NeverhoodEngine *vm, Scene *parentScene, int16 x, int16 y)
|
|
: Klaymen(vm, parentScene, x, y) {
|
|
|
|
// Empty
|
|
}
|
|
|
|
uint32 KmScene1608::xHandleMessage(int messageNum, const MessageParam ¶m) {
|
|
uint32 messageResult = 0;
|
|
switch (messageNum) {
|
|
case 0x2032:
|
|
_isSittingInTeleporter = param.asInteger() != 0;
|
|
messageResult = 1;
|
|
break;
|
|
case 0x4001:
|
|
case 0x4800:
|
|
startWalkToX(param.asPoint().x, false);
|
|
break;
|
|
case NM_KLAYMEN_STAND_IDLE:
|
|
if (_isSittingInTeleporter)
|
|
GotoState(&Klaymen::stSitIdleTeleporter);
|
|
else
|
|
GotoState(&Klaymen::stTryStandIdle);
|
|
break;
|
|
case NM_KLAYMEN_PICKUP:
|
|
if (param.asInteger() == 2)
|
|
GotoState(&Klaymen::stPickUpNeedle);
|
|
else if (param.asInteger() == 1)
|
|
GotoState(&Klaymen::stPickUpTube);
|
|
else
|
|
GotoState(&Klaymen::stPickUpGeneric);
|
|
break;
|
|
case 0x4817:
|
|
setDoDeltaX(param.asInteger());
|
|
gotoNextStateExt();
|
|
break;
|
|
case 0x481B:
|
|
if (param.asPoint().y != 0)
|
|
startWalkToXDistance(param.asPoint().y, param.asPoint().x);
|
|
else
|
|
startWalkToAttachedSpriteXDistance(param.asPoint().x);
|
|
break;
|
|
case NM_KLAYMEN_TURN_TO_USE:
|
|
if (_isSittingInTeleporter)
|
|
GotoState(&Klaymen::stTurnToUseInTeleporter);
|
|
break;
|
|
case NM_KLAYMEN_RETURN_FROM_USE:
|
|
if (_isSittingInTeleporter)
|
|
GotoState(&Klaymen::stReturnFromUseInTeleporter);
|
|
break;
|
|
case 0x481F:
|
|
if (param.asInteger() == 1)
|
|
GotoState(&Klaymen::stWonderAboutAfter);
|
|
else if (param.asInteger() == 0)
|
|
GotoState(&Klaymen::stWonderAboutHalf);
|
|
else if (param.asInteger() == 4)
|
|
GotoState(&Klaymen::stTurnAwayFromUse);
|
|
else if (param.asInteger() == 3)
|
|
GotoState(&Klaymen::stTurnToUseHalf);
|
|
else
|
|
GotoState(&Klaymen::stWonderAbout);
|
|
break;
|
|
case 0x482D:
|
|
setDoDeltaX(_x > (int16)param.asInteger() ? 1 : 0);
|
|
gotoNextStateExt();
|
|
break;
|
|
case 0x4834:
|
|
GotoState(&Klaymen::stStepOver);
|
|
break;
|
|
case 0x4835:
|
|
sendMessage(_parentScene, 0x2032, 1);
|
|
_isSittingInTeleporter = true;
|
|
GotoState(&Klaymen::stSitInTeleporter);
|
|
break;
|
|
case 0x4836:
|
|
sendMessage(_parentScene, 0x2032, 0);
|
|
_isSittingInTeleporter = false;
|
|
GotoState(&Klaymen::stGetUpFromTeleporter);
|
|
break;
|
|
case 0x483F:
|
|
startSpecialWalkRight(param.asInteger());
|
|
break;
|
|
case 0x4840:
|
|
startSpecialWalkLeft(param.asInteger());
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return messageResult;
|
|
}
|
|
|
|
} // End of namespace Neverhood
|