diff options
-rw-r--r-- | .htaccess | 1 | ||||
-rw-r--r-- | craftmine.php | 9 | ||||
-rw-r--r-- | css/craftmine.css | 9 | ||||
-rw-r--r-- | inc/Inventory.inc | 41 | ||||
-rw-r--r-- | inc/Item.inc | 17 | ||||
-rw-r--r-- | inc/account.inc | 18 | ||||
-rw-r--r-- | inc/craftmine.inc | 14 | ||||
-rw-r--r-- | inc/messages.inc | 15 | ||||
-rw-r--r-- | inc/mine.inc | 4 | ||||
-rw-r--r-- | inc/shop.inc | 59 | ||||
-rw-r--r-- | index.xhtml | 78 | ||||
-rw-r--r-- | js/craftmine.js | 22 | ||||
-rw-r--r-- | js/gui.js | 42 | ||||
-rw-r--r-- | js/shop.js | 57 |
14 files changed, 371 insertions, 15 deletions
diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..1aea756 --- /dev/null +++ b/.htaccess @@ -0,0 +1 @@ +DirectoryIndex index.xhtml diff --git a/craftmine.php b/craftmine.php index 5df926f..869c83a 100644 --- a/craftmine.php +++ b/craftmine.php @@ -1,7 +1,10 @@ <?php -session_start(); require_once("inc/mine.inc"); +require_once("inc/shop.inc"); + +session_start(); // Must be placed *BEFORE* $_SESSION is actually used and *AFTER* all classes are imported + /** * Indique au client une message requete. */ @@ -32,7 +35,9 @@ if (!isset($_POST["op"])) { $op = $_POST["op"]; switch($op) { case "withdrawMine": withdrawMine(); break; - case "getCraftMine": sendMine(); break; + case "getCraftMine": sendCraftMine(); break; + case "buildShop": buildShop(); break; + case "buyItem": buyItem(); break; default: reportBadRequest(); } diff --git a/css/craftmine.css b/css/craftmine.css new file mode 100644 index 0000000..2a51ff7 --- /dev/null +++ b/css/craftmine.css @@ -0,0 +1,9 @@ +.tab-pane { + display: none; +} +.tab-pane:target { + display: block; +} +.item-icon { + font-size: 3em; +} diff --git a/inc/Inventory.inc b/inc/Inventory.inc new file mode 100644 index 0000000..efe54f2 --- /dev/null +++ b/inc/Inventory.inc @@ -0,0 +1,41 @@ +<?php + +class Inventory { + + public $items = array(); + + public static function created() { + return !empty($_SESSION["inventory"]); + } + + public static function sendContent() { + return self::get()->items; + } + + public static function get() { + if(!self::created()) { + $_SESSION["inventory"] = new Inventory(); + } + return $_SESSION["inventory"]; + } + + private function _addItem($item) { + $this->items[] = $item; + } + + public static function addItem($item) { + $inv = self::get(); + $inv->_addItem($item); + } + + private function _removeItem($item) { + unset($this->items[array_search($item, $this->items)]); + } + + public static function removeItem($item) { + $inv = self::get(); + $inv->_removeItem($item); + } +} + +?> diff --git a/inc/Item.inc b/inc/Item.inc new file mode 100644 index 0000000..bf77818 --- /dev/null +++ b/inc/Item.inc @@ -0,0 +1,17 @@ +<?php + +class Item { + public $name = ""; + public $cost = 0; + public $icon = ""; + public $desc = ""; + + function __construct($name, $cost, $icon, $desc) { + $this->name = $name; + $this->cost = $cost; + $this->icon = $icon; + $this->desc = $desc; + } +} + +?> diff --git a/inc/account.inc b/inc/account.inc new file mode 100644 index 0000000..19f311d --- /dev/null +++ b/inc/account.inc @@ -0,0 +1,18 @@ +<?php +require_once("messages.inc"); + +function debitAccount($amount) { + if($_SESSION["mine"]["gold"] <= $amount) { + sendError("gold_insufficient"); + return false; + } + $_SESSION["mine"]["gold"] -= $amount; + return true; +} + +function creditAccount($amount) { + $_SESSION["mine"]["gold"] += $amount; +} + + +?> diff --git a/inc/craftmine.inc b/inc/craftmine.inc new file mode 100644 index 0000000..a30538c --- /dev/null +++ b/inc/craftmine.inc @@ -0,0 +1,14 @@ +<?php + +require_once("mine.inc"); +require_once("shop.inc"); + +function sendCraftMine() { + $data = array("gold" => sendMine(), + "shop" => sendShop(), + "inventory" => Inventory::sendContent(), + ); + echo json_encode($data); +} + +?> diff --git a/inc/messages.inc b/inc/messages.inc new file mode 100644 index 0000000..f1ca8b3 --- /dev/null +++ b/inc/messages.inc @@ -0,0 +1,15 @@ +<?php + +$messages = array( + "shop_already_built" => "You have already built a shop.", + "gold_insufficient" => "You don't have enough gold.", + "shop_missing_item" => "This item does not exist.", +); + +function sendError($msg) { + global $messages; + $text = $messages[$msg]; + echo json_encode(array("error" => $text)); +} + +?> diff --git a/inc/mine.inc b/inc/mine.inc index aea04ad..6a04cc4 100644 --- a/inc/mine.inc +++ b/inc/mine.inc @@ -8,13 +8,13 @@ function withdrawMine() { $amount = intval($_POST["amount"]); if($amount == 0) return; $_SESSION["mine"]["gold"] += $amount; - echo $_SESSION["mine"]["gold"]; + echo json_encode($_SESSION["mine"]["gold"]); } function sendMine() { if(empty($_SESSION["mine"])) initCraftMine(); $mine = $_SESSION["mine"]; - echo $mine["gold"]; + return $mine["gold"]; } diff --git a/inc/shop.inc b/inc/shop.inc new file mode 100644 index 0000000..11cf97b --- /dev/null +++ b/inc/shop.inc @@ -0,0 +1,59 @@ +<?php + +require_once("messages.inc"); +require_once("account.inc"); +require_once("Item.inc"); +require_once("Inventory.inc"); + +$shop = array( + "cost" => 3, + "items" => array( + new Item("cat", 6, "🐈", "Nyan!"), + new Item("torch", 3, "🔦", "Electric torch"), + ), +); + +function getItem($name) { + global $shop; + foreach($shop["items"] as $item) { + if($name == $item->name) { + return $item; + } + } + sendError("shop_missing_item"); + return false; +} + +function initShop() { + $_SESSION["shop"] = true; +} + +function sendShop() { + global $shop; + if(!empty($_SESSION["shop"])) + return $shop; + else return false; +} + +function buildShop() { + global $shop; + if(!empty($_SESSION["shop"])) { + sendError("shop_already_built"); + } + elseif(debitAccount($shop["cost"])) { + initShop(); + $_SESSION["mine"]["gold"] -= $shop["cost"]; + echo json_encode(sendShop()); + } +} + +function buyItem() { + $item = getItem($_POST["item"]); + if($item && debitAccount($item->cost)) { + Inventory::addItem($item); + echo json_encode($item); + } +} + + +?> diff --git a/index.xhtml b/index.xhtml index 5b38b69..6ec45ef 100644 --- a/index.xhtml +++ b/index.xhtml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/css" href="css/bootstrap.min.css"?> +<?xml-stylesheet type="text/css" href="css/craftmine.css"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> @@ -11,13 +12,78 @@ <meta name="author" content="Alexandre Renoux,Pierre-Emmanuel Novac"/> <title>CraftMine</title> <script type="text/javascript" charset="utf-8" src="js/craftmine.js"></script> + <script type="text/javascript" charset="utf-8" src="js/shop.js"></script> + <script type="text/javascript" charset="utf-8" src="js/gui.js"></script> </head> -<body onload="init()"> +<body onload="init()" onhashchange="changeTab()"> +<div class="container-fluid"> +<div class="row"> <h1>CraftMine</h1> - <span id="gold">0</span> - <span id="mine">0</span> - <form class="form-horizontal" method="post" action="craftmine.php"> - <button type="button" name="withdraw" onclick="withdrawMine()">Withdraw</button> - </form> +</div> +<div class="row"> + <div class="col-md-4"> + <div class="row"> + <div class="col-md-10"> + <span id="gold">0</span> + <span id="mine">0</span> + <form class="form-horizontal" method="post" action="craftmine.php"> + <button class="btn btn-default" type="button" name="withdraw" onclick="withdrawMine()">Withdraw</button> + </form> + </div> + </div> + <div id="error-box" class="row" style="margin-top:1em;display:none"> + <div class="col-md-10"> + <div class="alert alert-danger"> + <ul> + </ul> + </div> + </div> + </div> + <div id="info-box" class="row" style="margin-top:1em;display:none"> + <div class="col-md-10"> + <div class="alert alert-success"> + <ul> + </ul> + </div> + </div> + </div> + + </div> + <div class="col-md-8"> + <div class="row"> + + <div id="tabs-panel" class="tabbable"> + <ul class="nav nav-tabs"> + <li role="presentation"><a href="#tab1" data-toggle="tab">Build</a></li> + <li role="presentation"><a href="#tab2" data-toggle="tab">Shop</a></li> + <li role="presentation"><a href="#tab3" data-toggle="tab">Inventory</a></li> + <li role="presentation"><a href="#tab4" data-toggle="tab">Dungeon</a></li> + </ul> + <div class="tab-content"> + <div class="tab-pane" id="tab1"> + <h4>Select a building to build:</h4> + <ul class="list-inline"> + <li><button class="btn btn-default" type="button" onclick="">Miner's guild</button></li> + <li><button class="btn btn-default" type="button" onclick="buildShop()">Shop</button></li> + </ul> + </div> + <div class="tab-pane" id="tab2"> + <h4>There's no shop in this city.</h4> + </div> + <div class="tab-pane" id="tab3"> + <h4>Your inventory is empty.</h4> + </div> + <div class="tab-pane" id="tab4"> + <h4>Look at how poor you are! You can't access the dungeon, it is only for the elite.</h4> + </div> + </div> + </div> + + + + </div> + </div> +</div> +</div> </body> </html> diff --git a/js/craftmine.js b/js/craftmine.js index bbb1074..66c35fc 100644 --- a/js/craftmine.js +++ b/js/craftmine.js @@ -11,7 +11,12 @@ function sendRequest(url, params, callback) { xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.onreadystatechange = function() { if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == "200") { - callback(xhr); + var data = JSON.parse(xhr.responseText); + if(data.error) { + showError(data.error); + return; + } + if(callback) callback(data); } } xhr.send(params); @@ -24,9 +29,14 @@ function updateData() { } } +function debitAccount(amount) { + data.gold -= amount; + updateData("gold"); +} + function withdrawMine() { sendRequest("craftmine.php", "op=withdrawMine&amount="+data.mine, function(xhr) { - var gold = parseInt(xhr.responseText); // Server's response is a string + var gold = parseInt(xhr); // Server's response is a string if(isNaN(gold)) return; data.gold = gold; data.mine = 0; @@ -35,9 +45,10 @@ function withdrawMine() { } function initCraftMine() { - sendRequest("craftmine.php", "op=getCraftMine", function(xhr) { - var ret = xhr.responseText; - data.gold = parseInt(ret); // Server's response is a string + sendRequest("craftmine.php", "op=getCraftMine", function(ret) { + data.gold = parseInt(ret.gold); // Server's response is a string + if(ret.shop) displayShop(ret.shop); + displayInventory(ret.inventory); updateData("gold"); }) } @@ -50,5 +61,6 @@ function updateMine() { function init() { initCraftMine(); + changeTab(); window.setInterval(updateMine, 1000); } diff --git a/js/gui.js b/js/gui.js new file mode 100644 index 0000000..bdf1710 --- /dev/null +++ b/js/gui.js @@ -0,0 +1,42 @@ +var MESSAGE_TIMEOUT = 4000; + +function changeTab() { + var hashtype = window.location.hash.substr(1,3); + if(hashtype != "tab") return; + var id = window.location.hash.substr(4); + var tabs = document.querySelectorAll("#tabs-panel > ul > li"); + for(var i=0; i < tabs.length; i++) { + if(i == id-1) + tabs[i].className = "active"; + else + tabs[i].className = ""; + } + +} + +function showMessage(type, msg) { + var msg_box = document.getElementById(type+"-box"); + msg_box.style.display = "initial"; + var msg_list = msg_box.firstElementChild.firstElementChild.firstElementChild; + msg_list.innerHTML = "<li>" + msg + "</li>\n" + msg_list.innerHTML; + + window.setTimeout(hideMessage.bind(null, type), MESSAGE_TIMEOUT); +} + +function hideMessage(type) { + var msg_box = document.getElementById(type+"-box"); + var msg_list = msg_box.firstElementChild.firstElementChild.firstElementChild; + var item = msg_list.lastElementChild; + msg_list.removeChild(item); + + if(msg_list.children.length <= 0) + msg_box.style.display = "none"; +} + +function showError(msg) { + showMessage("error", msg); +} + +function showInfo(msg) { + showMessage("info", msg); +} diff --git a/js/shop.js b/js/shop.js new file mode 100644 index 0000000..00636e1 --- /dev/null +++ b/js/shop.js @@ -0,0 +1,57 @@ +function displayShop(ret) { + var tmphtml = "<h4> Select an item to buy it:</h4>"; + tmphtml += "<ul class=\"list-inline\">"; + for(var i=0; i < ret.items.length; i++) { + tmphtml += "<li>"; + tmphtml += "<button type=\"submit\" class=\"btn btn-primary\" onclick=\"buyItem('" + ret.items[i].name + "')\"><span class=\"item-icon\">" + ret.items[i].icon + "</span><br />" + ret.items[i].name + "</button>"; + tmphtml += "</li>"; + } + tmphtml += "</ul>" + document.getElementById("tab2").innerHTML = tmphtml; +} + +function displayInventory(items) { + for(var i=0; i < items.length; i++) { + addItem(items[i]); + } +} + +function buildShop() { + sendRequest("craftmine.php", "op=buildShop", function(ret) { + displayShop(ret); + debitAccount(ret.cost); + }); +} + +function addItem(ret) { + var itemhtml = "<li>"; + itemhtml += "<button type=\"submit\" class=\"btn btn-primary\" onclick=\"useItem('" + ret.name + "')\"><span class=\"item-icon\">" + ret.icon + "</span><br />" + ret.name + "</button>"; + itemhtml += "</li>"; + + var invcontent = document.getElementById("tab3"); + + if(invcontent.children.length <= 1) + { + var tmphtml = "<h4>Your bag contains the following items:</h4>"; + tmphtml += "<ul class=\"list-inline\">"; + tmphtml += itemhtml; + tmphtml += "</ul>" + invcontent.innerHTML = tmphtml; + } else + invcontent.getElementsByTagName('ul')[0].innerHTML += itemhtml; + + showInfo(ret.desc); +} + +function buyItem(name) { + sendRequest("craftmine.php", "op=buyItem&item="+name, function(ret) { + addItem(ret); + debitAccount(ret.cost); + }); +} + +function useItem(name) { + sendRequest("craftmine.php", "op=useItem&item="+name, function(ret) { + }); +} + |