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!
How to check if bullet flew through smoke?
Re: How to check if bullet flew through smoke?
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.
Re: How to check if bullet flew through smoke?
Thank you!! That worked excellently! :D
- L'In20Cible
- Project Leader
- Posts: 1534
- Joined: Sat Jul 14, 2012 9:29 pm
- Location: Québec
Re: How to check if bullet flew through smoke?
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?
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?
Nice catch!!
Return to “Plugin Development Support”
Who is online
Users browsing this forum: No registered users and 47 guests