From 5ffb77dd0002ce8bd08ec30dd19b72e4ed26990d Mon Sep 17 00:00:00 2001 From: Urban Modig Date: Sun, 10 Aug 2025 17:01:15 +0200 Subject: [PATCH] Initial commit --- .gitignore | 38 +++++ .idea/.gitignore | 10 ++ .idea/encodings.xml | 7 + .idea/misc.xml | 14 ++ pom.xml | 17 ++ src/main/java/se/urmo/game/Game.java | 94 +++++++++++ src/main/java/se/urmo/game/GameMap.java | 89 +++++++++++ src/main/java/se/urmo/game/GamePanel.java | 55 +++++++ src/main/java/se/urmo/game/Main.java | 9 ++ src/main/java/se/urmo/game/PacMan.java | 148 ++++++++++++++++++ .../java/se/urmo/game/input/KeyHandler.java | 28 ++++ src/main/java/se/urmo/game/map/MapTile.java | 26 +++ .../se/urmo/game/state/CollisionChecker.java | 39 +++++ src/main/java/se/urmo/game/state/Playing.java | 44 ++++++ src/main/java/se/urmo/game/util/LoadSave.java | 57 +++++++ src/main/java/se/urmo/game/util/MiscUtil.java | 31 ++++ src/main/resources/maps/map1.csv | 30 ++++ .../resources/sprites/PacManAssets-Ghosts.png | Bin 0 -> 3517 bytes .../resources/sprites/PacManAssets-Items.png | Bin 0 -> 1279 bytes .../resources/sprites/PacManAssets-PacMan.png | Bin 0 -> 1037 bytes .../resources/sprites/PacManAssets_Map.png | Bin 0 -> 11029 bytes .../resources/sprites/PacManAssets_Map_1.png | Bin 0 -> 7824 bytes .../resources/sprites/PacManAssets_Map_2.png | Bin 0 -> 8654 bytes .../resources/sprites/PacManAssets_Map_3.png | Bin 0 -> 8607 bytes .../sprites/PacManAssets_Map_Back&Maze.png | Bin 0 -> 6014 bytes .../sprites/PacManAssets_Map_TileSet.png | Bin 0 -> 4022 bytes .../sprites/PacManAssets_Map_TileSet2.png | Bin 0 -> 8162 bytes src/main/resources/sprites/pear36-8x.png | Bin 0 -> 313 bytes src/main/resources/sprites/sprite_atlas.png | Bin 0 -> 4884 bytes 29 files changed, 736 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 pom.xml create mode 100644 src/main/java/se/urmo/game/Game.java create mode 100644 src/main/java/se/urmo/game/GameMap.java create mode 100644 src/main/java/se/urmo/game/GamePanel.java create mode 100644 src/main/java/se/urmo/game/Main.java create mode 100644 src/main/java/se/urmo/game/PacMan.java create mode 100644 src/main/java/se/urmo/game/input/KeyHandler.java create mode 100644 src/main/java/se/urmo/game/map/MapTile.java create mode 100644 src/main/java/se/urmo/game/state/CollisionChecker.java create mode 100644 src/main/java/se/urmo/game/state/Playing.java create mode 100644 src/main/java/se/urmo/game/util/LoadSave.java create mode 100644 src/main/java/se/urmo/game/util/MiscUtil.java create mode 100644 src/main/resources/maps/map1.csv create mode 100644 src/main/resources/sprites/PacManAssets-Ghosts.png create mode 100644 src/main/resources/sprites/PacManAssets-Items.png create mode 100644 src/main/resources/sprites/PacManAssets-PacMan.png create mode 100644 src/main/resources/sprites/PacManAssets_Map.png create mode 100644 src/main/resources/sprites/PacManAssets_Map_1.png create mode 100644 src/main/resources/sprites/PacManAssets_Map_2.png create mode 100644 src/main/resources/sprites/PacManAssets_Map_3.png create mode 100644 src/main/resources/sprites/PacManAssets_Map_Back&Maze.png create mode 100644 src/main/resources/sprites/PacManAssets_Map_TileSet.png create mode 100644 src/main/resources/sprites/PacManAssets_Map_TileSet2.png create mode 100644 src/main/resources/sprites/pear36-8x.png create mode 100644 src/main/resources/sprites/sprite_atlas.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..7bc07ec --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Environment-dependent path to Maven home directory +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..44b0a07 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..ab15743 --- /dev/null +++ b/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + org.example + MyPacman + 1.0-SNAPSHOT + + + 21 + 21 + UTF-8 + + + \ No newline at end of file diff --git a/src/main/java/se/urmo/game/Game.java b/src/main/java/se/urmo/game/Game.java new file mode 100644 index 0000000..8dd8723 --- /dev/null +++ b/src/main/java/se/urmo/game/Game.java @@ -0,0 +1,94 @@ +package se.urmo.game; + +import se.urmo.game.state.Playing; + +import javax.swing.*; +import java.awt.*; + +public class Game implements Runnable { + public final static int FPS_SET = 120; + public final static int UPS_SET = 200; + private final static double timePerFrame = 1000000000.0 / FPS_SET; + private final static double timePerUpdate = 1000000000.0 / UPS_SET; + + + private Thread gameThread; + private final JFrame window = new JFrame(); + private final GamePanel gamePanel = new GamePanel(this); + private Playing playing = new Playing(this); + + public void start() { + window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + window.setResizable(false); + window.setTitle("2d"); + + + window.add(gamePanel); + + window.pack(); + + window.setLocationRelativeTo(null); + window.setVisible(true); + + startGameThread(); + } + + public void startGameThread() { + this.gameThread = new Thread(this); + gameThread.start(); + } + + @Override + public void run() { + long previousTime = System.nanoTime(); + + int frames = 0; + int updates = 0; + long lastCheck = System.currentTimeMillis(); + + double deltaU = 0; + double deltaF = 0; + + while (gameThread !=null && gameThread.isAlive()) { + long currentTime = System.nanoTime(); + deltaU += (currentTime - previousTime) / timePerUpdate; + deltaF += (currentTime - previousTime) / timePerFrame; + + previousTime = currentTime; + + if (deltaU >= 1) { + update(); + updates++; + deltaU--; + } + + if (deltaF >= 1) { + gamePanel.repaint(); // triggers JPanel paintComponent + frames++; + deltaF--; + } + + if (System.currentTimeMillis() - lastCheck >= 1000) { + lastCheck = System.currentTimeMillis(); + System.out.println("FPS: " + frames + " | UPS: " + updates); + frames = 0; + updates = 0; + } + } + } + + private void update() { + playing.update(); + } + + public Playing getPlaying() { + return playing; + } + public GamePanel getGamePanel() { + return gamePanel; + } + + public void render(Graphics g) { + playing.draw(g); + } +} diff --git a/src/main/java/se/urmo/game/GameMap.java b/src/main/java/se/urmo/game/GameMap.java new file mode 100644 index 0000000..5289d3d --- /dev/null +++ b/src/main/java/se/urmo/game/GameMap.java @@ -0,0 +1,89 @@ +package se.urmo.game; + +import se.urmo.game.map.MapTile; +import se.urmo.game.util.LoadSave; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.IntStream; + +public class GameMap { + public static final int MAP_TILESIZE = 16;// 16px from left + public static final int OFFSET_Y = 7 * MAP_TILESIZE; // 160px from top + public static final int OFFSET_X = MAP_TILESIZE; // 16px from left + private BufferedImage[][] image = new BufferedImage[13][19]; + private MapTile[][] mapData; + + public GameMap() { + loadMap("maps/map1.csv"); + loadSprites(); + } + + private void loadMap(String path) { + List rows = new ArrayList<>(); + try (InputStream is = getClass().getClassLoader().getResourceAsStream(path); + BufferedReader br = new BufferedReader(new InputStreamReader(Objects.requireNonNull(is)))) { + + String line; + while ((line = br.readLine()) != null) { + String[] tokens = line.split(","); + int[] row = new int[tokens.length]; + for (int i = 0; i < tokens.length; i++) { + row[i] = Integer.parseInt(tokens[i].trim()); + } + rows.add(row); + } + + } catch (IOException | NullPointerException e) { + e.printStackTrace(); + } + mapData = rows.stream() + .map(row -> IntStream.of(row) + .mapToObj(MapTile::new) + .toArray(MapTile[]::new)) + .toArray(MapTile[][]::new); + } + + private void loadSprites() { + BufferedImage img = LoadSave.GetSpriteAtlas("sprites/PacManAssets_Map_TileSet2.png");//473B78 + for (int row = 0; row < 13; row++) { + for (int col = 0; col < 19; col++) { + image[row][col] = img.getSubimage(MAP_TILESIZE * col, MAP_TILESIZE * row, MAP_TILESIZE, MAP_TILESIZE); + } + } + } + + public void draw(Graphics g) { + for (int row = 0; row < mapData.length; row++) { + for (int col = 0; col < mapData[row].length; col++) { + MapTile tile = mapData[row][col]; + + BufferedImage tileImage = tile.getImage(); + + if (tileImage != null) { + int x = OFFSET_X + col * MAP_TILESIZE; + int y = OFFSET_Y + row * MAP_TILESIZE; + g.drawImage(tileImage, x, y, MAP_TILESIZE, MAP_TILESIZE, null); + } + } + } + } + + public boolean isPassable(int x, int y) { + int row = (y - OFFSET_Y) / MAP_TILESIZE; + int col = (x - OFFSET_X) / MAP_TILESIZE; + + if (row > mapData.length - 1) row = 0; + if (col > mapData[row].length - 1) col = 0; + if (row < 0) row = mapData.length - 1; + if (col < 0) col = mapData[row].length - 1; + + boolean passable = mapData[row][col].isPassable(); + System.out.println(row + "," + col + "is" +(passable?"":" not") + " passable"); + return passable; + } +} diff --git a/src/main/java/se/urmo/game/GamePanel.java b/src/main/java/se/urmo/game/GamePanel.java new file mode 100644 index 0000000..205f10a --- /dev/null +++ b/src/main/java/se/urmo/game/GamePanel.java @@ -0,0 +1,55 @@ +package se.urmo.game; + +import se.urmo.game.input.KeyHandler; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +public class GamePanel extends JPanel { + public static final int ORIGINAL_TILE_SIZE = 8; + public static final int SCALE = 1; + public static final int TILE_SIZE = ORIGINAL_TILE_SIZE * SCALE; + public static final int MAX_SCREEN_COL = 60; + public static final int MAX_SCREEN_ROW = 80; + public static final int SCREEN_WIDTH = MAX_SCREEN_COL * TILE_SIZE; + public static final int SCREEN_HEIGHT = MAX_SCREEN_ROW * TILE_SIZE; + private final Game game; + + + KeyHandler keyHandler = new KeyHandler(this); + + public GamePanel(Game game) { + this.game = game; + this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT)); + this.setBackground(Color.decode("#473B78")); + this.setDoubleBuffered(true); + this.addKeyListener(keyHandler); + this.setFocusable(true); + } + + public void paintComponent(Graphics g) { + super.paintComponent(g); + // Cast to Graphics2D for better control (optional) + Graphics2D g2d = (Graphics2D) g; + + // Fill full background with purple border + g2d.setColor(new Color(71, 59, 120)); // #473B78 + g2d.fillRect(0, 0, getWidth(), getHeight()); + + // Fill the inner map background with dark (almost black) + int border = 16; + g2d.setColor(new Color(20, 20, 28)); // Dark bluish-black like in the image + g2d.fillRect(border, border, getWidth() - 2 * border, getHeight() - 2 * border); + game.render(g); + } + + + public void keyPressed(KeyEvent e) { + game.getPlaying().keyPressed(e); + } + + public void keyReleased(KeyEvent e) { + game.getPlaying().keyReleased(); + } +} diff --git a/src/main/java/se/urmo/game/Main.java b/src/main/java/se/urmo/game/Main.java new file mode 100644 index 0000000..34637d8 --- /dev/null +++ b/src/main/java/se/urmo/game/Main.java @@ -0,0 +1,9 @@ +package se.urmo.game; + +//TIP To Run code, press or +// click the icon in the gutter. +public class Main { + public static void main(String[] args) { + new Game().start(); + } +} \ No newline at end of file diff --git a/src/main/java/se/urmo/game/PacMan.java b/src/main/java/se/urmo/game/PacMan.java new file mode 100644 index 0000000..a51b9f1 --- /dev/null +++ b/src/main/java/se/urmo/game/PacMan.java @@ -0,0 +1,148 @@ +package se.urmo.game; + +import se.urmo.game.state.CollisionChecker; +import se.urmo.game.util.LoadSave; +import se.urmo.game.util.MiscUtil; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Arrays; + + +public class PacMan { + private static final int RIGHT = 0; + private static final int LEFT = 1; + private static final int DOWN = 2; + private static final int UP = 3; + public static final int PACMAN_SIZE = GamePanel.TILE_SIZE; + private final Game game; + private int aniTick = 0; + private int aniIndex = 0; + private static final int ANIMATION_UPDATE_FREQUENCY = 25; + private int speed = 1; + private boolean moving; + private final BufferedImage[][] movmentImages = new BufferedImage[4][4]; + private int direction = 0; + private int xPos = 14*16 + 8, yPos = 29*16; // top left of object + private static final BufferedImage innerBox = MiscUtil.createOutlinedBox(8,8, Color.yellow, 2); + private CollisionChecker collisionChecker; + + public PacMan(Game game, CollisionChecker collisionChecker) { + this.game = game; + this.collisionChecker = collisionChecker; + loadAnimation(); + } + + private void loadAnimation() { + BufferedImage[][] image = new BufferedImage[3][4]; + + BufferedImage img = LoadSave.GetSpriteAtlas("sprites/PacManAssets-PacMan.png"); + for (int row = 0; row < 3; row++) { + for (int col = 0; col < 4; col++) { + image[row][col] = img.getSubimage(32 * col, 32 * row, PACMAN_SIZE, PACMAN_SIZE); + } + } + movmentImages[RIGHT] = image[0]; + movmentImages[LEFT] = Arrays.stream(image[0]) + .map(i -> LoadSave.rotate(i, 180)) + .toArray(BufferedImage[]::new); + movmentImages[DOWN] = Arrays.stream(image[0]) + .map(i -> LoadSave.rotate(i, 90)) + .toArray(BufferedImage[]::new); + movmentImages[UP] = Arrays.stream(image[0]) + .map(i -> LoadSave.rotate(i, 270)) + .toArray(BufferedImage[]::new); + } + + + public void draw(Graphics g) { + g.drawImage(innerBox, xPos, yPos, PACMAN_SIZE, PACMAN_SIZE, null); + //g.setColor(Color.RED); + //g.drawLine(xPos, yPos, xPos, yPos); + //g.drawImage(movmentImages[direction][aniIndex], xPos, yPos, PACMAN_SIZE, PACMAN_SIZE, null); + } + + public void setLeft() { + direction = LEFT; + } + + public void setRight() { + direction = RIGHT; + } + + public void setUp() { + direction = UP; + } + + public void setDown() { + direction = DOWN; + } + + public void update() { + //System.out.println("Pacman current pos: " + xPos + ", " + yPos); + updateAnimationTick(); + int nextTileX = xPos; + int nextTileY = yPos; + + switch (direction) { + case RIGHT: { + nextTileX++; + break; + } + case LEFT: + nextTileX--; + break; + case UP: + nextTileY--; + break; + case DOWN: + nextTileY++; + break; + } + + + if (moving && collisionChecker.canMoveTo(direction, nextTileX, nextTileY, PACMAN_SIZE, PACMAN_SIZE)) { + //boolean b = collisionChecker.canMoveTo(direction, nextTileX, nextTileY, PACMAN_SIZE, PACMAN_SIZE); + //System.out.println("Can" + (b ? " " : "not ") + "move to (" +nextTileX+ "," + nextTileY + ")"); + updatePosition(); + } + } + + private void updatePosition() { + if(moving) { + switch (direction) { + case RIGHT -> { + if(xPos + PACMAN_SIZE < GamePanel.SCREEN_WIDTH) xPos += speed; + } + case LEFT -> { + if(xPos > 0) xPos -= speed; + else xPos = 0; + } + case DOWN -> { + if(yPos + PACMAN_SIZE < GamePanel.SCREEN_HEIGHT) yPos += speed; + } + case UP ->{ + if(yPos > 0) yPos -= speed; + } + } + } + } + + private void updateAnimationTick() { + if (moving) { + aniTick++; + if (aniTick >= ANIMATION_UPDATE_FREQUENCY) { + aniTick = 0; + aniIndex++; + if (aniIndex >= 3) { + aniIndex = 0; + } + + } + } + } + + public void setMoving(boolean moving) { + this.moving = moving; + } +} diff --git a/src/main/java/se/urmo/game/input/KeyHandler.java b/src/main/java/se/urmo/game/input/KeyHandler.java new file mode 100644 index 0000000..b495307 --- /dev/null +++ b/src/main/java/se/urmo/game/input/KeyHandler.java @@ -0,0 +1,28 @@ +package se.urmo.game.input; + +import se.urmo.game.GamePanel; + +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; + +public class KeyHandler implements KeyListener { + private final GamePanel gamePanel; + + public KeyHandler(GamePanel gamePanel) { + this.gamePanel = gamePanel; + } + + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + gamePanel.keyPressed(e); + } + + @Override + public void keyReleased(KeyEvent e) { + gamePanel.keyReleased(e); + } +} diff --git a/src/main/java/se/urmo/game/map/MapTile.java b/src/main/java/se/urmo/game/map/MapTile.java new file mode 100644 index 0000000..ade6967 --- /dev/null +++ b/src/main/java/se/urmo/game/map/MapTile.java @@ -0,0 +1,26 @@ +package se.urmo.game.map; + +import se.urmo.game.util.MiscUtil; + +import java.awt.*; +import java.awt.image.BufferedImage; + +public class MapTile { + private final int value; + private final BufferedImage image; + private final boolean solid; + + public MapTile(int value) { + this.value = value; + this.image = value != 0 ? MiscUtil.createOutlinedBox(16, 16, Color.blue, 2) : null; + this.solid = value != 0; + } + + public BufferedImage getImage() { + return this.image; + } + + public boolean isPassable() { + return ! this.solid; + } +} diff --git a/src/main/java/se/urmo/game/state/CollisionChecker.java b/src/main/java/se/urmo/game/state/CollisionChecker.java new file mode 100644 index 0000000..fb93ff4 --- /dev/null +++ b/src/main/java/se/urmo/game/state/CollisionChecker.java @@ -0,0 +1,39 @@ +package se.urmo.game.state; + +import se.urmo.game.GameMap; + +public class CollisionChecker { + private GameMap map; + + public CollisionChecker(GameMap map) { + this.map = map; + } + + public boolean canMoveTo(int dir, int objectLeft, int objectTop, int width, int height) { + int objectRight = objectLeft + width; + int objectBotton = objectTop + height; + return switch (dir){ + case 0 -> isPassibleRight(objectRight, objectTop, objectBotton);// right + case 1 -> isPassibleLeft(objectLeft, objectTop, objectBotton);// right + case 2 -> isPassibleBottom(objectLeft, objectRight, objectBotton); + case 3 -> isPassibleTop(objectLeft, objectRight, objectTop);// right + default -> throw new IllegalArgumentException("Invalid dir: " + dir); + }; + } + + private boolean isPassibleBottom(int objectLeft, int objectRight, int objectBotton) { + return map.isPassable(objectLeft, objectBotton) && map.isPassable(objectRight, objectBotton); + } + + private boolean isPassibleTop(int objectLeft, int objectRight, int objectTop) { + return map.isPassable(objectLeft, objectTop) && map.isPassable(objectRight, objectTop); + } + + private boolean isPassibleLeft(int objectLeft, int objectTop, int objectBotton) { + return map.isPassable(objectLeft, objectTop) && map.isPassable(objectLeft, objectBotton); + } + + private boolean isPassibleRight(int objectRight, int objectTop, int objectBotton) { + return map.isPassable(objectRight, objectTop) && map.isPassable(objectRight, objectBotton); + } +} diff --git a/src/main/java/se/urmo/game/state/Playing.java b/src/main/java/se/urmo/game/state/Playing.java new file mode 100644 index 0000000..38d55ad --- /dev/null +++ b/src/main/java/se/urmo/game/state/Playing.java @@ -0,0 +1,44 @@ +package se.urmo.game.state; + +import se.urmo.game.Game; +import se.urmo.game.GameMap; +import se.urmo.game.PacMan; + +import java.awt.*; +import java.awt.event.KeyEvent; + + +public class Playing { + private PacMan pacMan; + private GameMap map = new GameMap(); + private final CollisionChecker collisionChecker = new CollisionChecker(map); + public Playing(Game game) { + this.pacMan = new PacMan(game, collisionChecker); + } + + public void update() { + pacMan.update(); + } + + public void keyPressed(KeyEvent e) { + pacMan.setMoving(true); + switch (e.getKeyCode()) { + case KeyEvent.VK_A -> pacMan.setLeft(); + case KeyEvent.VK_D -> pacMan.setRight(); + case KeyEvent.VK_W -> pacMan.setUp(); + case KeyEvent.VK_S -> pacMan.setDown(); + } + } + + public void draw(Graphics g) { + map.draw(g); + pacMan.draw(g); + } + + public void keyReleased() { + pacMan.setMoving(false); + } + public GameMap getMap() { + return map; + } +} diff --git a/src/main/java/se/urmo/game/util/LoadSave.java b/src/main/java/se/urmo/game/util/LoadSave.java new file mode 100644 index 0000000..adf9a0a --- /dev/null +++ b/src/main/java/se/urmo/game/util/LoadSave.java @@ -0,0 +1,57 @@ +package se.urmo.game.util; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; + +public class LoadSave { + + public static BufferedImage GetSpriteAtlas(String fileName) { + BufferedImage img = null; + InputStream is = LoadSave.class.getResourceAsStream("/" + fileName); + try { + img = ImageIO.read(is); + + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return img; + } + + public static BufferedImage rotate(BufferedImage img, double angleDegrees) { + double angleRadians = Math.toRadians(angleDegrees); + + // Bildens dimensioner + int w = img.getWidth(); + int h = img.getHeight(); + + // Skapa en ny bild med samma storlek och stöd för transparens + BufferedImage rotated = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = rotated.createGraphics(); + + // För bästa kvalitet + g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + // Skapa transform: rotera runt bildens mittpunkt + AffineTransform transform = new AffineTransform(); + transform.rotate(angleRadians, w / 2.0, h / 2.0); + + // Rita originalbilden med transform + g2d.setTransform(transform); + g2d.drawImage(img, 0, 0, null); + g2d.dispose(); + + return rotated; + } +} diff --git a/src/main/java/se/urmo/game/util/MiscUtil.java b/src/main/java/se/urmo/game/util/MiscUtil.java new file mode 100644 index 0000000..5dd273d --- /dev/null +++ b/src/main/java/se/urmo/game/util/MiscUtil.java @@ -0,0 +1,31 @@ +package se.urmo.game.util; + +import java.awt.*; +import java.awt.image.BufferedImage; + +public class MiscUtil { + public static BufferedImage createOutlinedBox(int width, int height, Color outlineColor, float lineThickness) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = image.createGraphics(); + + // Optional: Disable anti-aliasing for pixel-perfect edges + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + + // Set color and stroke + g2d.setColor(outlineColor); + g2d.setStroke(new BasicStroke(lineThickness)); + + // To avoid clipping, draw inside the bounds. + // Adjust for stroke thickness to stay within image bounds. + float halfStroke = lineThickness / 2f; + g2d.drawRect( + Math.round(halfStroke), + Math.round(halfStroke), + Math.round(width - lineThickness), + Math.round(height - lineThickness) + ); + + g2d.dispose(); + return image; + } +} diff --git a/src/main/resources/maps/map1.csv b/src/main/resources/maps/map1.csv new file mode 100644 index 0000000..28530d1 --- /dev/null +++ b/src/main/resources/maps/map1.csv @@ -0,0 +1,30 @@ + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,18,19, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3 + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1,20, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1,17, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 9 + 4, 5, 5, 5, 5,10, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0,11, 5, 5, 5, 5, 6 + 0, 0, 0, 0, 0,12, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0,13, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 +15,15,15,15,15,14, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,16,15,15,15,15,15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 5, 5, 5, 5, 5,10, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0,11, 5, 5, 5, 5, 5 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0,12, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,13, 0, 0, 0, 0, 0 + 1,15,15,15,15,14, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0,16, 2, 2, 2, 2, 3 + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 9 + 7, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 9 +21, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 9 +22,24,25, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 9 +23, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 9 + 7, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 9 + 7, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 9 + 7, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 9 + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9 + 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6 \ No newline at end of file diff --git a/src/main/resources/sprites/PacManAssets-Ghosts.png b/src/main/resources/sprites/PacManAssets-Ghosts.png new file mode 100644 index 0000000000000000000000000000000000000000..b729d238b9503e424888a6104114c88c1020babc GIT binary patch literal 3517 zcmds(cT`h%8^;5pGGvIz5HuiCq<}0bn-mMB7=_4^Az%R;2}=P5$_PWGkr4p}WCgH@ zED>2!0s$pVAy!BbWbYv(0Zf3KniU7@LQnZO(uA71zMY*gFNe#SppLvmJfjS^jm zN2A;j_s(LtJIxB)#8O_|OoPNpi<{pQun#z*B=ke{+eZ1qfazCB%BK4CXjuhGO#8bh z>Y~fH(oVLW1%43Y;)y#NlV31Z^vm6m;7@Nx^t6zx_|ffV)Oc9nT(;gC-e7I4p|R14 z3;Yd`7KiY%v+G;&I7cfedk3c`L60Ng#%09Xu*^-EG-*7P%_@zaSew?-j$}?EDb^|t z8!TpTYSj2RZdBdeRi77N0**;4v{aLcwRxN`;$*!LHyXx{DB2gB#yJ>_wMzl&EIwvL)e;;$&lFZxDE;ZQ5fEMR^1170N?yPME_cta3yi^ zCO`6)Qr+5o$VNqwP@07L+Z`N%UE9ED_PdhV*1?2RO@LN{+Cb@ko z=(Xud5Oi&Ny~63Clf>iQ~PW!)0^!C zIZEtZbqP~RF#=YE->NijZjcBrLH%3=EJqN!%gdKkU{J^3R*(k`C6rL(irrk`RWr-k zI#~)_1Olw_$7Fnv2xE7<`k3R4LTt-83HBl1)bBVCD>Bkg04l?O^~UL_R*PrC+RIk? zKOJuyA0r*UdZX~+kPUZE0e7xLq-#>7?}v0v#!Scs}6)<(Ci ze@RuJ`#NUpd|gI0G28!E-Lcmr-r|*u=ib(MggR+7eP`A_;L6+e2yp}D>kYgR_RVv0 zt$BY8-7O_Qb7qz_ESO{5_b9Pr=9*hc8_MIsP3_1EY!1H7y@K^HGcD*zz>Cca)E6nh z^SO(dzu3rdBS(!$c6VX65F-MZ%a>)5tt@>F+3g4Er3Yd_eFhkmF>x~_=(9kP#(+pu&c*?$g)P$uv85} zQ)(e3;^bQ<5P#Z(h=$7kZ+HWH#;Bo6gF3y8{>vM%ogunT9-A>rD%+FeG2H4|kpqp| zh|_^{N21ZUU(19p%C6HlklHUg;Rm7#ICPx}X5@2zM#POdIRTqZy8=Z~aNqXo|3YZu z^lz&C`tc680*)K#VSw`NK6$h(3nUcV)X~?Sa!wTAurDS%2l2cWU4H1J zhD^{IU-Hqu+c2o&+8>wi)j_Lq|2h6%Vo8%os#d|oz%Yez4LWRCi@#o_&3d5qeWyz| zu2xz%B1cOK+tt%-jUl(6o<;#qP`ywL(TS<7p}2Tq)^pLB{5Nx4Z9F}8I%MfhTv8H- zfDa7({o+BuIC4W!&IIUzhMVJQgn4I0ZbBvKjuI^iia9YGzrA?*-@*e{A1A!m=|4t? z7&{_L2gXEAR}D&tTNV4PP1fofSx%N)menut<||N?hg|!_{hP@{s6&C3j`$}6CjH5? zUc^nIqf$0ua;K2zT1#pxs6ECtp{UT`-Ms-NWa9nC2QY7)8#}s4%@b)E5k;b9NtfEm zj9TLWnrK4p&SiJYcaOTe-qn|W=I9@?wA{XgzqC$NCi(eX2ww|EJN-$IaU=TcqJq6mSX0r$>D0X;Q1K}hpY2->#YS4 z4jXc2b`aGp9u&m{SYd*=P;`e1eDdMBYgQ!);5W{OX&Xu~ZINE%eb_Zn4fFdis}MQ7a-L5IQ2 zqgpZccg?r$ z!Z&%ah@FDHS=$^iO9ahfiHm&te{PP)$h`OOGZ`HQXy-q(QhXxBb9y@r*JQV64s2ei zyDBjiyhB#uV=$RRf`KzdoJoQscb-&}0tYN>=zv1NGKa4cqhi0I832mCzP&I_`3QA& zUV*wM7`NlF4G?SpO;NM^Sqq~6uPins*zTQUs{%_TcvXFvBU6fy^!IEL2~wwo>2T=& znMuDzt4Ry0xw5=nL{+V^J&yt|rpC=}+1;WAO5f-yh_$hUgf*%KZF4iw?AbGJEtaW- z>wM3rB6!=@=8=4oIaAe9&zX|zrS|`nOIe!#kufeKGcx)$YuDABG9hyGtiKhA==z87z4jf^|tOdKrv9XQbp|wh1 z;iTKZw`Nx&CP8qi#S2;5ab5ZC*5e)tS@2<_=BSy-!>!<^AgZoQL~?;^kjU<L?@o-3 zxASyH#Py8AbG z%tH}Fpc;mT^cwS);oe%g=6w$C9u89%$;mQC*suI#>emi;Y#ZDMUOn33K34IS6v8@G z`=J4|W-c;Zv^08Plp;bk9}6%-;jdQ9H-~0yu ziKR>erX+N3M)uQA-JGQ=q|)S0w`%UUUiif7%_GV7RfDMZs-*Bhef9d}i;4xg_kN{l zY%si@%%0`9;t-&jthBfs%{s2MaJIxeIML7?XQm5VQ&a_hG-(#9Y w#CCZcfnhn|Px(xk*GpRCt{2noVdMM;M0R4FTINA&sMpD?<*gOBbq(bTPKzVdb{0D!jN zv_$!Y>^`5bTPCfptbgLHN@Hc)>6?^>?rAoM&f(X?HwKIHCA7cGWQh@l{}Evl{4_ zfUZe=N|OnwY!a;a0I*ZJghIWfWCB)v(fIf_ga%+EXLe#VnmkIYh)Lpq?{w3OCic&w zW1?wy93#trYxg~~Sq-if4*&qSy^FX~JODIS10XIwn^)R>oLV;$|E+g{uRjViUwuK# z1O!EY5`7~r+fJ~a3)8puhZ7%&N2F@qtx7h!zW39g%-!TR8oq16>Ge&#+#SQ!kuf0U zaU>KUi2fsGHP~6TvH#gG0D#QWRA0K8JB!TH6fWPCwea+KXYvPZzjCiPw%;a&<<77d zBz~qC3NW7;O#Jm6u(;BT{Kb_n)^qa6X6v%zFVs7zwH`&+t8*_Vw!!wz_D@_Lxgf1C z6Q7_wl~Y1yX-X-NM;QIYlU0D<-0`&irq%iI%~+o2wXoOT5N-s|@EOCv3%Iz_MfJwKgtuCfW*J;UF;KIl$T_JB%xJI za1<1abJBZ41MGVp0Km1~P_+5XA!a8=QzMwIE4pUI(SHY7Cf&dy&p3`!*{J~yJ4EdXCDV?%Q#zKB*H?yqqUJ61m1vy z!afd?X!}izJhiwmG*D|j z8fX>qe!d{R$L{Q9!n2P8(MfGpH)QXv{!Qd|C7ZPfWm^1PFEmC=;J(`%Q~| z8N@>7ND{B@H?0kn0^I54y>b100KkveKfuP`U)tg)ML(eMEr5T$s?#~u9kd>g&g(dUOqFq&dp7^U=UrRXICQrAGwNF3B_VzdU>egLpUGp(W0DsKW5uQ-}7;}^i^D)U_ zFc=I5!^!5zHV1(l-$+@G{zl4h^c;yOfm;n8K8SyfJ9mEEnBW+aC4uZRQ~g1R;s1xw0G6|6ojc$AU7cCBPcCK? pc*-%yz*CNS5o9nJ3Px&$4Nv%RCt{2oy~FMFbsu}ovp(CI2Cw&cL&>1?wMToqV$tCyoZctw2UYLBz_3# zeYe<29t1!nMG_Pd00000&d5u&0U4Pd_vhN@uW#?^{Q0}}52Ky1rthIWJ?_uz?XvzI zecO~N5yXbhj;}f4^W%$%?3}Qr@1b40?$Qp+B&gkdGZJl)kz5B5**GCG0MctG(oe*_ zo3BNmZJ@*fOGC7rAk~l3o}Evmn*dh+XBpTcE-}JN-&1=Tc%t~=&+PeN*T^1mt`U~{ z9@?V@e`d=EzpTZHzWc1bfs3~O=f~HNz*u0Z;o<-0$G}n1x*IvpUkiTJm}igc?LrgX zpQU}(1n@FIOW(2?=ID87T9Cd4@DBW%rnav3%{Q}l6Q)goh`^6Z&p1RS0Xzme_rjH377ZkWR=* z^_Ph-J?>BIM6gZ*FVeRFC0dEVNkGda@VWsv6F|#|*6G+D{jzJY!cxP-|5yxC(jIj^ zpnEZ>#|SJ3A7nYW#RzN&IoO5}t`XQ0cHk{x93#%WDbzXvEl6YNNJJ+;0000000000 z06+^VCoUoXeLD<+5R@iXlEn%}g%b(p6pk_d?Arjrl!zs43Gp$_2D-VwA$wu|S|64)%s z&~-@EnW}Wx0$O`rZI<8@2@69;IW8pv>03`NZPBEwIP`kEgcf{8zc4yeplb|U8n(xB zEaExxu08o=eIiPm06+&(6ZZW3=SPNHzA|->=q}(0bd3R`>*k^Ze}n`Sbpg=c?I z5eEH^yz^BqEA|d78NBoICFyOq%F7oA{P{xGhcvgzSzhY>T}~>)JEsqYHoj%CcZ*b* z`8{d(bSEvBLRV9nGlPCg@JrppClNBhQEt(G`IYC98&# z;r#g)iZnpT4?N`n0FghTh1Af17#a|k1B4}90SUGLdqI$O)Eyjt)i*v8IH7JpX)wsE zlh*+@Z6yF(PXHn(03j(rXw!dE&|wHcDL9K(4gA4E3+c)?g|9P)hPXq}+r8;H8)!TF zj_32$%jZ_*nGHhW{g}_Tt#+ZaLU|u5)Uw>Yo)NiRu=3|U{&nn}btyQsg+%=Qfp%Gd zQk$38vSpkfwHz`b0+*AK9nWms9qD<&)@;?bJDX;0s;tn^f|N9Uy?z)4Yvqv^99Ihp?DEFZ}b9zwOsKq+gB%o~aw(6pbEiKe{ z)w~PdzM9#$y*R5Bk6BQ_q{uV9i5FJ7ZIb)LX6;qgWCCK$UBZiO-rHJ5Q5F|59f%UF zf8Oz@5eP+GR6KD~7%qo}C`Ywhw{7jS6(1~?nHjV-;`Qm9mYWU)T6|4&M_8!tjV0Ek zN{toR@!ubjiU~4jS?J32Hy#%SSJxpHtevrH6cfgF#^4#fn}D? zk+2=R0K1+!DY=SreRFgYOUFf&d35ra^yP(1IqF@4ih=dPDzOdfHOMNxJ& z7ua?yP7c0IG5X*nGBp@5jG*MQk4;3CD#xZcyeY1Jv=EsNRsu4;9a=u=bYpIHP6wpY z>UHPDkKJDwo`OeFxwWb&g9*_F-ef`btnk+P8eGZ!o{ma}l?FpWr#o(!_4Us(m=|}n zB%mdSMZ^Z*<#{FTM}z;`m4rwt{3jRkgdRmSs{Q{R(EL~6Nfo!n zUQ3e7_57>wH3G=0+3PrT=LBccsIw!YuKg;;H`P$I-iJ8za97wa!e8xM3)iJqE*3fI z0fS!Oo43A71L1NZ)kIXfyQbRuQ)h&)fqRCoo`~34EvnB5IOrKb>-QXcr0ycaNj@IWVUhe_} z)MEB~62N;~yZ&PkI!c$UmRM~4`#0=bMQnf$TLYYs-vAu~yvM-B-~USx{};Ibw@nCX zmi5e{n6BhVAK+@ohiuZLy7@VwgK#15PtW~e;tPeC7Z0?7qEut5=N8xTEhlJ`?KRh| z%@_sUk1#fq@CZO6gvz@|M26GG7q3}cXy4qCG$#5&)IF0f`6X|E*4?mKc{I8G_oz~c zxIcT#3BRO|`q1}6-we&wxwN;~()XeP-XBIVwXp_++OwZ$W`*WX07R0~0gQ@L?9pTG z$F2;>e6bgSFQVV}h5Mb{qR)6+7s7wnBOXm>9woctL+Ubg2i{0ji_N(L4z=)GoX^J$ zJ@sq3W<>bCg41!o_Y1>Kem*8g7=IJH+g)15AU^r1_Gs0XjoW&5{<+O$=MgjIf7qft zk(Kp@jPdma<%vW_38HM8?%=XI&;lI>j-wD>D+wq*aU8>P$UOzk-U(si;fw$-;jYxGYcmJLvs~69D3`4pew4K~ z&`J&)z3kI0pFUp`Qo#*oC{cBx`1F-h9 zoDcbAUOx?*!OnVfnNu(Cd?%{&cqIF4*}Ls=23p36A4b|*SOZ8~dp~~845TG*098_s zDrcuz4g)ID$BoF|g~W8_VhlSi|2zkGj&JCc$a`AOEhwXmToz}J=o?c)x1`|$oTgU? znx=eq+jfnBU3v3om$I&=knkrthxSYy9n0~cA(|eST6663X)hf|-V{3e)6SEg6=UUT zWzm7c@b#tS2#bW!Hh608Nsd)wHMkJe4X~GXdgZe~@D}K9`_mhu!OC@|fpsLU?BYOq zhHzmwINJAJdRom*dcr>Zn$DO{UrfO&E~~z-mEW^S7)&bWzWHktJm=Zhbs>{W&75!u zFR*n>9qSz?8A+~mPguQG%Jmp-(xDI^df=P1I2imK-N2s3#<}ok%lJoNWt3;@Rr7%h zbXiHki9Re}cd3zQVw)AC9W)&;NRNkzd(nQilp5LB@Y^9jj+K2qw}6N@qC+~I=#{sS z?T7k7e@YE#UH>qg;$M-Ye;xY0>xIdW3FTgd(UJT8PtVibDsm$^4meckFkW>70b^qJ zj`nqnIVde2UR8Xk{95cR9a_)p_u*6R+Y@eunf*JjCGwkdNc{QqCt z672NGdL}WDEMcKzb~)>34MbEt0(5|z1y5Afy$C?J(Z38c&MFh85*Qa8MNdUcBs#c6 zOq8BiBv6SDGirWF{@SVuBB|9&X8f6uNvP?CZxs?DIqRvH#dLr&Ef2uPS=RQ?hBoT> zHwI)pXCd6yWvoc{c>U5MXsyC{qj4PBXg9g&M;4W`NcuwAySz9I*sGxHm>L#yRY!_A zH8@S`f*9rnX7_;;^}A+_w#~dNh93Aop=q&Yl?ZDujO5tkAjSF1S+lH!D}MnhpN#CM z*%Z!lF_GMCdmj)xPClkBvH6uy*4mDONPeCR-#c*_G$0};XqUx;b684xf8WFxZ;-9| zwrj|uYd=mrA~9qr@8G1%n-Ds?zy-X+3`jpswaAgvkyFb;mxk5_^w41$v|(H%_o00~ z-wuZ=n`U3XZ8}z_H@43|tRYHT$z!CrQsuZT<37i!|8J+}jo@9-?NEhq~;&i)jsTM^o9RP?f7 z3aza&ij0VH9#AItV({hmgZ%7j#+8nS`n})U25}&vfcAp@4XR9MSOI6dGOp2~*f|Ho z#Rn_`5x#O>rXS~D@$py;k3!?wD1t8TdOI^Q%w9P-q4j4cpOHR6jSA5t;W+z?_1t`7 z*3~~hbR&HPK+*k|K=~fAqx*yqyp_(^_6MJ3T@kn-i{yk|_1vC`?9)Lg#su-PKDuRJ zjUz8yVk9ye11vo~9>g3A|8to5dqCkKBe+|MMa; z`&deexKfo#t?y00jZ&WswQU6r_YBQY1L|(t9`&jcQX_C!-}dVR{j%TSEeZ;}>d`>*A|d ztF{=u+-;NPq;RkWdAF!cWq7e#0ro9rMpX7BRJ%7O(cU3zk zj&%gjrQW34N3T`h_~cGJC{!1;E1mly?X>K@eH{Hja)j3X0K|)#To1SwzO-;F*wd4&AwC*g+R`(*$mR@}MsiDo^?vf(N|1iU)2N*jAF@ih=hxeS zkpj(1T1SK8&gLF!^2Fw`GpCEhO@?JC8bX&&v)Jt}{0>=(Z3*IM5}*U)3c>eY5k<&S z6wti)s`|T;!tldzE=?1v*iEK#8~p)*sE)viY`QUT0%!o`nrb>Tr= z(gX#H;NLcr3YBpE`AZA_7Oi|tIS$WX_;6^C)afcQDN(1L4Qcb_wMwG3jfml9*R%88 zOy$jPxn_X*jh1M}SqXEbu$<)TD4xH{tVQt`@1bP>*oRgObtSdHUkVkM!pId4CgN6P&D!6#xTy*?=-?uc|3P3;bJ?R zIYO(omvaK`g@-}r#;DgoPgNlRta zWrh7m3@>{?Lp$r5nsD)_5`Cq*RN7l!>|W$^D3tBBObQ(DDdz5Re9;N`R9M4Y*ND{Rz@8g%M`bGYT-jS=X z7N&f^WVBDj(&r`L!FaOF_v=wt;}X@~34!=J&oT!3DYqAro?p&m3@UfIpA}7y^!0m) zD^aAqjaodDBO;sb+rdM%t|&u(8mZ!+AnZ~@E0$Nk9$KXum!gU?2svJs%lw=cZNnTNrx`Vt>B}ShoYhZ-S*hSpf%bfu7D1Bm{b$2X;KDnUuq)wZzh?naup=+zEe72246ki)jwMa(tnow(x>?!=V+XmX)^(I_{3yb?w zR9G%vM~uOiKE&XC!CQ(i$ki<)7sZoN5Cor-a}O>>hC(>~ZFtoNe!W_B(`MIW-L?3| zmfMVtk~#gf~90Ih=!VBqWYx&89}#f_Y^QZj%q zWh=jdpb{0P3EP=p4|=&AM*k=;;t0!#*+9d4L3u;L?1?NoccUbah_b+nWHqnQV}NM+ z!lNSOon+RNIYoD?wQNMD*z z;&|c(cl;jGpk_G@a%`r}kllgoYFL>G=EdNnR=KE!MJ$TLDuuEplq__S91t(LA(w*g zg&R`yrhfGxSJ;^0Jd9msxd!p>>+E+@Rc>N|wVkLHaqWA{`SQ%m6*h)jD68^#`VPWH zyHm^t1Vhu>SR@AIdXA+qAM~aOHEjj~cXMXSwgG$dHym%dOPh;mCE8mrpgQ@CoGgq9 zc2m8sNc7%-7)Ar-kcTm1nH#818n0!96Z+fHZZW8J5=5D-tkvajU>?RPeie?IN`Ue> zVJWr);u|+;{L%O~gTlSqvm3vVoy>1=o_xl-gIeh)HYGPrSp2TP(NLQ)idbckJWTFx zs@?25=q@!*r_ed1p4!_;RN>+Km8eQakVTq@^=3+sTq6ljTCU9Q&~4n!-a!a{U@Ls< z{B)r4z7v@H^A)zjcGHb+8%F7=7hxMkxX(zF2Ebs2nUrtXx9#2>C*t9|H9<3X<&1K! zmmr8(OjRQI9Y^*&TF@F+H>+FqmWF{_>peSG41v88XpSVi-G5HhgQx34O9d4)e! z!M#JsAT9ke!^1DF>=PGqB7nU{gSSBnG>s777r1S8B>e98W&RyJ$V9VdDMewwICHpw zP?p>3I@D0?-aDB=I{AE8`2b(J*6SP26@rEP#ZE5yp4giAfCr^N@6`}WKgAXb`IuK^ z8z^^A(s7nQlyKB^8{wgx9N~$Q`^^-DbX6-WzOV%47?{Dvc*RqCM>gz%z-SWO&)&)# zw$eLsyZtX>y2=gQjjN)Ye-l_;h2ZQ$aYRascJ6!7yvqmQD-@Rs1s#@-$Qz$b*rpO) z5zykJH!Qwz)g`K$KK!K$wNlpF%%Gj{peB~WP7zq0zYUEER#$ILtZUm`$1lz;H>9#y z*vJldGPQ>I9CmxTe!xDoD!(0zGA^@vA?is8Mys1$XGK*~ID@i#Fq`z3P617KUNtf` z{D?E%TX!`Cn_^zfkVi1dQ<5oB7;jAU{9#ON7ym2S4~248zOSv+EG75bqvt8AusAq{ zV$J~Fjz0Fq7sb$lP-iuj?PnZDUmR&U2$!jy9dFKGl@lN*t|W7MTt>RI-K>OWx1fOK z=mgtmlpr2|{0MGeS5Zihp(aHnI_SN)-+P)JzDglD0!|&-( zW|p%%$$2>^+}f-+(N<=SXxe5JqmC;*!+q1|_V8x6u-?C>mjVYt4|V0zomb#-fgxL* zW$Lw7soBFw4(Pvr`R3STHt5ePGl4?_L$MXD=`$HoOLG%Gn)jANH{86iBIxGhu_rZ} zgH$&KH%W~UHY0Uga*~2mZ^+4bp#>>QC@j6>?@)KQPY53JWXU6*&qM8(=;r9 z(E0Z7_C8z?738G^GFhQrS3K_^|h`ee&%Wp?!)_E?u3^O##Z z!J$uOUAWzGE+_nL@6^$wh?sYguXZ|vsjW|zs$SaYI*Cr)gU_Q9rDNKz{zyV>v$!F) z)wa==`9CoD&P|XkHy~f4YaBkt6RHy|L$@mOxZ+KyYDD*MLFTXT{!-5@<2n3Pd|`(({U%d z*Kl&)0C}t$Jj47wN;jpiS^#Q~axXX@LOZ7ks}=m(QaK_j{V#N>?}X6@i--x$jnubQ zld`sA39?2{oG@BBAh(k!NN15ChwHYUBQ=&sbJM^fCcgH(s)R;N+?GdyX*}Qva;_L` zOy1vA_7GHdgZKZ6(a-$a>adX*gY<07!t(#*@}52YAUAf4deet^DA6pV!= zzW!UvHjn$A0&{TeI=q*@yWme&50!eJzU+BRlx@hF9%}0qvphnsnzP#l(^e&32U)`+ zZt@$x62_7LX@J*19Hiv~%57`Y@a$q2SlIi_;h=mCI(|QQD%gI_W`K?RjD%S#6JVq{ z1o4o6Lq*8Tsq3;?80QP7FtDqa8$7Bdix8qdOBg__M{3%$@uWz&H}RG(LpAoDrN##!?pg1zWfQZCnkRNKc>-vvoQ<<6Rg zK;!scb50y7X+f*qd{{t0w~g?2E)60>ekO!712a zzehjQQ5ke*Q3d`LiE&XKCj=f!NEVoqYKIOVg;-T|BNM;z$XYdAg9Lk0OR*$aQ4ZwS z_w^fT6LgM+747i={>e%HDGhiA)|sC+5gEG7vA5gceQR>rK@-5bj29AWyuj-3UUEzCIy=R zpTB^0!o?Wg>y=$%d!%-5>(s?U3-Is+<5zIATL z0!}|#Yzg0AboX%ihStGb`r6WoM1B3kE4gvG$qQ;DLusXB5Ou%Ov-BVXk2TQCN6FLA z&nQ7@ebHHt8>$Q5nt$y_c+4IoCoz28uwp%ZwK&O6$Rs(BW_HEV<|asNIUrYgrFKji z^L4f+W5qUtlhE@Ec)h}`#6WIKO|$4gwI!(D;1T=?#yjI=>^4-`)TDoc(&-@l*LX-` zC0{O27+yPGNy>7K0|3b;!CL_3(!Fo6;@3P(KY_FtbTxFX3#*oC4)(%Wf%&f*F1jE3 z%K=L0n5(S{y)&HH0mFB*gz5?qK(7)UhiRxd&g6*aFSnLqF;| zRFVp^DK;4KPO>rdGAl?g7&*Y-cY;!MGAy8 zTaLhXNPn57UCM`;7LZYWC{vPQ+2qWWn*>~H=0op+!^h97!e(9 zmC18;xbEP~KOagzofCDrp6@`seBEFNq3I&y8uh$P#2GCZ$HIi#5(3iv?JOL&e}QBN zUaFnnmBem4AR+um&$=xkg}wF(&K_7)XiOQTc!@t@2jP_&A=5UGoj3M$aMtX{8wF$} zM3rRDwq%_Tt+!r*5nu+M%{D>Vpv{1iJ1T=}^@#Wy^I^!NY6iRg8wuW@0I`gvOxNa{ z3&S7Yd$(QL>mly4BCUGKVMw}3mj&%jrDt_a${DiMF73M&W5%a^SeOchB~T2Thkhs! zXR^)q&<5x>)6HJ4MJCNcDeRSFp8D54(hucC@-OjO7v#NQ5+Hw8DI%Qi+j{kI=a|kV z_neg47gKgVrftrBS(%_nF-uA47e2PA=UE$@k?T8ki65r4DD_KuNX4^Rt_7F4d!aC7 z#r9u;E44&aMBB4Sxc%;R*kq4gV<-SFhsr z4`ll@P`Pzmiv&Bko&dA`htFUCK5{@VEPd+4mtKSifWfY6v>TtNJk-_J%_}ZLsbWc8 zRGxCwe-T4SaO@a(5TO)}B}$o)lZR=GiqhIqL>fvjX~v$#yI#+Oedg2hKBH_m^d-0J z8)ZvHm-$xmgg*{XJgvJ1^w01Qg4{pofQs$Gx#4dChJP%Pu=r7AhRR0o5OFRZd!D=8 zF)cX?hvWiA5YTt!R-@>yLx zqrk=ewsMDmGxG4%9koRQj$R@~Y_pk{=s zh`VML2mMmFW%03K2bK=O_|Bk8RrkpZ9gw*8UJx=sqG;tdw^&L{kYv|pyrqT4z{=aR z8f0fSHdA+*vJaHX_cfgNA9-gwI@`%gl3Vd(Q)XG1Ap14O$Y(L;~$fcbCR|Ncx1l+3{-?CF)_i=dDS zs;R4m;54gV_vKlhQx_4K%k=Mq0 zEg^XL+AmWSkYja~i*^Go0%we)V%@kjPD2ZT_)Uk(N-YJgkN8Vrx^ghgpBSzYblW;w8af5`L*@60TEFu$j}gv zuStkJ{*+oual2{=zLV$|3q)m00H>}R!!1Co_OtIjAvKZk@5aJY)|D70uj-LRwXLkfB`mTbAbmv#= z1+x7J?xIosKLLlX`rfP_G;m9i79k-2lsdk>!8@-Plhx zHPT~U^CJj)xax6EP1>@!+Ldr26EVv7kc+bKp3WLqs6@`Ifxn37CTsHNal8qB(WQ+3 z(4B;=(dufwl`~X)l>WgTcY7GJCsYL5>v-i%y*Q&?MNqQUgL0G{GFfZdG|G$eBO)!F zM?|A8ti)|ZYqYYR6jd}LHA^UKJ2KnQ^VLR!^i>{?AF{fP;#pDjD3^MLO!loK!H8=D ztXr2VGiK{AP8lxknqC%v?t6QZ!ye@ymuk{MEE@1lz~6NqiP9C!pM^H?m&u+D*`6XR zgF{mz?{;%}z#jwtfU1Vk$}6xZxlys;Tg=mV2vA%j?FtMWcHt;=I za^u&xKO+FyCZ9dWyjBD&TD=96UIC+1*(~WMGfZf*1RmV1Un>~%(*e}c&qZXe$?Sf? zGad<OxqIiZXvTniFi=)lu** zLvduv%zW<$=WgI}+;^aWOg&38A-;67LFz=;6BhWL0Oih5iB2=oKPnHwGl`OOmJ07w~~IeE-7IE6k?dGCNtDDTkI z%om`Fiap&gyVm%b!2bO88J)=&ip;H4~p z18$lB+JHKNUrk1jIBikzO%2-uh|UYcWDbW$!sAv3rL^Z5j}ru>ff{NwM*Xb~plMIx zTt)5iudMBbf9>jnr^#X!JreQkc{573HuqD;w+1IzN}nH2^4JO&(VgY6vifS!Qe6f5 z&?p5eMfa(iLv*F4I|m=JWQKlZd|UiBQ@V8U(iaAK^@)1ppvA=CrSS^Mp3Ja5=Sgj@ zlWI~&VxGyUDEZJCEiA$Lfr`O_7qXO4LoPh7pz>P>~%|)aI{10t5aAavvF|!xU5K4udTE9m-+Nn z<(6<82QalOT;ko8bYs4|VLHF;jJ4~YMHiNumX;V!1aiCeY@c_Y*6Iu|b$kSy(NeMu zPVhcKFI`aS_@KW9qciUq`iZATE_FCIBh@7*+{xTf=QpA0%#^~7`FVg(5yO~6rK%Ge#%uw(Sd3NL1{2_SWIdwXS*sWI=kX*vPA?0e>9}f zcLG?NA6(K|AI<~#P66)!;EoLg7T>c<}|fH+-~;(PgroL}m*$5rsM zxJfo3Y8j5+keNSqXRXtDo9= zkDxgh3w>I)aD(p5+X6$-b$C2#@EM@OjNTnfFA4~q?fDB`jT}*dfpa&f5HK$AFahuZ zk^BGuho;5;qxx$t1HxinrhNTZ1=D7D!Nb8$lM+p^)PWp^WF#Uq>~T+?RTBT9dQ<;@ z_fXzk1;;s6k%BUd6JOBf_2xe zt1AWJ_lm~knkeesod@iL{e zUU={@^RR-W9U+KmhQ8XR=uyMOx2$?|Qb$5yNl75n*q$(99mct*fls15 zYe+@-HS^b#$~W|4PeJVgb87Z;8D-Vx1^^cb#ufs8)-c zv0NXchrOe7aHQ01dcup&QdwJpwVa2&)Rc`#X(OL#kj9NH(JuVfuaB=WS0EyTm&dG@ z=N9{>C&o%{UrRqJPv)d6MP~X&olVSy!gx+S4LHw>#VCMMS{go6Rz1xG6>+;ZffJQ%n_QN;!o2ZBR4joWB7?O5xiPV&pgIVnDC#x zLI4s-Sj9dCnlc@V&LvW(Gjy?AOJ*K5Im<>|KErB4AKVA7__sfK%Ee2JYeIX8fFphW z%L$cF+zb}YI(P~^$DNL{Y4GRAzEWc$u?eK>Otg??F&nBnox?|?{B3;rDqpm z1wl(fV%FmJdbgu^TgvogJdvop7cqk^UdZn`@A&_`bz0KH!`{M+fYeNNY;#OUCtCBK zb-Ot$!&q^=e!8zB5tJQo3__@sCufh+d9$n*W-FH}{cziX{Mj?EvpIxwyQ#bfWq^56 zN@OtqPQHTFS*|gD;veq8b>RWHZeD4Yi`|7HPkMrk!2fc(3!YtPC7Q`fOr2<6%v0{)wD`?NVhJg z$iD^sh}Ka2G#h00j=M^AvusV4o0d*WUD)rVQxG#tb=Z_g8Yx=UO>kkhzW4FaYD155 zp&TJWTqDwsq~jrcy@RL5Zw9L*U0k9EK0XX%Ylp2;jhyq274(Ac#(_3K)HJseZ?PUV zm2R7k+5#HPzn!Qr%{siXU5){;jgTgH?5kDH1RToGOgdGt-& zn~WyMYWpMLiE@4{n9}oSDZG z>TjP!N_{M~RMZiDf8t=3<&Yc|yA+)e8g_x4Nu@-s(zMiH6X^3aF-tIB@m{*C;iCpy z^U~KEHFih`D(fDVla2S>jsKMmz7^@YzQlU_U$nzMHpTXR*RDr4S-?gjt#gQmc!}XB zx6bXZ=UC(rOymy$WqyQf;7{=nW(|=m_XAb=V7dWg>yIy;y{AtYYgVxr-3e}GiXU>R zS9r7YmEEh0w09NddY>=+5$ErO!e%xzslvr_Iyjd7z&o|%DU z8-&o?avq(+ohr6?Z+W4gcrn)^gEOv3kfDiXpHUw>MMC0eiAr|`hyy2A_7L>C=5UQ| ze$k%yzG>^D+&vJu^cGV2e52i`Ej3QlJdIWBv2I(5S0OqU&8hO}VecoyxWSMvbh1#Y z|9UXhqQ;+;M-N*t*DOkVnP~c?usj4?HqM|L?XvlV_QGXlqN|!9y(_G%R{EfagZAF6LFYpd0-3U=PQ< zA`XSfM^r8SPFB5Lhy=U6fc*Hi=;e0d5#ztEf8$~Qb6U-N;Pjqi;i+OWG9b5#(^1X# zRXchO{Oh`-5X$E*@jYuMvH(N}jf)X2G_1f)6d` zTW=;2O?uTd$ka`w_%NKwW!8z&fk%WCc5|)6 z`;W6+UORw$XYkLvJ5I0FVD>u;*T+zAm6Y>5JRtZN`4+QM^|8&-H&xk+nh2*Omg7eX zjbd}xXe(cW)=>&@Y14aZeh=ac=*NcwWs4m7Bjgf4_nqAam;O55(k(cIEIF31fLT8A zP<~%i`=x%T@*F}mDZF0z<&b!dk)+;p@hPp|mEu^}sG4@xQG>Jqx|r)BLTfhYq`mfl zg1>mjy;uG=haevZgeINoAXpsy%OLEl-@0x*b44q5HFBS5&E1sMH?0Lm&NH-au2E0_ zU>&8^zb!~yjXWe;BanJ%HK{erwt+o);rW#@;ZQh6)?8QU163!h=LzfRa&6K@;dx#Q zZs?3+^6kqCM1gch@4SVDC~7we4qV-ooYi&$`@TZ}Woy?UZpvMg5D0BdzV+ey0L8r! z>^;7hc=0#-&ZlW#@h*MWGQoiIO zkoCt3WKFGsX?RLT)G-w2m8GjBQpv{sGggAz-rwsj(Ix6}B9*68Ykoz{+WiKqx%Fq# z;DV{NZ`3Yc`03I6)cQmGll;U2VtsZ^pnNpxbPR(i^S|Y~_+Jc9oq6j8wom1~>Fht~ zgRxLj&|ixQu)`v$yWsGNyx2=y&6nZ^=IAGjmKc^@iXNpnMwwdblRaglx2O*|? zb+9$KC0!K*CSqS#YD2At*mC;C%JRpdc9V41_3Ll5fb|%JqvMWEzozs(74MY~Dt60> zF!CvkE$YYDsmR?Dz+`L-42kb&Qx%Nw-ffGWB(Dja`)c*N@FbQJ8-uuge2a+qk^HE* zbw70w!bfbCv)Tp5pkLJ(G7NL~?-J~R#TIUi$^RwJ8>{$qtF}69USU}QfCp}e6dh?! z*N!ac7>OLLg>H3M52DA7(A_+{)BfIja?k+fK#nX6rpN~e*awm5$F}mz0x3}Zoo;LP z(0ZTP+=FxKMU>#yKdLotqw2QB9^k@|J5sIh;b;C7rVICJ;obC3sD%g)wL(xJ2m*r; zit4m=*iXG?QTZx^by26@%rjzpz7dFqNA_I=#kKy;h zF~(Lk<=1kdVuj0n;hM!vB>g@*?x6W1d9q@cV^no288-B!=!A;)pqExbRnwp1%sr{d9NH0HJ+1Pan0Y8guzwh|ck zOK!6@Z~W>L4%p2%4M&w0NLT^Ua zViKIb*vw&$>Nk?B@~%0@>*60p3rMS73D?LM=c`Eqd=LB+gli;VBI0AS>cHghqVl<4 z4iVh{JKg>}+}Bji|8WZyfbSk(&ft6^Lw5jdPnx_`_*RheoRI47HRiN6RB!Qw`VKab zdmpU4s6QRpE)K6mtc@0^I0;hDD-H`2`=KgRM=P;8B2~L1MJtLm6S{u$`O~92fVo(6 zI<>rzyytCY0c>)iSz811jo<@tmA2%{OS!$+8RI*}M zn7A?wpBZ@Ca{3!v@;()o<$3fI!VDOkuu*RcMEbh2nBGfc#G1HNW+J#9KM3^~3KIu!pT-n>l?1VHD#+3*$hh9+e`6f( z2);v)@TzF>TU7_FVC2-V(P>R*YIM;8%^pH&*iuSh9-UJ4VwqFrUy7a{rCnKX$c*<)M7{pOh?S&# zgrTFIfe;*%ZvMcS$wLZ~*g$32nh+@{(xJ&W zcKP6yyP#W+S2sJD$3>f^bGfSRxe0|?OMZrL!@oF}4`JGk=Aee+uz6%wkzT>A7~-{# zy5ZV-%J>3;D=3mRM8#n8E^%S7uBAM`ilV2H*~@5C7J9|lXAitmV9j`%TECKPJ{SnBz!Fe&tSbQ(%?mPaMpPIk_)QF$BUvjpb zvk>nL1=&C=mrL{(oGrA1L-Eli_?&hPsKPiEoN$5Sbs&+N@eAoXP2po9i~Sykl~L>$ z2KyO>W*f^5lcILH$SzSX!KGVE;#AT}0(fK7E$<5#z0B8&!%;fis5IL!g&jF!s77wo z&{eG*f+2TV9HK7^4wr{26q#*!`M=(~nJIJm@9|a&t8qrPRebn z9y)g~HS3d?LWh`Fsz0arn+?=vLUqXz9)muBw;(HIM;FkuN z%e5*^f+^YGuxElkr#yeTF!-X78N;SHHRuyM2X1RM|5&`as9gMHcG*E`sYfPbf|Ka) zK+fVl78J?jktZV-{7o~L^Rkzqv`C1+BO)#`{oe^F$0V#xJu;#bHp-f8!BdhR3?zj8 z>)UpBe!mjp&e8rOL{J(4+P`Ye$uB8mq7x@N!-I&h?W_?hsTt2mSE)YxR;Ui0umfZJ?U2qbwKj)_#R64B1UOQzg}Z{I`6zWF=#cPGU*>xVTT zzs3j2ocuo`fGd9Bs$$5hQ8@Q8GtRK5>k@&LXndbCQk22*$^jE6N3-2Y?M3xh z2x7U}X3(F5g#o1Mm7XBRpfJT(Ue9Tu-`h^aJuY}j>m|oGvye$)H{v!_Xi)Nmh&aOS zcSeZdx&=gZTm@&6vQ3Qe#U1P2Cjo)7>74t;H|^=t&KMHiHDF zRYE)rNLMi^tenbcYo|zm42ZzNxmPs(j)=|XGovD(3H4 z-)-KDDYMTUxVkySm>V!Kp<&aX{EmO591TF4w-mSFe^;xz32JfykTpPJw`_DdI80Xp z?$_X6i;XCeSs^f_;>4!CATh@V(5cnRS|YVUb1!DqAtH_Nc9OwbTjrGF9(11HRMstkL9g05%!-H1g&{3JdSu@)fV2(iDs0rt zf7rnK?N^`94>Lra_&4-CtnH<(JRq-DUKJe7AR(FM1n1w37BJo1Idy9f*@J6KTwpv4 zg6iDR3qw*4L^RqYqJ*eeHhcVoY%pi;Rt0(Ww=oCox2W2TPNErXo$K9|B#9%k&ad$$R{*Ak&CfEU-%$F0SS7>L#e9hGe;Vi<##7dn(oQ4{IKyQ zZs=R(H5JGCpz(qCiT6492`t=dql7$z7aY1})IOjUUr>%6F)G(k-tgFJ_J+qS1{`a! z2ISitYfU;_JvL3Fu;^1QC8wbW80jQW(V9Z?&1BrTR%rIW_f%5uj!v6ue>8Jf1QV9V zO~u0NTlgjHnf;V+|JaFcV=I2e;yF=>fq2z&b0KWyp^Rv}tG8GDrnh9v7p8}d{VB|# zji)Q=q)YiQiM{BZUG{d{_aX=LOB!qz=)9mgebc9Jx+ zfAHIoDRm<5g-yx7aZ$&H_5ORg&KR6MnSUH} G{eJ+=>LPvs literal 0 HcmV?d00001 diff --git a/src/main/resources/sprites/PacManAssets_Map_2.png b/src/main/resources/sprites/PacManAssets_Map_2.png new file mode 100644 index 0000000000000000000000000000000000000000..f343981e1f4e66de275014a942eefdc6efe201da GIT binary patch literal 8654 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/sprites/PacManAssets_Map_3.png b/src/main/resources/sprites/PacManAssets_Map_3.png new file mode 100644 index 0000000000000000000000000000000000000000..fac9c67d7db2a25b5f981d2110f388f11b5a4e00 GIT binary patch literal 8607 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

_>ETV%VEKEqbQVl1$2 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/sprites/pear36-8x.png b/src/main/resources/sprites/pear36-8x.png new file mode 100644 index 0000000000000000000000000000000000000000..6d34123924c4023aec24dad63d524bc27ce0d034 GIT binary patch literal 313 zcmV-90mlA`P)00001b5ch_0Itp) z=>Px#^GQTORA_fJ z4myhvsg;Z}@!vPBDS~zRmxqS$<*u3^&-r1)neY=GV`Dx7cr7AA8{{jlJgOus=U# zv76QdW?mN&ku%Z&iHJ2CAQ7=f10*8WXn;h-8V!($Sfc?F5o`VdVf-$5G!go!00000 LNkvXXu0mjfJ>rQ& literal 0 HcmV?d00001 diff --git a/src/main/resources/sprites/sprite_atlas.png b/src/main/resources/sprites/sprite_atlas.png new file mode 100644 index 0000000000000000000000000000000000000000..4d914163e9910a11d24cbf1e46895b804c6e3f96 GIT binary patch literal 4884 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 Jl-zwB@*fQJV?_V} literal 0 HcmV?d00001