scummvm/engines/watchmaker/walk/act.cpp
2024-09-20 23:28:32 +02:00

784 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 "watchmaker/walk/act.h"
#include "watchmaker/t3d.h"
#include "watchmaker/globvar.h"
#include "watchmaker/define.h"
#include "watchmaker/3d/math/llmath.h"
#include "watchmaker/walk/walk.h"
#include "watchmaker/3d/geometry.h"
#include "watchmaker/3d/loader.h"
#include "watchmaker/3d/animation.h"
#include "watchmaker/3d/t3d_body.h"
#include "watchmaker/message.h"
#include "watchmaker/schedule.h"
#include "watchmaker/ll/ll_anim.h"
#include "watchmaker/windows_hacks.h"
#include "watchmaker/walk/walkutil.h"
namespace Watchmaker {
int32 NumCurve;
void FixupCurAction(int32 oc);
/* -----------------28/04/98 17.51-------------------
* SlideChar
* --------------------------------------------------*/
void SlideChar(int32 oc) {
t3dCHARACTER *Ch = Character[oc];
t3dWALK *w = &Ch->Walk;
t3dF32 r, len, x1, x2, z1, z2;
int16 nf;
t3dV3F v;
if (/*!( w->Check & CLICKINTO ) &&*/ (w->CurPanel < 0)) {
CharStop(oc);
return ;
}
v.x = w->Look.x;
v.y = 0.0f;
v.z = w->Look.z;
x1 = w->Panel[w->CurPanel].a.x;
z1 = w->Panel[w->CurPanel].a.z;
x2 = w->Panel[w->CurPanel].b.x;
z2 = w->Panel[w->CurPanel].b.z;
if ((len = (x1 - x2) * (x1 - x2) + (z1 - z2) * (z1 - z2)) == 0) {
CharStop(oc);
return ;
}
r = ((z1 - v.z) * (z1 - z2) - (x1 - v.x) * (x2 - x1)) / len;
if (r > 1.0f) { // a destra di 2
x1 = x2;
z1 = z2;
} else if (r > 0.0f) { // dentro 1..2
x1 += r * (x2 - x1);
z1 += r * (z2 - z1);
}
nf = w->CurFrame + 1;
if ((w->CurAction == aWALK_START) || (w->CurAction == aWALK_LOOP) || (w->CurAction == aWALK_END)) {
if (nf >= (ActionStart[aWALK_LOOP] + ActionLen[aWALK_LOOP]))
nf = ActionStart[aWALK_LOOP];
} else if ((w->CurAction == aBACK_START) || (w->CurAction == aBACK_LOOP) || (w->CurAction == aBACK_END)) {
if (nf >= (ActionStart[aBACK_LOOP] + ActionLen[aBACK_LOOP]))
nf = ActionStart[aBACK_LOOP];
} else if ((w->CurAction == aRUN_START) || (w->CurAction == aRUN_LOOP) || (w->CurAction == aRUN_END)) {
if (nf >= (ActionStart[aRUN_LOOP] + ActionLen[aRUN_LOOP]))
nf = ActionStart[aRUN_LOOP];
}
w->NumPathNodes = w->CurrentStep = 0;
w->WalkSteps[0].curp = w->CurPanel;
w->WalkSteps[0].Angle = SinCosAngle(Ch->Dir.x, Ch->Dir.z);
w->WalkSteps[0].Frame = nf;
w->WalkSteps[0].Pos.x = x1;
w->WalkSteps[0].Pos.y = CurFloorY;
w->WalkSteps[0].Pos.z = z1;
w->WalkSteps[1].Act = 0;
w->NumSteps = 1;
}
/* -----------------07/05/98 11.15-------------------
* UpdateChar
* --------------------------------------------------*/
void UpdateChar(WGame &game, int32 oc, t3dF32 Speed, t3dF32 Rot) {
t3dCHARACTER *Char = Character[oc];
t3dWALK *w = &Char->Walk;
t3dV3F Pos, tmp;
t3dM3X3F mx;
if (!Char) return ;
if ((Speed == 0.0f) && (w->NumSteps == 0) && ((w->CurAction != aROT_DX && w->CurAction != aROT_SX) || (Rot == 0.0f))) {
if ((Char->Mesh->Flags & T3D_MESH_DEFAULTANIM))
CharStop(oc);
return;
}
_vm->_messageSystem.doEvent(EventClass::MC_MOUSE, ME_MOUSEHIDE, MP_DEFAULT, 0, 0, 0, NULL, NULL, NULL);
if (Char && Speed)
CharNextFrame(game, oc);
// Ruota l'omino
t3dVectCopy(&tmp, &Char->Dir);
tmp.z = -tmp.z;
tmp.y = 0.0f;
t3dVectAdd(&tmp, &Char->Pos, &tmp);
t3dMatView(&Char->Mesh->Matrix, &Char->Pos, &tmp);
t3dMatRot(&mx, 0.0f, Rot, 0.0f);
t3dMatMul(&Char->Mesh->Matrix, &mx, &Char->Mesh->Matrix);
Char->Mesh->Matrix.Flags &= ~T3D_MATRIX_IDENTITY;
t3dVectInit(&Char->Dir, 0.0f, 0.0f, -1.0f);
t3dVectTransform(&Char->Dir, &Char->Dir, &Char->Mesh->Matrix); //rotate by Character angle
if (Speed) {
FloorHit = 1;
Pos.y = CurFloorY;
if (Speed > 0.0f) {
if (bFastWalk) {
if ((w->CurFrame >= ActionStart[aRUN_END]) || (w->CurFrame < ActionStart[aRUN_START]))
w->CurFrame = ActionStart[aRUN_START];
} else if ((w->CurFrame >= ActionStart[aWALK_END]) || (w->CurFrame < ActionStart[aWALK_START]))
w->CurFrame = ActionStart[aWALK_START];
} else if ((Speed < 0.0f) && ((w->CurFrame >= ActionStart[aBACK_END]) || (w->CurFrame < ActionStart[aBACK_START])))
w->CurFrame = ActionStart[aBACK_START];
Speed = - Char->Mesh->DefaultAnim.Dist[w->CurFrame + 1] + Char->Mesh->DefaultAnim.Dist[w->CurFrame];
FixupCurAction(ocCURPLAYER);
tmp = Char->Dir * Speed;
t3dVectAdd(&Pos, &Char->Pos, &tmp);
PlayerPos[CurPlayer + ocDARRELL] = 0;
PlayerGotoPos[CurPlayer + ocDARRELL] = 0;
CheckCharacterWithBounds(game, oc, &Pos, 0, (uint8)((Speed < 0.0f) ? 2 : (bFastWalk ? 1 : 0)));
if (!(Char->Walk.Check & CLICKINTO) && (Char->Walk.NumSteps)) {
// fa solo 2 frames: il primo come l'attuale
Char->Walk.WalkSteps[1].curp = Char->Walk.WalkSteps[Char->Walk.NumSteps - 1].curp;
Char->Walk.WalkSteps[0].curp = Char->Walk.WalkSteps[Char->Walk.NumSteps - 1].curp;
Char->Walk.WalkSteps[1].Angle = Char->Walk.WalkSteps[0].Angle;
Char->Walk.WalkSteps[0].Angle = Char->Walk.WalkSteps[0].Angle;
Char->Walk.WalkSteps[2].Act = 0;
Char->Walk.NumSteps = 2;
Char->Walk.CurrentStep = 0;
} else
SlideChar(oc);
game._messageSystem.removeEvent(EventClass::MC_PLAYER, ME_ALL);
_vm->_messageSystem.doEvent(EventClass::MC_PLAYER, ME_PLAYERGOTO, MP_DEFAULT, 0, 0, 0, NULL, NULL, NULL);
}
}
/* -----------------28/05/98 10.38-------------------
* CharStop
* --------------------------------------------------*/
void CharStop(int32 oc) {
t3dCHARACTER *Char = Character[oc];
t3dV3F tmp;
if (!Char) return;
if ((Char->Mesh->CurFrame <= ActionStart[aSTAND]) && (Char->Mesh->CurFrame > 0)) return ;
if (Char->Walk.CurAction != aSTAND)
Char->Mesh->BlendPercent = 0;
Char->Walk.NumPathNodes = Char->Walk.CurrentStep = Char->Walk.NumSteps = 0;
Char->Walk.CurAction = aSTAND;
Char->Walk.CurFrame = ActionStart[aSTAND];
Char->Mesh->CurFrame = Char->Walk.CurFrame;
// Char->Pos.y = Char->Mesh->Trasl.y = CurFloorY;
t3dVectCopy(&tmp, &Char->Dir);
tmp.z = -tmp.z;
tmp.y = 0.0f;
t3dVectAdd(&tmp, &Char->Pos, &tmp);
t3dMatView(&Char->Mesh->Matrix, &Char->Pos, &tmp);
Char->Mesh->Matrix.Flags &= ~T3D_MATRIX_IDENTITY;
}
/* -----------------28/05/98 10.38-------------------
* CharSetPosition
* --------------------------------------------------*/
void CharSetPosition(int32 oc, uint8 pos, const char *room) {
t3dBODY *OldCurRoom = t3dCurRoom;
t3dCHARACTER *Char = Character[oc];
t3dV3F tmp;
CharStop(oc);
if (pos == 99) return;
if (room && (room[0] != '\0')) {
t3dBODY *roomPtr = _vm->_roomManager->getRoomIfLoaded(room);
if (roomPtr) {
t3dCurRoom = roomPtr;
}
}
if (pos) {
GetLightDirection(&tmp, pos);
if ((oc == ocCURPLAYER) || (oc == ocDARRELL && !CurPlayer) || (oc == ocVICTORIA && CurPlayer)) {
if ((PlayerPos[CurPlayer + ocDARRELL] = GetLightPosition(&Char->Pos, pos)) == 0) {
t3dCurRoom = OldCurRoom;
return ;
}
PlayerGotoPos[CurPlayer + ocDARRELL] = 0;
} else
PlayerPos[oc] = GetLightPosition(&Char->Pos, pos);
}
t3dVectCopy(&Char->Mesh->Trasl, &Char->Pos);
// Ruota l'omino
t3dVectSub(&tmp, &tmp, &Char->Pos);
tmp.z = -tmp.z;
tmp.y = 0.0f;
t3dVectAdd(&tmp, &Char->Pos, &tmp);
t3dMatView(&Char->Mesh->Matrix, &Char->Pos, &tmp);
Char->Mesh->Matrix.Flags &= ~T3D_MATRIX_IDENTITY;
Char->Dir.x = 0.0f; //first frame direction
Char->Dir.y = 0.0f;
Char->Dir.z = -1.0f;
t3dVectTransform(&Char->Dir, &Char->Dir, &Char->Mesh->Matrix); //rotate by Character angle
t3dCurRoom = OldCurRoom;
}
/* -----------------23/03/99 12.00-------------------
* CheckCharacterWithoutBounds
* --------------------------------------------------*/
void CheckCharacterWithoutBounds(WGame &game, int32 oc, const uint8 *dpl, uint8 back) {
t3dCHARACTER *Char = Character[oc];
t3dWALK *w = &Char->Walk;
t3dV3F tmp;
uint8 dp;
if (!Char) return;
StopObjAnim(game, oc);
// Reset some vars
if (!(Char->Mesh->Flags & T3D_MESH_DEFAULTANIM))
FixPos(oc);
Char->Walk.Panel = t3dCurRoom->Panel[t3dCurRoom->CurLevel];
Char->Walk.PanelNum = t3dCurRoom->NumPanels[t3dCurRoom->CurLevel];
if (t3dCurRoom) {
CurFloorY = t3dCurRoom->PanelHeight[t3dCurRoom->CurLevel];
}
Char->Mesh->Flags |= T3D_MESH_DEFAULTANIM;
t3dVectCopy(&Char->Pos, &Char->Mesh->Trasl);
w->NumPathNodes = 0;
w->PathNode[w->NumPathNodes].pos.x = Char->Pos.x;
w->PathNode[w->NumPathNodes].pos.z = Char->Pos.z;
w->PathNode[w->NumPathNodes].oldp = w->CurPanel;
w->PathNode[w->NumPathNodes].curp = -1;
w->PathNode[w->NumPathNodes].dist = 0.0f;
w->NumPathNodes ++;
w->CurPanel = -1;
w->Check = NOBOUNDCHECK | NOTSKIPPABLE;
dp = 0;
while (*dpl && GetLightPosition(&tmp, *dpl)) {
dp = *dpl++;
w->PathNode[w->NumPathNodes].pos.x = tmp.x;
w->PathNode[w->NumPathNodes].pos.z = tmp.z;
w->PathNode[w->NumPathNodes].oldp = -1;
w->PathNode[w->NumPathNodes].curp = -1;
w->PathNode[w->NumPathNodes].dist = t3dVectDistance(&tmp, &Char->Pos);
w->NumPathNodes ++;
Char->Walk.Cur.x = tmp.x;
Char->Walk.Cur.z = tmp.z;
}
bNotSkippableWalk = TRUE;
BuildStepList(oc, dp, back);
_vm->_messageSystem.deleteWaitingMsgs(MP_WAIT_PORTAL);
_vm->_messageSystem.deleteWaitingMsgs(MP_WAIT_ANIM);
_vm->_messageSystem.deleteWaitingMsgs(MP_WAIT_ACT);
}
/* -----------------01/07/98 16.10-------------------
* FixPos
* --------------------------------------------------*/
void FixPos(int32 oc) {
t3dCHARACTER *Ch = Character[oc];
t3dMESH *mesh = Ch->Mesh;
if (t3dCurRoom) {
CurFloorY = t3dCurRoom->PanelHeight[t3dCurRoom->CurLevel];
}
mesh->Trasl.y = CurFloorY;
t3dVectCopy(&Ch->Pos, &mesh->Trasl);
t3dVectInit(&Ch->Dir, 0.0f, 0.0f, -1.0f);
t3dVectTransform(&Ch->Dir, &Ch->Dir, &Ch->Mesh->Matrix); //rotate by Character angle
if (oc == ocCURPLAYER) {
PlayerPos[CurPlayer + ocDARRELL] = 0;
PlayerGotoPos[CurPlayer + ocDARRELL] = 0;
} else {
PlayerPos[oc] = 0;
PlayerGotoPos[oc] = 0;
}
CharStop(oc);
}
/* -----------------27/04/98 15.12-------------------
* BuildStepList
* --------------------------------------------------*/
void BuildStepList(int32 oc, uint8 dp, uint8 back) {
t3dCHARACTER *Ch = Character[oc];
t3dWALK *w = &Ch->Walk;
int16 LastStep, CurF;
t3dF32 len, curlen, startpos, angle, approx;
t3dV3F st, en, direction;
t3dF32 lastangle, *dist, bc;
int16 ws, wl, we;
int32 i, j, na, nla, nca;
if (!Ch || !w) return;
for (int step = 0; step < T3D_MAX_WALKSTEPS; step++) {
w->WalkSteps[step] = t3dSTEPS();
}
if (w->NumPathNodes < 2) {
w->NumSteps = 0;
w->CurrentStep = 0;
w->NumPathNodes = 0;
w->Check = 0;
return ;
}
len = 0.0;
curlen = 0.0;
startpos = 0.0;
lastangle = SinCosAngle(Ch->Dir.x, Ch->Dir.z);
// calcola lunghezza totale del percorso
for (i = 0; i < w->NumPathNodes - 1; i++) {
st.x = w->PathNode[i].pos.x;
st.y = 0.0;
st.z = w->PathNode[i].pos.z;
en.x = w->PathNode[i + 1].pos.x;
en.y = 0.0;
en.z = w->PathNode[i + 1].pos.z;
len += t3dVectDistance(&st, &en); // dist of two points
}
// Se il percorso e' piu' lungo di mezzo omino seleziona modalita' percorso lungo
if (fabs(len) > (ONE_STEP)) w->Check |= LONGPATH;
// Cerca di capire se gli conviene andare avanti o indietro
if (back >= 10) {
t3dVectInit(&st, w->PathNode[1].pos.x - w->PathNode[0].pos.x, 0.0f, w->PathNode[1].pos.z - w->PathNode[0].pos.z);
if (!(w->Check & LONGPATH) && (fabs(t3dVectAngle(&Ch->Dir, &st)) > 145.0f)) { // devo andare dietro
// DebugFile("Back %f\n%f %f | %f %f\n",t3dVectAngle( &Ch->Dir, &st ),Ch->Dir.x,Ch->Dir.z,st.x,st.z);
back = 2;
if ((dp) && (GetLightDirection(&st, dp)) && (st.x != 0.0f) && (st.z != 0.0f) &&
(GetLightPosition(&en, dp)) && (en.x != 0.0f) && (en.z != 0.0f)) {
t3dVectSub(&en, &st, &en);
if (fabs(t3dVectAngle(&Ch->Dir, &en)) > 145.0f)
back = 0;
}
} else {
if (fabs(len) > 40.0f * ONE_STEP)
back = 1;
else
back = 0;
}
if (bFastWalk && !back) back = 1;
}
// Seleziona azioni per camminare avanti o indietro
if (back == 1) {
ws = aRUN_START;
wl = aRUN_LOOP;
we = aRUN_END;
bc = 1.0f;
} else if (back == 2) {
ws = aBACK_START;
wl = aBACK_LOOP;
we = aBACK_END;
bc = -1.0f;
} else {
ws = aWALK_START;
wl = aWALK_LOOP;
we = aWALK_END;
bc = 1.0f;
}
LastStep = 0;
CurF = w->CurFrame;
dist = Ch->Mesh->DefaultAnim.Dist;
if ((CurF < ActionStart[ws]) || (CurF >= ActionStart[we])) CurF = ActionStart[ws];
if (CurF <= ActionStart[ws]) startpos = bc * dist[ActionStart[aSTAND]];
else startpos = bc * dist[CurF - 1];
// decide quanti frame fare e quali frame fare
while (curlen <= len) {
if (CurF == ActionStart[we]) {
startpos = (startpos - bc * dist[CurF]);
CurF = ActionStart[wl];
startpos = bc * dist[CurF] + startpos;
}
w->WalkSteps[LastStep].Act = wl;
w->WalkSteps[LastStep].Frame = CurF;
w->WalkSteps[LastStep++].Pos.y = curlen;
curlen += startpos - bc * dist[CurF];
startpos = bc * dist[CurF++];
if (LastStep > T3D_MAX_WALKSTEPS - 5) break;
}
if (CurF == ActionStart[we]) CurF = ActionStart[wl];
w->WalkSteps[LastStep].Act = wl;
w->WalkSteps[LastStep].Frame = CurF;
len = 0.0;
curlen = 0.0;
startpos = 0.0;
w->NumSteps = 0;
w->CurrentStep = 0;
w->WalkSteps[w->NumSteps].Angle = lastangle;
w->WalkSteps[w->NumSteps].Pos.x = w->PathNode[0].pos.x;
w->WalkSteps[w->NumSteps].Pos.y = CurFloorY;
w->WalkSteps[w->NumSteps].Pos.z = w->PathNode[0].pos.z;
w->WalkSteps[w->NumSteps++].curp = w->OldPanel;
for (i = 0; i < w->NumPathNodes - 1; i++) {
st.x = w->PathNode[i].pos.x;
st.y = 0.0;
st.z = w->PathNode[i].pos.z;
en.x = w->PathNode[i + 1].pos.x;
en.y = 0.0;
en.z = w->PathNode[i + 1].pos.z;
len += t3dVectDistance(&st, &en); // dist of two points
t3dVectSub(&direction, &en, &st);
t3dVectNormalize(&direction); // normalize direction
angle = SinCosAngle(bc * direction.x, bc * direction.z); //calc angles between new direction and first frame direction
lastangle = angle;
while ((w->WalkSteps[w->NumSteps].Pos.y <= len) && (w->NumSteps < LastStep)) {
curlen = w->WalkSteps[w->NumSteps].Pos.y;
t3dVectCopy(&w->WalkSteps[w->NumSteps].Pos, &st);
w->WalkSteps[w->NumSteps].Pos.x += (curlen - startpos) * direction.x;
w->WalkSteps[w->NumSteps].Pos.y = CurFloorY;
w->WalkSteps[w->NumSteps].Pos.z += (curlen - startpos) * direction.z;
w->WalkSteps[w->NumSteps].Angle = angle;
w->WalkSteps[w->NumSteps].curp = w->PathNode[i].curp;
w->NumSteps ++;
}
startpos = len;
}
if ((dp) && (GetLightDirection(&st, dp)) && (st.x != 0.0f) && (st.z != 0.0f)) {
lastangle = SinCosAngle((st.x - w->Cur.x), (st.z - w->Cur.z));
// DebugLogFile("LastPos %d | AN %d | %f %f", dp, lastangle, st.x, st.z );
}
w->WalkSteps[w->NumSteps].Angle = lastangle;
w->WalkSteps[w->NumSteps].Pos.x = w->Cur.x;
w->WalkSteps[w->NumSteps].Pos.y = CurFloorY;
w->WalkSteps[w->NumSteps].Pos.z = w->Cur.z;
w->WalkSteps[w->NumSteps++].curp = w->CurPanel;
// arrotonda la fine
if ((w->NumSteps > 2)) {
// FIXME: The following code should be checked for correct intended logic as
// it's previous form had sequence point issues.
angle = lastangle;
lastangle = w->WalkSteps[w->NumSteps - 2].Angle;
if (angle != lastangle) {
approx = angle - lastangle;
if (approx > T3D_PI) approx = -T3D_PI * 2 + approx;
else if (approx < -T3D_PI) approx = T3D_PI * 2 + approx;
approx /= 4.0f;
if (--LastStep > 0) w->WalkSteps[LastStep].Angle = angle - approx * 1.0f;
if (--LastStep > 0) w->WalkSteps[LastStep].Angle = angle - approx * 2.0f;
if (--LastStep > 0) w->WalkSteps[LastStep].Angle = angle - approx * 3.0f;
}
}
if (LastStep < 0) LastStep = 0;
lastangle = w->WalkSteps[0].Angle;
// fa le curve
NumCurve = 14;
for (i = 1; i < LastStep; i++) {
angle = w->WalkSteps[i].Angle;
// se ha fatto una curva
if (angle != lastangle) {
// calcola variazione di angoli
approx = angle - lastangle;
if (approx > T3D_PI) approx = -T3D_PI * 2 + approx;
else if (approx < -T3D_PI) approx = T3D_PI * 2 + approx;
// calcola in quanti frames puo' avvenire la variazione
for (nla = 1; nla < (NumCurve / 2); nla++)
if ((i - nla) > 0)
if (w->WalkSteps[i - nla].Angle != lastangle)
break;
for (nca = 1; nca < (NumCurve / 2); nca++)
if ((i + nca) < LastStep)
if (w->WalkSteps[i + nca].Angle != angle)
break;
na = (nla - 1) + (nca - 1) + 1;
// calcola il delta dell'andolo
approx /= (float)(na);
// aggiorna frames
for (j = -(nla - 1), na = 0; j < nca; j++, na++)
if (((i + j) > 0) && ((i + j) < LastStep))
w->WalkSteps[i + j].Angle = lastangle + approx * (float)(na);
i += (nca - 1);
//DebugFile("%d: %6f %6f %6f",i,w->WalkSteps[i-1].Angle,w->WalkSteps[i].Angle,w->WalkSteps[i+1].Angle);
}
lastangle = angle;
}
}
/* -----------------23/03/99 12.03-------------------
* CheckPathNodes
* --------------------------------------------------*/
int32 CheckPathNodes(int32 oc) {
t3dCHARACTER *Ch = Character[oc];
t3dWALK *w = &Ch->Walk;
int32 i;
uint16 b;
if (!Ch || !w) return FALSE;
// se interseca almeno un baffo si ferma!!
for (i = 1; i < w->NumPathNodes; i++) {
for (b = 0; b < w->PanelNum; b++) {
PointResult res = IntersLineLine(w->Panel[b].backA, w->Panel[b].backB,
w->PathNode[i - 1].pos, w->PathNode[i].pos);
if (res.isValid) {
w->NumPathNodes = i - 1;
w->CurPanel = w->PathNode[i - 1].curp;
w->NumSteps = 0;
w->CurrentStep = 0;
w->NumPathNodes = 0;
w->Check = 0;
return FALSE;
}
}
}
return TRUE;
}
/* -----------------17/03/98 16.30-------------------
* CheckCharacterWithBounds
* --------------------------------------------------*/
bool CheckCharacterWithBounds(WGame &game, int32 oc, t3dV3F *Pos, uint8 dp, uint8 back) {
t3dCHARACTER *Char = Character[oc];
int32 st;
t3dV3F tmp;
t3dPAN *p;
if (!Char) return FALSE;
StopObjAnim(game, oc);
Char->Walk.Cur.x = Pos->x;
Char->Walk.Cur.z = Pos->z;
// Reset some vars
if (!(Char->Mesh->Flags & T3D_MESH_DEFAULTANIM))
FixPos(oc);
Char->Walk.Panel = t3dCurRoom->Panel[t3dCurRoom->CurLevel];
Char->Walk.PanelNum = t3dCurRoom->NumPanels[t3dCurRoom->CurLevel];
if (t3dCurRoom) {
CurFloorY = t3dCurRoom->PanelHeight[t3dCurRoom->CurLevel];
}
for (int i = 0; i < T3D_MAX_CHARACTERS; i++) {
// If the character is not hidden and has panels, adds them
if (Character[i] && (Character[i] != Char) && !(Character[i]->Flags & (T3D_CHARACTER_HIDE | T3D_CHARACTER_BNDHIDE)) && (p = Character[i]->Body->Panel[0])) {
st = Char->Walk.PanelNum;
for (int j = 0; j < Character[i]->Body->NumPanels[0]; j++, p++, Char->Walk.PanelNum++) {
tmp.x = p->a.x;
tmp.y = CurFloorY;
tmp.z = p->a.z;
t3dVectTransform(&tmp, &tmp, &Character[i]->Mesh->Matrix);
t3dVectAdd(&tmp, &tmp, &Character[i]->Mesh->Trasl);
Char->Walk.Panel[Char->Walk.PanelNum].a.x = tmp.x;
Char->Walk.Panel[Char->Walk.PanelNum].a.z = tmp.z;
tmp.x = p->b.x;
tmp.y = CurFloorY;
tmp.z = p->b.z;
t3dVectTransform(&tmp, &tmp, &Character[i]->Mesh->Matrix);
t3dVectAdd(&tmp, &tmp, &Character[i]->Mesh->Trasl);
Char->Walk.Panel[Char->Walk.PanelNum].b.x = tmp.x;
Char->Walk.Panel[Char->Walk.PanelNum].b.z = tmp.z;
tmp.x = p->backA.x;
tmp.y = CurFloorY;
tmp.z = p->backA.z;
t3dVectTransform(&tmp, &tmp, &Character[i]->Mesh->Matrix);
t3dVectAdd(&tmp, &tmp, &Character[i]->Mesh->Trasl);
Char->Walk.Panel[Char->Walk.PanelNum].backA.x = tmp.x;
Char->Walk.Panel[Char->Walk.PanelNum].backA.z = tmp.z;
tmp.x = p->backB.x;
tmp.y = CurFloorY;
tmp.z = p->backB.z;
t3dVectTransform(&tmp, &tmp, &Character[i]->Mesh->Matrix);
t3dVectAdd(&tmp, &tmp, &Character[i]->Mesh->Trasl);
Char->Walk.Panel[Char->Walk.PanelNum].backB.x = tmp.x;
Char->Walk.Panel[Char->Walk.PanelNum].backB.z = tmp.z;
Char->Walk.Panel[Char->Walk.PanelNum].near1 = p->near1 + st;
Char->Walk.Panel[Char->Walk.PanelNum].near2 = p->near2 + st;
}
}
}
Char->Mesh->Flags |= T3D_MESH_DEFAULTANIM;
t3dVectCopy(&Char->Pos, &Char->Mesh->Trasl);
FindPath(oc, t3dCurCamera); // Calc path
if (CheckPathNodes(oc)) BuildStepList(oc, dp, back);
_vm->_messageSystem.deleteWaitingMsgs(MP_WAIT_PORTAL);
_vm->_messageSystem.deleteWaitingMsgs(MP_WAIT_ANIM);
_vm->_messageSystem.deleteWaitingMsgs(MP_WAIT_ACT);
if (Char->Walk.NumSteps >= 2) return TRUE;
else return FALSE;
}
/* -----------------29/09/98 15.09-------------------
* CharGotoPosition
* --------------------------------------------------*/
bool CharGotoPosition(WGame &game, int32 oc, uint8 pos, uint8 back, int32 anim) {
t3dV3F tmp;
uint8 cp;
if ((oc == ocCURPLAYER) || (oc == ocDARRELL && !CurPlayer) || (oc == ocVICTORIA && CurPlayer)) {
if ((PlayerPos[CurPlayer + ocDARRELL] == pos) || (PlayerGotoPos[CurPlayer + ocDARRELL] == pos)) return FALSE;
if ((cp = PlayerGotoPos[CurPlayer + ocDARRELL] = GetLightPosition(&tmp, pos)) == 0) return FALSE;
game._messageSystem.removeEvent(EventClass::MC_PLAYER, ME_ALL);
if (bFirstPerson)
_vm->_messageSystem.doEvent(EventClass::MC_CAMERA, ME_CAMERA1TO3, MP_DEFAULT, 0, 0, 0, nullptr, nullptr, nullptr);
_vm->_messageSystem.doEvent(EventClass::MC_PLAYER, ME_PLAYERGOTO, MP_DEFAULT, 0, 0, bFirstPerson, nullptr, nullptr, nullptr);
} else if ((cp = PlayerGotoPos[oc] = GetLightPosition(&tmp, pos)) == 0) return FALSE;
FloorHit = 1;
if (!CheckCharacterWithBounds(game, oc, &tmp, cp, back)) return FALSE;
if (anim)
Character[oc]->Walk.WalkSteps[Character[oc]->Walk.NumSteps].Act = (int16)anim;
return TRUE;
}
/* -----------------30/04/98 10.43-------------------
* FixupCurAction
* --------------------------------------------------*/
void FixupCurAction(int32 oc) {
t3dCHARACTER *Char = Character[oc];
t3dWALK *w = &Char->Walk;
w->CurAction = 1;
while (ActionStart[w->CurAction]) {
if (ActionStart[w->CurAction] > w->CurFrame)
break;
else
w->CurAction ++;
}
w->CurAction --;
}
/* -----------------27/04/98 18.29-------------------
* CharNextFrame
* --------------------------------------------------*/
uint8 CharNextFrame(WGame &game, int32 oc) {
t3dCHARACTER *Char = Character[oc];
int32 an, na, nf;
if (Char == nullptr)
return false;
if (Char->Walk.CurrentStep < Char->Walk.NumSteps) {
t3dVectCopy(&Char->Mesh->Trasl, &Char->Walk.WalkSteps[Char->Walk.CurrentStep].Pos);
t3dVectCopy(&Char->Pos, &Char->Walk.WalkSteps[Char->Walk.CurrentStep].Pos);
na = Char->Walk.WalkSteps[Char->Walk.CurrentStep].Act;
nf = Char->Walk.WalkSteps[Char->Walk.CurrentStep].Frame;
Char->Walk.CurFrame = nf;
Char->Mesh->CurFrame = Char->Walk.CurFrame;
Char->Walk.CurAction = na;
Char->Walk.OldPanel = Char->Walk.CurPanel;
Char->Walk.CurPanel = Char->Walk.WalkSteps[Char->Walk.CurrentStep].curp;
t3dMatRot(&Char->Mesh->Matrix, 0.0f, Char->Walk.WalkSteps[Char->Walk.CurrentStep].Angle + T3D_PI, 0.0f);
Char->Mesh->Matrix.Flags &= ~T3D_MATRIX_IDENTITY;
// rotate direction vector of the actor
Char->Dir.x = 0.0f; //first frame direction
Char->Dir.y = 0.0f;
Char->Dir.z = -1.0f;
t3dVectTransform(&Char->Dir, &Char->Dir, &Char->Mesh->Matrix); //rotate by Character angle
Char->Walk.CurrentStep ++;
if (FastWalk && ((Char->Walk.NumSteps - Char->Walk.CurrentStep) > 5))
Char->Walk.CurrentStep += 2;
FixupCurAction(oc);
if (oc == ocCURPLAYER)
PlayerPos[CurPlayer + ocDARRELL] = 0;
else
PlayerPos[oc] = 0;
return true;
} else {
if (Player == Char) {
an = TheTime + PLAYER_IDLE_TIME;
_vm->_messageSystem.doEvent(EventClass::MC_PLAYER, ME_PLAYERIDLE, MP_WAIT_RETRACE, (int16)(CurPlayer + ocDARRELL), 0, 0, &an, nullptr, nullptr);
PlayerPos[CurPlayer + ocDARRELL] = PlayerGotoPos[CurPlayer + ocDARRELL];
PlayerGotoPos[CurPlayer + ocDARRELL] = 0;
}
an = Char->Walk.WalkSteps[Char->Walk.NumSteps].Act;
Char->Walk.WalkSteps[0].reset();
Char->Walk.NumSteps = 0;
if (an) StartAnim(game, an);
return false;
}
}
/* -----------------28/04/98 17.51-------------------
* UpdateLook
* --------------------------------------------------*/
void UpdateLook(int32 oc) {
/* t3dCHARACTER *Char=Character[oc];
t3dWALK *w=&Char->Walk;
t3dF32 a1,a2;
a1 = SinCosAngle( w->Panel[w->CurPanel].x1 - w->CurX, w->Panel[w->CurPanel].z1 - w->CurZ );
a2 = SinCosAngle( w->LookX - w->CurX, w->LookZ - w->CurZ );
if ( fabs( a1-a2 ) < T3D_PI )
{
w->LookX = w->Panel[w->CurPanel].x1;
w->LookZ = w->Panel[w->CurPanel].z1;
}
else
{
w->LookX = w->Panel[w->CurPanel].x2;
w->LookZ = w->Panel[w->CurPanel].z2;
}
*/
}
} // End of namespace Watchmaker