Jump to content

Splash Damage 2.0 script (make explosions better!)


Recommended Posts

On 10/6/2022 at 10:10 PM, Mr_Blastman said:

Any chance adding Soviet S8 and S5 rockets to script?  They are woefully undereffective against ground targets in their current non-splash state.

if you let me know the log message it will be a simple thing. I'll correct the AGM65 values and add the rockets you mention.
To find the weapon name just look for "splash damage" in your dcs.log file.

I've added also a couple of missing bombs of the Mirage F1, will soon update this 3d.

Link to comment
Share on other sites

You are right AGM-65H=AGM-65D, based on warhead weight

i had added few weapons as well ( mainly for Mirage F1) but still not sure if the value should be exactly the warhead weight or some TNT equivalence so i put 130 as it was set for D version (also added new weapons from recently shared lua) , also not sure about some weapon name as i found in log, Durandal , and i saw other one which is "BLU107B_DURANDAL" not sure they are the same

Splash_Damage_2_0_2.lua

Link to comment
Share on other sites

1 hour ago, titi69 said:

i had added few weapons as well ( mainly for Mirage F1) but still not sure if the value should be exactly the warhead weight or some TNT equivalence...

Back in June of this year I was looking into those numbers trying to figure out if they were warhead weights, TNT equivalence or something else.  Based on some searching, it appears to me that these are supposed to represent the warhead's TNT equivalence in kilograms.  

I have two back to back entries that discuss my findings.  Hope this helps.


Edited by Mistermann
  • Like 1

System Specs:

Spoiler

 💻Processor:13th Gen Intel(R) Core(TM) i9-13900K - 🧠RAM: 64GB - 🎥Video Card: NVIDIA RTX 4090 - 🥽 Display: Pimax 8kx VR Headset - 🕹️Accessories:  VKB Gunfighter III MCG Ultimate, VKB STECS Standard, Thrustmaster TPR Pedals, Simshaker JetPad, Predator HOTAS Mounts, 3D Printed Flight Button Box 

Thrustmaster TWCS Mod

 

Link to comment
Share on other sites

  • 2 weeks later...

if you change this setting in the script , you will see message when you fire weapons, note the name (name can be found also in DCS.log), after thjat you can add the weapon in the script based on IRL spec warhead weight
null

image.png


Edited by titi69
Link to comment
Share on other sites

I did change the 

["weapon_missing_mesage"] = true

When i shoot guided misille AT-6 it wrote AT-6 is missing, but it doesnt wrote anything when i shoot S-8 rockets. Does it mean the S-8 are included? If yes, then the script does not do too much, because i still need direct hit to damage something. I dont found S-8 in the list, there is only C-8 , C is actually S in azbuka so it is probably the same, but even if i increase the number from 3 to 30 still no difference, so i don't know what is wrong.

 

Link to comment
Share on other sites

it is probably added if you don't get message , only way to increase dammage is to found the name used in game , may be check in dcs.log if it appear when you fire or remove temporarly the full list of weapons in the script and you should get message for the rocket, and check the value set in the script and increase it

 


Edited by titi69
Link to comment
Share on other sites

I probably didn't restart the game or something after i did the change in the lua file, so the change did not take effect. So when i tried it again after re save the mission with ["C-8"]=30, then the different was noticable a lot.  For me the default value 3 is not enough so for now i am testing 8 and it looks fine for me. 👍

  • Like 2
Link to comment
Share on other sites

On 2/18/2022 at 1:49 PM, Toumal said:

Aaaand another update: I think I fixed the stability issue - seems like the tracked_weapons map was growing over time. I added an attribute called launchTime in the onWpnEvent function:

function onWpnEvent(event)
  if event.id == world.event.S_EVENT_SHOT then
    if event.weapon then
      local ordnance = event.weapon
      local weapon_desc = ordnance:getDesc()
      if string.find(ordnance:getTypeName(), "weapons.shells") then 
        debugMsg("event shot, but not tracking: "..ordnance:getTypeName())
        return  --we wont track these types of weapons, so exit here
      end
        
      if explTable[ordnance:getTypeName()] then
--        trigger.action.outText(ordnance:getTypeName().." found.", 10)
      else 
