diff --git a/src/game/CAbstractPlayer.cpp b/src/game/CAbstractPlayer.cpp index b38b8fb5..7432498b 100644 --- a/src/game/CAbstractPlayer.cpp +++ b/src/game/CAbstractPlayer.cpp @@ -193,11 +193,11 @@ void CAbstractPlayer::LoadScout() { } void CAbstractPlayer::LoadFreeCam() { - itsFreeCam = new CFreeCam(this); itsFreeCam->BeginScript(); FreshCalc(); itsFreeCam->EndScript(); + SetFreeCamState(false); } void CAbstractPlayer::WriteDBG(int index, float val) { @@ -988,7 +988,11 @@ void CAbstractPlayer::ResetDashboard() { } void CAbstractPlayer::ToggleFreeCam() { - freeView = !freeView; + SetFreeCamState(!freeView); +} + +void CAbstractPlayer::SetFreeCamState(Boolean state) { + freeView = state; itsGame->ToggleFreeCam(freeView); itsFreeCam->ToggleState(freeView); diff --git a/src/game/CAbstractPlayer.h b/src/game/CAbstractPlayer.h index 309a99a6..a135c448 100644 --- a/src/game/CAbstractPlayer.h +++ b/src/game/CAbstractPlayer.h @@ -295,6 +295,7 @@ class CAbstractPlayer : public CRealMovers { // virtual void ToggleFreeCam(); + virtual void SetFreeCamState(Boolean state); virtual Boolean IsFreeCamAttached(); virtual void ControlSoundPoint(); virtual void ControlViewPoint(); diff --git a/src/game/CFreeCam.cpp b/src/game/CFreeCam.cpp index 6a6a37dd..f46dcdca 100644 --- a/src/game/CFreeCam.cpp +++ b/src/game/CFreeCam.cpp @@ -13,7 +13,10 @@ CFreeCam::CFreeCam(CAbstractPlayer *thePlayer) { camSpeed = 350; radius = FIX3(25000); + pitch = FIX3(125); // 45 degrees + heading = 0; + isAttached = false; action = camInactive; isActive = kIsActive; partCount = 0; @@ -23,13 +26,15 @@ CFreeCam::CFreeCam(CAbstractPlayer *thePlayer) { void CFreeCam::ToggleState(Boolean state) { CAbstractPlayer *spectatePlayer = itsGame->GetSpectatePlayer(); - if (state && spectatePlayer != NULL) { + if (state) { if (action == camInactive) { itsGame->AddActor(this); itsPlayer->freeCamIdent = ident; action = camAnimating; } - isAttached = true; + if (spectatePlayer != NULL) { + isAttached = true; + } } } @@ -46,71 +51,75 @@ void CFreeCam::ViewControl(FunctionTable *ft) { Vector direction; CAbstractPlayer *spectatePlayer = itsGame->GetSpectatePlayer(); + // This sets up the ability for the camera to follow a player if (isAttached && spectatePlayer != NULL) { vp->LookAtPart(spectatePlayer->viewPortPart); } - // Find direction vector for the camera - direction[0] = vp->atPoint[0] - vp->fromPoint[0]; - direction[1] = vp->atPoint[1] - vp->fromPoint[1]; - direction[2] = vp->atPoint[2] - vp->fromPoint[2]; - - // Find length of direction vector - Fixed len = FSqrt(FMul(direction[0], direction[0]) + FMul(direction[2], direction[2])); - - // Normalize Direction vector - direction[0] = FDivNZ(direction[0], len); - //direction[1] = FDivNZ(direction[1], len); - direction[2] = FDivNZ(direction[2], len); - - // Calc the horizontal viewing angle from the direction vector - Fixed heading, pitch; - heading = FOneArcTan2(direction[0], direction[2]); - - // Find new direction vector if mouse moved - Fixed xRot=0, zRot=0; - if (ft->mouseDelta.h > 0) { - heading -= FIX3(5); - } else if (ft->mouseDelta.h < 0) { - heading += FIX3(5); - } - xRot = FOneCos(heading); - zRot = FOneSin(heading); + // Mouse movements adjust polar coordinates + heading += FIX3(ft->mouseDelta.h * .2); + pitch -= FIX3(ft->mouseDelta.v * .2); + if (pitch > FIX3(250)) pitch = FIX3(250); + if (pitch < FIX3(10)) pitch = FIX3(10); + + // Convert from polar to cartesian + // Find normalized camera position + Fixed xRot=0, yRot=0, zRot=0; + xRot = FMul(FOneCos(heading), FOneSin(pitch)); + yRot = FOneCos(pitch); + zRot = FMul(FOneSin(heading), FOneSin(pitch)); direction[0] = xRot; + direction[1] = yRot; direction[2] = zRot; - // Calc movement distance for each axis + // Calc potential velocity for each axis Fixed finalXSpeed = FMulDivNZ(direction[0], ToFixed(camSpeed), ToFixed(1000)); Fixed finalYSpeed = FIX3(camSpeed); Fixed finalZSpeed = FMulDivNZ(direction[2], ToFixed(camSpeed), ToFixed(1000)); - // Camera rotation + // Set actual camera position vp->fromPoint[0] = vp->atPoint[0] - FMul(direction[0], radius); + vp->fromPoint[1] = vp->atPoint[1] + FMul(direction[1], radius); vp->fromPoint[2] = vp->atPoint[2] - FMul(direction[2], radius); + // Zoom out + if (TESTFUNC(kfuZoomOut, ft->held)) { + radius += FIX3(camSpeed); + if (radius > FIX3(50000)) { + radius = FIX3(50000); + } + } + // Zoom In + if (TESTFUNC(kfuZoomIn, ft->held)) { + radius -= FIX3(camSpeed); + if (radius < FIX3(10000)) { + radius = FIX3(10000); + } + } + // Orthogonal camera movement - if (TESTFUNC(kfuFreeCamForward, ft->held)) { + if (TESTFUNC(kfuForward, ft->held)) { isAttached = false; vp->fromPoint[0] += finalXSpeed; vp->fromPoint[2] += finalZSpeed; vp->atPoint[0] += finalXSpeed; vp->atPoint[2] += finalZSpeed; } - if (TESTFUNC(kfuFreeCamBackward, ft->held)) { + if (TESTFUNC(kfuReverse, ft->held)) { isAttached = false; vp->fromPoint[0] -= finalXSpeed; vp->fromPoint[2] -= finalZSpeed; vp->atPoint[0] -= finalXSpeed; vp->atPoint[2] -= finalZSpeed; } - if (TESTFUNC(kfuFreeCamLeft, ft->held)) { + if (TESTFUNC(kfuLeft, ft->held)) { isAttached = false; vp->fromPoint[0] += finalZSpeed; vp->fromPoint[2] -= finalXSpeed; vp->atPoint[0] += finalZSpeed; vp->atPoint[2] -= finalXSpeed; } - if (TESTFUNC(kfuFreeCamRight, ft->held)) { + if (TESTFUNC(kfuRight, ft->held)) { isAttached = false; vp->fromPoint[0] -= finalZSpeed; vp->fromPoint[2] += finalXSpeed; @@ -118,43 +127,25 @@ void CFreeCam::ViewControl(FunctionTable *ft) { vp->atPoint[2] += finalXSpeed; } - // Handle y-axis movement differently depending on if the camera is attached to a player or not // Up if (TESTFUNC(kfuFreeCamUp, ft->held)) { - if (isAttached) { - // Cam is attached so don't move focal point - vp->fromPoint[1] += finalYSpeed; - } else { - vp->fromPoint[1] += finalYSpeed; - // Don't move focal point until threshold is passed - if (vp->fromPoint[1] > yFromThreshold) { - vp->atPoint[1] += finalYSpeed; - } - } + isAttached = false; + vp->atPoint[1] += finalYSpeed; + vp->fromPoint[1] += finalYSpeed; } // Down if (TESTFUNC(kfuFreeCamDown, ft->held)) { - if (isAttached) { - // Cam is attached so don't move focal point - // Cam can't go below focal point - vp->fromPoint[1] -= finalYSpeed; - if (vp->fromPoint[1] < vp->atPoint[1]) { - vp->fromPoint[1] = vp->atPoint[1]; - } - } else { - // Don't let camera or focal point go below y=0 - // When zero is reached, save the height of the camera - // The focal point will not move on the y-axis until the camera is at least as far away (on y-axis) as the saved threshold - if (vp->atPoint[1] != 0) - vp->atPoint[1] -= finalYSpeed; - - if (vp->atPoint[1] < 0) { - yFromThreshold = vp->fromPoint[1]; + // Leave camera attached if already at y=0 + if (vp->atPoint[1] > 0) { + isAttached = false; + // Focal point should not go below 0 + // If focal point does go below zero, move camera by the same amount to keep it at a fixed distance + if (vp->atPoint[1] - finalYSpeed < 0) { + vp->fromPoint[1] -= vp->atPoint[1]; vp->atPoint[1] = 0; - } - vp->fromPoint[1] -= finalYSpeed; - if (vp->fromPoint[1] < 0) { - vp->fromPoint[1] = 0; + } else { + vp->atPoint[1] -= finalYSpeed; + vp->fromPoint[1] -= finalYSpeed; } } } diff --git a/src/game/CFreeCam.h b/src/game/CFreeCam.h index 487dc0a2..b3b6cb33 100644 --- a/src/game/CFreeCam.h +++ b/src/game/CFreeCam.h @@ -16,8 +16,7 @@ class CFreeCam final : public CRealMovers { CViewParameters *freeParams; short action; - Fixed radius; - Fixed yFromThreshold; + Fixed radius, heading, pitch; short camSpeed; Boolean isAttached; diff --git a/src/game/CPlayerManager.cpp b/src/game/CPlayerManager.cpp index ae06e933..98c705cb 100644 --- a/src/game/CPlayerManager.cpp +++ b/src/game/CPlayerManager.cpp @@ -78,10 +78,6 @@ void CPlayerManagerImpl::IPlayerManager(CAvaraGame *theGame, short id, CNetManag {"chatMode", 1 << kfuTypeText}, {"freeCamUp", 1 << kfuFreeCamUp}, {"freeCamDown", 1 << kfuFreeCamDown}, - {"freeCamForward", 1 << kfuFreeCamForward}, - {"freeCamLeft", 1 << kfuFreeCamLeft}, - {"freeCamRight", 1 << kfuFreeCamRight}, - {"freeCamBackward", 1 << kfuFreeCamBackward}, {"debug1", 1 << kfuDebug1}, {"debug2", 1 << kfuDebug2}}; diff --git a/src/game/KeyFuncs.h b/src/game/KeyFuncs.h index 0eff1915..d466bc63 100644 --- a/src/game/KeyFuncs.h +++ b/src/game/KeyFuncs.h @@ -91,10 +91,6 @@ enum { kfuLookRight, kfuAimForward, - kfuFreeCamForward, - kfuFreeCamBackward, - kfuFreeCamLeft, - kfuFreeCamRight, kfuFreeCamUp, kfuFreeCamDown, diff --git a/src/gui/CApplication.cpp b/src/gui/CApplication.cpp index 4a49254e..fc9aef07 100755 --- a/src/gui/CApplication.cpp +++ b/src/gui/CApplication.cpp @@ -110,12 +110,20 @@ bool CApplication::Update(const std::string name, std::string &value) { } try { json updatePref = json::parse("{ \"" + name + "\": " + value + "}"); - _prefs.update(updatePref); - WritePrefs(_prefs); + + // If the type of the new value is different than the old one + // this will easily cause a crash when reading the json + if (_prefs[name].type_name() == updatePref[name].type_name()) { + _prefs.update(updatePref); + WritePrefs(_prefs); + } else { + SDL_Log("Type mismatch. User added type '%s' did not match existing type '%s'. Prefs were not updated.", _prefs[name].type_name(), updatePref[name].type_name()); + return false; + } } catch (json::parse_error &ex) { // User typed in the command to change a pref. The value type did not match for the given pref - SDL_Log("User input value '%s' did not parse to the correct type.", name.c_str()); + SDL_Log("User input value for '%s' did not parse to the correct type.", name.c_str()); return false; // Did not update pref } return true; // Successfully updated pref diff --git a/src/gui/CRosterWindow.cpp b/src/gui/CRosterWindow.cpp index bbf39cc0..099df2a3 100755 --- a/src/gui/CRosterWindow.cpp +++ b/src/gui/CRosterWindow.cpp @@ -323,7 +323,7 @@ std::string CRosterWindow::GetStringStatus(CPlayerManager *player) { strStatus = "away"; } if (presence == kzSpectating) { - if (player->LoadingStatusIsIn(kLConnected, kLActive, kLLoaded, kLPaused)) { + if (player->LoadingStatusIsIn(kLConnected, kLActive, kLReady, kLLoaded, kLPaused)) { strStatus = "spectator"; } else if (strStatus.length() > 0) { strStatus += "*"; // make this into an eyeball char? diff --git a/src/gui/Preferences.h b/src/gui/Preferences.h index 9f4f040f..7d2f8417 100755 --- a/src/gui/Preferences.h +++ b/src/gui/Preferences.h @@ -132,12 +132,8 @@ static json defaultPrefs = { {"spectatePrevious", "["}, {"scoreboard", "/"}, {"chatMode", "Return"}, - {"freeCamUp", "Q"}, - {"freeCamDown", "E"}, - {"freeCamForward", "W"}, - {"freeCamLeft", "A"}, - {"freeCamRight", "D"}, - {"freeCamBackward", "S"}, + {"freeCamUp", "R"}, + {"freeCamDown", "F"}, {"debug1", "5"}, {"debug2", "6"}} }, diff --git a/src/tui/CommandManager.cpp b/src/tui/CommandManager.cpp index 10a11329..886ac269 100644 --- a/src/tui/CommandManager.cpp +++ b/src/tui/CommandManager.cpp @@ -510,6 +510,11 @@ bool CommandManager::GetSetPreference(VectorOfArgs vargs) { //write prefs itsApp->AddMessageLine(prefName + " changed from " + oldValue + " to " + newValue); itsApp->CApplication::PrefChanged(prefName); + } else { + itsApp->AddMessageLine("Error: Pref not updated", + MsgAlignment::Left, + MsgCategory::Error + ); } } }