Initial commit

This commit is contained in:
Mikko Ahlroth 2021-03-18 21:58:26 +02:00
commit b2588f5f54
27 changed files with 1097 additions and 0 deletions

158
class_abstractbeing.php Normal file
View file

@ -0,0 +1,158 @@
<?php
abstract class AbstractBeing extends Entity implements Being
{
const MAXITEMS = 5;
const VISIBILITY = parent::VSB_VISIBLE;
private $name;
private $items;
private $equips;
private $speed;
private $sight;
private $hp;
private $mp;
private $money;
private $exp;
static public function createName(AbstractBeing $being)
{
$being->name = 'FAIL_' . uniqid();
}
static public function giveRandomItems(AbstractBeing $being)
{
/*$amount = rand(0, static::MAXITEMS);
for ($i = 0; $i < $amount; ++$i)
{
$being->items[] = RandomItemFactory::getItem($being);
}*/
}
static public function equipRandomItems(AbstractBeing $being)
{
/*$amount = rand(0, count($being->items));
for ($i = 0; $i < $amount; ++$i)
{
try
{
$being->equip($being->items[$i]);
} catch (CannotEquipException $e)
{ }
}*/
}
static public function setRandomStats(AbstractBeing $being)
{
}
public function __construct($name = null, $exp = 0, array $items = null, array $equips = null, $speed = null, $sight = null, $hp = 0, $mp = 0, $money = null, Place $place = null)
{
$this->name = $name;
if ($items === null)
static::giveRandomItems($this);
if ($equips === null)
static::equipRandomItems($this);
static::setRandomStats($this);
if ($speed !== null)
$this->speed = $speed;
if ($sight !== null)
$this->sight = $sight;
if ($hp > 0)
$this->hp = $hp;
if ($mp > 0)
$this->mp = $mp;
if ($money !== null)
$this->money = $money;
if ($exp > 0)
$this->exp = $exp;
if ($place != null)
$this->setPlace($place);
}
public function setRandomPlace(Level $level = null)
{
$coord = $level->getEmptyPlace();
$this->setPlace(new Place($level, $coord));
}
public function move($dir)
{
$newX = $this->place->getCoord()->x;
$newY = $this->place->getCoord()->y;
if ($dir & DIR_DOWN)
++$newY;
elseif ($dir & DIR_UP)
--$newY;
if ($dir & DIR_RIGHT)
++$newX;
elseif ($dir & DIR_LEFT)
--$newX;
$newCoord = new Coord($newX, $newY);
if ($this->place->getLevel()->whatsAt($newCoord) instanceof EmptyFloor)
$this->setPlace(new Place($this->place->getLevel(), $newCoord));
// Clear sight data
$this->seenCells = array();
}
public function getName()
{
return $this->name;
}
public function getItems()
{
return $this->items;
}
public function getEquips()
{
return $this->equips;
}
public function getSpeed()
{
return $this->speed;
}
public function getSight()
{
return $this->sight;
}
public function getHP()
{
return $this->hp;
}
public function getMP()
{
return $this->mp;
}
public function getMoney()
{
return $this->money;
}
public function getExp()
{
return $this->exp;
}
public function __toString()
{
if (DudeStore::getDude()->getBase() == $this)
return '@';
return parent::__toString();
}
}

9
class_being.php Normal file
View file

@ -0,0 +1,9 @@
<?php
interface Being
{
/*public function tick();
public function attack($attack);
public function kill(Being $killer);
public function move(Place $place);*/
}

View file

@ -0,0 +1,9 @@
<?php
class CannotEquipException extends SDGException
{
public function getMessage()
{
return 'Cannot equip item: ' . parent::getMessage();
}
}

40
class_coord.php Normal file
View file

@ -0,0 +1,40 @@
<?php
class Coord
{
private $x;
private $y;
static public function createFromString($str)
{
$str = explode(',', $str);
return new self($str[0], $str[1]);
}
public function __construct($x, $y)
{
$this->x = $x;
$this->y = $y;
}
public function getDistance(Coord $coord)
{
return round(sqrt(pow($coord->x - $this->x, 2) + pow($coord->y - $this->y, 2)));
}
public function __get($name)
{
if ($name == 'x' || $name == 'y')
{
return $this->$name;
}
else
throw new SDGException('Can only access X and Y in ' . __CLASS__);
}
public function __toString()
{
return $this->x . ',' . $this->y;
}
}