--        env.info(ordnance:getTypeName().." missing from Splash Damage script")
        if splash_damage_options.weapon_missing_message == true then
          trigger.action.outText(ordnance:getTypeName().." missing from Splash Damage script", 10)
          debugMsg("desc: "..mist.utils.tableShow(weapon_desc))
        end
      end
      if (weapon_desc.category ~= 0) and event.initiator then
		local launchingUnit = ordnance:getLauncher()
		local launchingCoalition
		local launchingPlayerName
		if (launchingUnit ~= nil) then
			launchingCoalition = launchingUnit:getCoalition()
			launchingPlayerName = launchingUnit:getPlayerName()
		end

        if (weapon_desc.category == 1) then
          if (weapon_desc.MissileCategory ~= 1 and weapon_desc.MissileCategory ~= 2) then
            tracked_weapons[event.weapon.id_] = { wpn = ordnance, init = event.initiator:getName(), pos = ordnance:getPoint(), dir = ordnance:getPosition().x, name = ordnance:getTypeName(), speed = ordnance:getVelocity(), cat = ordnance:getCategory(), unit = launchingUnit, coalition = launchingCoalition, player = launchingPlayerName, launchTime = timer.getTime() }
          end
        else
          tracked_weapons[event.weapon.id_] = { wpn = ordnance, init = event.initiator:getName(), pos = ordnance:getPoint(), dir = ordnance:getPosition().x, name = ordnance:getTypeName(), speed = ordnance:getVelocity(), cat = ordnance:getCategory(), unit = launchingUnit, coalition = launchingCoalition, player = launchingPlayerName, launchTime = timer.getTime() }
        end
      end
    end
  end
end

 

(Note, I also added some extra information which I use to trigger MOOSE scoring for things killed by the shockwave)

Then in the track_wpns() function, I added a bit that removes entries after 1200 seconds, no matter what.

 

function track_wpns()
--  env.info("Weapon Track Start")
  for wpn_id_, wpnData in pairs(tracked_weapons) do   
    if wpnData.wpn:isExist() then  -- just update speed, position and direction.
      wpnData.pos = wpnData.wpn:getPosition().p
      wpnData.dir = wpnData.wpn:getPosition().x
      wpnData.speed = wpnData.wpn:getVelocity()
      --wpnData.lastIP = land.getIP(wpnData.pos, wpnData.dir, 50)
    else -- wpn no longer exists, must be dead.
--      trigger.action.outText("Weapon impacted, mass of weapon warhead is " .. wpnData.exMass, 2)
      local ip = land.getIP(wpnData.pos, wpnData.dir, lookahead(wpnData.speed))  -- terrain intersection point with weapon's nose.  Only search out 20 meters though.
      local impactPoint
      if not ip then -- use last calculated IP
        impactPoint = wpnData.pos
  --        trigger.action.outText("Impact Point:\nPos X: " .. impactPoint.x .. "\nPos Z: " .. impactPoint.z, 2)
      else -- use intersection point
        impactPoint = ip
  --        trigger.action.outText("Impact Point:\nPos X: " .. impactPoint.x .. "\nPos Z: " .. impactPoint.z, 2)
      end
      --env.info("Weapon is gone") -- Got to here -- 
      --trigger.action.outText("Weapon Type was: ".. wpnData.name, 20)
      if splash_damage_options.larger_explosions == true then
          --env.info("triggered explosion size: "..getWeaponExplosive(wpnData.name))
          trigger.action.explosion(impactPoint, getWeaponExplosive(wpnData.name))
          --trigger.action.smoke(impactPoint, 0)
      end
      --if wpnData.cat == Weapon.Category.ROCKET then
        blastWave(impactPoint, splash_damage_options.blast_search_radius, wpnData.ordnance, getWeaponExplosive(wpnData.name), wpnData.unit, wpnData.coalition, wpnData.player)
      --end
      tracked_weapons[wpn_id_] = nil -- remove from tracked weapons first.
    end
	if (timer.getTime() > wpnData.launchTime + 1200) then
	  tracked_weapons[wpn_id_] = nil
	end
  end
