view prices.php @ 361:2ef1ae4e185f misc

Another data update.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 27 Jun 2018 15:22:54 +0300
parents e02d4613d93f
children 0b12af2c103a
line wrap: on
line source

<?
/* Merchant/alchemist price calculator in PHP
 * (C) Copyright 2009-2013 Matti 'Ggr' Hamalainen <ccr@tnsp.org>
 *
 * Requires PHP 4.3 or later, primarily tested on PHP 5.2.x.
 *
 * Notes:
 * - Possibility for discount can be enabled per section, there is
 *   no "global" discount for everything, however.
 *
 * - Services in $services1_prices have a threshold for quantity
 *   discount, but services in $services2_prices do not. The total
 *   service discount % applies to both, too.
 *
 * - If "extra" field is set (as it is for services that have some
 *   additional material costs), the extra price DOES NOT get
 *   the section discount % applied!!
 *
 * - Ammunition, potions and salves sections have a "base" price,
 *   on top of which specials (more difficult to make, etc.) additional
 *   price can be set.
 *
 */
// General settings
$pageIndex = "prices.php";
$pageTitle = "Ggr's Merchant Pricelist";
$pageCharset = "UTF-8";
//$pageCSS = "foobar.css";  // Uncomment and change this, if you want to use your own CSS stylesheet file


// Enable service and product sections
$sections = array(
  "services1"  => true,
  "services2"  => true,
  "reagents"   => true,
  "arrows"     => true,
  "salves"     => true,
  "potions"    => false,
);


// Global additional desc, added to start of the page
$global_desc = '
<div style="border: 1px solid #0f0; padding: 15px; color: #ff0; text-align: center; font-size: 8pt;">
<span style="font-size: 20pt;">I do NOT make alchemist potions or rings*, or any SHIP stuff.</span><br />
<br />
(*) Well, actually I do make rings, but only for personal amusement. I do
not wish to spend time trying to come up with some specific ring type.)
</div>
';


// Generic services section settings
$services = array(
  "name"     => "services",
  "title"    => "Generic services",
  "discount" => true,	// enable discounts for this section

  "desc"     => "As one might expect, <b>I have most of the relevant
skills/spells/masteries at 100%</b>.",
);

// Service prices with discount thresholds
$services1_prices = array(
  "fw" => array(
    "name"     => "Feather weight",
    "subj"     => "cast",
    "tresh"    => 20,		// threshold for discount
    "price1"   => 2500,		// price per item below discount threshold
    "base"     => 10000,	// base price for discounted total
    "price2"   => 1750		// price per item with discount
  ),
  "prot" => array(
    "name"     => "Protect armour/weapon/item",
    "subj"     => "cast",
    "tresh"    => 20,
    "price1"   => 3000,
    "base"     => 10000,
    "price2"   => 2000
  ),
  "repair" => array(
    "name"     => "Repair armour/weapon/item",
    "tresh"    => 6,
    "subj"     => "item",
    "price1"   => 10000,
    "price2"   => 7500,
    "extra"    => " + materials"
  ),
);


// Services without discount threshold
$services2_prices = array(
  "labels" => array(
    "name"     => "Labelling",
    "subj"     => "item",
    "price"    => 3000
  ),
  "surg80" => array(
    "name"     => "Surgery to 80%",
    "subj"     => "item",
    "price"    => 10000,
  ),
  "surg100" => array(
    "name"     => "Surgery to 100", 
    "subj"     => "item",
    "price"    => 15000,
  ),
  "mip" => array(
    "name"     => "Money is Power",
    "subj"     => "cast",
    "price"    => 10000,
  ),
  "makegear" => array(
    "name"     => "Make mount gear",
    "subj"     => "item",
    "price"    => 20000,
    "extra"    => " + materials",
  ),
  "refitgear" => array(
    "name"     => "Refit mount gear",
    "subj"     => "item",
    "price"    => 10000,
    "extra"    => " + materials"
  ),

  "createaw" => array(
    "name"     => "Create armour/weapon",
    "subj"     => "item",
    "price"    => 15000,
    "extra"    => " + materials"
  ),
);


