class NiceMedicGun extends NiceWeapon abstract; var const float maxMedicCharge; var float medicChargeRegenRate; // This variable is dictated by client. var float medicCharge; // Medic charge is replicated on server via these periods var float medicChargeUpdatePeriod; // This variable is only relevant on a server, to predict current medic charge in-between new updates var float lastMedicChargeServerUpdate; // This variable is only relevant on a client, to predict current medic charge in-between weapon ticks var float lastMedicChargeClientUpdate; replication{ reliable if(Role < ROLE_Authority) ServerSetMedicCharge; reliable if(Role == ROLE_Authority) ClientSetMedicCharge, ClientSuccessfulHeal; } function NicePlainData.Data GetNiceData(){ local NicePlainData.Data transferData; transferData = super.GetNiceData(); class'NicePlainData'.static.SetFloat(transferData, "MedicCharge", GetCurrentMedicCharge()); class'NicePlainData'.static.SetFloat(transferData, "MedicChargeUpd", Level.TimeSeconds); return transferData; } function SetNiceData(NicePlainData.Data transferData, optional NiceHumanPawn newOwner){ super.SetNiceData(transferData, newOwner); medicCharge = class'NicePlainData'.static.GetFloat(transferData, "MedicCharge", 0.0); lastMedicChargeServerUpdate = class'NicePlainData'.static.GetFloat(transferData, "MedicChargeUpd", -1.0); if(lastMedicChargeServerUpdate >= 0.0) medicCharge += (Level.TimeSeconds - lastMedicChargeServerUpdate) * medicChargeRegenRate; lastMedicChargeServerUpdate = Level.TimeSeconds; ClientSetMedicCharge(medicCharge); } function ServerSetMedicCharge(float newCharge){ medicCharge = newCharge; lastMedicChargeServerUpdate = Level.TimeSeconds; } simulated function ClientSetMedicCharge(float newCharge){ medicCharge = newCharge; } // Returns current medic charge // Uses prediction a server simulated function float GetCurrentMedicCharge(){ if(Role < ROLE_Authority) return medicCharge; else return medicCharge + (Level.TimeSeconds - lastMedicChargeServerUpdate) * medicChargeRegenRate; } simulated function WeaponTick(float dt){ local int prevPeriodsAmount; local bool bWasBelowMax; if(Role < ROLE_Authority){ // Remember the old state bWasBelowMax = (medicCharge < maxMedicCharge); prevPeriodsAmount = Ceil(medicCharge / medicChargeUpdatePeriod); // Update medic charge medicCharge += (Level.TimeSeconds - lastMedicChargeClientUpdate) * medicChargeRegenRate; lastMedicChargeClientUpdate = Level.TimeSeconds; medicCharge = FMin(medicCharge, maxMedicCharge); secondaryCharge = Ceil(medicCharge); // Replicate to server when necessary if( (bWasBelowMax && medicCharge >= maxMedicCharge) || prevPeriodsAmount < Ceil(medicCharge / medicChargeUpdatePeriod) ) ServerSetMedicCharge(medicCharge); } super.WeaponTick(dt); } simulated function ClientSuccessfulHeal( NiceHumanPawn healer, NiceHumanPawn healed ){ if(healed == none) { return; } if(instigator != none && PlayerController(instigator.controller) != none) { PlayerController(instigator.controller).ClientMessage( "You've healed" @ healed.GetPlayerName(), 'CriticalEvent'); } } defaultproperties { maxMedicCharge=100.000000 medicChargeRegenRate=10.000000 medicChargeUpdatePeriod=10.000000 bShowSecondaryCharge=True SecondaryCharge=0 bChangeSecondaryIcon=True hudSecondaryTexture=Texture'KillingFloorHUD.HUD.Hud_Syringe' activeSlowdown=0.750000 activeSpeedup=2.000000 }