82
class_display.php Normal file
View file

@ -0,0 +1,82 @@
<?php
class Display
{
const STYLE_NONE = 0;
const STYLE_BOLD = 1;
const STYLE_ITALIC = 2;
const STYLE_UNDERLINE = 4;
const STYLE_BLINK = 8;
const STYLE_INVERSE = 16;
const COLOR_NONE = 9;
const COLOR_BLACK = 0;
const COLOR_RED = 1;
const COLOR_GREEN = 2;
const COLOR_YELLOW = 3;
const COLOR_BLUE = 4;
const COLOR_MAGENTA = 5;
const COLOR_CYAN = 6;
const COLOR_WHITE = 7;
private $xSize;
private $ySize;
private $stream;
public function __construct($xSize, $ySize, $stream)
{
$this->xSize = $xSize;
$this->ySize = $ySize;
$this->stream = $stream;
$this->color = self::COLOR_NONE;
}
public function write($text, $style = self::STYLE_NONE, $color = self::COLOR_NONE)
{
if ($style != self::STYLE_NONE)
$this->setStyle($style);
if ($color != self::COLOR_NONE)
$this->setColor($color);
fwrite($this->stream, $text);
}
public function writeTo($x, $y, $text, $style = self::STYLE_NONE, $color = self::COLOR_NONE)
{
$this->write(ANSI_CSI . $y . ';' . $x . 'H' . $text, $style, $color);
}
public function setCursor($x, $y)
{
$this->writeTo($x, $y, '');
}
public function setColor($color = self::COLOR_NONE)
{
$this->write(ANSI_CSI . (30 + $color) . 'm');
}
public function setStyle($style = self::STYLE_NONE)
{
if ($style == self::STYLE_NONE)
$this->write(ANSI_CSI . 0 . 'm');
else
{
if ($style & self::STYLE_BOLD)
$this->write(ANSI_CSI . 1 . 'm');
if ($style & self::STYLE_ITALIC)
$this->write(ANSI_CSI . 3 . 'm');
if ($style & self::STYLE_UNDERLINE)
$this->write(ANSI_CSI . 4 . 'm');
if ($style & self::STYLE_BLINK)
$this->write(ANSI_CSI . 5 . 'm');
if ($style & self::STYLE_INVERSE)
$this->write(ANSI_CSI . 7 . 'm');
}
}
public function clear()
{
$this->write(ANSI_CSI . 2 . 'J');
$this->setCursor(null, null);
}
}

19
class_displayfactory.php Normal file
View file

@ -0,0 +1,19 @@
<?php
abstract class DisplayFactory
{
static public function getDefault()
{
return new Display(TERM_X, TERM_Y, STDOUT);
}
static public function terminalSetRaw()
{
system('stty raw');
}
static public function terminalSetCooked()
{
system('stty cooked');
}
}

30
class_dude.php Normal file
View file

@ -0,0 +1,30 @@
<?php
class Dude implements Being
{
private $base;
public function __construct(Being $base)
{
$this->base = $base;
DudeStore::add($this);
}
public function getBase()
{
return clone $this->base;
}
public function move($dir)
{
$this->base->move($dir);
}
public function __call($method, $arguments)
{
if (is_callable('parent::' . $method))
call_user_func_array('parent::' . $method, $arguments);
else
throw new SDGException('Cannot call nonexistant method ' . $method);
}
}

16
class_dudestore.php Normal file
View file

@ -0,0 +1,16 @@
<?php
abstract class DudeStore
{
static private $dude;
static public function add(Dude $dude)
{
self::$dude = $dude;
}
static public function getDude()
{
return self::$dude;
}
}

50
class_dungeon.php Normal file
View file

@ -0,0 +1,50 @@
<?php
class Dungeon
{
private $levels;
private $lowest;
private $highest;
public function __construct()
{
$this->lowest = 0;
$this->highest = 0;
$this->levels = array();
}
public function addLevelAbove(Level $level)
{
if (!empty($this->levels))
{
++$this->highest;
}
$this->levels[$this->highest] = $level;
}
public function addLevelBelow(Level $level)
{
if (empty($this->levels))
{
--$this->lowest;
}
$this->levels[$this->lowest] = $level;
}
public function getLevels()
{
return $this->levels;
}
public function getLevel($number)
{
return (isset($this->levels[$number]))? $this->levels[$number] : null;
}
public function getLevelNumber(Level $level)
{
foreach ($levels as $number => $savedLevel)
if ($savedLevel == $level)
return $number;
}
}