--  env.info("Weapon Track End")
end

 

I see you expanded the blastWave function to tag the player data onto the weapons. Could you post how you updated the blastwave function to accept the extra parameters? 

 

Link to comment
Share on other sites

Sure!

 

function blastWave(_point, _radius, weapon, power, launchingUnit, launchingCoalition, launchingPlayer)
  local foundUnits = {}
  local volS = {
   id = world.VolumeType.SPHERE,
   params = {
     point = _point,
     radius = _radius
   }
  }
 
  local ifFound = function(foundObject, val)
    if foundObject:getDesc().category == Unit.Category.GROUND_UNIT and foundObject:getCategory() == Object.Category.UNIT then
      foundUnits[#foundUnits + 1] = foundObject
    end
    if foundObject:getDesc().category == Unit.Category.GROUND_UNIT then --if ground unit
      if splash_damage_options.blast_stun == true then
        --suppressUnit(foundObject, 2, weapon)
      end
    end
    if splash_damage_options.wave_explosions == true then
      local obj = foundObject
      local obj_location = obj:getPoint()
      local distance = getDistance(_point, obj_location)
      local timing = distance/500      
      if obj:isExist() then
        
        if tableHasKey(obj:getDesc(), "box") then
          local length = (obj:getDesc().box.max.x + math.abs(obj:getDesc().box.min.x))
          local height = (obj:getDesc().box.max.y + math.abs(obj:getDesc().box.min.y))
          local depth = (obj:getDesc().box.max.z + math.abs(obj:getDesc().box.min.z))
          local _length = length
          local _depth = depth
          if depth > length then 
            _length = depth 
            _depth = length
          end
          local surface_distance = distance - _depth/2 
          local scaled_power_factor = 0.006 * power + 1 --this could be reduced into the calc on the next line
          local intensity = (power * scaled_power_factor) / (4 * 3.14 * surface_distance * surface_distance )
          local surface_area = _length * height --Ideally we should roughly calculate the surface area facing the blast point, but we'll just find the largest side of the object for now
          local damage_for_surface = intensity * surface_area    
          --debugMsg(obj:getTypeName().." sa:"..surface_area.." distance:"..surface_distance.." dfs:"..damage_for_surface)
          if damage_for_surface > splash_damage_options.cascade_damage_threshold then
            local explosion_size = damage_for_surface
            if obj:getDesc().category == Unit.Category.STRUCTURE then
              explosion_size = intensity * splash_damage_options.static_damage_boost --apply an extra damage boost for static objects. should we factor in surface_area?
              --debugMsg("static obj :"..obj:getTypeName())
            end
            if explosion_size > power then explosion_size = power end --secondary explosions should not be larger than the explosion that created it
            local id = timer.scheduleFunction(explodeObject, {obj_location, distance, explosion_size, obj, launchingUnit, launchingCoalition, launchingPlayer}, timer.getTime() + timing)  --create the explosion on the object location
          end

          
        else --debugMsg(obj:getTypeName().." object does not have box property")
      end
        
    end
    
   end
    
  return true
  end

 

You will also want the explodeObject function here:

 

function explodeObject(table)
  local point = table[1]
  local distance = table[2]
  local power = table[3]
  local unit = table[4]
  local launchingUnit = table[5]
  local coalition = table[6]
  local player = table[7]
  trigger.action.explosion(point, power) 
  if (player ~= nil) then
	MyScoringInstance:DamageUnitFromSplashdamage(player, launchingUnit, coalition, unit)
  end
end

Finally in MOOSE I added this, which allows proper scoring of units destroyed by the blast wave:

function SCORING:DamageUnitFromSplashdamage(InitPlayerName, InitUnit, InitUnitCoalition, TargetUnit)
  if InitPlayerName ~= nil then -- It is a player that is hitting something
--	trigger.action.outText("InitPlayerName: "..InitPlayerName, 30)
--	trigger.action.outText("InitUnit: "..InitUnit:getName(), 30)
--	trigger.action.outText("InitUnitCoalition: "..InitUnitCoalition, 30)
--	trigger.action.outText("TargetUnit: "..TargetUnit:getName(), 30)
	local initUNIT = UNIT:FindByName(InitUnit:getName())
	if (initUNIT == nil) then
		trigger.action.outText("InitUNIT was nil", 30)
	end
    self:_AddPlayerFromUnit( InitUNIT )
    if self.Players[InitPlayerName] then -- This should normally not happen, but i'll test it anyway.
        -- A target got hit, score it.
        -- Player contains the score data from self.Players[InitPlayerName]
        local Player = self.Players[InitPlayerName]
        local TargetCategory = TargetUnit:getDesc().category
        local TargetUnitName = TargetUnit:getName()
		local TargetType = TargetUnit:getTypeName()
		local TargetUnitCategory = _SCORINGCategory[TargetCategory]
		local TargetCoalition = TargetUnit:getCoalition()
		local TargetUnitCoalition = _SCORINGCoalition[TargetCoalition]
		local TargetUnitType = TargetUnit:getTypeName()
		local TargetPlayerName = ""
		local InitCoalition = InitUnitCoalition
		local InitUnitName = "Splash Damage"
		local InitUnitCategory = "Splash Damage"
		local InitUnitType = "Splash Damage"
        -- Ensure there is a hit table per TargetCategory and TargetUnitName.
        Player.Hit[TargetCategory] = Player.Hit[TargetCategory] or {}
        Player.Hit[TargetCategory][TargetUnitName] = Player.Hit[TargetCategory][TargetUnitName] or {}
        
        -- PlayerHit contains the score counters and data per unit that was hit.
        local PlayerHit = Player.Hit[TargetCategory][TargetUnitName]
         
        PlayerHit.Score = PlayerHit.Score or 0
        PlayerHit.Penalty = PlayerHit.Penalty or 0
        PlayerHit.ScoreHit = PlayerHit.ScoreHit or 0
        PlayerHit.PenaltyHit = PlayerHit.PenaltyHit or 0
        PlayerHit.TimeStamp = PlayerHit.TimeStamp or 0
        PlayerHit.UNIT = PlayerHit.UNIT or TargetUNIT
        PlayerHit.ThreatLevel, PlayerHit.ThreatType = PlayerHit.UNIT:GetThreatLevel()

        -- Only grant hit scores if there was more than one second between the last hit.        
        if timer.getTime() - PlayerHit.TimeStamp > 1 then
          PlayerHit.TimeStamp = timer.getTime()

          local Score = 0
          
          if InitCoalition then -- A coalition object was hit.
            if InitCoalition == TargetCoalition then
              Player.Penalty = Player.Penalty + 10
              PlayerHit.Penalty = PlayerHit.Penalty + 10
              PlayerHit.PenaltyHit = PlayerHit.PenaltyHit + 1
      
--              MESSAGE
--                  :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit friendly target " .. 
--                        TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.PenaltyHit .. " times. " .. 
--                        "Penalty: -" .. PlayerHit.Penalty .. ".  Score Total:" .. Player.Score - Player.Penalty,
--                        MESSAGE.Type.Update
--                      )
--                  :ToAllIf( self:IfMessage<profanity>() and self:IfMessagesToAll() )
--                  :ToCoalitionIf( InitCoalition, self:IfMessage<profanity>() and self:IfMessagesToCoalition() )
              self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_PENALTY", 1, -10, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
            else
              Player.Score = Player.Score + 1
              PlayerHit.Score = PlayerHit.Score + 1
              PlayerHit.ScoreHit = PlayerHit.ScoreHit + 1
