diff --git a/actions.py b/actions.py index 435657b..ed2733a 100644 --- a/actions.py +++ b/actions.py @@ -9,4 +9,14 @@ class Move: class Idle: pass -Action = Move | Idle \ No newline at end of file +@dataclass +class NA: + pass + +Action = Move | Idle | NA + +action_timing = { + Move: 500, + Idle: 100, + NA: 1 +} \ No newline at end of file diff --git a/entity.py b/entity.py index c9a12f2..1d4b66d 100644 --- a/entity.py +++ b/entity.py @@ -1,5 +1,5 @@ from enum import Enum -from actions import Action, Idle +from actions import Action, Idle, NA class Entity(): pass @@ -9,7 +9,8 @@ class Item(Entity): class Character(Entity): def __init__(self): - self.action: Action = Idle() + self.speed = 1 + self.action: Action = NA() class Player(Character): def __init__(self): @@ -17,4 +18,7 @@ class Player(Character): class Enemy(Character): def __init__(self): - super().__init__() \ No newline at end of file + super().__init__() + + def calculate_action(self): + self.action: Action = Idle() \ No newline at end of file diff --git a/floor.py b/floor.py index e42c75c..1cdf15c 100644 --- a/floor.py +++ b/floor.py @@ -1,38 +1,60 @@ from enum import Enum +from typing import Tuple from entity import Character, Entity, Item class TileType(Enum): WALL = 1 AIR = 2 +class EntityMap: + """ + Class that stores entities in an special way in order to be able to reach in O(1) the values + """ + def __init__(self): + self.items = {} # K: Position V: List(Item) + self.pos_creatures = {} # K: Position V: Creature + self.creatures_pos = {} # K: Creature V: Position + + def get_item(self, x, y): + return self.items.get((x, y)) + + def get_creature(self, x, y): + return self.pos_creatures.get((x, y)) + + def get_creature_position(self, creature: Character): + return self.creatures_pos.get(creature) + + def add_item(self, x, y, item: Item): + if (x, y) not in self.items: + self.items[(x, y)] = [] + self.items[(x, y)].append(item) + + def add_creature(self, x, y, creature: Character) -> bool: + if (x, y) in self.pos_creatures: + return False + else: + self.pos_creatures[(x, y)] = creature + self.creatures_pos[creature] = (x, y) + return True + + def pop_creature_pos(self, x, y) -> Character | None: + if (x, y) in self.pos_creatures: + creature = self.pos_creatures.pop((x, y)) + self.creatures_pos.pop(creature) + return creature + + def pop_creature_ref(self, creature: Character) -> Tuple[int, int] | None: + if creature in self.creatures_pos: + pos = self.creatures_pos.pop(creature) + self.pos_creatures.pop(pos) + return pos + class Floor: def __init__(self, width, height): self.width = width self.height = height self.grid = [[TileType.AIR] * height] * width - self.entities = { - Character: {}, - Item: {} - } + self.entities = EntityMap() def get_tile(self, x, y): return self.grid[x][y] - - def add_entity(self, x, y, entity: Entity) -> bool: - if isinstance(entity, Character): - if (x, y) in self.entities[Character]: - return False - else: - self.entities[Character][(x, y)] = entity - return True - elif isinstance(entity, Item): - if (x, y) not in self.entities[Item]: - self.entities[Item][(x,y)] = [] - self.entities[Item][(x,y)].append(entity) - return True - else: - return False - - def pop_character(self, x, y) -> Character | None: - if (x, y) in self.entities[Character]: - return self.entities[Character].pop((x, y)) \ No newline at end of file diff --git a/game.py b/game.py index 9d08472..d35687f 100644 --- a/game.py +++ b/game.py @@ -1,5 +1,5 @@ from terminal import Terminal -from entity import Character, Player, Item +from entity import Character, Player, Item, Enemy from actions import * from floor import Floor, TileType @@ -15,16 +15,32 @@ class Game: self.player = Player() self.floor = Floor(20, 10) self.should_exit = False + self.ticks = 0 + self.schedule = {} def run(self): """ Runs the game """ - self.floor.add_entity(3, 3, self.player) + self.instance_character(3, 3, self.player) while not self.should_exit: self.render() - self.get_event() self.step() + self.ticks += 1 + + def instance_character(self, x, y, character: Character): + self.floor.entities.add_creature(x, y, character) + self.reschedule(character) + + def reschedule(self, character: Character): + """ + Calculates turns for the next avaliable ticks untill player turn + """ + time = (action_timing[character.action.__class__] // character.speed) + self.ticks + if self.schedule.get(time): + self.schedule[time].append(character) + else: + self.schedule[time] = [character] def render(self): """ @@ -32,21 +48,34 @@ class Game: """ for x in range(self.floor.width): for y in range(self.floor.height): - if (x, y) in self.floor.entities[Character]: + if (x, y) in self.floor.entities.pos_creatures: self.term.put_char(x, y, TEXTURES[Player]) - elif (x, y) in self.floor.entities[Item]: + elif (x, y) in self.floor.entities.items: self.term.put_char(x, y, 'i') else: self.term.put_char(x, y, TEXTURES[self.floor.get_tile(x, y)]) def step(self): + creaturas = self.schedule.get(self.ticks) + if creaturas: + for creatura in creaturas: + if isinstance(creatura, Player): + self.get_event() + elif isinstance(creatura, Enemy): + creatura.calculate_action() + self.reschedule(creatura) + self.perform(creatura) + self.schedule.pop(self.ticks) + + def perform(self, character: Character): """ - Performs a turn in the game + Performs an action for a creature """ - for (pos, character) in dict(self.floor.entities[Character]).items(): - if isinstance(character.action, Move): - character = self.floor.entities[Character].pop(pos) - self.floor.add_entity(pos[0] + character.action.x, pos[1] + character.action.y, character) + if isinstance(character.action, Move): + pos = self.floor.entities.pop_creature_ref(character) + if pos: + self.floor.entities.add_creature(pos[0] + character.action.x, pos[1] + character.action.y, character) + def get_event(self): """ diff --git a/log.log b/log.log new file mode 100644 index 0000000..e69de29