NicePack/sources/NiceReplicationInfo.uc

490 lines
18 KiB
Ucode

//==============================================================================
// NicePack / NiceReplicationInfo
//==============================================================================
// Manages sending messages from clients to server.
//==============================================================================
// 'Nice pack' source
// Do whatever the fuck you want with it
// Author: dkanus
// E-mail: dkanus@gmail.com
//==============================================================================
class NiceReplicationInfo extends ReplicationInfo
dependson(NiceBullet);
var NicePack Mut;
replication{
reliable if(Role < ROLE_Authority)
ServerDamagePawn, ServerDealDamage, ServerDealMeleeDamage,
ServerUpdateHit, ServerExplode, ServerJunkieExtension,
ServerStickProjectile, ServerHealTarget;
}
// Makes server to spawn a sticked projectile.
simulated function ServerStickProjectile
(
KFHumanPawn instigator,
Actor base,
name bone,
Vector shift,
Rotator direction,
NiceBullet.ExplosionData expData
){
class'NiceProjectileSpawner'.static.
StickProjectile(instigator, base, bone, shift, direction, expData);
}
// Returns scale value that determines how to scale explosion damage to
// given victim.
// Method assumes that a valid victim was passed.
simulated function float GetDamageScale(Actor victim, Vector explosionLocation,
Vector victimPoint,
float explRadius, float explExp){
local Vector dirToVictim;
local float scale;
local float distToVictim;
local KFPawn victimKFPawn;
local KFMonster victimMonster;
dirToVictim = victimPoint - explosionLocation;
distToVictim = FMax(1.0, VSize(dirToVictim));
scale = 1 - FMax(0.0, (distToVictim - victim.collisionRadius) / explRadius);
if(scale <= 0)
scale = 0;
else
scale = scale ** explExp;
// Try scaling for exposure level (only available to monsters and KFPawns)
victimKFPawn = KFPawn(victim);
victimMonster = KFMonster(victim);
if(victimKFPawn != none && victimKFPawn.health <= 0)
scale *= victimKFPawn.GetExposureTo(explosionLocation);
else if(victimMonster != none && victimMonster.health <= 0)
scale *= victimMonster.GetExposureTo(explosionLocation);
return scale;
}
// Returns scale values that determine how to scale explosion damage to
// given victim.
// There's two scale values due to how kf1 calculated explosion damage:
// by scaling it according to distance to two different points
// (location of the victim and a point 75% of collision height higher).
// First scale will be the one with the highest number.
// Method assumes that a valid victim was passed.
simulated function CalculateDamageScales( out float scale1, out float scale2,
Actor victim,
Vector explosionLocation,
float explRadius, float explExp){
local Vector victimPoint1, victimPoint2;
local float swap;
victimPoint1 = victim.location;
victimPoint2.z += victim.CollisionHeight * 0.25;
victimPoint2 = victim.location;
victimPoint2.z += victim.CollisionHeight * 0.75;
scale1 = GetDamageScale(victim, explosionLocation, victimPoint1,
explRadius, explExp);
scale2 = GetDamageScale(victim, explosionLocation, victimPoint2,
explRadius, explExp);
if(scale1 < scale2){
swap = scale1;
scale1 = scale2;
scale2 = swap;
}
}
// Simulates an explosion on a server.
simulated function ServerExplode
(
float explDamage,
float explRadius,
float explExp,
class<NiceWeaponDamageType> explDmgType,
float momentum,
Vector explLocation,
Pawn instigator,
optional Actor explosionTarget,
optional vector explosiveDirection,
optional bool preventProximityHeadDamage
){
local Actor victim;
local int numKilled;
local Vector dirToVictim;
local Vector hitLocation;
local float scale1, scale2;
local NiceMonster niceVictim;
if(Role < ROLE_Authority) return;
foreach VisibleActors(class'Actor', victim, explRadius, explLocation){
if(victim == none || victim == self) continue;
if(victim.role < ROLE_Authority) continue;
if(ExtendedZCollision(victim) != none) continue;
if(Trigger(victim) != none) continue;
niceVictim = NiceMonster(victim);
dirToVictim = Normal(victim.location - explLocation);
hitLocation = victim.location - 0.5 *
(victim.collisionHeight + victim.collisionRadius) * dirToVictim;
CalculateDamageScales( scale1, scale2,
victim, explLocation, explRadius, explExp);
// Deal head damage if explosion is close enough to the victim's head
if ( niceVictim != none && !preventProximityHeadDamage
&& niceVictim.GetDistanceToHead(explLocation) <= explRadius * 0.1)
{
ServerDealDamage( victim, explDamage, instigator,
hitLocation, 0.0 * dirToVictim,
explDmgType, 0.5);
}
// Deal main damage
if(scale1 > 0 || scale2 > 0) {
ServerDealDamage(
victim,
explDamage * FMax(scale1, scale2),
instigator,
hitLocation,
FMax(scale1, scale2) * momentum * dirToVictim,
explDmgType);
}
if(niceVictim != none) {
if (niceVictim.health <= 0) {
numKilled += 1;
}
else {
niceVictim.concussionCountdown = 10.0;
}
}
}
if(numKilled >= 4)
KFGameType(level.game).DramaticEvent(0.05);
else if(numKilled >= 2)
KFGameType(level.game).DramaticEvent(0.03);
}
simulated function ServerDamagePawn
(
KFPawn injured,
int damage,
Pawn instigatedBy,
Vector hitLocation,
Vector momentum,
Class<DamageType> damageType,
int hitPoint
){
local array<int> hitPoints;
if(injured == none) return;
hitPoints[0] = hitPoint;
injured.ProcessLocationalDamage(damage, instigatedBy, hitLocation, momentum,
damageType, hitPoints);
}
simulated function HandleNiceHealingMechanicsAndSkills
(
NiceHumanPawn healer,
NiceHumanPawn healed,
float healPotency
){
local bool hasZEDHeavenCanceller;
local NicePlayerController nicePlayer;
if(healer == none || healed == none) return;
nicePlayer = NicePlayerController(healer.controller);
if(nicePlayer == none)
return;
if(class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillCommandoAdrenalineShot')){
healed.medicAdrenaliteTime =
class'NiceSkillCommandoAdrenalineShot'.default.boostTime;
}
if(class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillMedicSymbioticHealth')){
healer.TakeHealing(
healer,
healer.healthMax *
class'NiceSkillMedicSymbioticHealth'.default.selfBoost,
healPotency,
KFWeapon(healer.weapon));
}
hasZEDHeavenCanceller = class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillCommandoZEDHeavenCanceller');
if(nicePlayer.IsZedTimeActive() && hasZEDHeavenCanceller){
healed.health = healed.healthMax;
healed.bZedTimeInvincible = true;
}
}
simulated function RemovePoisonAndBleed(NiceHumanPawn healed)
{
local Inventory I;
// log spam fix
if (healed == none)
return;
// No poison and bleed
if (healed.inventory == none)
return;
for (I = healed.inventory; I != none; I = I.inventory)
{
if (MeanPoisonInventory(I) != none || MeanBleedInventory(I) != none)
I.Destroy();
}
}
// Tells server to heal given human pawn.
simulated function ServerHealTarget(
NiceHumanPawn healed,
float charPotency,
Pawn instigator
) {
local NiceHumanPawn healer;
local PlayerController healedPC;
local KFPlayerReplicationInfo KFPRI;
local NiceMedicGun healingTool;
local float healTotal;
local float healPotency;
if(instigator == none || healed == none) return;
if(healed.health <= 0 || healed.health >= healed.healthMax) return;
KFPRI = KFPlayerReplicationInfo(instigator.PlayerReplicationInfo);
if(KFPRI == none || KFPRI.ClientVeteranSkill == none) return;
healer = NiceHumanPawn(instigator);
if(healer == none) return;
healingTool = NiceMedicGun(healer.weapon);
healPotency = KFPRI.ClientVeteranSkill.static.GetHealPotency(KFPRI);
healTotal = charPotency * healPotency;
healer.AlphaAmount = 255;
if(healingTool != none) {
healingTool.ClientSuccessfulHeal(healer, healed);
}
healedPC = PlayerController(healed.controller);
if(healedPC != none) {
healedPC.ClientMessage(
"You've been healed by" @ healer.GetPlayerName(),
'CriticalEvent');
}
if(healed.health >= healed.healthMax) {
healed.GiveHealth(healTotal, healed.healthMax);
return;
}
HandleNiceHealingMechanicsAndSkills(healer, healed, healPotency);
if(healed.health < healed.healthMax) {
healed.TakeHealing(healed, healTotal, healPotency, healingTool);
}
RemovePoisonAndBleed(healed);
}
simulated function HandleNiceDamageMechanicsAndSkills
(
NiceMonster niceZed,
out int damage,
NiceHumanPawn nicePawn,
out Vector hitLocation,
out Vector momentum,
class<NiceWeaponDamageType> damageType,
out float headshotLevel,
out float lockonTime
){
local bool hasZEDFrenzy;
local bool hasTranquilizer;
local bool hasVorpalBlade;
local NiceMonsterController zedController;
local NicePlayerController nicePlayer;
if(niceZed == none) return;
if(nicePawn == none) return;
nicePlayer = NicePlayerController(nicePawn.controller);
if(nicePlayer == none)
return;
// Medic's skills
if(class<NiceDamTypeMedicDart>(damageType) != none){
hasTranquilizer = class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillCommandoTranquilizer');
hasZEDFrenzy = class'NiceVeterancyTypes'.static.
hasSkill(nicePlayer, class'NiceSkillMedicZEDFrenzy');
// Medic's frenzy
if(hasZEDFrenzy && nicePlayer.IsZedTimeActive()){
niceZed.madnessCountDown =
class'NiceSkillMedicZEDFrenzy'.default.madnessTime;
zedController = NiceMonsterController(niceZed.controller);
if(zedController != none)
zedController.FindNewEnemy();
}
}
// Zerker's skills
if(class<niceDamageTypeVetBerserker>(DamageType) != none){
hasVorpalBlade = class'NiceVeterancyTypes'.static.
HasSkill(nicePlayer, class'NiceSkillZerkVorpalBlade');
if( hasVorpalBlade && headshotLevel > 0.0
&& !nicePawn.IsZedExtentionsRecorded(niceZed))
damage *= class'NiceSkillZerkVorpalBlade'.default.damageBonus;
}
}
simulated function UpdateMeleeInvincibility
(
NiceMonster niceZed,
int damage,
NiceHumanPawn nicePawn,
Vector hitLocation,
Vector momentum,
class<NiceWeaponDamageType> damageType,
float headshotLevel,
bool mainTarget
){
local bool hasGunzerker;
local bool allowedInvincibility;
if(nicePawn == none) return;
if(niceZed == none) return;
allowedInvincibility = class'NiceVeterancyTypes'.static.
GetVeterancy(nicePawn.PlayerReplicationInfo) == class'NiceVetBerserker';
allowedInvincibility = allowedInvincibility || niceZed.headHealth <= 0;
if(!allowedInvincibility)
return;
// Handle non-melee cases (gunzerker-invincibility)
hasGunzerker = class'NiceVeterancyTypes'.static.
hasSkill( NicePlayerController(nicePawn.controller),
class'NiceSkillZerkGunzerker');
if(hasGunzerker && class<niceDamageTypeVetBerserker>(damageType) == none)
nicePawn.TryExtendingInv(niceZed, false, headshotLevel > 0.0);
// Handle melee-cases
if(mainTarget && class<niceDamageTypeVetBerserker>(damageType) != none)
nicePawn.TryExtendingInv(niceZed, true, headshotLevel > 0.0);
nicePawn.ApplyWeaponStats(nicePawn.weapon);
}
simulated function UpdateArdour(bool isKill, NicePlayerController nicePlayer){
local bool hasArdour;
local NiceHumanPawn nicePawn;
local float cooldownChange;
if(nicePlayer == none) return;
if(nicePlayer.abilityManager == none) return;
nicePawn = NiceHumanPawn(nicePlayer.pawn);
if(nicePawn == none)
return;
hasArdour = class'NiceVeterancyTypes'.static.
hasSkill( nicePlayer,
class'NiceSkillSharpshooterArdour');
if(!hasArdour)
return;
cooldownChange =
class'NiceSkillSharpshooterArdour'.default.
headshotKillReduction[nicePawn.calibrationScore - 1];
if(!isKill){
cooldownChange *=
class'NiceSkillSharpshooterArdour'.default.justHeadshotReduction;
}
nicePlayer.abilityManager.AddToCooldown(1, -cooldownChange);
}
// Returns 'true' if before calling it zed was alive and had a head.
simulated function bool ServerDealDamageBase
(
Actor other,
int damage,
Pawn instigatedBy,
Vector hitLocation,
Vector momentum,
class<NiceWeaponDamageType> damageType,
optional float headshotLevel,
optional float lockonTime
){
local NiceMonster niceZed;
local NiceHumanPawn nicePawn;
local NicePlayerController nicePlayer;
local bool zedWasAliveWithHead;
if(other == none) return false;
niceZed = NiceMonster(other);
nicePawn = NiceHumanPawn(InstigatedBy);
if(nicePawn != none)
nicePlayer = NicePlayerController(nicePawn.Controller);
if(niceZed == none || nicePlayer == none){
other.TakeDamage( damage, instigatedBy,
hitLocation, momentum, damageType);
return false;
}
zedWasAliveWithHead = (niceZed.health > 0.0) && (niceZed.headHealth > 0.0);
HandleNiceDamageMechanicsAndSkills( niceZed, damage, nicePawn,
hitLocation, momentum, damageType,
headshotLevel, lockonTime);
niceZed.TakeDamageClient( damage, instigatedBy, hitLocation, momentum,
damageType, headshotLevel, lockonTime);
return zedWasAliveWithHead;
}
// Tells server to damage given pawn.
simulated function ServerDealDamage
(
Actor other,
int damage,
Pawn instigatedBy,
Vector hitLocation,
Vector momentum,
class<NiceWeaponDamageType> damageType,
optional float headshotLevel,
optional float lockonTime
){
local NiceMonster niceZed;
local bool zedWasAliveWithHead;
if(headshotLevel > 0)
UpdateArdour(false, NicePlayerController(instigatedBy.controller));
zedWasAliveWithHead = ServerDealDamageBase( other, damage, instigatedBy,
hitLocation, momentum,
damageType, headshotLevel,
lockonTime);
if(!zedWasAliveWithHead)
return;
niceZed = NiceMonster(other);
if( niceZed != none
&& (niceZed.health < 0 || niceZed.headHealth < 0))
UpdateArdour(true, NicePlayerController(instigatedBy.controller));
UpdateMeleeInvincibility( niceZed, damage,
NiceHumanPawn(instigatedBy),
hitLocation, momentum, damageType,
headshotLevel, true);
}
// Tells server to damage given pawn with melee.
// Difference with 'ServerDealDamage' is that this function passes data about
// whether our target was 'main' target of melee swing
// or was hit by AOE effect.
simulated function ServerDealMeleeDamage
(
Actor other,
int damage,
Pawn instigatedBy,
Vector hitLocation,
Vector momentum,
class<NiceWeaponDamageType> damageType,
bool mainTarget,
optional float headshotLevel
){
local bool zedWasAliveWithHead;
zedWasAliveWithHead = ServerDealDamageBase( other, damage, instigatedBy,
hitLocation, momentum,
damageType, headshotLevel, 0.0);
if(!zedWasAliveWithHead)
return;
UpdateMeleeInvincibility( NiceMonster(other), damage,
NiceHumanPawn(instigatedBy),
hitLocation, momentum, damageType,
headshotLevel, mainTarget);
}
simulated function ServerUpdateHit
(
Actor tpActor,
Actor hitActor,
Vector clientHitLoc,
Vector hitNormal,
optional Vector hitLocDiff
){
local KFWeaponAttachment weapAttach;
weapAttach = KFWeaponAttachment(tpActor);
if(weapAttach != none)
weapAttach.UpdateHit(hitActor, clientHitLoc + hitLocDiff, hitNormal);
}
simulated function ServerJunkieExtension( NicePlayerController player,
bool isHeadshot){
local NiceGameType niceGame;
local class<NiceVeterancyTypes> niceVet;
if(player == none || player.bJunkieExtFailed) return;
niceGame = NiceGameType(player.Level.Game);
if(niceGame == none || !niceGame.bZEDTimeActive)
return;
niceVet = class'NiceVeterancyTypes'.static.
GetVeterancy(player.PlayerReplicationInfo);
if(niceVet == none)
return;
if(niceVet.static.hasSkill(player, class'NiceSkillSharpshooterZEDAdrenaline')){
if(!isHeadshot)
player.bJunkieExtFailed = true;
else if(Mut != none)
Mut.JunkieZedTimeExtend();
}
}
defaultproperties
{
}