mirror of https://github.com/yaz0r/FITD.git
898 lines
25 KiB
C++
898 lines
25 KiB
C++
#include "common.h"
|
|
#include "hybrid.h"
|
|
|
|
hqrEntryStruct<sAnimation>* HQ_Anims = nullptr;
|
|
|
|
std::vector<sFrame> BufferAnim;
|
|
|
|
int SetAnimObjet(int frame, sAnimation* pAnimation, sBody* body)
|
|
{
|
|
if(frame >= pAnimation->m_numFrames)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
int numGroupsInAnimation = pAnimation->m_numGroups;
|
|
sFrame& keyframe = pAnimation->m_frames[frame];
|
|
|
|
animCurrentTime = keyframe.m_timestamp;
|
|
animKeyframeLength = animCurrentTime;
|
|
|
|
if(!(body->m_flags & INFO_ANIM))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
body->startAnim = &keyframe;
|
|
*(u16*)(body->m_scratchBuffer.data() + 4) = timer;
|
|
|
|
if(numGroupsInAnimation > body->m_groupOrder.size())
|
|
numGroupsInAnimation = body->m_groupOrder.size();
|
|
|
|
animStepX = keyframe.m_animStep.x;
|
|
animStepY = keyframe.m_animStep.y;
|
|
animStepZ = keyframe.m_animStep.z;
|
|
|
|
for(int i=0;i< numGroupsInAnimation;i++)
|
|
{
|
|
body->m_groups[i].m_state.m_type = keyframe.m_groups[i].m_type;
|
|
body->m_groups[i].m_state.m_delta = keyframe.m_groups[i].m_delta;
|
|
|
|
if(body->m_flags & INFO_OPTIMISE)
|
|
{
|
|
body->m_groups[i].m_state.m_rotateDelta = keyframe.m_groups[i].m_rotateDelta;
|
|
}
|
|
}
|
|
|
|
return(1);
|
|
|
|
}
|
|
|
|
int InitAnim(int animNum,int animType, int animInfo)
|
|
{
|
|
if(animNum == currentProcessedActorPtr->ANIM)
|
|
{
|
|
if(!(currentProcessedActorPtr->objectType & AF_ANIMATED))
|
|
{
|
|
if(currentProcessedActorPtr->objectType & AF_BOXIFY)
|
|
{
|
|
removeFromBGIncrust(currentProcessedActorIdx);
|
|
}
|
|
|
|
currentProcessedActorPtr->objectType |= AF_ANIMATED;
|
|
|
|
SetAnimObjet(currentProcessedActorPtr->frame, HQR_Get(HQ_Anims,animNum), HQR_Get(HQ_Bodys, currentProcessedActorPtr->bodyNum));
|
|
|
|
currentProcessedActorPtr->animType = animType;
|
|
currentProcessedActorPtr->animInfo = animInfo;
|
|
|
|
if(g_gameId > AITD1)
|
|
{
|
|
currentProcessedActorPtr->frame = 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
currentProcessedActorPtr->animType = animType;
|
|
currentProcessedActorPtr->animInfo = animInfo;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if(animNum == -1)
|
|
{
|
|
currentProcessedActorPtr->newAnim = -2;
|
|
return(1);
|
|
}
|
|
|
|
if(!(currentProcessedActorPtr->objectType & AF_ANIMATED))
|
|
{
|
|
currentProcessedActorPtr->objectType |= AF_ANIMATED;
|
|
|
|
if(currentProcessedActorPtr->objectType & AF_BOXIFY)
|
|
{
|
|
removeFromBGIncrust(currentProcessedActorIdx);
|
|
}
|
|
|
|
SetAnimObjet(0, HQR_Get(HQ_Anims,animNum), HQR_Get(HQ_Bodys, currentProcessedActorPtr->bodyNum));
|
|
|
|
currentProcessedActorPtr->newAnim = animNum;
|
|
currentProcessedActorPtr->newAnimType = animType;
|
|
currentProcessedActorPtr->newAnimInfo = animInfo;
|
|
if(g_gameId > AITD1)
|
|
{
|
|
currentProcessedActorPtr->frame = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if(g_gameId == AITD1)
|
|
{
|
|
if(currentProcessedActorPtr->animType & ANIM_UNINTERRUPTABLE)
|
|
return(0);
|
|
|
|
if(currentProcessedActorPtr->newAnimType & ANIM_UNINTERRUPTABLE)
|
|
return(0);
|
|
}
|
|
else
|
|
{
|
|
if(currentProcessedActorPtr->animType & ANIM_UNINTERRUPTABLE)
|
|
{
|
|
if(currentProcessedActorPtr->newAnimType & ANIM_UNINTERRUPTABLE)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
currentProcessedActorPtr->animInfo = animNum;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
currentProcessedActorPtr->newAnim = animNum;
|
|
currentProcessedActorPtr->newAnimType = animType;
|
|
currentProcessedActorPtr->newAnimInfo = animInfo;
|
|
|
|
if(g_gameId != AITD1)
|
|
{
|
|
currentProcessedActorPtr->frame = 0;
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
int evaluateReal(RealValue* data)
|
|
{
|
|
if(!data->numSteps)
|
|
return data->endValue;
|
|
|
|
if(timer - data->memoTicks> (unsigned int)data->numSteps)
|
|
{
|
|
data->numSteps = 0;
|
|
return data->endValue;
|
|
}
|
|
|
|
s32 valueDiff = data->endValue - data->startValue;
|
|
s32 currentTime = timer - data->memoTicks;
|
|
s32 interpolatedValue = data->startValue + ((valueDiff * currentTime) / data->numSteps);
|
|
|
|
return interpolatedValue;
|
|
}
|
|
|
|
int manageFall(int actorIdx, ZVStruct* zvPtr)
|
|
{
|
|
int fallResult = 0;
|
|
int i;
|
|
int room = objectTable[actorIdx].room;
|
|
|
|
for(i=0;i<NUM_MAX_OBJECT;i++)
|
|
{
|
|
tObject* currentTestedActorPtr = &objectTable[i];
|
|
|
|
if(currentTestedActorPtr->indexInWorld != -1 && i != actorIdx)
|
|
{
|
|
ZVStruct* testedZv = ¤tTestedActorPtr->zv;
|
|
|
|
if(currentTestedActorPtr->room != room)
|
|
{
|
|
ZVStruct localZv;
|
|
copyZv(zvPtr, &localZv);
|
|
getZvRelativePosition(&localZv, room, currentTestedActorPtr->room);
|
|
|
|
if(checkZvCollision(&localZv, testedZv))
|
|
{
|
|
objectTable[i].COL_BY = actorIdx;
|
|
fallResult++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(checkZvCollision(zvPtr, testedZv))
|
|
{
|
|
objectTable[i].COL_BY = actorIdx;
|
|
fallResult++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(fallResult);
|
|
}
|
|
|
|
void GereAnim(void)
|
|
{
|
|
if (currentProcessedActorPtr->objectType & AF_OBJ_2D) {
|
|
if ((currentProcessedActorPtr->ANIM != -1) && (currentProcessedActorPtr->bodyNum != -1)) {
|
|
sHybrid* pHybrid = HQR_Get(HQ_Hybrides, currentProcessedActorPtr->ANIM);
|
|
}
|
|
}
|
|
|
|
int oldStepZ=0;
|
|
int oldStepY=0;
|
|
int oldStepX=0;
|
|
int stepZ=0;
|
|
int stepY=0;
|
|
int stepX=0;
|
|
s16 localTable[3];
|
|
ZVStruct zvLocal;
|
|
ZVStruct* zvPtr;
|
|
|
|
int newAnim = currentProcessedActorPtr->newAnim;
|
|
|
|
if (newAnim != -1) // next anim ?
|
|
{
|
|
if (newAnim == -2) // completely stop anim and add actor to background
|
|
{
|
|
addActorToBgInscrust(currentProcessedActorIdx);
|
|
currentProcessedActorPtr->newAnim = -1;
|
|
currentProcessedActorPtr->newAnimType = 0;
|
|
currentProcessedActorPtr->newAnimInfo = -1;
|
|
currentProcessedActorPtr->flagEndAnim = 1;
|
|
|
|
return;
|
|
}
|
|
else {
|
|
if (!(currentProcessedActorPtr->newAnimType & ANIM_RESET)) // Reset
|
|
{
|
|
if (currentProcessedActorPtr->END_FRAME == 0)
|
|
{
|
|
currentProcessedActorPtr->worldX += currentProcessedActorPtr->stepX;
|
|
currentProcessedActorPtr->roomX += currentProcessedActorPtr->stepX;
|
|
|
|
currentProcessedActorPtr->worldZ += currentProcessedActorPtr->stepZ;
|
|
currentProcessedActorPtr->roomZ += currentProcessedActorPtr->stepZ;
|
|
|
|
currentProcessedActorPtr->stepX = 0;
|
|
currentProcessedActorPtr->stepZ = 0;
|
|
|
|
currentProcessedActorPtr->animNegX = 0;
|
|
currentProcessedActorPtr->animNegY = 0;
|
|
currentProcessedActorPtr->animNegZ = 0;
|
|
}
|
|
|
|
// TODO: AITD3 has some extra code here to handle bufferAnimCounter
|
|
StockInterAnim(BufferAnim[bufferAnimCounter], HQR_Get(HQ_Bodys, currentProcessedActorPtr->bodyNum));
|
|
|
|
bufferAnimCounter++;
|
|
if (bufferAnimCounter == NB_BUFFER_ANIM)
|
|
bufferAnimCounter = 0;
|
|
|
|
}
|
|
else {
|
|
ResetStartAnim(HQR_Get(HQ_Bodys, currentProcessedActorPtr->bodyNum));
|
|
currentProcessedActorPtr->newAnimType &= ~ANIM_RESET;
|
|
}
|
|
currentProcessedActorPtr->ANIM = newAnim;
|
|
currentProcessedActorPtr->animType = currentProcessedActorPtr->newAnimType;
|
|
currentProcessedActorPtr->animInfo = currentProcessedActorPtr->newAnimInfo;
|
|
|
|
currentProcessedActorPtr->newAnim = -1;
|
|
currentProcessedActorPtr->newAnimType = 0;
|
|
currentProcessedActorPtr->newAnimInfo = -1;
|
|
|
|
currentProcessedActorPtr->flagEndAnim = 0;
|
|
currentProcessedActorPtr->frame = 0;
|
|
|
|
currentProcessedActorPtr->numOfFrames = GetNbFramesAnim(HQR_Get(HQ_Anims, newAnim));
|
|
}
|
|
}
|
|
|
|
if(currentProcessedActorPtr->ANIM == -1) // no animation
|
|
{
|
|
currentProcessedActorPtr->END_FRAME = 0;
|
|
if(currentProcessedActorPtr->speed == 0)
|
|
{
|
|
int numObjectCollisions = checkObjectCollisions(currentProcessedActorIdx, ¤tProcessedActorPtr->zv);
|
|
|
|
for(int i = 0; i<numObjectCollisions; i++)
|
|
{
|
|
objectTable[currentProcessedActorPtr->COL[i]].COL_BY = currentProcessedActorIdx; // collision with current actor
|
|
}
|
|
|
|
oldStepY = 0;
|
|
oldStepZ = 0;
|
|
stepX = 0;
|
|
stepZ = 0;
|
|
stepY = 0;
|
|
}
|
|
else
|
|
{
|
|
oldStepX = currentProcessedActorPtr->stepX;
|
|
oldStepY = currentProcessedActorPtr->stepY;
|
|
oldStepZ = currentProcessedActorPtr->stepZ;
|
|
|
|
animStepY = 0;
|
|
animStepX = 0;
|
|
|
|
animStepZ = evaluateReal(¤tProcessedActorPtr->speedChange);
|
|
|
|
walkStep(0,animStepZ,currentProcessedActorPtr->beta);
|
|
|
|
stepX = animMoveX - oldStepX;
|
|
stepZ = animMoveZ - oldStepZ;
|
|
stepY = 0;
|
|
}
|
|
}
|
|
else // animation
|
|
{
|
|
oldStepX = currentProcessedActorPtr->stepX;
|
|
oldStepY = currentProcessedActorPtr->stepY;
|
|
oldStepZ = currentProcessedActorPtr->stepZ;
|
|
|
|
currentProcessedActorPtr->END_FRAME = SetInterAnimObjet(currentProcessedActorPtr->frame, HQR_Get(HQ_Anims, currentProcessedActorPtr->ANIM), HQR_Get(HQ_Bodys, currentProcessedActorPtr->bodyNum));
|
|
|
|
walkStep(animStepX,animStepZ,currentProcessedActorPtr->beta);
|
|
|
|
stepX = animMoveX+currentProcessedActorPtr->animNegX - oldStepX;
|
|
stepZ = animMoveZ+currentProcessedActorPtr->animNegZ - oldStepZ;
|
|
|
|
}
|
|
|
|
if(currentProcessedActorPtr->YHandler.numSteps) // currently falling ?
|
|
{
|
|
if(currentProcessedActorPtr->YHandler.numSteps != -1)
|
|
{
|
|
stepY = evaluateReal(¤tProcessedActorPtr->YHandler) - oldStepY;
|
|
}
|
|
else // stop falling
|
|
{
|
|
stepY = currentProcessedActorPtr->YHandler.endValue - oldStepY;
|
|
|
|
currentProcessedActorPtr->YHandler.numSteps = 0;
|
|
currentProcessedActorPtr->YHandler.endValue = 0;
|
|
currentProcessedActorPtr->YHandler.startValue = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
stepY = 0;
|
|
}
|
|
|
|
memcpy(localTable,currentProcessedActorPtr->COL,6);
|
|
|
|
if(stepX || stepY || stepZ) // start of movement management
|
|
{
|
|
zvPtr = ¤tProcessedActorPtr->zv;
|
|
copyZv(¤tProcessedActorPtr->zv,&zvLocal);
|
|
|
|
zvLocal.ZVX1 += stepX;
|
|
zvLocal.ZVX2 += stepX;
|
|
|
|
zvLocal.ZVY1 += stepY;
|
|
zvLocal.ZVY2 += stepY;
|
|
|
|
zvLocal.ZVZ1 += stepZ;
|
|
zvLocal.ZVZ2 += stepZ;
|
|
|
|
if(currentProcessedActorPtr->dynFlags & 1) // hard collision enabled for actor ?
|
|
{
|
|
int numCol = AsmCheckListCol(&zvLocal, &roomDataTable[currentProcessedActorPtr->room]);
|
|
|
|
for(int i=0;i<numCol;i++)
|
|
{
|
|
hardColStruct* pHardCol = hardColTable[i];
|
|
|
|
if(pHardCol->type == 9)
|
|
{
|
|
currentProcessedActorPtr->HARD_COL = (short)pHardCol->parameter;
|
|
}
|
|
|
|
if(pHardCol->type == 3)
|
|
{
|
|
currentProcessedActorPtr->HARD_COL = 255;
|
|
}
|
|
|
|
if(g_gameId == AITD1 || (g_gameId>=JACK && (pHardCol->type != 10 || currentProcessedActorIdx != currentCameraTargetActor)))
|
|
{
|
|
if(stepX || stepZ) // move on the X or Z axis ? update to avoid entering the hard col
|
|
{
|
|
//ZVStruct tempZv;
|
|
|
|
hardColStepX = stepX;
|
|
hardColStepZ = stepZ;
|
|
|
|
handleCollision(zvPtr, &zvLocal, &pHardCol->zv);
|
|
|
|
currentProcessedActorPtr->animNegX += hardColStepX - stepX;
|
|
currentProcessedActorPtr->animNegZ += hardColStepZ - stepZ;
|
|
|
|
zvLocal.ZVX1 += hardColStepX - stepX;
|
|
zvLocal.ZVX2 += hardColStepX - stepX;
|
|
zvLocal.ZVZ1 += hardColStepZ - stepZ;
|
|
zvLocal.ZVZ2 += hardColStepZ - stepZ;
|
|
|
|
stepX = hardColStepX;
|
|
stepZ = hardColStepZ;
|
|
}
|
|
|
|
if(stepY)
|
|
{
|
|
//assert(0); //not implemented
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // no hard collision -> just update the flag without performing the position update
|
|
{
|
|
if(AsmCheckListCol(&zvLocal, &roomDataTable[currentProcessedActorPtr->room]))
|
|
{
|
|
currentProcessedActorPtr->HARD_COL = 1;
|
|
}
|
|
else
|
|
{
|
|
currentProcessedActorPtr->HARD_COL = 0;
|
|
}
|
|
}
|
|
|
|
int numCol = checkObjectCollisions(currentProcessedActorIdx,&zvLocal); // get the number of actor/actor collision
|
|
|
|
for(int j=0;j<numCol;j++) // process the actor/actor collision
|
|
{
|
|
int collisionIndex = currentProcessedActorPtr->COL[j];
|
|
|
|
tObject* actorTouchedPtr = &objectTable[collisionIndex];
|
|
|
|
actorTouchedPtr->COL_BY = currentProcessedActorIdx;
|
|
|
|
ZVStruct* touchedZv = &actorTouchedPtr->zv;
|
|
|
|
if(actorTouchedPtr->objectType & AF_FOUNDABLE) // takable
|
|
{
|
|
if(currentProcessedActorPtr->trackMode == 1 /*&& ((gameId == AITD1 && defines.field_1E == 0) || (gameId >= JACK && defines.field_6 == 0))*/) // TODO: check if character isn't dead...
|
|
{
|
|
foundObject(actorTouchedPtr->indexInWorld, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(actorTouchedPtr->objectType & AF_MOVABLE) // can be pushed ?
|
|
{
|
|
ZVStruct localZv2;
|
|
|
|
bool isPushPossible = true;
|
|
|
|
copyZv(touchedZv, &localZv2);
|
|
|
|
localZv2.ZVX1 += stepX;
|
|
localZv2.ZVX2 += stepX;
|
|
|
|
localZv2.ZVZ1 += stepZ;
|
|
localZv2.ZVZ2 += stepZ;
|
|
|
|
if(!AsmCheckListCol(&localZv2, &roomDataTable[currentProcessedActorPtr->room]))
|
|
{
|
|
if(checkObjectCollisions(collisionIndex, &localZv2))
|
|
{
|
|
isPushPossible = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
isPushPossible = false;
|
|
}
|
|
|
|
if(!isPushPossible)
|
|
{
|
|
if(stepX || stepZ) //if we're trying to move
|
|
{
|
|
if(actorTouchedPtr->room != currentProcessedActorPtr->room)
|
|
{
|
|
ZVStruct localZv3;
|
|
|
|
copyZv(touchedZv, &localZv3);
|
|
|
|
getZvRelativePosition(&localZv3, actorTouchedPtr->room, currentProcessedActorPtr->room);
|
|
|
|
hardColStepX = stepX;
|
|
hardColStepZ = stepZ;
|
|
|
|
handleCollision(zvPtr, &zvLocal, &localZv3);
|
|
|
|
stepX = hardColStepX;
|
|
stepZ = hardColStepZ;
|
|
}
|
|
else
|
|
{
|
|
hardColStepX = stepX;
|
|
hardColStepZ = stepZ;
|
|
|
|
handleCollision(zvPtr, &zvLocal, touchedZv); // manage as hard collision
|
|
|
|
stepX = hardColStepX;
|
|
stepZ = hardColStepZ;
|
|
}
|
|
}
|
|
}
|
|
else // push succeed
|
|
{
|
|
if(actorTouchedPtr->objectType & AF_BOXIFY)
|
|
{
|
|
removeFromBGIncrust(collisionIndex);
|
|
}
|
|
|
|
actorTouchedPtr->objectType |= AF_ANIMATED;
|
|
|
|
actorTouchedPtr->worldX += stepX; // apply push to object
|
|
actorTouchedPtr->worldZ += stepZ;
|
|
|
|
actorTouchedPtr->roomX += stepX;
|
|
actorTouchedPtr->roomZ += stepZ;
|
|
|
|
copyZv(&localZv2,touchedZv);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// can't be pushed
|
|
if(currentProcessedActorPtr->dynFlags & 1)
|
|
{
|
|
if(stepX || stepZ) // if moving
|
|
{
|
|
if(actorTouchedPtr->room == currentProcessedActorPtr->room) // same room -> easy case
|
|
{
|
|
hardColStepX = stepX;
|
|
hardColStepZ = stepZ;
|
|
|
|
handleCollision(zvPtr, &zvLocal, touchedZv); // manage as hard collision
|
|
|
|
stepX = hardColStepX;
|
|
stepZ = hardColStepZ;
|
|
}
|
|
else // different room
|
|
{
|
|
ZVStruct localZv3;
|
|
|
|
copyZv(touchedZv, &localZv3);
|
|
|
|
getZvRelativePosition(&localZv3, actorTouchedPtr->room, currentProcessedActorPtr->room);
|
|
|
|
hardColStepX = stepX;
|
|
hardColStepZ = stepZ;
|
|
|
|
handleCollision(zvPtr, &zvLocal, &localZv3); // manage as hard collision
|
|
|
|
stepX = hardColStepX;
|
|
stepZ = hardColStepZ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // end of actor/actor collision
|
|
|
|
currentProcessedActorPtr->stepX = stepX + oldStepX;
|
|
currentProcessedActorPtr->stepY = stepY + oldStepY;
|
|
currentProcessedActorPtr->stepZ = stepZ + oldStepZ;
|
|
|
|
currentProcessedActorPtr->zv.ZVX1 += stepX;
|
|
currentProcessedActorPtr->zv.ZVX2 += stepX;
|
|
|
|
currentProcessedActorPtr->zv.ZVY1 += stepY;
|
|
currentProcessedActorPtr->zv.ZVY2 += stepY;
|
|
|
|
currentProcessedActorPtr->zv.ZVZ1 += stepZ;
|
|
currentProcessedActorPtr->zv.ZVZ2 += stepZ;
|
|
} // end of movement management
|
|
|
|
if(!currentProcessedActorPtr->YHandler.numSteps)
|
|
{
|
|
// fall management ?
|
|
currentProcessedActorPtr->worldY += currentProcessedActorPtr->stepY;
|
|
currentProcessedActorPtr->roomY += currentProcessedActorPtr->stepY;
|
|
|
|
currentProcessedActorPtr->stepY = 0;
|
|
|
|
if(currentProcessedActorPtr->objectType & AF_FALLABLE)
|
|
{
|
|
zvPtr = ¤tProcessedActorPtr->zv;
|
|
|
|
copyZv(zvPtr, &zvLocal);
|
|
|
|
zvLocal.ZVY2 += 100;
|
|
|
|
if(currentProcessedActorPtr->roomY < -10 && !AsmCheckListCol(&zvLocal,&roomDataTable[currentProcessedActorPtr->room]) && !manageFall(currentProcessedActorIdx,&zvLocal))
|
|
{
|
|
InitRealValue(0, 2000, 40, ¤tProcessedActorPtr->YHandler);
|
|
}
|
|
else
|
|
{
|
|
currentProcessedActorPtr->falling = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((currentProcessedActorPtr->YHandler.numSteps != -1) && (currentProcessedActorPtr->objectType & AF_FALLABLE))
|
|
{
|
|
currentProcessedActorPtr->falling = 1;
|
|
}
|
|
}
|
|
|
|
for(int i=0; i<3; i++)
|
|
{
|
|
int collisionIndex = localTable[i];
|
|
|
|
if(collisionIndex != -1)
|
|
{
|
|
tObject* actorTouchedPtr = &objectTable[collisionIndex];
|
|
|
|
if(actorTouchedPtr->objectType & AF_MOVABLE)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<3;i++)
|
|
{
|
|
if(currentProcessedActorPtr->COL[i] == collisionIndex)
|
|
break;
|
|
}
|
|
|
|
if(i == 3)
|
|
{
|
|
actorTouchedPtr->objectType &= ~AF_ANIMATED;
|
|
addActorToBgInscrust(collisionIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(currentProcessedActorPtr->END_FRAME) // key frame change
|
|
{
|
|
currentProcessedActorPtr->frame++;
|
|
|
|
if(currentProcessedActorPtr->frame >= currentProcessedActorPtr->numOfFrames) // end of anim ?
|
|
{
|
|
currentProcessedActorPtr->flagEndAnim = 1; // end of anim
|
|
currentProcessedActorPtr->frame = 0; // restart anim
|
|
|
|
if(!(currentProcessedActorPtr->animType & 1) && (currentProcessedActorPtr->newAnim == -1)) // is another anim waiting ?
|
|
{
|
|
currentProcessedActorPtr->animType &= 0xFFFD;
|
|
|
|
InitAnim(currentProcessedActorPtr->animInfo, 1, -1);
|
|
}
|
|
}
|
|
currentProcessedActorPtr->worldX += currentProcessedActorPtr->stepX;
|
|
currentProcessedActorPtr->roomX += currentProcessedActorPtr->stepX;
|
|
|
|
currentProcessedActorPtr->worldZ += currentProcessedActorPtr->stepZ;
|
|
currentProcessedActorPtr->roomZ += currentProcessedActorPtr->stepZ;
|
|
|
|
currentProcessedActorPtr->stepX = 0;
|
|
currentProcessedActorPtr->stepZ = 0;
|
|
|
|
currentProcessedActorPtr->animNegX = 0;
|
|
currentProcessedActorPtr->animNegY = 0;
|
|
currentProcessedActorPtr->animNegZ = 0;
|
|
}
|
|
else // not the end of anim
|
|
{
|
|
if((currentProcessedActorPtr->ANIM == -1) && (currentProcessedActorPtr->speed != 0) && (currentProcessedActorPtr->speedChange.numSteps == 0))
|
|
{
|
|
currentProcessedActorPtr->worldX += currentProcessedActorPtr->stepX;
|
|
currentProcessedActorPtr->roomX += currentProcessedActorPtr->stepX;
|
|
|
|
currentProcessedActorPtr->worldZ += currentProcessedActorPtr->stepZ;
|
|
currentProcessedActorPtr->roomZ += currentProcessedActorPtr->stepZ;
|
|
|
|
currentProcessedActorPtr->stepX = 0;
|
|
currentProcessedActorPtr->stepZ = 0;
|
|
|
|
InitRealValue(0,currentProcessedActorPtr->speed,60,¤tProcessedActorPtr->speedChange);
|
|
}
|
|
|
|
currentProcessedActorPtr->flagEndAnim = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void StockInterAnim(sFrame& buffer, sBody* bodyPtr)
|
|
{
|
|
if(bodyPtr->m_flags & INFO_ANIM)
|
|
{
|
|
*(u16*)(bodyPtr->m_scratchBuffer.data()+4) = (u16)timer;
|
|
bodyPtr->startAnim = &buffer;
|
|
|
|
buffer.m_groups.resize(bodyPtr->m_groups.size());
|
|
for (int i = 0; i < bodyPtr->m_groups.size(); i++) {
|
|
buffer.m_groups[i] = bodyPtr->m_groups[i].m_state;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResetStartAnim(sBody* bodyPtr) {
|
|
*(u16*)(bodyPtr->m_scratchBuffer.data() + 4) = (u16)timer; // reset timer
|
|
bodyPtr->startAnim = nullptr;
|
|
}
|
|
|
|
s16 GetNbFramesAnim(sAnimation* animPtr)
|
|
{
|
|
return animPtr->m_numFrames;
|
|
}
|
|
|
|
s16 PatchType(sGroupState* bodyPtr, u16 type) // local
|
|
{
|
|
bodyPtr->m_type = type;
|
|
|
|
return(bodyPtr->m_type);
|
|
}
|
|
|
|
void PatchInterAngle(s16* value, s16 previousValue, s16 nextValue, int bp, int bx) // local
|
|
{
|
|
s16 diff = nextValue - previousValue;
|
|
|
|
if(diff == 0)
|
|
{
|
|
*value = nextValue;
|
|
}
|
|
else
|
|
{
|
|
if(diff <= 0x200)
|
|
{
|
|
if(diff >= -0x200)
|
|
{
|
|
*value = ((diff*bp)/bx) + previousValue;
|
|
}
|
|
else
|
|
{
|
|
nextValue += 0x400;
|
|
nextValue -= previousValue;
|
|
|
|
*value = ((nextValue *bp)/bx) + previousValue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
previousValue += 0x400;
|
|
nextValue -= previousValue;
|
|
|
|
*value = ((nextValue *bp)/bx) + previousValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PatchInterStep(s16* value, s16 previousValue, s16 nextValue, int bp, int bx) // local
|
|
{
|
|
s16 cx = previousValue;
|
|
s16 ax = nextValue;
|
|
|
|
if(ax == cx)
|
|
{
|
|
*value = ax;
|
|
}
|
|
else
|
|
{
|
|
*value = (((ax - cx)*bp)/bx) + cx;
|
|
}
|
|
}
|
|
|
|
s16 SetInterAnimObjet(int frame, sAnimation* pAnim, sBody* pBody)
|
|
{
|
|
int numOfBonesInAnim = pAnim->m_numGroups;
|
|
u16 keyframeLength;
|
|
u16 timeOfKeyframeStart;
|
|
int ax;
|
|
u16 bx;
|
|
u16 time;
|
|
int bp;
|
|
int flag;
|
|
|
|
flag = pBody->m_flags;
|
|
|
|
sFrame* pKeyframe = &pAnim->m_frames[frame];
|
|
|
|
keyframeLength = pKeyframe->m_timestamp; // keyframe length
|
|
|
|
if(!(pBody->m_flags & INFO_ANIM)) // do not anim if the model can't be animated
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
timeOfKeyframeStart = *(u16*)(pBody->m_scratchBuffer.data() + 4); // time of start of keyframe
|
|
|
|
sFrame* pPreviousKeyframe = pBody->startAnim;
|
|
|
|
if(!pPreviousKeyframe)
|
|
{
|
|
pPreviousKeyframe = pKeyframe;
|
|
}
|
|
|
|
if(numOfBonesInAnim > pBody->m_groupOrder.size())
|
|
{
|
|
numOfBonesInAnim = pBody->m_groupOrder.size();
|
|
}
|
|
|
|
time = (u16)timer - timeOfKeyframeStart;
|
|
|
|
bx = keyframeLength;
|
|
bp = time;
|
|
|
|
if(time<keyframeLength) // interpolate keyframe
|
|
{
|
|
if(!(flag&INFO_OPTIMISE))
|
|
{
|
|
for (int i = 0; i < numOfBonesInAnim; i++)
|
|
{
|
|
point3dStruct& state = pBody->m_groups[i].m_state.m_delta;
|
|
point3dStruct& previousState = pPreviousKeyframe->m_groups[i].m_delta;
|
|
point3dStruct& nextState = pKeyframe->m_groups[i].m_delta;
|
|
switch(PatchType(&pBody->m_groups[i].m_state, pKeyframe->m_groups[i].m_type))
|
|
{
|
|
case 0: // rotate
|
|
PatchInterAngle(&state.x, previousState.x, nextState.x, bp, bx);
|
|
PatchInterAngle(&state.y, previousState.y, nextState.y, bp, bx);
|
|
PatchInterAngle(&state.z, previousState.z, nextState.z, bp, bx);
|
|
break;
|
|
case 1: // translate
|
|
case 2: // zoom
|
|
PatchInterStep(&state.x, previousState.x, nextState.x, bp, bx);
|
|
PatchInterStep(&state.y, previousState.y, nextState.y, bp, bx);
|
|
PatchInterStep(&state.z, previousState.z, nextState.z, bp, bx);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < numOfBonesInAnim; i++)
|
|
{
|
|
point3dStruct& state = pBody->m_groups[i].m_state.m_delta;
|
|
point3dStruct& previousState = pPreviousKeyframe->m_groups[i].m_delta;
|
|
point3dStruct& nextState = pKeyframe->m_groups[i].m_delta;
|
|
switch (PatchType(&pBody->m_groups[i].m_state, pKeyframe->m_groups[i].m_type))
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
PatchInterStep(&state.x, previousState.x, nextState.x, bp, bx);
|
|
PatchInterStep(&state.y, previousState.y, nextState.y, bp, bx);
|
|
PatchInterStep(&state.z, previousState.z, nextState.z, bp, bx);
|
|
break;
|
|
}
|
|
|
|
{
|
|
point3dStruct& state = pBody->m_groups[i].m_state.m_rotateDelta.value();
|
|
point3dStruct& previousState = pPreviousKeyframe->m_groups[i].m_rotateDelta.value();
|
|
point3dStruct& nextState = pKeyframe->m_groups[i].m_rotateDelta.value();
|
|
|
|
PatchInterAngle(&state.x, previousState.x, nextState.x, bp, bx);
|
|
PatchInterAngle(&state.y, previousState.y, nextState.y, bp, bx);
|
|
PatchInterAngle(&state.z, previousState.z, nextState.z, bp, bx);
|
|
}
|
|
}
|
|
}
|
|
|
|
animStepX = (pKeyframe->m_animStep.x * bp) / bx;
|
|
animStepY = (pKeyframe->m_animStep.y * bp) / bx;
|
|
animStepZ = (pKeyframe->m_animStep.z * bp) / bx;
|
|
|
|
animCurrentTime = bx;
|
|
animKeyframeLength = bp;
|
|
return(0);
|
|
}
|
|
else // change keyframe
|
|
{
|
|
for (int i = 0; i < numOfBonesInAnim; i++)
|
|
{
|
|
sGroupState& nextState = pKeyframe->m_groups[i];
|
|
pBody->m_groups[i].m_state = nextState;
|
|
};
|
|
|
|
pBody->startAnim = pKeyframe;
|
|
|
|
*(u16*)(pBody->m_scratchBuffer.data()+4) = (u16)timer;
|
|
|
|
animCurrentTime = bx;
|
|
animKeyframeLength = bx;
|
|
|
|
animStepX = pKeyframe->m_animStep.x;
|
|
animStepY = pKeyframe->m_animStep.y;
|
|
animStepZ = pKeyframe->m_animStep.z;
|
|
return(1);
|
|
}
|
|
|
|
}
|