function pubjokes_runevent($type)
{
    global $session;
    $jokenum = e_rand(1, 8);
    $landlord = getsetting("barkeep", "`)Cedrik");
    switch ($jokenum) {
        case 1:
            output("A tall, hairy man enters the pub and strolls over to the bar.  The frog sulking on the top of his bald head draws some stares.  %s looks him up and down, and after a moment's thought, nods up at the frog and asks \"So, mate - where did you get that?\"`n\"Well, it started off as a wart on my arse,\" says the frog.`n`n", $landlord);
            break;
        case 2:
            output("A small, mottled brown duck walks into the pub.  He waddles over to the bar, hops onto a stool, and fixes %s with an intense stare.  You watch closely, knowing that the two are about to face off in a battle of wits.`n\"Got any bread?\" asks the duck.`n\"No,\" replies %s.`n\"Got any bread?\" asks the duck.`n\"No,\" replies %s.`n\"Got any bread?\"`n\"No.\"`n\"Got any bread?\"`n\"No.\"`n\"Got any bread?\"`n\"No.\"`n\"Got any bread?\"`n\"`iNo.`i\"`n\"Got any bread?\"`n\"NO!\"`n\"Got any bread?\"`n\"No, and the next time you ask, I'm going to nail your damned beak to this bar.\"`nThe duck looks up at %s's fierce expression, and appears to reach a decision.`n\"Got any nails?\"`n\"No.\"`n\"Got any bread?\"`n%s's hands move too fast for you to see, but the loud hammering sound and the squeals of indignant quacking pain serve to paint you a pretty good picture.`n\"I lied about the nails,\" says %s with a smile, and goes back to serving drinks.`n`n", $landlord, $landlord, $landlord, $landlord, $landlord, $landlord);
            break;
        case 3:
            output("A severely drunk man blunders past you, laughing and slurring \"ALL MIDGETS ARE BASTARDS!\"`nA figure lurking in the shadows at the corners of the pub calls after him: \"Hey, I take offense at that!\"`nThe drunkard turns around and slurs back, \"Why, mate, 're you a Midget or summat?\"`n\"No, I'm a bastard.\"`n`n");
            break;
        case 4:
            output("A very attractive woman walks up to the bar. She gestures alluringly to Mick, the assistant bartender, who comes over immediately.  When he arrives, she seductively signals that he should bring his face closer to hers. When he does so, she begins to gently caress his full beard.`n\"Are you %s?\", she asks, softly stroking his face with both hands.`n\"Actually, no,\" he replies.\"Can you get him for me? I need to speak to him,\" she says, running her hands beyond his beard and into his hair.`n\"He's just downstairs changing the barrels,\" breathes Mick. \"Is there anything I can do?\"`n\"Yes, there is. I need you to give him a message,\" she continues, slyly popping a couple of her fingers into his mouth and allowing him to suck them gently.`n\"Wh-what should I tell him?\" Mick somehow manages to stammer, his ears as red as emergency flares.`n\"Tell him,\" she whispers, \"There is no toilet paper or hand soap in the ladies room.\"`n`n", $landlord);
            break;
        case 5:
            output("A wriggling SpiderKitty prances over to the bar, climbs up onto a stool and asks for a beer.  %s begins to pour, chuckling.  \"You know,\" he says, \"I named this pub after you.\"`n\"What,\" says the prancing SpiderKitty, \"You named your pub Dave?\"`n`n", $landlord);
            break;
        case 6:
            output("A horse walks into the pub and up to the bar.  %s says, \"Why the long face?\"`nThe horse shrugs. \"Crap jokes, mainly.\"`n\"Ah.\"`n`n", $landlord);
            break;
        case 7:
            output("A man walks in to the pub.  %s, seeing him, pulls his shotgun from under the bar.  \"OUT!\" he shouts.  \"YOU BLOODY WELL KNOW YOU'VE BEEN BARRED!\"`nAs the man sheepishly leaves, you ask %s what the problem was.  He turns to you, shaking his head.`n\"The sign that said \"Wet Floor\" was supposed to be a `icaution`i, not a request.\"`nYou wondered why your boots were sticking so bad.`n`n", $landlord, $landlord);
            break;
        case 8:
            output("You notice a man quite the worse for wear, staggering out of the pub with his pet giraffe in tow - similarly inebriated, the giraffe falls over onto its side, and the man keeps walking.  %s calls after him - \"Hey!  You can't leave that lyin' there!\"`nThe man turns around and gets as far as \"It's not a lion, it's a...\" before the lion bursts from its disguise and drags him screaming into the jungle.  The regulars shrug and go back to their pints.`n`n", $landlord);
            break;
    }
}
function offering_runevent($type)
{
    global $session;
    $session['user']['specialinc'] = "module:offering";
    $seen = get_module_pref("seen");
    $amt = round(max(1, $session['user']['dragonkills'] * 10) * $session['user']['level'] * max(1, 5000 - $session['user']['maxhitpoints']) / 20000);
    $op = httpget('op');
    if ($op == "") {
        output("`7While you are listening to others chatting, a bizarrely-dressed woman approaches with an outstretched hand. `n`n");
        output("\"`&For the offering!!! `^%s `&gold!`7\"", $amt);
        $seen++;
        set_module_pref("seen", $seen);
        addnav(array("Give her %s gold", $amt), "village.php?op=shop");
        addnav("Walk away", "village.php?op=nope");
    } elseif ($op == "nope") {
        output("`7You decide not to give any gold to this strange woman.`n");
        $session['user']['specialinc'] = "";
    } elseif ($session['user']['gold'] < $amt) {
        output("`7The woman stares at your hand.`n`n");
        output("\"`&No no no no no!!! He would not be pleased!!!`7\"`n`n");
        output("`7Without another word, she walks away.`n");
        $session['user']['specialinc'] = "";
    } else {
        output("`7You hand her `^%s`7 gold, and she lifts her head up, looks intently at something above her that only she can see, and whispers, `&\"%s!`&\" `7with apparent urgency.`n`n", $amt, getsetting("deathoverlord", '`$Ramius'));
        output("`7Without another word she scurries off, a determined look on her face, and a purpose in her stride.`n`n");
        if ($session['user']['dragonkills'] > 30) {
            $session['user']['deathpower'] += 10;
        } else {
            $session['user']['deathpower'] += 15;
        }
        $session['user']['gold'] -= $amt;
    }
}
function get_partner($player = false)
{
    global $session;
    if ($player === false) {
        $partner = getsetting("barmaid", "`%Violet");
        if ($session['user']['sex'] != SEX_MALE) {
            $partner = getsetting("bard", "`^Seth");
        }
    } else {
        if ($session['user']['marriedto'] == INT_MAX) {
            $partner = getsetting("barmaid", "`%Violet");
            if ($session['user']['sex'] != SEX_MALE) {
                $partner = getsetting("bard", "`^Seth");
            }
        } else {
            $sql = "SELECT name FROM " . db_prefix("accounts") . " WHERE acctid = {$session['user']['marriedto']}";
            $result = db_query($sql);
            if ($row = db_fetch_assoc($result)) {
                $partner = $row['name'];
            } else {
                $session['user']['marriedto'] = 0;
                $partner = getsetting("barmaid", "`%Violet");
                if ($session['user']['sex'] != SEX_MALE) {
                    $partner = getsetting("bard", "`^Seth");
                }
            }
        }
    }
    //	No need to translate names...
    //	tlschema("partner");
    //	$partner = translate_inline($partner);
    //	tlschema();
    return $partner;
}
function dump_item_ascode($item, $indent = "\t")
{
    $out = "";
    if (is_array($item)) {
        $temp = $item;
    } else {
        $temp = @unserialize($item);
    }
    if (is_array($temp)) {
        $out .= "array(\n{$indent}";
        $row = array();
        while (list($key, $val) = @each($temp)) {
            array_push($row, "'{$key}'=&gt;" . dump_item_ascode($val, $indent . "\t"));
        }
        if (strlen(join(", ", $row)) > 80) {
            $out .= join(",\n{$indent}", $row);
        } else {
            $out .= join(", ", $row);
        }
        $out .= "\n{$indent})";
    } else {
        $out .= "'" . htmlentities(addslashes($item), ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "'";
    }
    return $out;
}
function oneshotteleporter_run()
{
    global $session;
    $to = httpget("to");
    if ($to == "") {
        page_header("The Void");
        output("You press the button on your One-Shot Teleporter.  One obligatory blinding flash of light and pain later, you find yourself floating around in empty black nothingness!`n`nA flashing red light and an annoying BEEPing noise from your device insists that you select a destination, and quickly, before you find yourself stuck here or imploded.");
        $vloc = array();
        $vname = getsetting("villagename", LOCATION_FIELDS);
        $vloc[$vname] = "village";
        $vloc = modulehook("validlocation", $vloc);
        ksort($vloc);
        reset($vloc);
        addnav("Choose a Destination");
        foreach ($vloc as $loc => $val) {
            addnav(array("Go to %s", $loc), "runmodule.php?module=oneshotteleporter&to=" . htmlentities($loc));
        }
    } else {
        page_header("Back to Reality");
        output("You quickly select an outpost from the list.  With a sudden jolt, you find yourself standing in the middle of your chosen outpost!  You look around for your teleporting device, but realise that it must have only teleported you, not itself.  What a piece of junk.");
        $session['user']['location'] = $to;
        $session['user']['specialinc'] = "";
        addnav("Continue");
        addnav("Back to the Outpost", "village.php");
    }
    page_footer();
    return true;
}
function _curl($url)
{
    $ch = curl_init();
    if (!$ch) {
        return false;
    }
    // set URL and other appropriate options
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $val = 5;
    if (defined("DB_CONNECTED") && DB_CONNECTED == true) {
        require_once "lib/settings.php";
        $val = getsetting("curltimeout", 5);
    }
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $val);
    curl_setopt($ch, CURLOPT_TIMEOUT, $val);
    // grab URL and pass it to the browser
    $ret = curl_exec($ch);
    // close curl resource, and free up system resources
    curl_close($ch);
    $val = explode("\n", $ret);
    $total = count($val);
    $cur = 0;
    foreach ($val as $k => $a) {
        $cur++;
        $done[] = $a . ($cur != $total ? "\n" : "");
    }
    return $done;
}
function fightnav($allowspecial = true, $allowflee = true, $script = false)
{
    global $PHP_SELF, $session, $newenemies, $companions;
    tlschema("fightnav");
    if ($script === false) {
        $script = substr($PHP_SELF, strrpos($PHP_SELF, "/") + 1) . "?";
    } else {
        if (!strpos($script, "?")) {
            $script .= "?";
            //		}elseif (substr($script,strlen($script)-1)!="&" && !substr($script,strlen($script)-1)=="?"){
        } elseif (substr($script, strlen($script) - 1) != "&") {
            $script .= "&";
        }
    }
    $fight = "Fight";
    $run = "Run";
    if (!$session['user']['alive']) {
        $fight = "F?Torment";
        $run = "R?Flee";
    }
    addnav($fight, $script . "op=fight");
    if ($allowflee) {
        addnav($run, $script . "op=run");
    }
    if ($session['user']['superuser'] & SU_DEVELOPER) {
        addnav("Abort", $script);
    }
    if (getsetting("autofight", 0)) {
        addnav("Automatic Fighting");
        addnav("5?For 5 Rounds", $script . "op=fight&auto=five");
        addnav("1?For 10 Rounds", $script . "op=fight&auto=ten");
        $auto = getsetting("autofightfull", 0);
        if (($auto == 1 || $auto == 2 && !$allowflee) && count($newenemies) == 1) {
            addnav("U?Until End", $script . "op=fight&auto=full");
        } elseif ($auto == 1 || $auto == 2 && !$allowflee) {
            addnav("U?Until current enemy dies", $script . "op=fight&auto=full");
        }
    }
    if ($allowspecial) {
        addnav("Special Abilities");
        modulehook("fightnav-specialties", array("script" => $script));
        if ($session['user']['superuser'] & SU_DEVELOPER) {
            addnav("`&Super user`0", "");
            addnav("!?`&&#149; __GOD MODE", $script . "op=fight&skill=godmode", true);
        }
        modulehook("fightnav", array("script" => $script));
    }
    if (count($newenemies) > 1) {
        addnav("Targets");
        foreach ($newenemies as $index => $badguy) {
            if ($badguy['creaturehealth'] <= 0 || isset($badguy['dead']) && $badguy['dead'] == true) {
                continue;
            }
            addnav(array("%s%s`0", isset($badguy['istarget']) && $badguy['istarget'] ? "`#*`0" : "", $badguy['creaturename']), $script . "op=fight&newtarget={$index}");
        }
    }
    tlschema();
}
function lovers_chat_seth()
{
    global $session;
    if (httpget("act") == "") {
        output("You make your way over to where %s`0 is sitting, ale in hand.", getsetting("bard", "`^Seth"));
        output("Sitting down, and waiting for %s`0 to finish a song, you light your pipe.", getsetting("bard", "`^Seth"));
        addnav("Ask about your manliness", "runmodule.php?module=lovers&op=chat&act=armor");
        addnav("Discuss Sports", "runmodule.php?module=lovers&op=chat&act=sports");
    } elseif (httpget("act") == "sports") {
        output("You and %s`0 spend some time talking about the recent dwarf tossing competition.", getsetting("bard", "`^Seth"));
        output("Not wanting to linger around another man for too long, so no one \"wonders\", you decide you should find something else to do.");
    } else {
        $charm = $session['user']['charm'] + e_rand(-1, 1);
        output("%s`0 looks you up and down very seriously.", getsetting("bard", "`^Seth"));
        output("Only a friend can be truly honest, and that is why you asked him.");
        switch ($charm) {
            case -3:
            case -2:
            case -1:
            case 0:
                $msg = translate_inline("You make me glad I'm not gay!");
                break;
            case 1:
            case 2:
            case 3:
                $msg = translate_inline("I've seen some handsome men in my day, but I'm afraid you aren't one of them.");
                break;
            case 4:
            case 5:
            case 6:
                $msg = translate_inline("I've seen worse my friend, but only trailing a horse.");
                break;
            case 7:
            case 8:
            case 9:
                $msg = translate_inline("You're of fairly average appearance my friend.");
                break;
            case 10:
            case 11:
            case 12:
                $msg = translate_inline("You certainly are something to look at, just don't get too big of a head about it, eh?");
                break;
            case 13:
            case 14:
            case 15:
                $msg = translate_inline("You're quite a bit better than average!");
                break;
            case 16:
            case 17:
            case 18:
                $msg = translate_inline("Few women would be able to resist you!");
                break;
            default:
                $msg = translate_inline("I hate you, why, you are simply the most handsome man ever!");
        }
        output("Finally he reaches a conclusion and states, \"%s`0\"", $msg);
    }
}
function drinks_gettexts()
{
    global $session;
    $iname = getsetting("innname", LOCATION_INN);
    $drinktext = array("title" => "{$iname}", "barkeep" => getsetting("barkeep", "`tCedrik"), "return" => "", "demand" => "Pounding your fist on the bar, you demand another drink", "toodrunk" => " but {barkeep} continues to clean the glass he was working on.  \"`%You've had enough " . ($session['user']['sex'] ? "lass" : "lad") . ",`0\" he declares.", "toomany" => "{barkeep} eyes you critically. \"`%Ya've had enough of the hard stuff, my friend.  No more of that for you today.`0\"", "drinksubs" => array());
    $schemas = array('title' => "module-drinks", 'barkeep' => "module-drinks", 'return' => "module-drinks", 'demand' => "module-drinks", 'toodrunk' => "module-drinks", 'toomany' => "module-drinks", 'drinksubs' => "module-drinks");
    $drinktext['schemas'] = $schemas;
    return $drinktext;
}
function hunterslodge_customarmour_run()
{
    require_once "lib/sanitize.php";
    require_once "lib/names.php";
    global $session;
    $op = httpget("op");
    $free = httpget("free");
    page_header("Choose your Custom Armour");
    switch ($op) {
        case "change":
            output("Want to change your Custom Armour?  No problem.  Enter your desired armour in the box below.  You've got 25 characters to play around with.`n(leave this blank to disable custom armour naming and return to default, game-supplied armour names)`n`n");
            rawoutput("<form action='runmodule.php?module=hunterslodge_customarmour&op=confirm&free=" . $free . "' method='POST'>");
            $armour = get_module_pref("customarmour");
            rawoutput("<input id='input' name='newarmour' width='25' maxlength='25' value='" . htmlentities($armour, ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "'>");
            rawoutput("<input type='submit' class='button' value='Preview'>");
            rawoutput("</form>");
            addnav("", "runmodule.php?module=hunterslodge_customarmour&op=confirm&free=" . $free);
            addnav("Cancel");
            addnav("Don't set custom armour, just go back to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
        case "confirm":
            $newarmour = httppost("newarmour");
            $sub = httpget("sub");
            $newarmour = str_replace("`", "", $newarmour);
            $newarmour = comment_sanitize($newarmour);
            $newarmour = substr($newarmour, 0, 25);
            if ($newarmour) {
                output("Your new custom armour is:`n%s`nWould you like to set your new armour now?`n`n", $newarmour);
            } else {
                output("You've chosen to go back to the default, game-supplied armours.  Are you sure that's what you want?`n`n");
            }
            addnav("Confirm");
            addnav("Set custom armour", "runmodule.php?module=hunterslodge_customarmour&op=set&free={$free}&newarmour=" . rawurlencode($newarmour));
            addnav("Cancel");
            addnav("Don't set custom armour, just go back to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
        case "set":
            $newarmour = rawurldecode(httpget("newarmour"));
            if ($newarmour == "") {
                output("Your custom armour name has been removed.  The next time you change your armour, you'll return to game-supplied armour names.`n`n");
            } else {
                output("Your custom armour has been set to %s!`n`n", $newarmour);
                $session['user']['armor'] = $newarmour;
            }
            set_module_pref("customarmour", $newarmour);
            if (!$free) {
                require_once "modules/iitems/lib/lib.php";
                $id = has_item("hunterslodge_customarmour");
                delete_item($id);
            }
            addnav("Return");
            addnav("Return to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
    }
    page_footer();
}
function namecolor_form()
{
    $regname = get_player_basename();
    output("Your name currently is this:");
    rawoutput($regname);
    output(", which looks like %s`7`n`n", $regname);
    output("How would you like your name to look?`n");
    rawoutput("<form action='runmodule.php?module=namecolor&op=namepreview' method='POST'><input name='newname' value=\"" . HTMLEntities($regname, ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "\"> <input type='submit' class='button' value='Preview'></form>");
    addnav("", "runmodule.php?module=namecolor&op=namepreview");
}
function logd_error_notify($errno, $errstr, $errfile, $errline, $backtrace)
{
    global $session;
    $sendto = explode(";", getsetting("notify_address", ""));
    $howoften = getsetting("notify_every", 30);
    reset($sendto);
    $data = datacache("error_notify", 86400);
    if (!is_array($data)) {
        $data = array('firstrun' => true, 'errors' => array());
    } else {
        $data['firstrun'] = false;
    }
    $do_notice = false;
    if (!array_key_exists($errstr, $data['errors'])) {
        $do_notice = true;
    } elseif (strtotime("now") - $data['errors'][$errstr] > $howoften * 60) {
        $do_notice = true;
    }
    if ($data['firstrun']) {
        debug("First run, not notifying users.");
    } else {
        if ($do_notice) {
            /***
             * Set up the mime bits
             **/
            require_once "sanitize.php";
            $notice_text = "This is a multi-part message in MIME format.";
            $userstr = "";
            if ($session && isset($session['user']['name']) && isset($sesson['user']['acctid'])) {
                $userstr = "Error triggered by user " . $session['user']['name'] . " (" . $session['user']['acctid'] . ")\n";
            }
            $plain_text = "{$userstr}{$errstr} in {$errfile} ({$errline})\n" . sanitize_html($backtrace);
            $html_text = "<html><body>{$errstr} in {$errfile} ({$errline})<hr>{$backtrace}</body></html>";
            $semi_rand = md5(time());
            $mime_boundary = "==MULTIPART_BOUNDARY_{$semi_rand}";
            $mime_boundary_header = chr(34) . $mime_boundary . chr(34);
            $subject = "{$_SERVER['HTTP_HOST']} {$level}";
            $body = "{$notice_text}\r\n\r\n--{$mime_boundary}\r\nContent-Type: text/plain; charset=us-ascii\r\nContent-Transfer-Encoding: 7bit\r\n\r\n{$plain_text}\r\n\r\n--{$mime_boundary}\r\nContent-Type: text/html; charset=us-ascii\r\nContent-Transfer-Encoding: 7bit\r\n\r\n{$html_text}\r\n\r\n--{$mime_boundary}--";
            /***
             * Mime bits are set up,
             **/
            while (list($key, $email) = each($sendto)) {
                debug("Notifying {$email} of this error.");
                mail($email, $subject, $body, "From: " . $from . "\n" . "MIME-Version: 1.0\n" . "Content-Type: multipart/alternative;\n" . "     boundary=" . $mime_boundary_header);
            }
            //mark the time that notice was last sent for this error.
            $data['errors'][$errstr] = strtotime("now");
        } else {
            debug("Not notifying users for this error, it's only been " . round((strtotime("now") - $data['errors'][$errstr]) / 60, 2) . " minutes.");
        }
    }
    updatedatacache("error_notify", $data);
    debug($data);
}
function do_forced_nav($anonymous, $overrideforced)
{
    global $baseaccount, $session, $REQUEST_URI;
    rawoutput("<!--\nAllowAnonymous: " . ($anonymous ? "True" : "False") . "\nOverride Forced Nav: " . ($overrideforced ? "True" : "False") . "\n-->");
    if (isset($session['loggedin']) && $session['loggedin']) {
        $sql = "SELECT *  FROM " . db_prefix("accounts") . " WHERE acctid = '" . $session['user']['acctid'] . "'";
        $result = db_query($sql);
        if (db_num_rows($result) == 1) {
            $session['user'] = db_fetch_assoc($result);
            $baseaccount = $session['user'];
            $session['bufflist'] = unserialize($session['user']['bufflist']);
            if (!is_array($session['bufflist'])) {
                $session['bufflist'] = array();
            }
            $session['user']['dragonpoints'] = unserialize($session['user']['dragonpoints']);
            $session['user']['prefs'] = unserialize($session['user']['prefs']);
            if (!is_array($session['user']['dragonpoints'])) {
                $session['user']['dragonpoints'] = array();
            }
            if (is_array(unserialize($session['user']['allowednavs']))) {
                $session['allowednavs'] = unserialize($session['user']['allowednavs']);
            } else {
                $session['allowednavs'] = array($session['user']['allowednavs']);
            }
            if (!$session['user']['loggedin'] || date("U") - strtotime($session['user']['laston']) > getsetting("LOGINTIMEOUT", 900)) {
                $session = array();
                redirect("index.php?op=timeout", "Account not logged in but session thinks they are.");
            }
        } else {
            $session = array();
            $session['message'] = translate_inline("`4Error, your login was incorrect`0", "login");
            redirect("index.php", "Account Disappeared!");
        }
        db_free_result($result);
        //check the nav exists in the session's allowednavs array
        if (isset($session['allowednavs'][$REQUEST_URI]) && $session['allowednavs'][$REQUEST_URI] && $overrideforced !== true) {
            //The nav is fine
            //clear the navs - more navs will be added as the script the player is currently viewing loads and executes
            $session['allowednavs'] = array();
        } else {
            if ($overrideforced !== true) {
                //This nav is not fine at all.  Redirect the player to badnav.php.
                $session['badnav'] = 1;
                redirect("badnav.php", "Navigation not allowed to {$REQUEST_URI}");
            }
        }
    } else {
        if (!$anonymous) {
            $session['message'] = translate_inline("You are not logged in, this may be because your session timed out.", "login");
            redirect("index.php?op=timeout&nli=true", "Not logged in: {$REQUEST_URI}");
        }
    }
}
function forest($noshowmessage = false)
{
    global $session, $playermount;
    tlschema("forest");
    //	mass_module_prepare(array("forest", "validforestloc"));
    addnav("Heal");
    addnav("H?Hospital Tent", "healer.php");
    addnav("Fight");
    addnav("L?Look for Something to Kill", "forest.php?op=search");
    if ($session['user']['level'] > 1) {
        addnav("S?Go Slumming", "forest.php?op=search&type=slum");
    }
    addnav("T?Go Thrillseeking", "forest.php?op=search&type=thrill");
    if (getsetting("suicide", 0)) {
        if (getsetting("suicidedk", 10) <= $session['user']['dragonkills']) {
            addnav("*?Search `\$Suicidally`0", "forest.php?op=search&type=suicide");
        }
    }
    if ($session['user']['level'] >= 15 && $session['user']['seendragon'] == 0) {
        // Only put the green dragon link if we are a location which
        // should have a forest.   Don't even ask how we got into a forest()
        // call if we shouldn't have one.   There is at least one way via
        // a superuser link, but it shouldn't happen otherwise.. We just
        // want to make sure however.
        $isforest = 0;
        $vloc = modulehook('validforestloc', array());
        foreach ($vloc as $i => $l) {
            if ($session['user']['location'] == $i) {
                $isforest = 1;
                break;
            }
        }
        if ($isforest || count($vloc) == 0) {
            addnav("G?`@Seek Out the Green Dragon", "forest.php?op=dragon");
        }
    }
    addnav("Other");
    villagenav();
    if ($noshowmessage != true) {
        output("`c`7`bThe Forest`b`0`c");
        output("The Forest, home to evil creatures and evildoers of all sorts.`n`n");
        output("The thick foliage of the forest restricts your view to only a few yards in most places.");
        output("The paths would be imperceptible except for your trained eye.");
        output("You move as silently as a soft breeze across the thick moss covering the ground, wary to avoid stepping on a twig or any of the numerous pieces of bleached bone that populate the forest floor, lest you betray your presence to one of the vile beasts that wander the forest.`n");
        modulehook("forest-desc");
    }
    modulehook("forest", array());
    module_display_events("forest", "forest.php");
    addnav("Inventory");
    addnav("View your Inventory", "inventory.php?items_context=forest");
    tlschema();
}
/**
 * This function prepares the fight, sets up options and gives hook a hook to change options on a per-player basis.
 *
 * @param array $options The options given by a module or basics.
 * @return array The complete options.
 */
function prepare_fight($options = false)
{
    global $companions;
    $basicoptions = array("maxattacks" => getsetting("maxattacks", 4));
    if (!is_array($options)) {
        $options = array();
    }
    $fightoptions = $options + $basicoptions;
    $fightoptions = modulehook("fightoptions", $fightoptions);
    // We'll also reset the companions here...
    prepare_companions();
    return $fightoptions;
}
function inncoupons_run()
{
    require_once "lib/sanitize.php";
    global $session;
    $op = httpget("op");
    $iname = getsetting("innname", LOCATION_INN);
    $cost = get_module_setting("cost");
    $config = unserialize($session['user']['donationconfig']);
    if (!is_array($config)) {
        $config = array();
    }
    if (isset($config['innstays']) && $config['innstays']) {
        set_module_pref("availablestays", $config['innstays']);
        unset($config['innstays']);
        $session['user']['donationconfig'] = serialize($config);
    }
    if ($op == "room") {
        $num = get_module_pref("availablestays");
        $num--;
        set_module_pref("availablestays", $num);
        $session['user']['loggedin'] = 0;
        $session['user']['location'] = $iname;
        $session['user']['boughtroomtoday'] = 1;
        $session['user']['restorepage'] = "inn.php?op=strolldown";
        saveuser();
        $session = array();
        redirect("index.php");
    } elseif ($op == "innstays") {
        page_header("Hunter's Lodge");
        output("`7J. C. Petersen turns to you. \"`&Ten free nights in %s will cost %s points,`7\" he says.", $iname, $cost);
        output("\"`&Will this suit you?`7\"`n`n");
        addnav("Confirm Inn Stays");
        addnav("Yes", "runmodule.php?module=inncoupons&op=innconfirm");
        addnav("No", "lodge.php");
    } elseif ($op == "innconfirm") {
        page_header("Hunter's Lodge");
        addnav("L?Return to the Lodge", "lodge.php");
        $pointsavailable = $session['user']['donation'] - $session['user']['donationspent'];
        if ($pointsavailable >= $cost) {
            output("`7J. C. Petersen gives you a card that reads \"Coupon: Good for ten free stays at %s\"", $iname);
            $num = get_module_pref("availablestays");
            $num += 10;
            set_module_pref("availablestays", $num);
            $session['user']['donationspent'] += $cost;
        } else {
            output("`7J. C. Petersen looks down his nose at you.");
            output("\"`&I'm sorry, but you do not have the %s points required to purchase the coupons. Please return when you do and I'll be happy to sell them to you.`7\"", $cost);
        }
    }
    page_footer();
}
function translationwizard_run()
{
    global $session, $logd_version, $coding;
    check_su_access(SU_IS_TRANSLATOR);
    //check again Superuser Access
    $op = httpget('op');
    page_header("Translation Wizard");
    //get some standards
    $languageschema = get_module_pref("language", "translationwizard");
    //these lines grabbed the local scheme, in 1.1.0 there is a setting for it
    $coding = getsetting("charset", "ISO-8859-1");
    $viewsimple = get_module_pref("view", "translationwizard");
    $mode = httpget('mode');
    $namespace = httppost('ns');
    $from = httpget('from');
    $page = get_module_setting(page);
    if (httpget('ns') != "" && $namespace == "") {
        $namespace = httpget('ns');
    }
    //if there is no post then there is maybe something to get
    $trans = httppost("transtext");
    if (is_array($trans)) {
        $transintext = $trans;
    } else {
        if ($trans) {
            $transintext = array($trans);
        } else {
            $transintext = array();
        }
    }
    $trans = httppost("transtextout");
    if (is_array($trans)) {
        $transouttext = $trans;
    } else {
        if ($trans) {
            $transouttext = array($trans);
        } else {
            $transouttext = array();
        }
    }
    //end of the header
    if ($op == "") {
        $op = "default";
    }
    require "./modules/translationwizard/errorhandler.php";
    require "./modules/translationwizard/{$op}.php";
    require_once "lib/superusernav.php";
    superusernav();
    require "./modules/translationwizard/build_nav.php";
    page_footer();
}
function haberdasher_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "village":
            if ($session['user']['location'] == getsetting("villagename", LOCATION_FIELDS)) {
                tlschema($args['schemas']['marketnav']);
                addnav($args["marketnav"]);
                tlschema();
                addnav("D?Deimos' Haberdashery", "runmodule.php?module=haberdasher");
            }
            break;
        case "biostat":
            if (get_module_pref("hatsize", false, $args['acctid'])) {
                output("`^Hat Size: `@%s`n", get_module_pref("hatsize", false, $args['acctid']));
            }
            break;
        case "dragonkilltext":
            $losepercent = get_module_setting("losepercent");
            $hatgold = get_module_pref("hatgold");
            if ($losepercent > 0 && $hatgold > 0) {
                $losepercent /= 100;
                $loseamount = floor($hatgold * $losepercent);
                $hatgold -= $loseamount;
                if ($hatgold <= get_module_setting("lowesthat")) {
                    output("`n`nYou find a hat nearby, but it's too badly burnt to be worth wearing.");
                    $hatgold = 0;
                } else {
                    output("`n`nYou find a hat nearby, somewhat burnt, but still wearable.");
                }
                set_module_pref("hatgold", $hatgold);
                $hatsize = haberdasher_sizecalc($session['user']['acctid']);
            }
            break;
        case "validateprefs":
            if (isset($args['hatsize'])) {
                if (is_numeric($args['hatsize'])) {
                    if (isset($args['hatgold'])) {
                        $hatsize = haberdasher_rawsizecalc($args['hatgold']);
                        if ($hatsize == 0) {
                            $args['hatgold'] = 0;
                        }
                        $args['hatsize'] = $hatsize;
                    }
                }
            }
            break;
    }
    return $args;
}
function heidi_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "village":
            $allowgift = get_module_setting("allowgift");
            $allowdp = get_module_setting("allowdp");
            $changeallowed = get_module_setting("changeallowed");
            // disable for farmies lower than level 10
            if (($allowgift || $allowdp || $changeallowed > 0) && ($session['user']['dragonkills'] > 0 || $session['user']['level'] >= 10)) {
                tlschema($args['schemas']['marketnav']);
                addnav($args['marketnav']);
                tlschema();
                addnav("H?Heidi's Place", "runmodule.php?module=heidi");
            }
            break;
        case "newday":
            if ($args['resurrection'] != 'true') {
                set_module_pref("pvpchange", 0);
            }
            set_module_pref("pendingdp", 0);
            $turns = getsetting("turns", 10) + $session['user']['spirits'];
            reset($session['user']['dragonpoints']);
            while (list($key, $val) = each($session['user']['dragonpoints'])) {
                if ($val == "ff") {
                    $turns++;
                }
            }
            set_module_pref("newdayturns", $turns);
            $echance = e_rand(0, 100);
            $mult = e_rand(200, 400);
            $addgold = round($mult * ($session['user']['level'] / max(10, $session['user']['dragonkills'])));
            if ($session['user']['dragonkills'] < 6) {
                $addgold * 1.5;
            }
            if ($echance >= get_module_setting("findperc")) {
                $addgold = 0;
            }
            set_module_pref("addgold", $addgold);
            if ($addgold > 1) {
                // they are a recipient
                $session['user']['gold'] += $addgold;
                output("`n`5Beside your pillow is a small leather bag containing %s gold, and a note: `^Blessings to ye, child, for someone cared enough to send ye a gift.", $addgold);
                output("`5Wondering who it is from, you add it to your purse.`n");
                debuglog("gained {$addgold} gold from an anonymous gift.");
            }
            break;
    }
    return $args;
}
function clanform()
{
    rawoutput("<form action='clan.php?op=new&apply=1' method='POST'>");
    addnav("", "clan.php?op=new&apply=1");
    output("`b`cNew Clan Application Form`c`b");
    output("Clan Name: ");
    rawoutput("<input name='clanname' maxlength='50' value=\"" . htmlentities(stripslashes(httppost('clanname')), ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "\">");
    output("`nShort Name: ");
    rawoutput("<input name='clanshort' maxlength='5' size='5' value=\"" . htmlentities(stripslashes(httppost('clanshort')), ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "\">");
    output("`nNote, color codes are permitted in neither clan names nor short names.");
    output("The clan name is shown on player bios and on clan overview pages while the short name is displayed next to players' names in comment areas and such.`n");
    $apply = translate_inline("Apply");
    rawoutput("<input type='submit' class='button' value='{$apply}'></form>");
}
function mysticalshop_uninstall()
{
    require_once './modules/mysticalshop/run/editor_what/delete.php';
    $items = db_query('SELECT id FROM ' . db_prefix('magicitems'));
    while ($item = db_fetch_assoc($items)) {
        mysticalshop_delete_item($item['id']);
    }
    $sql = 'DROP TABLE IF EXISTS ' . db_prefix('magicitems');
    db_query($sql);
    if (getsetting('usedatacache', false)) {
        require_once './modules/mysticalshop/libcoredup.php';
        mysticalshop_massinvalidate('modules-mysticalshop-');
    }
}
function hunterslodge_namedmount_run()
{
    require_once "lib/sanitize.php";
    require_once "lib/names.php";
    global $session;
    global $playermount;
    $op = httpget("op");
    $free = httpget("free");
    page_header("Name your Mount");
    switch ($op) {
        case "change":
            output("Want to change your Mount's name?  No problem.  Enter your desired name in the box below.  You've got 25 characters to play around with.`n(leave this blank to disable mount naming)`n`n");
            rawoutput("<form action='runmodule.php?module=hunterslodge_namedmount&op=confirm&free=" . $free . "' method='POST'>");
            rawoutput("<input id='input' name='newname' width='25' maxlength='25' value='" . htmlentities($race, ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "'>");
            rawoutput("<input type='submit' class='button' value='Preview'>");
            rawoutput("</form>");
            addnav("", "runmodule.php?module=hunterslodge_namedmount&op=confirm&free=" . $free);
            addnav("Cancel");
            addnav("Don't set a mount name, just go back to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
        case "confirm":
            $newname = httppost("newname");
            $sub = httpget("sub");
            $newname = comment_sanitize($newname);
            $newname = substr($newname, 0, 25);
            if ($newname) {
                output("Your Mount's name is now:`n%s`0 the %s`nWould you like to set your mount's name now?`n`n", $newname, $playermount['mountname']);
            } else {
                output("You've chosen to go back to having an unnamed Mount.  Are you sure that's what you want?`n`n");
            }
            addnav("Confirm");
            addnav("Set mount name", "runmodule.php?module=hunterslodge_namedmount&op=set&free={$free}&newname=" . rawurlencode($newname));
            addnav("Cancel");
            addnav("Don't set a custom mount name, just go back to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
        case "set":
            $newname = rawurldecode(httpget("newname"));
            output("You now ride %s`0 the %s!`n`n", $newname, $playermount['mountname']);
            set_module_pref("mountname", $newname);
            if (!$free) {
                $id = has_item("hunterslodge_namedmount");
                delete_item($id);
            }
            addnav("Return");
            addnav("Return to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
    }
    page_footer();
}
function allhof_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "village":
            if ($session['user']['location'] != getsetting("villagename", LOCATION_FIELDS)) {
                tlschema($args['schemas']['infonav']);
                addnav($args['infonav']);
                tlschema();
                addnav("Hall o' Fame", "hof.php?hof=1");
            }
            break;
    }
    return $args;
}
function pvpwarning($dokill = false)
{
    global $session;
    $days = getsetting("pvpimmunity", 5);
    $exp = getsetting("pvpminexp", 1500);
    if ($session['user']['age'] <= $days && $session['user']['dragonkills'] == 0 && $session['user']['pk'] == 0 && $session['user']['experience'] <= $exp) {
        if ($dokill) {
            output("`\$Warning!`^ Since you were still under PvP immunity, but have chosen to attack another player, you have lost this immunity!!`n`n");
            $session['user']['pk'] = 1;
        } else {
            output("`\$Warning!`^ Players are immune from Player vs Player (PvP) combat for their first %s days in the game or until they have earned %s experience, or until they attack another player.  If you choose to attack another player, you will lose this immunity!`n`n", $days, $exp);
        }
    }
    modulehook("pvpwarning", array("dokill" => $dokill));
}
function db_query($sql, $die = true)
{
    //debug("SQL Query: ".$sql);
    if (defined("DB_NODB") && !defined("LINK")) {
        return array();
    }
    global $session, $dbinfo, $allqueries, $allqueriesbyfile;
    $dbinfo['queriesthishit']++;
    $fname = DBTYPE . "_query";
    $starttime = getmicrotime();
    $thisquery = array();
    $thisquery['query'] = $sql;
    $r = $fname($sql, LINK);
    if (!$r && $die === true) {
        if (defined("IS_INSTALLER")) {
            return array();
        } else {
            if ($session['user']['superuser'] & SU_DEVELOPER || 1) {
                require_once "lib/show_backtrace.php";
                die("<pre>" . HTMLEntities($sql, ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "</pre>" . db_error(LINK) . show_backtrace());
            } else {
                die("A most bogus error has occurred.  I apologise, but the page you were trying to access is broken.  Please use your browser's back button and try again.");
            }
        }
    }
    $endtime = getmicrotime();
    if ($endtime - $starttime >= 1.0 && $session['user']['superuser'] & SU_DEBUG_OUTPUT) {
        $s = trim($sql);
        if (strlen($s) > 800) {
            $s = substr($s, 0, 400) . " ... " . substr($s, strlen($s) - 400);
        }
        debug("Slow Query (" . round($endtime - $starttime, 2) . "s): " . HTMLEntities($s, ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "`n");
    }
    $thisquery['time'] = round($endtime - $starttime, 5);
    $trace = debug_backtrace();
    $thisquery['file1'] = $trace[0]['file'];
    $thisquery['line1'] = $trace[0]['line'];
    $thisquery['file2'] = $trace[1]['file'];
    $thisquery['line2'] = $trace[1]['line'];
    $allqueries[] = $thisquery;
    $allqueriesbyfile[$thisquery['file1']]['time'] += $thisquery['time'];
    $allqueriesbyfile[$thisquery['file1']]['hits'] += 1;
    unset($dbinfo['affected_rows']);
    $dbinfo['affected_rows'] = db_affected_rows();
    $dbinfo['querytime'] += $endtime - $starttime;
    return $r;
}
function statue_dohook($hookname, $args)
{
    global $REQUEST_URI;
    global $session;
    $capital = getsetting("villagename", LOCATION_FIELDS);
    $hero = get_module_setting("hero");
    switch ($hookname) {
        case "village-desc":
            if ($session['user']['location'] != $capital) {
                break;
            }
            if ($hero == 0) {
                output("`n`@The people wandering past periodically stop to admire a statue of the ancient hero, `&MightyE`@.`0`n");
            } else {
                $sql = "SELECT name FROM " . db_prefix("accounts") . " WHERE acctid='{$hero}'";
                $result = db_query_cached($sql, "lasthero");
                $row = db_fetch_assoc($result);
                output("`0The inhabitants of %s are busy erecting a statue for their newest hero, `&%s`0, on the only statue pedestal around.  The remains of the statue that had stood there before lie in such ruins around the pedestal that it is no longer recognizable.`0`n`n", $session['user']['location'], $row['name']);
            }
            break;
        case "index":
            if (!get_module_setting("showonindex")) {
                break;
            }
            $heroname = "MightyE";
            if ($hero != 0) {
                $sql = "SELECT name FROM " . db_prefix("accounts") . " WHERE acctid='{$hero}'";
                $result = db_query_cached($sql, "lasthero");
                $row = db_fetch_assoc($result);
                $heroname = $row['name'];
            }
            output("`@The most recent hero of the realm is: `&%s`0`n`n", $heroname);
            break;
        case "dragonkill":
            set_module_setting("hero", $session['user']['acctid']);
            invalidatedatacache("lasthero");
            break;
        case "namechange":
            if ($hero == $session['user']['acctid']) {
                invalidatedatacache("lasthero");
            }
            break;
    }
    return $args;
}
function racekittymorph_uninstall()
{
    global $session;
    $vname = getsetting("villagename", LOCATION_FIELDS);
    $gname = "kittania";
    $sql = "UPDATE " . db_prefix("accounts") . " SET location='{$vname}' WHERE location = '{$gname}'";
    db_query($sql);
    if ($session['user']['location'] == $gname) {
        $session['user']['location'] = $vname;
    }
    // Force anyone who was a Kittymorph to rechoose race
    $sql = "UPDATE  " . db_prefix("accounts") . " SET race='" . RACE_UNKNOWN . "' WHERE race='Kittymorph'";
    db_query($sql);
    if ($session['user']['race'] == 'Kittymorph') {
        $session['user']['race'] = RACE_UNKNOWN;
    }
    return true;
}
function friends_run()
{
    global $session;
    popup_header("Who's Online");
    //Output online characters list
    $sql = "SELECT name,laston,loggedin FROM " . db_prefix("accounts") . " WHERE locked=0 AND loggedin=1 AND laston>'" . date("Y-m-d H:i:s", strtotime("-" . getsetting("LOGINTIMEOUT", 900) . " seconds")) . "' ORDER BY laston DESC";
    $result = db_query($sql);
    rawoutput("<table>");
    while ($row = db_fetch_assoc($result)) {
        rawoutput("<tr><td>");
        output("%s", $row['name']);
        rawoutput("</td><td>");
        output("%s", $row['laston']);
        rawoutput("</td></tr>");
    }
    rawoutput("</table>");
    popup_footer();
}
function innchat_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "innchatter":
            $id = $session['user']['acctid'];
            if (e_rand(1, 2) == 1) {
                $sql = "SELECT name FROM " . db_prefix("accounts") . " WHERE locked=0 AND acctid != '{$id}' ORDER BY rand(" . e_rand() . ") LIMIT 1";
            } else {
                $sql = "SELECT creaturename AS name FROM " . db_prefix("masters") . " WHERE 1 ORDER BY rand(" . e_rand() . ") LIMIT 1";
            }
            // Only let this hit the database once every 10 minute if we're
            // using data caching.  Otherwise it could be expensive.  If they
            // hit it multiple times within ten minutes, it'll use the same
            // random name of player or master.  We'll invalidate the name when someone's name changes
            // for any reason.
            $res = db_query_cached($sql, "innchat-names");
            $row = db_fetch_assoc($res);
            // Give 2 out of X (currently 7 (5+these 2)) chances of hearing about
            // a player.
            $noplayers = translate_inline("loneliness in town");
            if ($row['name'] == "") {
                $row['name'] = $noplayers;
            }
            $args[] = $row['name'];
            $args[] = $row['name'];
            $args[] = translate_inline("Frequently Asked Questions");
            $args[] = translate_inline("dwarf tossing");
            $args[] = translate_inline("YOU");
            $args[] = getsetting("villagename", LOCATION_FIELDS);
            $args[] = translate_inline("today's weather");
            $args[] = translate_inline("the elementary discord of being");
            // "Das elementare Zerwürfnis des Seins" no idea if that makes any sense in english. (Ok, it doesn't make sense in german too.) It's from a "Jägermeister" commercial spot :)
            break;
        case "namechange":
        case "dragonkill":
            // Someone just did a dragonkill or had their name changed.  Since it
            // it could have been this person, we'll just invalidate the cache
            invalidatedatacache("innchat-names");
            break;
    }
    return $args;
}
function mysticalshop_massinvalidate($name)
{
    if (getsetting('usedatacache', false)) {
        $name = DATACACHE_FILENAME_PREFIX . $name;
        global $datacachefilepath;
        if ($datacachefilepath == '') {
            $datacachefilepath = getsetting('datacachepath', '/tmp');
        }
        if (@is_dir($datacachefilepath)) {
            $dir = dir($datacachefilepath);
            while (($file = $dir->read()) !== false) {
                if (strpos($file, $name) !== false) {
                    invalidatedatacache(str_replace(DATACACHE_FILENAME_PREFIX, '', $file));
                }
            }
            $dir->close();
        }
    }
}