Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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