mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 21:59:17 +00:00
ILLUSIONS: Implement pathwalking (actual pathfinding todo)
This commit is contained in:
parent
e0e4d2ffa9
commit
f2c48e3ae0
@ -25,6 +25,7 @@
|
||||
#include "illusions/camera.h"
|
||||
#include "illusions/cursor.h"
|
||||
#include "illusions/dictionary.h"
|
||||
#include "illusions/fixedpoint.h"
|
||||
#include "illusions/input.h"
|
||||
#include "illusions/screen.h"
|
||||
#include "illusions/scriptman.h"
|
||||
@ -94,29 +95,29 @@ Actor::Actor(IllusionsEngine *vm)
|
||||
|
||||
_notifyId3C = 0;
|
||||
|
||||
_pathCtrY = 0;
|
||||
|
||||
_controlRoutine = 0;
|
||||
setControlRoutine(new Common::Functor2Mem<Control*, uint32, void, Controls>(_vm->_controls, &Controls::actorControlRoutine));
|
||||
|
||||
#if 0 // TODO
|
||||
_field2 = 0;
|
||||
_path40 = 0;
|
||||
_path4C = 0;
|
||||
_pathFlag50 = 0;
|
||||
_walkCallerThreadId1 = 0;
|
||||
_pathAngle = 0;
|
||||
_pathFlag50 = false;
|
||||
_pathCtrX = 0;
|
||||
_pathInitialPosFlag = 1;
|
||||
_pathCtrY = 0;
|
||||
_pathInitialPosFlag = true;
|
||||
_pathInitialPos.x = 0;
|
||||
_pathInitialPos.y = 0;
|
||||
_pathPoints = 0;
|
||||
_pathPointIndex = 0;
|
||||
_pathPointsCount = 0;
|
||||
_pathNode = 0;
|
||||
|
||||
#if 0 // TODO
|
||||
_field2 = 0;
|
||||
_namedPointsCount = 0;
|
||||
_namedPoints = 0;
|
||||
_field164 = 0;
|
||||
_pathWalkRects = 0;
|
||||
_pathWalkPoints = 0;
|
||||
_pathNode = 0;
|
||||
_pathPoints = 0;
|
||||
_pathPointIndex = 0;
|
||||
_pathPointsCount = 0;
|
||||
_regionLayer = 0;
|
||||
_transitionRegionId = 0;
|
||||
_field18C = 0;
|
||||
@ -342,7 +343,7 @@ void Control::setActorScale(int scale) {
|
||||
for (uint i = 0; i < kSubObjectsCount; ++i)
|
||||
if (_actor->_subobjects[i]) {
|
||||
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[i]);
|
||||
subControl->activateObject();
|
||||
subControl->setActorScale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,19 +529,17 @@ void Control::setActorFrameIndex(int16 frameIndex) {
|
||||
|
||||
void Control::stopActor() {
|
||||
_actor->_seqCodeIp = 0;
|
||||
/* TODO
|
||||
if (_actor->_pathNode) {
|
||||
if (_actor->_flags & 0x0400) {
|
||||
// TODO delete _actor->_pathNode;
|
||||
delete _actor->_pathNode;
|
||||
_actor->_flags &= ~0x0400;
|
||||
}
|
||||
_actor->_pathNode = 0;
|
||||
_actor->_pathPoints = 0;
|
||||
_actor->_pathPointsCount = 0;
|
||||
_actor->_pathPointIndex = 0;
|
||||
_actor->_path40 = 0;
|
||||
_actor->_walkCallerThreadId1 = 0;
|
||||
}
|
||||
*/
|
||||
_vm->notifyThreadId(_actor->_notifyThreadId1);
|
||||
_vm->notifyThreadId(_actor->_notifyId3C);
|
||||
}
|
||||
@ -570,16 +569,14 @@ void Control::startTalkActor(uint32 sequenceId, byte *entryTblPtr, uint32 thread
|
||||
if (_actor->_linkIndex2) {
|
||||
Control *subControl = _vm->_dict->getObjectControl(_actor->_subobjects[_actor->_linkIndex2 - 1]);
|
||||
if (subControl->_actor->_flags & 1) {
|
||||
/* TODO
|
||||
if (control->_actor->pathNode) {
|
||||
if (subControl->_actor->_pathNode) {
|
||||
doSeq = false;
|
||||
subControl->_actor->notifyThreadId2 = threadId;
|
||||
subControl->_actor->entryTblPtr = entryTblPtr;
|
||||
subControl->_actor->flags |= 0x80;
|
||||
Thread *thread = _vm->_threads->findThread(threadId);
|
||||
subControl->_actor->_notifyThreadId2 = threadId;
|
||||
subControl->_actor->_entryTblPtr = entryTblPtr;
|
||||
subControl->_actor->_flags |= 0x80;
|
||||
Thread *thread = _vm->_scriptMan->_threads->findThread(threadId);
|
||||
thread->sendMessage(kMsgClearSequenceId2, 0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
if (doSeq)
|
||||
@ -653,7 +650,7 @@ void Control::startSubSequence(int linkIndex, uint32 sequenceId) {
|
||||
linkedActor->_sequenceId = sequenceId;
|
||||
linkedActor->_notifyThreadId1 = 0;
|
||||
linkedActor->_notifyId3C = 0;
|
||||
linkedActor->_path40 = 0;
|
||||
linkedActor->_walkCallerThreadId1 = 0;
|
||||
|
||||
Sequence *sequence = _vm->_dict->findSequence(sequenceId);
|
||||
linkedActor->_seqCodeIp = sequence->_sequenceCode;
|
||||
@ -688,6 +685,213 @@ void Control::stopSubSequence(int linkIndex) {
|
||||
}
|
||||
}
|
||||
|
||||
void Control::startMoveActor(uint32 sequenceId, Common::Point destPt, uint32 callerThreadId1, uint32 callerThreadId2) {
|
||||
PointArray *pathNode;
|
||||
ActorType *actorType = _vm->_dict->findActorType(_actorTypeId);
|
||||
|
||||
_actor->_pathAngle = 0;
|
||||
_actor->_pathFlag50 = false;
|
||||
_actor->_seqCodeValue3 = 0;
|
||||
_actor->_seqCodeValue1 = 0;
|
||||
// TODO _actor->_field_BC = _actor->_position.x;
|
||||
// TODO _actor->_field_BE = _actor->_position.x;
|
||||
_actor->_pathInitialPosFlag = true;
|
||||
// TODO _actor->_field_C0 = destPt.x;
|
||||
// TODO _actor->_field_C2 = destPt.y;
|
||||
|
||||
/* TODO
|
||||
uint newFacing;
|
||||
if (calcPointDirection(_actor->_position, destPt, newFacing))
|
||||
faceActor(newFacing);
|
||||
*/
|
||||
|
||||
if (actorType->_value1E)
|
||||
_actor->_pathCtrY = actorType->_value1E;
|
||||
else
|
||||
_actor->_pathCtrY = 140;
|
||||
|
||||
pathNode = createPath(destPt);
|
||||
|
||||
if (pathNode->size() == 1 &&
|
||||
_actor->_position.x == (*pathNode)[0].x &&
|
||||
_actor->_position.y == (*pathNode)[0].y) {
|
||||
delete pathNode;
|
||||
_vm->notifyThreadId(callerThreadId2);
|
||||
} else {
|
||||
_actor->_posXShl = _actor->_position.x << 16;
|
||||
_actor->_posYShl = _actor->_position.y << 16;
|
||||
startSequenceActor(sequenceId, 1, 0);
|
||||
_actor->_pathNode = pathNode;
|
||||
_actor->_pathPointsCount = pathNode->size();
|
||||
_actor->_pathPoints = pathNode->size();
|
||||
_actor->_flags |= 0x0400;
|
||||
_actor->_walkCallerThreadId1 = callerThreadId1;
|
||||
_vm->notifyThreadId(_actor->_notifyId3C);
|
||||
_actor->_notifyId3C = callerThreadId2;
|
||||
_actor->_pathPointIndex = 0;
|
||||
_vm->_input->discardButtons(0x10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PointArray *Control::createPath(Common::Point destPt) {
|
||||
// TODO Implement actual pathfinding
|
||||
PointArray *pathNode = new PointArray();
|
||||
pathNode->push_back(destPt);
|
||||
return pathNode;
|
||||
}
|
||||
|
||||
void Control::updateActorMovement(uint32 deltaTime) {
|
||||
// TODO This needs some cleanup
|
||||
|
||||
static const int16 kAngleTbl[] = {60, 0, 120, 0, 60, 0, 120, 0};
|
||||
|
||||
while (1) {
|
||||
|
||||
bool again = false;
|
||||
|
||||
/* TODO
|
||||
if (controla->objectId == GameScript_getField0() && again == const0 && Input_pollButton__(0x10u)) {
|
||||
again = 1;
|
||||
Control_disappearActor__(controla);
|
||||
HIBYTE(_actor->_flags) |= 0x80u;
|
||||
_actor->_seqCodeIp = 0;
|
||||
deltaTime = 2;
|
||||
}
|
||||
*/
|
||||
|
||||
Common::Point prevPt;
|
||||
if (_actor->_pathPointIndex == 0) {
|
||||
if (_actor->_pathInitialPosFlag) {
|
||||
_actor->_pathCtrX = 0;
|
||||
_actor->_pathInitialPos = _actor->_position;
|
||||
_actor->_pathInitialPosFlag = false;
|
||||
}
|
||||
prevPt = _actor->_pathInitialPos;
|
||||
} else {
|
||||
prevPt = (*_actor->_pathNode)[_actor->_pathPointIndex - 1];
|
||||
}
|
||||
|
||||
Common::Point currPt = (*_actor->_pathNode)[_actor->_pathPointIndex];
|
||||
|
||||
int16 deltaX = currPt.x - prevPt.x;
|
||||
int16 deltaY = currPt.y - prevPt.y;
|
||||
|
||||
if (!_actor->_pathFlag50) {
|
||||
|
||||
// TODO Move to own function
|
||||
FP16 angle;
|
||||
if (currPt.x == prevPt.x) {
|
||||
if (prevPt.y >= currPt.y)
|
||||
angle = fixedMul(-0x5A0000, 0x478);
|
||||
else
|
||||
angle = fixedMul(0x5A0000, 0x478);
|
||||
} else {
|
||||
angle = fixedAtan(fixedDiv(deltaY << 16, deltaX << 16));
|
||||
}
|
||||
_actor->_pathAngle = angle;
|
||||
|
||||
// TODO Move to own function
|
||||
int16 v13 = (fixedTrunc(fixedMul(angle, 0x394BB8)) + 360) % 360;
|
||||
if (deltaX >= 0)
|
||||
v13 += 180;
|
||||
v13 = (v13 + 90) % 360;
|
||||
int16 v15 = kAngleTbl[0] / -2;
|
||||
uint newFacing = 1;
|
||||
for (uint i = 0; i < 8; ++i) {
|
||||
v15 += kAngleTbl[i];
|
||||
if (v13 < v15) {
|
||||
newFacing = 1 << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newFacing != _actor->_facing) {
|
||||
refreshSequenceCode();
|
||||
faceActor(newFacing);
|
||||
}
|
||||
|
||||
_actor->_pathFlag50 = true;
|
||||
|
||||
}
|
||||
|
||||
FP16 deltaX24, deltaY24;
|
||||
|
||||
if (_actor->_flags & 0x0400) {
|
||||
|
||||
FP16 v20 = fixedMul((deltaTime + _actor->_pathCtrX) << 16, _actor->_pathCtrY << 16);
|
||||
FP16 v21 = fixedDiv(v20, 100 << 16);
|
||||
FP16 v22 = fixedMul(v21, _actor->_scale << 16);
|
||||
FP16 v23 = fixedDiv(v22, 100 << 16);
|
||||
_actor->_seqCodeValue1 = 100 * _actor->_pathCtrY * deltaTime / 100;
|
||||
if (v23) {
|
||||
FP16 prevDistance = fixedDistance(prevPt.x << 16, prevPt.y << 16, _actor->_posXShl, _actor->_posYShl);
|
||||
FP16 distance = prevDistance + v23;
|
||||
if (prevPt.x > currPt.x)
|
||||
distance = -distance;
|
||||
deltaX24 = fixedMul(fixedCos(_actor->_pathAngle), distance);
|
||||
deltaY24 = fixedMul(fixedSin(_actor->_pathAngle), distance);
|
||||
} else {
|
||||
deltaX24 = _actor->_posXShl - (prevPt.x << 16);
|
||||
deltaY24 = _actor->_posYShl - (prevPt.y << 16);
|
||||
}
|
||||
} else {
|
||||
if (100 * (int)deltaTime <= _actor->_seqCodeValue2)
|
||||
break;
|
||||
deltaX24 = deltaX << 16;
|
||||
deltaY24 = deltaY << 16;
|
||||
}
|
||||
|
||||
if (ABS(deltaX24) < ABS(deltaX << 16) ||
|
||||
ABS(deltaY24) < ABS(deltaY << 16)) {
|
||||
FP16 newX = (prevPt.x << 16) + deltaX24;
|
||||
FP16 newY = (prevPt.y << 16) + deltaY24;
|
||||
if (newX == _actor->_posXShl && newY == _actor->_posYShl) {
|
||||
_actor->_pathCtrX += deltaTime;
|
||||
} else {
|
||||
_actor->_pathCtrX = 0;
|
||||
_actor->_posXShl = newX;
|
||||
_actor->_posYShl = newY;
|
||||
_actor->_position.x = fixedTrunc(_actor->_posXShl);
|
||||
_actor->_position.y = fixedTrunc(_actor->_posYShl);
|
||||
}
|
||||
} else {
|
||||
_actor->_position = currPt;
|
||||
_actor->_posXShl = _actor->_position.x << 16;
|
||||
_actor->_posYShl = _actor->_position.y << 16;
|
||||
--_actor->_pathPointsCount;
|
||||
++_actor->_pathPointIndex;
|
||||
++_actor->_pathPoints;
|
||||
_actor->_pathInitialPosFlag = true;
|
||||
if (_actor->_pathPointsCount == 0) {
|
||||
if (_actor->_flags & 0x0400) {
|
||||
delete _actor->_pathNode;
|
||||
_actor->_flags &= ~0x0400;
|
||||
}
|
||||
_actor->_pathNode = 0;
|
||||
_actor->_pathPoints = 0;
|
||||
_actor->_pathPointsCount = 0;
|
||||
_actor->_pathPointIndex = 0;
|
||||
if (_actor->_notifyId3C) {
|
||||
_vm->notifyThreadId(_actor->_notifyId3C);
|
||||
_actor->_walkCallerThreadId1 = 0;
|
||||
}
|
||||
again = false;
|
||||
}
|
||||
_actor->_pathFlag50 = false;
|
||||
}
|
||||
|
||||
if (!again)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Control::refreshSequenceCode() {
|
||||
Sequence *sequence = _vm->_dict->findSequence(_actor->_sequenceId);
|
||||
_actor->_seqCodeIp = sequence->_sequenceCode;
|
||||
}
|
||||
|
||||
void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entryTblPtr, uint32 notifyThreadId) {
|
||||
|
||||
stopActor();
|
||||
@ -701,7 +905,7 @@ void Control::startSequenceActorIntern(uint32 sequenceId, int value, byte *entry
|
||||
_actor->_sequenceId = sequenceId;
|
||||
_actor->_notifyThreadId1 = notifyThreadId;
|
||||
_actor->_notifyId3C = 0;
|
||||
_actor->_path40 = 0;
|
||||
_actor->_walkCallerThreadId1 = 0;
|
||||
|
||||
Sequence *sequence = _vm->_dict->findSequence(sequenceId);
|
||||
|
||||
@ -963,8 +1167,8 @@ void Controls::actorControlRoutine(Control *control, uint32 deltaTime) {
|
||||
if (actor->_pauseCtr > 0)
|
||||
return;
|
||||
|
||||
if (false/*actor->_pathNode*/) {
|
||||
// TODO Update pathwalking
|
||||
if (control->_actor->_pathNode) {
|
||||
control->updateActorMovement(deltaTime);
|
||||
} else {
|
||||
actor->_seqCodeValue1 = 100 * deltaTime;
|
||||
}
|
||||
@ -1014,10 +1218,8 @@ void Controls::destroyControl(Control *control) {
|
||||
_vm->_cursor->setControl(0);
|
||||
|
||||
if (control->_actor) {
|
||||
/* TODO
|
||||
if (actor->_pathNode && (actor->_flags & 0x400))
|
||||
delete actor->_pathNode;
|
||||
*/
|
||||
if (control->_actor->_pathNode && (control->_actor->_flags & 0x400))
|
||||
delete control->_actor->_pathNode;
|
||||
if (!(control->_actor->_flags & 0x200))
|
||||
control->_actor->destroySurface();
|
||||
/* TODO
|
||||
|
@ -66,6 +66,7 @@ protected:
|
||||
};
|
||||
|
||||
typedef Common::Functor2<Control*, uint32, void> ActorControlRoutine;
|
||||
typedef Common::Array<Common::Point> PointArray;
|
||||
|
||||
class Actor {
|
||||
public:
|
||||
@ -134,8 +135,17 @@ public:
|
||||
int _seqCodeValue2;
|
||||
int _seqCodeValue3;
|
||||
|
||||
int _pathCtrY;
|
||||
int _path40;
|
||||
int _pathCtrX, _pathCtrY;
|
||||
int _pathAngle;
|
||||
int32 _posXShl, _posYShl;
|
||||
uint _pathPointIndex;
|
||||
uint _pathPointsCount;
|
||||
Common::Point _pathInitialPos;
|
||||
bool _pathInitialPosFlag;
|
||||
bool _pathFlag50;
|
||||
PointArray *_pathNode;
|
||||
uint _pathPoints;
|
||||
uint32 _walkCallerThreadId1;
|
||||
|
||||
};
|
||||
|
||||
@ -176,6 +186,10 @@ public:
|
||||
void setActorIndexTo2();
|
||||
void startSubSequence(int linkIndex, uint32 sequenceId);
|
||||
void stopSubSequence(int linkIndex);
|
||||
void startMoveActor(uint32 sequenceId, Common::Point destPt, uint32 callerThreadId1, uint32 callerThreadId2);
|
||||
PointArray *createPath(Common::Point destPt);
|
||||
void updateActorMovement(uint32 deltaTime);
|
||||
void refreshSequenceCode();
|
||||
public:
|
||||
IllusionsEngine *_vm;
|
||||
uint _flags;
|
||||
|
@ -41,20 +41,33 @@ FP16 fixedDiv(FP16 a, FP16 b) {
|
||||
return ((float)a / b) * 65536.0;
|
||||
}
|
||||
|
||||
int fixedTrunc(FP16 value) {
|
||||
int16 fixedTrunc(FP16 value) {
|
||||
// CHECKME Not sure if this correct
|
||||
int result = value >> 16;
|
||||
int16 result = (value >> 16) & 0xFFFF;
|
||||
if ((value & 0xFFFF) >= 0x8000)
|
||||
++result;
|
||||
return result;
|
||||
}
|
||||
|
||||
FP16 fixedDistance(FP16 x1, FP16 y1, FP16 x2, FP16 y2) {
|
||||
float xd = ABS(fixedToFloat(x1) - fixedToFloat(x2));
|
||||
float yd = ABS(fixedToFloat(y1) - fixedToFloat(y2));
|
||||
float xd = fixedToFloat(x1) - fixedToFloat(x2);
|
||||
float yd = fixedToFloat(y1) - fixedToFloat(y2);
|
||||
if (xd != 0.0 || yd != 0.0)
|
||||
return floatToFixed(sqrt(xd * xd + yd * yd));
|
||||
return 0;
|
||||
}
|
||||
|
||||
FP16 fixedAtan(FP16 value) {
|
||||
//return floatToFixed(atan2(1.0, fixedToFloat(value)));
|
||||
return floatToFixed(atan(fixedToFloat(value)));
|
||||
}
|
||||
|
||||
FP16 fixedCos(FP16 value) {
|
||||
return floatToFixed(cos(fixedToFloat(value)));
|
||||
}
|
||||
|
||||
FP16 fixedSin(FP16 value) {
|
||||
return floatToFixed(sin(fixedToFloat(value)));
|
||||
}
|
||||
|
||||
} // End of namespace Illusions
|
||||
|
@ -29,16 +29,15 @@ namespace Illusions {
|
||||
|
||||
typedef int32 FP16;
|
||||
|
||||
struct FPRect {
|
||||
FP16 x1, y1, x2, y2;
|
||||
};
|
||||
|
||||
FP16 floatToFixed(float value);
|
||||
float fixedToFloat(FP16 value);
|
||||
FP16 fixedMul(FP16 a, FP16 b);
|
||||
FP16 fixedDiv(FP16 a, FP16 b);
|
||||
int fixedTrunc(FP16 value);
|
||||
int16 fixedTrunc(FP16 value);
|
||||
FP16 fixedDistance(FP16 x1, FP16 y1, FP16 x2, FP16 y2);
|
||||
FP16 fixedAtan(FP16 value);
|
||||
FP16 fixedCos(FP16 value);
|
||||
FP16 fixedSin(FP16 value);
|
||||
|
||||
} // End of namespace Illusions
|
||||
|
||||
|
@ -354,7 +354,7 @@ void ScriptMan::newScriptThread(uint32 threadId, uint32 callingThreadId, uint no
|
||||
scriptThread->pause();
|
||||
if (_doScriptThreadInit) {
|
||||
int updateResult = 4;
|
||||
while (scriptThread->_pauseCtr <= 0 && updateResult != 1 && updateResult != 2)
|
||||
while (scriptThread->_pauseCtr <= 0 && updateResult != kTSTerminate && updateResult != kTSYield)
|
||||
updateResult = scriptThread->update();
|
||||
}
|
||||
}
|
||||
|
@ -422,10 +422,7 @@ void ScriptOpcodes::opStartMoveActor(ScriptThread *scriptThread, OpCall &opCall)
|
||||
// NOTE Skipped checking for stalled sequence, not sure if needed
|
||||
Control *control = _vm->_dict->getObjectControl(objectId);
|
||||
Common::Point pos = _vm->getNamedPointPosition(namedPointId);
|
||||
// TODO _control->startMoveActor(sequenceId, pos, opCall._callerThreadId, opCall._threadId);
|
||||
|
||||
//DEBUG Resume calling thread, later done by the walking
|
||||
_vm->notifyThreadId(opCall._threadId);
|
||||
control->startMoveActor(sequenceId, pos, opCall._callerThreadId, opCall._threadId);
|
||||
}
|
||||
|
||||
void ScriptOpcodes::opSetActorToNamedPoint(ScriptThread *scriptThread, OpCall &opCall) {
|
||||
|
Loading…
Reference in New Issue
Block a user