// Mage reagents
$reagents = array(
  "name"     => "reagent",
  "title"    => "Power reagents",
  "discount" => true,	// enable discounts for this section
  "datafile" => "reagents.txt",

  "desc"     => "Bulk orders may require time to complete, inquire.
<b>Notice! Availability presented below may or may not reflect the current stock situation.</b>",

  "prices" => array(
    "Blast reagents" => array(
      "acid1" => array("acid", "Acid Blast",           "handful of olivine powder",    125),
      "acid2" => array("acid", "Acid Storm",           "pair of interlocked rings",    125),

      "asph1" => array("asph", "Blast Vacuum",         "bronze marble",                150),
      "asph2" => array("asph", "Vacuum Globe",         "small fan",                    150),

      "elec1" => array("elec", "Electrocution",        "small piece of electrum wire", 125),
      "elec2" => array("elec", "Lightning Storm",      "cluster of tungsten wires",    125),

      "cold1" => array("cold", "Cold Ray",             "steel arrowhead",              150),
      "cold2" => array("cold", "Hailstorm",            "handful of onyx gravel",       125),

      "pois1" => array("pois", "Summon Carnal Spores", "silvery bark chip",            125),
      "pois2" => array("pois", "Killing Cloud",        "ebony tube",                   100),

      "fire1" => array("fire", "Lava Blast",           "granite sphere",               125),
      "fire2" => array("fire", "Lava Storm",           "blue cobalt cup",              125),

      "mana1" => array("mana", "Golden Arrow",         "copper rod",                   125),
      "mana2" => array("mana", "Magic Eruption",       "tiny platinum hammer",         125),
    ),
  
    "Prot reagents" => array(
      "phys3" => array("phys", "Armour of Aether",         "small highsteel disc",     200),
      "acid3" => array("acid", "Acid Shield",              "stone cube",               125),
      "asph3" => array("asph", "Aura of Wind",             "tiny leather bag",         275),
      "fire3" => array("fire", "Flame Shield",             "small glass cone",         150),
      "cold3" => array("cold", "Frost Shield",             "grey fur triangle",        275),
      "elec3" => array("elec", "Lightning Shield",         "small iron rod",           100),
      "mana3" => array("mana", "Repulsor Aura",            "quartz prism",             125),
      "pois3" => array("pois", "Shield of Detoxification", "tiny amethyst crystal",    125),
    )
  )
);


// Ammunition
$arrows = array(
  "name" => "arrow",
  "title" => "Ammunition",
  "desc" => "Only advertised <b>damage types</b> are available. If you want
other material combos for base ammunition, these may be negotiable. Feel
free to inquire about other ammunition types (bullets, etc.).
",

  "base" => 300, // base price per arrow, the values below are added on top of this
  "discount" => true, // enable discounts for this section

  "i_fields" => 2,
  "i_price" => 2,
  "i_titles" => array("Type", "Materials", "Price / arrow", "#"),
  "prices" => array(
    "phys" => array("Normal (phys)", "ebony, feathers, diamond",     0),
    "psi"  => array("Psi",           "* + brain",                    100),
    "acid" => array("Acid",          "* + stomach",                  100),
    "elec" => array("Elec",          "* + tungsten",                 100),
    "mana" => array("Mana",          "* + crystalline",              150),
    "cold" => array("Cold",          "* + ice",                      150),
    "fire" => array("Fire",          "* + fire",                     250),
    "asph" => array("Asphyx",        "* + toadstool",                350),
//    "pois" => array("Poison",        "* + h'cliz",                   300),
  )
);


// Salves
$salves = array(
  "name" => "salve",
  "title" => "Salves",
  "desc" => "All salves sold by me are <b>+25 to stat</b> with <b>10 min</b>
duration. Salves of same type do not stack, so you can't get +50 or such,
but different types of salves can be used simultaneously (like int and wis).
One salve has 4 portions (e.g. 4 uses) and weighs about 1kg.
<br />
<b>Salve orders will take some time to complete, I don't keep much stock on these currently.</b>
",

  "base" => 6000,
  "discount" => false,

  "i_fields" => 1,
  "i_price" => 1,
  "i_titles" => array("Salve", "Price / piece", "#"),
  "prices" => array(
    "str"  => array("+str", 0),
    "con"  => array("+con", 0),
    "int"  => array("+int", 0),
    "wis"  => array("+wis", 0),
    "dex"  => array("+dex", 0),

    "pack" => array("white cloth pack for holding salves [0/15]", 29000),
  )
);


// Alchemist potions
$potions = array(
  "name" => "potion",
  "title" => "Alchemist potions",
  "desc" => "Potion orders have no guaranteed completion time! If you want
potions sooner rather than later, ask someone else!
",

  "base" => 5500,
  "discount" => false,

  "i_fields" => 1,
  "i_price" => 1,
  "i_titles" => array("Potion", "Price / piece", "#"),
  "prices" => array(
    "generic" => array("Generic potion",                   0),
  ),
);



