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 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,
@ -93,9 +94,9 @@ simulated function ServerExplode
float momentum,
Vector explLocation,
Pawn instigator,
optional bool allowDoubleExplosion,
optional Actor explosionTarget,
optional vector explosiveDirection
optional vector explosiveDirection,
optional bool preventProximityHeadDamage
){
local Actor victim;
local int numKilled;
@ -109,26 +110,33 @@ simulated function ServerExplode
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){
ServerDealDamage( victim, explDamage * scale1, instigator,
hitLocation, scale1 * momentum * dirToVictim,
explDmgType);
if(scale1 > 0 || scale2 > 0) {
ServerDealDamage(
victim,
explDamage * FMax(scale1, scale2),
instigator,
hitLocation,
FMax(scale1, scale2) * momentum * dirToVictim,
explDmgType);
}
// Deal secondary damage
if(allowDoubleExplosion && victim != none && scale2 > 0){
ServerDealDamage( victim, explDamage * scale2, instigator,
hitLocation, scale2 * momentum * dirToVictim,
explDmgType);
}
niceVictim = NiceMonster(victim);
if(NiceMonster(victim) != none) {
if (NiceMonster(victim).health <= 0) {
if(niceVictim != none) {
if (niceVictim.health <= 0) {
numKilled += 1;
}
else {

View File

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

View File

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

View File

@ -19,7 +19,7 @@ defaultproperties
StereoFireSoundRef="KF_LAWSnd.LAW_FireST"
NoAmmoSoundRef="KF_LAWSnd.LAW_DryFire"
DamageType=class'NiceDamTypeLAWBlunt'
DamageMax=750
DamageMax=350
bSplashDamage=True
bRecommendSplashDamage=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));
}
}
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 )
return;
bHurtEntry = true;
if( Role == ROLE_Authority && Instigator != none && Instigator.PlayerReplicationInfo != none )
Stats = SRStatsBase(Instigator.PlayerReplicationInfo.SteamStatsAndAchievements);
foreach CollidingActors (class 'Actor', Victims, DamageRadius, HitLocation)
{
P = none;
KFMonsterVictim = none;
bMonster = false;
KFP = none;
bAlreadyChecked = false;
simulated function HurtRadius(
float damageAmount,
float damageRadius,
class<DamageType> damageType,
float momentum,
Vector hitLocation
) {
local NicePlayerController niceController;
local NiceReplicationInfo niceRI;
// don't let blast damage affect fluid - VisibleCollisingActors doesn't really work for them - jag
if( (Victims != self) && (Hurtwall != Victims) && (Victims.Role == ROLE_Authority) && !Victims.IsA('FluidSurfaceInfo')
&& ExtendedZCollision(Victims)==None )
{
if( (Instigator==None || Instigator.Health<=0) && KFPawn(Victims)!=None )
Continue;
dir = Victims.Location - HitLocation;
dist = FMax(1,VSize(dir));
dir = dir/dist;
damageScale = 1 - FMax(0,(dist - Victims.CollisionRadius)/DamageRadius);
if (instigator == none) return;
niceController = NicePlayerController(instigator.controller);
if (niceController == none) return;
niceRI = niceController.niceRI;
if (niceRI == none) return;
if ( Instigator == None || Instigator.Controller == None )
{
Victims.SetDelayedDamageInstigatorController( InstigatorController );
}
Destroy();
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;
niceRI.ServerExplode(damageAmount,
damageRadius,
1.0,
niceExplosiveDamage,
momentum,
hitLocation,
instigator);
}
// Overridden to spawn different AvoidMarker
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 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:
// check if it's a player doing damage before relying on it
function ModDamage( out int damage,