Browse Source

Add unit tests for UnitFactory functionality and initialize units package

master
Matteo Benedetto 4 months ago
parent
commit
689b21bf65
  1. 10
      engine/controls.py
  2. 43
      engine/graphics.py
  3. 22
      engine/scoring.py
  4. 56
      engine/tkinter.py
  5. 33
      engine/unit_manager.py
  6. 175
      rats.py
  7. 8
      units/__init__.py
  8. 15
      units/bomb.py
  9. 4
      units/points.py
  10. 16
      units/rat.py

10
engine/controls.py

@ -7,9 +7,9 @@ class KeyBindings:
def key_pressed(self, key, coords=None): def key_pressed(self, key, coords=None):
keybindings = self.configs[f"keybinding_{self.game_status}"] keybindings = self.configs[f"keybinding_{self.game_status}"]
if key in keybindings.get("quit", []): if key in keybindings.get("quit", []):
self.engine.close() self.render_engine.close()
elif key in keybindings.get("new_rat", []): elif key in keybindings.get("new_rat", []):
self.new_rat() self.spawn_rat()
elif key in keybindings.get("kill_rat", []): elif key in keybindings.get("kill_rat", []):
if self.units: if self.units:
self.units[random.choice(list(self.units.keys()))].die(score=5) self.units[random.choice(list(self.units.keys()))].die(score=5)
@ -17,7 +17,7 @@ class KeyBindings:
self.audio = not self.audio self.audio = not self.audio
elif key in keybindings.get("toggle_full_screen", []): elif key in keybindings.get("toggle_full_screen", []):
self.full_screen = not self.full_screen self.full_screen = not self.full_screen
self.engine.full_screen(self.full_screen) self.render_engine.full_screen(self.full_screen)
elif key in keybindings.get("scroll_up", []): elif key in keybindings.get("scroll_up", []):
self.start_scrolling("Up") self.start_scrolling("Up")
elif key in keybindings.get("scroll_down", []): elif key in keybindings.get("scroll_down", []):
@ -27,7 +27,7 @@ class KeyBindings:
elif key in keybindings.get("scroll_right", []): elif key in keybindings.get("scroll_right", []):
self.start_scrolling("Right") self.start_scrolling("Right")
elif key in keybindings.get("spawn_bomb", []): elif key in keybindings.get("spawn_bomb", []):
self.play_sound("PUTDOWN.WAV") self.render_engine.play_sound("PUTDOWN.WAV")
self.spawn_bomb(self.pointer) self.spawn_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"
@ -44,7 +44,7 @@ class KeyBindings:
self.start_game() self.start_game()
def quit_game(self): def quit_game(self):
self.engine.close() self.render_engine.close()
def key_released(self, key): def key_released(self, key):
if key in ["Up", "Down", "Left", "Right", 8, 9, 10, 11]: if key in ["Up", "Down", "Left", "Right", 8, 9, 10, 11]:
self.stop_scrolling() self.stop_scrolling()

43
engine/graphics.py

@ -0,0 +1,43 @@
import os
class Graphics():
def load_assets(self):
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.rat_assets = {}
self.bomb_assets = {}
for sex in ["MALE", "FEMALE", "BABY"]:
self.rat_assets[sex] = {}
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))
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.assets = {}
for file in os.listdir("assets/Rat"):
if file.endswith(".png"):
self.assets[file[:-4]] = self.render_engine.load_image(f"Rat/{file}")
# ==================== RENDERING ====================
def draw_maze(self):
if self.background_texture is None:
texture_tiles = []
for y, row in enumerate(self.map.matrix):
for x, cell in enumerate(row):
variant = x*y % 4
tile = self.grasses[variant] if cell else self.tunnel
texture_tiles.append((tile, x*self.cell_size, y*self.cell_size))
self.background_texture = self.render_engine.create_texture(texture_tiles)
self.render_engine.draw_background(self.background_texture)
def scroll_cursor(self, x=0, y=0):
if self.pointer[0] + x > self.map.width or self.pointer[1] + y > self.map.height:
return
self.pointer = (
max(1, min(self.map.width-2, self.pointer[0] + x)),
max(1, min(self.map.height-2, self.pointer[1] + y))
)
self.render_engine.scroll_view(self.pointer)

22
engine/scoring.py

