Change explosives mechanics

This commit is contained in:
Anton Tarasenko 2024-04-23 23:24:11 +07:00
parent 08c7d99de9
commit e79d49ce0d
6 changed files with 65 additions and 123 deletions

View File

@ -71,6 +71,7 @@ simulated function CalculateDamageScales( out float scale1, out float scale2,
local Vector victimPoint1, victimPoint2; local Vector victimPoint1, victimPoint2;
local float swap; local float swap;
victimPoint1 = victim.location; victimPoint1 = victim.location;
victimPoint2.z += victim.CollisionHeight * 0.25;
victimPoint2 = victim.location; victimPoint2 = victim.location;
victimPoint2.z += victim.CollisionHeight * 0.75; victimPoint2.z += victim.CollisionHeight * 0.75;
scale1 = GetDamageScale(victim, explosionLocation, victimPoint1, scale1 = GetDamageScale(victim, explosionLocation, victimPoint1,
@ -93,9 +94,9 @@ simulated function ServerExplode
float momentum, float momentum,
Vector explLocation, Vector explLocation,
Pawn instigator, Pawn instigator,
optional bool allowDoubleExplosion,
optional Actor explosionTarget, optional Actor explosionTarget,
optional vector explosiveDirection optional vector explosiveDirection,
optional bool preventProximityHeadDamage
){ ){
local Actor victim; local Actor victim;
local int numKilled; local int numKilled;
@ -109,26 +110,33 @@ simulated function ServerExplode
if(victim.role < ROLE_Authority) continue; if(victim.role < ROLE_Authority) continue;
if(ExtendedZCollision(victim) != none) continue; if(ExtendedZCollision(victim) != none) continue;
if(Trigger(victim) != none) continue; if(Trigger(victim) != none) continue;
niceVictim = NiceMonster(victim);
dirToVictim = Normal(victim.location - explLocation); dirToVictim = Normal(victim.location - explLocation);
hitLocation = victim.location - 0.5 * hitLocation = victim.location - 0.5 *
(victim.collisionHeight + victim.collisionRadius) * dirToVictim; (victim.collisionHeight + victim.collisionRadius) * dirToVictim;
CalculateDamageScales( scale1, scale2, CalculateDamageScales( scale1, scale2,
victim, explLocation, explRadius, explExp); 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 // Deal main damage
if(scale1 > 0){ if(scale1 > 0 || scale2 > 0) {
ServerDealDamage( victim, explDamage * scale1, instigator, ServerDealDamage(
hitLocation, scale1 * momentum * dirToVictim, victim,
explDmgType); explDamage * FMax(scale1, scale2),
instigator,
hitLocation,
FMax(scale1, scale2) * momentum * dirToVictim,
explDmgType);
} }
// Deal secondary damage if(niceVictim != none) {
if(allowDoubleExplosion && victim != none && scale2 > 0){ if (niceVictim.health <= 0) {
ServerDealDamage( victim, explDamage * scale2, instigator,
hitLocation, scale2 * momentum * dirToVictim,
explDmgType);
}
niceVictim = NiceMonster(victim);
if(NiceMonster(victim) != none) {
if (NiceMonster(victim).health <= 0) {
numKilled += 1; numKilled += 1;
} }
else { else {

View File

@ -128,7 +128,7 @@ function bool PreventDeath(Pawn Killed, Controller Killer, class<DamageType> dam
class'NiceSkillDemoReactiveArmor'.default.explExponent, class'NiceSkillDemoReactiveArmor'.default.explExponent,
class'NiceDamTypeDemoSafeExplosion', class'NiceDamTypeDemoSafeExplosion',
class'NiceSkillDemoReactiveArmor'.default.explMomentum, class'NiceSkillDemoReactiveArmor'.default.explMomentum,
killed.location, killed, true killed.location, killed
); );
return true; return true;
} }

View File

@ -28,9 +28,9 @@ static function Explode(
bullet.charExplosionMomentum, bullet.charExplosionMomentum,
hitLocation, hitLocation,
bullet.instigator, bullet.instigator,
true,
explosionTarget, explosionTarget,
Vector(bullet.Rotation) Vector(bullet.Rotation),
bullet.bStuck
); );
if (KFMonster(bullet.base) != none && bullet.bStuck && bullet.bStuckToHead) { if (KFMonster(bullet.base) != none && bullet.bStuck && bullet.bStuckToHead) {

View File

@ -19,7 +19,7 @@ defaultproperties
StereoFireSoundRef="KF_LAWSnd.LAW_FireST" StereoFireSoundRef="KF_LAWSnd.LAW_FireST"
NoAmmoSoundRef="KF_LAWSnd.LAW_DryFire" NoAmmoSoundRef="KF_LAWSnd.LAW_DryFire"
DamageType=class'NiceDamTypeLAWBlunt' DamageType=class'NiceDamTypeLAWBlunt'
DamageMax=750 DamageMax=350
bSplashDamage=True bSplashDamage=True
bRecommendSplashDamage=True bRecommendSplashDamage=True
bWaitForRelease=True bWaitForRelease=True

View File

@ -39,114 +39,32 @@ function TakeDamage(int Damage, Pawn InstigatedBy, Vector HitLocation, Vector Mo
Explode(HitLocation, vect(0,0,1)); Explode(HitLocation, vect(0,0,1));
} }
} }
simulated function HurtRadius( float DamageAmount, float DamageRadius, class<DamageType> DamageType, float Momentum, vector HitLocation )
{
local actor Victims;
local float damageScale, dist;
local vector dir;
local int NumKilled;
local KFMonster KFMonsterVictim;
local bool bMonster;
local Pawn P;
local KFPawn KFP;
local array<Pawn> CheckedPawns;
local int i;
local bool bAlreadyChecked;
local SRStatsBase Stats;
if ( bHurtEntry ) simulated function HurtRadius(
return; float damageAmount,
bHurtEntry = true; float damageRadius,
class<DamageType> damageType,
float momentum,
Vector hitLocation
) {
local NicePlayerController niceController;
local NiceReplicationInfo niceRI;
if( Role == ROLE_Authority && Instigator != none && Instigator.PlayerReplicationInfo != none ) if (instigator == none) return;
Stats = SRStatsBase(Instigator.PlayerReplicationInfo.SteamStatsAndAchievements); niceController = NicePlayerController(instigator.controller);
if (niceController == none) return;
niceRI = niceController.niceRI;
if (niceRI == none) return;
foreach CollidingActors (class 'Actor', Victims, DamageRadius, HitLocation) Destroy();
{
P = none;
KFMonsterVictim = none;
bMonster = false;
KFP = none;
bAlreadyChecked = false;
// don't let blast damage affect fluid - VisibleCollisingActors doesn't really work for them - jag niceRI.ServerExplode(damageAmount,
if( (Victims != self) && (Hurtwall != Victims) && (Victims.Role == ROLE_Authority) && !Victims.IsA('FluidSurfaceInfo') damageRadius,
&& ExtendedZCollision(Victims)==None ) 1.0,
{ niceExplosiveDamage,
if( (Instigator==None || Instigator.Health<=0) && KFPawn(Victims)!=None ) momentum,
Continue; hitLocation,
dir = Victims.Location - HitLocation; instigator);
dist = FMax(1,VSize(dir));
dir = dir/dist;
damageScale = 1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius);
if ( Instigator == None || Instigator.Controller == None )
{
Victims.SetDelayedDamageInstigatorController( InstigatorController );
}
P = Pawn(Victims);
if( P != none ) {
for (i = 0; i < CheckedPawns.Length; i++) {
if (CheckedPawns[i] == P) {
bAlreadyChecked = true;
break;
}
}
if( bAlreadyChecked )
continue;
CheckedPawns[CheckedPawns.Length] = P;
KFMonsterVictim = KFMonster(Victims);
if( KFMonsterVictim != none && KFMonsterVictim.Health <= 0 )
KFMonsterVictim = none;
KFP = KFPawn(Victims);
if( KFMonsterVictim != none ) {
damageScale *= KFMonsterVictim.GetExposureTo(Location + 15 * -Normal(PhysicsVolume.Gravity));
bMonster = true; // in case TakeDamage() and further Die() deletes the monster
}
else if( KFP != none ) {
damageScale *= KFP.GetExposureTo(Location + 15 * -Normal(PhysicsVolume.Gravity));
}
if ( damageScale <= 0)
continue;
}
if(NiceMonster(Victims) != none)
Victims.TakeDamage(damageScale * DamageAmount,Instigator,Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dir
,(damageScale * Momentum * dir), niceExplosiveDamage);
else
Victims.TakeDamage(damageScale * DamageAmount,Instigator,Victims.Location - 0.5 * (Victims.CollisionHeight + Victims.CollisionRadius) * dir
,(damageScale * Momentum * dir), DamageType);
if( bMonster && (KFMonsterVictim == none || KFMonsterVictim.Health < 1) ) {
NumKilled++;
}
if (Vehicle(Victims) != None && Vehicle(Victims).Health > 0)
{
Vehicle(Victims).DriverRadiusDamage(DamageAmount, DamageRadius, InstigatorController, DamageType, Momentum, HitLocation);
}
}
}
if( Role == ROLE_Authority )
{
if ( bBlewInHands && NumKilled >= 5 && Stats != none )
class'ScrnAchievements'.static.ProgressAchievementByID(Stats.Rep, 'SuicideBomber', 1);
if ( NumKilled >= 4 )
{
KFGameType(Level.Game).DramaticEvent(0.05);
}
else if ( NumKilled >= 2 )
{
KFGameType(Level.Game).DramaticEvent(0.03);
}
}
bHurtEntry = false;
} }
// Overridden to spawn different AvoidMarker // Overridden to spawn different AvoidMarker
simulated function HitWall( vector HitNormal, actor Wall ){ simulated function HitWall( vector HitNormal, actor Wall ){

View File

@ -681,6 +681,22 @@ simulated function float IsHeadshotClient( Vector Loc,
return 1.0 - (distance / (headRadius * headScale * additionalScale)); return 1.0 - (distance / (headRadius * headScale * additionalScale));
return 0.0; return 0.0;
} }
// Calculates distance from `location` to this zed's head.
simulated function float GetDistanceToHead(Vector location) {
local Coords headBoneCoords;
local Vector headLocation;
local Vector AToLineOrig;
local Vector lineDir;
if(headBone == '') {
return 0.0;
}
headBoneCoords = GetBoneCoords(headBone);
headLocation =
headBoneCoords.Origin + headHeight * headScale * headBoneCoords.XAxis;
return VSize(location - headLocation);
}
// In case of a future modifications: // In case of a future modifications:
// check if it's a player doing damage before relying on it // check if it's a player doing damage before relying on it
function ModDamage( out int damage, function ModDamage( out int damage,