b243cf04d3
- Added BMP_1_EXPLOSION_DOWN.png to original and preview directories. - Added BMP_1_EXPLOSION_LEFT.png to original and preview directories. - Added BMP_1_EXPLOSION_RIGHT.png to original and preview directories. - Added BMP_1_EXPLOSION_UP.png to original and preview directories. These assets are part of the explosion animation for the game, enhancing visual effects during gameplay.
198 lines
6.8 KiB
Python
198 lines
6.8 KiB
Python
from .unit import Unit
|
|
from . import rat
|
|
from .points import Point
|
|
from engine.collision_system import CollisionLayer
|
|
import uuid
|
|
import random
|
|
|
|
# Costanti
|
|
AGE_THRESHOLD = 200
|
|
NUCLEAR_TIMER = 50 # 1 second at ~50 FPS
|
|
|
|
|
|
class Bomb(Unit):
|
|
def __init__(self, game, position=(0,0), id=None):
|
|
super().__init__(game, position, id, collision_layer=CollisionLayer.BOMB)
|
|
# Specific attributes for bombs
|
|
self.speed = 4 # Bombs age faster
|
|
self.fight = False
|
|
|
|
def move(self):
|
|
pass
|
|
|
|
def collisions(self):
|
|
pass
|
|
|
|
def die(self, unit=None):
|
|
if not unit:
|
|
unit = self
|
|
self.game.units.pop(unit.id)
|
|
|
|
|
|
def draw(self):
|
|
n = self.age // 40
|
|
n= 3 -n +1
|
|
if n == 0:
|
|
n = 1
|
|
if n < 0:
|
|
n = 0
|
|
image = self.game.bomb_assets[n]
|
|
image_size = self.game.render_engine.get_image_size(image)
|
|
self.rat_image = image
|
|
partial_x, partial_y = 0, 0
|
|
|
|
x_pos = self.position_before[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
|
|
y_pos = self.position_before[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
|
|
|
|
if self.is_hidden_in_tunnel(image_size):
|
|
return
|
|
|
|
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
|
|
|
class Timer(Bomb):
|
|
def move(self):
|
|
self.age += self.speed
|
|
if self.age == AGE_THRESHOLD:
|
|
self.die()
|
|
|
|
def die(self, unit=None, score=None):
|
|
"""Handle bomb explosion and chain reactions using vectorized collision system."""
|
|
score = 10
|
|
print("BOOM")
|
|
target_unit = unit if unit else self
|
|
self.game.render_engine.play_sound("BOMB.WAV")
|
|
|
|
# Use base class cleanup with error handling
|
|
try:
|
|
if target_unit.id in self.game.units:
|
|
self.game.units.pop(target_unit.id)
|
|
except:
|
|
print(f"Unit {target_unit.id} already dead")
|
|
|
|
# Bomb-specific behavior: create explosion
|
|
self.game.spawn_unit(Explosion, target_unit.position)
|
|
|
|
# Collect all explosion positions using vectorized approach
|
|
explosion_positions = []
|
|
|
|
# Check for chain reactions in all four directions
|
|
for direction in ["N", "S", "E", "W"]:
|
|
x, y = target_unit.position
|
|
while True:
|
|
if not self.game.map.is_wall(x, y):
|
|
explosion_positions.append((x, y))
|
|
else:
|
|
break
|
|
if direction == "N":
|
|
y -= 1
|
|
elif direction == "S":
|
|
y += 1
|
|
elif direction == "E":
|
|
x += 1
|
|
elif direction == "W":
|
|
x -= 1
|
|
|
|
# Create all explosions at once
|
|
for pos in explosion_positions:
|
|
self.game.spawn_unit(Explosion, pos)
|
|
|
|
# Use optimized collision system to get all rats in explosion area
|
|
# This replaces the nested loop with a single vectorized operation
|
|
victim_ids = self.game.collision_system.get_units_in_area(
|
|
explosion_positions,
|
|
layer_filter=CollisionLayer.RAT
|
|
)
|
|
|
|
# Kill all victims with score multiplier
|
|
for victim_id in victim_ids:
|
|
victim = self.game.get_unit_by_id(victim_id)
|
|
if victim and victim.id in self.game.units:
|
|
# Determine position based on partial_move
|
|
victim_pos = victim.position if victim.partial_move >= 0.5 else victim.position_before
|
|
if victim_pos in explosion_positions:
|
|
victim.die(score=score)
|
|
if score < 160:
|
|
score *= 2
|
|
|
|
|
|
class Explosion(Bomb):
|
|
def __init__(self, game, position=(0,0), id=None):
|
|
# Initialize with proper EXPLOSION layer
|
|
Unit.__init__(self, game, position, id, collision_layer=CollisionLayer.EXPLOSION)
|
|
self.speed = 20 # Bombs age faster * 5
|
|
self.fight = False
|
|
|
|
def move(self):
|
|
self.age += self.speed
|
|
if self.age >= AGE_THRESHOLD:
|
|
self.die()
|
|
|
|
def draw(self):
|
|
image = self.game.assets["BMP_EXPLOSION"]
|
|
image_size = self.game.render_engine.get_image_size(image)
|
|
partial_x, partial_y = 0, 0
|
|
|
|
x_pos = self.position_before[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
|
|
y_pos = self.position_before[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
|
|
|
|
if self.is_hidden_in_tunnel(image_size):
|
|
return
|
|
|
|
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
|
|
|
|
|
class NuclearBomb(Unit):
|
|
def __init__(self, game, position=(0,0), id=None):
|
|
super().__init__(game, position, id, collision_layer=CollisionLayer.BOMB)
|
|
self.speed = 1 # Slow countdown
|
|
self.fight = False
|
|
self.timer = NUCLEAR_TIMER # 1 second timer
|
|
|
|
def move(self):
|
|
"""Count down the nuclear timer"""
|
|
self.timer -= 1
|
|
if self.timer <= 0:
|
|
self.explode()
|
|
|
|
def collisions(self):
|
|
pass
|
|
|
|
|
|
def explode(self):
|
|
"""Nuclear explosion that affects all rats on the map"""
|
|
print("NUCLEAR EXPLOSION!")
|
|
|
|
# Play nuclear explosion sound
|
|
self.game.render_engine.play_sound("nuke.wav")
|
|
|
|
# Trigger white screen effect
|
|
self.game.render_engine.trigger_white_flash()
|
|
|
|
# Remove the nuclear bomb from the game
|
|
if self.id in self.game.units:
|
|
self.game.units.pop(self.id)
|
|
|
|
# Kill 90% of all rats on the map
|
|
rats_to_kill = []
|
|
# If unit is a child class of Rat
|
|
for unit in self.game.units.values():
|
|
if isinstance(unit, rat.Rat):
|
|
if random.random() < 0.7: # 70% chance to kill each rat
|
|
rats_to_kill.append(unit)
|
|
for unit in rats_to_kill:
|
|
unit.die(score=5)
|
|
|
|
print(f"Nuclear explosion killed {len(rats_to_kill)} rats!")
|
|
|
|
def draw(self):
|
|
"""Draw nuclear bomb on position"""
|
|
image = self.game.assets["BMP_NUCLEAR"]
|
|
image_size = self.game.render_engine.get_image_size(image)
|
|
|
|
x_pos = self.position[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2
|
|
y_pos = self.position[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2
|
|
|
|
if self.is_hidden_in_tunnel(image_size, position=self.position):
|
|
return
|
|
|
|
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit") |