--              MESSAGE
--                  :NewType( self.DisplayMessagePrefix .. "Player '" .. InitPlayerName .. "' hit enemy target " .. 
--                        TargetUnitCategory .. " ( " .. TargetType .. " ) " .. PlayerHit.ScoreHit .. " times. " .. 
--                        "Score: " .. PlayerHit.Score .. ".  Score Total:" .. Player.Score - Player.Penalty,
--                        MESSAGE.Type.Update
--                      )
--                  :ToAllIf( self:IfMessage<profanity>() and self:IfMessagesToAll() )
--                  :ToCoalitionIf( InitCoalition, self:IfMessage<profanity>() and self:IfMessagesToCoalition() )
              self:ScoreCSV( InitPlayerName, TargetPlayerName, "HIT_SCORE", 1, 1, InitUnitName, InitUnitCoalition, InitUnitCategory, InitUnitType, TargetUnitName, TargetUnitCoalition, TargetUnitCategory, TargetUnitType )
            end
		  end
		end
    end
  end
end

Messages were commented out to reduce the message spam.

EDIT: If you want the whole thing, look up and download my mission "Caucasus Dynamic Conflict" on the DCS website.


Edited by Toumal
  • Like 1
Link to comment
Share on other sites

I am not a programer, i have some basic but my knowledge is not enough to modify the script myself.

