Merge branch 'display' into 'master'

Meilleur affichage

See merge request ynerant/dungeon-battle!8
This commit is contained in:
ynerant 2020-11-10 21:34:34 +01:00
commit 3b3b8ee8da
25 changed files with 527 additions and 117 deletions

View File

@ -0,0 +1,15 @@
from dungeonbattle.game import Game
from dungeonbattle.display.display_manager import DisplayManager
from dungeonbattle.term_manager import TermManager
class Bootstrap:
@staticmethod
def run_game():
with TermManager() as term_manager: # pragma: no cover
game = Game()
game.new_game()
display = DisplayManager(term_manager.screen, game)
game.display_refresh = display.refresh
game.run(term_manager.screen)

View File

View File

@ -0,0 +1,44 @@
import curses
from typing import Any, Optional, Union
from dungeonbattle.display.texturepack import TexturePack
from dungeonbattle.tests.screen import FakePad
class Display:
x: int
y: int
width: int
height: int
pad: Any
def __init__(self, screen: Any, pack: Optional[TexturePack] = None):
self.screen = screen
self.pack = pack or TexturePack.get_pack("ascii")
def newpad(self, height: int, width: int) -> Union[FakePad, Any]:
return curses.newpad(height, width) if self.screen else FakePad()
def resize(self, y: int, x: int, height: int, width: int) -> None:
self.x = x
self.y = y
self.width = width
self.height = height
if self.pad:
self.pad.resize(height - 1, width - 1)
def refresh(self, *args) -> None:
if len(args) == 4:
self.resize(*args)
self.display()
def display(self) -> None:
raise NotImplementedError
@property
def rows(self) -> int:
return curses.LINES if self.screen else 42
@property
def cols(self) -> int:
return curses.COLS if self.screen else 42

View File

