diff options
-rw-r--r-- | engines/illusions/actor.cpp | 266 | ||||
-rw-r--r-- | engines/illusions/actor.h | 20 | ||||
-rw-r--r-- | engines/illusions/fixedpoint.cpp | 21 | ||||
-rw-r--r-- | engines/illusions/fixedpoint.h | 9 | ||||
-rw-r--r-- | engines/illusions/scriptman.cpp | 2 | ||||
-rw-r--r-- | engines/illusions/scriptopcodes.cpp | 5 |
6 files changed, 274 insertions, 49 deletions
diff --git a/engines/illusions/actor.cpp b/engines/illusions/actor.cpp index d9eb94975f..2973a92f73 100644 --- a/engines/illusions/actor.cpp +++ b/engines/illusions/actor.cpp @@ -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 diff --git a/engines/illusions/actor.h b/engines/illusions/actor.h index 50d3f7c1c8..4dd8ba50f4 100644 --- a/engines/illusions/actor.h +++ b/engines/illusions/actor.h @@ -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; @@ -211,7 +225,7 @@ public: void unpauseControlsByTag(uint32 tag); bool getOverlappedObject(Control *control, Common::Point pt, Control **outOverlappedControl, int minPriority); bool findNamedPoint(uint32 namedPointId, Common::Point &pt); - void actorControlRoutine(Control *control, uint32 deltaTime); + void actorControlRoutine(Control *control, uint32 deltaTime); public: typedef Common::List<Control*> Items; typedef Items::iterator ItemsIterator; diff --git a/engines/illusions/fixedpoint.cpp b/engines/illusions/fixedpoint.cpp index 7fc15e424e..54dbb137cd 100644 --- a/engines/illusions/fixedpoint.cpp +++ b/engines/illusions/fixedpoint.cpp @@ -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 diff --git a/engines/illusions/fixedpoint.h b/engines/illusions/fixedpoint.h index a14eb8b51b..1320daa7e7 100644 --- a/engines/illusions/fixedpoint.h +++ b/engines/illusions/fixedpoint.h @@ -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 diff --git a/engines/illusions/scriptman.cpp b/engines/illusions/scriptman.cpp index 20749438d1..8a59d70a1e 100644 --- a/engines/illusions/scriptman.cpp +++ b/engines/illusions/scriptman.cpp @@ -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(); } } diff --git a/engines/illusions/scriptopcodes.cpp b/engines/illusions/scriptopcodes.cpp index 77a7d1f523..00f57956dc 100644 --- a/engines/illusions/scriptopcodes.cpp +++ b/engines/illusions/scriptopcodes.cpp @@ -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) { |