aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpiernov <piernov@piernov.org>2016-05-03 10:37:18 +0200
committerpiernov <piernov@piernov.org>2016-05-03 10:37:18 +0200
commit64e184b901fd4e7c9a829d14c5c34416923171c3 (patch)
tree70b5281ca85a38ef2a077e226dcce56a40ed563a
parentadd9d3248a5adc02b071a301005c6f11195f7f7b (diff)
parentb8112f72b322fe5bf7048ac76251c8c637b9fee2 (diff)
downloadcandybox-64e184b901fd4e7c9a829d14c5c34416923171c3.tar.gz
candybox-64e184b901fd4e7c9a829d14c5c34416923171c3.tar.bz2
candybox-64e184b901fd4e7c9a829d14c5c34416923171c3.tar.xz
candybox-64e184b901fd4e7c9a829d14c5c34416923171c3.zip
Merge branch 'master' into alexichi
-rw-r--r--craftmine.php17
-rw-r--r--css/Symbola.ttfbin0 -> 2188952 bytes
-rw-r--r--css/craftmine.css12
-rw-r--r--data/save/.gitignore1
-rw-r--r--inc/Inventory.inc6
-rw-r--r--inc/Item.inc12
-rw-r--r--inc/messages.inc18
-rw-r--r--inc/mine.inc2
-rw-r--r--inc/savegame.inc92
-rw-r--r--inc/shop.inc1
-rw-r--r--index.xhtml18
-rw-r--r--js/craftmine.js8
-rw-r--r--js/gui.js6
-rw-r--r--js/savegame.js42
14 files changed, 217 insertions, 18 deletions
diff --git a/craftmine.php b/craftmine.php
index 72817cc..242e1fd 100644
--- a/craftmine.php
+++ b/craftmine.php
@@ -5,8 +5,12 @@ require_once("inc/guild.inc");
require_once("inc/shop.inc");
require_once("inc/craftmine.inc");
require_once("inc/dungeon.inc");
+require_once("inc/savegame.inc");
+
session_start(); // Must be placed *BEFORE* $_SESSION is actually used and *AFTER* all classes are imported
+$op = "";
+
/**
* Indique au client une message requete.
*/
@@ -27,14 +31,16 @@ function reportBadRequest() {
exit();
}
if (!isset($_POST["op"])) {
- reportBadRequest();
-}
+ if(!isset($_GET["op"]))
+ reportBadRequest();
+ else
+ $op = $_GET["op"];
+} else $op = $_POST["op"];
/**
* On récupère l'opération à exécuter et on le fait.
*/
-$op = $_POST["op"];
switch($op) {
case "withdrawMine": withdrawMine(); break;
case "createGuild": createGuild(); break;
@@ -45,6 +51,11 @@ switch($op) {
case "buildDungeon" : buildDungeon(); break;
case "launchDungeon" : launchDungeon(); break;
case "exitDungeon" : exitDungeon(); break;
+ case "saveGame": saveGame(); break;
+ case "downSave": downSave(); break;
+ case "listSaves": listSaves(); break;
+ case "loadSave": loadSave(); break;
+ case "deleteSave": deleteSave(); break;
default: reportBadRequest();
}
diff --git a/css/Symbola.ttf b/css/Symbola.ttf
new file mode 100644
index 0000000..51d9a88
--- /dev/null
+++ b/css/Symbola.ttf
Binary files differ
diff --git a/css/craftmine.css b/css/craftmine.css
index 2a51ff7..c459baa 100644
--- a/css/craftmine.css
+++ b/css/craftmine.css
@@ -1,9 +1,21 @@
+@font-face {
+ font-family: "Symbola";
+ font-weight: bold;
+ src: url('Symbola.ttf');
+}
.tab-pane {
display: none;
}
.tab-pane:target {
display: block;
}
+.list-inline > li {
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
.item-icon {
+ display:inline-block;
+ width: 1em;
font-size: 3em;
+ font-family: "Symbola";
}
diff --git a/data/save/.gitignore b/data/save/.gitignore
new file mode 100644
index 0000000..4fcbff5
--- /dev/null
+++ b/data/save/.gitignore
@@ -0,0 +1 @@
+*.save.xml
diff --git a/inc/Inventory.inc b/inc/Inventory.inc
index 20c63bf..024a4fe 100644
--- a/inc/Inventory.inc
+++ b/inc/Inventory.inc
@@ -45,7 +45,11 @@ class Inventory {
$inv = self::get();
$inv->_removeItem($item);
}
-
+
+ public function addToXML($root) {
+ foreach($this->items as $item)
+ $item->addToXML($root);
+ }
}
?>
diff --git a/inc/Item.inc b/inc/Item.inc
index bf77818..8e90998 100644
--- a/inc/Item.inc
+++ b/inc/Item.inc
@@ -12,6 +12,18 @@ class Item {
$this->icon = $icon;
$this->desc = $desc;
}
+
+ function addToXML($root) {
+ $item = $root->addChild("item");
+ $item->addChild("name", $this->name);
+ $item->addChild("cost", $this->cost);
+ $item->addChild("icon", $this->icon);
+ $item->addChild("desc", $this->desc);
+ }
+
+ public static function fromXML($xml) {
+ return new static((string)$xml->name, +(string)$xml->cost /* convert to number */, (string)$xml->icon, (string)$xml->desc);
+ }
}
?>
diff --git a/inc/messages.inc b/inc/messages.inc
index c24bd18..c51adba 100644
--- a/inc/messages.inc
+++ b/inc/messages.inc
@@ -7,12 +7,26 @@ $messages = array(
"guild_not_yet_created" => "You need to create a guild first.",
"guild_already_built" => "You have aready built a guild.",
"dungeon_already_available" => "You can already access the dungeon"
+
+ "gamesave_ok" => "Game saved.",
+ "gamesave_error" => "An error occured when trying to save the game.",
+ "gamesave_not_found" => "Couldn't find the specified save file.",
+ "gamesave_delete_fail" => "Couldn't delete the specified save file.",
+ "gamesave_delete_success" => "Game save successfully removed from server",
);
-function sendError($msg) {
+function sendMessage($type, $msg) {
global $messages;
$text = $messages[$msg];
- echo json_encode(array("error" => $text));
+ echo json_encode(array($type => $text));
+}
+
+function sendError($msg) {
+ sendMessage("error", $msg);
+}
+
+function sendInfo($msg) {
+ sendMessage("info", $msg);
}
?>
diff --git a/inc/mine.inc b/inc/mine.inc
index 94a2c66..752fc69 100644
--- a/inc/mine.inc
+++ b/inc/mine.inc
@@ -1,7 +1,7 @@
<?php
function initCraftMine() {
- $_SESSION["mine"] = array("mine" => 0, "gold" => 0, "miners" => 0);
+ $_SESSION["mine"] = array("gold" => 0, "miners" => 0);
}
function withdrawMine() {
diff --git a/inc/savegame.inc b/inc/savegame.inc
new file mode 100644
index 0000000..1fa95b0
--- /dev/null
+++ b/inc/savegame.inc
@@ -0,0 +1,92 @@
+<?php
+
+require_once("inc/messages.inc");
+
+define("SAVEDIR", "data/save");
+
+function genXML($table, $xml) {
+ foreach($table as $k => $v) {
+ if(is_object($v)) { // Object: either Item or Inventory
+ if(is_callable(array($v, "addToXML"))) // Check if the object has a addToXML method
+ $v->addToXML($xml->addChild($k));
+ } elseif(is_array($v)) // Nested array
+ genXML($v, $xml->addChild($k));
+ else // Single value (numeric or string)
+ $xml->addChild($k, $v);
+ }
+}
+
+function genSave() {
+ $save = new SimpleXMLElement("<save/>");
+ genXML($_SESSION, $save);
+ return $save;
+}
+
+function genFilename() {
+ return "craftmine-".date("d-m-Y_H-i-s").".save.xml";
+}
+
+function saveGame() {
+ $save = genSave();
+ if($save->asXML(SAVEDIR."/".genFilename())) sendInfo("gamesave_ok");
+ else sendError("gamesave_error");
+}
+
+function downSave() {
+ $save = "";
+ $filename = "";
+
+ if(empty($_GET["filename"])) {
+ $filename = genFilename();
+ $save = genSave()->asXML(); // Send current game save file if no file specified
+ } else {
+ $filename = $_GET["filename"];
+ $save = file_get_contents(SAVEDIR . "/" . $filename);
+ if(empty($save)) return; // Probably file not found
+ }
+
+ header("Content-Type: application/xml"); // Force browser to intepret the file as XML
+ header("Content-Disposition: attachment; filename=".$filename); // Force download with specific filename
+ header("Cache-Control: no-cache"); // Avoid storing save file in proxy/browser cache
+ echo $save;
+}
+
+function listSaves() {
+ chdir(SAVEDIR); // Go to SAVEDIR folder, avoiding leading folder name in file list
+ echo json_encode(glob("*.save.xml"));
+}
+
+function parseSave($xml, &$table) { // Passing $table by reference
+ foreach($xml as $k => $v) {
+ if($v->count() == 0) { // No child, treat as string
+ $v = (string)$v;
+ if(is_numeric($v)) $v = +$v; // If it is in fact a number, treat it that way using PHP unary '+' coercion
+ $table[$k] = $v;
+ } elseif($k == "inventory") { // Special case for inventory: objects need to be created
+ foreach($v as $item) Inventory::addItem(Item::fromXML($item));
+ } else { // If nested array
+ $table[$k] = array();
+ parseSave($v, $table[$k]);
+ } // Other types unsupported (unused)
+ }
+}
+
+function deleteSave() {
+ if(empty($_POST["filename"])) return;
+ $path = SAVEDIR . "/" . basename($_POST["filename"]); // remove any leading directory
+ if(file_exists($path) && unlink($path))
+ sendInfo("gamesave_delete_success");
+ else sendError("gamesave_delete_fail");
+}
+
+function loadSave() {
+ if(empty($_POST["filename"])) return;
+ $xml = simplexml_load_file(SAVEDIR . "/" . $_POST["filename"]);
+ if(empty($xml)) {
+ sendError("gamesave_not_found");
+ return;
+ }
+ $_SESSION = array(); // drop current game
+ parseSave($xml, $_SESSION);
+}
+?>
diff --git a/inc/shop.inc b/inc/shop.inc
index 83b08b0..49ee20b 100644
--- a/inc/shop.inc
+++ b/inc/shop.inc
@@ -48,7 +48,6 @@ function buildShop() {
}
elseif(debitAccount($shop["cost"])) {
initShop();
- $_SESSION["mine"]["gold"] -= $shop["cost"];
echo json_encode($shop);
}
}
diff --git a/index.xhtml b/index.xhtml
index 2745c8a..ed3e7a6 100644
--- a/index.xhtml
+++ b/index.xhtml
@@ -16,7 +16,7 @@
<script type="text/javascript" charset="utf-8" src="js/shop.js"></script>
<script type="text/javascript" charset="utf-8" src="js/gui.js"></script>
<script type="text/javascript" charset="utf-8" src="js/dungeon.js"></script>
-
+ <script type="text/javascript" charset="utf-8" src="js/savegame.js"></script>
</head>
<body onload="init()" onhashchange="changeTab()">
<div class="container-fluid">
@@ -34,6 +34,8 @@
<form class="form-horizontal" method="post" action="craftmine.php">
<button class="btn btn-default" type="button" name="withdraw" onclick="withdrawMine()">Withdraw</button>
<button class="btn btn-default" type="button" name="HireMiner" onclick="hireMiner()">Hire one miner</button>
+ <button class="btn btn-default" type="button" onclick="saveGame()">Save game</button>
+ <button class="btn btn-default" type="button" onclick="downGame()">Download game</button>
</form>
</div>
</div>
@@ -64,6 +66,7 @@
<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>
+ <li role="presentation" class="pull-right"><a href="#tab5" data-toggle="tab" onclick="listSaves()">Save</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane" id="tab1">
@@ -83,11 +86,18 @@
<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 class="tab-pane" id="tab5">
+ <h4>Saved games:</h4>
+ <div class="form" id="listsaves">
+ </div>
+ <ul class="list-inline">
+ <li><button class="btn btn-default" type="button" onclick="loadSave()">Load</button></li>
+ <li><button class="btn btn-default" type="button" onclick="downloadSave()">Download</button></li>
+ <li><button class="btn btn-default" type="button" onclick="deleteSave()">Delete</button></li>
+ </ul>
+ </div>
</div>
</div>
-
-
-
</div>
</div>
</div>
diff --git a/js/craftmine.js b/js/craftmine.js
index 7c37e59..ffc9b5e 100644
--- a/js/craftmine.js
+++ b/js/craftmine.js
@@ -14,7 +14,10 @@ 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") {
- var data = JSON.parse(xhr.responseText);
+ var data = "";
+ if(xhr.responseText) data = JSON.parse(xhr.responseText);
+ if(data.info)
+ showInfo(data.info);
if(data.error) {
showError(data.error);
return;
@@ -50,11 +53,12 @@ function withdrawMine() {
function initCraftMine() {
sendRequest("craftmine.php", "op=getCraftMine", function(ret) {
data.gold = parseInt(ret.gold); // Server's response is a string
+ data.mine = 0; // Reset mine
if(ret.shop) displayShop(ret.shop);
displayInventory(ret.inventory);
if(ret.dungeon) displayDungeon();
data.miners = parseInt(ret.miners);
- updateData("gold","miners");
+ updateData("gold", "mine", "miners");
})
}
diff --git a/js/gui.js b/js/gui.js
index bdf1710..89fa0fa 100644
--- a/js/gui.js
+++ b/js/gui.js
@@ -6,10 +6,8 @@ function changeTab() {
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 = "";
+ if(i == id-1) tabs[i].classList.add("active"); // Doesn't work with IE < 10 (and Opera Mini), but who cares?
+ else tabs[i].classList.remove("active");
}
}
diff --git a/js/savegame.js b/js/savegame.js
new file mode 100644
index 0000000..4a08f91
--- /dev/null
+++ b/js/savegame.js
@@ -0,0 +1,42 @@
+function listSaves() {
+ sendRequest("craftmine.php", "op=listSaves", function(ret) {
+ var tmphtml=""
+ for(var i=0; i<ret.length; i++) {
+ tmphtml += "<label class=\"radio\"><input name=\"saveRadio\" value=\"" + i + "\" type=\"radio\" />" + ret[i] + "</label>\n";
+ }
+ console.log(tmphtml);
+ document.getElementById("listsaves").innerHTML = tmphtml;
+ });
+}
+
+function getCheckedSave() {
+ var radios = document.getElementsByName('saveRadio');
+ for (var i = 0, length = radios.length; i < length; i++) {
+ if (radios[i].checked) return radios[i].parentNode.textContent;
+ }
+ return -1;
+}
+
+function loadSave() {
+ sendRequest("craftmine.php", "op=loadSave&filename="+getCheckedSave(), function(ret) {
+ initCraftMine();
+ });
+}
+
+function downloadSave() {
+ window.open("craftmine.php?op=downSave&filename="+getCheckedSave(), "_blank");
+}
+
+function deleteSave() {
+ sendRequest("craftmine.php", "op=deleteSave&filename="+getCheckedSave(), function(ret) {
+ listSaves();
+ });
+}
+
+function saveGame() {
+ sendRequest("craftmine.php", "op=saveGame");
+}
+
+function downGame() {
+ window.open("craftmine.php?op=downSave", "_blank");
+}