7
class_emptyfloor.php Normal file
View file

@ -0,0 +1,7 @@
<?php
class EmptyFloor extends Entity
{
const CHAR = '.';
const VISIBILITY = parent::VSB_INVISIBLE;
}

113
class_entity.php Normal file
View file

@ -0,0 +1,113 @@
<?php
abstract class Entity
{
/**
* Different visibility types for entities
*/
const VSB_INVISIBLE = 0;
const VSB_VISIBLE = 1;
const VSB_SEETHROUGH = 2;
protected $place;
protected $seenCells = array();
public function __toString()
{
return static::CHAR;
}
static public function getChar()
{
return static::CHAR;
}
public function getVisibility()
{
return static::VISIBILITY;
}
public function setPlace(Place $place)
{
// Remove from old place if exists
if ($this->place !== null)
$this->place->getLevel()->removeEntity($this->place->getCoord());
$this->place = $place;
if ($this->place !== null)
$this->place->getLevel()->insertEntity($this->place->getCoord(), $this);
}
public function getPlace()
{
return $this->place;
}
public function drawPath(Entity $target, $callback)
{
$targetX = $target->getPlace()->getCoord()->x;
$targetY = $target->getPlace()->getCoord()->y;
$startX = $this->getPlace()->getCoord()->x;
$startY = $this->getPlace()->getCoord()->y;
if ($startX == $targetX && $startY == $targetY)
return;
$diffX = $targetX - $startX;
$diffY = $targetY - $startY;
$step = max(abs($diffX), abs($diffY));
$stepX = $diffX / $step;
$stepY = $diffY / $step;
if ($stepX != 0)
$steps = floor($diffX / $stepX);
else
$steps = floor($diffY / $stepY);
$x = $startX;
$y = $startY;
$i = 0;
do
{
$x += $stepX;
$y += $stepY;
++$i;
if (!$callback(new Coord(floor($x), floor($y))))
return;
} while ((floor($x) != $targetX || floor($y) != $targetY)
&& $i < $steps);
}
public function canSee(Entity $target)
{
// Check if already marked as seen
if (isset($this->seenCells[$target->getPlace()->getCoord()->x][$target->getPlace()->getCoord()->y]))
return true;
// Check distance
if ($this->getSight() < $this->getPlace()->getCoord()->getDistance($target->getPlace()->getCoord()))
return false;
// Check each cell on the way for opaque objects
$level = $this->getPlace()->getLevel();
$return = true;
$seenCells =& $this->seenCells;
$this->drawPath($target, function(Coord $coord) use (&$return, $level, $target,
&$seenCells)
{
$obj = $level->whatsAt($coord);
if ($obj !== null && $obj != $target && $obj->getVisibility() == Entity::VSB_VISIBLE)
{
$return = false;
return false;
}
$seenCells[$coord->x][$coord->y] = true;
return true;
});
return $return;
}
}

26
class_human.php Normal file
View file

@ -0,0 +1,26 @@
<?php
class Human extends AbstractBeing
{
const CHAR = 'H';
private $sex;
public function __construct($name = null, $exp = 0, array $items = null, array $equips = null, $speed = null, $sight = null, $hp = 0, $mp = 0, $money = null, Place $place = null)
{
$this->sex = rand(0, 1);
parent::__construct($name, $exp, $items, $equips, $speed, $sight, $hp, $mp, $money, $place);
}
public function setSex($sex)
{
$this->sex = $sex;
}
public function getSex()
{
if ($this->sex == 0)
return 'male';
return 'female';
}
}

15
class_item.php Normal file
View file

@ -0,0 +1,15 @@
<?php
interface Item
{
private $name;
private $value;
public function equip(Being wearer);
public function unequip(Being wearer);
public function sell(Being seller, Being buyer);
public function use(Being user);
public function getName();
public function getValue();
}

298
class_level.php Normal file
View file

