Initial commit
This commit is contained in:
784
engines/watchmaker/walk/act.cpp
Normal file
784
engines/watchmaker/walk/act.cpp
Normal file
@@ -0,0 +1,784 @@
|
||||
/* 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
|
||||
45
engines/watchmaker/walk/act.h
Normal file
45
engines/watchmaker/walk/act.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_ACT_H
|
||||
#define WATCHMAKER_ACT_H
|
||||
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/globvar.h"
|
||||
#include "watchmaker/game.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
void CheckCharacterWithoutBounds(WGame &game, int32 oc, const uint8 *dpl, uint8 back);
|
||||
bool CheckCharacterWithBounds(WGame &game, int32 oc, t3dV3F *Pos, uint8 dp, uint8 back);
|
||||
void CharSetPosition(int32 oc, uint8 pos, const char *room);
|
||||
void CharStop(int32 oc);
|
||||
uint8 CharNextFrame(WGame &game, int32 oc);
|
||||
bool CharGotoPosition(WGame &game, int32 oc, uint8 pos, uint8 back, int32 anim);
|
||||
void FixPos(int32 oc);
|
||||
void UpdateLook(int32 oc);
|
||||
void BuildStepList(int32 oc, uint8 dp, uint8 back);
|
||||
void UpdateChar(WGame &game, int32 oc, t3dF32 Speed, t3dF32 Rot);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_ACT_H
|
||||
572
engines/watchmaker/walk/ball.cpp
Normal file
572
engines/watchmaker/walk/ball.cpp
Normal file
@@ -0,0 +1,572 @@
|
||||
/* 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/ball.h"
|
||||
#include "watchmaker/globvar.h"
|
||||
#include "watchmaker/define.h"
|
||||
#include "watchmaker/ll/ll_mesh.h"
|
||||
#include "watchmaker/3d/loader.h"
|
||||
#include "watchmaker/3d/math/llmath.h"
|
||||
#include "watchmaker/3d/geometry.h"
|
||||
#include "watchmaker/3d/t3d_mesh.h"
|
||||
#include "watchmaker/ll/ll_anim.h"
|
||||
#include "watchmaker/walk/act.h"
|
||||
#include "watchmaker/ll/ll_util.h"
|
||||
#include "watchmaker/classes/do_camera.h"
|
||||
#include "watchmaker/renderer.h"
|
||||
#include "watchmaker/classes/do_keyboard.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct SPhys Ball[MAX_GOPHERS];
|
||||
t3dV3F OldBallCameraSource, OldBallCameraTarget;
|
||||
int32 ExplosionTimer;
|
||||
t3dF32 IperLight, LastFloorY;
|
||||
|
||||
/* -----------------16/02/99 11.02-------------------
|
||||
* InitPhys
|
||||
* --------------------------------------------------*/
|
||||
void InitPhys(struct SPhys *p) {
|
||||
p->Kg = 9.80665f; // costante gravitazionale
|
||||
p->Kn = 6.0f * T3D_PI * 0.00023f; // coefficiente di attrito viscoso
|
||||
p->Kc = 0.70f; // percentuale di energia cinetica che si conserva
|
||||
p->Kt = 0.50f; // percentuale di energia cinetica che si conserva per terra
|
||||
p->Mp = 0.40f; // massa palla
|
||||
p->Mb = 2.00f; // massa braccio
|
||||
p->Rp = 0.13f; // raggio palla
|
||||
p->Td = 0.0f; // differenza di tempo trascorsa tra un istante e l'altro
|
||||
p->Ts = 0.0f; // tempo trascorso dall'ultimo impatto
|
||||
p->Tb = 0.0f; // tempo di carica del braccio
|
||||
p->InAir = 0; // Se sta volando
|
||||
|
||||
t3dVectInit(&p->Fv, 0.0f, 0.0f, 0.0f); // forza del vento
|
||||
t3dVectFill(&p->V0, 0.0f); // velocita' iniziale palla
|
||||
t3dVectFill(&p->Vt, 0.0f); // velocita' attuale palla
|
||||
t3dUpdateArrow(Freccia50->Mesh, 0.0f);
|
||||
}
|
||||
|
||||
/* -----------------16/02/99 11.05-------------------
|
||||
* ContinuePhys
|
||||
* --------------------------------------------------*/
|
||||
void ContinuePhys(struct SPhys *p) {
|
||||
p->Ts += p->Td;
|
||||
if (!p->InAir) { // se non vola, esce
|
||||
t3dVectCopy(&p->S0, &p->St);
|
||||
t3dVectCopy(&p->V0, &p->Vt);
|
||||
return ;
|
||||
}
|
||||
t3dVectFill(&p->At, 0.0f);
|
||||
if (p->MVt > 0.1f) { // Attrito aria se vola
|
||||
p->At.x -= (p->Kn * p->Rp * p->V0.x / p->Mp);
|
||||
p->At.y -= (p->Kn * p->Rp * p->V0.y / p->Mp);
|
||||
p->At.z -= (p->Kn * p->Rp * p->V0.z / p->Mp);
|
||||
}
|
||||
|
||||
p->At.y -= p->Kg;
|
||||
|
||||
p->At.x += p->Fv.x / p->Mp; // Vento
|
||||
p->At.y += p->Fv.y / p->Mp;
|
||||
p->At.z += p->Fv.z / p->Mp;
|
||||
|
||||
p->MAt = (t3dF32)sqrt(p->At.x * p->At.x + p->At.y * p->At.y + p->At.z * p->At.z);
|
||||
|
||||
p->Vt.x = p->V0.x + p->At.x * p->Td;
|
||||
p->Vt.y = p->V0.y + p->At.y * p->Td;
|
||||
p->Vt.z = p->V0.z + p->At.z * p->Td;
|
||||
p->MVt = (t3dF32)sqrt(p->Vt.x * p->Vt.x + p->Vt.y * p->Vt.y + p->Vt.z * p->Vt.z);
|
||||
|
||||
p->St.x = p->S0.x + p->V0.x * p->Td + p->At.x * p->Td * p->Td / 2.0f;
|
||||
p->St.y = p->S0.y + p->V0.y * p->Td + p->At.y * p->Td * p->Td / 2.0f;
|
||||
p->St.z = p->S0.z + p->V0.z * p->Td + p->At.z * p->Td * p->Td / 2.0f;
|
||||
|
||||
// if( p->St.y < CurFloorY ) p->St.y = CurFloorY;
|
||||
// DebugFile("%f;%f;%f;",p->St.x,p->St.y,p->St.z);
|
||||
|
||||
t3dVectCopy(&p->S0, &p->St);
|
||||
t3dVectCopy(&p->V0, &p->Vt);
|
||||
}
|
||||
|
||||
|
||||
/* -----------------03/05/99 15.34-------------------
|
||||
* NextGopher
|
||||
* --------------------------------------------------*/
|
||||
void NextGopher(WGame &game) {
|
||||
if (CurGopher >= 0) {
|
||||
StopObjAnim(game, ocCURPLAYER);
|
||||
CharStop(ocCURPLAYER);
|
||||
}
|
||||
CurGopher = ((CurGopher + 1) >= MAX_GOPHERS) ? 0 : CurGopher + 1;
|
||||
|
||||
Character[ocCURPLAYER] = Character[CurGopher + 1];
|
||||
Player = Character[CurGopher + 1];
|
||||
Player->Flags &= ~T3D_CHARACTER_HIDE;
|
||||
Player->Mesh->Flags |= T3D_MESH_DEFAULTANIM;
|
||||
// Riposiziona sempre il personaggio sul suolo
|
||||
t3dClipToSurface(game.init, &Player->Mesh->Trasl);
|
||||
CurFloorY = Player->Mesh->Trasl.y;
|
||||
LastFloorY = Player->Mesh->Trasl.y;
|
||||
Ball[CurGopher].TimeLeft = 60.0f;
|
||||
t3dUpdateArrow(Freccia50->Mesh, 0.0f);
|
||||
game._renderer->setCurCameraViewport(t3dCurCamera->Fov, bSuperView);
|
||||
t3dVectFill(&OldBallCameraTarget, 0.0f);
|
||||
t3dVectFill(&OldBallCameraSource, 0.0f);
|
||||
bGolfMode = 0;
|
||||
}
|
||||
|
||||
/* -----------------16/02/99 11.06-------------------
|
||||
* ChangePhys
|
||||
* --------------------------------------------------*/
|
||||
void ChangePhys(struct SPhys *p, int flags) {
|
||||
p->Ts = 0.0f;
|
||||
if (flags == 1) { // urto per terra
|
||||
if (!p->InAir) return; // se non vola, esce
|
||||
t3dVectCopy(&p->S0, &p->St);
|
||||
p->V0.x = p->Vt.x * p->Kt;
|
||||
p->V0.y = -p->Vt.y * p->Kt;
|
||||
p->V0.z = p->Vt.z * p->Kt;
|
||||
p->MVt = (t3dF32)sqrt(p->V0.x * p->V0.x + p->V0.y * p->V0.y + p->V0.z * p->V0.z);
|
||||
} else if (flags == 2) { // riposizionamento della palla
|
||||
t3dVectFill(&p->V0, 0.0f);
|
||||
p->MVt = 0.0f;
|
||||
p->InAir = 0;
|
||||
} else { // urto col braccio
|
||||
t3dVectCopy(&p->S0, &p->St);
|
||||
p->Vb.x = p->Fb.x * p->Tb / p->Mb;
|
||||
p->Vb.y = p->Fb.y * p->Tb / p->Mb;
|
||||
p->Vb.z = p->Fb.z * p->Tb / p->Mb;
|
||||
|
||||
p->V0.x = ((p->Mp - p->Mb) * p->Vt.x / (p->Mp + p->Mb) + 2.0f * p->Mb * p->Vb.x / (p->Mp + p->Mb)) * p->Kc;
|
||||
p->V0.y = ((p->Mp - p->Mb) * p->Vt.y / (p->Mp + p->Mb) + 2.0f * p->Mb * p->Vb.y / (p->Mp + p->Mb)) * p->Kc;
|
||||
p->V0.z = ((p->Mp - p->Mb) * p->Vt.z / (p->Mp + p->Mb) + 2.0f * p->Mb * p->Vb.z / (p->Mp + p->Mb)) * p->Kc;
|
||||
p->MVt = (t3dF32)sqrt(p->V0.x * p->V0.x + p->V0.y * p->V0.y + p->V0.z * p->V0.z);
|
||||
p->InAir = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------13/04/99 10.52-------------------
|
||||
* UpdateBall
|
||||
* --------------------------------------------------*/
|
||||
void UpdateBall(WGame &game, struct SPhys *p) {
|
||||
t3dV3F zero, tmp, start, end;
|
||||
int32 i;
|
||||
t3dMESH *m;
|
||||
Init &init = game.init;
|
||||
auto &renderer = *game._renderer;
|
||||
auto windowInfo = game._renderer->getScreenInfos();
|
||||
|
||||
// Se ha finito il tempo, cambia talpa
|
||||
if ((p->TimeLeft < 0.0f) && ((bGolfMode == 0) || (bGolfMode == 1)))
|
||||
NextGopher(game);
|
||||
// Aggiorna la freccia
|
||||
UpdateArrow();
|
||||
// Riposiziona sempre il personaggio sul suolo
|
||||
t3dClipToSurface(init, &Player->Mesh->Trasl);
|
||||
CurFloorY = Player->Mesh->Trasl.y;
|
||||
LastFloorY = CurFloorY;
|
||||
IperLight = 0.0f;
|
||||
|
||||
// Muove la palla
|
||||
if (bGolfMode != 5)
|
||||
ContinuePhys(p);
|
||||
Palla50->Mesh->Trasl = p->St * (2.55f * 100.0f);
|
||||
|
||||
// Se vola e tocca il terreno ferma tutto
|
||||
if ((bGolfMode == 2) || (bGolfMode == 3) || (bGolfMode == 4)) {
|
||||
t3dVectCopy(&start, &Palla50->Mesh->Trasl);
|
||||
start.y = 260000.0f;
|
||||
t3dVectCopy(&end, &Palla50->Mesh->Trasl);
|
||||
end.y = -130000.0f;
|
||||
for (i = 0; i < 6; i++)
|
||||
if ((m = LinkMeshToStr(init, init.Obj[oNEXTPORTAL].getMeshLink(i))) && (t3dVectMeshInters(m, start, end, &tmp)))
|
||||
break;
|
||||
if (tmp.y < 0.0f) tmp.y = 0.0f;
|
||||
if ((Palla50->Mesh->Trasl.y < (tmp.y + 0.01f)) && (p->MVt > 0.1)) {
|
||||
ExplosionTimer = 0;
|
||||
t3dVectCopy(&Explode50->Mesh->Trasl, &tmp);
|
||||
bGolfMode = 5;
|
||||
}
|
||||
|
||||
t3dVectCopy(&zero, &p->Vt);
|
||||
t3dVectNormalize(&zero);
|
||||
if (bGolfMode == 3)
|
||||
if (((Palla50->Mesh->Trasl.y < (tmp.y + EYES_HEIGHT * 15.0f)) && (zero.y < 0.0f)) || (zero.y < -0.5f))
|
||||
bGolfMode = 4;
|
||||
}
|
||||
// Aggiorna i markers
|
||||
GopherMark[0]->Flags |= T3D_CHARACTER_HIDE;
|
||||
GopherMark[1]->Flags |= T3D_CHARACTER_HIDE;
|
||||
GopherMark[2]->Flags |= T3D_CHARACTER_HIDE;
|
||||
if ((bGolfMode == 0) || (bGolfMode == 1)) {
|
||||
for (i = 0; i < MAX_GOPHERS; i++) {
|
||||
if (i == CurGopher) continue;
|
||||
|
||||
if (bGolfMode)
|
||||
t3dVectSub(&tmp, &Character[i + 1]->Mesh->Trasl, &Palla50->Mesh->Trasl);
|
||||
else
|
||||
t3dVectSub(&tmp, &Character[i + 1]->Mesh->Trasl, &Player->Mesh->Trasl);
|
||||
t3dVectNormalize(&tmp);
|
||||
tmp *= EYES_HEIGHT * 4.0f;
|
||||
if (bGolfMode)
|
||||
t3dVectAdd(&GopherMark[i]->Mesh->Trasl, &Palla50->Mesh->Trasl, &tmp);
|
||||
else
|
||||
t3dVectAdd(&GopherMark[i]->Mesh->Trasl, &Player->Mesh->Trasl, &tmp);
|
||||
GopherMark[i]->Mesh->Trasl.y += EYES_HEIGHT * 2.0f;
|
||||
GopherMark[i]->Flags &= ~T3D_CHARACTER_HIDE;
|
||||
}
|
||||
}
|
||||
// Aggiorna il cono visivo
|
||||
p->ViewCone.x1 = 130 + (int32)(Player->Mesh->Trasl.x / 255.0f * 0.341f) + windowInfo.width - renderer.getBitmapRealDimX(GopherMap);
|
||||
p->ViewCone.y1 = 146 - (int32)(Player->Mesh->Trasl.z / 255.0f * 0.341f);
|
||||
tmp = Player->Dir * 20.0f;
|
||||
zero = Player->Dir * 10.0f;
|
||||
p->ViewCone.x2 = p->ViewCone.x1 + (int32)(tmp.x + zero.z);
|
||||
p->ViewCone.y2 = p->ViewCone.y1 - (int32)(tmp.z - zero.x);
|
||||
p->ViewCone.x3 = p->ViewCone.x1 + (int32)(tmp.x - zero.z);
|
||||
p->ViewCone.y3 = p->ViewCone.y1 - (int32)(tmp.z + zero.x);
|
||||
DisplayD3DTriangle(*game._renderer, p->ViewCone.x1, p->ViewCone.y1, p->ViewCone.x2, p->ViewCone.y2, p->ViewCone.x3, p->ViewCone.y3, 125, 125, 125, 125);
|
||||
|
||||
// Aggiorna la mappa e le scritte
|
||||
game._renderer->_2dStuff.displayDDBitmap(GopherMap, windowInfo.width - renderer.getBitmapRealDimX(GopherMap), 0, 0, 0, 0, 0);
|
||||
for (i = 0; i < MAX_GOPHERS; i++)
|
||||
game._renderer->_2dStuff.displayDDBitmap(GopherPos[i], windowInfo.width - renderer.getBitmapRealDimX(GopherMap) +
|
||||
130 + (int32)(Character[i + 1]->Mesh->Trasl.x / 255.0f * 0.341f) - renderer.getBitmapRealDimX(GopherPos[i]) / 2,
|
||||
146 - (int32)(Character[i + 1]->Mesh->Trasl.z / 255.0f * 0.341f) - renderer.getBitmapRealDimY(GopherPos[i]) / 2, 0, 0, 0, 0);
|
||||
if (bGolfMode)
|
||||
game._renderer->_2dStuff.displayDDBitmap(GopherBall, windowInfo.width - renderer.getBitmapRealDimX(GopherMap) +
|
||||
130 + (int32)(Palla50->Mesh->Trasl.x / 255.0f * 0.341f) - renderer.getBitmapRealDimX(GopherBall) / 2,
|
||||
146 - (int32)(Palla50->Mesh->Trasl.z / 255.0f * 0.341f) - renderer.getBitmapRealDimY(GopherBall) / 2, 0, 0, 0, 0);
|
||||
if ((bGolfMode == 0) || (bGolfMode == 1)) {
|
||||
DebugVideo(*game._renderer, 10, 32, "TimeLeft: %d", (int32)p->TimeLeft);
|
||||
p->TimeLeft -= p->Td;
|
||||
if ((Player->Mesh->Flags & T3D_MESH_DEFAULTANIM) && (Player->Mesh->CurFrame > 5) && (Player->Mesh->CurFrame < 271))
|
||||
p->TimeLeft -= 2.0f * p->Td;
|
||||
}
|
||||
if (bGolfMode == 1) {
|
||||
DebugVideo(*game._renderer, 10, 48, "Angle: %d %d", 45 - (int)(Ball[CurGopher].Angle.x * 180.0f / T3D_PI), (int)(Ball[CurGopher].Angle.y * 180.0f / T3D_PI));
|
||||
DebugVideo(*game._renderer, 10, 64, "Power: %d", (int)Ball[CurGopher].Angle.z);
|
||||
}
|
||||
game._renderer->_2dStuff.displayDDBitmap(EndPic, windowInfo.width - renderer.getBitmapRealDimX(EndPic) - 20, windowInfo.height - renderer.getBitmapRealDimY(EndPic) - 20, 0, 0, 0, 0);
|
||||
|
||||
// Aggiorna la camera
|
||||
ProcessGopherCamera(game);
|
||||
// Controlla che la camera non finisca sotto terra
|
||||
t3dVectCopy(&tmp, &t3dCurCamera->Source);
|
||||
if (t3dClipToSurface(init, &tmp))
|
||||
if (t3dCurCamera->Source.y < (tmp.y + CHEST_HEIGHT))
|
||||
t3dCurCamera->Source.y = (tmp.y + CHEST_HEIGHT);
|
||||
|
||||
t3dVectCopy(&OldBallCameraSource, &t3dCurCamera->Source);
|
||||
t3dVectCopy(&OldBallCameraTarget, &t3dCurCamera->Target);
|
||||
// Illumina quello che sta vicino alla camera
|
||||
t3dLightChar(Player->Mesh, &t3dCurCamera->Source);
|
||||
t3dLightChar(Freccia50->Mesh, &t3dCurCamera->Source);
|
||||
t3dLightRoom(init, t3dCurRoom, &t3dCurCamera->Target, 5000.0f, 15000.0f, IperLight);
|
||||
}
|
||||
|
||||
/* -----------------04/05/99 10.07-------------------
|
||||
* ProcessGopherKeyboard
|
||||
* --------------------------------------------------*/
|
||||
void ProcessGopherKeyboard() {
|
||||
warning("Stubbed: ProcessGopherKeyboard");
|
||||
#if 0
|
||||
t3dF32 AngleX, AngleY, AngleSpeed;
|
||||
t3dF32 TurnSpeed, Speed = 1.0f;
|
||||
t3dM3X3F mx;
|
||||
|
||||
AngleX = AngleY = AngleSpeed = 0.0f;
|
||||
TurnSpeed = 3.5f * FrameFactor;
|
||||
|
||||
ProcessKBInput();
|
||||
|
||||
if (KeyDown(DIK_ESCAPE)) // Quitta il gioco
|
||||
CloseSys();
|
||||
if (KeyUp(DIK_W)) { // Modalita' wireframe
|
||||
bForceWire ^= 1;
|
||||
if (bForceWire)
|
||||
rSetRenderMode(rWIREFRAMEMODE);
|
||||
else
|
||||
rSetRenderMode(rSOLIDMODE);
|
||||
}
|
||||
// if( KeyUp(DIK_I) ) // Escono Informazioni
|
||||
// bShowInfo ^= 1;
|
||||
// if( KeyUp(DIK_B) ) // Escono BoundingBox
|
||||
// bShowBoundingBox ^= 1;
|
||||
// if( KeyUp(DIK_P) ) // Escono Pannelli
|
||||
// bShowPanels ^= 1;
|
||||
if (KeyUp(DIK_RETURN)) // Avanza di un frame tutte le animazioni
|
||||
NextGopher();
|
||||
|
||||
if (KeyUp(DIK_1)) CharSetPosition(ocCURPLAYER, 1, NULL);
|
||||
if (KeyUp(DIK_2)) CharSetPosition(ocCURPLAYER, 2, NULL);
|
||||
if (KeyUp(DIK_3)) CharSetPosition(ocCURPLAYER, 3, NULL);
|
||||
if (KeyUp(DIK_4)) CharSetPosition(ocCURPLAYER, 4, NULL);
|
||||
if (KeyUp(DIK_5)) CharSetPosition(ocCURPLAYER, 5, NULL);
|
||||
if (KeyUp(DIK_6)) CharSetPosition(ocCURPLAYER, 6, NULL);
|
||||
if (KeyUp(DIK_7)) CharSetPosition(ocCURPLAYER, 7, NULL);
|
||||
if (KeyUp(DIK_8)) CharSetPosition(ocCURPLAYER, 8, NULL);
|
||||
if (KeyUp(DIK_9)) CharSetPosition(ocCURPLAYER, 9, NULL);
|
||||
if (KeyUp(DIK_NUMPAD0)) CharSetPosition(ocCURPLAYER, 10, NULL);
|
||||
if (KeyUp(DIK_NUMPAD1)) CharSetPosition(ocCURPLAYER, 11, NULL);
|
||||
if (KeyUp(DIK_NUMPAD2)) CharSetPosition(ocCURPLAYER, 12, NULL);
|
||||
if (KeyUp(DIK_NUMPAD3)) CharSetPosition(ocCURPLAYER, 13, NULL);
|
||||
if (KeyUp(DIK_NUMPAD4)) CharSetPosition(ocCURPLAYER, 14, NULL);
|
||||
if (KeyUp(DIK_NUMPAD5)) CharSetPosition(ocCURPLAYER, 15, NULL);
|
||||
if (KeyUp(DIK_NUMPAD6)) CharSetPosition(ocCURPLAYER, 16, NULL);
|
||||
if (KeyUp(DIK_NUMPAD7)) CharSetPosition(ocCURPLAYER, 17, NULL);
|
||||
if (KeyUp(DIK_NUMPAD8)) CharSetPosition(ocCURPLAYER, 18, NULL);
|
||||
if (KeyUp(DIK_NUMPAD9)) CharSetPosition(ocCURPLAYER, 19, NULL);
|
||||
|
||||
if (KeyUp(DIK_TAB)) { // Cambia modalita'
|
||||
|
||||
if (!bGolfMode) {
|
||||
t3dMatCopy(&Freccia50->Mesh->Matrix, &Player->Mesh->Matrix);
|
||||
t3dVectCopy(&Palla50->Mesh->Trasl, &Player->Mesh->Trasl);
|
||||
Palla50->Mesh->Flags |= T3D_MESH_HIDDEN;
|
||||
Palla50->Flags &= ~T3D_CHARACTER_HIDE;
|
||||
StartAnim(aGOPHER_ACTION);
|
||||
bGolfMode = 1;
|
||||
|
||||
t3dVectScale(&Ball[CurGopher].S0, &Palla50->Mesh->Trasl, 1.0f / (2.55f * 100.0f));
|
||||
t3dVectCopy(&Ball[CurGopher].St, &Ball[CurGopher].S0);
|
||||
|
||||
t3dVectInit(&Ball[CurGopher].Fb, 0.0f, 40.0f, -40.0f);
|
||||
if (Ball[CurGopher].Angle.z) {
|
||||
t3dVectNormalize(&Ball[CurGopher].Fb);
|
||||
t3dVectScale(&Ball[CurGopher].Fb, &Ball[CurGopher].Fb, Ball[CurGopher].Angle.z);
|
||||
t3dMatRot(&mx, -Ball[CurGopher].Angle.x, Ball[CurGopher].Angle.y, 0.0f);
|
||||
t3dVectTransform(&Ball[CurGopher].Fb, &Ball[CurGopher].Fb, &mx);
|
||||
}
|
||||
t3dVectTransform(&Ball[CurGopher].Fb, &Ball[CurGopher].Fb, &Freccia50->Mesh->Matrix);
|
||||
InitPhys(&Ball[CurGopher]);
|
||||
} else {
|
||||
Freccia50->Flags |= T3D_CHARACTER_HIDE;
|
||||
ContinueAnim(aGOPHER_ACTION);
|
||||
}
|
||||
}
|
||||
|
||||
if (KeyDown(DIK_LEFT) && !bGolfMode) { // Ruota a Destra
|
||||
AngleY = (-1) * TurnSpeed / 180.0f * T3D_PI;
|
||||
if ((Player->Walk.CurAction <= aSTAND) || (Player->Walk.CurAction == aROT_DX)) {
|
||||
PlayerGotoPos[CurPlayer] = 0;
|
||||
PlayerPos[CurPlayer] = 0;
|
||||
Player->Walk.CurAction = aROT_SX;
|
||||
Player->Walk.CurFrame = ActionStart[Player->Walk.CurAction];
|
||||
Player->Mesh->CurFrame = Player->Walk.CurFrame;
|
||||
} else if (Player->Walk.CurAction == aROT_SX) {
|
||||
PlayerGotoPos[CurPlayer] = 0;
|
||||
PlayerPos[CurPlayer] = 0;
|
||||
Player->Walk.CurFrame ++;
|
||||
if (Player->Walk.CurFrame >= ActionStart[Player->Walk.CurAction + 1] - 1)
|
||||
Player->Walk.CurFrame = ActionStart[Player->Walk.CurAction];
|
||||
Player->Mesh->CurFrame = Player->Walk.CurFrame;
|
||||
}
|
||||
} else if (KeyDown(DIK_RIGHT) && !bGolfMode) { // Ruota a Sinistra
|
||||
AngleY = TurnSpeed / 180.0f * T3D_PI;
|
||||
if ((Player->Walk.CurAction <= aSTAND) || (Player->Walk.CurAction == aROT_SX)) {
|
||||
PlayerGotoPos[CurPlayer] = 0;
|
||||
PlayerPos[CurPlayer] = 0;
|
||||
Player->Walk.CurAction = aROT_DX;
|
||||
Player->Walk.CurFrame = ActionStart[Player->Walk.CurAction];
|
||||
Player->Mesh->CurFrame = Player->Walk.CurFrame;
|
||||
} else if (Player->Walk.CurAction == aROT_DX) {
|
||||
PlayerGotoPos[CurPlayer] = 0;
|
||||
PlayerPos[CurPlayer] = 0;
|
||||
Player->Walk.CurFrame ++;
|
||||
if (Player->Walk.CurFrame >= ActionStart[Player->Walk.CurAction + 1] - 1)
|
||||
Player->Walk.CurFrame = ActionStart[Player->Walk.CurAction];
|
||||
Player->Mesh->CurFrame = Player->Walk.CurFrame;
|
||||
}
|
||||
}
|
||||
|
||||
if (KeyDown(DIK_UP) && !bGolfMode)
|
||||
AngleSpeed = 20.0f;
|
||||
else if (KeyDown(DIK_DOWN) && !bGolfMode)
|
||||
AngleSpeed = -20.0f;
|
||||
|
||||
if ((Player) && !bGolfMode)
|
||||
UpdateChar(ocCURPLAYER, AngleSpeed * Speed, AngleY);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* -----------------04/05/99 10.29-------------------
|
||||
* UpdateArrow
|
||||
* --------------------------------------------------*/
|
||||
void UpdateArrow() {
|
||||
warning("Stubbed: UpdateArrow");
|
||||
#if 0
|
||||
t3dF32 AngleX, AngleY, AngleSpeed;
|
||||
t3dM3X3F mx, mv;
|
||||
t3dV3F zero;
|
||||
|
||||
if (bGolfMode != 1) {
|
||||
KeyClear(DIK_SPACE);
|
||||
return;
|
||||
}
|
||||
|
||||
AngleX = AngleY = 0.0f;
|
||||
AngleSpeed = t3dVectMod(&Ball[CurGopher].Fb);
|
||||
t3dVectNormalize(&Ball[CurGopher].Fb);
|
||||
|
||||
if ((Ball[CurGopher].Angle.x > -0.35f) && KeyDown(DIK_UP)) AngleX -= 0.01f;
|
||||
if ((Ball[CurGopher].Angle.x < 0.35f) && KeyDown(DIK_DOWN)) AngleX += 0.01f;
|
||||
if ((Ball[CurGopher].Angle.y < 0.25f) && KeyDown(DIK_RIGHT)) AngleY += 0.01f;
|
||||
if ((Ball[CurGopher].Angle.y > -0.25f) && KeyDown(DIK_LEFT)) AngleY -= 0.01f;
|
||||
if ((AngleSpeed < 90.0f) && KeyDown(DIK_A)) AngleSpeed += 1.0f;
|
||||
if ((AngleSpeed > 41.0f) && KeyDown(DIK_Z)) AngleSpeed -= 1.0f;
|
||||
Ball[CurGopher].Angle.x += AngleX;
|
||||
Ball[CurGopher].Angle.y += AngleY;
|
||||
Ball[CurGopher].Angle.z = AngleSpeed;
|
||||
|
||||
t3dVectFill(&zero, 0.0f);
|
||||
t3dMatView(&mv, &zero, &Ball[CurGopher].Fb, 0.0f);
|
||||
t3dMatRot(&mx, AngleX, AngleY, 0.0f);
|
||||
t3dVectTransform(&Ball[CurGopher].Fb, &Ball[CurGopher].Fb, &mv);
|
||||
t3dVectTransform(&Ball[CurGopher].Fb, &Ball[CurGopher].Fb, &mx);
|
||||
t3dVectTransformInv(&Ball[CurGopher].Fb, &Ball[CurGopher].Fb, &mv);
|
||||
t3dVectScale(&Ball[CurGopher].Fb, &Ball[CurGopher].Fb, AngleSpeed);
|
||||
|
||||
t3dMatViewAlt(&Freccia50->Mesh->Matrix, &Ball[CurGopher].Fb);
|
||||
|
||||
if (KeyUp(DIK_SPACE)) {
|
||||
Freccia50->Flags |= T3D_CHARACTER_HIDE;
|
||||
Player->Mesh->CurFrame = 271;
|
||||
Palla50->Mesh->CurFrame = 271;
|
||||
ContinueAnim(aGOPHER_ACTION);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* -----------------04/05/99 10.37-------------------
|
||||
* ProcessGopherCamera
|
||||
* --------------------------------------------------*/
|
||||
void ProcessGopherCamera(WGame &game) {
|
||||
t3dV3F zero, tmp;
|
||||
t3dF32 dist, dist2;
|
||||
struct SPhys *p = &Ball[CurGopher];
|
||||
|
||||
// Gestione della telecamera
|
||||
if (!bGolfMode) { // inquadra omino
|
||||
t3dVectInit(&zero, -Player->Dir.x, 0.0f, -Player->Dir.z);
|
||||
t3dVectNormalize(&zero);
|
||||
zero *= (EYES_HEIGHT * 2.0f);
|
||||
zero.y = CHEST_HEIGHT;
|
||||
|
||||
game._cameraMan->GetCameraTarget(game.init, &t3dCurCamera->Target);
|
||||
t3dCurCamera->Target.y = LastFloorY + CHEST_HEIGHT;
|
||||
t3dVectAdd(&t3dCurCamera->Source, &t3dCurCamera->Target, &zero);
|
||||
Palla50->Flags |= T3D_CHARACTER_HIDE;
|
||||
Freccia50->Flags |= T3D_CHARACTER_HIDE;
|
||||
Explode50->Flags |= T3D_CHARACTER_HIDE;
|
||||
InitPhys(p);
|
||||
} else if (bGolfMode == 1) { // inquadra palla
|
||||
t3dVectInit(&zero, -p->Fb.x, 0.0f, -p->Fb.z);
|
||||
t3dVectNormalize(&zero);
|
||||
zero *= (EYES_HEIGHT * 2.0f);
|
||||
zero.y = CHEST_HEIGHT;
|
||||
|
||||
t3dVectCopy(&t3dCurCamera->Target, &Palla50->Mesh->Trasl);
|
||||
t3dCurCamera->Target.y += CHEST_HEIGHT;
|
||||
t3dVectAdd(&t3dCurCamera->Source, &t3dCurCamera->Target, &zero);
|
||||
Explode50->Flags |= T3D_CHARACTER_HIDE;
|
||||
t3dVectCopy(&Freccia50->Mesh->Trasl, &Palla50->Mesh->Trasl);
|
||||
t3dUpdateArrow(Freccia50->Mesh, Ball[CurGopher].Angle.z * 15.0f);
|
||||
} else if (bGolfMode == 2) { // inquadra pallina che vola
|
||||
t3dVectCopy(&t3dCurCamera->Target, &Palla50->Mesh->Trasl);
|
||||
t3dVectFill(&OldBallCameraTarget, 0.0f);
|
||||
t3dVectFill(&OldBallCameraSource, 0.0f);
|
||||
Freccia50->Flags |= T3D_CHARACTER_HIDE;
|
||||
|
||||
if (p->Ts > 0.5f) {
|
||||
bGolfMode = 3;
|
||||
game._renderer->setCurCameraViewport(45.0f, bSuperView);
|
||||
}
|
||||
} else if (bGolfMode == 3) { // inquadra terra
|
||||
t3dVectCopy(&tmp, &p->Vt);
|
||||
t3dVectNormalize(&tmp);
|
||||
|
||||
t3dVectInit(&zero, p->Vt.x, -15.0f, p->Vt.z);
|
||||
t3dVectNormalize(&zero);
|
||||
|
||||
if (tmp.y < zero.y)
|
||||
t3dVectInit(&zero, p->Vt.x, p->Vt.y, p->Vt.z);
|
||||
else
|
||||
t3dVectInit(&zero, p->Vt.x, -15.0f, p->Vt.z);
|
||||
|
||||
zero *= 500.0f;
|
||||
t3dVectCopy(&t3dCurCamera->Source, &Palla50->Mesh->Trasl);
|
||||
t3dVectAdd(&t3dCurCamera->Target, &t3dCurCamera->Source, &zero);
|
||||
if (t3dCurCamera->Target.y < CurFloorY) {
|
||||
dist = t3dVectMod(&zero) * ((CurFloorY - t3dCurCamera->Source.y) / zero.y);
|
||||
t3dVectNormalize(&zero);
|
||||
zero *= dist;
|
||||
t3dVectAdd(&t3dCurCamera->Target, &t3dCurCamera->Source, &zero);
|
||||
}
|
||||
t3dVectFill(&OldBallCameraTarget, 0.0f);
|
||||
t3dVectFill(&OldBallCameraSource, 0.0f);
|
||||
Freccia50->Flags |= T3D_CHARACTER_HIDE;
|
||||
} else if (bGolfMode == 4) { // ferma la camera
|
||||
t3dVectCopy(&t3dCurCamera->Target, &Palla50->Mesh->Trasl);
|
||||
t3dVectFill(&OldBallCameraTarget, 0.0f);
|
||||
t3dVectFill(&OldBallCameraSource, 0.0f);
|
||||
} else if (bGolfMode == 5) {
|
||||
Palla50->Flags |= T3D_CHARACTER_HIDE;
|
||||
Freccia50->Flags |= T3D_CHARACTER_HIDE;
|
||||
Explode50->Flags &= ~T3D_CHARACTER_HIDE;
|
||||
|
||||
if (ExplosionTimer > 200) {
|
||||
// NextGopher();
|
||||
game._renderer->setCurCameraViewport(t3dCurCamera->Fov, bSuperView);
|
||||
t3dVectFill(&OldBallCameraTarget, 0.0f);
|
||||
t3dVectFill(&OldBallCameraSource, 0.0f);
|
||||
bGolfMode = 0;
|
||||
} else if (ExplosionTimer > 100) {
|
||||
t3dUpdateExplosion(Explode50->Mesh, IperLight = (20.0f - (t3dF32)(ExplosionTimer++ -100) / 20.0f));
|
||||
Explode50->Mesh->Trasl.y -= HALF_STEP / 3.0f;
|
||||
} else
|
||||
t3dUpdateExplosion(Explode50->Mesh, IperLight = ((t3dF32)(ExplosionTimer++) / 5.0f));
|
||||
IperLight *= 100.0f;
|
||||
IperLight += 2000.0f;
|
||||
IperLight = 0.0f;
|
||||
}
|
||||
|
||||
// Smooth della camera
|
||||
dist2 = t3dVectDistance(&t3dCurCamera->Source, &t3dCurCamera->Target);
|
||||
dist = t3dVectDistance(&t3dCurCamera->Target, &OldBallCameraTarget);
|
||||
if ((dist > 20.0f) && (dist < HALF_STEP * 30.0f) && OldBallCameraTarget.z) {
|
||||
t3dVectSub(&tmp, &t3dCurCamera->Target, &OldBallCameraTarget);
|
||||
t3dVectNormalize(&tmp);
|
||||
tmp *= 20.0f;
|
||||
t3dVectAdd(&t3dCurCamera->Target, &OldBallCameraTarget, &tmp);
|
||||
}
|
||||
dist = t3dVectDistance(&t3dCurCamera->Source, &OldBallCameraSource);
|
||||
if ((dist < HALF_STEP * 30.0f) && OldBallCameraSource.z) {
|
||||
game._cameraMan->ClipGolfCameraMove(&t3dCurCamera->Source, &OldBallCameraSource, &t3dCurCamera->Target);
|
||||
t3dVectSub(&tmp, &t3dCurCamera->Source, &t3dCurCamera->Target);
|
||||
t3dVectNormalize(&tmp);
|
||||
tmp *= dist2;
|
||||
t3dVectAdd(&t3dCurCamera->Source, &t3dCurCamera->Target, &tmp);
|
||||
}
|
||||
|
||||
t3dVectCopy(&OldBallCameraSource, &t3dCurCamera->Source);
|
||||
t3dVectCopy(&OldBallCameraTarget, &t3dCurCamera->Target);
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
75
engines/watchmaker/walk/ball.h
Normal file
75
engines/watchmaker/walk/ball.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_BALL_H
|
||||
#define WATCHMAKER_BALL_H
|
||||
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/struct.h"
|
||||
#include "watchmaker/globvar.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
struct SPhys {
|
||||
t3dF32 Kg = 0.0f; // costante gravitazionale
|
||||
t3dF32 Kn = 0.0f; // coefficiente di attrito viscoso
|
||||
t3dF32 Kc = 0.0f; // percentuale di energia cinetica che si conserva
|
||||
t3dF32 Kt = 0.0f; // percentuale di energia cinetica che si conserva per terra
|
||||
t3dF32 Mp = 0.0f; // massa palla
|
||||
t3dF32 Mb = 0.0f; // massa braccio
|
||||
t3dF32 Rp = 0.0f; // raggio palla
|
||||
t3dF32 Td = 0.0f; // differenza di tempo trascorsa tra un istante e l'altro
|
||||
t3dF32 Ts = 0.0f; // tempo trascorso dall'ultimo impatto
|
||||
t3dF32 Tb = 0.0f; // tempo di carica del braccio
|
||||
|
||||
t3dV3F Fb; // forza braccio
|
||||
t3dV3F Vb; // velocita' braccio
|
||||
t3dV3F Fv; // forza del vento
|
||||
t3dV3F V0; // velocita' iniziale palla
|
||||
t3dV3F S0; // posizione iniziale palla
|
||||
|
||||
t3dV3F St; // posizione attuale
|
||||
t3dV3F Vt; // velocita' attuale
|
||||
t3dV3F At; // accelerazione attuale
|
||||
t3dF32 MVt = 0.0f; // modulo della velocita' attuale
|
||||
t3dF32 MAt = 0.0f; // modulo dell'accelerazione attuale
|
||||
|
||||
uint8 InAir; // Se e' in volo
|
||||
t3dV3F Angle; // Angolazione colpo
|
||||
t3dF32 TimeLeft = 0.0f; // Tempo Riamente
|
||||
SD3DTriangle ViewCone; // Cono visivo
|
||||
};
|
||||
|
||||
void InitPhys(struct SPhys *p);
|
||||
void ContinuePhys(struct SPhys *p);
|
||||
void ChangePhys(struct SPhys *p, int flags);
|
||||
void NextGopher(WGame &game);
|
||||
void ProcessGopherKeyboard();
|
||||
void UpdateArrow();
|
||||
void ProcessGopherCamera(WGame &game);
|
||||
void UpdateBall(WGame &game, struct SPhys *p);
|
||||
|
||||
extern struct SPhys Ball[];
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_BALL_H
|
||||
779
engines/watchmaker/walk/walk.cpp
Normal file
779
engines/watchmaker/walk/walk.cpp
Normal file
@@ -0,0 +1,779 @@
|
||||
/* 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/walk.h"
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/globvar.h"
|
||||
#include "watchmaker/3d/geometry.h"
|
||||
#include "watchmaker/3d/t3d_body.h"
|
||||
#include "watchmaker/walk/walkutil.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
#include "watchmaker/walk/act.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
// locals
|
||||
/*
|
||||
WALK60 0 225 0
|
||||
WALKBACK 4 162 226
|
||||
RUN80 5 92 385
|
||||
GIRODX 4 63 473
|
||||
GIROSX 4 63 533
|
||||
|
||||
aNULL 0 x3 0 0
|
||||
aSTAND 1 x3 3 3
|
||||
aWALK_START 1+ x3 4 4
|
||||
aWALK_LOOP 14 x3 42 42
|
||||
aWALK_END 75 x3 225 225
|
||||
aBACK_START 1+ x3 4 226
|
||||
aBACK_LOOP 12 x3 36 258
|
||||
aBACK_END 54 x3 162 384
|
||||
aRUN_START 1+ x4 5 385
|
||||
aRUN_LOOP 7 x4 28 408
|
||||
aRUN_END 23 x4 92 472
|
||||
aROT_DX 21 x3 63 473
|
||||
aROT_SX 21 x3 63 533
|
||||
592
|
||||
*/
|
||||
int32 ActionStart[] = {0, 3, 4, 42, 225, 226, 258, 384, 385, 408, 472, 473, 533, 592 };
|
||||
// N S WS WL WE BS BL BE RS, RL RE RD RS
|
||||
int32 ActionLen[] = {1, 1, 38, 183, 1, 32, 126, 1, 23, 64, 1, 63, 63, 0};
|
||||
|
||||
/*-----------------16/10/96 11.07-------------------
|
||||
Guarda e 2 pannelli sono nello stesso blocco
|
||||
--------------------------------------------------*/
|
||||
int FindAttachedPanel(int32 oc, int srcp, int destp) {
|
||||
t3dCHARACTER *Act = Character[oc];
|
||||
t3dWALK *w = &Act->Walk;
|
||||
int curp;
|
||||
int nearp;
|
||||
int b;
|
||||
|
||||
// se almeno uno e' sul pavimento sul pavimento esci
|
||||
if ((srcp < 0) || (destp < 0))
|
||||
return (0);
|
||||
|
||||
// se sono uguali torna 1
|
||||
if (srcp == destp)
|
||||
return (1);
|
||||
|
||||
curp = srcp;
|
||||
nearp = w->Panel[srcp].near1;
|
||||
|
||||
for (b = 0;; b++) {
|
||||
// se sono attaccati torna 1
|
||||
if (curp == destp)
|
||||
return (1);
|
||||
|
||||
// se e' tornato al pannello di partenza torna 0
|
||||
if ((srcp == curp) && (b))
|
||||
return (0);
|
||||
|
||||
if (b > w->PanelNum)
|
||||
return (0);
|
||||
|
||||
// se sono attaccati al vertice 1 prende il 2
|
||||
if (w->Panel[nearp].near1 == curp) {
|
||||
curp = nearp;
|
||||
nearp = w->Panel[curp].near2;
|
||||
} else {
|
||||
curp = nearp;
|
||||
nearp = w->Panel[curp].near1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------19/10/96 10.38-------------------
|
||||
Fa uscire puto da pannello interno
|
||||
--------------------------------------------------*/
|
||||
void PointOut(int32 oc, t3dCAMERA *Camera) {
|
||||
t3dCHARACTER *Act = Character[oc];
|
||||
t3dWALK *w = &Act->Walk;
|
||||
PointXZ p;
|
||||
float inters;
|
||||
float temp;
|
||||
float nx, nz;
|
||||
int b;
|
||||
#define LARGEVAL 60.0 // 30 cm = 15 enlarge * 2
|
||||
|
||||
inters = 32000.0;
|
||||
|
||||
// se ho beccato il pavimento devo contare quante volte interseca
|
||||
// i box larghi la retta omino pto
|
||||
if (w->CurPanel < 0)
|
||||
return;
|
||||
|
||||
nx = w->Panel[w->CurPanel].a.z - w->Panel[w->CurPanel].b.z;
|
||||
nz = w->Panel[w->CurPanel].b.x - w->Panel[w->CurPanel].a.x;
|
||||
temp = (t3dF32)sqrt(nx * nx + nz * nz);
|
||||
nx /= temp;
|
||||
nz /= temp;
|
||||
|
||||
// sposta il punto trovato sui pannelli larghi
|
||||
for (b = 0; b < w->PanelNum; b++) {
|
||||
// controlla solo pannelli esterni con stessi flags
|
||||
// if( ( Panel[b].flags & 0x80000000 ) &&
|
||||
// ( Panel[b].flags & (Panel[CurPanel].flags & 0x7FFFFFFF) ) )
|
||||
{
|
||||
// controlla pto 1
|
||||
temp = DistF(w->Cur, w->Panel[b].a);
|
||||
|
||||
if (temp < inters) {
|
||||
inters = temp;
|
||||
w->CurPanel = b;
|
||||
p = w->Panel[b].a;
|
||||
}
|
||||
|
||||
// controlla pto 2
|
||||
temp = DistF(w->Cur, w->Panel[b].b);
|
||||
|
||||
if (temp < inters) {
|
||||
inters = temp;
|
||||
w->CurPanel = b;
|
||||
p = w->Panel[b].b;
|
||||
}
|
||||
|
||||
// controlla intersezione con camera
|
||||
PointResult res = IntersLineLine(w->Panel[b].a, w->Panel[b].b,
|
||||
Camera->Source.x, Camera->Source.z,
|
||||
w->Cur.x, w->Cur.z);
|
||||
if (res.isValid) {
|
||||
temp = DistF(w->Cur, res.result);
|
||||
|
||||
if (temp < inters) {
|
||||
inters = temp;
|
||||
w->CurPanel = b;
|
||||
p = res.result;
|
||||
}
|
||||
}
|
||||
|
||||
// controlla intersezione con omino
|
||||
res = IntersLineLine(w->Panel[b].a, w->Panel[b].b,
|
||||
Act->Pos.x, Act->Pos.z,
|
||||
w->Cur.x, w->Cur.z);
|
||||
if (res.isValid) {
|
||||
temp = DistF(w->Cur, res.result);
|
||||
|
||||
if (temp < inters) {
|
||||
inters = temp;
|
||||
w->CurPanel = b;
|
||||
p = res.result;
|
||||
}
|
||||
}
|
||||
|
||||
// controlla intersezione con normale pannello
|
||||
/* PointResult res = IntersLineLine( w->Panel[b].x1, w->Panel[b].z1,
|
||||
w->Panel[b].x2, w->Panel[b].z2,
|
||||
w->CurX+nx*LARGEVAL, w->CurZ+nz*LARGEVAL,
|
||||
w->CurX-nx*LARGEVAL, w->CurZ-nz*LARGEVAL );
|
||||
if (res.isValid)
|
||||
{
|
||||
temp = DistF( w->Cur, res.result );
|
||||
|
||||
if( temp < inters )
|
||||
{
|
||||
inters = temp;
|
||||
w->CurPanel = b;
|
||||
x = res.result.x;
|
||||
z = res.result.z;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
w->Cur = p;
|
||||
|
||||
#undef LARGEVAL
|
||||
}
|
||||
|
||||
/*-----------------15/10/96 14.23-------------------
|
||||
Valuta lunghezza percorso
|
||||
--------------------------------------------------*/
|
||||
float EvalPath(int32 oc, int a, PointXZ dest, int nearp) {
|
||||
t3dCHARACTER *Act = Character[oc];
|
||||
t3dWALK *w = &Act->Walk;
|
||||
float len;
|
||||
PointXZ cur;
|
||||
int b;
|
||||
int curp;
|
||||
|
||||
b = 0;
|
||||
|
||||
len = 0.0;
|
||||
|
||||
curp = w->PathNode[a].curp;
|
||||
cur = w->PathNode[a].pos;
|
||||
|
||||
for (;;) {
|
||||
// se raggiunge il pto esce
|
||||
if (curp == w->PathNode[a + 1].curp) {
|
||||
len += DistF(cur, w->PathNode[a + 1].pos);
|
||||
break;
|
||||
}
|
||||
|
||||
// se e' tornato al pannello di partenza non trova starda
|
||||
if ((curp == w->PathNode[a].curp) && (b)) {
|
||||
len += 320000.0; // lunghezza assurda
|
||||
break;
|
||||
}
|
||||
|
||||
// altrimenti va fino al prossimo pannello
|
||||
|
||||
// se nearp e' attacato a curp col vertice 1
|
||||
if (w->Panel[nearp].near1 == curp) {
|
||||
// vai al vertice 2 la prossima volta
|
||||
len += DistF(cur, dest);
|
||||
|
||||
cur = dest;
|
||||
|
||||
dest = w->Panel[nearp].b;
|
||||
|
||||
curp = nearp;
|
||||
nearp = w->Panel[curp].near2;
|
||||
} else {
|
||||
// vai al vertice 1 la prossima volta
|
||||
len += DistF(cur, dest);
|
||||
|
||||
cur = dest;
|
||||
|
||||
dest = w->Panel[nearp].a;
|
||||
|
||||
curp = nearp;
|
||||
nearp = w->Panel[curp].near1;
|
||||
}
|
||||
|
||||
b++;
|
||||
}
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------15/10/96 10.18-------------------
|
||||
cerca percorso piu' corto aggirando ostacoli
|
||||
--------------------------------------------------*/
|
||||
void FindShortPath(int32 oc) {
|
||||
t3dCHARACTER *Act = Character[oc];
|
||||
t3dWALK *w = &Act->Walk;
|
||||
t3dPATHNODE TempPath[T3D_MAX_PATHNODES];
|
||||
int count = 0, inters;
|
||||
float len1, len2;
|
||||
PointXZ cur;
|
||||
int curp, nearp, oldp;
|
||||
PointXZ dest;
|
||||
signed int a, b, c, fail = 0;
|
||||
|
||||
count = 0;
|
||||
// aggiunge partenza
|
||||
TempPath[count].pos.x = Act->Pos.x;
|
||||
TempPath[count].pos.z = Act->Pos.z;
|
||||
TempPath[count].dist = 0.0;
|
||||
TempPath[count].oldp = w->OldPanel;
|
||||
TempPath[count].curp = w->OldPanel;
|
||||
count ++;
|
||||
|
||||
// per ogni ostacolo cerca di aggirarlo a destra e a sinistra
|
||||
// poi guarda quello che e' piu' corto
|
||||
for (a = 0; a < w->NumPathNodes - 1; a++) {
|
||||
memcpy(&TempPath[count], &w->PathNode[a], sizeof(t3dPATHNODE));
|
||||
count ++;
|
||||
|
||||
curp = w->PathNode[a].curp;
|
||||
|
||||
// se pannello sorgente e destinazione non sono sullo stesso blocco
|
||||
if (!(FindAttachedPanel(oc, curp, w->PathNode[a + 1].curp)))
|
||||
continue;
|
||||
|
||||
// aggira l'ostacolo partendo da near1
|
||||
len1 = EvalPath(oc, a, w->Panel[curp].a, w->Panel[curp].near1) + DistF(w->PathNode[a].pos, w->Panel[curp].a);
|
||||
|
||||
// aggira l'ostacolo partendo da near2
|
||||
len2 = EvalPath(oc, a, w->Panel[curp].b, w->Panel[curp].near2) + DistF(w->PathNode[a].pos,w->Panel[curp].b);
|
||||
|
||||
// guarda quale starda era piu' breve e se esiste una strada
|
||||
if ((len1 < 320000.0) && (len2 < 320000.0)) {
|
||||
if (len1 < len2) {
|
||||
dest = w->Panel[curp].a;
|
||||
nearp = w->Panel[curp].near1;
|
||||
} else {
|
||||
dest = w->Panel[curp].b;
|
||||
nearp = w->Panel[curp].near2;
|
||||
}
|
||||
|
||||
cur = w->PathNode[a].pos;
|
||||
oldp = curp;
|
||||
|
||||
b = 0;
|
||||
|
||||
// salva percorso piu corto
|
||||
for (;;) {
|
||||
|
||||
TempPath[count].pos = cur;
|
||||
TempPath[count].oldp = oldp;
|
||||
TempPath[count].curp = curp;
|
||||
count ++;
|
||||
|
||||
// se raggiunge il pto esce
|
||||
if (curp == w->PathNode[a + 1].curp) {
|
||||
// attenzione: prima era
|
||||
//memcpy( &TempPath[count], &PathNode[++a], sizeof( struct SPathNode ) );
|
||||
memcpy(&TempPath[count], &w->PathNode[a + 1], sizeof(t3dPATHNODE));
|
||||
count ++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// se e' tornato al pannello di partenza non trova starda
|
||||
if ((curp == w->PathNode[a].curp) && (b)) {
|
||||
fail = 1; // si ferma al vertice prima
|
||||
break; // e non contiuma a camminare
|
||||
}
|
||||
|
||||
// altrimenti va fino al prossimo pannello
|
||||
|
||||
// se nearp e' attacato a curp col vertice 1
|
||||
if (w->Panel[nearp].near1 == curp) {
|
||||
// vai al vertice 2 la prossima volta
|
||||
cur = dest;
|
||||
|
||||
dest = w->Panel[nearp].b;
|
||||
|
||||
oldp = curp;
|
||||
curp = nearp;
|
||||
nearp = w->Panel[curp].near2;
|
||||
} else {
|
||||
// vai al vertice 1 la prossima volta
|
||||
cur = dest;
|
||||
|
||||
dest = w->Panel[nearp].a;
|
||||
|
||||
oldp = curp;
|
||||
curp = nearp;
|
||||
nearp = w->Panel[curp].near1;
|
||||
}
|
||||
|
||||
b++;
|
||||
}
|
||||
|
||||
} else {
|
||||
//DebugText("Fail: FindShortPath");
|
||||
fail = 1;
|
||||
}
|
||||
|
||||
if (fail) // se non riesce ad aggirare ostacolo si ferma
|
||||
break;
|
||||
}
|
||||
|
||||
// aggiunge arrivo
|
||||
TempPath[count].pos = w->Cur;
|
||||
TempPath[count].dist = 0.0;
|
||||
TempPath[count].oldp = w->CurPanel;
|
||||
TempPath[count].curp = w->CurPanel;
|
||||
count ++;
|
||||
|
||||
for (b = 0; b < count; b++)
|
||||
DebugLogFile("FSP %d: %f %f | %d %d", b, TempPath[b].pos.x, TempPath[b].pos.z, TempPath[b].oldp, TempPath[b].curp);
|
||||
// dopo che ha aggirato tutti gli ostacoli ottimizza
|
||||
|
||||
// memcpy( w->PathNode, TempPath, sizeof( struct SPathNode )*count );
|
||||
// w->NumPathNodes = count;
|
||||
// return ;
|
||||
|
||||
w->NumPathNodes = 0;
|
||||
for (a = 0; a < count; a++) {
|
||||
//printf("N:%d | ",a);
|
||||
if (w->NumPathNodes > (T3D_MAX_PATHNODES - 2))
|
||||
w->NumPathNodes = (T3D_MAX_PATHNODES - 2);
|
||||
|
||||
// prima leva tutti i nodi attaccati
|
||||
for (b = (count - 1); b >= a; b--)
|
||||
if (DistF(TempPath[b].pos, TempPath[a].pos) < EPSILON)
|
||||
break;
|
||||
DebugLogFile("Da %d passo a %d\n", a, b);
|
||||
a = b;
|
||||
|
||||
memcpy(&w->PathNode[w->NumPathNodes], &TempPath[a], sizeof(t3dPATHNODE));
|
||||
w->NumPathNodes ++;
|
||||
|
||||
for (b = (count - 1); b > a + 1; b--) {
|
||||
inters = 0;
|
||||
for (c = 0; c < w->PanelNum; c++) {
|
||||
// non deve intersecare pannello stretto mai
|
||||
// if( !( w->Panel[c].flags & 0x80000000 ) )
|
||||
{
|
||||
PointResult res = IntersLineLine(w->Panel[c].backA, w->Panel[c].backB,
|
||||
TempPath[a].pos, TempPath[b].pos);
|
||||
if (res.isValid)
|
||||
inters ++;
|
||||
|
||||
res = IntersLineLine(w->Panel[c].a, w->Panel[c].backA,
|
||||
TempPath[a].pos, TempPath[b].pos);
|
||||
if (res.isValid) {
|
||||
len2 = DistF(res.result, TempPath[a].pos);
|
||||
len1 = DistF(res.result, TempPath[b].pos);
|
||||
|
||||
// interseca in un pto distante da partenza e arrivo
|
||||
if ((len1 > EPSILON) && (len2 > EPSILON))
|
||||
inters ++;
|
||||
}
|
||||
|
||||
res = IntersLineLine(w->Panel[c].b, w->Panel[c].backB,
|
||||
TempPath[a].pos, TempPath[b].pos);
|
||||
if (res.isValid) {
|
||||
len2 = DistF(res.result, TempPath[a].pos);
|
||||
len1 = DistF(res.result, TempPath[b].pos);
|
||||
|
||||
// interseca in un pto distante da partenza e arrivo
|
||||
if ((len1 > EPSILON) && (len2 > EPSILON))
|
||||
inters ++;
|
||||
}
|
||||
|
||||
if (inters)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// se da a posso raggiungere b direttamente
|
||||
if (!inters) {
|
||||
curp = w->PathNode[w->NumPathNodes - 1].curp;
|
||||
oldp = TempPath[b].oldp;
|
||||
|
||||
for (c = a; c <= b; c++)
|
||||
if ((TempPath[c].oldp == curp) && (TempPath[c].curp == oldp))
|
||||
break;
|
||||
|
||||
// se non erano collegati signica che e' passato per il pavimento
|
||||
if (c > b) {
|
||||
DebugLogFile("Arr %d %d Part %d %d | %d", b, TempPath[b].oldp, a, w->PathNode[w->NumPathNodes - 1].curp, w->NumPathNodes - 1);
|
||||
w->PathNode[w->NumPathNodes - 1].curp = -1; // partenza
|
||||
TempPath[b].oldp = -1; // arrivo
|
||||
}
|
||||
a = b - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (b = 0; b < w->NumPathNodes; b++)
|
||||
DebugLogFile("SSP %d: %f %f | %d %d", b, w->PathNode[b].pos.x, w->PathNode[b].pos.z, w->PathNode[b].oldp, w->PathNode[b].curp);
|
||||
}
|
||||
|
||||
/* -----------------04/02/98 15.48-------------------
|
||||
* Crea percorso
|
||||
* --------------------------------------------------*/
|
||||
void FindPath(int32 oc, t3dCAMERA *Camera) {
|
||||
t3dCHARACTER *Act = Character[oc];
|
||||
t3dWALK *w = &Act->Walk;
|
||||
int inters, check;
|
||||
float dist;
|
||||
int b;
|
||||
|
||||
w->NumPathNodes = 0;
|
||||
w->CurrentStep = 0;
|
||||
w->NumSteps = 0;
|
||||
|
||||
// FIXME: condition never happen!
|
||||
//if( !w->PathNode ) return;
|
||||
|
||||
check = 0;
|
||||
inters = 0;
|
||||
w->NumPathNodes = 0;
|
||||
|
||||
w->OldPanel = w->CurPanel;
|
||||
if (FloorHit)
|
||||
w->CurPanel = -1;
|
||||
/* else
|
||||
w->CurPanel = 1;
|
||||
*/
|
||||
PointOut(oc, Camera);
|
||||
w->Look = w->Cur;
|
||||
|
||||
// se hai cliccato dietro il pannello di partenza o dell'angolo non puo' camminare
|
||||
if ((w->CurPanel < 0) && (w->OldPanel >= 0) &&
|
||||
// dietro il pannello di partenza
|
||||
((PointInside(oc, b = w->OldPanel, w->Cur)) ||
|
||||
// dietro il pannello angolo1
|
||||
((DistF(w->Panel[w->OldPanel].a.x, w->Panel[w->OldPanel].a.z, Act->Pos.x, Act->Pos.z) < EPSILON) &&
|
||||
(PointInside(oc, b = w->Panel[w->OldPanel].near1, w->Cur))) ||
|
||||
// dietro il pannello angolo2
|
||||
((DistF(w->Panel[w->OldPanel].b.x, w->Panel[w->OldPanel].b.z, Act->Pos.x, Act->Pos.z) < EPSILON) &&
|
||||
(PointInside(oc, b = w->Panel[w->OldPanel].near2, w->Cur))))) {
|
||||
w->Cur.x = Act->Pos.x;
|
||||
w->Cur.z = Act->Pos.z;
|
||||
w->CurPanel = b;
|
||||
w->NumPathNodes = 0;
|
||||
check |= CLICKINTO;
|
||||
w->Check = check;
|
||||
return ;
|
||||
}
|
||||
DebugLogFile("W: CP %d OP %d | %f %f | %f %f", w->CurPanel, w->OldPanel, Act->Pos.x, Act->Pos.z, w->Cur.x, w->Cur.z);
|
||||
|
||||
dist = DistF(Act->Pos.x, Act->Pos.z, w->Cur.x, w->Cur.z);
|
||||
// if( dist < EPSILON )
|
||||
// return ;
|
||||
|
||||
for (b = 0; b < w->PanelNum; b++) {
|
||||
PointResult res = IntersLineLine(w->Panel[b].a, w->Panel[b].b,
|
||||
Act->Pos.x, Act->Pos.z,
|
||||
w->Cur.x, w->Cur.z);
|
||||
if (res.isValid) {
|
||||
inters ++;
|
||||
DebugLogFile("Inters %d: %f %f %f %f", b, w->Panel[b].a.x, w->Panel[b].a.z, w->Panel[b].b.x, w->Panel[b].b.z);
|
||||
|
||||
w->PathNode[w->NumPathNodes].pos = res.result;
|
||||
w->PathNode[w->NumPathNodes].dist = DistF(Act->Pos.x, Act->Pos.z, res.result.x, res.result.z);
|
||||
w->PathNode[w->NumPathNodes].oldp = b;
|
||||
w->PathNode[w->NumPathNodes].curp = b;
|
||||
w->NumPathNodes ++;
|
||||
|
||||
// ANGOLI - leva intersezioni in angoli
|
||||
if ((w->OldPanel >= 0) && ((b == w->Panel[w->OldPanel].near1) || (b == w->Panel[w->OldPanel].near2))) {
|
||||
// altrimenti se e' vicino al pannello di partenza
|
||||
if ((w->PathNode[w->NumPathNodes - 1].dist < EPSILON) &&
|
||||
(b != w->OldPanel) && (b != w->CurPanel)) {
|
||||
// e la distanza e' molto piccola leva l'intersezione
|
||||
inters --;
|
||||
w->NumPathNodes --;
|
||||
check |= OLDANGLESKIP;
|
||||
|
||||
// se ho cliccato dentro il pannello vicino
|
||||
if ((w->CurPanel < 0) && (PointInside(oc, b, w->Cur))) {
|
||||
w->Cur.x = Act->Pos.x;
|
||||
w->Cur.z = Act->Pos.z;
|
||||
w->CurPanel = b;
|
||||
w->NumPathNodes = 0;
|
||||
check |= CLICKINTO;
|
||||
w->Check = check;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
} else if ((w->CurPanel >= 0) && ((b == w->Panel[w->CurPanel].near1) || (b == w->Panel[w->CurPanel].near2))) {
|
||||
// altrimenti se e' vicino al pannello di arrivo
|
||||
if ((fabs(w->PathNode[w->NumPathNodes - 1].dist - dist) < EPSILON) &&
|
||||
(b != w->OldPanel) && (b != w->CurPanel)) {
|
||||
// e la distanza e' molto piccola leva l'intersezione
|
||||
inters --;
|
||||
w->NumPathNodes --;
|
||||
check |= CURANGLESKIP;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// aggiunge sempre nodo partenza e arrivo solo se su un pannelli
|
||||
else if (b == w->OldPanel) {
|
||||
inters ++;
|
||||
|
||||
w->PathNode[w->NumPathNodes].pos.x = Act->Pos.x;
|
||||
w->PathNode[w->NumPathNodes].pos.z = Act->Pos.z;
|
||||
w->PathNode[w->NumPathNodes].dist = 0.0;
|
||||
w->PathNode[w->NumPathNodes].oldp = w->OldPanel;
|
||||
w->PathNode[w->NumPathNodes].curp = w->OldPanel;
|
||||
w->NumPathNodes ++;
|
||||
|
||||
check |= NOOLDINTERS;
|
||||
} else if (b == w->CurPanel) {
|
||||
inters ++;
|
||||
|
||||
w->PathNode[w->NumPathNodes].pos = w->Cur;
|
||||
w->PathNode[w->NumPathNodes].dist = dist;
|
||||
w->PathNode[w->NumPathNodes].oldp = w->CurPanel;
|
||||
w->PathNode[w->NumPathNodes].curp = w->CurPanel;
|
||||
w->NumPathNodes ++;
|
||||
|
||||
check |= NOCURINTERS;
|
||||
}
|
||||
}
|
||||
|
||||
// il percorso e' definito da:
|
||||
// start Act.px, Act.pz
|
||||
// NumPathNodes PathNode
|
||||
// end CurX, CurZ
|
||||
|
||||
// se scontra contro qualche pannello
|
||||
if (inters) {
|
||||
SortPath(oc);
|
||||
|
||||
// se dispari e vado nel pavimento ma non sono partito da pannello
|
||||
// se vado nel pavimento e ultimi due nodi non sono su stesso blocco
|
||||
// se all'esterno dell'ultimo pannello sposta ultimo nodo
|
||||
if (w->NumPathNodes > 1)
|
||||
DebugLogFile("I %d | CP %d | OP %d | FA %d (%d %d) | PI %d (%d)", inters, w->CurPanel, w->OldPanel,
|
||||
FindAttachedPanel(oc, w->PathNode[w->NumPathNodes - 2].curp, w->PathNode[w->NumPathNodes - 1].curp), w->PathNode[w->NumPathNodes - 2].curp, w->PathNode[w->NumPathNodes - 1].curp,
|
||||
PointInside(oc, w->PathNode[w->NumPathNodes - 1].curp, w->Cur), w->PathNode[w->NumPathNodes - 1].curp);
|
||||
|
||||
if (((inters & 1) && (w->CurPanel < 0) && (w->OldPanel < 0)) ||
|
||||
((w->CurPanel < 0) && (w->NumPathNodes >= 1) && (PointInside(oc, w->PathNode[w->NumPathNodes - 1].curp, w->Cur))) ||
|
||||
(((inters - 1) & 1) && (w->CurPanel < 0) && (w->NumPathNodes >= 2) &&
|
||||
(!(FindAttachedPanel(oc, w->PathNode[w->NumPathNodes - 2].curp, w->PathNode[w->NumPathNodes - 1].curp)) ||
|
||||
(PointInside(oc, w->PathNode[w->NumPathNodes - 1].curp, w->Cur))))) {
|
||||
w->CurPanel = w->PathNode[w->NumPathNodes - 1].curp;
|
||||
|
||||
PointOut(oc, Camera); // tira fuori il pto trovato
|
||||
|
||||
w->PathNode[w->NumPathNodes].pos = w->Cur;
|
||||
w->PathNode[w->NumPathNodes].oldp = w->CurPanel;
|
||||
w->PathNode[w->NumPathNodes].curp = w->CurPanel;
|
||||
|
||||
UpdateLook(oc);
|
||||
|
||||
w->NumPathNodes ++;
|
||||
|
||||
check |= POINTOUT1;
|
||||
|
||||
DebugLogFile("PO %d %d %f", w->NumPathNodes, w->CurPanel, DistF(Act->Pos.x, Act->Pos.z, w->Cur.x, w->Cur.z));
|
||||
// if ( DistF( Act->Pos.x, Act->Pos.z, w->CurX, w->CurZ ) < EPSILON )
|
||||
// check |= CLICKINTO;
|
||||
}
|
||||
|
||||
// se arrivo su pavimento
|
||||
if (w->CurPanel < 0) {
|
||||
inters = 0;
|
||||
|
||||
// conto intersezioni con pannelli stretti
|
||||
// e con unione pannelli larghi con pannelli stretti
|
||||
for (b = 0; b < w->PanelNum; b++) {
|
||||
PointResult res;
|
||||
res = IntersLineLine(w->Panel[b].a, w->Panel[b].b,
|
||||
w->PathNode[w->NumPathNodes - 1].pos, w->Cur);
|
||||
if (res.isValid)
|
||||
if ((DistF(res.result, w->PathNode[w->NumPathNodes - 1].pos) > EPSILON) &&
|
||||
(DistF(res.result, w->Cur) > EPSILON))
|
||||
inters ++;
|
||||
|
||||
res = IntersLineLine(w->Panel[b].a, w->Panel[b].backA,
|
||||
w->PathNode[w->NumPathNodes - 1].pos, w->Cur);
|
||||
if (res.isValid)
|
||||
if ((DistF(res.result, w->PathNode[w->NumPathNodes - 1].pos) > EPSILON) &&
|
||||
(DistF(res.result, w->Cur) > EPSILON))
|
||||
inters ++;
|
||||
|
||||
res = IntersLineLine(w->Panel[b].b, w->Panel[b].backB,
|
||||
w->PathNode[w->NumPathNodes - 1].pos, w->Cur);
|
||||
if (res.isValid)
|
||||
if ((DistF(res.result, w->PathNode[w->NumPathNodes - 1].pos) > EPSILON) &&
|
||||
(DistF(res.result, w->Cur) > EPSILON))
|
||||
inters ++;
|
||||
|
||||
if (inters)
|
||||
break;
|
||||
}
|
||||
|
||||
// se nell'ultimo tratto c'e un ostacolo leva primo nodo
|
||||
if (inters) {
|
||||
w->CurPanel = w->PathNode[w->NumPathNodes - 1].curp;
|
||||
|
||||
PointOut(oc, Camera); // tira fuori il pto trovato
|
||||
w->PathNode[w->NumPathNodes].pos = w->Cur;
|
||||
w->PathNode[w->NumPathNodes].oldp = w->CurPanel;
|
||||
w->PathNode[w->NumPathNodes].curp = w->CurPanel;
|
||||
|
||||
UpdateLook(oc);
|
||||
|
||||
w->NumPathNodes ++;
|
||||
|
||||
check |= POINTOUT2;
|
||||
}
|
||||
}
|
||||
|
||||
DebugLogFile("CP: %d || OP: %d || %f %f || I: %d || C: %d || NPN: %d", w->CurPanel, w->OldPanel, w->Cur.x, w->Cur.z, inters, check, w->NumPathNodes);
|
||||
//DebugText("CP: %d || OP: %d || I: %d || C: %d || PI: %d || NPN: %d", CurPanel, OldPanel, inters, check, PointInside( OldPanel, CurX, CurZ ), NumPathNodes );
|
||||
|
||||
w->PathNode[w->NumPathNodes].pos = w->Cur;
|
||||
w->PathNode[w->NumPathNodes].dist = DistF(Act->Pos.x, Act->Pos.z, w->Cur.x, w->Cur.z);
|
||||
w->PathNode[w->NumPathNodes].oldp = w->CurPanel;
|
||||
w->PathNode[w->NumPathNodes].curp = w->CurPanel;
|
||||
w->NumPathNodes ++;
|
||||
|
||||
for (b = 0; b < w->NumPathNodes; b++)
|
||||
DebugLogFile("FP %d: %f %f | %d %d", b, w->PathNode[b].pos.x, w->PathNode[b].pos.z, w->PathNode[b].oldp, w->PathNode[b].curp);
|
||||
|
||||
FindShortPath(oc);
|
||||
|
||||
// DisplayPath();
|
||||
} else { // altrimenti starda diretta
|
||||
DebugLogFile("NOI CP: %d || OP: %d || I: %d || C: %d || NPN: %d", w->CurPanel, w->OldPanel, inters, check, w->NumPathNodes);
|
||||
//DebugText("NOI CP: %d || OP: %d || I: %d || C: %d || PI: %d || NPN: %d", CurPanel, OldPanel, inters, check, PointInside( OldPanel, CurX, CurZ ), NumPathNodes );
|
||||
w->PathNode[w->NumPathNodes].pos.x = Act->Pos.x;
|
||||
w->PathNode[w->NumPathNodes].pos.z = Act->Pos.z;
|
||||
w->PathNode[w->NumPathNodes].dist = 0.0;
|
||||
w->PathNode[w->NumPathNodes].oldp = w->OldPanel;
|
||||
w->PathNode[w->NumPathNodes].curp = w->OldPanel;
|
||||
w->NumPathNodes ++;
|
||||
|
||||
w->PathNode[w->NumPathNodes].pos = w->Cur;
|
||||
w->PathNode[w->NumPathNodes].dist = DistF(Act->Pos.x, Act->Pos.z, w->Cur.x, w->Cur.z);
|
||||
w->PathNode[w->NumPathNodes].oldp = w->CurPanel;
|
||||
w->PathNode[w->NumPathNodes].curp = w->CurPanel;
|
||||
w->NumPathNodes ++;
|
||||
|
||||
}
|
||||
w->Check = check;
|
||||
DebugLogFile("End Walk %f %f %d | %f %f %d", Act->Pos.x, Act->Pos.z, w->OldPanel, w->Cur.x, w->Cur.z, w->CurPanel);
|
||||
}
|
||||
|
||||
/* -----------------12/02/99 11.07-------------------
|
||||
* ForceAnimInBounds
|
||||
* --------------------------------------------------*/
|
||||
void ForceAnimInBounds(int32 oc) {
|
||||
t3dCHARACTER *Act = Character[oc];
|
||||
t3dWALK *w = &Act->Walk;
|
||||
t3dV3F *Trasl;
|
||||
int inters, nf;
|
||||
float dist;
|
||||
int a, b;
|
||||
|
||||
if (!Act || !w) return ;
|
||||
|
||||
nf = Act->Mesh->Anim.NumFrames;
|
||||
Trasl = Act->Mesh->Anim.BoneTable[0].Trasl;
|
||||
if (!Trasl) return ;
|
||||
|
||||
inters = 0;
|
||||
dist = DistF(Trasl[0].x, Trasl[0].z, Trasl[nf - 1].x, Trasl[nf - 1].z);
|
||||
if (dist < EPSILON) return ; // Se non si muove esce
|
||||
|
||||
for (a = 1; a < nf; a++) {
|
||||
for (b = 0; b < w->PanelNum; b++) {
|
||||
// Se all'ultimo frame finirei dentro un pannello aggiorna CurPanel
|
||||
if ((a == (nf - 1)) && (PointInside(oc, b, Trasl[a].x, Trasl[a].z))) {
|
||||
w->OldPanel = w->CurPanel;
|
||||
w->CurPanel = b;
|
||||
DebugLogFile("Aggiorno CurPanel %d", b);
|
||||
}
|
||||
// Se un punto interseca pannello slida
|
||||
PointResult res = IntersLineLine(w->Panel[b].a, w->Panel[b].b,
|
||||
Trasl[0].x, Trasl[0].z,
|
||||
Trasl[a].x, Trasl[a].z);
|
||||
if (res.isValid) {
|
||||
inters ++;
|
||||
|
||||
Trasl[a].x = res.result.x;
|
||||
Trasl[a].z = res.result.z;
|
||||
DebugLogFile("%d: entrerebbe in %d", a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
(void)inters;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
51
engines/watchmaker/walk/walk.h
Normal file
51
engines/watchmaker/walk/walk.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_WALK_H
|
||||
#define WATCHMAKER_WALK_H
|
||||
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
#define EPSILON 0.007f
|
||||
|
||||
#define NOOLDINTERS 1
|
||||
#define NOCURINTERS 2
|
||||
#define OLDANGLESKIP 4
|
||||
#define CURANGLESKIP 8
|
||||
#define CLICKINTO 16
|
||||
#define POINTOUT1 32
|
||||
#define POINTOUT2 64
|
||||
#define LONGPATH 128
|
||||
#define NOBOUNDCHECK 256
|
||||
#define NOTSKIPPABLE 512
|
||||
|
||||
extern int32 ActionLen[];
|
||||
extern int32 ActionStart[];
|
||||
|
||||
void FindPath(int32 oc, t3dCAMERA *Camera);
|
||||
void ForceAnimInBounds(int32 oc);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_WALK_H
|
||||
239
engines/watchmaker/walk/walkutil.cpp
Normal file
239
engines/watchmaker/walk/walkutil.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
/* 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/walkutil.h"
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
#include "watchmaker/walk/walk.h"
|
||||
#include "watchmaker/globvar.h"
|
||||
#include "watchmaker/windows_hacks.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
/* -----------------05/06/00 12.49-------------------
|
||||
* PointIn2DRectangle
|
||||
* --------------------------------------------------*/
|
||||
bool PointInside2DRectangle(double pgon[4][2], double x, double z) {
|
||||
bool inside_flag;
|
||||
|
||||
// Crossing-Multiply algorithm
|
||||
{
|
||||
int j, yflag0, yflag1, xflag0;
|
||||
double *vtx0, *vtx1 ;
|
||||
|
||||
vtx0 = pgon[3];
|
||||
// get test bit for above/below X axis
|
||||
yflag0 = (vtx0[1] >= z);
|
||||
vtx1 = pgon[0];
|
||||
|
||||
inside_flag = 0;
|
||||
for (j = 5; --j ;) {
|
||||
yflag1 = (vtx1[1] >= z);
|
||||
if (yflag0 != yflag1) {
|
||||
xflag0 = (vtx0[0] >= x);
|
||||
if ((xflag0 == (vtx1[0] >= x)) && (xflag0))
|
||||
inside_flag += (yflag0 ? -1 : 1);
|
||||
else if ((vtx1[0] - (vtx1[1] - z) * (vtx0[0] - vtx1[0]) / (vtx0[1] - vtx1[1])) >= x)
|
||||
inside_flag += (yflag0 ? -1 : 1);
|
||||
}
|
||||
// Move to the next pair of vertices, retaining info as possible.
|
||||
yflag0 = yflag1 ;
|
||||
vtx0 = vtx1 ;
|
||||
vtx1 += 2 ;
|
||||
}
|
||||
}
|
||||
|
||||
return (inside_flag) ;
|
||||
}
|
||||
|
||||
/* 04/02/98 16.01 ----------------------------------
|
||||
Guarda se un pto e' all'interno di un pannello
|
||||
--------------------------------------------------*/
|
||||
int PointInside(int32 oc, int32 pan, const PointXZ &point) {
|
||||
return PointInside(oc, pan, (double)point.x, (double)point.z);
|
||||
}
|
||||
int PointInside(int32 oc, int32 pan, double x, double z) {
|
||||
t3dWALK *w = &Character[oc]->Walk;
|
||||
double pgon[4][2], ox, oz, s;
|
||||
|
||||
if (pan < 0)
|
||||
return FALSE;
|
||||
|
||||
pgon[0][0] = (double)w->Panel[pan].a.x;
|
||||
pgon[0][1] = (double)w->Panel[pan].a.z;
|
||||
pgon[3][0] = (double)w->Panel[pan].b.x;
|
||||
pgon[3][1] = (double)w->Panel[pan].b.z;
|
||||
|
||||
pgon[1][0] = (double)w->Panel[pan].backA.x;
|
||||
pgon[1][1] = (double)w->Panel[pan].backA.z;
|
||||
|
||||
pgon[2][0] = (double)w->Panel[pan].backB.x;
|
||||
pgon[2][1] = (double)w->Panel[pan].backB.z;
|
||||
|
||||
ox = pgon[3][0] - pgon[0][0];
|
||||
oz = pgon[3][1] - pgon[0][1];
|
||||
s = sqrt(ox * ox + oz * oz);
|
||||
ox /= s;
|
||||
oz /= s;
|
||||
pgon[0][0] -= EPSILON * ox;
|
||||
pgon[0][1] -= EPSILON * oz;
|
||||
pgon[3][0] += EPSILON * ox;
|
||||
pgon[3][1] += EPSILON * oz;
|
||||
|
||||
ox = pgon[2][0] - pgon[1][0];
|
||||
oz = pgon[2][1] - pgon[1][1];
|
||||
s = sqrt(ox * ox + oz * oz);
|
||||
ox /= s;
|
||||
oz /= s;
|
||||
pgon[1][0] -= EPSILON * ox;
|
||||
pgon[1][1] -= EPSILON * oz;
|
||||
pgon[2][0] += EPSILON * ox;
|
||||
pgon[2][1] += EPSILON * oz;
|
||||
|
||||
return (PointInside2DRectangle(pgon, x, z)) ;
|
||||
}
|
||||
|
||||
/*-----------------07/10/96 11.14-------------------
|
||||
Distanza falsa tra 2 punti 2D
|
||||
--------------------------------------------------*/
|
||||
float DistF(PointXZ a, PointXZ b) {
|
||||
return DistF(a.x, a.z, b.x, b.z);
|
||||
}
|
||||
|
||||
float DistF(float x1, float y1, float x2, float y2) {
|
||||
float d1 = (float)fabs(x1 - x2);
|
||||
float d2 = (float)fabs(y1 - y2);
|
||||
#if 0
|
||||
float minimum;
|
||||
|
||||
if (d1 >= d2)
|
||||
minimum = d2;
|
||||
else
|
||||
minimum = d1;
|
||||
|
||||
return d1+d2 - ( minimum / 2.0 );
|
||||
#endif
|
||||
return (float)(sqrt(d1 * d1 + d2 * d2));
|
||||
}
|
||||
/*-----------------07/10/96 11.21-------------------
|
||||
Interseca linea 2D con linea 2D
|
||||
--------------------------------------------------*/
|
||||
PointResult IntersLineLine(const PointXZ &a, const PointXZ &b, const PointXZ &c, const PointXZ &d) {
|
||||
return IntersLineLine(a.x, a.z, b.x, b.z, c.x, c.z, d.x, d.z);
|
||||
}
|
||||
PointResult IntersLineLine(const PointXZ &a, const PointXZ &b, float xc, float yc, float xd, float yd) {
|
||||
return IntersLineLine(a.x, a.z, b.x, b.z, xc, yc, xd, yd);
|
||||
}
|
||||
PointResult IntersLineLine(float xa, float ya, float xb, float yb, float xc, float yc, float xd, float yd) {
|
||||
float divisor = (float)((xb - xa) * (yd - yc) - (yb - ya) * (xd - xc));
|
||||
if (!divisor) divisor = 0.000001f;
|
||||
float r = (float)((ya - yc) * (xd - xc) - (xa - xc) * (yd - yc)) / divisor;
|
||||
float s = (float)((ya - yc) * (xb - xa) - (xa - xc) * (yb - ya)) / divisor;
|
||||
|
||||
PointResult result;
|
||||
if ((r < -EPSILON) || (r > (1.0f + EPSILON)) || (s < -EPSILON) || (s > (1.0f + EPSILON))) {
|
||||
result.isValid = false;
|
||||
} else {
|
||||
if (r < 0.0f) r = 0.0f;
|
||||
else if (r > 1.0f) r = 1.0f;
|
||||
|
||||
result.result.x = xa + r * (xb - xa);
|
||||
result.result.z = ya + r * (yb - ya);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*-----------------15/10/96 10.33-------------------
|
||||
Compara distanza percorso (qsort)
|
||||
--------------------------------------------------*/
|
||||
int PathCompare(const void *arg1, const void *arg2) {
|
||||
const t3dPATHNODE *p1, *p2;
|
||||
|
||||
p1 = (const t3dPATHNODE *)arg1;
|
||||
p2 = (const t3dPATHNODE *)arg2;
|
||||
|
||||
if (p1->dist < p2->dist)
|
||||
return -1;
|
||||
else if (p1->dist > p2->dist)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------15/10/96 10.34-------------------
|
||||
Sorta i nodi del percorso trovato
|
||||
--------------------------------------------------*/
|
||||
void SortPath(int32 oc) {
|
||||
t3dWALK *w = &Character[oc]->Walk;
|
||||
qsort(&w->PathNode[0], w->NumPathNodes, sizeof(t3dPATHNODE), PathCompare);
|
||||
}
|
||||
|
||||
/*-----------------06/11/95 15.42-------------------
|
||||
Torna l'angolo in rad dati seno e coseno
|
||||
--------------------------------------------------*/
|
||||
t3dF32 SinCosAngle(t3dF32 sinus, t3dF32 cosinus) {
|
||||
t3dF32 t;
|
||||
t = (t3dF32)sqrt((t3dF64)(sinus * sinus) + (t3dF64)(cosinus * cosinus));
|
||||
cosinus /= t;
|
||||
sinus /= t;
|
||||
|
||||
if ((sinus == cosinus) && (cosinus == 0)) {
|
||||
return 0;
|
||||
#if 0
|
||||
// FIXME: Is this duplicate code correct as the 2e4 is identical...
|
||||
} else if (sinus * cosinus >= 0) {
|
||||
// 1e3 quad
|
||||
if (sinus >= 0)
|
||||
// 1 quad
|
||||
return (t3dF32)acos(cosinus);
|
||||
else
|
||||
// 3 quad
|
||||
return (t3dF32)T3D_PI * 2.0f - (t3dF32)acos(cosinus);
|
||||
#endif
|
||||
} else {
|
||||
// 2e4 quad
|
||||
if (sinus >= 0)
|
||||
// 2 quad
|
||||
return (t3dF32)acos(cosinus);
|
||||
else
|
||||
// 3 quad
|
||||
return (t3dF32)T3D_PI * 2.0f - (t3dF32)acos(cosinus);
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------09/11/98 10.44-------------------
|
||||
* t3dVectAngle
|
||||
* torna angolo in gradi (da -180 a +180) tra due vettori
|
||||
* --------------------------------------------------*/
|
||||
t3dF32 t3dVectAngle(t3dV3F *n, t3dV3F *o) {
|
||||
t3dF32 a = ((SinCosAngle(n->z, n->x) - SinCosAngle(o->z, o->x)) * 180.0f) / T3D_PI;
|
||||
|
||||
while (a > 360.0f) a -= 360.0f;
|
||||
while (a < 0.0f) a += 360.0f;
|
||||
|
||||
if (a > 180.0f) a -= 360.0f;
|
||||
else if (a < -180.0f) a += 360.0f;
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
45
engines/watchmaker/walk/walkutil.h
Normal file
45
engines/watchmaker/walk/walkutil.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WATCHMAKER_WALKUTIL_H
|
||||
#define WATCHMAKER_WALKUTIL_H
|
||||
|
||||
#include "watchmaker/types.h"
|
||||
#include "watchmaker/t3d.h"
|
||||
|
||||
namespace Watchmaker {
|
||||
|
||||
t3dF32 SinCosAngle(t3dF32 sinus, t3dF32 cosinus);
|
||||
t3dF32 t3dVectAngle(t3dV3F *n, t3dV3F *o);
|
||||
int PointInside(int32 oc, int32 pan, const PointXZ &point);
|
||||
int PointInside(int32 oc, int32 pan, double x, double z);
|
||||
bool PointInside2DRectangle(double pgon[4][2], double x, double z);
|
||||
float DistF(PointXZ a, PointXZ b);
|
||||
float DistF(float x1, float y1, float x2, float y2);
|
||||
PointResult IntersLineLine(const PointXZ &a, const PointXZ &b, float xc, float yc, float xd, float yd);
|
||||
PointResult IntersLineLine(const PointXZ &a, const PointXZ &b, const PointXZ &c, const PointXZ &d);
|
||||
PointResult IntersLineLine(float xa, float ya, float xb, float yb, float xc, float yc, float xd, float yd);
|
||||
int PathCompare(const void *arg1, const void *arg2);
|
||||
void SortPath(int32 oc);
|
||||
|
||||
} // End of namespace Watchmaker
|
||||
|
||||
#endif // WATCHMAKER_WALKUTIL_H
|
||||
Reference in New Issue
Block a user