shotgun with packet delays

This commit is contained in:
Chris Dawalt 2021-08-05 03:51:43 -04:00
parent 7753285cfb
commit d3a620bb55
16 changed files with 487 additions and 178 deletions

View file

@ -231,7 +231,7 @@ TS_HUD_DrawWeaponSelect(void)
return;
}
drawPlayerInventory_buy(FALSE);
drawPlayerInventory(FALSE);
drawPlayerInventory_TopBar(-1, FALSE);
}//HUD_DrawWeaponSelect

View file

@ -57,7 +57,7 @@ imageCropBounds_t ary_LCD_numberSet[] = {
void drawWeaponOptionBar(vector arg_vDrawOrigin, string arg_sOptionName, BOOLEAN arg_fBrightLight, float arg_opac);
void drawPlayerInventory_TopBar(int arg_iSlotSelected, BOOL arg_fBuyMode);
void drawPlayerInventory_buy(BOOL arg_fBuyMode);
void drawPlayerInventory(BOOL arg_fBuyMode);
void drawPlayerInventory_place(int arg_iSlot, int arg_iRow, string arg_sWeaponSpritePath, string arg_sSelectedWeaponDisplayName, BOOL arg_fBuyMode, optional int ammoCount, optional BOOL hasAnyAmmo, optional int bitsUpgradeOpts);

View file

@ -70,11 +70,13 @@ drawPlayerInventory_TopBar(int arg_iSlotSelected, BOOL arg_fBuyMode)
}//drawPlayerInventory_TopBar
// While in the buy screen, draw each slot according to the current temp config.
// This includes using the #1 slot for the text
// ...We're going to take advantage of the fact that weaponconfig_weapon_t
// This includes using the #1 slot for the text.
// For buymode, we're displaying the tempconfig (what things to buy at spawntime).
// Otherwise, this is the player's ingame inventory being drawn.
void
drawPlayerInventory_buy(BOOL arg_fBuyMode)
drawPlayerInventory(BOOL arg_fBuyMode)
{
player pl = (player)pSeat->m_ePlayer;

View file

@ -41,11 +41,7 @@
#if defined(CSQC) || defined(MENU)
#if defined(CLIENT) || defined(MENU)
//TAGGG - just give those bits names
#define DRAWTEXTFIELD_ALIGN_LEFT 1
@ -68,11 +64,6 @@
typedef struct{
string sFilePath;
float w;

View file

@ -1438,6 +1438,7 @@ void
VGUI_BuySideMenu_Update(player arg_player, vector vPos, vector vWindowSiz, float fFontSizeMulti)
{
// If we leave spectator view (spawned and walking/aiming), disallow the buy menu.
// (could also check for "player.iState == PLAYER_STATE::SPAWNED" )
if(getplayerkeyvalue(player_localnum, "*spec") == "0"){
VGUI_ChangeScreen(VGUI_SCREEN::NONE);
@ -1472,7 +1473,7 @@ VGUI_BuySideMenu_Update(player arg_player, vector vPos, vector vWindowSiz, float
BuySideMenu_onInputEvent();
drawPlayerInventory_buy(TRUE);
drawPlayerInventory(TRUE);
for(int i = 0i; i <= iActiveLayer; i = i + 1i){
//Adjust these as needed. These also show where to draw the "0 Cancel" button

View file

@ -426,11 +426,20 @@ CSEv_TS_playerDropWeapon_(){
#ifdef SERVER
// Server receives the message
void
CSEv_TS_playerChangeFiremode_(void){
player pl = (player)self;
#ifdef FIREMODE_PREDICTION_TEST
pl.doFiremodeChange = TRUE;
#else
_TS_playerChangeFiremode();
#endif//FIREMODE_PREDICTION_TEST
}
#endif
@ -443,10 +452,18 @@ TS_playerChangeFiremode(void){
if(pl.inventoryEquippedIndex == -1){
return;
}
#ifdef CLIENT
sendevent("TS_playerChangeFiremode", "");
// and do it my side too?
#ifdef FIREMODE_PREDICTION_TEST
pl.ignoreFiremodeReceiveTime = time + 0.4f;
pl.doFiremodeChange = TRUE;
#else
// do it for the client too?
_TS_playerChangeFiremode();
#endif//FIREMODE_PREDICTION_TEST
#else
// SHOULD NOT HAPPEN, should call the CSEv_ version instead
#endif
@ -458,6 +475,12 @@ _TS_playerChangeFiremode(void ) {
player pl = (player)self;
weapondynamic_t dynaRef = pl.ary_myWeapons[pl.inventoryEquippedIndex];
#if defined(CLIENT_CMD_SAFEMODE) && defined(CLIENT)
// nope!
return;
#endif
if(dynaRef.weaponTypeID == WEAPONDATA_TYPEID_GUN || dynaRef.weaponTypeID == WEAPONDATA_TYPEID_IRONSIGHT){
weapondata_gun_t* basicPointer = (weapondata_gun_t*) pl.getEquippedWeaponData();
weapondata_gun_t basicRef = *(basicPointer);
@ -470,10 +493,13 @@ _TS_playerChangeFiremode(void ) {
}
int* fireModeVar;
int* fireModeVar_net;
if(!pl.weaponEquippedAkimbo){
fireModeVar = &dynaRef.iFireMode;
fireModeVar_net = &dynaRef.iFireMode_net;
}else{
fireModeVar = &dynaRef.iFireModeAkimbo;
fireModeVar_net = &dynaRef.iFireModeAkimbo_net;
}
if( (*fireModeVar) == basicRef.iBitsFireModes){
@ -506,6 +532,12 @@ _TS_playerChangeFiremode(void ) {
if(basicRef.iBitsFireModes & currentChoice){
//this power of 2 is a valid fireMode? pick it
(*fireModeVar) = currentChoice;
#ifdef CLIENT
// effectively SAVE_STATE on whatever choice
(*fireModeVar_net) = currentChoice;
#endif
return;
}
@ -551,6 +583,8 @@ void
_TS_playerUseItems(void){
player pl = (player)self;
if(pl.inventoryEquippedIndex != -1){
weapondynamic_t dynaRef = pl.ary_myWeapons[pl.inventoryEquippedIndex];
@ -573,6 +607,16 @@ _TS_playerUseItems(void){
//no togglable buyopts at all? I guess that's it.
}else{
#if defined(CLIENT_CMD_SAFEMODE) && defined(CLIENT)
// Have a much simpler version instead
#ifdef CLIENT
localsound("weapons/switch.wav", CHAN_AUTO, 1.0f);
#endif
return;
#endif
if(bitCount == 1){
//one bit available? just toggle on/off then.
if(bitCount_on){

View file

@ -85,6 +85,64 @@ Game_Input(void)
self.impulse = 0;
#endif
/*
// FreeHL's way
if (input_buttons & INPUT_BUTTON0)
Weapons_Primary();
else if (input_buttons & INPUT_BUTTON4)
Weapons_Reload();
else if (input_buttons & INPUT_BUTTON3)
Weapons_Secondary();
//else
pl.callWeaponThink(); //Weapons_Release();
// Added portion to that.
if(input_buttons & INPUT_BUTTON0){
pl.gflags |= GF_SEMI_TOGGLED;
}else{
// held down the previous frame, but not now? That's a release.
if(pl.gflags & GF_SEMI_TOGGLED){
TS_Weapon_PrimaryAttackRelease(pl, TRUE);
pl.gflags &= ~GF_SEMI_TOGGLED;
}
}
if(input_buttons & INPUT_BUTTON3){
pl.gflags |= GF_SEMI_SECONDARY_TOGGLED;
}else{
if(pl.gflags & GF_SEMI_SECONDARY_TOGGLED){
TS_Weapon_SecondaryAttackRelease(pl, TRUE);
pl.gflags &= ~GF_SEMI_SECONDARY_TOGGLED;
}
}
// it's this way or the much more modified way further down
return;
*/
#ifdef FIREMODE_PREDICTION_TEST
if(pl.doFiremodeChange){
// so they say?
#ifdef CLIENT
//sendevent("TS_playerChangeFiremode", "");
#endif
int iOldFiremode = pl.ary_myWeapons[pl.inventoryEquippedIndex].iFireMode;
_TS_playerChangeFiremode();
pl.doFiremodeChange = FALSE;
int iNewFiremode = pl.ary_myWeapons[pl.inventoryEquippedIndex].iFireMode;
printfline("!!! pl.doFiremodeChange seen! Firemode, old:%i new:%i", iOldFiremode, iNewFiremode);
}
#endif
// better TS way, weapon thinks happen alongside checking inputs
pl.callWeaponThink();
@ -102,8 +160,6 @@ Game_Input(void)
// to give some tolerance to ease some slight frame desyncs between the client/server.
BOOL wasPassingFrame = (pl.w_attack_next <= 0);
#if INPUT_TAP_DETECT_CHOICE == 1
processInputs();

View file

@ -11,7 +11,7 @@
#define PLAYER_INVENTORY_GENERIC pl.ary_myWeapons
#define PLAYER_INVENTORY_GENERIC_MAX pl.ary_myWeapons_softMax
//The server has the player's physical money for use anytime.
//Can make changes to it as needed. Just use the usual "ifdef SSQC" check first.
//Can make changes to it as needed. Just use the usual "ifdef SERVER" check first.
//...actually, we're using CHANGE_PLAYER_MONEY instead. It includes instructions for changing the player's own memory of total amount
//spent (useless for the server?), and actually changes the money count.
#define PLAYER_MONEY pl.money

View file

@ -27,8 +27,19 @@ enum PLAYER_STATE{
};
#define PREDICTED_CUSTOM(arg_t, x) arg_t x; arg_t x ##_net
#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 ROLL_BACK_ARY(ary, i) ary[i] = ary ##_net[i]
#define SAVE_STATE_ARY(ary, i) ary ##_net[i] = ary[i]
#define PREDICTED_CUSTOM(arg_t, x) arg_t x; arg_t x ##_net
/*
#define ROLL_BACK_ARRAY_MEMBER(ary, i, sub) ary[i].sub = ary ##_net[i].sub
#define SAVE_STATE_ARRAY_MEMBER(ary, i, sub) x ##_net = x // did not do
*/
noref int input_sequence;
class player:base_player
@ -296,17 +307,17 @@ class player:base_player
// When do I want to move on to the next phase?
// For reload2 without a changed shotgunReloadIndexQueued or seeing the shotgun is full,
// it wants to repeat to put more bullets in.
float shotgunAddAmmoTime;
float shotgunAddAmmoSoundTime;
PREDICTED_FLOAT(shotgunAddAmmoTime);
PREDICTED_FLOAT(shotgunAddAmmoSoundTime);
#ifdef CLIENT
#else
// This time must pass before re-setting the shotgunAddAmmoTime/shotgunAddAmmoSoundTime counters is allowed.
// Why do we need to do this? Ask FTE.
float shotgunAddAmmoTime_cooldownSetTime;
#endif
// shared
// length of time for the start, intermediate (ammo loading) and end animations.
@ -318,6 +329,11 @@ class player:base_player
int shotgunReload3_seq;
float shotgunReload3_Duration;
// was BOOL
PREDICTED_FLOAT(doFiremodeChange);
//////////////////////////////////////////////////////////////////////////////
//Grenade stuff
@ -401,15 +417,14 @@ class player:base_player
//This will tell us whether we intend to equip the akimbo version of hte currently
// equipped weapon. This is done since akimso variants, although selected separately in
// equipped weapon. This is done since akimso variants, although selected separately in222222222222
// weapon select, are still tied to the exact same element in ary_myWeapons.
// was BOOL.
PREDICTED_FLOAT(weaponEquippedAkimbo);
//TAGGG - you're the man now, dog!
weapondynamic_t ary_myWeapons[ary_myWeapons_length];
int ary_myWeapons_softMax;
PREDICTED_INT(ary_myWeapons_softMax);
// Have one space for each type of ammo available.
// If there were a large number of ammunitions and a low likelihood that all/most were
@ -417,7 +432,8 @@ class player:base_player
// of ammunitions expected and keep track of which one an index (0, 1, 2, 3, etc.) refers
// 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];
//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
@ -443,6 +459,9 @@ class player:base_player
//float lastweapon;
#endif
#ifdef FIREMODE_PREDICTION_TEST
float ignoreFiremodeReceiveTime;
#endif
//TAGGG - NEW, constructor
void(void) player;
@ -474,6 +493,11 @@ class player:base_player
virtual void(void) callWeaponThink;
/*
virtual BOOL(void) shotgunAddAmmoTime_canSet;
virtual void(void) shotgunAddAmmoTime_setCooldownSetTime;
*/
//TAGGG - CRITICAL.
// overriding Nuclide player physics method!
// If any ever get renamed, this needs to be kept up-to-date with that!
@ -508,7 +532,6 @@ class player:base_player
#endif
////////////////////////////////////////////////////////////

View file

@ -73,7 +73,8 @@ player::ReceiveEntity(float new, float fl)
anim_bottom = readbyte();
anim_bottom_time = readfloat();
}
int i;
float temp_flViewModelFrame;
temp_flViewModelFrame = readfloat();
@ -200,14 +201,18 @@ player::ReceiveEntity(float new, float fl)
shotgunReloadIndexQueued = readbyte();
shotgunWaitingForPump = readbyte();
//shotgunReload2_ammoLoadDelay = readbyte();
//shotgunAddAmmoTime = readbyte();
//shotgunAddAmmoSoundTime = readbyte();
shotgunAddAmmoTime = readfloat();
shotgunAddAmmoSoundTime = readfloat();
//doFiremodeChange = readbyte();
currentZoomChoice = readbyte() - 1;
// TODO: IDEA. Only send updates for the currently equipped weapon, maybe the previously equipped one
// a few frames too? Unsure.
ary_myWeapons_softMax = readbyte();
for(int i = 0; i < ary_myWeapons_softMax; i++){
for(i = 0; i < ary_myWeapons_softMax; i++){
ary_myWeapons[i].weaponID = readbyte();
//printfline("ERE I GO %i - %i\n", i, ary_myWeapons[i].weaponID);
ary_myWeapons[i].weaponTypeID = readbyte();
ary_myWeapons[i].iBitsUpgrade = readbyte();
ary_myWeapons[i].iCount = readbyte();
@ -216,7 +221,21 @@ player::ReceiveEntity(float new, float fl)
ary_myWeapons[i].iClipLeft = readbyte();
ary_myWeapons[i].iClipAkimboLeft = readbyte();
ary_myWeapons[i].iBitsUpgrade_on = readbyte();
ary_myWeapons[i].iFireMode = readbyte();
int newFir = readbyte();
#if defined(FIREMODE_PREDICTION_TEST)
if(i == this.inventoryEquippedIndex && ary_myWeapons[i].iFireMode != newFir){
printfline("!!! player::ReceiveEntity, iFireMode update, changed firemode, WAS: %i NOW: %i", ary_myWeapons[i].iFireMode, newFir);
}
if(time >= this.ignoreFiremodeReceiveTime){
printfline("X Change blocked, too soon");
ary_myWeapons[i].iFireMode = newFir;
}
#else
ary_myWeapons[i].iFireMode = newFir;
#endif
ary_myWeapons[i].iFireModeAkimbo = readbyte();
ary_myWeapons[i].iIronSight = readbyte();
ary_myWeapons[i].forceBodygroup1Submodel = readbyte();
@ -224,7 +243,7 @@ player::ReceiveEntity(float new, float fl)
//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)
ary_ammoTotal[i] = readlong();
@ -232,8 +251,6 @@ player::ReceiveEntity(float new, float fl)
/////////////////////////////////////////////////////
currentZoomChoice = readbyte() - 1;
// TODO! Check for any change in ammo values like this:
@ -312,6 +329,37 @@ player::PredictPreFrame(void)
SAVE_STATE(shotgunReloadIndexQueued);
SAVE_STATE(shotgunWaitingForPump);
SAVE_STATE(shotgunAddAmmoTime);
SAVE_STATE(shotgunAddAmmoSoundTime);
//SAVE_STATE(doFiremodeChange);
SAVE_STATE(ary_myWeapons_softMax);
for(int 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);
SAVE_STATE(ary_myWeapons[i].iCount);
//SAVE_STATE(ary_myWeapons[i].iPrice);
//SAVE_STATE(ary_myWeapons[i].iSlots);
SAVE_STATE(ary_myWeapons[i].iClipLeft);
SAVE_STATE(ary_myWeapons[i].iClipAkimboLeft);
SAVE_STATE(ary_myWeapons[i].iBitsUpgrade_on);
SAVE_STATE(ary_myWeapons[i].iFireMode);
SAVE_STATE(ary_myWeapons[i].iFireModeAkimbo);
SAVE_STATE(ary_myWeapons[i].iIronSight);
SAVE_STATE(ary_myWeapons[i].forceBodygroup1Submodel);
}
//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++){
// 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);
}
}
/*
@ -381,6 +429,35 @@ player::PredictPostFrame(void)
ROLL_BACK(shotgunReloadIndexQueued);
ROLL_BACK(shotgunWaitingForPump);
ROLL_BACK(shotgunAddAmmoTime);
ROLL_BACK(shotgunAddAmmoSoundTime);
//ROLL_BACK(doFiremodeChange);
ROLL_BACK(ary_myWeapons_softMax);
for(int 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);
ROLL_BACK(ary_myWeapons[i].iCount);
//ROLL_BACK(ary_myWeapons[i].iPrice);
//ROLL_BACK(ary_myWeapons[i].iSlots);
ROLL_BACK(ary_myWeapons[i].iClipLeft);
ROLL_BACK(ary_myWeapons[i].iClipAkimboLeft);
ROLL_BACK(ary_myWeapons[i].iBitsUpgrade_on);
ROLL_BACK(ary_myWeapons[i].iFireMode);
ROLL_BACK(ary_myWeapons[i].iFireModeAkimbo);
ROLL_BACK(ary_myWeapons[i].iIronSight);
ROLL_BACK(ary_myWeapons[i].forceBodygroup1Submodel);
}
//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++){
// 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);
}
}
@ -497,6 +574,37 @@ player::EvaluateEntity(void)
SAVE_STATE(shotgunReloadIndexQueued);
SAVE_STATE(shotgunWaitingForPump);
SAVE_STATE(shotgunAddAmmoTime);
SAVE_STATE(shotgunAddAmmoSoundTime);
//SAVE_STATE(doFiremodeChange);
SAVE_STATE(ary_myWeapons_softMax);
for(int 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);
SAVE_STATE(ary_myWeapons[i].iCount);
//SAVE_STATE(ary_myWeapons[i].iPrice);
//SAVE_STATE(ary_myWeapons[i].iSlots);
SAVE_STATE(ary_myWeapons[i].iClipLeft);
SAVE_STATE(ary_myWeapons[i].iClipAkimboLeft);
SAVE_STATE(ary_myWeapons[i].iBitsUpgrade_on);
SAVE_STATE(ary_myWeapons[i].iFireMode);
SAVE_STATE(ary_myWeapons[i].iFireModeAkimbo);
SAVE_STATE(ary_myWeapons[i].iIronSight);
SAVE_STATE(ary_myWeapons[i].forceBodygroup1Submodel);
}
//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++){
// 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);
}
}
/*
@ -517,9 +625,6 @@ player::SendEntity(entity ePEnt, float fChanged)
return (0);
}
//TAGGG - REPLACED.
/*
// other players don't need to know about these attributes
@ -539,6 +644,9 @@ player::SendEntity(entity ePEnt, float fChanged)
/* the generic client attributes */
base_player::SendEntity(ePEnt, fChanged);
int i;
if (fChanged & PLAYER_TOPFRAME) {
WriteByte(MSG_ENTITY, anim_top);
@ -630,13 +738,17 @@ player::SendEntity(entity ePEnt, float fChanged)
WriteByte(MSG_ENTITY, shotgunReloadIndexQueued );
WriteByte(MSG_ENTITY, shotgunWaitingForPump );
//WriteByte(MSG_ENTITY, shotgunReload2_ammoLoadDelay );
//WriteByte(MSG_ENTITY, shotgunAddAmmoTime );
//WriteByte(MSG_ENTITY, shotgunAddAmmoSoundTime );
WriteFloat(MSG_ENTITY, shotgunAddAmmoTime );
WriteFloat(MSG_ENTITY, shotgunAddAmmoSoundTime );
//WriteByte(MSG_ENTITY, doFiremodeChange);
WriteByte(MSG_ENTITY, currentZoomChoice + 1 );
//weapondynamic_t ary_myWeapons[ary_myWeapons_length];
WriteByte(MSG_ENTITY, ary_myWeapons_softMax );
for(int i = 0; i < ary_myWeapons_softMax; i++){
for(i = 0; i < ary_myWeapons_softMax; i++){
WriteByte(MSG_ENTITY, ary_myWeapons[i].weaponID );
WriteByte(MSG_ENTITY, ary_myWeapons[i].weaponTypeID );
WriteByte(MSG_ENTITY, ary_myWeapons[i].iBitsUpgrade );
@ -654,14 +766,12 @@ player::SendEntity(entity ePEnt, float fChanged)
//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++){
// using 'WriteLong' instead of 'WriteByte', because SOME AMMO POOL just had to
// exceed 255, didn't it.
WriteLong(MSG_ENTITY, ary_ammoTotal[i] );
}
WriteByte(MSG_ENTITY, currentZoomChoice + 1 );
return (1);
@ -680,6 +790,10 @@ player::player(void){
// reasonable default?
iState = PLAYER_STATE::NOCLIP;
#ifdef FIREMODE_PREDICTION_TEST
ignoreFiremodeReceiveTime = -1;
#endif
#ifdef SERVER
money = 0; //safety?
@ -872,7 +986,9 @@ player::reset(BOOL resetInventory){
shotgunReload2_ammoLoadDelay = -1;
shotgunAddAmmoTime = -1;
shotgunAddAmmoSoundTime = -1;
#ifdef CLIENT
shotgunAddAmmoTime_cooldownSetTime = -1;
#endif
shotgunReload1_seq = -1;
shotgunReload1_Duration = -1;
shotgunReload2_seq = -1;
@ -880,6 +996,8 @@ player::reset(BOOL resetInventory){
shotgunReload3_seq = -1;
shotgunReload3_Duration = -1;
doFiremodeChange = FALSE;
//Grenade stuff
printfline("I set grenadeFireIndex to -1, D!");
grenadeFireIndex = -1;
@ -1192,6 +1310,30 @@ player::callWeaponThink(void){
}
// well that didn't work.
/*
BOOL
player::shotgunAddAmmoTime_canSet(void){
#ifdef CLIENT
// require the cooldown
// is cltime better? Unsure
return (time >= shotgunAddAmmoTime_cooldownSetTime);
#else
// Server? Always
return TRUE;
#endif
}
void
player::shotgunAddAmmoTime_setCooldownSetTime(void){
#ifdef CLIENT
// do it
shotgunAddAmmoTime_cooldownSetTime = time + 0.02f;
#else
// Server? I don't.
#endif
}
*/
#ifdef SERVER
// runs every frame server-side. postthink, oddly enough, does not.

View file

@ -12,6 +12,31 @@
// Few config macros:
// If this is on, what's done for clientside on some commands (change firemode, change
// buyoption toggleables) will be dummied or much simpler to avoid a slight flicker
// seen in realistic packet delays (typical multiplayer).
// Why doesn't the chage made just stay until server update? I have no idea.
//#define CLIENT_CMD_SAFEMODE
// Do testing to see my attempt to get prediction with firemodes working (default control:
// F-key).
// Or, obvious with a high cl_delay_packets choice (1000), the firemode flickers to the
// new value and back to the old one, the full second has to pass for a delay_packets choice
// of 1000, and then it stays at the new version. ...?
// Why do messages keep coming back from the server to revert the firemode until the server
// message comes back? Shouldn't it be the case that nothing happens to it until then?
//#define FIREMODE_PREDICTION_TEST
///////////////////////////////////////////////////////////////////////////
#define NULL __NULL__
#define BOOL float
@ -32,6 +57,12 @@
// That means Nuclide's printf is only a shortener of print + sprintf for calls
// without any other fill-ins (%d, etc.).
// Undoing that here for now, compatible with original calls anytime.
// And do we care about bprint (broadcast-print)? Example:
// bprint(PRINT_HIGH, sprintf("SSQC: %s", sWow) );
// Probably not for debugging as printf is working fine for the typical rapid-fire
// single player debug.
#ifdef printf
#undef printf
#endif

View file

@ -325,12 +325,12 @@ typedef struct{
// TODO. make this a struct instead? should be feasible.
// yes this is a class... hm. fix later.
class weapondynamic_t{
int weaponID; //what weapon is this referring to in the array of weapon data (glock, SOCOM, SMG, M4A1, etc.)
int weaponTypeID; //what type of struct does the weapon use for convenient casting in lookups (gun, ironsight, melee, throwable)?
PREDICTED_INT(weaponID); //what weapon is this referring to in the array of weapon data (glock, SOCOM, SMG, M4A1, etc.)
PREDICTED_INT(weaponTypeID); //what type of struct does the weapon use for convenient casting in lookups (gun, ironsight, melee, throwable)?
// what did the player actually buy?
// Also set this even for forced buyopts, such as the ruger's silencer.
int iBitsUpgrade;
PREDICTED_INT(iBitsUpgrade);
// How many of this weapon are equipped? The Akimbo BuyOpt makes this potentially 2.
// Weapons that come akimbo (golden colts) will still treat this as "1".
@ -338,39 +338,39 @@ class weapondynamic_t{
// This is for whether the current weapon should be treated as one (golden colts drop together in one
// model) or whether dropping just removes the akimbo version.
// Throwing knives can also use this iCount to stack instead.
int iCount;
PREDICTED_INT(iCount);
//Does keeping track of these things on an actual inventory'd weapon even makes sense?
//Ah well, lazy client-server logic compatability for now.
int iPrice;
int iSlots;
PREDICTED_INT(iPrice);
PREDICTED_INT(iSlots);
int iClipLeft;
int iClipAkimboLeft; //ammo left of the 2nd weapon if the akimbo option is present.
PREDICTED_INT(iClipLeft);
PREDICTED_INT(iClipAkimboLeft); //ammo left of the 2nd weapon if the akimbo option is present.
// Buyopts flashlight and lasersight can be toggled on/off. The rest don't need
// to be part of this bitmask to be on at all times.
int iBitsUpgrade_on;
PREDICTED_INT(iBitsUpgrade_on);
// What firemode is the player using for this weapon now?
int iFireMode;
int iFireModeAkimbo;
PREDICTED_INT(iFireMode);
PREDICTED_INT(iFireModeAkimbo);
// Is the player using ironsight (right-click)? Also include checks for scoping / drawing overlays
// in logic later if needed.
// This is usually a boolean (0 or 1... off or on), but weapons with multiple magnifications can use
// this to count too, such as for 2times or 10times. 0(off), 1(2x), 2(10x).
int iIronSight;
PREDICTED_INT(iIronSight);
// Do I force the first bodygroup's submodel to a certain choice?
// NOTE - do not set to 0 during intended use! That is only a lazy default to say, don't do anything
// to the submodel on drawing this weapon. Submodels actually start at 1, even if the only one.
// If set to 0, the change will only be noticed on undrawing/drawing the weapon as the submodel will
// not be applied then. Set to 1 to change in real time (likely the intention).
int forceBodygroup1Submodel;
PREDICTED_INT(forceBodygroup1Submodel);
void(void) weapondynamic_t;
@ -718,7 +718,6 @@ typedef struct{
string sWorldModelPath;
string sIconFilePath;
//!!!!!!!!!
BOOL(player pl, weapondynamic_t arg_thisWeapon, BOOL hasAmmo) vOnPrimaryAttack;
BOOL(player pl, weapondynamic_t arg_thisWeapon, BOOL hasAmmo) vOnPrimaryAttackRelease;
BOOL(player pl, weapondynamic_t arg_thisWeapon, BOOL hasAmmo) vOnSecondaryAttack;
@ -732,7 +731,6 @@ typedef struct{
void(player pl, weapondynamic_t arg_thisWeapon) vOnColdCock;
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
int iAnim_Idle_Index;
int iAnim_Deploy_Index;

View file

@ -1,5 +1,14 @@
weapon_t w_null = {};
// Populate each slot with a member of the enum early on in runtime instead.
@ -35,9 +44,7 @@ weapon_base_setWholeAttackDelay(player pl, float amount){
pl.w_attack_next = amount;
pl.w_attack_akimbo_next = amount;
// I think this is a good idea, right?
// or, is only for the client better? Turned out to be the case somewhere else...
//#ifdef SERVER
//#ifdef CLIENT
//SAVE_STATE(pl.w_attack_next);
//SAVE_STATE(pl.w_attack_akimbo_next);
//#endif
@ -421,6 +428,18 @@ BOOL
weapon_shotgun_onInterrupt(
player pl, weapondata_basic_t* basePRef, weapondynamic_t arg_thisWeapon
){
if(pl.shotgunReloadIndex == 0){
// not reloading, nothing to interrupt.
return FALSE;
}
if(pl.shotgunReloadIndex == 1 || pl.shotgunReloadIndex == 2){
// pre-reload or shell-load sequences? Going to the end instead next time.
pl.shotgunReloadIndex = 3;
}
/*
if(pl.shotgunReloadIndex == 0){
// nothing to interrupt.
return FALSE;
@ -436,6 +455,7 @@ weapon_shotgun_onInterrupt(
pl.shotgunReloadIndexQueued = 3;
}
//}
*/
return TRUE;
}// weapon_shotgun_onInterrupt
@ -492,7 +512,6 @@ weapon_shotgun_reload(
}
pl.isChangingIronsight = FALSE;
SAVE_STATE(pl.isChangingIronsight);
pl.currentZoomChoice = -1;
pl.setZoom(1.00f);
pl.aryNextBurstShotTime_softLength = 0;
@ -503,7 +522,6 @@ weapon_shotgun_reload(
//printfline("weapon_shotgun_reload %i %d", pl.shotgunReloadIndex, pl.shotgunPumpEndTime);
pl.isReloading = TRUE;
pl.shotgunReloadIndex = 1;
//printfline("HERES THAT shotgunReload1_Duration %.2f", pl.shotgunReload1_Duration);
weapon_base_setWholeAttackDelay(pl, pl.shotgunReload1_Duration);
@ -511,11 +529,21 @@ weapon_shotgun_reload(
pl.shotgunReloadIndexQueued = 2;
TS_Weapons_ViewAnimation(pl.shotgunReload1_seq, pl.shotgunReload1_Duration );
pl.shotgunReloadIndex = 1;
}//weapon_shotgun_reload
#ifdef CLIENT
void viewEv_playShotgunInsertShellSound(void){
player pl = (player)self;
sound(pl, CHAN_AUTO, "weapons/insert-shell.wav", 1, ATTN_NONE);
}
#endif
// NOTICE - shotguns with typical shotgun reload logic should use this method at all
// times. It includes checks for whether the shotgun is actually reloading or not
// (don't do anything if not of course)
@ -525,103 +553,99 @@ weapon_shotgun_onThink_reloadLogic(player pl, weapondata_gun_t* basePRef, weapon
//printfline("FRAME att: %.2f", pl.w_attack_next);
if(pl.shotgunReloadIndex > 0){
//reloading at all only.
if(pl.shotgunAddAmmoTime != -1 && pl.w_attack_next <= pl.shotgunAddAmmoTime){
// add the ammo!!
arg_thisWeapon.iClipLeft++;
pl.ary_ammoTotal[baseRef.iAmmoDataID] -= 1;
if(pl.w_attack_next <= 0){
//time has surpassed the time to the next phase? Check the pl.shotgunReloadIndexQueued.
pl.shotgunReloadIndex = pl.shotgunReloadIndexQueued;
//printfline("ack: %i", pl.shotgunReloadIndex);
if(pl.shotgunReloadIndex == 0){
//little bit of cleanup, since we're done reloading.
pl.isReloading = FALSE;
//printfline("shotgunWaitingForPump go BYEBYE 1");
//if we were waiting for a pump, stop now. the anim did a pump by this point.
pl.shotgunWaitingForPump = FALSE;
//NOTICE - an index of 0 should not be possible, we move away from it always.
}else if(pl.shotgunReloadIndex == 2){
//time to plug the bullets in
if( arg_thisWeapon.iClipLeft >= baseRef.iClipMax || pl.ary_ammoTotal[baseRef.iAmmoDataID] <= 0 ){
pl.shotgunReloadIndex = 3;
TS_Weapons_ViewAnimation(pl.shotgunReload3_seq, pl.shotgunReload3_Duration);
weapon_base_setWholeAttackDelay(pl, pl.shotgunReload3_Duration);
pl.shotgunReloadIndexQueued = 0;
}else{
// if we still have ammo left in the reserve,
// AND the clip is not full, repeat, going to reload again.
TS_Weapons_ViewAnimation(pl.shotgunReload2_seq, pl.shotgunReload2_Duration);
pl.shotgunReloadIndex = 2;
weapon_base_setWholeAttackDelay(pl, pl.shotgunReload2_Duration);
pl.shotgunReloadIndexQueued = 2;
// 2.0 - 0.3 = 1.7
// idea: set shotgunAddAmmoTime to the w_attack_next (total duration of the anim) minus ammoLoadDelay,
// since w_attack_next counts down. When w_attack_next goes below shotgunAddAmmoTime, that means
// the "shotgunReload2_ammoLoadDelay" amount of time has passed, same thing, better for networking.
//// pl.shotgunAddAmmoTime = time + pl.shotgunReload2_ammoLoadDelay;
pl.shotgunAddAmmoTime = pl.w_attack_next - pl.shotgunReload2_ammoLoadDelay;
pl.shotgunAddAmmoSoundTime = time + pl.shotgunReload2_ammoLoadDelay - 0.03f;
}
}else if(pl.shotgunReloadIndex == 3){
//end anim
TS_Weapons_ViewAnimation(pl.shotgunReload3_seq, pl.shotgunReload3_Duration);
weapon_base_setWholeAttackDelay(pl, pl.shotgunReload3_Duration);
pl.shotgunReloadIndexQueued = 0;
}
}// w_attack_next <= 0
printfline("I ADDED AMMO TO SHOTGUN. %i - %i", arg_thisWeapon.iClipLeft, pl.ary_ammoTotal[baseRef.iAmmoDataID]);
if(pl.shotgunReloadIndex == 2){
////if(pl.shotgunAddAmmoTime != -1 && time >= pl.shotgunAddAmmoTime){
if(pl.shotgunAddAmmoTime != -1 && pl.w_attack_next <= pl.shotgunAddAmmoTime){
//add the ammo!!
arg_thisWeapon.iClipLeft++;
pl.ary_ammoTotal[baseRef.iAmmoDataID] -= 1;
#ifdef CLIENT
sound(pl, CHAN_ITEM, "weapons/insert-shell.wav", 1, ATTN_NONE);
#endif
pl.shotgunAddAmmoTime = -1; //don't keep doing it.
}
if(pl.shotgunAddAmmoSoundTime != -1 && time >= pl.shotgunAddAmmoSoundTime){
//TS_PlayInsertShellSound(pl);
pl.shotgunAddAmmoSoundTime = -1;
}
}
pl.shotgunAddAmmoTime = -1; //don't keep doing it.
}
if(pl.w_attack_next <= 0){
// little copy from base think logic, since we're replacing it for shotguns.
if(pl.isChangingIronsight){
weapon_gun_endOfIronSight(pl, basePRef, arg_thisWeapon);
}
if(pl.shotgunAddAmmoSoundTime != -1 && pl.w_attack_next <= pl.shotgunAddAmmoSoundTime){
//TS_PlayInsertShellSound(pl);
//TS_Weapons_PlaySoundChannelDirect(pl, "weapons/insert-shell.wav", CHAN_AUTO);
// TODO: if you want other players to hear this, the server should play it for all players
// except the localone here because it already played clientside, again with a delay would be
// pointless for the one that already heard it.
/*
#ifdef CLIENT
sound(pl, CHAN_AUTO, "weapons/insert-shell.wav", 1, ATTN_NONE);
#endif
*/
pl.shotgunAddAmmoSoundTime = -1;
}
if(pl.w_attack_next > 0.0){
return;
}
// in case this weapon is ironsight.
if(pl.isChangingIronsight){
weapon_gun_endOfIronSight(pl, basePRef, arg_thisWeapon);
return;
}
if(pl.shotgunReloadIndex == 0){
// nothing to do here
}else if(pl.shotgunReloadIndex == 1 || pl.shotgunReloadIndex == 2){
// end of pre-reload anim (bringing the shotgun into place) or a shell-load anim.
// Same thing wanted in either case: start another shell-load anim
printfline("w_attack_next pass!!!");
if (pl.ary_ammoTotal[baseRef.iAmmoDataID] <= 0 || arg_thisWeapon.iClipLeft >= baseRef.iClipMax) {
//pl.shotgunReloadIndex = 3;
//if(pl.shotgunAddAmmoTime_canSet()){
// pl.shotgunAddAmmoTime_setCooldownSetTime();
TS_Weapons_ViewAnimation(pl.shotgunReload3_seq, pl.shotgunReload3_Duration);
weapon_base_setWholeAttackDelay(pl, pl.shotgunReload3_Duration);
pl.shotgunReloadIndex = 0;
pl.isReloading = FALSE;
//}
}else{
TS_Weapons_ViewAnimation(pl.shotgunReload2_seq, pl.shotgunReload2_Duration);
weapon_base_setWholeAttackDelay(pl, pl.shotgunReload2_Duration);
pl.shotgunReloadIndex = 2;
//if(pl.shotgunAddAmmoTime_canSet()){
// pl.shotgunAddAmmoTime_setCooldownSetTime();
printfline("I SET shotgunAddAmmoTime!");
//View_AddEvent(w_ejectshell_pistol, pl.w_attack_next - pl.shotgunReload2_ammoLoadDelay);
#ifdef CLIENT
View_AddEvent(viewEv_playShotgunInsertShellSound, pl.shotgunReload2_Duration - (pl.shotgunReload2_ammoLoadDelay - 0.03f));
#endif
pl.shotgunAddAmmoTime = pl.shotgunReload2_Duration - pl.shotgunReload2_ammoLoadDelay;
//pl.shotgunAddAmmoSoundTime = pl.shotgunReload2_Duration - (pl.shotgunReload2_ammoLoadDelay - 0.03f);
//}
//arg_thisWeapon.iClipLeft++;
//pl.ary_ammoTotal[baseRef.iAmmoDataID]--;
}
}else if(pl.shotgunReloadIndex == 3){
// end of reload anim wanted!
TS_Weapons_ViewAnimation(pl.shotgunReload3_seq, pl.shotgunReload3_Duration);
weapon_base_setWholeAttackDelay(pl, pl.shotgunReload3_Duration);
pl.shotgunReloadIndex = 0;
// this will be true when the fire delay expires, but doesn't hurt happening earlier.
pl.isReloading = FALSE;
}
}//weapon_shotgun_onThink_reloadLogic
@ -1143,7 +1167,6 @@ weapon_ironsight_ToggleIronsight(
printfline("time: %.2f weapon_ironsight_ToggleIronsight PASS. CURRENT:%i", time, arg_thisWeapon.iIronSight);
pl.isChangingIronsight = TRUE;
SAVE_STATE(pl.isChangingIronsight);
//TAGGG - QUESTION.
// Why does only from ironSight == 0, going towards 1, use the "_EndIdle" version, but
@ -1202,7 +1225,6 @@ weapon_gun_Reload(
}
pl.isChangingIronsight = FALSE;
SAVE_STATE(pl.isChangingIronsight);
pl.currentZoomChoice = -1;
pl.setZoom(1.00f);
pl.aryNextBurstShotTime_softLength = 0;
@ -1247,7 +1269,6 @@ weapon_gun_Reload_CustomSequence(
}
pl.isChangingIronsight = FALSE;
SAVE_STATE(pl.isChangingIronsight);
pl.currentZoomChoice = -1;
pl.setZoom(1.00f);
pl.aryNextBurstShotTime_softLength = 0;
@ -1295,7 +1316,6 @@ weapon_ironsight_Reload(
}
pl.isChangingIronsight = FALSE;
SAVE_STATE(pl.isChangingIronsight);
pl.currentZoomChoice = -1;
pl.setZoom(1.00f);
pl.aryNextBurstShotTime_softLength = 0;
@ -1377,7 +1397,6 @@ weapon_gun_endOfIronSight(
}
pl.isChangingIronsight = FALSE;
SAVE_STATE(pl.isChangingIronsight);
}

View file

@ -167,7 +167,6 @@ w_benellim3_holster(void)
void
w_benellim3_primary(void)
{
float randomChoice;
player pl = (player)self;
weapondynamic_t arg_thisWeapon = pl.ary_myWeapons[pl.inventoryEquippedIndex];
@ -178,11 +177,13 @@ w_benellim3_primary(void)
return;
}
// good place? should this go above onInterrupt above?
if (pl.w_attack_next > 0.0) {
return;
}
if(arg_thisWeapon.iFireMode == BITS_FIREMODE_SEMI){
INPUT_PRIMARY_TAP_GATE
}
@ -200,8 +201,10 @@ w_benellim3_primary(void)
View_AddEvent(w_ejectshell_pistol, 0.0f);
#endif
randomChoice = random();
if(randomChoice > 0.5){
// float randomChoice = random();
// why the cast to float here? No idea
int r = (float)input_sequence % 2;
if(r == 0){
TS_Weapons_ViewAnimation(weaponseq_benellim3::pump, 29.0f/35.0f);
}else{
TS_Weapons_ViewAnimation(weaponseq_benellim3::pump2, 25.0f/35.0f);

View file

@ -180,7 +180,6 @@ w_mossberg500_holster(void)
void
w_mossberg500_primary(void)
{
float randomChoice;
player pl = (player)self;
weapondynamic_t arg_thisWeapon = pl.ary_myWeapons[pl.inventoryEquippedIndex];
@ -219,8 +218,8 @@ w_mossberg500_primary(void)
if(!arg_thisWeapon.iIronSight){
TS_Weapons_ViewAnimation(weaponseq_mossberg500::pump, 31.0f/35.0f);
}else{
randomChoice = random();
if(randomChoice > 0.5){
int r = (float)input_sequence % 2;
if(r == 0){
TS_Weapons_ViewAnimation(weaponseq_mossberg500::pumpb, 31.0f/35.0f);
}else{
TS_Weapons_ViewAnimation(weaponseq_mossberg500::pumpb2, 31.0f/35.0f);

View file

@ -203,8 +203,8 @@ w_spas12_primary(void)
View_AddEvent(w_ejectshell_pistol, 0.0f);
#endif
randomChoice = random();
if(randomChoice > 0.5){
int r = (float)input_sequence % 2;
if(r == 0){
TS_Weapons_ViewAnimation(weaponseq_spas12::pump, 31.0f/35.0f);
}else{
TS_Weapons_ViewAnimation(weaponseq_spas12::pump2, 31.0f/35.0f);