122 lines
3.9 KiB
Python
122 lines
3.9 KiB
Python
from terminal import Terminal
|
|
from entity import Creature, Player, Enemy
|
|
from actions import *
|
|
from floor import Floor, TileType
|
|
import sys
|
|
|
|
TEXTURES = {
|
|
TileType.WALL: '#',
|
|
TileType.AIR: '.',
|
|
Player: '@'
|
|
}
|
|
|
|
class Game:
|
|
def __init__(self):
|
|
self.term = Terminal()
|
|
self.player = Player()
|
|
self.floor = Floor(20, 10)
|
|
self.should_exit = False
|
|
self.ticks = 0
|
|
self.schedule = {}
|
|
self.redirect_io('prints.log', 'errors.log')
|
|
|
|
def __del__(self):
|
|
self.restore_io()
|
|
|
|
def restore_io(self) -> None:
|
|
sys.stdout = self.stdout_original
|
|
sys.stderr = self.stderr_original
|
|
self.stdout_file.close()
|
|
self.stderr_file.close()
|
|
|
|
def redirect_io(self, stdout_file, stderr_file) -> None:
|
|
self.stdout_original = sys.stdout
|
|
self.stderr_original = sys.stderr
|
|
self.stdout_file = open(stdout_file, 'w')
|
|
self.stderr_file = open(stderr_file, 'w')
|
|
sys.stdout = self.stdout_file
|
|
sys.stderr = self.stderr_file
|
|
|
|
def run(self):
|
|
"""
|
|
Runs the game
|
|
"""
|
|
self.instance_creature(3, 3, self.player)
|
|
self.render()
|
|
while not self.should_exit:
|
|
self.step()
|
|
if self.action_was_performed:
|
|
self.render()
|
|
|
|
def instance_creature(self, x, y, creature: Creature):
|
|
"""
|
|
Instances a creature in space and time
|
|
"""
|
|
self.floor.entities.add_creature(x, y, creature)
|
|
self.reschedule(creature)
|
|
|
|
def reschedule(self, creature: Creature):
|
|
"""
|
|
Calculates the ticks in which the creature will perform its next action
|
|
"""
|
|
time = (ACTION_TIMING[creature.action.__class__] // creature.speed) + self.ticks
|
|
if self.schedule.get(time):
|
|
self.schedule[time].append(creature)
|
|
else:
|
|
self.schedule[time] = [creature]
|
|
|
|
def render(self):
|
|
"""
|
|
Renders the game
|
|
"""
|
|
for x in range(self.floor.width):
|
|
for y in range(self.floor.height):
|
|
if (x, y) in self.floor.entities.pos_creatures:
|
|
self.term.put_char(x, y, TEXTURES[Player])
|
|
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):
|
|
"""
|
|
Perfoms a step in the game. Sets the `action_was_performed` attribute accordingly
|
|
"""
|
|
self.action_was_performed = False
|
|
creatures = self.schedule.get(self.ticks)
|
|
if creatures:
|
|
for creature in creatures:
|
|
if isinstance(creature, Player):
|
|
self.input_event()
|
|
elif isinstance(creature, Enemy):
|
|
creature.calculate_action()
|
|
self.reschedule(creature)
|
|
self.perform(creature)
|
|
self.schedule.pop(self.ticks)
|
|
self.action_was_performed = True
|
|
self.ticks += 1
|
|
|
|
def perform(self, creature: Creature):
|
|
"""
|
|
Performs an action for a creature
|
|
"""
|
|
if isinstance(creature.action, Move):
|
|
pos = self.floor.entities.pop_creature_ref(creature)
|
|
if pos:
|
|
self.floor.entities.add_creature(pos[0] + creature.action.x, pos[1] + creature.action.y, creature)
|
|
|
|
def input_event(self):
|
|
"""
|
|
Waits for a game event to happen, and behaves accordingly
|
|
"""
|
|
keycode = self.term.get_key()
|
|
if keycode == "q":
|
|
self.should_exit = True
|
|
elif keycode == "KEY_RIGHT":
|
|
self.player.action = Move(1, 0)
|
|
elif keycode == "KEY_LEFT":
|
|
self.player.action = Move(-1, 0)
|
|
elif keycode == "KEY_DOWN":
|
|
self.player.action = Move(0, 1)
|
|
elif keycode == "KEY_UP":
|
|
self.player.action = Move(0, -1) |