@ -0,0 +1,22 @@
import datetime
class Scoring:
# ==================== SCORING ====================
def save_score(self):
with open("scores.txt", "a") as f:
f.write(f"{datetime.datetime.now()} - {self.points}\n")
def read_score(self):
table = []
with open("scores.txt") as f:
rows = f.read().splitlines()
for row in rows:
table.append(row.split(" - "))
table.sort(key=lambda x: int(x[1]), reverse=True)
return table
def add_point(self, value):
self.points += value

56
engine/tkinter.py

@ -1,56 +0,0 @@
import tkinter as tk
import os
class GameWindow:
"""Classe che gestisce la finestra di gioco e il rendering grafico."""
def __init__(self, width, height, cell_size, title, key_callback=None):
self.cell_size = cell_size
self.window = tk.Tk()
self.window.title(title)
self.canvas = tk.Canvas(self.window, width=width*cell_size, height=height*cell_size)
self.canvas.pack()
self.menu = tk.Menu(self.window)
self.menu.add_command(label="Quit", command=self.window.destroy)
self.status_bar = tk.Label(self.window, text=title, bd=1, relief=tk.SUNKEN, anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
self.window.config(menu=self.menu)
if key_callback:
self.window.bind("<Key>", key_callback)
def load_image(self, path, transparent_color=None):
image = tk.PhotoImage(file=os.path.join(os.path.dirname(__file__), "..", "assets", path))
if transparent_color:
gray_pixels = []
for y in range(image.height()):
for x in range(image.width()):
r, g, b = image.get(x, y)
if r == transparent_color[0] and g == transparent_color[1] and b == transparent_color[2]:
gray_pixels.append((x, y))
for x, y in gray_pixels:
image.transparency_set(x, y, 1)
return image.zoom(self.cell_size // 20)
def bind(self, event, callback):
self.window.bind(event, callback)
def draw_image(self, x, y, image, tag, anchor="nw"):
self.canvas.create_image(x, y, image=image, anchor=anchor, tag=tag)
def draw_rectangle(self, x, y, width, height, tag, outline="red"):
self.canvas.create_rectangle(x, y, x+width, y+height, outline=outline, tag=tag)
def delete_tag(self, tag):
self.canvas.delete(tag)
def update_status(self, text):
self.status_bar.config(text=text)
def new_cycle(self, delay, callback):
self.window.after(delay, callback)
def mainloop(self, **kwargs):
kwargs["update"]()
self.window.mainloop()
def get_image_size(self, image):
return image.width(), image.height()

33
engine/unit_manager.py

@ -0,0 +1,33 @@
import random
import uuid
from units import rat, bomb
class UnitManager:
def count_rats(self):
count = 0
for unit in self.units.values():
if isinstance(unit, rat.Rat):
count += 1
return count
def spawn_rat(self, position=None):
if position is None:
position = self.choose_start()
rat_class = rat.Male if random.random() < 0.5 else rat.Female
self.spawn_unit(rat_class, position)
def spawn_bomb(self, position):
self.spawn_unit(bomb.Timer, position)
def spawn_unit(self, unit, position, **kwargs):
id = uuid.uuid4()
self.units[id] = unit(self, position, id, **kwargs)
def choose_start(self):
if not hasattr(self, '_valid_positions'):
self._valid_positions = [
(x, y) for y in range(1, self.map.height-1)
for x in range(1, self.map.width-1)
if self.map.matrix[y][x]
]
return random.choice(self._valid_positions)

175
rats.py

@ -1,23 +1,31 @@
#!/usr/bin/python3 #!/usr/bin/python3
import random import random
from units import rat, bomb
import uuid import uuid
from engine import maze, sdl2 as engine, controls from engine import maze, sdl2 as engine, controls, graphics, unit_manager, scoring
import os import os
import datetime import datetime
import json import json
class MiceMaze(controls.KeyBindings): class MiceMaze(
controls.KeyBindings,
unit_manager.UnitManager,
graphics.Graphics,
scoring.Scoring
):
# ==================== INITIALIZATION ====================
def __init__(self, maze_file): def __init__(self, maze_file):
self.map = maze.Map(maze_file) self.map = maze.Map(maze_file)
self.audio = True self.audio = True
self.cell_size = 40 self.cell_size = 40
self.full_screen = False self.full_screen = False
self.engine = engine.GameWindow(self.map.width, self.map.height, self.render_engine = engine.GameWindow(self.map.width, self.map.height,
self.cell_size, "Mice!", self.cell_size, "Mice!",
key_callback=(self.key_pressed, self.key_released, self.axis_scroll)) key_callback=(self.key_pressed, self.key_released, self.axis_scroll))
self.graphics_load() self.load_assets()
self.pointer = (random.randint(1, self.map.width-2), random.randint(1, self.map.height-2)) self.pointer = (random.randint(1, self.map.width-2), random.randint(1, self.map.height-2))
self.scroll_cursor() self.scroll_cursor()
self.points = 0 self.points = 0
@ -43,150 +51,67 @@ class MiceMaze(controls.KeyBindings):
def start_game(self): def start_game(self):
for _ in range(5): for _ in range(5):
self.new_rat() self.spawn_rat()
def count_rats(self): # ==================== GAME LOGIC ====================
count = 0
def update_maze(self):
if self.game_over():
return
if self.game_status == "paused":
self.render_engine.dialog("Pause")
return
if self.game_status == "start_menu":
self.render_engine.dialog("Welcome to the Mice!", subtitle="A game by Matteo because he was bored",image=self.assets["BMP_WEWIN"])
return
self.render_engine.delete_tag("unit")
self.render_engine.delete_tag("effect")
self.render_engine.draw_pointer(self.pointer[0] * self.cell_size, self.pointer[1] * self.cell_size)
self.unit_positions.clear()
self.unit_positions_before.clear()
for unit in self.units.values(): for unit in self.units.values():
if isinstance(unit, rat.Rat): self.unit_positions.setdefault(unit.position, []).append(unit)
count += 1 self.unit_positions_before.setdefault(unit.position_before, []).append(unit)
return count for unit in self.units.copy().values():
unit.move()
def new_rat(self, position=None): unit.collisions()
if position is None: unit.draw()
position = self.choose_start() self.render_engine.update_status(f"Mice: {self.count_rats()} - Points: {self.points}")
rat_class = rat.Male if random.random() < 0.5 else rat.Female self.scroll()
self.spawn_unit(rat_class, position) self.render_engine.new_cycle(50, self.update_maze)
def spawn_bomb(self, position):
self.spawn_unit(bomb.Timer, position)
def spawn_unit(self, unit, position, **kwargs):
id = uuid.uuid4()
self.units[id] = unit(self, position, id, **kwargs)
def choose_start(self):
if not hasattr(self, '_valid_positions'):
self._valid_positions = [
(x, y) for y in range(1, self.map.height-1)
for x in range(1, self.map.width-1)
if self.map.matrix[y][x]
]
return random.choice(self._valid_positions)
def draw_maze(self):
if self.background_texture is None:
texture_tiles = []
for y, row in enumerate(self.map.matrix):
for x, cell in enumerate(row):
variant = x*y % 4
tile = self.grasses[variant] if cell else self.tunnel
texture_tiles.append((tile, x*self.cell_size, y*self.cell_size))
self.background_texture = self.engine.create_texture(texture_tiles)
self.engine.draw_background(self.background_texture)
def run(self):
self.render_engine.mainloop(update=self.update_maze, bg_update=self.draw_maze)
# ==================== GAME OVER LOGIC ====================
def game_over(self): def game_over(self):
if self.game_end[0]: if self.game_end[0]:
if not self.game_end[1]: if not self.game_end[1]:
self.engine.dialog("Game Over: Mice are too many!", image=self.assets["BMP_WEWIN"]) self.render_engine.dialog("Game Over: Mice are too many!", image=self.assets["BMP_WEWIN"])
else: else:
self.engine.dialog(f"You Win! Points: {self.points}", image=self.assets["BMP_WEWIN"], scores=self.read_score()) self.render_engine.dialog(f"You Win! Points: {self.points}", image=self.assets["BMP_WEWIN"], scores=self.read_score())
return True return True
if self.count_rats() > 200: if self.count_rats() > 200:
self.stop_sound() self.render_engine.stop_sound()
self.play_sound("WEWIN.WAV") self.render_engine.play_sound("WEWIN.WAV")
self.game_end = (True, False) self.game_end = (True, False)
self.game_status = "paused" self.game_status = "paused"
return True return True
if not len(self.units): if not len(self.units):
self.stop_sound() self.render_engine.stop_sound()
self.play_sound("VICTORY.WAV") self.render_engine.play_sound("VICTORY.WAV")
self.play_sound("WELLDONE.WAV", tag="effects") self.render_engine.play_sound("WELLDONE.WAV", tag="effects")
self.game_end = (True, True) self.game_end = (True, True)
self.game_status = "paused" self.game_status = "paused"
self.save_score() self.save_score()
return True return True
def save_score(self):
with open("scores.txt", "a") as f:
f.write(f"{datetime.datetime.now()} - {self.points}\n")
def read_score(self):
table = []
with open("scores.txt") as f:
rows = f.read().splitlines()
for row in rows:
table.append(row.split(" - "))
table.sort(key=lambda x: int(x[1]), reverse=True)
return table
def update_maze(self):
if self.game_over():
return
if self.game_status == "paused":
self.engine.dialog("Pause")
return
if self.game_status == "start_menu":
self.engine.dialog("Welcome to the Mice!", subtitle="A game by Matteo because he was bored",image=self.assets["BMP_WEWIN"])
return
self.engine.delete_tag("unit")
self.engine.delete_tag("effect")
self.engine.draw_pointer(self.pointer[0] * self.cell_size, self.pointer[1] * self.cell_size)
self.unit_positions.clear()
self.unit_positions_before.clear()
for unit in self.units.values():
self.unit_positions.setdefault(unit.position, []).append(unit)
for unit in self.units.copy().values():
unit.move()
unit.collisions()
unit.draw()
self.engine.update_status(f"Mice: {self.count_rats()} - Points: {self.points}")
self.scroll()
self.engine.new_cycle(50, self.update_maze)
def run(self):
self.engine.mainloop(update=self.update_maze, bg_update=self.draw_maze)
def scroll_cursor(self, x=0, y=0):
if self.pointer[0] + x > self.map.width or self.pointer[1] + y > self.map.height:
return
self.pointer = (
max(1, min(self.map.width-2, self.pointer[0] + x)),
max(1, min(self.map.height-2, self.pointer[1] + y))
)
self.engine.scroll_view(self.pointer)
def play_sound(self, sound_file,tag="base"):
self.engine.play_sound(sound_file, tag=tag)
def stop_sound(self, tag=None):
self.engine.stop_sound()
def graphics_load(self):
self.tunnel = self.engine.load_image("Rat/BMP_TUNNEL.png", surface=True)
self.grasses = [self.engine.load_image(f"Rat/BMP_1_GRASS_{i+1}.png", surface=True) for i in range(4)]
self.rat_assets = {}
self.bomb_assets = {}
for sex in ["MALE", "FEMALE", "BABY"]:
self.rat_assets[sex] = {}
for direction in ["UP", "DOWN", "LEFT", "RIGHT"]:
self.rat_assets[sex][direction] = self.engine.load_image(f"Rat/BMP_{sex}_{direction}.png", transparent_color=(128, 128, 128))
for n in range(5):
self.bomb_assets[n] = self.engine.load_image(f"Rat/BMP_BOMB{n}.png", transparent_color=(128, 128, 128))
self.assets = {}
for file in os.listdir("assets/Rat"):
if file.endswith(".png"):
self.assets[file[:-4]] = self.engine.load_image(f"Rat/{file}")
def add_point(self, value):
self.points += value
if __name__ == "__main__": if __name__ == "__main__":

8
units/__init__.py

@ -0,0 +1,8 @@
"""
Units package - Game unit classes and factory.
"""
from .unit import Unit
from .rat import Rat, Male, Female
from .bomb import Bomb, Timer, Explosion
from .points import Point

15
units/bomb.py

@ -31,14 +31,14 @@ class Bomb(Unit):
if n < 0: if n < 0:
n = 0 n = 0
image = self.game.bomb_assets[n] image = self.game.bomb_assets[n]
image_size = self.game.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
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.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")
class Timer(Bomb): class Timer(Bomb):
def move(self): def move(self):
@ -51,7 +51,7 @@ class Timer(Bomb):
score = 10 score = 10
print("BOOM") print("BOOM")
target_unit = unit if unit else self target_unit = unit if unit else self
self.game.play_sound("BOMB.WAV") self.game.render_engine.play_sound("BOMB.WAV")
# Use base class cleanup with error handling # Use base class cleanup with error handling
try: try:
@ -62,20 +62,23 @@ class Timer(Bomb):
# Bomb-specific behavior: create explosion # Bomb-specific behavior: create explosion
self.game.spawn_unit(Explosion, target_unit.position) self.game.spawn_unit(Explosion, target_unit.position)
# Check for chain reactions in all four directions
for direction in ["N", "S", "E", "W"]: for direction in ["N", "S", "E", "W"]:
x, y = unit.position x, y = target_unit.position
while True: while True:
if not self.game.map.is_wall(x, y): if not self.game.map.is_wall(x, y):
self.game.spawn_unit(Explosion, (x, y)) self.game.spawn_unit(Explosion, (x, y))
for victim in self.game.unit_positions.get((x, y), []): for victim in self.game.unit_positions.get((x, y), []):
if victim.id in self.game.units: if victim.id in self.game.units:
if victim.partial_move >= 0.5: if victim.partial_move >= 0.5:
print(f"Victim {victim.id} at {x}, {y} dies")
victim.die(score=score) victim.die(score=score)
if score < 160: if score < 160:
score *= 2 score *= 2
for victim in self.game.unit_positions_before.get((x, y), []): for victim in self.game.unit_positions_before.get((x, y), []):
if victim.id in self.game.units: if victim.id in self.game.units:
if victim.partial_move < 0.5: if victim.partial_move < 0.5:
print(f"Victim {victim.id} at {x}, {y} dies")
victim.die(score=score) victim.die(score=score)
if score < 160: if score < 160:
score *= 2 score *= 2
@ -99,10 +102,10 @@ class Explosion(Bomb):
def draw(self): def draw(self):
image = self.game.assets["BMP_EXPLOSION"] image = self.game.assets["BMP_EXPLOSION"]
image_size = self.game.engine.get_image_size(image) image_size = self.game.render_engine.get_image_size(image)
partial_x, partial_y = 0, 0 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 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.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
units/points.py

@ -32,11 +32,11 @@ class Point(Unit):
def draw(self): def draw(self):
image = self.game.assets[f"BMP_BONUS_{self.value}"] image = self.game.assets[f"BMP_BONUS_{self.value}"]
image_size = self.game.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
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.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")

16
units/rat.py

@ -98,12 +98,12 @@ class Rat(Unit):
self.game.spawn_unit(Point, target_unit.position_before, value=score) self.game.spawn_unit(Point, target_unit.position_before, value=score)
def draw(self): def draw(self):
start_perf = self.game.engine.get_perf_counter() start_perf = self.game.render_engine.get_perf_counter()
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[sex][direction]
image_size = self.game.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
@ -114,9 +114,9 @@ class Rat(Unit):
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.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")
self.bbox = (x_pos, y_pos, x_pos + image_size[0], y_pos + image_size[1]) self.bbox = (x_pos, y_pos, x_pos + image_size[0], y_pos + image_size[1])
#self.game.engine.draw_rectangle(self.bbox[0], self.bbox[1], self.bbox[2] - self.bbox[0], self.bbox[3] - self.bbox[1], "unit") #self.game.render_engine.draw_rectangle(self.bbox[0], self.bbox[1], self.bbox[2] - self.bbox[0], self.bbox[3] - self.bbox[1], "unit")
class Male(Rat): class Male(Rat):
def __init__(self, game, position=(0,0), id=None): def __init__(self, game, position=(0,0), id=None):
@ -125,7 +125,7 @@ class Male(Rat):
def fuck(self, unit): def fuck(self, unit):
if not unit.pregnant: if not unit.pregnant:
self.game.play_sound("SEX.WAV") self.game.render_engine.play_sound("SEX.WAV")
self.stop = 100 self.stop = 100
unit.stop = 200 unit.stop = 200
unit.pregnant = PREGNANCY_DURATION unit.pregnant = PREGNANCY_DURATION
@ -144,7 +144,7 @@ class Female(Rat):
self.babies -= 1 self.babies -= 1
self.stop = 20 self.stop = 20
if self.partial_move > 0.2: if self.partial_move > 0.2:
self.game.new_rat(self.position) self.game.spawn_rat(self.position)
else: else:
self.game.new_rat(self.position_before) self.game.spawn_rat(self.position_before)
self.game.play_sound("BIRTH.WAV") self.game.render_engine.play_sound("BIRTH.WAV")
Loading…
Cancel
Save