burst fire view kickback fix, accuracy kickback time proper, compiles

This commit is contained in:
Chris Dawalt 2021-10-02 22:01:09 -04:00
parent 94aee91bf0
commit 497393eea6
4 changed files with 113 additions and 47 deletions

View file

@ -31,6 +31,7 @@ enum PLAYER_STATE{
#define ATTR_CHANGED_ARY(ary, i) (ary ##_net[i] != ary[i])
#define PREDICTED_ARY_INT(ary, size) int ary[size]; int ary ##_net[size]
#define PREDICTED_ARY_FLOAT(ary, size) float ary[size]; float ary ##_net[size]
#define ROLL_BACK_ARY(ary, i) ary[i] = ary ##_net[i]
#define SAVE_STATE_ARY(ary, i) ary ##_net[i] = ary[i]
@ -339,10 +340,19 @@ class player:base_player
// Shared, but don't network! I think?
int aryNextBurstShotTime_softLength;
float aryNextBurstShotTime[5];
int aryNextBurstShotTime_listenIndex;
// apparently we do need to do this, at least network somewhat.
// Unsure how much, maybe the 'aryNextBurstShotTime' every single frame
// is a bit overkill, should only need to be set at the start of a burst-fire.
// So no need for networking as the client/server should set those to the same
// values independently, but no idea of the prediction-rollbacks on clientside
// would complicate that, maybe still do the SAVE/ROLL_BACK stuff?
// aryNextBurstShotTime_listenIndex depends on the time and updates a lot,
// that one most likely has to stay networked and predicted.
PREDICTED_INT(aryNextBurstShotTime_softLength);
PREDICTED_ARY_FLOAT(aryNextBurstShotTime, 5);
PREDICTED_INT(aryNextBurstShotTime_listenIndex);
PREDICTED_ARY_INT(ary_ammoTotal, AMMO_ID::LAST_ID);
//shotgun stuff
//////////////////////////////////////////////////////////////////////////////
@ -384,21 +394,22 @@ class player:base_player
//////////////////////////////////////////////////////////////////////////////
// -1 = nothing special, holding grenade normally. Pressing primary/secondary
// 0 = nothing special, holding grenade normally. Pressing primary/secondary
// starts the next phase.
// 0 = pull-pin animation, and stays this way until the animation finishes and
// 1 = pull-pin animation, and stays this way until the animation finishes and
// neither input is held down. Then the next phase starts.
// 1 = throw or throw-slide anim picked, based on primary or secondary being
// 2 = throw or throw-slide anim picked, based on primary or secondary being
// pressed the most recently. Jumps to phase 2.
// 2 = throw/slide anim playing. Grenade spawns very soon. After the anim
// 3 = throw/slide anim playing. Grenade spawns very soon. After the anim
// finishes, decide whether to bring another grenade up (has ammo), other-
// wise, discard the weapon and pick another.
PREDICTED_INT(grenadeFireIndex);
// at what time do I throw the grenade after starting the throw/toss anim?
float grenadeSpawnTime;
float grenadeHeldDuration;
//TAGGG - should these be predicted too? Unsure. Possibly not.
PREDICTED_FLOAT(grenadeSpawnTime);
PREDICTED_FLOAT(grenadeHeldDuration);
// Same for this, but it has been for a while
PREDICTED_FLOAT(bGrenadeToss); //set to FALSE if it's a typical throw instead.
@ -472,7 +483,7 @@ class player:base_player
// to. Sounds like a lot of extra work for a single ammo counter per type of ammo which
// is all this is.
//int ary_ammoTotal[AMMO_ID::LAST_ID];
PREDICTED_ARY_INT(ary_ammoTotal,AMMO_ID::LAST_ID);
PREDICTED_ARY_INT(ary_ammoTotal, AMMO_ID::LAST_ID);
// Provided for quick reference. How many slots does the current loadout take?
// There is a record of how much money has been spent, similar to config, but that isn't

View file

@ -236,7 +236,10 @@ player::ReceiveEntity(float new, float fl)
nextAkimboAttackPreference = readbyte();
akimboDualFireToleranceTime = readfloat();
grenadeFireIndex = readbyte() - 1;
grenadeFireIndex = readbyte();
grenadeHeldDuration = readfloat();
grenadeSpawnTime = readfloat();
bGrenadeToss = readbyte();
@ -276,6 +279,12 @@ player::ReceiveEntity(float new, float fl)
fKarateStamina = readfloat();
aryNextBurstShotTime_softLength = readbyte();
for(i = 0; i < aryNextBurstShotTime_softLength; i++){
aryNextBurstShotTime[i] = readfloat();
}
aryNextBurstShotTime_listenIndex = readbyte() - 1;
shotgunReloadIndex = readbyte();
shotgunAddAmmoTime = readfloat();
shotgunAddAmmoSoundTime = readfloat();
@ -381,6 +390,7 @@ so we can roll them back later.
void
player::PredictPreFrame(void)
{
int i;
//printfline("---PREDICT PRE FRAME");
@ -407,7 +417,10 @@ player::PredictPreFrame(void)
SAVE_STATE(iZoomLevel);
SAVE_STATE(nextAkimboAttackPreference);
SAVE_STATE(akimboDualFireToleranceTime);
SAVE_STATE(grenadeFireIndex);
SAVE_STATE(grenadeHeldDuration);
SAVE_STATE(grenadeSpawnTime);
SAVE_STATE(bGrenadeToss);
@ -428,6 +441,12 @@ player::PredictPreFrame(void)
SAVE_STATE(fKarateStamina);
SAVE_STATE(aryNextBurstShotTime_softLength);
for(i = 0; i < aryNextBurstShotTime_softLength; i++){
SAVE_STATE_ARY(ary_ammoTotal, i);
}
SAVE_STATE(aryNextBurstShotTime_listenIndex);
SAVE_STATE(shotgunReloadIndex);
@ -436,7 +455,7 @@ player::PredictPreFrame(void)
SAVE_STATE(ary_myWeapons_softMax);
for(int i = 0; i < ary_myWeapons_softMax; i++){
for(i = 0; i < ary_myWeapons_softMax; i++){
SAVE_STATE(ary_myWeapons[i].weaponID);
SAVE_STATE(ary_myWeapons[i].weaponTypeID);
SAVE_STATE(ary_myWeapons[i].iBitsUpgrade);
@ -455,7 +474,7 @@ player::PredictPreFrame(void)
//UNNECESSARY. This array is of fixed length, so known at all times.
//WriteByte(MSG_ENTITY, ary_ammoTotal_softMax);
for(int i = 0; i < AMMO_ID::LAST_ID; i++){
for(i = 0; i < AMMO_ID::LAST_ID; i++){
// See serverside equivalent, too much info was lost from some pools being over 255
// (well I guess that's all there is to it)
SAVE_STATE_ARY(ary_ammoTotal, i);
@ -482,6 +501,7 @@ Where we roll back our values to the ones last sent/verified by the server.
void
player::PredictPostFrame(void)
{
int i;
//printfline("---PREDICT POST FRAME");
sendevent("ViewOffsetR", "fff", vViewAngleOffsetTotalChange[0], vViewAngleOffsetTotalChange[1], vViewAngleOffsetTotalChange[2]);
@ -513,7 +533,10 @@ player::PredictPostFrame(void)
ROLL_BACK(nextAkimboAttackPreference);
ROLL_BACK(akimboDualFireToleranceTime);
ROLL_BACK(grenadeFireIndex);
ROLL_BACK(grenadeHeldDuration);
ROLL_BACK(grenadeSpawnTime);
ROLL_BACK(bGrenadeToss);
//flKarateBlockCooldown
@ -532,15 +555,21 @@ player::PredictPostFrame(void)
ROLL_BACK(fUncrouchBlockDelay);
ROLL_BACK(fKarateStamina);
ROLL_BACK(aryNextBurstShotTime_softLength);
for(i = 0; i < aryNextBurstShotTime_softLength; i++){
ROLL_BACK_ARY(ary_ammoTotal, i);
}
ROLL_BACK(aryNextBurstShotTime_listenIndex);
ROLL_BACK(shotgunReloadIndex);
ROLL_BACK(shotgunAddAmmoTime);
ROLL_BACK(shotgunAddAmmoSoundTime);
ROLL_BACK(ary_myWeapons_softMax);
for(int i = 0; i < ary_myWeapons_softMax; i++){
for(i = 0; i < ary_myWeapons_softMax; i++){
ROLL_BACK(ary_myWeapons[i].weaponID);
ROLL_BACK(ary_myWeapons[i].weaponTypeID);
ROLL_BACK(ary_myWeapons[i].iBitsUpgrade);
@ -559,7 +588,7 @@ player::PredictPostFrame(void)
// UNNECESSARY. This array is of fixed length, so known at all times.
//WriteByte(MSG_ENTITY, ary_ammoTotal_softMax);
for(int i = 0; i < AMMO_ID::LAST_ID; i++){
for(i = 0; i < AMMO_ID::LAST_ID; i++){
// See serverside equivalent, too much info was lost from some pools being over 255
// (well I guess that's all there is to it)
ROLL_BACK_ARY(ary_ammoTotal, i);
@ -659,7 +688,10 @@ player::EvaluateEntity(void)
SAVE_STATE(iZoomLevel);
SAVE_STATE(nextAkimboAttackPreference);
SAVE_STATE(akimboDualFireToleranceTime);
SAVE_STATE(grenadeFireIndex);
SAVE_STATE(grenadeHeldDuration);
SAVE_STATE(grenadeSpawnTime);
SAVE_STATE(bGrenadeToss);
//flKarateBlockCooldown
@ -679,6 +711,13 @@ player::EvaluateEntity(void)
SAVE_STATE(fKarateStamina);
SAVE_STATE(aryNextBurstShotTime_softLength);
for(i = 0; i < aryNextBurstShotTime_softLength; i++){
SAVE_STATE_ARY(ary_ammoTotal, i);
}
SAVE_STATE(aryNextBurstShotTime_listenIndex);
SAVE_STATE(shotgunReloadIndex);
SAVE_STATE(shotgunAddAmmoTime);
@ -789,7 +828,10 @@ player::SendEntity(entity ePEnt, float fChanged)
}
WriteByte(MSG_ENTITY, nextAkimboAttackPreference);
WriteFloat(MSG_ENTITY, akimboDualFireToleranceTime);
WriteByte(MSG_ENTITY, grenadeFireIndex + 1);
WriteByte(MSG_ENTITY, grenadeFireIndex);
WriteFloat(MSG_ENTITY, grenadeHeldDuration);
WriteFloat(MSG_ENTITY, grenadeSpawnTime);
WriteByte(MSG_ENTITY, bGrenadeToss);
WriteByte(MSG_ENTITY, armor );
@ -813,6 +855,12 @@ player::SendEntity(entity ePEnt, float fChanged)
WriteFloat(MSG_ENTITY, fKarateStamina);
WriteByte(MSG_ENTITY, aryNextBurstShotTime_softLength);
for(i = 0; i < aryNextBurstShotTime_softLength; i++){
WriteFloat(MSG_ENTITY, aryNextBurstShotTime[i]);
}
WriteByte(MSG_ENTITY, aryNextBurstShotTime_listenIndex + 1);
WriteByte(MSG_ENTITY, shotgunReloadIndex );
WriteFloat(MSG_ENTITY, shotgunAddAmmoTime );
@ -1013,7 +1061,7 @@ player::reset(BOOL resetInventory){
shotgunAddAmmoSoundTime = -1;
//Grenade stuff
grenadeFireIndex = -1;
grenadeFireIndex = 0;
grenadeHeldDuration = -1;
grenadeSpawnTime = -1;
bGrenadeToss = FALSE;
@ -1152,7 +1200,7 @@ player::updateTimers(void){
if(fAccuracyKickbackStartCooldown <= 0){
// begin reducing
//fAccuracyKickback -= frametime * 0.1;
fAccuracyKickback = max(0, fAccuracyKickback - input_timelength);
fAccuracyKickback = max(0, fAccuracyKickback - input_timelength * 0.1);
if(fAccuracyKickback <= 0){
// stop!
@ -1211,9 +1259,10 @@ player::updateTimers(void){
// test? main one
#ifndef CLIENT
GET_MY_VIEW_ANGLES = GET_MY_VIEW_ANGLES + finalChange;
#else
// (this might be pointless?)
this.vViewAngleOffsetTotalChangeAlt += finalChange;
#else
#endif

View file

@ -307,6 +307,10 @@ weapon_base_onAttack(player pl, weapondata_basic_t* basePRef, weapondynamic_t ar
// For firing once the left or right has been picked for firing, does not matter which as this has
// no effect on the weapon stats. Also applies kickback for firing once.
// TODO: restore random-ness of kickback, going left/right angle-wise and
// varrying the intensity, 65% to 100%, as shown commented out below.
// Need shared randoms for that to work, input_sequence is not relayed
// to the server on processing an input it seems.
void
weapon_base_onAttack_individual(player pl, weapondata_basic_t* basePRef, weapondynamic_t arg_thisWeapon, int shellCount){
@ -391,12 +395,15 @@ weapon_base_onAttack_individual(player pl, weapondata_basic_t* basePRef, weapond
finalAng = ( 90 - (angleRange/2) + randoAngFactor*( angleRange ) ) * (M_PI/180);
pl.addViewAngleOffset(finalAng, finalAmount);
// TODO - be better shared later?
// Syncing view kickback would need the random-ness to be handled between server/client,
// maybe seeded randoms? I forget.
// Properly predicted shotgun firing would be a good demonstration of that too,
// so what happens instantly (client sees) and what actually happened (server sees; everyone
// else sees) line up.
// separate accuracy-kickback that spaces the crosshairs out and causes the weapon-spread
// to be higher to discourage firing too much, even beyon the view-kickback that forces
// the camera up. I don't think it has any random component, determined by weapon
// stats only.
// Also this is going off what makes sense with the as-is game stats, 0.1 is the
// highest accuracy kickback allowed and it slows down at a rate of 10% real-time.
// When reached, the 0.1 cap takes 1 second of not-firing to be completely reset.
// fAccuracyKickbackStartCooldown is still real-time, so 0.14 seconds, and the reduction
// starts happening after it runs out.
pl.fAccuracyKickbackStartCooldown = 0.14;
pl.fAccuracyKickback += baseRef.firestats.fAccuracyKickback;
if(pl.fAccuracyKickback >= 0.1){

View file

@ -38,7 +38,7 @@ void weapon_m61grenade_onThink(player pl, weapondynamic_t arg_thisWeapon){
// If using to keep track of what animation to play (like HL having different throw anims for
// range), that should be networked so that this gives an accurate viewmodel.
// ALTHOUGH, this applies to the time of picking a throw anim, not spawning the grenade.
if(pl.grenadeSpawnTime != -1 && pl.grenadeFireIndex > 0){
if(pl.grenadeSpawnTime != -1 && pl.grenadeFireIndex > 1){
pl.grenadeHeldDuration = min(pl.grenadeHeldDuration + input_timelength, 3);
if(pl.w_attack_next <= pl.grenadeSpawnTime){
@ -71,44 +71,43 @@ void weapon_m61grenade_onThink(player pl, weapondynamic_t arg_thisWeapon){
printfline("!!! w_attack_next FINISHED WITH GRENFIREIN: %i", pl.grenadeFireIndex);
prevChoice = pl.grenadeFireIndex;
}
if(pl.grenadeFireIndex > 0){
if(pl.grenadeFireIndex > 1){
printfline("pl.grenadeFireIndex resolved: %i", pl.grenadeFireIndex);
}
*/
if(pl.grenadeFireIndex == 0){
if(pl.grenadeFireIndex == 1){
// pin pull animation is finished, ready to throw when the input is not held down.
pl.grenadeHeldDuration = min(pl.grenadeHeldDuration + input_timelength, 3);
if(!(input_buttons & INPUT_BUTTON0) && !(input_buttons & INPUT_BUTTON3)){
// neither input held down? Move on
//printfline("!!! RELEASE");
pl.grenadeFireIndex = 1;
pl.grenadeFireIndex = 2;
}
}
// should this be joined by else or no?
if(pl.grenadeFireIndex == 1){
if(pl.grenadeFireIndex == 2){
// Release detected, do the throw anim + spawn the grenade soon
if(!pl.bGrenadeToss){
TS_Weapons_ViewAnimation(weaponseq_m61grenade::throw, 11.0f/30.0f);
}else{
TS_Weapons_ViewAnimation(weaponseq_m61grenade::throw_slide, 11.0f/30.0f);
}
pl.grenadeFireIndex = 2;
pl.grenadeFireIndex = 3;
// re-use shotgunAddAmmoTime instead, make the var more genericly named maybe???
//pl.grenadeSpawnTime = time + 4.0f/30.0f;
weapon_base_setWholeAttackDelay(pl, (11.0f/30.0f) * 1);
pl.grenadeSpawnTime = pl.w_attack_next - 4.0f/30.0f;
}else if(pl.grenadeFireIndex == 2){
}else if(pl.grenadeFireIndex == 3){
// Throw anim is over, decide whether to deploy another grenade or remove the
// weapon if out of grenades.
//printfline("Remove grenade? Count:%i", arg_thisWeapon.iCount);
if(arg_thisWeapon.iCount > 0){
TS_Weapons_ViewAnimation(weaponseq_m61grenade::draw, 31.0f / 40.0f );
printfline("I set grenadeFireIndex to -1, B!");
pl.grenadeFireIndex = -1;
printfline("I set grenadeFireIndex to 0, B!");
pl.grenadeFireIndex = 0;
weapon_base_setWholeAttackDelay(pl, (31.0f/40.0f));
}else{
@ -122,8 +121,8 @@ void weapon_m61grenade_onThink(player pl, weapondynamic_t arg_thisWeapon){
//printfline("removeWeaponFromInventory POST cur weapo: %i", pl.inventoryEquippedIndex);
printfline("I set grenadeFireIndex to -1, C!");
pl.grenadeFireIndex = -1; // paranoia?
printfline("I set grenadeFireIndex to 0, C!");
pl.grenadeFireIndex = 0; // paranoia?
return;
}
@ -183,8 +182,8 @@ void weapon_grenade_onInputPress(player pl, weapondynamic_t arg_thisWeapon, int
// Initiating a throw is only do-able when the attack delay is up, and a fresh key press.
// Don't allow to interrupt the deploy anim.
if(pl.w_attack_next <= 0 && (INPUT_PRIMARY_TAP_CHECK(pl) || INPUT_SECONDARY_TAP_CHECK(pl))){
if(pl.grenadeFireIndex == -1){
pl.grenadeFireIndex = 0;
if(pl.grenadeFireIndex == 0){
pl.grenadeFireIndex = 1;
printfline("WHAT THE heckin heck IS THIS %.2f", time);
pl.grenadeSpawnTime = -1; // not yet!
pl.grenadeHeldDuration = 0;
@ -194,7 +193,7 @@ void weapon_grenade_onInputPress(player pl, weapondynamic_t arg_thisWeapon, int
}
// Once already started, this can affect being a normal throw or slide-throw.
if(pl.grenadeFireIndex == 0){
if(pl.grenadeFireIndex == 1){
if(attackTypeUsed & BITS_AKIMBOCHOICE_LEFT){
pl.bGrenadeToss = FALSE; //throw, this was primary.
}else if(attackTypeUsed & BITS_AKIMBOCHOICE_RIGHT){
@ -221,12 +220,12 @@ void weapon_grenade_onInputRelease(player pl, weapondynamic_t arg_thisWeapon){
// (except above, checks a bit differently for spawning the grenade)
return;
}
if(pl.grenadeFireIndex == 0){
if(pl.grenadeFireIndex == 1){
// pin pull animation is finished, ready to throw when the input is not held down.
if(!(input_buttons & INPUT_BUTTON0) && !(input_buttons & INPUT_BUTTON3)){
// primary not held down? Move on then
//printfline("!!! RELEASE DETECT");
pl.grenadeFireIndex = 1;
pl.grenadeFireIndex = 2;
}
}
}
@ -277,8 +276,8 @@ w_m61grenade_draw(void)
player pl = (player)self;
weapondynamic_t arg_thisWeapon = pl.ary_myWeapons[pl.inventoryEquippedIndex];
printfline("I set grenadeFireIndex to -1, A!");
pl.grenadeFireIndex = -1;
printfline("I set grenadeFireIndex to 0, A!");
pl.grenadeFireIndex = 0;
pl.grenadeSpawnTime = -1;
pl.grenadeHeldDuration = 0;