@ -0,0 +1,298 @@
<?php
class Level
{
const MIN_STROKES = 5;
const MAX_STROKES = 25;
const BLOOM_MAX = 1, BLOOM_MIN = 0;
// This needs its own definitions of these so we can use some stupid array tricks
const DIR_NONE = -1, DIR_UP = 0, DIR_RIGHT = 1, DIR_DOWN = 2, DIR_LEFT = 3;
private $coords;
private $width;
private $height;
private $dungeon;
private $changes;
public function __construct(Dungeon $dungeon, $createRandom = true)
{
$this->coords = array();
$this->width = 0;
$this->height = 0;
if ($createRandom)
$this->createRandom();
$this->dungeon = $dungeon;
}
public function whatsAt(Coord $place)
{
return (isset($this->coords[(string) $place]))? $this->coords[(string) $place] : null;
}
public function insertEntity(Coord $place, Entity $entity)
{
if (isset($this->coords[(string) $place])
&& !($this->coords[(string) $place] instanceof EmptyFloor))
throw new PlaceOccupiedException('Cannot insert, place already taken.');
$this->coords[(string) $place] = $entity;
$this->width = max($this->width, $place->x);
$this->height = max($this->height, $place->y);
}
public function removeEntity(Coord $place)
{
if (!isset($this->coords[(string) $place])
|| $this->coords[(string) $place] instanceof EmptyFloor)
throw new PlaceException('Cannot remove, nothing there.');
unset($this->coords[(string) $place]);
$floor = new EmptyFloor();
$floor->setPlace(new Place($this, $place));
}
public function printLevel(Display $disp)
{
foreach ($this->coords as $coord => $content)
{
// +1 to X and Y since in the terminal they start from 1,1
$expCoord = Coord::createFromString($coord);
$disp->writeTo($expCoord->x + 1, $expCoord->y + 1, $this->whatsAt($expCoord));
}
}
public function getWidth()
{
return $this->width;
}
public function getHeight()
{
return $this->height;
}
public function getDungeon()
{
return $dungeon;
}
public function getEmptyPlace()
{
$keys = array_keys($this->coords);
shuffle($keys);
do
{
$coord = array_pop($keys);
if ($coord === null)
throw new PlaceException('No empty place found for entity.');
$content = $this->coords[$coord];
} while (!($content instanceof EmptyFloor));
return Coord::createFromString($coord);
}
private function createRandom()
{
$strokes = array();
$strokeAmount = rand(static::MIN_STROKES, static::MAX_STROKES);
$ends = array();
for ($i = 0; $i < $strokeAmount; ++$i)
{
$start = null; $dir = 0;
if (empty($ends)) // If empty, start somewhere
{
$start = new Coord(rand(2, TERM_X - 3), rand(2, TERM_Y - 3));
$freeDir = rand(self::DIR_UP, self::DIR_LEFT);
$ends[] = $start;
$strokes[(string) $start] = true;
}
else // Else find a previous intersection and start there
{
$freeDir = self::DIR_NONE;
shuffle($ends);
$endAmnt = count($ends);
for ($r = 0; $r < $endAmnt && $freeDir == self::DIR_NONE; ++$r)
{
$start = $ends[$r];
$freeDir = $this->getFreeDir($start, $strokes);
}
// No free spots could be found, end algorithm
if ($freeDir == self::DIR_NONE)
break;
}
// Now create strokes from that place onwards
$strokeLines = rand(1, ceil($strokeAmount / 2));
for ($r = 0; $r < $strokeLines; ++$r)
{
$newStart = $this->strokeLine($start, $strokes, $ends);
if ($newStart === null) // Couldn't find a free direction
break;
$start = $newStart;
$ends[] = $start;
}
}
// Widen created strokes
$strokes = $this->bloom($strokes);
// Build walls
$this->buildWalls($strokes);
}
private function getFreeDir(Coord $coord, array $reserved)
{
$dirs = range(self::DIR_UP, self::DIR_LEFT);
shuffle($dirs);
foreach ($dirs as $dir)
{
if ($dir == self::DIR_UP && $coord->y > 1 && !isset($reserved[(string) (new Coord($coord->x, $coord->y - 1))]))
return $dir;
elseif ($dir == self::DIR_DOWN && $coord->y < TERM_Y - 2 && !isset($reserved[(string) (new Coord($coord->x, $coord->y + 1))]))
return $dir;
elseif ($dir == self::DIR_RIGHT && $coord->x < TERM_X - 2 && !isset($reserved[(string) (new Coord($coord->x + 1, $coord->y))]))
return $dir;
elseif ($dir == self::DIR_LEFT && $coord->x > 1 && !isset($reserved[(string) (new Coord($coord->x - 1, $coord->y))]))
return $dir;
}
return self::DIR_NONE;
}
private function strokeLine(Coord $start, array &$strokes, array &$ends)
{
// Get direction
$dir = $this->getFreeDir($start, $strokes);
if ($dir == self::DIR_NONE)
return null;
switch ($dir)
{
case self::DIR_UP:
$maxLen = ceil(($start->y - 1) / 3);
break;
case self::DIR_DOWN:
$maxLen = ceil((TERM_Y - 2 - $start->y) / 3);
break;
case self::DIR_RIGHT:
$maxLen = ceil((TERM_X - 2 - $start->x) / 3);
break;
case self::DIR_LEFT:
$maxLen = ceil(($start->x - 1) / 3);
}
$length = rand(ceil($maxLen / 2), $maxLen);
$nextCoord = clone $start;
// Now add line to $strokes
for ($i = 1; $i <= $length; ++$i)
{
switch ($dir)
{
case self::DIR_UP:
$nextCoord = new Coord($nextCoord->x, $nextCoord->y - 1);
break;
case self::DIR_DOWN:
$nextCoord = new Coord($nextCoord->x, $nextCoord->y + 1);
break;
case self::DIR_RIGHT:
$nextCoord = new Coord($nextCoord->x + 1, $nextCoord->y);
break;
case self::DIR_LEFT:
$nextCoord = new Coord($nextCoord->x - 1, $nextCoord->y);
}
$strokes[(string) $nextCoord] = true;
$ends[] = $nextCoord;
}
return $nextCoord;
}
private function bloom(array $reserved)
{
$bloom = rand(self::BLOOM_MIN, self::BLOOM_MAX);
$added = array();
foreach ($reserved as $key => $coord)
{
$coord = Coord::createFromString($key);
for ($x = ($coord->x - $bloom); $x <= ($coord->x + $bloom); ++$x)
{
for ($y = ($coord->y - $bloom); $y <= ($coord->y + $bloom); ++$y)
{
if ($x > 0 && $x < TERM_X - 1 && $y > 0 && $y < TERM_Y - 1)
{
$added[(string) (new Coord($x, $y))] = true;
}
}
}
// Calculate next bloom size
$action = rand(1, 6);
switch ($action)
{
case 1:
// Completely new bloom 1/6 of the time
$bloom = rand(self::BLOOM_MIN, self::BLOOM_MAX);
break;
case 2:
// Slightly new bloom 1/6 of the time
$vals = array(max($bloom - 1, self::BLOOM_MIN), min($bloom + 1, self::BLOOM_MAX));
$bloom = $vals[array_rand($vals)];
break;
// Else no change to bloom 2/3 of the time
}
}
return array_merge($reserved, $added);
}
private function buildWalls(array $reserved)
{
foreach ($reserved as $coord => $dummy)
{
$coord = Coord::createFromString($coord);
// Loop around each cell
for ($x = ($coord->x - 1); $x <= ($coord->x + 1); ++$x)
{
for ($y = ($coord->y - 1); $y <= ($coord->y + 1); ++$y)
{
if ($x < 0 || $y < 0 || $x >= TERM_X || $y >= TERM_Y)
throw new SDGException();
if ($x >= 0 && $x < TERM_X && $y >= 0 && $y < TERM_Y && !isset($reserved[$x . ',' . $y])) // This cell is empty
{
try
{
$wall = new Wall();
$wall->setPlace(new Place($this, new Coord($x, $y)));
} catch (PlaceOccupiedException $e)
{ }
}
}
}
// Create empty floor tile for reserved place
$floor = new EmptyFloor();
$floor->setPlace(new Place($this, $coord));
}
}
}

