ILLUSIONS: Implement pathwalking (actual pathfinding todo)

This commit is contained in:
johndoe123 2014-03-31 19:54:55 +02:00 committed by Eugene Sandulenko
parent e0e4d2ffa9
commit f2c48e3ae0
6 changed files with 274 additions and 49 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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();
}
}

View File

@ -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) {