You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.2 KiB
149 lines
4.2 KiB
import utils
|
|
import numpy as np
|
|
|
|
class Player:
|
|
def __init__(self, x, y):
|
|
self.x = x
|
|
self.y = y
|
|
self.symbol = '@'
|
|
self.name = 'You'
|
|
self.hp = 10
|
|
self.damage = 2
|
|
|
|
class Enemy:
|
|
def __init__(self, x, y, symbol):
|
|
self.x = x
|
|
self.y = y
|
|
self.symbol = symbol
|
|
self.name = 'Python'
|
|
self.hp = 5
|
|
self.damage = 1
|
|
self.hearing_distance = 5
|
|
|
|
class ECS:
|
|
def __init__(self):
|
|
self.entities = {}
|
|
self.facts = {}
|
|
self.id_counter = 0
|
|
|
|
def entity(self):
|
|
self.id_counter += 1
|
|
return self.id_counter
|
|
|
|
def set(self, entity_id, obj):
|
|
name = obj.__class__.__qualname__
|
|
target = self.entities.get(name, {})
|
|
target[entity_id] = obj
|
|
self.entities[name] = target
|
|
|
|
def query(self, cls):
|
|
return self.entities[cls.__qualname__].items()
|
|
|
|
class Systems:
|
|
def __init__(self, ecs, ui, the_map):
|
|
self.ecs = ecs
|
|
self.map = the_map
|
|
self.ui = ui
|
|
self.height = self.map.height
|
|
self.width = self.map.width
|
|
self.paths = np.full((self.height, self.width), utils.PATH_LIMIT, dtype=int)
|
|
|
|
def add_neighbors(self, neighbors, closed, near_y, near_x):
|
|
points = utils.compass(near_x, near_y)
|
|
|
|
for x,y in points:
|
|
if self.map.inbounds(x,y) and closed[y, x] == utils.SPACE:
|
|
closed[y, x] = utils.WALL
|
|
neighbors.append([x,y])
|
|
|
|
def path_enemies(self, in_grid):
|
|
self.paths.fill(utils.PATH_LIMIT)
|
|
closed = self.map.map.copy()
|
|
starting_pixels = []
|
|
open_pixels = []
|
|
|
|
counter = 0
|
|
while counter < self.height * self.width:
|
|
x = counter % self.width
|
|
y = counter // self.width
|
|
if in_grid[y, x] == 0:
|
|
self.paths[y, x] = 0
|
|
closed[y, x] = utils.WALL
|
|
starting_pixels.append([x,y])
|
|
counter += 1
|
|
|
|
for x, y in starting_pixels:
|
|
self.add_neighbors(open_pixels, closed, y, x)
|
|
|
|
counter = 1
|
|
while counter < utils.PATH_LIMIT and open_pixels:
|
|
next_open = []
|
|
for x,y in open_pixels:
|
|
self.paths[y, x] = counter
|
|
self.add_neighbors(next_open, closed, y, x)
|
|
open_pixels = next_open
|
|
counter += 1
|
|
|
|
for x, y in open_pixels:
|
|
self.paths[y, x] = counter
|
|
|
|
def move_enemies(self):
|
|
in_grid = np.full((self.map.height, self.map.width), 1, dtype=int)
|
|
in_grid[self.player.y, self.player.x] = 0
|
|
|
|
self.path_enemies(in_grid)
|
|
# for every enemy (actors[0] is player)
|
|
for enemy in self.actors[1:]:
|
|
nearby = utils.compass(enemy.x, enemy.y)
|
|
our_path = self.paths[enemy.y, enemy.x]
|
|
|
|
if our_path > enemy.hearing_distance: continue
|
|
|
|
for x, y in nearby:
|
|
if self.paths[y, x] <= our_path and not self.actor_collision(enemy, x, y):
|
|
enemy.x = x
|
|
enemy.y = y
|
|
break
|
|
|
|
def death(self, target):
|
|
self.actors.remove(target)
|
|
self.ui.post_status(f"Killed {target.name}")
|
|
|
|
def combat(self, actor, target):
|
|
target.hp -= actor.damage
|
|
if target.hp > 0:
|
|
self.ui.post_status(f"HIT {target.name} for {actor.damage}")
|
|
else:
|
|
self.death(target)
|
|
|
|
def actor_collision(self, actor, x, y):
|
|
for target in self.actors:
|
|
if target != actor and target.x == x and target.y == y:
|
|
return target
|
|
return None
|
|
|
|
def collision(self, actor, x, y):
|
|
if self.map.collision(x, y): return True
|
|
|
|
target = self.actor_collision(actor, x, y)
|
|
|
|
if target:
|
|
self.combat(actor, target)
|
|
return True
|
|
|
|
return False
|
|
|
|
def move_player(self, actor, x, y):
|
|
if not self.collision(actor, x, y):
|
|
actor.x = x
|
|
actor.y = y
|
|
|
|
def spawn_actors(self, enemy_count):
|
|
x, y = self.map.spawn()
|
|
self.player = Player(x, y)
|
|
self.actors = [self.player]
|
|
|
|
for i in range(0, enemy_count):
|
|
x, y = self.map.spawn()
|
|
enemy = Enemy(x, y, '{')
|
|
self.actors.append(enemy)
|
|
|