What i am thinking about is trees destruction. Any chance to add functionality of the script , it would remove trees in impact zone? Or some other script for that?


Edited by bingbean
Link to comment
Share on other sites

On 11/4/2022 at 10:24 AM, bingbean said:

I am not a programer, i have some basic but my knowledge is not enough to modify the script myself.

What i am thinking about is trees destruction. Any chance to add functionality of the script , it would remove trees in impact zone? Or some other script for that?

 

I made some research , but it looks like there is no script equivalent for "SCENERY REMOVE OBJECTS ZONE". , which is a shame.  Otherwise i would be pretty easy.

I would only add: trigger.action.sceneryremoveobjectszone(impactPoint, trees) under trigger.action.explosion(impactPoint, getWeaponExplosive(wpnData.name)) in function track_wpns() and it would by probably done. 

However the function "trigger.action.sceneryremoveobjectszone(impactPoint, trees)" doesn't exist so it will not be so easy.

Link to comment
Share on other sites

  • 2 weeks later...
On 10/13/2022 at 3:19 PM, leonardo_c said:

I added a few more weapons and corrected the Mavericks as suggested.

Have fun.

Splash_Damage_2.zip 6.14 kB · 61 downloads

 

I've been using the original from Dec from OP with no issues. Yesterday I downloaded this and tried it in my mission but it looks like the blast radius isn't centered on where the munition hits? Furthermore, it looks as if the blast triggers damage of surrounding units even BEFORE the bomb hits the ground.  

 

Lag or an issue with this script? (I was using the laser guided 500lbs bomb)


Edited by Aphelion079
for clarity
Link to comment
Share on other sites

  • 2 weeks later...
  • 2 weeks later...
  • 3 weeks later...

Has anyone else noticed with the script that weapons interfere with each other when in close-ish proximity?

2 IR Mavs.. first got a kill (tank), the second was killed by the first, and no kill

2 Laser Hydra's launched together (multiple = 2) kill each other at the target, target BMP survived

  • Thanks 1
Link to comment
Share on other sites

  • 3 weeks later...
  • 4 weeks later...

@Toumal@Grimm

I noticed this doesn't offer kill messages for direct instant-kill hits, such as from laser guided APKWS, but seems to work really well for splash damage from slightly missed dumb bombs. Was wondering if either of you have played around with this script since? Not sure if there might be a timing conflict between the weapon and the created blast? Or is this something where only Moose can reliably score from?


Edited by FusRoPotato
Link to comment
Share on other sites

Hi

Just added some values to the script on github

i'm waiting for author to publish or not modifications

thanks 😉

  • Like 1

System specs: Win10 x64 | i7-9700KF / i9-12900KF | 48/64 GB | GTX 1080 Ti 11 GB / RTX 3090TI 24GB | *NvME PRO 2To | HOTAS Warthog/Virpil | MFG Crosswind Pedals | Button Box

Link to comment
Share on other sites

5 hours ago, Kervinou said:

Just added some values to the script on github

Values for what munitions?

System Specs:

Spoiler

 💻Processor:13th Gen Intel(R) Core(TM) i9-13900K - 🧠RAM: 64GB - 🎥Video Card: NVIDIA RTX 4090 - 🥽 Display: Pimax 8kx VR Headset - 🕹️Accessories:  VKB Gunfighter III MCG Ultimate, VKB STECS Standard, Thrustmaster TPR Pedals, Simshaker JetPad, Predator HOTAS Mounts, 3D Printed Flight Button Box 

Thrustmaster TWCS Mod

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...