Page 1 of 1
How to check if bullet flew through smoke?
Posted: Sat Apr 25, 2020 10:00 pm
by BackRaw
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!
Re: How to check if bullet flew through smoke?
Posted: Sun Apr 26, 2020 12:21 am
by VinciT
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
Re: How to check if bullet flew through smoke?
Posted: Sat May 02, 2020 12:14 am
by BackRaw
Thank you!! That worked excellently! :D
Re: How to check if bullet flew through smoke?
Posted: Sat May 02, 2020 12:51 am
by VinciT
Glad I could help.

Re: How to check if bullet flew through smoke?
Posted: Sat May 02, 2020 3:09 pm
by L'In20Cible
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.

Re: How to check if bullet flew through smoke?
Posted: Sat May 02, 2020 8:57 pm
by VinciT
Whoops, serves me right for ripping this out of my other plugin. Fixed in the
previous post. Thank you for noticing the errors.

Re: How to check if bullet flew through smoke?
Posted: Fri May 08, 2020 7:45 am
by BackRaw
Nice catch!!