OK
This commit is contained in:
@@ -10,5 +10,6 @@
|
|||||||
"scroll_right": ["Right", 11],
|
"scroll_right": ["Right", 11],
|
||||||
"spawn_bomb": ["Space", 1],
|
"spawn_bomb": ["Space", 1],
|
||||||
"spawn_mine": ["Left Ctrl", 2, 17],
|
"spawn_mine": ["Left Ctrl", 2, 17],
|
||||||
|
"spawn_nuclear_bomb": ["N", 3],
|
||||||
"pause": ["P", 16]
|
"pause": ["P", 16]
|
||||||
}
|
}
|
||||||
+20
-7
@@ -1,17 +1,20 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Audio conversion script to convert mine.wav to u8 22100 Hz format
|
Audio conversion script to convert audio files to u8 22100 Hz format
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from pydub import AudioSegment
|
from pydub import AudioSegment
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
def convert_mine_wav():
|
def convert_audio(input_path, output_path=None):
|
||||||
"""Convert mine.wav to u8 format at 22100 Hz"""
|
"""Convert audio file to u8 format at 22100 Hz"""
|
||||||
|
|
||||||
# Input and output paths
|
# Generate output path if not provided
|
||||||
input_path = "sound/mine.wav"
|
if output_path is None:
|
||||||
output_path = "sound/mine_converted.wav"
|
base_name = os.path.splitext(input_path)[0]
|
||||||
|
output_path = f"{base_name}_converted.wav"
|
||||||
|
|
||||||
if not os.path.exists(input_path):
|
if not os.path.exists(input_path):
|
||||||
print(f"Error: {input_path} not found!")
|
print(f"Error: {input_path} not found!")
|
||||||
@@ -73,5 +76,15 @@ def convert_mine_wav():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error during conversion: {e}")
|
print(f"Error during conversion: {e}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function to handle command line arguments"""
|
||||||
|
parser = argparse.ArgumentParser(description='Convert audio files to u8 22100 Hz format')
|
||||||
|
parser.add_argument('input_file', help='Input audio file path')
|
||||||
|
parser.add_argument('-o', '--output', help='Output file path (optional)')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
convert_audio(args.input_file, args.output)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
convert_mine_wav()
|
main()
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ class KeyBindings:
|
|||||||
self.spawn_bomb(self.pointer)
|
self.spawn_bomb(self.pointer)
|
||||||
elif key in keybindings.get("spawn_mine", []):
|
elif key in keybindings.get("spawn_mine", []):
|
||||||
self.spawn_mine(self.pointer)
|
self.spawn_mine(self.pointer)
|
||||||
|
elif key in keybindings.get("spawn_nuclear_bomb", []):
|
||||||
|
self.spawn_nuclear_bomb(self.pointer)
|
||||||
elif key in keybindings.get("pause", []):
|
elif key in keybindings.get("pause", []):
|
||||||
self.game_status = "paused" if self.game_status == "game" else "game"
|
self.game_status = "paused" if self.game_status == "game" else "game"
|
||||||
elif key in keybindings.get("start_game", []):
|
elif key in keybindings.get("start_game", []):
|
||||||
|
|||||||
@@ -6,11 +6,16 @@ class Graphics():
|
|||||||
self.tunnel = self.render_engine.load_image("Rat/BMP_TUNNEL.png", surface=True)
|
self.tunnel = self.render_engine.load_image("Rat/BMP_TUNNEL.png", surface=True)
|
||||||
self.grasses = [self.render_engine.load_image(f"Rat/BMP_1_GRASS_{i+1}.png", surface=True) for i in range(4)]
|
self.grasses = [self.render_engine.load_image(f"Rat/BMP_1_GRASS_{i+1}.png", surface=True) for i in range(4)]
|
||||||
self.rat_assets = {}
|
self.rat_assets = {}
|
||||||
|
self.rat_assets_textures = {}
|
||||||
self.bomb_assets = {}
|
self.bomb_assets = {}
|
||||||
for sex in ["MALE", "FEMALE", "BABY"]:
|
for sex in ["MALE", "FEMALE", "BABY"]:
|
||||||
self.rat_assets[sex] = {}
|
self.rat_assets[sex] = {}
|
||||||
for direction in ["UP", "DOWN", "LEFT", "RIGHT"]:
|
for direction in ["UP", "DOWN", "LEFT", "RIGHT"]:
|
||||||
self.rat_assets[sex][direction] = self.render_engine.load_image(f"Rat/BMP_{sex}_{direction}.png", transparent_color=(128, 128, 128))
|
self.rat_assets[sex][direction] = self.render_engine.load_image(f"Rat/BMP_{sex}_{direction}.png", transparent_color=(128, 128, 128))
|
||||||
|
for sex in ["MALE", "FEMALE", "BABY"]:
|
||||||
|
self.rat_assets_textures[sex] = {}
|
||||||
|
for direction in ["UP", "DOWN", "LEFT", "RIGHT"]:
|
||||||
|
self.rat_assets_textures[sex][direction] = self.render_engine.load_image(f"Rat/BMP_{sex}_{direction}.png", transparent_color=(128, 128, 128), surface=False)
|
||||||
for n in range(5):
|
for n in range(5):
|
||||||
self.bomb_assets[n] = self.render_engine.load_image(f"Rat/BMP_BOMB{n}.png", transparent_color=(128, 128, 128))
|
self.bomb_assets[n] = self.render_engine.load_image(f"Rat/BMP_BOMB{n}.png", transparent_color=(128, 128, 128))
|
||||||
self.assets = {}
|
self.assets = {}
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ class Scoring:
|
|||||||
for row in rows:
|
for row in rows:
|
||||||
table.append(row.split(" - "))
|
table.append(row.split(" - "))
|
||||||
table.sort(key=lambda x: int(x[1]), reverse=True)
|
table.sort(key=lambda x: int(x[1]), reverse=True)
|
||||||
return table
|
return table[:3]
|
||||||
|
|
||||||
def add_point(self, value):
|
def add_point(self, value):
|
||||||
self.points += value
|
self.points += value
|
||||||
+119
-11
@@ -54,6 +54,18 @@ class GameWindow:
|
|||||||
self.running = True
|
self.running = True
|
||||||
self.delay = 30
|
self.delay = 30
|
||||||
self.performance = 0
|
self.performance = 0
|
||||||
|
self.last_status_text = ""
|
||||||
|
self.stats_sprite = None
|
||||||
|
self.mean_fps = 0
|
||||||
|
self.fpss = []
|
||||||
|
self.text_width = 0
|
||||||
|
self.text_height = 0
|
||||||
|
self.ammo_text = ""
|
||||||
|
|
||||||
|
# White flash effect state
|
||||||
|
self.white_flash_active = False
|
||||||
|
self.white_flash_start_time = 0
|
||||||
|
self.white_flash_opacity = 255
|
||||||
|
|
||||||
# Input handling
|
# Input handling
|
||||||
self.key_down, self.key_up, self.axis_scroll = key_callback
|
self.key_down, self.key_up, self.axis_scroll = key_callback
|
||||||
@@ -151,7 +163,7 @@ class GameWindow:
|
|||||||
"""Draw background texture with current view offset"""
|
"""Draw background texture with current view offset"""
|
||||||
self.renderer.copy(bg_texture, dstrect=sdl2.SDL_Rect(self.w_offset, self.h_offset, self.width, self.height))
|
self.renderer.copy(bg_texture, dstrect=sdl2.SDL_Rect(self.w_offset, self.h_offset, self.width, self.height))
|
||||||
|
|
||||||
def draw_image(self, x, y, sprite, tag, anchor="nw"):
|
def draw_image(self, x, y, sprite, tag=None, anchor="nw"):
|
||||||
"""Draw an image sprite at specified coordinates"""
|
"""Draw an image sprite at specified coordinates"""
|
||||||
if not self.is_in_visible_area(x, y):
|
if not self.is_in_visible_area(x, y):
|
||||||
return
|
return
|
||||||
@@ -225,20 +237,50 @@ class GameWindow:
|
|||||||
# TODO: Fix outline parameter usage
|
# TODO: Fix outline parameter usage
|
||||||
color = (0, 0, 255) if self.button_cursor == list(coords) else (0, 0, 0)
|
color = (0, 0, 255) if self.button_cursor == list(coords) else (0, 0, 0)
|
||||||
self.draw_rectangle(x, y, width, height, "button", outline=color)
|
self.draw_rectangle(x, y, width, height, "button", outline=color)
|
||||||
self.draw_text(text, self.fonts[20], (x + 10, y + 10), (0, 0, 0))
|
#self.draw_text(text, self.fonts[20], (x + 10, y + 10), (0, 0, 0))
|
||||||
|
|
||||||
def update_status(self, text):
|
def update_status(self, text):
|
||||||
"""Update and display the status bar with FPS information"""
|
"""Update and display the status bar with FPS information"""
|
||||||
fps = int(1000 / self.performance) if self.performance != 0 else 0
|
fps = int(1000 / self.performance) if self.performance != 0 else 0
|
||||||
status_text = f"FPS: {fps} - {text}"
|
# at 10% of probability print fps
|
||||||
font = self.fonts[20]
|
if len(self.fpss) > 20:
|
||||||
sprite = self.factory.from_text(status_text, color=sdl2.ext.Color(0, 0, 0), fontmanager=font)
|
self.mean_fps = round(sum(self.fpss) / len(self.fpss)) if self.fpss else fps
|
||||||
text_width, text_height = sprite.size
|
#print(f"FPS: {self.mean_fps}")
|
||||||
|
self.fpss.clear()
|
||||||
# Draw background for status text
|
else:
|
||||||
self.renderer.fill((3, 3, text_width + 10, text_height + 4), sdl2.ext.Color(255, 255, 255))
|
self.fpss.append(fps)
|
||||||
self.draw_text(status_text, font, (8, 5), sdl2.ext.Color(0, 0, 0))
|
|
||||||
|
|
||||||
|
status_text = f"FPS: {self.mean_fps} - {text}"
|
||||||
|
if status_text != self.last_status_text:
|
||||||
|
self.last_status_text = status_text
|
||||||
|
font = self.fonts[20]
|
||||||
|
self.stats_sprite = self.factory.from_text(status_text, color=sdl2.ext.Color(0, 0, 0), fontmanager=font)
|
||||||
|
if self.text_width != self.stats_sprite.size[0] or self.text_height != self.stats_sprite.size[1]:
|
||||||
|
self.text_width, self.text_height = self.stats_sprite.size
|
||||||
|
# create a background for the status text using texture
|
||||||
|
self.stats_background = self.factory.from_color(sdl2.ext.Color(255, 255, 255), (self.text_width + 10, self.text_height + 4))
|
||||||
|
|
||||||
|
# self.renderer.fill((3, 3, self.text_width + 10, self.text_height + 4), sdl2.ext.Color(255, 255, 255))
|
||||||
|
self.renderer.copy(self.stats_background, dstrect=sdl2.SDL_Rect(3, 3, self.text_width + 10, self.text_height + 4))
|
||||||
|
self.renderer.copy(self.stats_sprite, dstrect=sdl2.SDL_Rect(8, 5, self.text_width, self.text_height))
|
||||||
|
|
||||||
|
def update_ammo(self, ammo, assets):
|
||||||
|
"""Update and display the ammo count"""
|
||||||
|
ammo_text = f"{ammo['bomb']['count']}/{ammo['bomb']['max']} {ammo['mine']['count']}/{ammo['mine']['max']} {ammo['nuclear']['count']}/{ammo['nuclear']['max']} "
|
||||||
|
if self.ammo_text != ammo_text:
|
||||||
|
self.ammo_text = ammo_text
|
||||||
|
font = self.fonts[20]
|
||||||
|
self.ammo_sprite = self.factory.from_text(ammo_text, color=sdl2.ext.Color(0, 0, 0), fontmanager=font)
|
||||||
|
text_width, text_height = self.ammo_sprite.size
|
||||||
|
self.ammo_background = self.factory.from_color(sdl2.ext.Color(255, 255, 255), (text_width + 10, text_height + 4))
|
||||||
|
text_width, text_height = self.ammo_sprite.size
|
||||||
|
position = (self.target_size[0] - text_width - 10, self.target_size[1] - text_height - 5)
|
||||||
|
#self.renderer.fill((position[0] - 5, position[1] - 2, text_width + 10, text_height + 4), sdl2.ext.Color(255, 255, 255))
|
||||||
|
self.renderer.copy(self.ammo_background, dstrect=sdl2.SDL_Rect(position[0] - 5, position[1] - 2, text_width + 10, text_height + 4))
|
||||||
|
self.renderer.copy(self.ammo_sprite, dstrect=sdl2.SDL_Rect(position[0], position[1], text_width, text_height))
|
||||||
|
self.renderer.copy(assets["BMP_BOMB0"], dstrect=sdl2.SDL_Rect(position[0]+25, position[1], 20, 20))
|
||||||
|
self.renderer.copy(assets["mine"], dstrect=sdl2.SDL_Rect(position[0]+80, position[1], 20, 20))
|
||||||
|
self.renderer.copy(assets["BMP_NUCLEAR"], dstrect=sdl2.SDL_Rect(position[0]+130, position[1], 20, 20))
|
||||||
# ======================
|
# ======================
|
||||||
# VIEW & NAVIGATION
|
# VIEW & NAVIGATION
|
||||||
# ======================
|
# ======================
|
||||||
@@ -328,6 +370,10 @@ class GameWindow:
|
|||||||
# Execute main update
|
# Execute main update
|
||||||
kwargs["update"]()
|
kwargs["update"]()
|
||||||
|
|
||||||
|
# Update and draw white flash effect
|
||||||
|
if self.update_white_flash():
|
||||||
|
self.draw_white_flash()
|
||||||
|
|
||||||
# Handle SDL events
|
# Handle SDL events
|
||||||
events = sdl2.ext.get_events()
|
events = sdl2.ext.get_events()
|
||||||
for event in events:
|
for event in events:
|
||||||
@@ -335,7 +381,11 @@ class GameWindow:
|
|||||||
self.running = False
|
self.running = False
|
||||||
elif event.type == sdl2.SDL_KEYDOWN and self.key_down:
|
elif event.type == sdl2.SDL_KEYDOWN and self.key_down:
|
||||||
key = sdl2.SDL_GetKeyName(event.key.keysym.sym).decode('utf-8')
|
key = sdl2.SDL_GetKeyName(event.key.keysym.sym).decode('utf-8')
|
||||||
self.key_down(key)
|
# Check for Right Ctrl key to trigger white flash
|
||||||
|
if event.key.keysym.sym == sdl2.SDLK_RCTRL:
|
||||||
|
self.trigger_white_flash()
|
||||||
|
else:
|
||||||
|
self.key_down(key)
|
||||||
elif event.type == sdl2.SDL_KEYUP and self.key_up:
|
elif event.type == sdl2.SDL_KEYUP and self.key_up:
|
||||||
key = sdl2.SDL_GetKeyName(event.key.keysym.sym).decode('utf-8')
|
key = sdl2.SDL_GetKeyName(event.key.keysym.sym).decode('utf-8')
|
||||||
self.key_up(key)
|
self.key_up(key)
|
||||||
@@ -362,6 +412,64 @@ class GameWindow:
|
|||||||
# SPECIAL EFFECTS
|
# SPECIAL EFFECTS
|
||||||
# ======================
|
# ======================
|
||||||
|
|
||||||
|
def trigger_white_flash(self):
|
||||||
|
"""Trigger the white flash effect"""
|
||||||
|
self.white_flash_active = True
|
||||||
|
self.white_flash_start_time = sdl2.SDL_GetTicks()
|
||||||
|
self.white_flash_opacity = 255
|
||||||
|
|
||||||
|
def update_white_flash(self):
|
||||||
|
"""Update the white flash effect and return True if it should be drawn"""
|
||||||
|
if not self.white_flash_active:
|
||||||
|
return False
|
||||||
|
|
||||||
|
current_time = sdl2.SDL_GetTicks()
|
||||||
|
elapsed_time = current_time - self.white_flash_start_time
|
||||||
|
|
||||||
|
if elapsed_time < 1000: # First 1 second : full white
|
||||||
|
self.white_flash_opacity = 255
|
||||||
|
return True
|
||||||
|
elif elapsed_time < 3000: # Next 2 seconds: fade out
|
||||||
|
# Calculate fade based on remaining time (2000ms fade duration)
|
||||||
|
fade_progress = (elapsed_time - 1000) / 2000.0 # 0.0 to 1.0
|
||||||
|
self.white_flash_opacity = int(255 * (1.0 - fade_progress))
|
||||||
|
return True
|
||||||
|
else: # Effect is complete
|
||||||
|
self.white_flash_active = False
|
||||||
|
self.white_flash_opacity = 0
|
||||||
|
return False
|
||||||
|
|
||||||
|
def draw_white_flash(self):
|
||||||
|
"""Draw the white flash overlay"""
|
||||||
|
if self.white_flash_opacity > 0:
|
||||||
|
# Create a white surface with the current opacity
|
||||||
|
white_surface = sdl2.SDL_CreateRGBSurface(
|
||||||
|
0, self.target_size[0], self.target_size[1], 32,
|
||||||
|
0x000000FF, # R mask
|
||||||
|
0x0000FF00, # G mask
|
||||||
|
0x00FF0000, # B mask
|
||||||
|
0xFF000000 # A mask
|
||||||
|
)
|
||||||
|
|
||||||
|
if white_surface:
|
||||||
|
# Fill surface with white
|
||||||
|
sdl2.SDL_FillRect(white_surface, None,
|
||||||
|
sdl2.SDL_MapRGBA(white_surface.contents.format,
|
||||||
|
255, 255, 255, self.white_flash_opacity))
|
||||||
|
|
||||||
|
# Convert to texture and draw
|
||||||
|
white_texture = self.factory.from_surface(white_surface)
|
||||||
|
white_texture.position = (0, 0)
|
||||||
|
|
||||||
|
# Enable alpha blending for the texture
|
||||||
|
sdl2.SDL_SetTextureBlendMode(white_texture.texture, sdl2.SDL_BLENDMODE_BLEND)
|
||||||
|
|
||||||
|
# Draw the white overlay
|
||||||
|
self.renderer.copy(white_texture, dstrect=sdl2.SDL_Rect(0, 0, self.target_size[0], self.target_size[1]))
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
sdl2.SDL_FreeSurface(white_surface)
|
||||||
|
|
||||||
# ======================
|
# ======================
|
||||||
# UTILITY METHODS
|
# UTILITY METHODS
|
||||||
# ======================
|
# ======================
|
||||||
|
|||||||
+23
-4
@@ -17,19 +17,38 @@ class UnitManager:
|
|||||||
self.spawn_unit(rat_class, position)
|
self.spawn_unit(rat_class, position)
|
||||||
|
|
||||||
def spawn_bomb(self, position):
|
def spawn_bomb(self, position):
|
||||||
|
if self.ammo["bomb"]["count"] <= 0:
|
||||||
|
return
|
||||||
self.render_engine.play_sound("PUTDOWN.WAV")
|
self.render_engine.play_sound("PUTDOWN.WAV")
|
||||||
self.spawn_unit(bomb.Timer, position)
|
self.spawn_unit(bomb.Timer, position)
|
||||||
|
self.ammo["bomb"]["count"] -= 1
|
||||||
|
|
||||||
|
def spawn_nuclear_bomb(self, position):
|
||||||
|
"""Spawn a nuclear bomb at the specified position"""
|
||||||
|
if self.ammo["nuclear"]["count"] <= 0:
|
||||||
|
return
|
||||||
|
if self.map.is_wall(position[0], position[1]):
|
||||||
|
return
|
||||||
|
self.render_engine.play_sound("NUCLEAR.WAV")
|
||||||
|
self.ammo["nuclear"]["count"] -= 1
|
||||||
|
self.spawn_unit(bomb.NuclearBomb, position)
|
||||||
|
|
||||||
def spawn_mine(self, position):
|
def spawn_mine(self, position):
|
||||||
|
if self.ammo["mine"]["count"] <= 0:
|
||||||
|
return
|
||||||
if self.map.is_wall(position[0], position[1]):
|
if self.map.is_wall(position[0], position[1]):
|
||||||
return
|
return
|
||||||
self.render_engine.play_sound("PUTDOWN.WAV")
|
self.render_engine.play_sound("PUTDOWN.WAV")
|
||||||
self.spawn_unit(mine.Mine, position)
|
self.ammo["mine"]["count"] -= 1
|
||||||
|
self.spawn_unit(mine.Mine, position, on_bottom=True)
|
||||||
|
|
||||||
def spawn_unit(self, unit, position, **kwargs):
|
def spawn_unit(self, unit, position, on_bottom=False, **kwargs):
|
||||||
id = uuid.uuid4()
|
id = uuid.uuid4()
|
||||||
self.units[id] = unit(self, position, id, **kwargs)
|
if on_bottom:
|
||||||
|
self.units = {id: unit(self, position, id, **kwargs), **self.units}
|
||||||
|
else:
|
||||||
|
self.units[id] = unit(self, position, id, **kwargs)
|
||||||
|
|
||||||
def choose_start(self):
|
def choose_start(self):
|
||||||
if not hasattr(self, '_valid_positions'):
|
if not hasattr(self, '_valid_positions'):
|
||||||
self._valid_positions = [
|
self._valid_positions = [
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import uuid
|
|
||||||
from engine import maze, sdl2 as engine, controls, graphics, unit_manager, scoring
|
|
||||||
import os
|
import os
|
||||||
import datetime
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
from engine import maze, sdl2 as engine, controls, graphics, unit_manager, scoring
|
||||||
|
|
||||||
class MiceMaze(
|
class MiceMaze(
|
||||||
controls.KeyBindings,
|
controls.KeyBindings,
|
||||||
unit_manager.UnitManager,
|
unit_manager.UnitManager,
|
||||||
@@ -40,6 +38,20 @@ class MiceMaze(
|
|||||||
self.start_game()
|
self.start_game()
|
||||||
self.background_texture = None
|
self.background_texture = None
|
||||||
self.configs = self.get_config()
|
self.configs = self.get_config()
|
||||||
|
self.ammo = {
|
||||||
|
"bomb": {
|
||||||
|
"count": 2,
|
||||||
|
"max": 5
|
||||||
|
},
|
||||||
|
"nuclear": {
|
||||||
|
"count": 1,
|
||||||
|
"max": 1
|
||||||
|
},
|
||||||
|
"mine": {
|
||||||
|
"count": 5,
|
||||||
|
"max": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def get_config(self):
|
def get_config(self):
|
||||||
configs = {}
|
configs = {}
|
||||||
@@ -57,6 +69,15 @@ class MiceMaze(
|
|||||||
|
|
||||||
# ==================== GAME LOGIC ====================
|
# ==================== GAME LOGIC ====================
|
||||||
|
|
||||||
|
def refill_ammo(self):
|
||||||
|
for ammo_type, data in self.ammo.items():
|
||||||
|
if ammo_type == "bomb":
|
||||||
|
if random.random() < 0.01:
|
||||||
|
data["count"] = min(data["count"] + 1, data["max"])
|
||||||
|
elif ammo_type == "mine":
|
||||||
|
if random.random() < 0.05:
|
||||||
|
data["count"] = min(data["count"] + 1, data["max"])
|
||||||
|
|
||||||
def update_maze(self):
|
def update_maze(self):
|
||||||
if self.game_over():
|
if self.game_over():
|
||||||
return
|
return
|
||||||
@@ -79,6 +100,8 @@ class MiceMaze(
|
|||||||
unit.collisions()
|
unit.collisions()
|
||||||
unit.draw()
|
unit.draw()
|
||||||
self.render_engine.update_status(f"Mice: {self.count_rats()} - Points: {self.points}")
|
self.render_engine.update_status(f"Mice: {self.count_rats()} - Points: {self.points}")
|
||||||
|
self.refill_ammo()
|
||||||
|
self.render_engine.update_ammo(self.ammo, self.assets)
|
||||||
self.scroll()
|
self.scroll()
|
||||||
self.render_engine.new_cycle(50, self.update_maze)
|
self.render_engine.new_cycle(50, self.update_maze)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,9 +1,12 @@
|
|||||||
from .unit import Unit
|
from .unit import Unit
|
||||||
|
from . import rat
|
||||||
from .points import Point
|
from .points import Point
|
||||||
import uuid
|
import uuid
|
||||||
|
import random
|
||||||
|
|
||||||
# Costanti
|
# Costanti
|
||||||
AGE_THRESHOLD = 200
|
AGE_THRESHOLD = 200
|
||||||
|
NUCLEAR_TIMER = 50 # 1 second at ~50 FPS
|
||||||
|
|
||||||
|
|
||||||
class Bomb(Unit):
|
class Bomb(Unit):
|
||||||
@@ -106,4 +109,58 @@ class Explosion(Bomb):
|
|||||||
x_pos = self.position_before[0] * self.game.cell_size + (self.game.cell_size - image_size[0]) // 2 + partial_x
|
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
|
y_pos = self.position_before[1] * self.game.cell_size + (self.game.cell_size - image_size[1]) // 2 + partial_y
|
||||||
|
|
||||||
|
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)
|
||||||
|
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=None)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
self.game.render_engine.draw_image(x_pos, y_pos, image, anchor="nw", tag="unit")
|
||||||
+4
-3
@@ -98,8 +98,9 @@ class Rat(Unit):
|
|||||||
self.game.units.pop(target_unit.id)
|
self.game.units.pop(target_unit.id)
|
||||||
|
|
||||||
# Rat-specific behavior: spawn points
|
# Rat-specific behavior: spawn points
|
||||||
self.game.spawn_unit(Point, death_position, value=score)
|
if score not in [None, 0]:
|
||||||
|
self.game.spawn_unit(Point, death_position, value=score)
|
||||||
|
|
||||||
# Add blood stain directly to background
|
# Add blood stain directly to background
|
||||||
self.game.add_blood_stain(death_position)
|
self.game.add_blood_stain(death_position)
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@ class Rat(Unit):
|
|||||||
direction = self.calculate_rat_direction()
|
direction = self.calculate_rat_direction()
|
||||||
|
|
||||||
sex = self.sex if self.age > AGE_THRESHOLD else "BABY"
|
sex = self.sex if self.age > AGE_THRESHOLD else "BABY"
|
||||||
image = self.game.rat_assets[sex][direction]
|
image = self.game.rat_assets_textures[sex][direction]
|
||||||
image_size = self.game.render_engine.get_image_size(image)
|
image_size = self.game.render_engine.get_image_size(image)
|
||||||
self.rat_image = image
|
self.rat_image = image
|
||||||
partial_x, partial_y = 0, 0
|
partial_x, partial_y = 0, 0
|
||||||
|
|||||||
Reference in New Issue
Block a user