50
class_leveldrawer.php Normal file
View file

@ -0,0 +1,50 @@
<?php
class LevelDrawer
{
private $disp;
private $dude;
public function __construct(Display $disp)
{
$this->dude = DudeStore::getDude();
$this->changeDisplay($disp);
}
public function changeDisplay(Display $disp)
{
$this->disp = $disp;
}
public function drawEverything()
{
$this->dude->getPlace()->getLevel()->printLevel();
}
public function drawDudeView()
{
$this->drawView($this->dude->getBase());
}
public function drawView(AbstractBeing $being)
{
$radius = $being->getSight();
$beingX = $being->getPlace()->getCoord()->x;
$beingY = $being->getPlace()->getCoord()->y;
// Only print the characters inside the being's sight radius
for ($x = $beingX - $radius; $x <= $beingX + $radius; ++$x)
{
for ($y = $beingY - $radius; $y <= $beingY + $radius; ++$y)
{
$obj = $being->getPlace()->getLevel()->whatsAt(new Coord($x, $y));
if ($obj !== null)
{
// Draw path to object and only display those that can be seen
if ($being->canSee($obj))
$this->disp->writeTo($x + 1, $y + 1, $obj);
}
}
}
}
}

23
class_place.php Normal file
View file

@ -0,0 +1,23 @@
<?php
class Place
{
private $level;
private $coord;
public function __construct(Level $level, Coord $coord)
{
$this->level = $level;
$this->coord = $coord;
}
public function getCoord()
{
return $this->coord;
}
public function getLevel()
{
return $this->level;
}
}

