mirror of
https://github.com/vladtrc/iw4L
synced 2026-10-26 02:11:39 -04:00
Keep muzzle flashes and attached effects playing past the first minutes
spawn_effect takes one of 255 bolt records for every effect played on a tag, and nothing gave them back: run_garbage_collection cleared the effect slot and dropped the record. A minute or two into a match with bots, the muzzle flashes and shell ejects of every shot had used them all, and from then on every bolted effect failed with EffectLimit and was dropped without a word. That took later muzzle flashes, the jets' afterburners and the precision airstrike's cluster bomb, which is played on its tag_origin model and spawns the bomblets' ground explosions, so the airstrike did its damage with no fire or smoke. Garbage collection now puts a dead effect's record back on the free list, and the ring-full check runs before a record is taken, so that refusal no longer leaks one either. Seen on an iPhone build on mp_terminal before the fix: Uzi muzzle flashes at 0:30, none under steady fire at 2:40, and no fire or smoke where a precision airstrike landed about 3 minutes in. With the fix, in another match on the same map, the stealth bomber's fire and smoke showed and the player's SCAR still flashed 4 minutes in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+15
-3
@@ -860,6 +860,14 @@ impl FxSystemHost {
|
||||
Some(idx as u8)
|
||||
}
|
||||
|
||||
fn free_bolt_record(&mut self, index: u8) {
|
||||
let Some(next) = self.bolt_next.get_mut(usize::from(index)) else {
|
||||
return;
|
||||
};
|
||||
*next = self.bolt_first_free;
|
||||
self.bolt_first_free = i32::from(index);
|
||||
}
|
||||
|
||||
pub fn spawn_effect(
|
||||
&mut self,
|
||||
def_name: &str,
|
||||
@@ -873,6 +881,9 @@ impl FxSystemHost {
|
||||
if wants_spotlight && self.spotlight_count >= FX_SPOT_LIGHT_LIMIT {
|
||||
return Err(SpawnFail::TooManySpotlights);
|
||||
}
|
||||
if self.ring_occupancy() >= FX_EFFECT_HANDLE_RING_SIZE as i32 {
|
||||
return Err(SpawnFail::RingFull);
|
||||
}
|
||||
let bolt_index = if bolt == FX_SPAWN_BOLT_NONE {
|
||||
0xff
|
||||
} else {
|
||||
@@ -883,9 +894,6 @@ impl FxSystemHost {
|
||||
};
|
||||
|
||||
let alloc = self.first_free_effect;
|
||||
if self.ring_occupancy() >= FX_EFFECT_HANDLE_RING_SIZE as i32 {
|
||||
return Err(SpawnFail::RingFull);
|
||||
}
|
||||
self.first_free_effect = alloc.wrapping_add(1);
|
||||
|
||||
let ring_i = (alloc as u32 & (FX_EFFECT_HANDLE_RING_SIZE - 1)) as usize;
|
||||
@@ -986,6 +994,10 @@ impl FxSystemHost {
|
||||
self.set_handle_at_ring(active_index as u32, handle);
|
||||
active_index = active_index.wrapping_add(1);
|
||||
if let Some(slot) = handle_to_slot(handle) {
|
||||
let bolt = self.effects[slot].bolt;
|
||||
if bolt != 0xff {
|
||||
self.free_bolt_record(bolt);
|
||||
}
|
||||
self.effects[slot] = FxEffectSlot::default();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user