changeset 303:0f751e08c932 misc

Import chest manager files.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 29 Dec 2015 02:16:46 +0200
parents b7a8b9cf7689
children 5f5f45216218
files chester/index.php chester/itemfixes.inc.php
diffstat 2 files changed, 1040 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chester/index.php	Tue Dec 29 02:16:46 2015 +0200
@@ -0,0 +1,996 @@
+<?
+$pageTitle = "Pupunen BatMUD Container Command Creator ALPHA";
+$pageIndex = "index.php";
+
+require "mgeneric.inc.php";
+require "itemfixes.inc.php";
+
+
+function getJSArraySegment($arr)
+{
+  $str = "";
+  foreach ($arr as $item) {
+    if ($str != "") $str .= ", ";
+    if (is_array($item))
+      $str .= "[".getJSArraySegment($item)."]";
+    else
+      $str .= "\"".addslashes($item)."\"";
+  }
+  return $str;
+}
+
+
+function printInputField($id, $label, $len, $value = "")
+{
+  global $jsData;
+  $jsData .= "document.getElementById(\"".$id."\").value = \"".$value."\";\n";
+
+  echo "<label for=\"".$id."\">".htmlentities($label).": </label>".
+  "<input type=\"text\" name=\"".$id."\" maxlength=\"".$len.
+  "\" size=\"".$len."\" id=\"".$id."\" value=\"".htmlentities($value)."\" />\n";
+}
+
+
+function printCheckBox($id, $label, $value = FALSE)
+{
+  global $jsData;
+  $jsData .= "document.getElementById(\"".$id."\").checked = ".($value ? "true" : "false").";\n";
+  
+  echo "<input type=\"checkbox\" id=\"".$id."\" value=\"".$value."\" ".($value ? "checked=\"checked\"" : "")." />".
+  "<label for=\"".$id."\">".htmlentities($label)."</label>";
+}
+
+
+function printOptionSelect($id, $size, $multi = FALSE)
+{
+  echo "<select ".($multi ? " multiple=\"multiple\"" : "")." size=\"".$size."\" id=\"".$id."\"><option></option></select>";
+}
+
+
+function performItemFixups($input, $table, &$changed)
+{
+  $changed = 0;
+
+  foreach ($table as $pat => $rep) {
+    // Static patterns start with asterisk "*"
+    if ($pat[0] == "*") {
+      if (substr($pat, 1) == $input) {
+        $changed = 1;
+        return $rep;
+      }
+    } else {
+      // Perform regexp replacment
+      $res = preg_replace("/".$pat."/", $rep, $input, -1, $changed);
+      if ($changed > 0)
+        return $res;
+    }
+
+  }
+  
+  return $input;
+}
+
+
+if (isset($_POST["mode"])) {
+  $formMode = intval($_POST["mode"]);
+} else
+  $formMode = 0;
+
+
+cmPrintPageHeader($pageTitle, "
+ <style type=\"text/css\">
+  <!--
+  .buttons { width: 100%; }
+  select { width: 100%; }
+  
+  div.options, #commands, #status {
+    background: #268;
+    border: 1px solid white;
+    color: white;
+  }
+  
+  div.options { display: none; position: fixed; top: 2em; left: 2em; padding: 1em; }
+
+  #commands { display: none; position: fixed; top: 2em; left: 2em; padding: 1em; z-index: 15; }
+  
+  #status { position: absolute; bottom: 1em; right: 1em; left: 1em; padding: 2pt; z-index: -1; }
+  -->
+ </style>
+");
+echo "<h1>".$pageTitle."</h1>\n";
+
+
+/*
+ * Initial mode, request item listing
+ */
+if ($formMode == 0) {
+?>
+<noscript>
+<p>
+<b>This application REQUIRES JavaScript to be enabled!</b>
+</p>
+</noscript>
+<form action="<? echo $pageIndex; ?>" method="post">
+<p>
+ <input type="hidden" value="YToxOntzOjU6Iml0ZW1zIjthOjQ3OntpOjA7czozODoiVGhlIHN0YWZmIG9mIExlcmV0aGluIGxhYmVsZWQgYXMgfEdncnwiO2k6MTtzOjM1OiJzd2lybGVkIGdyZWVuIHZlc3QgbGFiZWxlZCBhcyAoR2dyKSI7aToyO3M6Njk6ImEgd2VsbC1jcmFmdGVkIHBhaXIgb2Ygc3R1ZC1jb3ZlcmVkIGxlYXRoZXIgbGVnZ2luZ3MgbGFiZWxlZCBhcyAoR2dyKSI7aTozO3M6NTU6IlJpbmcgb2Ygd2lzZG9tIFtNYWRlIGJ5OiBOdWFuZV0gbGFiZWxlZCBhcyA2d2lzMWhwci9nZ3IiO2k6NDtzOjU0OiJzaGluaW5nIHJpbmcgY3JhZnRlZCBvdXQgb2YgbW9vbnN0b25lIGxhYmVsZWQgYXMgKEdncikiO2k6NTtzOjUxOiJHcmlteSBncmVhdCBjbG9hayBvZiB0cnVlIHNvcmNlcmVyIGxhYmVsZWQgYXMgfEdncnwiO2k6NjtzOjI5OiJhIGJsYWNrIGhvb2QgbGFiZWxlZCBhcyB8R2dyfCI7aTo3O3M6Mzg6InRoZSB0b21lIG9mIGtub3dsZWRnZSBsYWJlbGVkIGFzIChHZ3IpIjtpOjg7czo1MzoiaGVhdnkgdGFiYXJkIHdpdGggYSBjaGFsaWNlIGVuc2lnbmlhIGxhYmVsZWQgYXMgKEdncikiO2k6OTtzOjQ3OiJkYXJrIGdyZXkgYW5kIHdoaXRlIHBsYWlkIGtpbHQgbGFiZWxlZCBhcyAoR2dyKSI7aToxMDtzOjM4OiJzdHJvbmcgc2FwcGhpcmUgYm9vdHMgbGFiZWxlZCBhcyAoR2dyKSI7aToxMTtzOjI3OiJzdW4gYW11bGV0IGxhYmVsZWQgYXMgKEdncikiO2k6MTI7czo0MDoiQW5jaWVudCBCcmFjZXJzIG9mIFh6dWkgbGFiZWxlZCBhcyAoR2dyKSI7aToxMztzOjQyOiJnbGl0dGVyaW5nIGxlZyBwcm90ZWN0b3JzIGxhYmVsZWQgYXMgKEdncikiO2k6MTQ7czo0OToiYSBicmFjZWxldCBtYWRlIG9mIGdyZWVuIGNyeXN0YWwgbGFiZWxlZCBhcyAoR2dyKSI7aToxNTtzOjQ5OiJhIGJyYWNlbGV0IG1hZGUgb2YgZ3JlZW4gY3J5c3RhbCBsYWJlbGVkIGFzIChHZ3IpIjtpOjE2O3M6NDU6ImEgcmVpbmZvcmNlZCBicm9uemUgYnJhY2VsZXQgbGFiZWxlZCBhcyAoR2dyKSI7aToxNztzOjQyOiJ0aGUgQnJhY2VsZXRzIG9mIERhcmtuZXNzIGxhYmVsZWQgYXMgKEdncikiO2k6MTg7czozNDoiVGlidXJjaW8ncyBhbXVsZXQgbGFiZWxlZCBhcyAoR2dyKSI7aToxOTtzOjQ5OiJuZWNrbGFjZSBtYWRlIG91dCBvZiBzaGFycCBmYW5ncyBsYWJlbGVkIGFzIChHZ3IpIjtpOjIwO3M6NjI6ImEgZ2xpbW1lcmluZyBsZWF0aGVyIGJlbHQgd2l0aCBnZW0gZGVjb3JhdGlvbiBsYWJlbGVkIGFzIChHZ3IpIjtpOjIxO3M6NDE6ImEgaGVhdnkgYmxhY2sgbWV0YWwgcmluZyBsYWJlbGVkIGFzIChHZ3IpIjtpOjIyO3M6NDE6ImEgaGVhdnkgYmxhY2sgbWV0YWwgcmluZyBsYWJlbGVkIGFzIChHZ3IpIjtpOjIzO3M6NDU6IkRlbW9uaWMgUmluZyBvZiBJbnZpc2liaWxpdHkgbGFiZWxlZCBhcyAoR2dyKSI7aToyNDtzOjMxOiJhIHB1cnBsZSBnbG92ZSBsYWJlbGVkIGFzIChHZ3IpIjtpOjI1O3M6MzE6ImEgcHVycGxlIGdsb3ZlIGxhYmVsZWQgYXMgKEdncikiO2k6MjY7czozMDoiYSBncmVlbiBnbG92ZSBsYWJlbGVkIGFzIChHZ3IpIjtpOjI3O3M6MzA6ImEgZ3JlZW4gZ2xvdmUgbGFiZWxlZCBhcyAoR2dyKSI7aToyODtzOjQzOiJhIHBhaXIgb2YgYmxhY2sgYm9vdHMgbGFiZWxlZCBhcyB8R2dyTXVycml8IjtpOjI5O3M6NzI6IkEgYmVhdXRpZnVsIHJvc2FyeSBlbmZvbGRlZCB3aXRoIHdoaXRlIG1pc3QgbGFiZWxlZCBhcyB8R2dyTXVycml8IChob2x5KSI7aTozMDtzOjgyOiJhIHNtYWxsIHJpbmcgYmVhcmluZyB0aGUgZW1ibGVtIG9mIHRoZSBidW5ueSBbTWFkZSBieTogS2lvbWV0XSBsYWJlbGVkIGFzIDZ3aXMyaW50IjtpOjMxO3M6NjE6ImEgdmlhbCBjb250YWluaW5nIHRoZSB0ZWFycyBvZiBPeHRvdGggbGFiZWxlZCBhcyAoR2dyKSAoaG9seSkiO2k6MzI7czo0NDoiQSBsZWF0aGVyIHBvdWNoIGxhYmVsZWQgYXMgdjQgKHF1YXJ0ZXIgZnVsbCkiO2k6MzM7czo0Mzoic2xlZXZlcyBvZiBtb29taW4gZW11bHNpb24gbGFiZWxlZCBhcyAoR2dyKSI7aTozNDtzOjMzOiJhIGdyZWVuIGhlYWRiYW5kIGxhYmVsZWQgYXMgKEdncikiO2k6MzU7czozNDoiQ2FwZSBvZiBLbm93bGVkZ2UgbGFiZWxlZCBhcyAoR2dyKSI7aTozNjtzOjU0OiJUaGUgZ2xlYW1pbmcgYmx1ZSBjb2xsYXIgb2YgQmVuZ2Fsb3JlIGxhYmVsZWQgYXMgKEdncikiO2k6Mzc7czo1MToiZ29sZGVuIGJlbHQgb2YgRmFpciBSaXZlci1EYXVnaHRlciBsYWJlbGVkIGFzIChHZ3IpIjtpOjM4O3M6NDI6ImEgYmxhY2sgY2xvYWsgKGV2aWwgZ2xvdykgbGFiZWxlZCBhcyB8R2dyfCI7aTozOTtzOjM1OiJSaW5nIG9mIHRoZSBNZWR1c2EgbGFiZWxlZCBhcyAoR2dyKSI7aTo0MDtzOjQ0OiJBIGxvdyB3aWRlLWJyaW1tZWQgaGF0IGxhYmVsZWQgYXMgfEdnck11cnJpfCI7aTo0MTtzOjEzOiJhIHN0ZXRob3Njb3BlIjtpOjQyO3M6NjY6ImEgc2hpbW1lcmluZyBibHVlIGJyZWFzdHBsYXRlIG1hZGUgb2YgcXVhcnR6IGxhYmVsZWQgYXMgfEdnck11cnJpfCI7aTo0MztzOjUzOiJhIHBhaXIgb2YgcHVyZSB3aGl0ZSBmbG93aW5nIHNsZWV2ZXMgbGFiZWxlZCBhcyAoR2dyKSI7aTo0NDtzOjQzOiJSZWRmYW5nIEJlYWRzIG9mIElyb24gV2lsbCBsYWJlbGVkIGFzIChHZ3IpIjtpOjQ1O3M6NTk6Ik5vdmEgQXJjYW51bSwgTWVsa2lvcidzIGJvb2sgb2YgbmVjcm9tYW5jeSBsYWJlbGVkIGFzIChHZ3IpIjtpOjQ2O3M6NDQ6ImEgcGFpciBvZiBzaG9ydCBncmVlbiBib290cyBsYWJlbGVkIGFzIChHZ3IpIjt9fQ==" name="data" />
+ <input type="hidden" value="2" name="mode" />
+First, you should provide a list of equipments you wish to manage.
+Just plain copy &amp; paste of an inventory listing is enough.
+You can also test with pre-defined equipments, 
+ <input type="submit" value=" Test " /> by clicking the button.
+</p>
+</form>
+<p>
+<b>Stacks of items are not supported, and few other things may cause problems too.</b>
+</p>
+<form action="<? echo $pageIndex; ?>" method="post">
+ <p>  
+ <textarea name="data" cols="100" rows="20"></textarea>
+ <input type="hidden" value="1" name="mode" />
+ </p>
+ <div class="icenter">
+  <input type="submit" value=" Submit " />
+ </div>
+</form>
+<?
+}
+
+/*
+ * Parse and validate item
+ */
+else if ($formMode == 1) {
+  if (isset($_POST["data"])) {
+    $formData = stripslashes($_POST["data"]);
+    
+    $postData = explode("\n", $formData);
+    $data = array();
+    $ignored = array();
+
+    function addItems($num, $desc)
+    {
+      global $data;
+      for ($i = 0; $i < $num; $i++)
+        $data["items"][] = $desc;
+    }
+    
+    $fixNumbersMatch = join("|", array_keys($fixNumbers));
+    
+    foreach ($postData as $line) {
+      // Trim whitespace
+      $str = trim($line);
+      if ($str == "") continue;
+
+      // Strip glows and counters from item "handle"
+      if (preg_match("/^(.+?)\s+(\(glowing\))?\s*(<.+? glow>|\(\d+\/\d+\)|\[\d+\/\d+\])/", $str, $m))
+        $str = $m[1];
+      
+      // Discard multi-item lines
+      if (preg_match("/^(many|".$fixNumbersMatch.")\s+(.+?)( labeled as .+|)$/", $str, $m)) {
+        if (!isset($fixNumbers[$m[1]])) {
+          $ignored[$str] = "Unparsed stack of many";
+        } else {
+          $n = $fixNumbers[$m[1]];
+          $res = performItemFixups($m[2], $fixStackTable, $changed);
+          if ($changed > 0)
+            addItems($n, $res.$m[3]);
+          else
+            $ignored[$str] = "Unsupported item stack";
+        }
+      } else {
+        // Other item name fixups
+        addItems(1, performItemFixups($str, $fixItemTable, $changed));
+      }
+    }
+
+    if (count($ignored) > 0) {
+?>
+<p>Item data processed. Following lines <b>were not accepted</b>:</p>
+<table>
+ <tr><th>Item</th><th>Reason</th></tr>
+<?
+      foreach ($ignored as $name => $reason) {
+        echo " <tr><td>".htmlentities($name)."</td><td>".htmlentities($reason)."</td></tr>\n";
+      }
+      $filename = "ignored.txt";
+      $outFile = @fopen($filename, "a");
+      if ($outFile !== FALSE) {
+        @chmod($filename, 0600);
+        foreach ($ignored as $name => $reason) {
+          fwrite($outFile, $name."§".$reason."\n");
+        }
+        fclose($outFile);
+      }
+
+      $encData = base64_encode(serialize($data));
+?>
+</table>
+
+<form action="<? echo $pageIndex; ?>" method="post">
+ <input type="hidden" value="<? echo $encData ?>" name="data" />
+ <input type="hidden" value="2" name="mode" />
+<?
+// echo "<textarea name=\"data\" cols=\"100\" rows=\"20\">".$encData."</textarea>\n";
+?>
+ <br />
+ <input type="submit" value=" Continue " />
+</form>
+<?
+    } else 
+      $formMode = 3;
+  } else
+    stError("No item data provided.");
+} // formMode == 1
+
+
+/*
+ * Unserialize data from previous step
+ */
+if ($formMode == 2) {
+  if (isset($_POST["data"])) {
+    $formData = base64_decode($_POST["data"]);
+    $data = @unserialize($formData);
+    $formMode = 3;
+  }
+  if ($data === FALSE) {
+    stError("Could not unserialize data, internal error.");
+  }
+}
+
+
+/*
+ * Interactive editor mode begins here
+ */
+if ($formMode == 3 && $data !== FALSE) {
+?>
+<form id="done" action="<? echo $pageIndex; ?>" method="post">
+ <p id="create_buttons">
+  <input type="button" value=" Create BatMUD Commands " onclick="createInit('batmud');" />
+<!--  <input type="button" value=" Create TinyFugue Macros " onclick="createInit('tf');" /> 
+-->
+  <input type="button" value=" Create SAVEBLOB " onclick="createInit('save');" />
+  <input type="button" value=" Reset All " onclick="resetAll();" />
+  <input type="button" value=" Empty Containers " onclick="emptyContainers();" />
+ </p>
+
+
+ <table>
+  <tr>
+
+   <td>
+    <h2>Items pool</h2>
+    <? printOptionSelect("curr_items", 10, TRUE); ?>
+    <table class="buttons">
+     <tr>
+      <td><input type="button" value=" Delete " onclick="deleteItems(this.form);" /></td>
+      <td><input type="button" value=" Add new " onclick="addItems(this.form);" disabled="disabled" /></td>
+      <td><b><span id="curr_nitems"></span> items</b></td>
+      <td><input type="button" value=" AutoMove " onclick="autoMoveItems(this.form);" /></td>
+      <td style="width: 60%; text-align: right;"><input type="button" value=" Move to container " onclick="moveItems(this.form);" /></td>
+     </tr>
+    </table>
+   </td>
+
+   <td id="container_editor">
+    <h2>Editing container "<span id="curr_name"></span>"</h2>
+    <? printOptionSelect("curr_container", 10, TRUE); ?>
+    <table class="buttons">
+     <tr>
+      <td><input type="button" value=" Remove selected " onclick="containerRemoveItems(this.form);" /></td>
+      <td><b><span id="curr_info"></span> items</b></td>
+     </tr>
+    </table>
+   </td>
+  </tr>
+
+  <tr>
+   <td>
+    <h2>Create / edit a container</h2>
+<?
+printInputField("container_name", "Identifier/name", 15);
+printInputField("container_slots", "Number of slots", 5);
+ ?>
+    <input type="button" value=" Create new " onclick="containerCreate(this.form);" id="create_button" />
+    <input type="button" value=" Modify " onclick="containerModify(this.form);" id="modify_button" />
+   </td>
+
+   <td id="container_list_editor">
+    <h2>Defined containers</h2>
+    <? printOptionSelect("container_list", 5, FALSE); ?>
+    <table class="buttons">
+     <tr>
+      <td><input type="button" value=" Switch to " onclick="containerEdit(this.form);" /></td>
+      <td><input type="button" value=" Delete " onclick="containerDelete(this.form);" /></td>
+      <td><b><span id="containers_info"></span> items total</b></td>
+     </tr>
+    </table> 
+   </td>
+
+  </tr>
+ </table>
+</form>
+
+<div id="commands">
+ <textarea id="command_data" cols="80" rows="10"></textarea>
+ <br />
+ <input type="button" value=" Close " onclick="viewCommands(false, '');" />
+</div>
+
+<div id="options_batmud" class="options">
+  <? printInputField("cmd_delim", "Command delimiter", 15, ";"); ?><br />
+  <? printInputField("cmd_prefix", "Command name prefix", 15, "mcp"); ?><br />
+  <? printInputField("cmd_cmd", "Command", 32, "put \$1 in \$2"); ?> (<b>$1</b> = item, <b>$2</b> = container)<br />
+  <? printCheckBox("cmd_sequence", "Create sequence for each item, instead of command alias list.", FALSE); ?><br />
+  <? printCheckBox("cmd_autoclose", "Add commands for automatically opening and closing each container.", FALSE); ?><br />
+  <br />
+  <input type="button" value=" Create " onclick="createCommands('batmud');" />
+  <input type="button" value=" Cancel " onclick="createInit('clear');" />
+</div>
+
+<div id="options_tf" class="options">
+  <input type="button" value=" Create " onclick="createCommands('tf');" />
+  <input type="button" value=" Cancel " onclick="createInit('clear');" />
+</div>
+
+<div id="lol" class="options"></div>
+
+<div id="status">&nbsp;</div>
+
+<script type="text/javascript">
+<!--
+var curr_container = null;
+
+
+function Container(name, slots, items)
+{
+  this.name = name;
+  this.slots = slots;
+  this.items = items;
+  this.changed = true;
+
+  this.getCountByName = function(n) {
+    var cnt = 0;
+    for (var i = 0; i < this.items.length; i++) {
+      if (this.items[i] == n) cnt++;
+    }
+    return cnt;
+  }
+
+  this.getSpace = function() {
+    return this.slots - this.items.length;
+  }
+
+  this.addItem = function(item) {
+    if (this.items.length < slots) {
+      this.changed = true;
+      this.items.push(item);
+      return true;
+    } else
+      return false;
+  }
+
+  this.deleteItemById = function(id) {
+    this.changed = true;
+    delete this.items[id];
+  }
+  
+  this.flush = function() {
+    this.changed = true;
+    for (var i = 0; i < this.items.length; i++) {
+      if (this.items[i] == undefined) {
+        this.items.splice(i, 1);
+        i -= 1;
+      }
+    }
+  }
+  
+  this.moveItemById = function(container, id) {
+    var item = this.getItemByIndex(id);
+    if (item != null) {
+      if (!container.addItem(item))
+        return false;
+      this.deleteItemById(id);
+      this.changed = true;
+      return true;
+    } else
+      return false;
+  }
+
+  this.getItemId = function(item) {
+    return this.items.indexOf(item);
+  }
+
+  this.getItemByIndex = function(id) {
+    if (id < 0 || id >= this.items.length) return null;
+    return this.items[id];
+  }
+}
+//-->
+<?
+function getContainerObject($name, $slots, $items)
+{
+  return "new Container(\"".$name."\", \"".$slots."\", [".getJSArraySegment($items)."])";
+}
+
+$str = "";
+if (isset($data["containers"])) {
+  foreach ($data["containers"] as $container) {
+    if ($str != "") $str .= ", ";
+    $str .= getContainerObject($container["name"], $container["slots"], $container["items"]);
+  }
+}
+
+echo "
+var list_containers;
+var list_items;
+
+function initContainers()
+{
+  list_containers = [".$str."];
+}
+
+function initItems()
+{
+  list_items = ".(isset($data["items"]) ? getContainerObject("items", 10000, $data["items"]) : "null").";
+}
+
+function initSettings()
+{
+".$jsData."
+  curr_container = null;
+}
+";
+?>
+<!-- kludge --><!--
+
+function resetAll()
+{
+  var answer = confirm("Really delete all defined containers and reset item pool to original state? You will have to re-define containers from scratch.");
+  if (!answer) {
+    statusMsg("Reset operation cancelled.");
+    return;
+  }
+  initContainers();
+  initItems();
+  initSettings();
+  updatePage();
+  statusMsg('Welcome to the editor. <b>&copy; Copyright 2011 Matti H&auml;m&auml;l&auml;inen aka Ggr Pupunen.</b>');
+}
+
+
+function emptyContainers()
+{
+  var answer = confirm("Really clear (empty) all defined containers and reset item pool to original state?");
+  if (!answer) {
+    statusMsg("Clear operation cancelled.");
+    return;
+  }
+
+  initItems();
+
+  for (var i = 0; i < list_containers.length; i++) {
+    list_containers[i].items = [];
+    if (i == 0) {
+      curr_container = list_containers[i];
+      curr_container.changed = true;
+    }
+  }
+  
+  updatePage();
+}
+
+
+function setHTML(id, str)
+{
+  var o = document.getElementById(id);
+  if (o != null)
+    o.innerHTML = str;
+}
+
+
+function setListData(id, list)
+{
+  var o = document.getElementById(id);
+  o.options.length = 0;
+  for (var i = 0; i < list.length; i++) {
+    o.options[i] = new Option(list[i], i, false, false);
+  }
+}
+
+
+// Update the form data
+function updatePage()
+{
+  // List of items
+  if (list_items != null && list_items.changed) {
+    list_items.changed = false;
+    setListData("curr_items", list_items.items);
+    setHTML("curr_nitems", list_items.items.length);
+  }
+
+  // List of containers
+  var container_list_editor = document.getElementById("container_list_editor");
+  if (list_containers.length > 0) {
+    container_list_editor.style.display = "block";
+
+    o = document.getElementById("container_list");
+    o.options.length = 0;
+    var total_items = 0;
+    var total_slots = 0;
+    for (var i = 0; i < list_containers.length; i++) {
+      o.options[i] = new Option(list_containers[i].name +" (" + list_containers[i].items.length +" of "+ list_containers[i].slots +" items)", i, false);
+      total_items += list_containers[i].items.length;
+      total_slots += list_containers[i].slots;
+    }
+    setHTML("containers_info", total_items+" / "+total_slots);
+  } else {
+    container_list_editor.style.display = "none";
+  }
+  
+
+  // Update current container
+  var container_editor = document.getElementById("container_editor");
+  if (curr_container != null) {
+    container_editor.style.display = "block";
+    setHTML("curr_name", curr_container.name);
+    setHTML("curr_info", curr_container.items.length+" / "+curr_container.slots);
+
+    if (curr_container.changed) {
+      curr_container.changed = false;
+      setListData("curr_container", curr_container.items);
+    }
+  } else {
+    container_editor.style.display = "none";
+  }
+}
+
+// Output status message
+function statusMsg(msg)
+{
+  var o = document.getElementById("status");
+  o.innerHTML = msg;
+}
+
+
+// Clear values of a given form
+function clearForm(f)
+{
+  for (var i = 0; i < f.elements.length; i++) {
+    var e = f.elements[i];
+    if (e.type.toLowerCase() == "text") e.value = "";
+  }
+}
+
+
+function validateContainerData(f)
+{
+  var name = f.elements['container_name'].value;
+  var slots = parseInt(f.elements['container_slots'].value, 10);
+
+  if (isNaN(slots) || slots < 1) {
+    statusMsg("Number of slots not set or is invalid.");
+    return null;
+  }
+
+  if (name == "") {
+    statusMsg("Empty container name "+name+".");
+    return null;
+  }
+
+  if (name.match(/[^a-z0-9_]/)) {
+    statusMsg("Invalid container name, only lower case alphanumerics and underscore are allowed.");
+    return null;
+  }
+  
+  return {name: name, slots: slots};
+}
+
+// Create a new container, set current container to it
+function containerCreate(f)
+{
+  var c = validateContainerData(f);
+  if (c == null)
+    return;
+    
+  for (var i = 0; i < list_containers.length; i++) {
+    if (list_containers[i].name == c.name) {
+      statusMsg("Container with identifier '<b>"+c.name+"</b>' already exists!");
+      return;
+    }
+  }
+
+  curr_container = new Container(c.name, c.slots, []);
+  list_containers.push(curr_container);
+
+  clearForm(f);
+  statusMsg("Created new container '<b>"+c.name+"</b>' with <b>"+c.slots+"</b> slots.");
+  updatePage();
+}
+
+
+// Change current container
+function containerModify(f)
+{
+  if (curr_container == null) {
+    statusMsg("No current container, create or select one.");
+    return;
+  }
+
+  var c = validateContainerData(f);
+  if (c == null)
+    return;
+
+  if (c.slots < curr_container.items.length) {
+    statusMsg("New number of slots can't be smaller than number of items in it! ("+ c.slots +" < "+ curr_container.items.length +")");
+    return;
+  }
+
+  curr_container.name = c.name;
+  curr_container.slots = c.slots;
+
+  clearForm(f);
+  statusMsg("Updated container.");
+  updatePage();
+}
+
+
+function containerCheckSelected(f)
+{
+  var id = f.elements['container_list'].selectedIndex;
+  
+  if (id < 0 || id >= list_containers.length) {
+    statusMsg("Invalid container, internal error!");
+    return -1;
+  }
+
+  return {id: id, container: list_containers[id]};
+}
+
+
+// Delete a container from container list
+function containerDelete(f)
+{
+  var ret = containerCheckSelected(f);
+  if (ret.id < 0 || ret.container == null) return;
+
+  var name = ret.container.name;
+  var len = ret.container.items.length;
+
+  var answer = confirm("Really delete selected container '"+name+"' and move "+len+" items back to pool?");
+  if (!answer) {
+    statusMsg("Delete operation cancelled.");
+    return;
+  }
+
+  if (curr_container == ret.container)
+    curr_container = null;
+
+  for (var i = 0; i < len; i++) {
+    if (!ret.container.moveItemById(list_items, i)) {
+      statusMsg("Internal error moving item "+ i);
+      return;
+    }
+  }
+
+  list_containers.splice(ret.id, 1);
+      
+  if (len > 0) {
+    statusMsg("Deleted container '"+name+"', "+len+" items returned to pool.");
+  } else {
+    statusMsg("Deleted empty container '"+name+"'.");
+  }
+  updatePage();
+}
+
+
+// Change currently edited container to another
+function containerEdit(f)
+{
+  var ret = containerCheckSelected(f);
+  if (ret.id < 0 || ret.container == null) return;
+
+  curr_container = ret.container;
+  curr_container.changed = true;
+  statusMsg("Switched to container '"+ret.container.name+"'.");
+  updatePage();
+}
+
+
+function containerRemoveItems(f)
+{
+  if (curr_container == null) {
+    statusMsg("Internal error.");
+    return;
+  }
+  
+  var selected = getSelectedItems(f.elements['curr_container']);
+  
+  if (selected.length == 0) {
+    statusMsg("No items selected for deletion.");
+    return;
+  } else {
+    for (var i = 0; i < selected.length; i++)
+      curr_container.moveItemById(list_items, selected[i]);
+
+    curr_container.flush();
+    updatePage();
+    statusMsg("Removed " + selected.length + " from current container.");
+  }
+}
+
+function getSelectedItems(items)
+{
+  var selected = [];
+  if (items != null) {
+    for (var i = 0; i < items.length; i++)
+    if (items[i].selected) selected.push(items[i].value);
+  }
+  return selected;
+}
+
+
+function deleteItems(f)
+{
+  var selected = getSelectedItems(f.elements['curr_items']);
+
+  if (selected.length == 0) {
+    statusMsg("No items selected for deletion.");
+    return;
+  } else {
+    var answer = confirm("Really delete selected items?");
+    if (!answer) {
+      statusMsg("Delete operation cancelled.");
+      return;
+    }
+    
+    for (var i = 0; i < selected.length; i++)
+      list_items.deleteItemById(selected[i]);
+
+    list_items.flush();
+    updatePage();
+    statusMsg("Deleted "+selected.length+" items.");
+  }
+}
+
+
+function moveItems(f)
+{
+  if (curr_container == null) {
+    statusMsg("No container selected, cannot move items.");
+    return;
+  }
+  
+  var selected = getSelectedItems(f.elements['curr_items']);
+  
+  if (selected.length == 0) {
+    statusMsg("No items selected for deletion.");
+    return;
+  } else {
+    if (curr_container.getSpace() < selected.length) {
+      statusMsg("Not enough space! "+ selected.length +" items, only "+ curr_container.getSpace() +" slots available!");
+      return;
+    }
+  
+    for (var i = 0; i < selected.length; i++) {
+      if (!list_items.moveItemById(curr_container, selected[i])) {	
+        statusMsg("Internal error moving item #"+i+": '"+selected[i]+"'.");
+        return;
+      }
+    }
+
+    list_items.flush();
+    updatePage();
+    statusMsg("Moved " + selected.length + " items to current container.");
+  }
+}
+
+
+function autoMoveItems(f)
+{
+  var selected = getSelectedItems(f.elements['curr_items']);
+  
+  if (selected.length == 0) {
+    statusMsg("No items selected for AutoMove(tm).");
+    return;
+  }
+
+  if (list_containers.length == 0) {
+    statusMsg("No containers available for AutoMove(tm).");
+    return;
+  }
+
+  var remaining = selected.length;
+  var n = 0;
+  var changed = 0;
+  while (remaining > 0 && n < list_containers.length) {
+    curr = list_containers[n];
+    
+    for (var q = curr.getSpace(); q > 0 && remaining > 0; q--) {
+      remaining--;
+      changed++;
+      if (!list_items.moveItemById(curr, selected[remaining])) {	
+        statusMsg("Internal error moving item #"+remaining+": '"+selected[remaining]+"'.");
+        return;
+      }
+    }
+
+    n++;
+  }
+
+  if (changed > 0) {
+    list_items.flush();
+    updatePage();
+  }
+
+  if (remaining > 0) {
+    statusMsg("Not enough space! <b>"+ remaining +" of "+ selected.length +"</b> items left without slots!");
+    return;
+  }
+
+  statusMsg("AutoMoved " + selected.length + " items to containers.");
+}
+
+
+function serializePHP(obj)
+{
+  var res;
+
+  if (obj == undefined)
+    return null;
+
+  switch (typeof(obj)) {
+    case "array":
+      res = "[";
+      for (var i = 0; i < obj.length; i++) {
+        if (i > 0) res += ", ";
+        res += serializePHP(obj[i]);
+      }
+      res += "]";
+      return res;
+    
+    case "string":
+      return " '" + escape(obj) + "'";
+    
+    case "number":
+      return isFinite(obj) ? obj.toString() : null;
+    
+    case "object":
+      var o = [];
+      for (a in obj) {
+        if (typeof(obj[a]) != "function") {
+          o.push('"' + a + '": ' + serializePHP(obj[a]));
+        }
+      }
+      if (o.length > 0)
+        return " {" + o.join(",") + "} ";
+      else
+        return " {} ";
+
+    case "boolean":
+      return obj ? "true" : "false";
+        
+    default:
+      return obj.toString();
+  }
+}
+
+
+var edit_modes = ['batmud', 'tf', 'save'];
+
+function createInit(mode)
+{
+  for (i = 0; i < edit_modes.length; i++) {
+    var o = document.getElementById("options_"+edit_modes[i]);
+    if (o != null) {
+      o.style.display = (edit_modes[i] == mode) ? "block" : "none";
+    }
+  }
+
+  if (mode == "save") {
+    var tmp = { "containers": list_containers, "items": list_items };
+    viewCommands(true, serializePHP(tmp));
+/*
+    var o = document.getElementById("lol");
+    o.style.display = "block";
+    o.innerHTML = serializePHP(tmp);
+*/
+    return;
+  }
+}
+
+
+function expandCmd(cmd, item, name)
+{
+  var str = cmd.replace(/\$1/g, item);
+  return str.replace(/\$2/g, name);
+}
+
+
+function createCommands(mode)
+{
+  if (list_containers.length == 0) {
+    statusMsg("No container configurations defined!");
+    return;
+  }
+
+  var str = "";
+  for (var i = 0; i < list_containers.length; i++) {
+    var container = list_containers[i];
+    var counts = [];
+    var curr = [];
+
+    for (var n = 0; n < container.items.length; n++) {
+      var cnt = container.getCountByName(container.items[n]);
+      counts[container.items[n]] = cnt;
+      curr[container.items[n]] = 1;
+    }
+
+    var cmd_autoclose = document.getElementById("cmd_autoclose").checked;
+    var cmd_delim = document.getElementById("cmd_delim").value;
+    var cmd_prefix = document.getElementById("cmd_prefix").value;
+    if (cmd_delim == "") cmd_delim = ";";
+    var cmd_cmd = document.getElementById("cmd_cmd").value;
+    var cmd_seq = document.getElementById("cmd_sequence").checked;
+    var s = "";
+
+    for (var n = 0; n < container.items.length; n++) {
+      var item = container.items[n];
+      var tmp = ""+item;
+
+      if (counts[item] > 1) {
+        tmp += " " + curr[item];
+        curr[item]++;
+      }
+
+      if (mode == "batmud") {
+        if (cmd_seq) {
+          s += expandCmd(cmd_cmd, tmp, container.name) + "\n";
+        } else {
+          if (s != "") s += ",";
+          s += tmp;
+        }
+      }
+    }
+    
+    if (mode == "batmud") {
+      if (!cmd_seq)      str += "command "+ cmd_prefix + container.name +" ";
+      if (cmd_autoclose) str += "open "+ container.name + cmd_delim;
+      if (!cmd_seq)      str += expandCmd(cmd_cmd, s, container.name);
+        else 		 str += s;
+      if (cmd_autoclose) str += cmd_delim +"close "+ container.name;
+      str += "\n";
+    }
+  }
+
+  viewCommands(true, str);
+}
+
+function viewCommands(state, str)
+{
+  var o = document.getElementById("commands");
+  o.style.display = state ? "block" : "none";
+  var o = document.getElementById("command_data");
+  o.innerHTML = str;
+}
+
+
+initContainers();
+initItems();
+initSettings();
+updatePage();
+//-->
+</script>
+<?
+}
+
+if ($errorSet)
+{
+  echo "<h2>An error occured</h2>\n<ul>\n";
+  
+  foreach ($errorMsgs as $msg)
+    echo " <li>".$msg."</li>\n";
+
+  echo "</ul>\n";
+}
+
+cmPrintPageFooter();
+?>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chester/itemfixes.inc.php	Tue Dec 29 02:16:46 2015 +0200
@@ -0,0 +1,44 @@
+<?
+
+// Special item name fixups
+$fixItemTable = array(
+  "^a book of eternal youth \([a-z ]+\)" => "a book of eternal youth",
+  "^small crystal box \([a-z ]+\)" => "small crystal box"
+);
+
+
+// Multi-stack item fixups
+$fixStackTable = array(
+  "^(purple|green) gloves" => 'a ${1} glove',
+  "^Blue gloves of master Conjurer" => 'Blue glove of master Conjurer',
+  "^bracelet mades of green crystal" => "bracelet made of green crystal",
+  "^alchemist moulded rings" => "alchemist moulded ring",
+  "^Rings of wisdom" => "Ring of wisdom",
+  "^Nova Arcanum, Melkior's books of necromancy" => "Nova Arcanum, Melkior's book of necromancy",
+
+  // Generic rings
+  "^(heavy black metal|steel) rings" => 'a ${1} ring',
+
+  // Damiens
+  "^arm protectors called Damien \(\S+\)" => 'an arm protector called Damien (${1})',
+  
+  // Containers  
+  "^white cloth packs for holding salves" => "white cloth pack for holding salves",
+  "^(small|HUGE) shiny boxes for storing minerals" => 'a ${1} shiny box for storing minerals',
+  "^(small|HUGE) sturdy packs for storing potions" => 'a ${1} sturdy pack for storing potions',
+);
+
+
+$fixNumbers = array(
+  "two"     => 2,
+  "three"   => 3,
+  "four"    => 4,
+  "five"    => 5,
+  "six"     => 6,
+  "seven"   => 7,
+  "eight"   => 8,
+  "nine"    => 9,
+  "ten"     => 10
+);
+
+?>
\ No newline at end of file