How to check if bullet flew through smoke?

Please post any questions about developing your plugin here. Please use the search function before posting!
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

How to check if bullet flew through smoke?

Postby BackRaw » Sat Apr 25, 2020 10:00 pm

Hi,

what would be the best method to check whether a bullet flew through smoke on impact (let's say bullet_impact)? If there's a way to get the box of a smoke grenade's smoke, I could calculate whether it flew through the box or not. Can we get that box location? If not, is there a different/better way to do this?

Thanks!
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: How to check if bullet flew through smoke?

Postby VinciT » Sun Apr 26, 2020 12:21 am

Heh, needed the same thing a few months ago. Took me a while until I stumbled upon CBotManager::IsLineBlockedBySmoke(). Works in both CSS and CSGO, but you might need to fiddle around with the bloat argument in CSGO, since the shape of the smoke is a bit different from the CSS one. Either way it should get the job done:

Syntax: Select all

# ../smoke_trace/smoke_trace.py

# Python
import math

# Source.Python
from entities.dictionary import EntityDictionary
from events import Event
from listeners import OnEntitySpawned
from mathlib import Vector
from players.dictionary import PlayerDictionary


# Smoke radius defined within Counter-Strike: Source.
SMOKE_RADIUS = 155


smoke_instances = EntityDictionary()
player_instances = PlayerDictionary()


@Event('bullet_impact')
def bullet_impact(event):
blocked = is_line_blocked_by_smoke(
start=player_instances.from_userid(event['userid']).eye_location,
end=Vector(event['x'], event['y'], event['z'])
)

# Did the bullet go through a smoke?
if blocked:
pass


@Event('smokegrenade_detonate')
def smoke_detonate(event):
# Add the 'smokegrenade_projectile' that just detonated to the dictionary.
# The entity itself doesn't get removed upon detonation, but after the
# smoke effect disappears.
try:
smoke_instances[event['entityid']]
except KeyError:
pass


@OnEntitySpawned
def on_entity_spawned(base_entity):
try:
index = base_entity.index
except ValueError:
return

# In CSS, the 'smokegrenade_detonate' event does not have the 'entityid'
# variable, so we have to check when 'env_particlesmokegrenade' spawns
# instead.
if 'env_particlesmokegrenade' in base_entity.classname:
smoke_instances[index]


def is_line_blocked_by_smoke(start, end, bloat=1.0):
"""Checks if the line defined by the given 'start' and 'end' points is
blocked by a smoke.

Args:
start (Vector): Starting point of the line.
end (Vector): Ending point of the line.
bloat (float): Used to fine-tune the radius of the smoke.

Returns:
bool: True if the line is blocked by a smoke, False otherwise.
"""
smoke_radius_sq = SMOKE_RADIUS * SMOKE_RADIUS * bloat * bloat
total_smoked_length = 0.0

line_dir = end - start
line_length = line_dir.normalize()

for smoke in smoke_instances.values():
smoke_origin = smoke.origin

to_grenade = smoke_origin - start
along_dist = to_grenade.dot(line_dir)

# Find the closest point to the 'smokegrenade_projectile' along the
# line.
if along_dist < 0:
close = start
elif along_dist >= line_length:
close = end
else:
close = start + line_dir * along_dist

to_close = close - smoke_origin
length_sq = to_close.length_sqr

# Does some part of the line go through the smoke?
if length_sq < smoke_radius_sq:
start_sq = to_grenade.length_sqr
end_sq = (smoke_origin - end).length_sqr

# Is the starting point inside the smoke?
if start_sq < smoke_radius_sq:

# Is the ending point inside the smoke?
if end_sq < smoke_radius_sq:
# The whole line is inside the smoke.
total_smoked_length += (end - start).length
else:
# The line starts inside the smoke, but ends up outside.
half_smoked_length = math.sqrt(smoke_radius_sq - length_sq)

if along_dist > 0:
# The line goes through the closest point.
total_smoked_length += half_smoked_length + (
close - start).length
else:
# The line starts after the closest point.
total_smoked_length += half_smoked_length - (
close - start).length

# Is the ending point inside the smoke?
elif end_sq < smoke_radius_sq:
# The line starts outside the smoke, but ends up inside.
half_smoked_length = math.sqrt(smoke_radius_sq - length_sq)

v = end - smoke_origin
if v.dot(line_dir) > 0:
# The line goes through the closest point.
total_smoked_length += half_smoked_length + (
close - end).length

else:
# The line ends before reaching the closest point.
total_smoked_length += half_smoked_length - (
close - end).length

else:
# Both the starting and ending points are outside the smoke.
smoked_length = 2.0 * math.sqrt(smoke_radius_sq - length_sq)
total_smoked_length += smoked_length

max_smoked_length = 0.7 * SMOKE_RADIUS
return total_smoked_length > max_smoked_length
Last edited by VinciT on Sat May 02, 2020 8:55 pm, edited 1 time in total.
ImageImageImageImageImage
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Re: How to check if bullet flew through smoke?

Postby BackRaw » Sat May 02, 2020 12:14 am

Thank you!! That worked excellently! :D
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: How to check if bullet flew through smoke?

Postby VinciT » Sat May 02, 2020 12:51 am

Glad I could help. :grin:
ImageImageImageImageImage
User avatar
L'In20Cible
Project Leader
Posts: 1533
Joined: Sat Jul 14, 2012 9:29 pm
Location: Québec

Re: How to check if bullet flew through smoke?

Postby L'In20Cible » Sat May 02, 2020 3:09 pm

VinciT wrote:Works in both CSS and CSGO

Actually, it will only work on CS:GO and the following line will raise on CS:S:
VinciT wrote:

Syntax: Select all

smoke_instances[event['entityid']]

You would need to search for it based on the x, y, and z coordinates passed to the event or the easiest way would be to track env_particlesmokegrenade spawn/deletion.

As a side note, the following:

Syntax: Select all

@OnEntityDeleted
def on_entity_deleted(base_entity):
"""Called when an entity is being removed."""
try:
index = base_entity.index
except ValueError:
return

# Is this a 'smokegrenade_projectile' entity?
try:
smoke_instances.pop(index)
except KeyError:
pass


Is redundant. The EntityDictionary class already takes care of that internally. :smile:
User avatar
VinciT
Senior Member
Posts: 331
Joined: Thu Dec 18, 2014 2:41 am

Re: How to check if bullet flew through smoke?

Postby VinciT » Sat May 02, 2020 8:57 pm

Whoops, serves me right for ripping this out of my other plugin. Fixed in the previous post. Thank you for noticing the errors. :tongue:
ImageImageImageImageImage
User avatar
BackRaw
Senior Member
Posts: 537
Joined: Sun Jul 15, 2012 1:46 am
Location: Germany
Contact:

Re: How to check if bullet flew through smoke?

Postby BackRaw » Fri May 08, 2020 7:45 am

Nice catch!!

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 23 guests