//============================================================================
// The code starts here - utility functions
//============================================================================
function convPrice($val)
{
  if ($val > 1000000)
    return round($val / 1000000.0, 4)."M";
  elseif ($val > 1000)
    return round($val / 1000.0, 2)."k";
  else
    return $val;
}


function getVal($name, &$val) 
{
  if (isset($_REQUEST["num_".$name]) && is_numeric($_REQUEST["num_".$name])) {
    $val = $_REQUEST["num_".$name];
    if ($val != 0)
      return TRUE;
  } else
    $val = -1;

  return FALSE;
}


function getField($name)
{
  if (getVal($name, $val))
    $s = " value=\"".$val."\"";
  else
    $s = "";

  return "<input type=\"text\" name=\"num_".$name."\" size=\"10\" class=\"itext\"".$s." />";
}


function getDiscount($dfield, &$dfactor, &$dstr)
{
  $dfactor = 1.0;
  $dstr = "";

  if (getVal($dfield."_discount", $dval)) {
    addVal($dfield."_discount", $dval);

    if ($dval > 0 && $dval <= 100) {
      $dfactor = $dval / 100.0;
      $dstr = " [".-(100 - $dval)."%]";
    } elseif ($dval < 0 && $dval >= -100) {
      $dfactor = (100 + $dval) / 100.0;
      $dstr = " [".$dval."%]";
    }
  }
}


function printSectionHeader($sec)
{
  echo "<h2>".$sec["title"]."</h2>\n";

  if (isset($sec["desc"]))
    echo "<p>".$sec["desc"]."</p>\n";

  echo "<table class=\"pritab\">\n";
}


function printSectionFooter($sec)
{
  echo "</table>\n<p>\n";
  
  if ($sec["discount"]) {
    echo $sec["title"]." total discount %: ".
    getField($sec["name"]."_discount")."<br />\n".
    "";
  }

  echo "<input type=\"submit\" value=\" Calculate \" class=\"isubmit\" />\n".
  "</p>\n\n";
}


//============================================================================

if (1)
{
  echo
  "<?xml version=\"1.0\" encoding=\"".$pageCharset."\"?>\n".
  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n".
//  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n".
  "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n";
}
else
{
  echo
  "<!DOCTYPE HTML>\n".
  "<html>\n";
}
?>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=<? echo $pageCharset; ?>" />
 <title><? echo $pageTitle; ?></title>
