mirror of
https://github.com/isledecomp/isle.git
synced 2025-10-23 00:14:22 +00:00
1054 lines
26 KiB
C++
1054 lines
26 KiB
C++
#include "legonavcontroller.h"
|
|
|
|
#include "3dmanager/lego3dmanager.h"
|
|
#include "act3.h"
|
|
#include "infocenter.h"
|
|
#include "legoanimationmanager.h"
|
|
#include "legocameracontroller.h"
|
|
#include "legocharactermanager.h"
|
|
#include "legogamestate.h"
|
|
#include "legoinputmanager.h"
|
|
#include "legolocations.h"
|
|
#include "legomain.h"
|
|
#include "legoplantmanager.h"
|
|
#include "legosoundmanager.h"
|
|
#include "legoutils.h"
|
|
#include "legovideomanager.h"
|
|
#include "legoworld.h"
|
|
#include "misc.h"
|
|
#include "mxbackgroundaudiomanager.h"
|
|
#include "mxdebug.h"
|
|
#include "mxmisc.h"
|
|
#include "mxtimer.h"
|
|
#include "mxtransitionmanager.h"
|
|
#include "mxutilities.h"
|
|
#include "realtime/realtime.h"
|
|
#include "realtime/realtimeview.h"
|
|
#include "viewmanager/viewmanager.h"
|
|
|
|
#include <vec.h>
|
|
|
|
DECOMP_SIZE_ASSERT(LegoNavController, 0x70)
|
|
|
|
// MSVC 4.20 didn't define a macro for this key
|
|
#ifndef VK_OEM_MINUS
|
|
#define VK_OEM_MINUS 0xBD
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.1416
|
|
#endif
|
|
#ifdef DTOR
|
|
#undef DTOR
|
|
#endif
|
|
#define DTOR(angle) ((angle) * M_PI / 180.)
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// GLOBAL: LEGO1 0x100f4c28
|
|
int LegoNavController::g_defdeadZone = 40;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c2c
|
|
float LegoNavController::g_defzeroThreshold = 0.001f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c30
|
|
float LegoNavController::g_defmaxLinearVel = 40.0f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c34
|
|
float LegoNavController::g_defmaxRotationalVel = 20.0f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c38
|
|
float LegoNavController::g_defmaxLinearAccel = 15.0f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c3c
|
|
float LegoNavController::g_defmaxRotationalAccel = 30.0f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c40
|
|
float LegoNavController::g_defminLinearAccel = 4.0f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c44
|
|
float LegoNavController::g_defminRotationalAccel = 15.0f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c48
|
|
float LegoNavController::g_defmaxLinearDeccel = 50.0f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c4c
|
|
float LegoNavController::g_defmaxRotationalDeccel = 50.0f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c50
|
|
float LegoNavController::g_defrotSensitivity = 0.4f;
|
|
|
|
// GLOBAL: LEGO1 0x100f4c54
|
|
MxBool LegoNavController::g_defuseRotationalVel = FALSE;
|
|
|
|
// GLOBAL: LEGO1 0x100f66a0
|
|
MxU32 g_changeLight = FALSE;
|
|
|
|
// GLOBAL: LEGO1 0x100f66a4
|
|
MxS32 g_locationCalcStep = 0;
|
|
|
|
// GLOBAL: LEGO1 0x100f66a8
|
|
MxS32 g_nextLocation = 0;
|
|
|
|
// GLOBAL: LEGO1 0x100f66ac
|
|
MxBool g_resetPlants = FALSE;
|
|
|
|
// GLOBAL: LEGO1 0x100f66b0
|
|
MxS32 g_animationCalcStep = 0;
|
|
|
|
// GLOBAL: LEGO1 0x100f66b4
|
|
MxS32 g_nextAnimation = 0;
|
|
|
|
// GLOBAL: LEGO1 0x100f66b8
|
|
MxU32 g_switchAct = FALSE;
|
|
|
|
// GLOBAL: LEGO1 0x100f66bc
|
|
LegoAnimationManager::PlayMode g_unk0x100f66bc = LegoAnimationManager::e_unk2;
|
|
|
|
// GLOBAL: LEGO1 0x100f66c0
|
|
char g_debugPassword[] = "OGEL";
|
|
|
|
// GLOBAL: LEGO1 0x100f66c8
|
|
char* g_currentInput = g_debugPassword;
|
|
|
|
// GLOBAL: LEGO1 0x100f66cc
|
|
MxS32 g_nextCharacter = -1;
|
|
|
|
// GLOBAL: LEGO1 0x100f66d0
|
|
MxBool g_enableMusic = TRUE;
|
|
|
|
// GLOBAL: LEGO1 0x100f66d4
|
|
MxU32 g_fpsEnabled = TRUE;
|
|
|
|
// FUNCTION: LEGO1 0x10054ac0
|
|
LegoNavController::LegoNavController()
|
|
{
|
|
SetToDefaultParams();
|
|
|
|
m_linearVel = 0.0f;
|
|
m_rotationalVel = 0.0f;
|
|
m_targetLinearVel = 0.0f;
|
|
m_targetRotationalVel = 0.0f;
|
|
m_linearAccel = 0.0f;
|
|
m_rotationalAccel = 0.0f;
|
|
m_trackDefault = FALSE;
|
|
m_unk0x5d = FALSE;
|
|
m_isAccelerating = FALSE;
|
|
m_unk0x64 = 0.0f;
|
|
m_unk0x68 = 0.0f;
|
|
m_unk0x60 = 0.0f;
|
|
|
|
m_lastTime = Timer()->GetTime();
|
|
|
|
InputManager()->Register(this);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054c30
|
|
LegoNavController::~LegoNavController()
|
|
{
|
|
InputManager()->UnRegister(this);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054ca0
|
|
void LegoNavController::SetControlMax(int p_hMax, int p_vMax)
|
|
{
|
|
m_hMax = p_hMax;
|
|
m_vMax = p_vMax;
|
|
|
|
if (VideoManager()->GetVideoParam().Flags().GetFullScreen()) {
|
|
m_hMax = 640;
|
|
m_vMax = 480;
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054cd0
|
|
// FUNCTION: BETA10 0x1009ad76
|
|
void LegoNavController::SetToDefaultParams()
|
|
{
|
|
m_deadZone = g_defdeadZone;
|
|
m_zeroThreshold = g_defzeroThreshold;
|
|
m_maxRotationalAccel = g_defmaxRotationalAccel;
|
|
m_maxLinearAccel = g_defmaxLinearAccel;
|
|
m_minRotationalAccel = g_defminRotationalAccel;
|
|
m_minLinearAccel = g_defminLinearAccel;
|
|
m_maxRotationalDeccel = g_defmaxRotationalDeccel;
|
|
m_maxLinearDeccel = g_defmaxLinearDeccel;
|
|
m_maxRotationalVel = g_defmaxRotationalVel;
|
|
m_maxLinearVel = g_defmaxLinearVel;
|
|
m_useRotationalVel = g_defuseRotationalVel;
|
|
m_rotSensitivity = g_defrotSensitivity;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054d40
|
|
void LegoNavController::GetDefaults(
|
|
int* p_dz,
|
|
float* p_lv,
|
|
float* p_rv,
|
|
float* p_la,
|
|
float* p_ra,
|
|
float* p_ld,
|
|
float* p_rd,
|
|
float* p_lmina,
|
|
float* p_rmina,
|
|
float* p_rs,
|
|
MxBool* p_urs
|
|
)
|
|
{
|
|
*p_dz = g_defdeadZone;
|
|
*p_lv = g_defmaxLinearVel;
|
|
*p_rv = g_defmaxRotationalVel;
|
|
*p_la = g_defmaxLinearAccel;
|
|
*p_ra = g_defmaxRotationalAccel;
|
|
*p_ld = g_defmaxLinearDeccel;
|
|
*p_rd = g_defmaxRotationalDeccel;
|
|
*p_lmina = g_defminLinearAccel;
|
|
*p_rmina = g_defminRotationalAccel;
|
|
*p_rs = g_defrotSensitivity;
|
|
*p_urs = g_defuseRotationalVel;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054dd0
|
|
void LegoNavController::SetDefaults(
|
|
int p_dz,
|
|
float p_lv,
|
|
float p_rv,
|
|
float p_la,
|
|
float p_ra,
|
|
float p_ld,
|
|
float p_rd,
|
|
float p_lmina,
|
|
float p_rmina,
|
|
float p_rs,
|
|
MxBool p_urs
|
|
)
|
|
{
|
|
g_defdeadZone = p_dz;
|
|
g_defmaxLinearVel = p_lv;
|
|
g_defmaxRotationalVel = p_rv;
|
|
g_defmaxLinearAccel = p_la;
|
|
g_defmaxRotationalAccel = p_ra;
|
|
g_defmaxLinearDeccel = p_ld;
|
|
g_defmaxRotationalDeccel = p_rd;
|
|
g_defminLinearAccel = p_lmina;
|
|
g_defminRotationalAccel = p_rmina;
|
|
g_defrotSensitivity = p_rs;
|
|
g_defuseRotationalVel = p_urs;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054e40
|
|
void LegoNavController::SetTargets(int p_hPos, int p_vPos, MxBool p_accel)
|
|
{
|
|
if (m_trackDefault != FALSE) {
|
|
SetToDefaultParams();
|
|
}
|
|
|
|
if (p_accel != FALSE) {
|
|
m_targetRotationalVel = CalculateNewTargetVel(p_hPos, m_hMax / 2, m_maxRotationalVel);
|
|
m_targetLinearVel = CalculateNewTargetVel(m_vMax - p_vPos, m_vMax / 2, m_maxLinearVel);
|
|
m_rotationalAccel = CalculateNewAccel(p_hPos, m_hMax / 2, m_maxRotationalAccel, (int) m_minRotationalAccel);
|
|
m_linearAccel = CalculateNewAccel(m_vMax - p_vPos, m_vMax / 2, m_maxLinearAccel, (int) m_minLinearAccel);
|
|
}
|
|
else {
|
|
m_targetRotationalVel = 0;
|
|
m_targetLinearVel = 0;
|
|
m_linearAccel = m_maxLinearDeccel;
|
|
m_rotationalAccel = m_maxRotationalDeccel;
|
|
}
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054f10
|
|
float LegoNavController::CalculateNewTargetVel(int p_pos, int p_center, float p_max)
|
|
{
|
|
float newVel;
|
|
int diff = p_pos - p_center;
|
|
|
|
if (diff > m_deadZone) {
|
|
newVel = (diff - m_deadZone) * p_max / (p_center - m_deadZone);
|
|
}
|
|
else if (diff < -m_deadZone) {
|
|
newVel = (diff + m_deadZone) * p_max / (p_center - m_deadZone);
|
|
}
|
|
else {
|
|
newVel = 0.0;
|
|
}
|
|
|
|
return newVel;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054f90
|
|
float LegoNavController::CalculateNewAccel(int p_pos, int p_center, float p_max, int p_min)
|
|
{
|
|
float newAccel;
|
|
int diff = p_pos - p_center;
|
|
|
|
newAccel = Abs(diff) * p_max / p_center;
|
|
|
|
if (newAccel < p_min) {
|
|
newAccel = (float) p_min;
|
|
}
|
|
|
|
return newAccel;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10054fe0
|
|
float LegoNavController::CalculateNewVel(float p_targetVel, float p_currentVel, float p_accel, float p_time)
|
|
{
|
|
float newVel = p_currentVel;
|
|
|
|
float velDiff = p_targetVel - p_currentVel;
|
|
int vSign = velDiff > 0 ? 1 : -1;
|
|
|
|
if (Abs(velDiff) > m_zeroThreshold) {
|
|
float deltaVel = p_accel * p_time;
|
|
newVel = p_currentVel + (deltaVel * vSign);
|
|
|
|
if (vSign > 0) {
|
|
newVel = Min(newVel, p_targetVel);
|
|
}
|
|
else {
|
|
newVel = Max(newVel, p_targetVel);
|
|
}
|
|
}
|
|
|
|
return newVel;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10055080
|
|
// FUNCTION: BETA10 0x1009b26b
|
|
MxBool LegoNavController::CalculateNewPosDir(
|
|
const Vector3& p_curPos,
|
|
const Vector3& p_curDir,
|
|
Vector3& p_newPos,
|
|
Vector3& p_newDir,
|
|
const Vector3* p_und
|
|
)
|
|
{
|
|
if (!g_isWorldActive) {
|
|
return FALSE;
|
|
}
|
|
|
|
MxBool changed = FALSE;
|
|
MxBool und = FALSE;
|
|
|
|
MxTime currentTime = Timer()->GetTime();
|
|
float deltaTime = (currentTime - m_lastTime) / 1000.0;
|
|
m_lastTime = currentTime;
|
|
|
|
if (ProcessKeyboardInput() == FAILURE) {
|
|
ProcessJoystickInput(und);
|
|
}
|
|
|
|
if (m_useRotationalVel) {
|
|
m_rotationalVel = CalculateNewVel(m_targetRotationalVel, m_rotationalVel, m_rotationalAccel * 40.0f, deltaTime);
|
|
}
|
|
else {
|
|
m_rotationalVel = m_targetRotationalVel;
|
|
}
|
|
|
|
m_linearVel = CalculateNewVel(m_targetLinearVel, m_linearVel, m_linearAccel, deltaTime);
|
|
|
|
if (und || (Abs(m_rotationalVel) > m_zeroThreshold) || (Abs(m_linearVel) > m_zeroThreshold)) {
|
|
float rot_mat[3][3];
|
|
Mx3DPointFloat delta_pos, new_dir, new_pos;
|
|
|
|
if (m_linearVel < -(m_maxLinearVel * 0.4f)) {
|
|
m_linearVel = -(m_maxLinearVel * 0.4f);
|
|
}
|
|
|
|
VXS3(delta_pos, p_curDir, m_linearVel * deltaTime);
|
|
VPV3(p_newPos, p_curPos, delta_pos);
|
|
|
|
float delta_rad;
|
|
if (m_useRotationalVel) {
|
|
delta_rad = DTOR(m_rotationalVel * deltaTime);
|
|
}
|
|
else {
|
|
delta_rad = DTOR(m_rotationalVel * m_rotSensitivity);
|
|
}
|
|
|
|
if (p_und != NULL && (*p_und)[1] < 0.0f) {
|
|
delta_rad = -delta_rad;
|
|
}
|
|
|
|
IDENTMAT3(rot_mat);
|
|
rot_mat[0][0] = rot_mat[2][2] = cos(delta_rad);
|
|
rot_mat[0][2] = rot_mat[2][0] = sin(delta_rad);
|
|
rot_mat[0][2] *= -1.0f;
|
|
VXM3(p_newDir, p_curDir, rot_mat);
|
|
|
|
changed = TRUE;
|
|
}
|
|
|
|
if (m_unk0x5d) {
|
|
float rot_mat[3][3];
|
|
Mx3DPointFloat delta_pos, new_pos, new_dir;
|
|
|
|
if (changed) {
|
|
SET3(new_pos, p_newPos);
|
|
SET3(new_dir, p_newDir);
|
|
}
|
|
else {
|
|
SET3(new_pos, p_curPos);
|
|
SET3(new_dir, p_curDir);
|
|
}
|
|
|
|
if (m_unk0x64 != 0.0f) {
|
|
delta_pos[0] = new_dir[0] * m_unk0x64;
|
|
delta_pos[1] = new_dir[1] * m_unk0x64;
|
|
delta_pos[2] = new_dir[2] * m_unk0x64;
|
|
}
|
|
else {
|
|
FILLVEC3(delta_pos, 0.0f);
|
|
}
|
|
|
|
delta_pos[1] += m_unk0x60;
|
|
VPV3(p_newPos, new_pos, delta_pos);
|
|
|
|
if (m_unk0x68 != 0.0f) {
|
|
float delta_rad = DTOR(m_unk0x68);
|
|
IDENTMAT3(rot_mat);
|
|
rot_mat[0][0] = rot_mat[2][2] = cos(delta_rad);
|
|
rot_mat[0][2] = rot_mat[2][0] = sin(delta_rad);
|
|
rot_mat[0][2] *= -1.0f;
|
|
VXM3(p_newDir, new_dir, rot_mat);
|
|
}
|
|
else {
|
|
SET3(p_newDir, new_dir);
|
|
}
|
|
|
|
m_unk0x60 = m_unk0x64 = m_unk0x68 = 0.0f;
|
|
m_unk0x5d = FALSE;
|
|
changed = TRUE;
|
|
}
|
|
|
|
return changed;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10055500
|
|
// FUNCTION: BETA10 0x1009bff8
|
|
MxResult LegoNavController::UpdateLocation(const char* p_location)
|
|
{
|
|
MxResult result = FAILURE;
|
|
|
|
for (MxS32 i = 0; i < (MxS32) sizeOfArray(g_locations); i++) {
|
|
if (!strcmpi(p_location, g_locations[i].m_name)) {
|
|
MxMatrix mat;
|
|
LegoROI* viewROI = VideoManager()->GetViewROI();
|
|
|
|
CalcLocalTransform(g_locations[i].m_position, g_locations[i].m_direction, g_locations[i].m_up, mat);
|
|
|
|
Mx3DPointFloat vec;
|
|
vec.Clear();
|
|
|
|
viewROI->SetWorldVelocity(vec);
|
|
viewROI->WrappedSetLocal2WorldWithWorldDataUpdate(mat);
|
|
VideoManager()->Get3DManager()->Moved(*viewROI);
|
|
|
|
SoundManager()->UpdateListener(
|
|
viewROI->GetWorldPosition(),
|
|
viewROI->GetWorldDirection(),
|
|
viewROI->GetWorldUp(),
|
|
viewROI->GetWorldVelocity()
|
|
);
|
|
|
|
result = SUCCESS;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10055620
|
|
// FUNCTION: BETA10 0x1009c145
|
|
MxResult LegoNavController::UpdateLocation(MxU32 p_location)
|
|
{
|
|
MxResult result = FAILURE;
|
|
|
|
if (p_location < sizeOfArray(g_locations)) {
|
|
MxMatrix mat;
|
|
LegoROI* viewROI = VideoManager()->GetViewROI();
|
|
|
|
CalcLocalTransform(
|
|
g_locations[p_location].m_position,
|
|
g_locations[p_location].m_direction,
|
|
g_locations[p_location].m_up,
|
|
mat
|
|
);
|
|
|
|
Mx3DPointFloat vec;
|
|
vec.Clear();
|
|
|
|
viewROI->SetWorldVelocity(vec);
|
|
viewROI->WrappedSetLocal2WorldWithWorldDataUpdate(mat);
|
|
VideoManager()->Get3DManager()->Moved(*viewROI);
|
|
|
|
SoundManager()->UpdateListener(
|
|
viewROI->GetWorldPosition(),
|
|
viewROI->GetWorldDirection(),
|
|
viewROI->GetWorldUp(),
|
|
viewROI->GetWorldVelocity()
|
|
);
|
|
|
|
result = SUCCESS;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10055720
|
|
// FUNCTION: BETA10 0x1009c259
|
|
LegoLocation* LegoNavController::GetLocation(MxU32 p_location)
|
|
{
|
|
if (p_location < sizeOfArray(g_locations)) {
|
|
return &g_locations[p_location];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10055740
|
|
MxS32 LegoNavController::GetNumLocations()
|
|
{
|
|
return sizeOfArray(g_locations);
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10055750
|
|
MxResult LegoNavController::ProcessJoystickInput(MxBool& p_und)
|
|
{
|
|
LegoOmni* instance = LegoOmni::GetInstance();
|
|
|
|
if (instance->GetInputManager()) {
|
|
MxS32 joystickX;
|
|
MxS32 joystickY;
|
|
DWORD buttonState;
|
|
MxS32 povPosition;
|
|
|
|
if (instance->GetInputManager()
|
|
->GetJoystickState((MxU32*) &joystickX, (MxU32*) &joystickY, &buttonState, (MxU32*) &povPosition) !=
|
|
FAILURE) {
|
|
MxU32 yVal = (joystickY * m_vMax) / 100;
|
|
MxU32 xVal = (joystickX * m_hMax) / 100;
|
|
|
|
if (joystickX <= 45 || joystickX >= 55 || joystickY <= 45 || joystickY >= 55) {
|
|
m_targetLinearVel = CalculateNewTargetVel(m_vMax - yVal, m_vMax / 2, m_maxLinearVel);
|
|
m_linearAccel = CalculateNewAccel(m_vMax - yVal, m_vMax / 2, m_maxLinearAccel, (int) m_minLinearAccel);
|
|
m_targetRotationalVel = CalculateNewTargetVel(xVal, m_hMax / 2, m_maxRotationalVel);
|
|
m_rotationalAccel =
|
|
CalculateNewAccel(xVal, m_hMax / 2, m_maxRotationalAccel, (int) m_minRotationalAccel);
|
|
}
|
|
else {
|
|
m_targetRotationalVel = 0.0;
|
|
m_targetLinearVel = 0.0;
|
|
m_linearAccel = m_maxLinearDeccel;
|
|
m_rotationalAccel = m_maxRotationalDeccel;
|
|
}
|
|
|
|
if (povPosition >= 0) {
|
|
LegoWorld* world = CurrentWorld();
|
|
|
|
if (world && world->GetCameraController()) {
|
|
world->GetCameraController()->RotateY(DTOR(povPosition));
|
|
p_und = TRUE;
|
|
}
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
}
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x100558b0
|
|
MxResult LegoNavController::ProcessKeyboardInput()
|
|
{
|
|
MxBool skipRotationVelAndAccelCalc = FALSE;
|
|
MxBool skipLinearVelAndAccelCalc = FALSE;
|
|
LegoInputManager* inputManager = LegoOmni::GetInstance()->GetInputManager();
|
|
MxU32 keyFlags;
|
|
|
|
if (inputManager == NULL || inputManager->GetNavigationKeyStates(keyFlags) == FAILURE) {
|
|
return FAILURE;
|
|
}
|
|
|
|
if (keyFlags == 0) {
|
|
if (m_isAccelerating) {
|
|
m_targetRotationalVel = 0.0;
|
|
m_targetLinearVel = 0.0;
|
|
m_rotationalAccel = m_maxRotationalDeccel;
|
|
m_linearAccel = m_maxLinearDeccel;
|
|
m_isAccelerating = FALSE;
|
|
}
|
|
|
|
return FAILURE;
|
|
}
|
|
|
|
m_isAccelerating = TRUE;
|
|
|
|
MxS32 hMax;
|
|
switch (keyFlags & LegoInputManager::c_leftOrRight) {
|
|
case LegoInputManager::c_left:
|
|
hMax = 0;
|
|
break;
|
|
case LegoInputManager::c_right:
|
|
hMax = m_hMax;
|
|
break;
|
|
default:
|
|
m_targetRotationalVel = 0.0;
|
|
m_rotationalAccel = m_maxRotationalDeccel;
|
|
skipRotationVelAndAccelCalc = TRUE;
|
|
break;
|
|
}
|
|
|
|
MxS32 vMax;
|
|
switch (keyFlags & LegoInputManager::c_upOrDown) {
|
|
case LegoInputManager::c_up:
|
|
vMax = 0;
|
|
break;
|
|
case LegoInputManager::c_down:
|
|
vMax = m_vMax;
|
|
break;
|
|
default:
|
|
m_targetLinearVel = 0.0;
|
|
m_linearAccel = m_maxLinearDeccel;
|
|
skipLinearVelAndAccelCalc = TRUE;
|
|
break;
|
|
}
|
|
|
|
MxFloat maxAccelDivisor = keyFlags & LegoInputManager::c_ctrl ? 1.0f : 4.0f;
|
|
MxFloat minAccelDivisor = keyFlags & LegoInputManager::c_ctrl ? 1.0f : 2.0f;
|
|
|
|
if (!skipRotationVelAndAccelCalc) {
|
|
m_targetRotationalVel = CalculateNewTargetVel(hMax, m_hMax / 2, m_maxRotationalVel);
|
|
m_rotationalAccel = CalculateNewAccel(
|
|
hMax,
|
|
m_hMax / 2,
|
|
m_maxRotationalAccel / maxAccelDivisor,
|
|
(int) (m_minRotationalAccel / minAccelDivisor)
|
|
);
|
|
}
|
|
|
|
if (!skipLinearVelAndAccelCalc) {
|
|
m_targetLinearVel = CalculateNewTargetVel(m_vMax - vMax, m_vMax / 2, m_maxLinearVel);
|
|
m_linearAccel = CalculateNewAccel(
|
|
m_vMax - vMax,
|
|
m_vMax / 2,
|
|
m_maxLinearAccel / maxAccelDivisor,
|
|
(int) (m_minLinearAccel / minAccelDivisor)
|
|
);
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
// FUNCTION: LEGO1 0x10055a60
|
|
// FUNCTION: BETA10 0x1009c712
|
|
MxLong LegoNavController::Notify(MxParam& p_param)
|
|
{
|
|
if (((MxNotificationParam&) p_param).GetNotification() == c_notificationKeyPress) {
|
|
m_unk0x5d = TRUE;
|
|
MxU8 key = ((LegoEventNotificationParam&) p_param).GetKey();
|
|
|
|
switch (key) {
|
|
case VK_PAUSE: // Pause game
|
|
if (Lego()->IsPaused()) {
|
|
Lego()->Resume();
|
|
}
|
|
else {
|
|
Lego()->Pause();
|
|
}
|
|
break;
|
|
case VK_ESCAPE: { // Return to infocenter
|
|
LegoWorld* currentWorld = CurrentWorld();
|
|
if (currentWorld != NULL) {
|
|
InfocenterState* state = (InfocenterState*) GameState()->GetState("InfocenterState");
|
|
assert(state);
|
|
|
|
if (state != NULL && state->m_state != InfocenterState::e_exitQueried && currentWorld->Escape()) {
|
|
BackgroundAudioManager()->Stop();
|
|
TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE);
|
|
state->m_state = InfocenterState::e_exitQueried;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case VK_SPACE: // Interrupt/end animations or free navigation
|
|
AnimationManager()->FUN_10061010(TRUE);
|
|
break;
|
|
case 'Z': { // Make nearby plants "dance"
|
|
LegoOmni* omni = Lego();
|
|
|
|
if (omni->GetCurrentWorld() != NULL && omni->GetCurrentWorld()->GetWorldId() == LegoOmni::e_act1) {
|
|
LegoVideoManager* videoMgr = LegoOmni::GetInstance()->GetVideoManager();
|
|
ViewROI* roi = videoMgr->GetViewROI();
|
|
ViewManager* view = videoMgr->Get3DManager()->GetLego3DView()->GetViewManager();
|
|
LegoPlantManager* plantMgr = LegoOmni::GetInstance()->GetPlantManager();
|
|
Mx3DPointFloat viewPosition(roi->GetWorldPosition());
|
|
MxS32 numPlants = plantMgr->GetNumPlants();
|
|
|
|
for (MxS32 i = 0; i < numPlants; i++) {
|
|
LegoEntity* entity = plantMgr->CreatePlant(i, NULL, LegoOmni::e_act1);
|
|
|
|
if (entity != NULL && !entity->IsInteraction(LegoEntity::c_disabled)) {
|
|
LegoROI* roi = entity->GetROI();
|
|
|
|
if (roi != NULL && roi->GetVisibility()) {
|
|
const BoundingBox& box = roi->GetWorldBoundingBox();
|
|
|
|
if (view->IsBoundingBoxInFrustum(box)) {
|
|
Mx3DPointFloat roiPosition(roi->GetWorldPosition());
|
|
roiPosition -= viewPosition;
|
|
|
|
if (roiPosition.LenSquared() < 2000.0 || roi->GetLodLevel() > 0) {
|
|
entity->ClickAnimation();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case VK_ADD:
|
|
case VK_SUBTRACT: { // Cycles through characters and puts them in front of you
|
|
if (g_nextCharacter == -1) {
|
|
g_nextCharacter = 0;
|
|
}
|
|
else {
|
|
CharacterManager()->ReleaseActor(CharacterManager()->GetActorName(g_nextCharacter));
|
|
|
|
if (key == VK_ADD) {
|
|
g_nextCharacter++;
|
|
if (g_nextCharacter >= CharacterManager()->GetNumActors()) {
|
|
g_nextCharacter = 0;
|
|
}
|
|
}
|
|
else {
|
|
g_nextCharacter--;
|
|
if (g_nextCharacter < 0) {
|
|
g_nextCharacter = CharacterManager()->GetNumActors() - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
LegoROI* roi = CharacterManager()->GetActorROI(CharacterManager()->GetActorName(g_nextCharacter), TRUE);
|
|
if (roi != NULL) {
|
|
MxMatrix mat;
|
|
ViewROI* viewRoi = LegoOmni::GetInstance()->GetVideoManager()->GetViewROI();
|
|
const float* position = viewRoi->GetWorldPosition();
|
|
const float* direction = viewRoi->GetWorldDirection();
|
|
const float* up = viewRoi->GetWorldUp();
|
|
CalcLocalTransform(position, direction, up, mat);
|
|
mat.TranslateBy(direction[0] * 2.0f, direction[1] - 1.0, direction[2] * 2.0f);
|
|
roi->UpdateTransformationRelativeToParent(mat);
|
|
}
|
|
break;
|
|
}
|
|
case VK_F12: { // Saves the game
|
|
InfocenterState* state = (InfocenterState*) GameState()->GetState("InfocenterState");
|
|
if (state && state->HasRegistered()) {
|
|
GameState()->Save(0);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
// Check if the the key is part of the debug password
|
|
if (!*g_currentInput) {
|
|
// password "protected" debug shortcuts
|
|
switch (((LegoEventNotificationParam&) p_param).GetKey()) {
|
|
case VK_TAB:
|
|
VideoManager()->ToggleFPS(g_fpsEnabled);
|
|
if (g_fpsEnabled) {
|
|
g_fpsEnabled = FALSE;
|
|
}
|
|
else {
|
|
g_fpsEnabled = TRUE;
|
|
}
|
|
default:
|
|
m_unk0x5d = FALSE;
|
|
break;
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
if (g_changeLight && key <= '1') {
|
|
LegoROI* roi = VideoManager()->GetViewROI();
|
|
Tgl::FloatMatrix4 matrix;
|
|
Matrix4 in(matrix);
|
|
roi->GetLocalTransform(in);
|
|
VideoManager()->Get3DManager()->GetLego3DView()->SetLightTransform(key - '0', matrix);
|
|
g_changeLight = FALSE;
|
|
}
|
|
else if (g_locationCalcStep) {
|
|
if (g_locationCalcStep == 1) {
|
|
// Calculate base offset into g_locations
|
|
g_nextLocation = (key - '0') * 10;
|
|
g_locationCalcStep = 2;
|
|
}
|
|
else {
|
|
// Add to base g_locations offset
|
|
g_nextLocation += key - '0';
|
|
g_locationCalcStep = 0;
|
|
UpdateLocation(g_nextLocation);
|
|
}
|
|
}
|
|
else if (g_animationCalcStep) {
|
|
if (g_animationCalcStep == 1) {
|
|
// Calculate base offset into possible animation object IDs (up to 999)
|
|
g_nextAnimation = (key - '0') * 100;
|
|
g_animationCalcStep = 2;
|
|
}
|
|
else if (g_animationCalcStep == 2) {
|
|
// Add to animation object ID offset
|
|
g_nextAnimation += (key - '0') * 10;
|
|
g_animationCalcStep = 3;
|
|
}
|
|
else {
|
|
// Add to animation object ID offset
|
|
g_nextAnimation += key - '0';
|
|
g_animationCalcStep = 0;
|
|
AnimationManager()->FUN_10060dc0(
|
|
g_nextAnimation,
|
|
NULL,
|
|
TRUE,
|
|
g_unk0x100f66bc,
|
|
NULL,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
g_unk0x100f66bc = LegoAnimationManager::e_unk2;
|
|
}
|
|
}
|
|
|
|
if (g_switchAct && key >= '1' && key <= '5') {
|
|
switch (GameState()->GetCurrentAct()) {
|
|
case LegoGameState::e_act1:
|
|
GameState()->m_currentArea = LegoGameState::e_isle;
|
|
break;
|
|
case LegoGameState::e_act2:
|
|
GameState()->m_currentArea = LegoGameState::e_act2main;
|
|
break;
|
|
case LegoGameState::e_act3:
|
|
GameState()->m_currentArea = LegoGameState::e_act3script;
|
|
break;
|
|
}
|
|
|
|
switch (key) {
|
|
case '1':
|
|
GameState()->SetCurrentAct(LegoGameState::e_act1);
|
|
GameState()->SwitchArea(LegoGameState::e_isle);
|
|
break;
|
|
case '2':
|
|
GameState()->SwitchArea(LegoGameState::e_act2main);
|
|
break;
|
|
case '3':
|
|
GameState()->SwitchArea(LegoGameState::e_act3script);
|
|
break;
|
|
case '4': {
|
|
Act3State* act3State = (Act3State*) GameState()->GetState("Act3State");
|
|
if (act3State == NULL) {
|
|
act3State = new Act3State();
|
|
assert(act3State);
|
|
GameState()->RegisterState(act3State);
|
|
}
|
|
|
|
GameState()->SetCurrentAct(LegoGameState::e_act3);
|
|
act3State->m_state = Act3State::e_goodEnding;
|
|
GameState()->m_currentArea = LegoGameState::e_act3script;
|
|
GameState()->SwitchArea(LegoGameState::e_infomain);
|
|
break;
|
|
}
|
|
case '5': {
|
|
Act3State* act3State = (Act3State*) GameState()->GetState("Act3State");
|
|
if (act3State == NULL) {
|
|
act3State = new Act3State();
|
|
assert(act3State);
|
|
GameState()->RegisterState(act3State);
|
|
}
|
|
|
|
GameState()->SetCurrentAct(LegoGameState::e_act3);
|
|
act3State->m_state = Act3State::e_badEnding;
|
|
GameState()->m_currentArea = LegoGameState::e_act3script;
|
|
GameState()->SwitchArea(LegoGameState::e_infomain);
|
|
break;
|
|
}
|
|
}
|
|
|
|
g_switchAct = FALSE;
|
|
}
|
|
else {
|
|
MxDSAction action;
|
|
action.SetObjectId(key - '0');
|
|
action.SetAtomId(MxAtomId("q:\\lego\\media\\model\\common\\common", e_lowerCase2));
|
|
LegoOmni::GetInstance()->Start(&action);
|
|
}
|
|
break;
|
|
case 'A':
|
|
if (g_animationCalcStep == 1) {
|
|
Lego()->m_initialized = TRUE;
|
|
AnimationManager()->FUN_10060570(TRUE);
|
|
g_animationCalcStep = 0;
|
|
}
|
|
else {
|
|
LegoWorld* world = CurrentWorld();
|
|
if (world != NULL) {
|
|
MxDSAction action;
|
|
action.SetObjectId(1);
|
|
action.SetAtomId(world->GetAtomId());
|
|
LegoOmni::GetInstance()->Start(&action);
|
|
}
|
|
}
|
|
break;
|
|
case 'C':
|
|
g_locationCalcStep = 1;
|
|
break;
|
|
case 'D':
|
|
m_unk0x60 = -1.0;
|
|
break;
|
|
case 'F':
|
|
RealtimeView::SetUserMaxLOD(0.0);
|
|
break;
|
|
case 'G':
|
|
g_switchAct = TRUE;
|
|
break;
|
|
case 'H':
|
|
RealtimeView::SetUserMaxLOD(5.0);
|
|
break;
|
|
case 'I': {
|
|
LegoROI* roi = VideoManager()->GetViewROI();
|
|
MxMatrix mat;
|
|
mat.SetIdentity();
|
|
mat.RotateX(0.2618f);
|
|
roi->WrappedUpdateWorldDataWithTransform(mat);
|
|
break;
|
|
}
|
|
case 'J': {
|
|
LegoROI* roi = VideoManager()->GetViewROI();
|
|
MxMatrix mat;
|
|
mat.SetIdentity();
|
|
mat.RotateZ(0.2618f);
|
|
roi->WrappedUpdateWorldDataWithTransform(mat);
|
|
break;
|
|
}
|
|
case 'K': {
|
|
MxMatrix mat;
|
|
LegoROI* roi = LegoOmni::GetInstance()->GetVideoManager()->GetViewROI();
|
|
mat.SetIdentity();
|
|
mat.RotateZ(-0.2618f);
|
|
roi->WrappedUpdateWorldDataWithTransform(mat);
|
|
break;
|
|
}
|
|
case 'L':
|
|
g_changeLight = TRUE;
|
|
break;
|
|
case 'M': {
|
|
LegoROI* roi = LegoOmni::GetInstance()->GetVideoManager()->GetViewROI();
|
|
MxMatrix mat;
|
|
mat.SetIdentity();
|
|
mat.RotateX(-0.2618f);
|
|
roi->WrappedUpdateWorldDataWithTransform(mat);
|
|
break;
|
|
}
|
|
case 'N':
|
|
if (VideoManager()) {
|
|
VideoManager()->SetRender3D(!VideoManager()->GetRender3D());
|
|
}
|
|
break;
|
|
case 'P':
|
|
if (!g_resetPlants) {
|
|
PlantManager()->LoadWorldInfo(LegoOmni::e_act1);
|
|
g_resetPlants = TRUE;
|
|
}
|
|
else {
|
|
PlantManager()->Reset(LegoOmni::e_act1);
|
|
g_resetPlants = FALSE;
|
|
}
|
|
break;
|
|
case 'S':
|
|
g_enableMusic = g_enableMusic == FALSE;
|
|
BackgroundAudioManager()->Enable(g_enableMusic);
|
|
break;
|
|
case 'U':
|
|
m_unk0x60 = 1.0;
|
|
break;
|
|
case 'V':
|
|
if (g_nextAnimation > 0 && g_animationCalcStep == 0) {
|
|
AnimationManager()->FUN_10061010(FALSE);
|
|
}
|
|
|
|
if (g_animationCalcStep != 0) {
|
|
g_unk0x100f66bc = LegoAnimationManager::e_unk2;
|
|
}
|
|
|
|
g_nextAnimation = 0;
|
|
g_animationCalcStep = 1;
|
|
break;
|
|
case 'W': {
|
|
MxMatrix mat;
|
|
LegoROI* roi = LegoOmni::GetInstance()->GetVideoManager()->GetViewROI();
|
|
const float* position = roi->GetWorldPosition();
|
|
const float* direction = roi->GetWorldDirection();
|
|
const float* up = roi->GetWorldUp();
|
|
|
|
MxTrace(
|
|
"pos: %f, %f, %f\ndir: %f, %f, %f\nup: %f, %f, %f\n",
|
|
EXPAND3(position),
|
|
EXPAND3(direction),
|
|
EXPAND3(up)
|
|
);
|
|
break;
|
|
}
|
|
case 'X':
|
|
RealtimeView::SetUserMaxLOD(3.6);
|
|
break;
|
|
case VK_MULTIPLY: {
|
|
MxU8 newActor = GameState()->GetActorId() + 1;
|
|
|
|
if (newActor > LegoActor::c_laura) {
|
|
newActor = LegoActor::c_pepper;
|
|
}
|
|
|
|
GameState()->SetActorId(newActor);
|
|
break;
|
|
}
|
|
case VK_DIVIDE:
|
|
GameState()->SetActorId(LegoActor::c_brickster);
|
|
break;
|
|
case VK_F11:
|
|
if (GameState()->m_isDirty) {
|
|
GameState()->m_isDirty = FALSE;
|
|
}
|
|
else {
|
|
GameState()->m_isDirty = TRUE;
|
|
}
|
|
break;
|
|
case VK_OEM_MINUS:
|
|
g_unk0x100f66bc = LegoAnimationManager::e_unk1;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
if (*g_currentInput == ((LegoEventNotificationParam&) p_param).GetKey()) {
|
|
g_currentInput++;
|
|
}
|
|
else {
|
|
g_currentInput = g_debugPassword;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|