6
class_placeexception.php Normal file
View file

@ -0,0 +1,6 @@
<?php
class PlaceException extends SDGException
{
}

View file

@ -0,0 +1,6 @@
<?php
class PlaceOccupiedException extends PlaceException
{
}

View file

@ -0,0 +1,9 @@
<?php
class RandomItemFactory
{
static public function getItem(AbstractBeing $being)
{
}
}

7
class_room.php Normal file
View file

@ -0,0 +1,7 @@
<?php
class Room
{
}

6
class_sdgexception.php Normal file
View file

@ -0,0 +1,6 @@
<?php
class SDGException extends Exception
{
}

24
class_settings.php Normal file
View file

@ -0,0 +1,24 @@
<?php
class Settings
{
private $settings;
public function __construct()
{
$this->settings = array();
}
public function set($setting, $value)
{
$this->settings[$setting] = $value;
}
public function get($setting)
{
if (is_object($this->settings[$setting]))
return clone $this->settings[$setting];
else
return $this->settings[$setting];
}
}

19
class_settingsman.php Normal file
View file

@ -0,0 +1,19 @@
<?php
class SettingsMan
{
static private $sets;
static public function get($set = 0)
{
return self::$sets[$set];
}
static public function add($set = null, Settings $settings)
{
if ($set !== null)
self::$sets[$set] = $settings;
else
self::$sets[] = $settings;
}
}

7
class_wall.php Normal file
View file

@ -0,0 +1,7 @@
<?php
class Wall extends Entity
{
const VISIBILITY = parent::VSB_VISIBLE;
const CHAR = '#';
}

4
inc_ansi.php Normal file
View file

@ -0,0 +1,4 @@
<?php
define('ANSI_ESC', chr(0x1B));
define('ANSI_CSI', ANSI_ESC . '[');

10
inc_stuffz.php Normal file
View file

@ -0,0 +1,10 @@
<?php
const DIR_NONE = 0,
DIR_UP = 1,
DIR_DOWN = 2,
DIR_RIGHT = 4,
DIR_LEFT = 8;
const TERM_X = 126,
TERM_Y = 40;

54
sdg.php Normal file
View file

@ -0,0 +1,54 @@
<?php
// Some Dungeon Game
// 0.1
// © Nicd
require_once 'inc_stuffz.php';
require_once 'inc_ansi.php';
function __autoload($class)
{
require_once 'class_' . strtolower($class) . '.php';
}
$disp = DisplayFactory::getDefault();
$disp->clear();
$disp->setColor(Display::COLOR_RED);
$dungeon = new Dungeon();
$level = new Level($dungeon);
$dungeon->addLevelBelow($level);
$human = new Human('', 0, null, null, null, 40);
$enemy = new Human();
$enemy->setRandomPlace($level);
$dude = new Dude($human);
$human->setRandomPlace($level);
$draw = new LevelDrawer($disp);
DisplayFactory::terminalSetRaw();
$disp->clear();
$draw->drawDudeView();
$input = '';
do
{
$input = fread(STDIN, 1);
if (ctype_digit($input))
{
$dude->move($input);
$disp->clear();
$draw->drawDudeView();
}
elseif ($input == 'd')
{
$enemy->drawPath($disp, $dude->getBase());
}
} while($input != 'q');
$disp->setStyle();
DisplayFactory::terminalSetCooked();