@ -0,0 +1,56 @@
import curses
from dungeonbattle.display.mapdisplay import MapDisplay
from dungeonbattle.display.statsdisplay import StatsDisplay
from dungeonbattle.display.menudisplay import MainMenuDisplay
from dungeonbattle.display.texturepack import TexturePack
from typing import Any
from dungeonbattle.game import Game, GameMode
class DisplayManager:
def __init__(self, screen: Any, g: Game):
self.game = g
self.screen = screen
pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
self.mapdisplay = MapDisplay(screen, pack)
self.statsdisplay = StatsDisplay(screen, pack)
self.mainmenudisplay = MainMenuDisplay(self.game.main_menu,
screen, pack)
self.displays = [self.statsdisplay, self.mapdisplay,
self.mainmenudisplay]
self.update_game_components()
def update_game_components(self) -> None:
for d in self.displays:
d.pack = TexturePack.get_pack(self.game.settings.TEXTURE_PACK)
self.mapdisplay.update_map(self.game.map)
self.statsdisplay.update_player(self.game.player)
def refresh(self) -> None:
if self.game.state == GameMode.PLAY:
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5, self.cols)
self.statsdisplay.refresh(self.rows * 4 // 5, 0,
self.rows // 5, self.cols)
if self.game.state == GameMode.MAINMENU:
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
self.resize_window()
def resize_window(self) -> bool:
"""
If the window got resized, ensure that the screen size got updated.
"""
y, x = self.screen.getmaxyx() if self.screen else (0, 0)
if self.screen and curses.is_term_resized(self.rows,
self.cols): # pragma: nocover
curses.resizeterm(y, x)
return True
return False
@property
def rows(self) -> int:
return curses.LINES if self.screen else 42
@property
def cols(self) -> int:
return curses.COLS if self.screen else 42

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python
from dungeonbattle.entities.player import Player
from dungeonbattle.interfaces import Map
from .display import Display
class MapDisplay(Display):
player: Player
def __init__(self, *args):
super().__init__(*args)
def update_map(self, m: Map) -> None:
self.map = m
self.pad = self.newpad(m.height, m.width + 1)
def update_pad(self) -> None:
self.pad.addstr(0, 0, self.map.draw_string(self.pack))
for e in self.map.entities:
self.pad.addstr(e.y, e.x, self.pack.PLAYER)
def display(self) -> None:
y, x = self.map.currenty, self.map.currentx
deltay, deltax = (self.height // 2) + 1, (self.width // 2) + 1
pminrow, pmincol = y - deltay, x - deltax
sminrow, smincol = max(-pminrow, 0), max(-pmincol, 0)
deltay, deltax = self.height - deltay, self.width - deltax
smaxrow = self.map.height - (y + deltay) + self.height - 1
smaxrow = min(smaxrow, self.height - 1)
smaxcol = self.map.width - (x + deltax) + self.width - 1
smaxcol = min(smaxcol, self.width - 1)
pminrow = max(0, min(self.map.height, pminrow))
pmincol = max(0, min(self.map.width, pmincol))
self.pad.clear()
self.update_pad()
self.pad.refresh(pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)

View File

@ -0,0 +1,79 @@
from dungeonbattle.menus import Menu, MainMenu
from .display import Display
class MenuDisplay(Display):
position: int
def __init__(self, *args):
super().__init__(*args)
self.menubox = self.newpad(self.rows, self.cols)
def update_menu(self, menu: Menu) -> None:
self.menu = menu
self.values = [str(a) for a in menu.values]
self.trueheight = len(self.values)
self.truewidth = max([len(a) for a in self.values])
# Menu values are printed in pad
self.pad = self.newpad(self.trueheight, self.truewidth + 2)
for i in range(self.trueheight):
self.pad.addstr(i, 0, " " + self.values[i])
def update_pad(self) -> None:
for i in range(self.trueheight):
self.pad.addstr(i, 0, " ")
# set a marker on the selected line
self.pad.addstr(self.menu.position, 0, ">")
def display(self) -> None:
cornery = 0 if self.height - 2 >= self.menu.position - 1 \
else self.trueheight - self.height + 2 \
if self.height - 2 >= self.trueheight - self.menu.position else 0
# Menu box
self.menubox.addstr(0, 0, "" + "" * (self.width - 2) + "")
for i in range(1, self.height - 1):
self.menubox.addstr(i, 0, "" + " " * (self.width - 2) + "")
self.menubox.addstr(self.height - 1, 0,
"" + "" * (self.width - 2) + "")
self.menubox.refresh(0, 0, self.y, self.x,
self.height + self.y,
self.width + self.x)
self.update_pad()
self.pad.refresh(cornery, 0, self.y + 1, self.x + 2,
self.height - 2 + self.y,
self.width - 2 + self.x)
@property
def preferred_width(self) -> int:
return self.truewidth + 6
@property
def preferred_height(self) -> int:
return self.trueheight + 2
class MainMenuDisplay(Display):
def __init__(self, menu: MainMenu, *args):
super().__init__(*args)
self.menu = menu
self.pad = self.newpad(self.rows, self.cols)
with open("resources/ascii_art.txt", "r") as file:
self.title = file.read().split("\n")
self.menudisplay = MenuDisplay(self.screen, self.pack)
self.menudisplay.update_menu(self.menu)
def display(self) -> None:
for i in range(len(self.title)):
self.pad.addstr(4 + i, self.width // 2
- len(self.title[0]) // 2 - 1, self.title[i])
self.pad.refresh(0, 0, self.y, self.x, self.height, self.width)
menuwidth = min(self.menudisplay.preferred_width, self.width)
menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1
self.menudisplay.refresh(
menuy, menux, min(self.menudisplay.preferred_height,
self.height - menuy), menuwidth)

View File

@ -0,0 +1,41 @@
from .display import Display
from dungeonbattle.entities.player import Player
class StatsDisplay(Display):
player: Player
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.pad = self.newpad(self.rows, self.cols)
def update_player(self, p: Player) -> None:
self.player = p
def update_pad(self) -> None:
string = ""
for _ in range(self.width - 1):
string = string + "-"
self.pad.addstr(0, 0, string)
string2 = "Player -- LVL {} EXP {}/{} HP {}/{}"\
.format(self.player.level, self.player.current_xp,
self.player.max_xp, self.player.health,
self.player.maxhealth)
for _ in range(self.width - len(string2) - 1):
string2 = string2 + " "
self.pad.addstr(1, 0, string2)
string3 = "Stats : STR {} INT {} CHR {} DEX {} CON {}"\
.format(self.player.strength,
self.player.intelligence, self.player.charisma,
self.player.dexterity, self.player.constitution)
for _ in range(self.width - len(string3) - 1):
string3 = string3 + " "
self.pad.addstr(2, 0, string3)
def display(self) -> None:
self.pad.clear()
self.update_pad()
self.pad.refresh(0, 0, self.y, self.x,
2 + self.y,
self.width + self.x)

View File

@ -0,0 +1,37 @@
class TexturePack:
_packs = dict()
name: str
EMPTY: str
WALL: str
FLOOR: str
PLAYER: str
ASCII_PACK: "TexturePack"
SQUIRREL_PACK: "TexturePack"
def __init__(self, name: str, **kwargs):
self.name = name
self.__dict__.update(**kwargs)
TexturePack._packs[name] = self
@classmethod
def get_pack(cls, name: str) -> "TexturePack":
return cls._packs[name.lower()]
TexturePack.ASCII_PACK = TexturePack(
name="ascii",
EMPTY=' ',
WALL='#',
FLOOR='.',
PLAYER='@',
)
TexturePack.SQUIRREL_PACK = TexturePack(
name="squirrel",
EMPTY=' ',
WALL='',
FLOOR='.',
PLAYER='🐿️',
)

View File

@ -2,8 +2,15 @@ from ..interfaces import FightingEntity
class Player(FightingEntity):
maxhealth = 20
strength = 5
maxhealth: int = 20
strength: int = 5
intelligence: int = 1
charisma: int = 1
dexterity: int = 1
constitution: int = 1
level: int = 1
current_xp: int = 0
max_xp: int = 10
def move_up(self) -> bool:
return self.check_move(self.y - 1, self.x, True)
@ -16,3 +23,13 @@ class Player(FightingEntity):
def move_right(self) -> bool:
return self.check_move(self.y, self.x + 1, True)
def level_up(self) -> None:
while self.current_xp > self.max_xp:
self.level += 1
self.current_xp -= self.max_xp
self.max_xp = self.level * 10
def add_xp(self, xp: int) -> None:
self.current_xp += xp
self.level_up()

View File

@ -3,10 +3,10 @@ from typing import Any
from .entities.player import Player
from .interfaces import Map
from .mapdisplay import MapDisplay
from .settings import Settings
from enum import Enum, auto
from . import menus
from typing import Callable
class GameMode(Enum):
@ -22,23 +22,35 @@ class KeyValues(Enum):
LEFT = auto()
RIGHT = auto()
ENTER = auto()
SPACE = auto()
class Game:
map: Map
player: Player
display_refresh: Callable[[], None]
def __init__(self) -> None:
"""
Init the game.
"""
self.state = GameMode.MAINMENU
self.main_menu = menus.MainMenu()
self.settings = Settings()
self.settings.load_settings()
self.settings.write_settings()
def new_game(self, init_pad: bool = True) -> None:
def new_game(self) -> None:
"""
Create a new game on the screen.
"""
# TODO generate a new map procedurally
self.m = Map.load("example_map.txt")
self.map = Map.load("resources/example_map.txt")
self.map.currenty = 1
self.map.currentx = 6
self.player = Player()
self.player.move(1, 6)
self.m.add_entity(self.player)
self.d = MapDisplay(self.m, self.player, init_pad)
self.map.add_entity(self.player)
@staticmethod
def load_game(filename: str) -> None:
@ -46,14 +58,22 @@ class Game:
raise NotImplementedError()
def run(self, screen: Any) -> None:
"""
Main infinite loop.
We wait for a player action, then we do what that should be done
when the given key got pressed.
"""
while True:
screen.clear()
screen.refresh()
self.d.display(self.player.y, self.player.x)
self.display_refresh()
key = screen.getkey()
self.handle_key_pressed(self.translate_key(key))
def translate_key(self, key: str) -> KeyValues:
"""
Translate the raw string key into an enum value that we can use.
"""
if key in (self.settings.KEY_DOWN_SECONDARY,
self.settings.KEY_DOWN_PRIMARY):
return KeyValues.DOWN
@ -68,27 +88,57 @@ class Game:
return KeyValues.UP
elif key == self.settings.KEY_ENTER:
return KeyValues.ENTER
elif key == ' ':
return KeyValues.SPACE
def handle_key_pressed(self, key: KeyValues) -> None:
"""
Indicates what should be done when the given key is pressed,
according to the current game state.
"""
if self.state == GameMode.PLAY:
if key == KeyValues.UP:
self.player.move_up()
if key == KeyValues.DOWN:
self.player.move_down()
if key == KeyValues.LEFT:
self.player.move_left()
if key == KeyValues.RIGHT:
self.player.move_right()
if self.state == GameMode.MAINMENU:
if key == KeyValues.DOWN:
self.main_menu.go_down()
if key == KeyValues.UP:
self.main_menu.go_up()
if key == KeyValues.ENTER:
option = self.main_menu.validate()
if option == menus.MainMenuValues.START:
self.state = GameMode.PLAY
elif option == menus.MainMenuValues.SETTINGS:
self.state = GameMode.SETTINGS
elif option == menus.MainMenuValues.EXIT:
sys.exit(0)
self.handle_key_pressed_play(key)
elif self.state == GameMode.MAINMENU:
self.handle_key_pressed_main_menu(key)
elif self.state == GameMode.SETTINGS:
self.handle_key_pressed_settings(key)
self.display_refresh()
def handle_key_pressed_play(self, key: KeyValues) -> None:
"""
In play mode, arrows or zqsd should move the main character.
"""
if key == KeyValues.UP:
self.player.move_up()
elif key == KeyValues.DOWN:
self.player.move_down()
elif key == KeyValues.LEFT:
self.player.move_left()
elif key == KeyValues.RIGHT:
self.player.move_right()
elif key == KeyValues.SPACE:
self.state = GameMode.MAINMENU
def handle_key_pressed_main_menu(self, key: KeyValues) -> None:
"""
In the main menu, we can navigate through options.
"""
if key == KeyValues.DOWN:
self.main_menu.go_down()
if key == KeyValues.UP:
self.main_menu.go_up()
if key == KeyValues.ENTER:
option = self.main_menu.validate()
if option == menus.MainMenuValues.START:
self.state = GameMode.PLAY
elif option == menus.MainMenuValues.SETTINGS:
self.state = GameMode.SETTINGS
elif option == menus.MainMenuValues.EXIT:
sys.exit(0)
def handle_key_pressed_settings(self, key: KeyValues) -> None:
"""
For now, in the settings mode, we can only go backwards.
"""
if key == KeyValues.SPACE:
self.state = GameMode.MAINMENU

View File

@ -1,5 +1,7 @@
#!/usr/bin/env python
from enum import Enum
from enum import Enum, auto
from dungeonbattle.display.texturepack import TexturePack
class Map:
@ -10,6 +12,10 @@ class Map:
width: int
height: int
tiles: list
# coordinates of the point that should be
# on the topleft corner of the screen
currentx: int
currenty: int
def __init__(self, width: int, height: int, tiles: list):
self.width = width
@ -42,24 +48,34 @@ class Map:
lines = [line for line in lines if line]
height = len(lines)
width = len(lines[0])
tiles = [[Tile(c)
tiles = [[Tile.from_ascii_char(c)
for x, c in enumerate(line)] for y, line in enumerate(lines)]
return Map(width, height, tiles)
def draw_string(self) -> str:
def draw_string(self, pack: TexturePack) -> str:
"""
Draw the current map as a string object that can be rendered
in the window.
"""
return "\n".join("".join(tile.value for tile in line)
return "\n".join("".join(tile.char(pack) for tile in line)
for line in self.tiles)
class Tile(Enum):
EMPTY = ' '
WALL = ''
FLOOR = '.'
EMPTY = auto()
WALL = auto()
FLOOR = auto()
@classmethod
def from_ascii_char(cls, ch: str) -> "Tile":
for tile in Tile:
if tile.char(TexturePack.ASCII_PACK) == ch:
return tile
raise ValueError(ch)
def char(self, pack: TexturePack) -> str:
return getattr(pack, self.name)
def is_wall(self) -> bool:
return self == Tile.WALL
@ -74,6 +90,7 @@ class Tile(Enum):
class Entity:
y: int
x: int
name: str
map: Map
def __init__(self):
@ -104,6 +121,11 @@ class FightingEntity(Entity):
health: int
strength: int
dead: bool
intelligence: int
charisma: int
dexterity: int
constitution: int
level: int
def __init__(self):
super().__init__()

View File

@ -1,34 +0,0 @@
#!/usr/bin/env python
import curses
from dungeonbattle.entities.player import Player
from dungeonbattle.interfaces import Map
class MapDisplay:
def __init__(self, m: Map, player: Player, init_pad: bool = True):
self.map = m
self.player = player
if init_pad:
self.pad = curses.newpad(m.height, m.width + 1)
def update_pad(self) -> None:
self.pad.addstr(0, 0, self.map.draw_string())
# TODO Not all entities should be a player
for e in self.map.entities:
self.pad.addstr(e.y, e.x, '🐿')
def display(self, y: int, x: int) -> None:
deltay, deltax = (curses.LINES // 2) + 1, (curses.COLS // 2) + 1
pminrow, pmincol = y - deltay, x - deltax
sminrow, smincol = max(-pminrow, 0), max(-pmincol, 0)
deltay, deltax = curses.LINES - deltay, curses.COLS - deltax
smaxrow = self.map.height - (y + deltay) + curses.LINES - 1
smaxrow = min(smaxrow, curses.LINES - 1)
smaxcol = self.map.width - (x + deltax) + curses.COLS - 1
smaxcol = min(smaxcol, curses.COLS - 1)
pminrow = max(0, min(self.map.height, pminrow))
pmincol = max(0, min(self.map.width, pmincol))
self.pad.clear()
self.update_pad()
self.pad.refresh(pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)

View File

@ -1,4 +1,4 @@
from enum import Enum, auto
from enum import Enum
from typing import Any
@ -19,9 +19,12 @@ class Menu:
class MainMenuValues(Enum):
START = auto()
SETTINGS = auto()
EXIT = auto()
START = 'Jouer'
SETTINGS = 'Paramètres'
EXIT = 'Quitter'
def __str__(self):
return self.value
class MainMenu(Menu):

View File

@ -29,7 +29,7 @@ class Settings:
['KEY_RIGHT', 'Touche secondaire pour aller vers la droite']
self.KEY_ENTER = \
['\n', 'Touche pour valider un menu']
self.TEXTURE_PACK = ['ASCII', 'Pack de textures utilisé']
self.TEXTURE_PACK = ['ascii', 'Pack de textures utilisé']
def __getattribute__(self, item: str) -> Any:
superattribute = super().__getattribute__(item)

View File

@ -2,7 +2,7 @@ import curses
from types import TracebackType
class TermManager:
class TermManager: # pragma: no cover
def __init__(self):
self.screen = curses.initscr()
# convert escapes sequences to curses abstraction

View File

@ -11,7 +11,7 @@ class TestEntities(unittest.TestCase):
"""
Load example map that can be used in tests.
"""
self.map = Map.load("example_map.txt")
self.map = Map.load("resources/example_map.txt")
def test_basic_entities(self) -> None:
"""
@ -95,3 +95,8 @@ class TestEntities(unittest.TestCase):
self.assertFalse(player.move_right())
self.assertTrue(player.move_down())
self.assertTrue(player.move_down())
player.add_xp(70)
self.assertEqual(player.current_xp, 10)
self.assertEqual(player.max_xp, 40)
self.assertEqual(player.level, 4)

View File

@ -1,5 +1,9 @@
import os
import unittest
from dungeonbattle.bootstrap import Bootstrap
from dungeonbattle.display.display import Display
from dungeonbattle.display.display_manager import DisplayManager
from dungeonbattle.game import Game, KeyValues, GameMode
from dungeonbattle.menus import MainMenuValues
@ -10,10 +14,22 @@ class TestGame(unittest.TestCase):
Setup game.
"""
self.game = Game()
self.game.new_game(False)
self.game.new_game()
display = DisplayManager(None, self.game)
self.game.display_refresh = display.refresh
def test_load_game(self) -> None:
self.assertRaises(NotImplementedError, Game.load_game, "game.save")
self.assertRaises(NotImplementedError, Display(None).display)
def test_bootstrap_fail(self) -> None:
"""
Ensure that the test can't play the game,
because there is no associated shell.
Yeah, that's only for coverage.
"""
self.assertRaises(Exception, Bootstrap.run_game)
self.assertEqual(os.getenv("TERM", "unknown"), "unknown")
def test_key_translation(self) -> None:
"""
@ -37,6 +53,7 @@ class TestGame(unittest.TestCase):
self.game.settings.KEY_RIGHT_SECONDARY), KeyValues.RIGHT)
self.assertEqual(self.game.translate_key(
self.game.settings.KEY_ENTER), KeyValues.ENTER)
self.assertEqual(self.game.translate_key(' '), KeyValues.SPACE)
def test_key_press(self) -> None:
"""
@ -54,7 +71,8 @@ class TestGame(unittest.TestCase):
self.game.handle_key_pressed(KeyValues.ENTER)
self.assertEqual(self.game.state, GameMode.SETTINGS)
self.game.state = GameMode.MAINMENU
self.game.handle_key_pressed(KeyValues.SPACE)
self.assertEqual(self.game.state, GameMode.MAINMENU)
self.game.handle_key_pressed(KeyValues.DOWN)
self.assertEqual(self.game.main_menu.validate(),
@ -95,3 +113,6 @@ class TestGame(unittest.TestCase):
new_y, new_x = self.game.player.y, self.game.player.x
self.assertEqual(new_y, y)
self.assertEqual(new_x, x - 1)
self.game.handle_key_pressed(KeyValues.SPACE)
self.assertEqual(self.game.state, GameMode.MAINMENU)

View File

@ -1,5 +1,6 @@
import unittest
from dungeonbattle.display.texturepack import TexturePack
from dungeonbattle.interfaces import Map, Tile
@ -8,16 +9,16 @@ class TestInterfaces(unittest.TestCase):
"""
Create a map and check that it is well parsed.
"""
m = Map.load_from_string(".\n.\n")
m = Map.load_from_string(".#\n#.\n")
self.assertEqual(m.width, 2)
self.assertEqual(m.height, 2)
self.assertEqual(m.draw_string(), ".█\n.")
self.assertEqual(m.draw_string(TexturePack.ASCII_PACK), ".#\n#.")
def test_load_map(self) -> None:
"""
Try to load a map from a file.
"""
m = Map.load("example_map.txt")
m = Map.load("resources/example_map.txt")
self.assertEqual(m.width, 52)
self.assertEqual(m.height, 17)
@ -31,3 +32,4 @@ class TestInterfaces(unittest.TestCase):
self.assertTrue(Tile.FLOOR.can_walk())
self.assertFalse(Tile.WALL.can_walk())
self.assertTrue(Tile.EMPTY.can_walk())
self.assertRaises(ValueError, Tile.from_ascii_char, 'unknown')

View File

@ -0,0 +1,17 @@
class FakePad:
"""
In order to run tests, we simulate a fake curses pad that accepts functions
but does nothing with them.
"""
def addstr(self, y: int, x: int, message: str) -> None:
pass
def refresh(self, pminrow: int, pmincol: int, sminrow: int,
smincol: int, smaxrow: int, smaxcol: int) -> None:
pass
def clear(self) -> None:
pass
def resize(self, height: int, width: int) -> None:
pass

View File

@ -17,16 +17,16 @@ class TestSettings(unittest.TestCase):
self.assertEqual(settings.KEY_DOWN_SECONDARY, 'KEY_DOWN')
self.assertEqual(settings.KEY_LEFT_SECONDARY, 'KEY_LEFT')
self.assertEqual(settings.KEY_RIGHT_SECONDARY, 'KEY_RIGHT')
self.assertEqual(settings.TEXTURE_PACK, 'ASCII')
self.assertEqual(settings.TEXTURE_PACK, 'ascii')
self.assertEqual(settings.get_comment(settings.TEXTURE_PACK),
settings.get_comment('TEXTURE_PACK'))
self.assertEqual(settings.get_comment(settings.TEXTURE_PACK),
'Pack de textures utilisé')
settings.TEXTURE_PACK = 'UNICODE'
self.assertEqual(settings.TEXTURE_PACK, 'UNICODE')
settings.TEXTURE_PACK = 'squirrel'
self.assertEqual(settings.TEXTURE_PACK, 'squirrel')
settings.write_settings()
settings.load_settings()
self.assertEqual(settings.TEXTURE_PACK, 'UNICODE')
self.assertEqual(settings.TEXTURE_PACK, 'squirrel')

View File

@ -1,8 +0,0 @@
# This is the base ascii texturepack
ascii = {
"EMPTY": ' ',
"WALL": '#',
"FLOOR": '.',
"PLAYER": '@'
}

View File

@ -1,17 +0,0 @@
███████ █████████████
█.....█ █...........█
█.....█ █████...........█
█.....█ █...............█
█.█████ █.███...........█
█.█ █.█ █...........█
█.█ █.█ █████████████
█.█ █.█
█.████ █.█
█....█ █.█
████.███████████████████.█
█.....................█ █████████████████
█.....................█ █...............█
█.....................███████...............█
█...........................................█
█.....................███████...............█
███████████████████████ █████████████████

View File

@ -1,9 +1,5 @@
#!/usr/bin/env python
from dungeonbattle.game import Game
from dungeonbattle.term_manager import TermManager
from dungeonbattle.bootstrap import Bootstrap
if __name__ == "__main__":
with TermManager() as term_manager:
game = Game()
game.new_game()
game.run(term_manager.screen)
Bootstrap.run_game()

11
resources/ascii_art.txt Normal file
View File

@ -0,0 +1,11 @@
██████ █████ █ ██ ██▓ ██▀███ ██▀███ ▓█████ ██▓ ▄▄▄▄ ▄▄▄ ▄▄▄█████▓▄▄▄█████▓ ██▓ ▓█████
▒██ ▒ ▒██▓ ██▒ ██ ▓██▒▓██▒▓██ ▒ ██▒▓██ ▒ ██▒▓█ ▀ ▓██▒ ▓█████▄ ▒████▄ ▓ ██▒ ▓▒▓ ██▒ ▓▒▓██▒ ▓█ ▀
░ ▓██▄ ▒██▒ ██░▓██ ▒██░▒██▒▓██ ░▄█ ▒▓██ ░▄█ ▒▒███ ▒██░ ▒██▒ ▄██▒██ ▀█▄ ▒ ▓██░ ▒░▒ ▓██░ ▒░▒██░ ▒███
▒ ██▒░██ █▀ ░▓▓█ ░██░░██░▒██▀▀█▄ ▒██▀▀█▄ ▒▓█ ▄ ▒██░ ▒██░█▀ ░██▄▄▄▄██░ ▓██▓ ░ ░ ▓██▓ ░ ▒██░ ▒▓█ ▄
▒██████▒▒░▒███▒█▄ ▒▒█████▓ ░██░░██▓ ▒██▒░██▓ ▒██▒░▒████▒░██████▒ ░▓█ ▀█▓ ▓█ ▓██▒ ▒██▒ ░ ▒██▒ ░ ░██████▒░▒████▒
▒ ▒▓▒ ▒ ░░░ ▒▒░ ▒ ░▒▓▒ ▒ ▒ ░▓ ░ ▒▓ ░▒▓░░ ▒▓ ░▒▓░░░ ▒░ ░░ ▒░▓ ░ ░▒▓███▀▒ ▒▒ ▓▒█░ ▒ ░░ ▒ ░░ ░ ▒░▓ ░░░ ▒░ ░
░ ░▒ ░ ░ ░ ▒░ ░ ░░▒░ ░ ░ ▒ ░ ░▒ ░ ▒░ ░▒ ░ ▒░ ░ ░ ░░ ░ ▒ ░ ▒░▒ ░ ▒ ▒▒ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░
░ ░ ░ ░ ░ ░░░ ░ ░ ▒ ░ ░░ ░ ░░ ░ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░

17
resources/example_map.txt Normal file
View File

@ -0,0 +1,17 @@
####### #############
#.....# #...........#
#.....# #####...........#
#.....# #...............#
#.##### #.###...........#
#.# #.# #...........#
#.# #.# #############
#.# #.#
#.#### #.#
#....# #.#
####.###################.#
#.....................# #################
#.....................# #...............#
#.....................#######...............#
#...........................................#
#.....................#######...............#
####################### #################