public static void SharedUpdateCurrentWeapon( ICharacter character, WeaponState state, double deltaTime) { var protoWeapon = state.ActiveProtoWeapon; if (protoWeapon == null) { return; } if (state.CooldownSecondsRemains > 0) { // decrease cooldown state.CooldownSecondsRemains -= deltaTime; } WeaponAmmoSystem.SharedUpdateReloading(state, character, deltaTime); if (Api.IsServer && !character.ServerIsOnline && state.SharedGetInputIsFiring()) { state.SharedSetInputIsFiring(false); } // check ammo (if applicable to this weapon prototype) var canFire = state.WeaponReloadingState == null && protoWeapon.SharedCanFire(character, state); if (state.CooldownSecondsRemains > 0) { // firing cooldown is not completed if (!state.SharedGetInputIsFiring() && state.IsEventWeaponStartSent) { // not firing anymore SharedCallOnWeaponInputStop(state, character); } return; } var wasFiring = state.IsFiring; if (!state.IsFiring) { state.IsFiring = state.SharedGetInputIsFiring(); } else // if IsFiring { if (!SharedShouldFireMore(state)) { state.IsFiring = state.SharedGetInputIsFiring(); } } if (!canFire) { // cannot fire (no ammo, etc) state.IsFiring = false; } if (!state.IsFiring) { if (wasFiring) { // just stopped firing SharedCallOnWeaponFinished(state, character); } // the character is not firing // reset delay for the next shot (it will be set when firing starts next time) state.DamageApplyDelaySecondsRemains = 0; return; } // let's process what happens when we're in the firing mode if (!state.IsEventWeaponStartSent) { // started firing SharedCallOnWeaponStart(state, character); } if (state.DamageApplyDelaySecondsRemains <= 0) { // initialize delay to next shot state.DamageApplyDelaySecondsRemains = protoWeapon.DamageApplyDelay; SharedCallOnWeaponShot(character, protoWeapon); } // decrease the remaining time to the damage application state.DamageApplyDelaySecondsRemains -= deltaTime; if (state.DamageApplyDelaySecondsRemains > 0) { // firing delay not completed return; } // firing delay completed state.ShotsDone++; //Logger.Dev("Weapon fired, shots done: " + state.ShotsDone); SharedFireWeapon(character, state.ActiveItemWeapon, protoWeapon, state); state.CooldownSecondsRemains += protoWeapon.FireInterval - protoWeapon.DamageApplyDelay; if (!protoWeapon.IsLoopedAttackAnimation) { // we don't want to stuck this animation in the last frame // that's fix for the issue: // "Fix extended animation "stuck" issue for mobs (like limbs stuck in the end position and movement animation appears broken)" state.IsEventWeaponStartSent = false; } }
public static void SharedUpdateCurrentWeapon( ICharacter character, WeaponState state, double deltaTime) { var protoWeapon = state.ProtoWeapon; if (protoWeapon == null) { return; } if (deltaTime > 0.4) { // too large delta time probably due to a frame skip deltaTime = 0.4; } if (state.CooldownSecondsRemains > 0) { state.CooldownSecondsRemains -= deltaTime; if (state.CooldownSecondsRemains < -0.2) { // clamp the remaining cooldown in case of a frame skip state.CooldownSecondsRemains = -0.2; } } if (state.ReadySecondsRemains > 0) { state.ReadySecondsRemains -= deltaTime; } if (state.FirePatternCooldownSecondsRemains > 0) { state.FirePatternCooldownSecondsRemains -= deltaTime; if (state.FirePatternCooldownSecondsRemains <= 0) { state.FirePatternCurrentShotNumber = 0; } } // TODO: restore this condition when we redo UI countdown animation for ViewModelHotbarItemWeaponOverlayControl.ReloadDurationSeconds //if (state.CooldownSecondsRemains <= 0) //{ WeaponAmmoSystem.SharedUpdateReloading(state, character, deltaTime); //} if (Api.IsServer && !character.ServerIsOnline && state.SharedGetInputIsFiring()) { state.SharedSetInputIsFiring(false); } // check ammo (if applicable to this weapon prototype) var canFire = (Api.IsClient || character.ServerIsOnline) && state.WeaponReloadingState is null && protoWeapon.SharedCanFire(character, state); if (state.CooldownSecondsRemains > 0) { // firing cooldown is not completed if (!state.SharedGetInputIsFiring() && state.IsEventWeaponStartSent) { // not firing anymore SharedCallOnWeaponInputStop(state, character); } return; } var wasFiring = state.IsFiring; if (!state.IsFiring) { state.IsFiring = state.SharedGetInputIsFiring(); } else // if IsFiring { if (!SharedShouldFireMore(state)) { state.IsFiring = state.SharedGetInputIsFiring(); } } if (!canFire) { // cannot fire (no ammo, etc) state.IsFiring = false; } if (!state.IsFiring) { if (wasFiring) { // just stopped firing SharedCallOnWeaponFinished(state, character); } // the character is not firing // reset delay for the next shot (it will be set when firing starts next time) state.DamageApplyDelaySecondsRemains = 0; return; } if (state.WeaponCache is null) { SharedRebuildWeaponCache(character, state); } // let's process what happens when we're in the firing mode if (!state.IsEventWeaponStartSent) { // started firing SharedCallOnWeaponStart(state, character); } if (state.DamageApplyDelaySecondsRemains <= 0) { // initialize delay to next shot state.DamageApplyDelaySecondsRemains = Shared.RoundDurationByServerFrameDuration(protoWeapon.DamageApplyDelay); SharedCallOnWeaponShot(character, protoWeapon); } // decrease the remaining time to the damage application state.DamageApplyDelaySecondsRemains -= deltaTime; if (state.DamageApplyDelaySecondsRemains > 0) { // firing delay not completed return; } // firing delay completed state.ShotsDone++; //Logger.Dev("Weapon fired, shots done: " + state.ShotsDone); SharedFireWeapon(character, state.ItemWeapon, protoWeapon, state); var cooldownDuration = Shared.RoundDurationByServerFrameDuration(protoWeapon.FireInterval) - Shared.RoundDurationByServerFrameDuration(protoWeapon.DamageApplyDelay); //Logger.Dev($"Cooldown adding: {cooldownDuration} for {protoWeapon}"); state.CooldownSecondsRemains += cooldownDuration; if (!protoWeapon.IsLoopedAttackAnimation) { // we don't want to stuck this animation in the last frame // that's fix for the issue: // "Fix extended animation "stuck" issue for mobs (like limbs stuck in the end position and movement animation appears broken)" state.IsEventWeaponStartSent = false; } }