<?
if (isset($pageCSS))
{
 echo "<link rel=\"stylesheet\" title=\"Default\" href=\"".$pageCSS."\" type=\"text/css\" />\n";
}
else
{
?>
 <style type="text/css">
 <!--
 body { background: black; color: white; font-family: Arial, Verdana, sans-serif; font-size: 10pt; }
 th   { background: gray; }

 table.pritab { width: 70%; }
 table.pritab tr:hover td { background: green; }
 tr.a td { background: #333; }
 tr.b td { background: #444; }
 
 h1,h2,h3,h4  { color: #f00; border-bottom: 1px solid #c00; }

 .hide { display: none; }

 .phys { color: #ddd; }
 .fire { color: #f00; }
 .cold { color: #00f; }
 .mana { color: #ff0; }
 .asph { color: #8ff; }
 .pois { color: #0f0; }
 .elec { color: #08f; }
 -->
 </style>
<? } ?>
</head>
<body>
<?
//============================================================================
// Data input mode
//============================================================================
if (!isset($_REQUEST["ok"]))
{
echo "<h1>".$pageTitle."</h1>\n";

if (isset($global_desc))
  echo $global_desc;

echo "\n<form action=\"".$pageIndex."\" method=\"post\" autocomplete=\"off\">\n".
"<p><input type=\"hidden\" name=\"ok\" value=\"ok\" /></p>\n";

if ($sections["services1"] || $sections["services2"])
{
  printSectionHeader($services);

  if ($sections["services1"])
  {
    foreach ($services1_prices as $key => $item)
    {
      $s = isset($item["extra"]) ? $item["extra"] : "";
      echo
      " <tr>\n".
      "  <th>".$item["name"]."</th>\n".
      "  <th>Cost</th>\n".
      "  <th>#</th>\n".
      "  <th class=\"hide\"></th>\n".
      " </tr>\n".
      " <tr><td>1-".($item["tresh"]-1)." ".$item["subj"]."s</td>".
      "<td>".convPrice($item["price1"])." / ".$item["subj"].$s."</td>".
      "<td>-</td><td class=\"hide\"></td></tr>\n".
      " <tr><td>".$item["tresh"]."+ ".$item["subj"]."s</td><td>";

      if (isset($item["base"]))
        echo convPrice($item["base"])." initial fee + ".convPrice($item["price2"])." / ".$item["subj"].$s;
      else
        echo convPrice($item["price2"])." / ".$item["subj"].$s;

      echo "</td><td>".getField($key)."</td>";

      if (isset($item["extra"]))
        echo "<td>+ ".getField($key."_extra")."</td>";
      else
        echo "<td class=\"hide\"></td>";

      echo "</tr>\n";
    }
  } // services1 enabled


  if ($sections["services2"])
  {
    echo
    " <tr>\n".
    "  <th>Service</th>\n".
    "  <th>Cost</th>\n".
    "  <th>#</th>\n".
    "  <th class=\"hide\"></th>\n".
    " </tr>\n";
    
    foreach ($services2_prices as $key => $item)
    {
      echo 
      " <tr><td>".$item["name"]."</td>".
      "<td>".convPrice($item["price"])." / ".$item["subj"]."</td>".
      "<td>".getField($key)."</td>";

      if (isset($item["extra"]))
        echo "<td>+ ".getField($key."_extra")."</td>";
      else
        echo "<td></td>\n";

      echo "</tr>\n";
    }
  } // services2 enabled

  printSectionFooter($services);

} // services1 || services2 enabled


if ($sections["reagents"])
{
  $sec = $reagents;

  $showSupply = FALSE;
  if (file_exists($sec["datafile"]) &&
    ($data = @file_get_contents($sec["datafile"])) !== FALSE)
  {
    $supply = array();
    $lines = explode("\n", strtolower($data));
    foreach ($lines as $line)
    {
      $tmp = explode("|", $line);
      if (count($tmp) >= 2)
        $supply[$tmp[1]] = $tmp[0];
    }
    $showSupply = TRUE;
  }

  printSectionHeader($sec);
  foreach ($sec["prices"] as $fkey => $flist)
  {
    echo "<tr><th colspan=\"".($showSupply ? 6 : 5)."\">".$fkey."</th></tr>\n".
    " <tr>\n".
    "  <th>Type</th>\n".
    "  <th>Spell</th>\n".
    "  <th>Reagent</th>\n".
    "  <th>Price</th>\n".
    "  <th>#</th>\n".
    ($showSupply ? "  <th>Avail</th>\n" : "").
    " </tr>";
  
    $row = 1;
    foreach ($flist as $key => $item)
    {
      $s = ($row % 2 == 1) ? "a" : "b";
      echo
        " <tr class=\"".$s."\"><td class=\"".$item[0]."\">".$item[0].
        "</td><td>".$item[1]."</td><td>".$item[2]."</td><td>".$item[3]."</td>".
        "<td>".getField($key)."</td>";

      $spell = strtolower($item[1]);
      if ($showSupply && isset($supply[$spell]))
        echo "<td>".$supply[$spell]."</td>";
      echo "</tr>\n";
      $row++;
    }
  }

  printSectionFooter($sec);
} // reagents enabled


function printSection($sec)
{
  printSectionHeader($sec);
  
  echo " <tr>\n";
  foreach ($sec["i_titles"] as $title)
    echo "  <th>".$title."</th>\n";
  echo " </tr>\n";

  $name = $sec["name"];
  $base = isset($sec["base"]) ? $sec["base"] : 0;
  $row = 1;
  foreach ($sec["prices"] as $key => $item)
  {
    $s = ($row % 2 == 1) ? "a" : "b";

    echo " <tr class=\"".$s."\">";
    
    for ($i = 0; $i < $sec["i_fields"]; $i++)
      echo "<td>".$item[$i]."</td>";
    
    $add = isset($sec["i_price"]) ? $item[$sec["i_price"]] : 0;
    
    echo "<td><b>".($base + $add)."</b></td>".
    "<td>".getField($name."_".$key)."</td></tr>\n";
    $row++;
  }

  printSectionFooter($sec);
}


if ($sections["arrows"]) printSection($arrows);
if ($sections["potions"]) printSection($potions);
if ($sections["salves"]) printSection($salves);

echo "</form>\n";

}
else
{

//============================================================================
// Billing result mode
//============================================================================
function printLine($name, $num, $price, $header = FALSE)
{
  global $billText;
  $td1 = $header ? "<th>" : "<td>";
  $td2 = $header ? "</th>" : "</td>";

  echo " <tr>".$td1.$name.$td2.$td1.$num.$td2.$td1."<b>".convPrice($price)."</b>".$td2."</tr>\n";

  $s = sprintf("%-55s | %-6d | %s", $name, $num, convPrice($price));
  if ($header)
    $billText .= str_repeat("-", 75)."\n".$s."\n\n";
  else
    $billText .= $s."\n";
}

function addLine($name, $num, $price)
{
  global $totalPrice, $subTotal;
  $totalPrice += $price;
  $subTotal += $price;
  printLine($name, $num, $price);
}

function addVal($key, $val)
{
  global $formText;
  $formText .= "<input type=\"hidden\" name=\"num_".$key."\" value=\"".$val."\" />\n";
}


//============================================================================
// Services
//============================================================================
?>
<h1>Totals</h1>
<table class="pritab">
 <tr>
  <th>Item</th>
  <th>#</th>
  <th>Total</th>
 </tr>
<?
$subTotal = $totalPrice = 0;
$billText = "";
$formText = "";

getDiscount("services", $factor, $str);

if ($sections["services1"])
{
  foreach ($services1_prices as $key => $item)
  if (getVal($key, $val))
  {
    addVal($key, $val);

    if ($val >= $item["tresh"]) {
      if (isset($item["base"]))
        $total = $item["base"] + ($val * $item["price2"]);
      else
        $total = $val * $item["price2"];

      $s = " (discount for >= ".$item["tresh"].")";
    } else {
      $total = $val * $item["price1"];
      $s = "";
    }

    addLine($item["name"].$s.$str, $val, $total * $factor);

    // Extra does not get discount
    if (isset($item["extra"]) && getVal($key."_extra", $tmp))
    {
      addVal($key."_extra", $tmp);
      addLine("|".$item["extra"], $val, $tmp);
    }
  }
}

if ($sections["services2"])
{
  foreach ($services2_prices as $key => $item)
  if (getVal($key, $val))
  {
    addVal($key, $val);

    $total = $val * $item["price"];

    addLine($item["name"].$str, $val, $total * $factor);

    // Extra does not get discount
    if (isset($item["extra"]) && getVal($key."_extra", $tmp))
    {
      addVal($key."_extra", $tmp);
      addLine("|".$item["extra"], $val, $tmp);
    }
  }
}

if ($subTotal > 0)
  printLine("Services subtotal", "", $subTotal, TRUE);


//============================================================================
// Reagents
//============================================================================
if ($sections["reagents"])
{
  $sec = $reagents;
  getDiscount($sec["name"], $factor, $s);
  $numReagents = 0;
  $subTotal = 0;
  foreach ($sec["prices"] as $fkey => $flist)
  foreach ($flist as $key => $item)
  {
    if (getVal($key, $val) && $val > 0)
    {
      addVal($key, $val);
      addLine($item[2]." (".$item[1].")".$s, $val, $val * $item[3] * $factor);
      $numReagents += $val;
    }
  }
  if ($numReagents > 0)
    printLine("Total ".$sec["name"]."s", $numReagents, $subTotal, TRUE);
}

//============================================================================
// Generic sections
//============================================================================
function calculateSection($sec)
{
  $name = $sec["name"];

  if ($sec["discount"])
    getDiscount($name, $factor, $str);
  else
  {
    $str = "";
    $factor = 1;
  }
  
  $base = isset($sec["base"]) ? $sec["base"] : 0;
  $numItems = 0;
  $subTotal = 0;
  foreach ($sec["prices"] as $key => $item)
  {
    if (getVal($name."_".$key, $val) && $val > 0)
    {
      addVal($name."_".$key, $val);

      $add = isset($sec["i_price"]) ? $item[$sec["i_price"]] : 0;

      addLine($item[0]." (".convPrice($base + $add)." / ".$name.")".$str, $val,
      $val * ($base + $add) * $factor);

      $numItems += $val;
      $subTotal += $val * ($base + $add) * $factor;
    }
  }
  if ($numItems > 0)
    printLine("Total ".$name."s", $numItems, $subTotal, TRUE);
}

if ($sections["arrows"]) calculateSection($arrows);
if ($sections["potions"]) calculateSection($potions);
if ($sections["salves"]) calculateSection($salves);

echo  "</table>\n".
"<p>Final total: <b>".$totalPrice."</b> gold (".convPrice($totalPrice).")</p>\n".
"<hr />\n".
"<textarea rows=\"15\" cols=\"80\">\n".
"Services bill\n".
"=============\n\n".
addslashes($billText."\nFinal total: ".$totalPrice." gold (".convPrice($totalPrice).")\n").
"</textarea>\n".
"<hr />\n<form action=\"".$pageIndex."\" method=\"post\">\n".$formText.
"<input type=\"submit\" value=\" Back \" class=\"isubmit\" />\n</form>\n";
}
?>
</body>
</html>