From 056308dd46421227e354dd28db9d25f123d510f9 Mon Sep 17 00:00:00 2001 From: Tom Anderson Date: Wed, 10 Jul 2024 01:41:51 -0600 Subject: [PATCH] consistent grenade/missile/plasma shooting rates (#417) * fix FramesFromNow usage many frame number checks were of the form if (doSomething < frameNumber) { doSomething = FrameFromNow(3) } For classic mode that means to doSomething at most every 4th frame. But for high-FPS, this code would start doing something on frame 13 instead of on frame 16... faster than classic. Changing code to work across frame rates like this: if (doSomething <= frameNumber) { doSomething = FrameFromNow(3+1) } * fix tests and bugs found by tests The HECTOR.Boost* tests had to be fixed because they were actually boosting on frame 1 since boostEndFrame inits to 0. * added 1 classic-frame limiter to the plasma shot so that all frame rates behave the same on shooting rate --- src/game/CAbstractPlayer.cpp | 22 ++++++++++++---------- src/game/CAbstractPlayer.h | 1 + src/game/CBall.cpp | 8 ++++---- src/tests.cpp | 18 +++++++++--------- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/game/CAbstractPlayer.cpp b/src/game/CAbstractPlayer.cpp index c53bd3d9..b433a0f7 100644 --- a/src/game/CAbstractPlayer.cpp +++ b/src/game/CAbstractPlayer.cpp @@ -175,6 +175,7 @@ void CAbstractPlayer::StartSystems() { nextGrenadeLoad = 0; nextMissileLoad = 0; + nextPlasmaShot = 0; // variables in AdaptableSettings need to have "classic" counterparts in case they are changed in CWalkerActor::ReceiveConfig() classicGeneratorPower = FIX3(30); @@ -1144,12 +1145,12 @@ void CAbstractPlayer::ArmSmartMissile() { } if (!didDetach && oldKind != kweSmart && missileCount) { - if (nextMissileLoad < itsGame->frameNumber) { + if (nextMissileLoad <= itsGame->frameNumber) { theWeapon = itsGame->itsDepot->AquireWeapon(kweSmart); weaponIdent = theWeapon->Arm(viewPortPart); if (weaponIdent) { missileCount--; - nextMissileLoad = itsGame->FramesFromNow(3); + nextMissileLoad = itsGame->FramesFromNow(4); } } else fireGun = false; @@ -1177,12 +1178,12 @@ void CAbstractPlayer::ArmGrenade() { } if (!didDetach && oldKind != kweGrenade && grenadeCount) { - if (nextGrenadeLoad < itsGame->frameNumber) { + if (nextGrenadeLoad <= itsGame->frameNumber) { theWeapon = itsGame->itsDepot->AquireWeapon(kweGrenade); weaponIdent = theWeapon->Arm(viewPortPart); if (weaponIdent) { grenadeCount--; - nextGrenadeLoad = itsGame->FramesFromNow(2); + nextGrenadeLoad = itsGame->FramesFromNow(3); } } else fireGun = false; @@ -1294,11 +1295,11 @@ void CAbstractPlayer::KeyboardControl(FunctionTable *ft) { FPS_DEBUG(" motors after keyb = " << FormatVector(motors, 2) << std::endl); - if (TESTFUNC(kfuBoostEnergy, ft->down) && boostsRemaining && (boostEndFrame < itsGame->frameNumber)) { + if (TESTFUNC(kfuBoostEnergy, ft->down) && boostsRemaining && (boostEndFrame <= itsGame->frameNumber)) { CBasicSound *theSound; boostsRemaining--; - boostEndFrame = itsGame->FramesFromNow(BOOSTLENGTH); + boostEndFrame = itsGame->FramesFromNow(BOOSTLENGTH+1); if (!boostControlLink) boostControlLink = gHub->GetSoundLink(); @@ -1715,7 +1716,8 @@ void CAbstractPlayer::GunActions() { if (weapon) { weapon->Fire(); weaponIdent = 0; - } else { + } else if (nextPlasmaShot <= itsGame->frameNumber) { + nextPlasmaShot = itsGame->FramesFromNow(1); i = gunEnergy[0] < gunEnergy[1]; if (gunEnergy[i] >= activeGunEnergy) { Vector missileSpeed; @@ -1986,7 +1988,7 @@ bool CAbstractPlayer::ReincarnateComplete(CIncarnator* newSpot) { LinkPartSpheres(); if (reEnergize) { - boostEndFrame = itsGame->FramesFromNow(MINIBOOSTTIME); + boostEndFrame = itsGame->FramesFromNow(MINIBOOSTTIME+1); reEnergize = false; if (shields < maxShields) shields = maxShields; @@ -2299,10 +2301,10 @@ void CAbstractPlayer::TakeGoody(GoodyRecord *gr) { if (energy > maxEnergy) energy = maxEnergy; - if (gr->boostTime > 0 && (boostEndFrame < itsGame->frameNumber)) { + if (gr->boostTime > 0 && (boostEndFrame <= itsGame->frameNumber)) { CBasicSound *theSound; - boostEndFrame = itsGame->FramesFromNow(gr->boostTime); + boostEndFrame = itsGame->FramesFromNow(gr->boostTime+1); if (!boostControlLink) boostControlLink = gHub->GetSoundLink(); diff --git a/src/game/CAbstractPlayer.h b/src/game/CAbstractPlayer.h index 769dbcfb..1ab4488b 100644 --- a/src/game/CAbstractPlayer.h +++ b/src/game/CAbstractPlayer.h @@ -83,6 +83,7 @@ class CAbstractPlayer : public CRealMovers { short grenadeCount = 0; FrameNumber nextGrenadeLoad = 0; FrameNumber nextMissileLoad = 0; + FrameNumber nextPlasmaShot = 0; short missileLimit = 0; short grenadeLimit = 0; diff --git a/src/game/CBall.cpp b/src/game/CBall.cpp index 73b54d73..509c3072 100644 --- a/src/game/CBall.cpp +++ b/src/game/CBall.cpp @@ -298,7 +298,7 @@ void CBall::MagnetAction() { Vector snapTo; CSmartPart *newHost; - if ((theActor->ident != oldHost || looseFrame < thisFrame) && + if ((theActor->ident != oldHost || looseFrame <= thisFrame) && !(theActor->maskBits & kPlayerBit && holdShieldLimit < shields && theActor->teamColor != teamColor)) { snapCode = theActor->GetBallSnapPoint(group, location, snapTo, localSnap, &newHost); @@ -495,7 +495,7 @@ void CBall::FrameAction() { SecondaryDamage(teamColor, -1, ksiObjectCollision); return; // *** return after dispose! *** case kDoRelease: - looseFrame = itsGame->FramesFromNow(100); + looseFrame = itsGame->FramesFromNow(101); oldHost = hostIdent; case kDoReset: { CSmartPart *savedHost; @@ -532,7 +532,7 @@ long CBall::ReceiveSignal(long theSignal, void *miscData) { case kBallReleaseSignal: { CSmartPart *theBall = partList[0]; - looseFrame = itsGame->FramesFromNow(32); + looseFrame = itsGame->FramesFromNow(33); oldHost = hostIdent; ReleaseAttachment(); speed[0] += FMul(pitchZ, theBall->itsTransform[2][0]) + FMul(pitchY, theBall->itsTransform[1][0]); @@ -563,7 +563,7 @@ void CBall::ReleaseDamage(Fixed hitEnergy) { if (hostPart && playerAttach) { releaseHoldAccumulator += hitEnergy; if (releaseHoldAccumulator > dropDamage) { - looseFrame = itsGame->FramesFromNow(10); + looseFrame = itsGame->FramesFromNow(11); oldHost = hostIdent; ReleaseAttachment(); } diff --git a/src/tests.cpp b/src/tests.cpp index 488ee0e2..533ee878 100644 --- a/src/tests.cpp +++ b/src/tests.cpp @@ -468,11 +468,11 @@ vector HectorEnergyRegen(int steps, bool useBoost, int fra int ticksPerStep = GetTicksPerStep(frameTime); scenario.hector->energy = scenario.hector->maxEnergy * 0.5; - if (useBoost) { - scenario.hector->itsManager->GetFunctions()->down = (1 << kfuBoostEnergy); - } for (int i = 0; i < steps; i++) { + if (i == 1 && useBoost) { + scenario.hector->itsManager->GetFunctions()->down = (1 << kfuBoostEnergy); + } HectorEnergyReadings current(scenario.hector); energyValues.push_back(current); for (int k = 0; k < ticksPerStep; k++) { @@ -490,11 +490,11 @@ vector HectorPlasmaRegen(int steps, bool useBoost, int fra scenario.hector->gunEnergy[0] = 0; scenario.hector->gunEnergy[1] = 0; - if (useBoost) { - scenario.hector->itsManager->GetFunctions()->down = (1 << kfuBoostEnergy); - } for (int i = 0; i < steps; i++) { + if (i == 1 && useBoost) { + scenario.hector->itsManager->GetFunctions()->down = (1 << kfuBoostEnergy); + } HectorEnergyReadings current(scenario.hector); energyValues.push_back(current); for (int k = 0; k < ticksPerStep; k++) { @@ -511,11 +511,11 @@ vector HectorShieldRegen(int steps, bool useBoost, int fra int ticksPerStep = GetTicksPerStep(frameTime); scenario.hector->shields = scenario.hector->maxShields * 0.5; - if (useBoost) { - scenario.hector->itsManager->GetFunctions()->down = (1 << kfuBoostEnergy); - } for (int i = 0; i < steps; i++) { + if (i == 1 && useBoost) { + scenario.hector->itsManager->GetFunctions()->down = (1 << kfuBoostEnergy); + } HectorEnergyReadings current(scenario.hector); energyValues.push_back(current); for (int k = 0; k < ticksPerStep; k++) {