[]Cork~ told me it works, haha
[mudd.git] / mud.php
diff --git a/mud.php b/mud.php
new file mode 100644 (file)
index 0000000..9e347a3
--- /dev/null
+++ b/mud.php
@@ -0,0 +1,220 @@
+<?php
+
+abstract class model {
+
+    private $config_file = '/etc/mud.ini';
+    private $db;
+
+    public function __construct() {
+        $config = parse_ini_file($this->config_file, true);
+        $this->db = new mysqli(
+            $config['database']['domain'],
+            $config['database']['user'],
+            $config['database']['password'],
+            $config['database']['database']);
+        if (mysqli_connect_errno()) {
+            echo "Problem connecting to database: ";
+            echo mysqli_connect_error();
+            exit();
+        }
+    }
+
+    public function query() {
+        $args = func_get_args();
+        $statement = $this->db->prepare(array_shift($args));
+        if ($args) call_user_func_array(array($statement, 'bind_param'), &$args);
+        $statement->execute();
+        $statement->store_result();
+        $statement->store_result();
+        $data = $statement->result_metadata();
+        $return = $row = $fields = array();
+        $fields[0] = &$statement;
+        while($field = $data->fetch_field())
+            $fields[] = &$row[$field->name];
+        call_user_func_array("mysqli_stmt_bind_result", $fields);
+        $i = 0;
+        while ($statement->fetch()) {
+            foreach ($row as $key=>$value) $return[$i][$key] = $value;
+            $i++;
+        }
+        $statement->free_result();
+        return $return;
+    }
+
+    public function insert() {
+        $args = func_get_args();
+        $statement = $this->db->prepare(array_shift($args));
+        call_user_func_array(array($statement, 'bind_param'), &$args);
+        $statement->execute();
+        return $this->db->insert_id;
+    }
+
+}
+
+class universe {
+    public $rows = 30;
+    public $columns = 30;
+    public $rooms = array();
+
+    public function __construct($db) {
+        $rooms = $db->query("SELECT id,x,y,state FROM rooms");
+        if ($rooms) {
+            foreach ($rooms as $room) {
+                $this->rooms[$room['x']][$room['y']] =
+                    array('id' => $room['id'], 'state' => $room['state']);
+            }
+        } else {
+            $sql = 'INSERT INTO rooms (x,y,state) VALUES(?,?,?)';
+            $types = 'iii';
+            for ($x = 0; $x < $this->columns; $x++) {
+                $column = array();
+                for ($y = 0; $y < $this->rows; $y++) {
+                    $state = (rand(0, 9) < 2 ? true : false);
+                    $id = $db->insert($sql, $types, $x, $y, $state);
+                    $this->rooms[$x][$y] = 
+                        array('id' => $id, 'state' => $state);
+                }
+            }
+        }
+    }
+
+    public function serialize() {
+        $serial = array();
+        for ($x = 0; $x < $this->columns; $x++) {
+            for ($y = 0; $y < $this->rows; $y++) {
+                $serial[$x][$y] = $this->rooms[$x][$y]['state'];
+            }
+        }
+        return $serial;
+    }
+
+}
+
+class player {
+
+    public $id;
+    public $name;
+    public $room;
+    public $x;
+    public $y;
+
+    public function __construct($db) {
+        $player = $db->query(
+            'SELECT players.id, players.name, players.room, rooms.x, rooms.y'
+            . ' FROM players LEFT JOIN rooms ON players.room = rooms.id'
+            . ' WHERE players.id = ?',
+            'i', $_SESSION['id']
+        );
+        $player = $player[0];
+        $this->id = $player['id'];
+        $this->name = $player['name'];
+        $this->room = $player['room'];
+        $this->x = $player['x'];
+        $this->y = $player['y'];
+    }
+
+}
+
+class mud extends model {
+
+    private $universe;
+
+    public function __construct() {
+        parent::__construct();
+        session_start();
+        $this->universe = new universe($this);
+    }
+
+    private function join() {
+        $x = 0;
+        $y = 0;
+        if (isset($_SESSION['id'])) {
+            $x = $this->player->x;
+            $y = $this->player->y;
+            $id = $this->player->id;
+        } else {
+            do {
+                $x = rand(0, count($this->universe->rooms)-1);
+                $y = rand(0, count($this->universe->rooms[0])-1);
+            } while ($this->universe->rooms[$x][$y]['state']);
+            $id = $this->insert('INSERT INTO players (name,room) VALUES(?,?)',
+                                'si', 'majuscule', $this->universe->rooms[$x][$y]['id']);
+            $_SESSION['id'] = $id;
+        }
+        return array('x' => $x, 'y' => $y, 'id' => $id);
+    }
+
+    private function yell($msg) {
+        $this->insert(
+            'INSERT INTO messages (message,type,room,source) VALUES(?,?,?,?)',
+            'ssii', $msg, 'yell', $this->player->room, $this->player->id);
+    }
+
+    private function poll() {
+        $time = isset($_SESSION['last_polled']) ? $_SESSION['last_polled'] : 0;
+        $messages = $this->query(
+            'SELECT message, type, name, sent, players.id FROM messages LEFT JOIN players'
+            . ' ON destination = players.id'
+            . ' OR source = players.id'
+            . ' WHERE TIMESTAMPDIFF(MINUTE, sent, NOW()) < 5'
+            . ' AND UNIX_TIMESTAMP(sent) >= ?'
+            . ' AND (type = "yell"'
+                . ' OR (type = "tell" AND destination = ?)'
+                . ' OR (type = "say" AND messages.room = ?))',
+            'iii', $time, $this->player->id, $this->player->room);
+        $_SESSION['last_polled'] = time();
+        return $messages;
+    }
+
+    public function response($content) {
+        header('Content-Type: application/json');
+        echo json_encode($content);
+    }
+
+    public function command($cmd) {
+        if (!$_GET['cmd'])
+            $this->error(400, 'Missing command: expected `cmd` field');
+        if ($_GET['cmd'] != 'join' && $_GET['cmd'] != 'start' && !isset($_SESSION['id']))
+            $this->error(401, 'Missing user ID: please join first');
+        if (isset($_SESSION['id'])) $this->player = new player($this);
+        switch ($cmd) {
+            case 'start':
+                $this->response($this->universe->serialize());
+                break;
+            case 'join':
+                $this->response($this->join());
+                break;
+            case 'move':
+                $this->response(array('valid' => $this->move()));
+                break;
+            case 'tell':
+                $this->tell();
+                break;
+            case 'yell':
+                $this->yell($_GET['msg']);
+                break;
+            case 'say':
+                $this->say();
+                break;
+            case 'tell':
+                $this->tell();
+                break;
+            case 'poll':
+                echo json_encode($this->poll());
+                break;
+            default:
+                $this->error(400, 'Unknown command');
+        }
+    }
+
+    private function error($status, $msg) {
+        header("HTTP/1.0 $status");
+        echo $msg;
+    }
+
+}
+
+$mud = new mud();
+$mud->command($_GET['cmd']);
+
+?>