function friendlist_unignore()
{
    global $session;
    $ac = httpget('ac');
    $ignored = rexplode(get_module_pref('ignored', 'friendlist', $ac));
    $iveignored = rexplode(get_module_pref('iveignored'));
    if (in_array($ac, $iveignored)) {
        $sql = "SELECT name FROM " . db_prefix("accounts") . " WHERE acctid={$ac} AND locked=0";
        $result = db_query($sql);
        if (db_num_rows($result) > 0) {
            $row = db_fetch_assoc($result);
            $info = sprintf_translate("%s`Q has been removed from your list.", $row['name']);
            require_once "lib/systemmail.php";
            $t = array("`\$Ignore List Removal");
            $mailmessage = array("%s`0`@ has removed you from %s ignore list.", $session['user']['name'], $session['user']['sex'] ? translate_inline("her") : translate_inline("his"));
            systemmail($ac, $t, $mailmessage);
        } else {
            $info = translate_inline("That user no longer exists...");
        }
    }
    $ignored = array_diff($ignored, array($session['user']['acctid']));
    $ignored = rimplode($ignored);
    set_module_pref('ignored', $ignored, 'friendlist', $ac);
    if (in_array($ac, $iveignored)) {
        $iveignored = array_diff($iveignored, array($ac));
        $iveignored = rimplode($iveignored);
        set_module_pref('iveignored', $iveignored);
    }
    output_notl($info);
}
function iitems_moduleprefs_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "iitems-use-item":
            if ($args['master']['modulepref'] && $args['master']['modulepref_module'] && $args['modulepref_type']) {
                $module = $args['master']['modulepref_module'];
                $pref = $args['master']['modulepref'];
                $val = $args['master']['modulepref_val'];
                if ($args['master']['modulepref_type'] == "increment") {
                    increment_module_pref($pref, $val, $module);
                } else {
                    if ($args['master']['modulepref_type'] == "set") {
                        set_module_pref($pref, $val, $module);
                    }
                }
            }
            break;
        case "iitems-superuser":
            output("`bIItems: Module Prefs`b`n");
            output("Alter module prefs upon use of the item.  Good for modules where items could be used, but which don't support IItems yet.`n");
            output("`bmodulepref`b - the name of the modulepref to alter.`n");
            output("`bmodulepref_module`b - the name of the module to which this pref belongs.`n");
            output("`bmodulepref_type`b - either \"increment\" or \"set\", for incrementing or setting moduleprefs.`n");
            output("`bmodulepref_val`b - the value to set or increment.`n");
            output("Example usage:`nmodulepref = availablestays | modulepref_module = inncoupons | modulepref_type = increment | modulepref_val = 5.  Gives the player five free stays at the Inn when this item is used.`n`n");
            break;
    }
    return $args;
}
function hepzibah_runevent($type)
{
    global $session;
    $from = "village.php?";
    // Since there is no interaction here, don't even set this
    //$session['user']['specialinc'] = "module:Hepzibah";
    $voucher = get_module_pref("voucher", "marquee");
    $city = $session['user']['location'];
    $op = httpget('op');
    // Since the text in both cases is mostly the same, make it common
    output("`7As you're walking around, admiring the sights, a wizened old woman approaches.`n`n");
    output("Her greying hair stands out in shock, and her nose is hooked and gnarled.");
    output("It takes all your willpower not to run away from this ghastly sight.`n`n");
    output("She smiles the most evil looking smile you have ever encountered.`n`n");
    output("`&\"Hello, warrior!");
    if (!is_module_installed("marquee") || $voucher) {
        output("Enjoying your visit?\"`n`n");
        output("`7Before you can answer, she has wandered off towards another tourist.`n`n");
        output("`7You shudder and head away quickly.`n`n");
    } elseif ($op == "" && !$voucher) {
        output("For you, a gift!\"`n`n");
        output("`7Before you can protest, she has grabbed your wrist, and placed a small voucher into your hand.");
        output("It reads, `Q\"One Free Pizza at the Marquee\".`n`n");
        output("`&\"Enjoy your stay in {$city}, warrior!\" `7she says, before wandering off towards another tourist.`n`n");
        set_module_pref("voucher", 1, "marquee");
    }
    // Since we never set the special inc, we don't need to unset it.
    //if ($op != "") {
    //    $session['user']['specialinc'] = "";
    //}
}
function wcgpoints_supporterpoints_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "wcgpoints_increased":
            if (get_module_pref("gotfirst")) {
                $session['user']['donation'] += 5;
                output("`5`bYou have five extra Supporter Points!`b  Thank you for contributing to humanitarian research.`0`n`n");
            } else {
                if (get_module_pref("runtime", "wcgpoints") > get_module_setting("initialrequirement")) {
                    $session['user']['donation'] += get_module_setting("initialreward");
                    require_once "lib/systemmail.php";
                    $subj = "You've got Supporter Points!";
                    $body = "As a thank-you for helping us to support humanitarian research via grid computing, we've given you 500 Supporter Points completely free of charge.  Thank you so much!  Remember that you'll get five extra Supporter Points every time your World Community Grid points increase (which is usually every 24 hours, if you let the client run regularly).  Have fun!";
                    systemmail($session['user']['acctid'], $subj, $body);
                    set_module_pref("gotfirst", true);
                }
            }
            break;
        case "wcg-features-desc":
            output("`bFree Supporter Points`b: After you've run the World Community Grid client for at least 24 hours (it doesn't have to be all at once - an hour here and an hour there will soon add up), you'll get 500 Supporter Points completely free of charge.  After that, you'll get 5 Supporter Points every time World Community Grid reports that your Cobblestones have increased.`n`n");
            break;
    }
    return $args;
}
function faqmute_dohook($hookname, $args)
{
    global $session;
    $seen = get_module_pref("seenfaq");
    switch ($hookname) {
        case "insertcomment":
            if (!$seen && !$session['user']['dragonkills']) {
                $args['mute'] = 1;
                $mutemsg = "`n`\$You have to read the FAQ before you can post comments. You can find it in any town.`0`n`n";
                $mutemsg = translate_inline($mutemsg);
                $args['mutemsg'] = $mutemsg;
            }
            break;
        case "faq-posttoc":
            if (!$seen) {
                set_module_pref("seenfaq", true);
            }
            break;
        case "bioinfo":
            $id = $args['acctid'];
            $seen = get_module_pref("seenfaq", false, $id);
            if (httpget("op") == "faqmute") {
                set_module_pref("seenfaq", false, false, $id);
                output("`nPlayer's FAQ seen status reset.`n");
            } elseif ($session['user']['superuser'] & SU_EDIT_COMMENTS && $seen && !$args['dragonkills']) {
                addnav("Mute Player Options");
                addnav("FAQmute player", "bio.php?char=" . $id . "&ret=" . rawurlencode(httpget("ret")) . "&op=faqmute");
            }
            break;
    }
    return $args;
}
function bioextension_dohook($hookname, $args)
{
    global $session;
    if ($hookname == "bioinfo") {
        $sql = "SELECT donation FROM " . db_prefix("accounts") . " WHERE acctid = '" . $args['acctid'] . "'";
        $result = db_query($sql);
        $row = db_fetch_assoc($result);
        if ($row['donation'] >= get_module_setting("threshhold")) {
            $bio = get_module_pref("user_extendedbio", "bioextension", $args['acctid']);
            $link = get_module_pref("user_extlink", "bioextension", $args['acctid']);
            $bio = str_replace(chr(13), "`n", $bio);
            $bio = stripslashes($bio);
            output("`0%s`n`n", $bio);
            if (substr($link, 0, 5) == "http:") {
                rawoutput("<a href=\"" . $link . "\">Player's webpage</a><br /><br />");
            }
        }
    } else {
        if ($hookname == "footer-prefs") {
            $bio = get_module_pref("user_extendedbio");
            $limit = get_module_setting("charlimit");
            if (strlen($bio) > $limit) {
                output("`c`4`bWARNING`b`0`c`nYour Extended Bio is oversized by %s characters.  If you navigate away from this page, your Extended Bio will have %s characters indiscriminately cut from the end.  Please edit and re-save your Extended Bio to avoid cuts.", strlen($bio) - $limit, strlen($bio) - $limit);
                $bio = substr($bio, 0, $limit);
                set_module_pref("user_extendedbio", $bio);
            }
        }
    }
    return $args;
}
function drunkard_runevent($type)
{
    global $session;
    require_once "lib/partner.php";
    $partner = get_partner();
    $chance = get_module_setting("spillchance");
    $roll = e_rand(1, 100);
    $seen = get_module_pref("seen");
    set_module_pref("seen", $seen + 1);
    output("`5A very drunk patron stumbles into you as you make your way across the crowded room.`n`n");
    if ($roll < $chance) {
        // He spills on you
        output("`5He is carrying a nearly full glass of ale.");
        output("As he collides with you, it spills all over your nearly clean clothes!");
        output("As you look up, you notice %s`5 watching you and become acutely embarrassed.", $partner);
        output("You notice %s`5 is trying to keep from laughing out loud at your mishap.", $partner);
        output("`n`n`&You `\$lose 1`& charm point.");
        if ($session['user']['charm'] > 0) {
            $session['user']['charm']--;
        }
    } else {
        // You're safe
        output("`5Fortunately his glass was already empty.");
        output("You escort him over to a chair where he can sit without running into everyone else.");
        output("As you stand up, you catch %s's`5 eye and receive a big smile for your kindness.", $partner);
        output("`n`n`&You gain `^1`& charm.");
        $session['user']['charm']++;
    }
}
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 nicotinegum_use($args)
{
    $addiction = get_module_pref("addiction", "smoking");
    $betweensmokes = 250 - $addiction;
    set_module_pref("betweensmokes", $betweensmokes, "smoking");
    apply_buff("smoking", array("allowinpvp" => 1, "allowintrain" => 1, "rounds" => -1, "schema" => "module-smoking"));
    return $args;
}
function donationreminder_run()
{
    global $session;
    page_header("Why hello there!");
    output("`0Hello!  My name's CavemanJoe, I'm the admin here at Improbable Island, and I think it's time you and I had a little chat.`n`nOr, you can just click Continue and carry on your merry way!`n`n...still here?`n`nHello?`n`nHello!`n`nSo.  You've downloaded over three thousand pages on Improbable Island!  That's an awful lot of clicking and keypresses!  I really hope you're having a good time.  You might be wondering why I'm interrupting your game like this, so I'll tell you.  There are a couple of reasons.`n`nFirstly - I'd like to hear from you!  We've got an active forum at http://enquirer.improbableisland.com, in which it'd be nice to hear any ideas or suggestions you might have.  Surely in your thousands of page loads you've found something that could be improved upon?`n`nSecondly, you haven't got any Supporter Points!`n`nYes, this is me saying \"stick a couple of bucks in the hat, will you?\" - yeah, you knew it was coming eventually - but I'm hoping to do it in a way that's at least interesting, and shows you a little bit about how running an online game actually works these days.`n`nImprobable Island is still pretty much a one-man show.  I have some awesome moderators who help me out with the day-to-day running of the game so that I can spend my days coding, but the design and programming of the game beyond its original (Legend of the Green Dragon 1.1.1) codebase is single-handed.  In 2009 I took the plunge, crossed my fingers, and quit my day job to work full-time on Improbable Island.`n`nIt's been pretty good so far.  It's meant taking a pay cut, but I'm happier and I get to do something that affects more people, so that's more than balanced out.`n`nStill, it's a demanding job.  I don't know if you've ever tried to make a game before, but if you have then you'll know how much of a pain in the bum it is trying to balance everything out so it's fair and challenging, never mind the actual programming, writing, artwork creation, layout, graphic design and so forth.  When you're talking about a game with several thousand participants, it gets even harder.`n`nIt's especially hard when you consider that if you want to make any sort of real money in online games, you've got to be a complete asshole.`n`nYou've got to splatter flashing banner ads and popups all over your pages.  You've got to set up cynical gameplay mechanics that are designed for nothing more than to keep people coming back (like growing virtual crops that you absolutely have to harvest between 8 and 10 pm tonight or they're wasted).  You've got to encourage your players to sign up for dodgy offers for free iPods.  You've got to charge money for absolutely everything you can, and you've got to make sure that the people with the most money are the people with the highest rankings in the game.  You've got to hit the psychological buttons discovered over decades of research into gaming and the marketing thereof; you've got to create rare items that people want not because they're useful, but because scarcity goes hand-in-hand with perceived value (`#there are only two `4Stinking Buckets of Dead Eels`# on the whole Island!  I've gotta get one!`0).  You've got to have a subscription option rather than one-time payments, because people forget to cancel their subscriptions.  You've got to spam your players' FaceBook pages with all sorts of meaningless drivel so that social obligation keeps them playing long after the game is no longer fun.  Your marketing has to be a cynical grab at the teenage boy market, enabled by the inclusion of preposterously large breasts in every banner ad.  You have to base your game around a pre-established theme, because coming up with new ideas costs time and money.  You have to create mindless, repetitive gameplay and then charge money for items that allow your players to skip over the boring parts.  You have to make your players compete with each other on parameters that they can influence with money, because some of them will go nuts trying to keep up with the Joneses.  You have to make awful, shallow games with the widest possible appeal to the lowest common denominator and attach enormous marketing and artwork budgets because everybody knows that pretty anime-themed games targeted at 17-25 year old males make shedloads of money, especially when you throw in some of the aforementioned preposterously large breasts.  With very few exceptions, you don't get rich in online games by making good games, or even by trying to be a decent bloke.`n`nYou certainly don't get rich by only advertising on webcomic sites that you personally enjoy.  You don't get rich by putting up enormous walls of text right at the start of your game to scare away people who don't enjoy reading.  You sure as hell don't get rich by only trying to attract and retain curious, intelligent, likeable players!  Of which you are clearly one, or you wouldn't have gotten this far!`n`n(see how I transparently flatter you into giving me money?  Hell, it's worth a shot)`n`nSetting up a distributed computing team and generating over a hundred years' worth of humanitarian research is cool, but it doesn't make you any money.  Giving the better part of six grand to Doctors Without Borders doesn't make you any money either (in fact it costs you money!  Who'd have thought it?).  Fair and balanced gameplay doesn't make you money - all the time you spend balancing your game is time you could be spending mining your players' data and habits for interesting tidbits you can sell to spammers and market researchers.  Games based on a post-EMP valve-and-relay future don't make any money - you should go with steampunk instead, it's very lucrative right now.`n`nIf you've got any sort of conscience, you'll end up whittling your options for making money down to two choices.  The first one is to make an excellent game and then not let anybody play it unless they pay you first.  The second one is to make the game free to play, and then after the player's passed a certain threshold, just go right ahead and ask them outright for some money.`n`nBut you should make it clear to them that nothing bad will happen if they don't donate.  It's important that the player reading the request knows that they're not being coerced into anything, and that the game isn't going to come to a grinding halt if they don't give you any money.  You can point out, if you're feeling manipulative, that their enjoyment has cost you money - which is technically true, but you've got to tell the whole truth.  Three thousand pages' worth of data transfer, database storage space and (most crucially) CPU cycles only works out to pennies since you spent all those nights optimizing the codebase, so it's kinda hard to guilt the player into giving you money that way.`n`nIf you want to ask a player for money, you should point out that just under three per cent of players who sign up make a donation at some point.  They're the ones who counter, in their five-and-ten-dollar donations, all the loose change that the non-donating players end up costing.  The player you're asking money from shouldn't feel that if they don't donate, nobody else will, or that if they don't donate, you'll be upset with them, because you won't - it's only pennies after all.`n`nYou should tell them that you're not rich, but that you're not starving either.  Be honest with them.  It's true that your donating players are your only source of income - but if the player you're talking to doesn't donate, then someone else will.`n`nSo, that's what I'm doing with you right now.  Asking you nicely for money using only the truth, rather than trying to lever it out of you via cheap trickery.  And the truth is that Improbable Island could be making a whole hell of a lot more money than it is right now - but it wouldn't be the same place.`n`nImprobable Island became the game that you enjoy today because its players give me just enough money to justify it as a day job.  If they had given me less money, then I'd need to attract more players, meaning I'd have to be less picky about the sort of people I advertise to.`n`nAnd if you're wondering what's in it for you, you should give me money because:`n1) Every time you or somebody else makes a donation, more Supply Crates are dropped on the World Map.`n2) You'll get 100 Supporter Points for every dollar you donate, with which you can get awesome things in the Hunter's Lodge.`n3) Every donation fills up the Extended Play bar a little bit more, and when it's full, everybody gets more Stamina (click on the coin slot to the bottom right to see where it's up to now).`n4) Every dollar you give to me is a one-fingered salute to the makers of FaceBook Friends Alienator, Annual Generic Football Game 2010 Endorsed by Some Guy, and The Free iPod Game.`n5) If you ever meet me in a pub, you'll have already bought me a pint.`n`nSo!  That's why you should donate some money towards Improbable Island's server costs, advertising budget, and my own costs of living.  And if you don't donate, then I hope this message was at least interesting to read.`n`nI'll return you to the game now.  Don't worry, this is a one-time message and nothing bad will happen if you don't donate.`n`nThanks,`n`n-Admin CavemanJoe`n`n");
    set_module_pref("seenmsg", 1, "donationreminder");
    addnav("Back to the game");
    addnav("Continue", "village.php");
    page_footer();
}
function letteropener_install()
{
    if (!is_module_active('letteropener')) {
        output("`2Installing Letter opener Module.`n");
        output("`b`4Be sure to set access for Admin and Moderators from User Settings!`b`n");
    }
    set_module_pref("letteraccess", 1, "letteropener");
    module_addhook("footer-popup");
    module_addhook("superuser");
    return true;
}
function achievements_award_medal($sname, $vname, $desc, $icon, $acctid = false)
{
    global $session;
    if (!$acctid) {
        $acctid = $session['user']['acctid'];
    }
    $ach = array("name" => $name, "desc" => $desc, "icon" => $icon);
    $info = unserialize(get_module_pref("achievements", "achievements"));
    $info[$sname] = array($ach);
    set_module_pref("achievements", serialize($info), "achievements", $acctid);
}
function reqmultiplier_change($new)
{
    global $session;
    $old = get_module_pref("multiplier", "reqmultiplier");
    if ($new >= $old) {
        set_module_pref("multiplier", $new, "reqmultiplier");
        return true;
    } else {
        return false;
    }
}
function monsterrepellentspray_use($args)
{
    global $session;
    if ($args['context'] == "fight") {
        apply_buff('rspray_fight', array("startmsg" => "`3You pull out a can of Monster Repellent Spray, and spray it liberally on the enemy!`n", "name" => "`^Repellent Spray Attack", "rounds" => 10, "badguyatkmod" => 0.4, "badguydefmod" => 0.4, "roundmsg" => "{badguy} is coughing, choking and all runny-nosed, and cannot attack or defend as effectively!", "wearoff" => "The effects of your Monster Repellent Spray seem to have worn off...`n", "expireafterfight" => 1, "schema" => "iitems-catcher"));
    } else {
        apply_buff('rspray_normal', array("name" => "`^Repellent Spray", "rounds" => -1, "badguyatkmod" => 0.8, "badguydefmod" => 0.8, "roundmsg" => "{badguy} can't stand the smell of your Monster Repellent Spray, and doesn't want to get too close!", "schema" => "iitems-catcher"));
        set_module_pref("encounterchance", 50, "worldmapen");
        output("You liberally douse yourself with an entire can of Monster Repellent Spray.  For the rest of this game day, your chances of encountering a monster on the Island Map have been halved, and monsters you do encounter will be reluctant to attack you as hard.`n`n");
    }
    return $args;
}
function biochat_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "bioend":
            require_once "lib/commentary.php";
            output("`n`n`0%s`0's Natter feed:`n", $args['name']);
            addcommentary();
            $section = "bio-" . $args['acctid'];
            viewcommentary($section, "Natter!", 25);
            if (!strpos(httpget('ret'), "bio.php")) {
                set_module_pref("lastplace", httpget('ret'));
            }
            $sql = "SELECT COUNT(commentid) AS totalcomments FROM " . db_prefix("commentary") . " WHERE section='{$section}'";
            $result = db_query($sql);
            $row = db_fetch_assoc($result);
            $all = $row['totalcomments'];
            set_module_pref("total", $all, "biochat", $args['acctid']);
            if ($args['acctid'] == $session['user']['acctid']) {
                //this is the player looking at his or her own bio
                set_module_pref("seen", $all);
            }
            $return = get_module_pref("lastplace");
            if ($return) {
                $return = substr($return, strrpos($return, "/") + 1);
                addnav("Been clicking around Bios and Nattering for a while?");
                addnav("Go `iright`i back to where you came from", $return);
            }
            debug($return);
            break;
        case "commentaryoptions":
            if (!strpos($_SERVER['REQUEST_URI'], "char=" . $session['user']['acctid'] . "&")) {
                $link = "bio.php?char=" . $session['user']['acctid'] . "&ret=" . URLEncode($_SERVER['REQUEST_URI']);
                $total = get_module_pref("total");
                $seen = get_module_pref("seen");
                output("<a href=\"{$link}\">View my Bio</a> ", true);
                if ($seen != $total) {
                    $new = $total - $seen;
                    if ($new == 1) {
                        output("(1 unread Natter) ");
                    } else {
                        output("(%s unread Natters) ", $new);
                    }
                }
                addnav("", $link);
            }
            break;
    }
    return $args;
}
function klutz_runevent($type)
{
    global $session;
    output("`7While you're minding your own business, a lady plows headlong into you.`n`n");
    output("`&\"Oh! Oh, I'm terribly sorry! I mustn't have been watching where I was going...\"`n`n");
    output("`7She scrambles on the ground, trying to collect all the things she has dropped.");
    output("You help her gather her belongings.`n`n");
    output("`^She is most grateful for your help!`n`n");
    if (get_module_pref("gotgem") == 0 && e_rand(1, 4) == 1) {
        output("`7As a thank you, she hands you a `5gem`7!");
        $session['user']['gems']++;
        set_module_pref("gotgem", 1);
    }
}
function hunterslodge_customrace_run()
{
    require_once "lib/sanitize.php";
    require_once "lib/names.php";
    global $session;
    $op = httpget("op");
    $free = httpget("free");
    page_header("Choose your Custom Race");
    switch ($op) {
        case "change":
            output("Want to change your Custom Race?  No problem.  Enter your desired race in the box below.  You've got 25 characters to play around with.`n(leave this blank to disable custom race naming and return to default, game-supplied race names)`n`n");
            rawoutput("<form action='runmodule.php?module=hunterslodge_customrace&op=confirm&free=" . $free . "' method='POST'>");
            $race = get_module_pref("customrace");
            rawoutput("<input id='input' name='newrace' 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_customrace&op=confirm&free=" . $free);
            addnav("Cancel");
            addnav("Don't set a custom race, just go back to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
        case "confirm":
            $newrace = httppost("newrace");
            $sub = httpget("sub");
            $newrace = str_replace("`", "", $newrace);
            $newrace = comment_sanitize($newrace);
            $newrace = substr($newrace, 0, 25);
            if ($newrace) {
                output("Your new custom race is:`n%s`nWould you like to set your new Race now?`n`n", $newrace);
            } else {
                output("You've chosen to go back to the default, game-supplied races.  Are you sure that's what you want?`n`n");
            }
            addnav("Confirm");
            addnav("Set custom race", "runmodule.php?module=hunterslodge_customrace&op=set&free={$free}&newrace=" . rawurlencode($newrace));
            addnav("Cancel");
            addnav("Don't set a custom race, just go back to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
        case "set":
            $newrace = rawurldecode(httpget("newrace"));
            output("Your custom race has been set to %s!`n`n", $newrace);
            set_module_pref("customrace", $newrace);
            if (!$free) {
                $id = has_item("hunterslodge_customrace");
                delete_item($id);
            }
            addnav("Return");
            addnav("Return to the Lodge", "runmodule.php?module=iitems_hunterslodge&op=start");
            break;
    }
    page_footer();
}
function defaultpreferences_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "newday":
            if (get_module_pref("hasbeenset") == 0) {
                $session['user']['prefs']['timestamp'] = 2;
                $session['user']['prefs']['emailonmail'] = 1;
                $session['user']['prefs']['systemmail'] = 1;
                set_module_pref("hasbeenset", 1);
            }
            break;
    }
    return $args;
}
function iitems_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "superuser":
            if (get_module_pref("superuser") == 1) {
                addnav("Item Editor", "runmodule.php?module=iitems&op=superuser&superop=start");
            }
            break;
        case "village":
        case "forest":
        case "worldnav":
            addnav("Inventory");
            addnav("Show Inventory", "runmodule.php?module=iitems&op=inventory&from=" . $hookname);
            break;
        case "fightnav-specialties":
            $script = $args['script'];
            iitems_show_fight_items($script);
            break;
        case "apply-specialties":
            if (httpget('skill') == "iitems") {
                $item = httpget('item');
                iitems_use_item($item, false, "fight");
            }
            break;
        case "dragonkill":
            $oldinventory = iitems_get_player_inventory();
            $newinventory = array();
            foreach ($oldinventory as $key => $vals) {
                $details = iitems_get_item_details($vals['itemid']);
                if ($details['dkpersist']) {
                    $newinventory[$key] = $vals;
                }
            }
            set_module_pref("items", serialize($newinventory), "iitems");
            break;
        case "newday":
            $use = iitems_has_property("useatnewday", 1, true, false, false, "all");
            debug($use);
            if (count($use) && is_array($use)) {
                foreach ($use as $item => $details) {
                    iitems_use_item($details['itemid'], false, $details['inventorylocation']);
                }
            }
            break;
    }
    return $args;
}
function medals_award_medal($sname, $vname, $desc, $icon, $awardtext = false, $acctid = false)
{
    global $session;
    if (!$acctid) {
        $acctid = $session['user']['acctid'];
    }
    $ach = array("name" => $vname, "desc" => $desc, "icon" => $icon);
    $info = unserialize(get_module_pref("medals", "medals"));
    if (!isset($info[$sname])) {
        $info[$sname] = $ach;
        if ($awardtext) {
            output_notl("`n%s`n`n", $awardtext);
        }
        set_module_pref("medals", serialize($info), "medals", $acctid);
    }
}
function extrarandom_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "choosebadguy":
            //If we've seen this creature before, choose a new one
            $pcreatures = @unserialize(get_module_pref("lastcreatures"));
            if (!is_array($pcreatures)) {
                $pcreatures = array();
            }
            if ($args['creatureid'] > 1) {
                global $attempts;
                if (in_array($args['creatureid'], $pcreatures)) {
                    if ($attempts < 3) {
                        //re-roll, getting a creature from the same level
                        debug("We've seen " . $args['creaturename'] . " too recently - switching monster");
                        $lvl = $args['creaturelevel'];
                        $id = $args['creatureid'];
                        if ($args['forest']) {
                            $sql = "SELECT * FROM " . db_prefix("creatures") . " WHERE creaturelevel = {$lvl} AND forest=1 AND creatureid != {$id} ORDER BY rand(" . e_rand() . ") LIMIT 1";
                        } else {
                            if ($args['graveyard']) {
                                $sql = "SELECT * FROM " . db_prefix("creatures") . " WHERE creaturelevel = {$lvl} AND forest=1 AND creatureid != {$id} ORDER BY rand(" . e_rand() . ") LIMIT 1";
                            }
                        }
                        $result = db_query($sql);
                        $args = db_fetch_assoc($result);
                        $attempts++;
                        $args = modulehook("choosebadguy", $args);
                    } else {
                        debug("Screw it!  Too many attempts!");
                    }
                }
                $pcreatures[] = $args['creatureid'];
                $count = count($pcreatures);
                $des = 8;
                if ($count > $des) {
                    for ($i = 0; $i < $count - $des; $i++) {
                        array_shift($pcreatures);
                    }
                }
                set_module_pref("lastcreatures", serialize($pcreatures));
            }
            break;
    }
    return $args;
}
function permanentaccount_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "iitems-use-item":
            if ($args['player']['itemid'] == "hunterslodge_permanentaccount") {
                if (get_module_pref("purchased")) {
                    $args['player']['usetext'] = "`c`b`4You already have a Permanent Account!`0`b`c`n";
                    $args['master']['destroyafteruse'] = 0;
                } else {
                    set_module_pref("purchased", 1);
                }
            }
            break;
    }
    return $args;
}
function rulesreminder_run()
{
    global $session;
    page_header("Site Rules");
    if (get_module_pref("seenrules") == 0) {
        set_module_pref("seenrules", 1);
        output("As you prepare to embark upon your newest adventure, a sombre-looking clown steps in front of you.  A little red name tag pinned to his chest says \"My name is MISTER NIPLOFF.  How can I help?\"  He is holding out a piece of paper in his left hand and a bag of rather soggy human nipples in his right.  Given the alternative, you take the piece of paper.`n`n");
        addnav("I couldn't agree more, Mister Niploff.  Please don't steal my nipples.", "forest.php");
    }
    if (get_module_pref("reminduser") == 1) {
        set_module_pref("reminduser", 0);
        output("As you prepare to embark upon your latest adventure, a sad-faced clown steps in front of you.  You recognise him as Mister Niploff, the sombre old soul who introduced you to the Game Rules.  But why is he here again?`n`nHe looks even more sombre than usual.  He reaches into his pocket and pulls out a large pair of scissors, which he prods gently against your chest.`n`n`bClearly he thinks you need a quick reminder about the rules!`b`n`nGiving you a pleading look, he pulls out his familiar piece of paper and offers it to you once again.`n`n");
        addnav("I understand, Mister Niploff.  I promise to be good in future.  Please don't steal my nipples.", "forest.php");
    }
    output("It reads:`4`n`n`nOn Improbable Island, there are just two rules.  One is designed to make the game more fun for everyone, and the other is designed to make the game more fun for you.  Here they are:`n`n`n1. `bDon't be a dick`b.`nI don't think we really need to clarify what a dick is, because people who need that sort of clarification are probably dicks.  But for the avoidance of doubt, \"don't be a dick\" also encompasses \"don't talk like a dick,\" which is to say omfg pls dont talk liek dis bcos it makes u look liek a dick lol.`n`n2. `bDon't take it seriously`b.`nImprobable Island is only a computer game.  Furthermore, it's a light-hearted and irreverent computer game played over the Internet.  The Internet, as you well know, is composed nearly entirely out of LOLCats and p**n.  So, of course, treating Improbable Island as `iSerious Business`i is a rather silly thing to do.  If you take the game too seriously, you won't enjoy it as much, and drama of the non-fun variety is a likely result.`nThis one is a little bit more complex, so I'll give some examples.`nExample 1: Someone PVP's you, and you go on a huge rant about it while refusing to turn off PVP (yes, you can opt-out of PVP).  This is pretty well the same as knocking the chess board off the table in the pub 'cause someone beat you.  The Admin steps in and bitch-slaps you for taking the game too seriously.`nExample 2: Someone makes a joke about a subject tangentially related to something you hold dear to your heart.  You immediately leap in with a rally cry of \"OMG TAHT'S NOT FUNNY YOU'RE WORSE THAN HITLER.\"  The Admin deletes your comments, then steps in and bitch-slaps you for taking the game too seriously.`nExample 3: The admin makes a slight change to the game mechanics, in an attempt to balance things out.  You send him a Distraction saying \"You've ruined the game!  All my hard work for nothing.\"  The Admin laughs at you for equating hard work with playing a computer game, and then steps in and bitch-slaps you for taking the game too seriously.  Then he twiddles his moustache and laughs some more.`n(Note that feedback about the game is encouraged, but if it contains the phrase \"hard work\" in relation to game-playing activity, it will immediately become a target of Admin Mockery regardless of its merit or lack thereof.)`n`n`nThere are also some technical rules that you should know about, although these don't relate to social interaction, or relate only tangentially.`n`n1. `bNo alts`b.`nAn alt is an account that a player creates in order to transfer resources between the alt and the player's main character.  This is cheating, and gives you an advantage over other players that can only be matched by them doing the same thing.  Thus, the game turns into a meaningless exercise in who has the most spare time and the least life outside of the Island.  That's not a game that anyone wants to win.`nUsage of alts for non-cheaty, prank-related purposes is okay.  In fact, this is actively encouraged.`n`n2. `bIf you find an exploit, tell the Admin.`b`nAn exploit is a bug in the game that allows you to gain an advantage over other players.  For example, you might find a way to keep large amounts of Requisition between DK's, or you might find a way to gain more of one resource without expending, or taking the risk of expending, any other resource (such as turns or hitpoints).  If you find one, exploit it, and it goes unnoticed, then the game becomes unbalanced, which can sometimes take a long time to fix.  Please report any and all loopholes and cheaty things to the Admin, using the Petition link.`n`n`nThanks for reading the rules, and have a pleasant stay!");
    page_footer();
}
function emilybundle_run()
{
    global $session;
    $op = httpget("op");
    page_header("The Emily Bundle");
    $cost = get_module_setting("cost");
    $stock = get_module_setting("stock");
    $playerpoints = $session['user']['donation'] - $session['user']['donationspent'];
    switch ($op) {
        case "start":
            output("So, Improbable Island has been going for a couple of years now and it's turning into something that can keep me alive and with a roof over my head without me having to do website design.  It's turned from a hobby into a full-time job.`n`nSince then, I've gotten married, and my wife, Emily(*), has gotten increasingly frustrated with her job.  She does database work for a hospital; the pay's good, but the hours and the work itself is pretty depressing.`n`nI've noticed lately that my original goal - \"Hey, I'll write a text adventure game!\" - hasn't quite worked out the way I wanted it to, because I thought it'd be about writing.  I figured I'd have a plot, decent characters, a beginning, middle and end - you know, a story.  But lately I've been doing a lot more building of games and systems than I have building of worlds, and I'm beginning to realise that that's what I'm good at.`n`nThe Island needs a writer.`n`nA dedicated writer, so that I can be a dedicated coder.  Recently I've done all sorts of stuff with Titans, Onslaught, new Commentary, Dwellings, and all that jazz - but the last actual piece of world-building writing that I did was in Common Ground, with its time-sensitive description text.  I believe that was before Christmas.`n`nOh, and there were some lions, too.`n`nTo give you an idea of where I am right now, let's say this: the system is in place to extend that level of time-and-context-sensitive detail to every Outpost.  I just don't have any writing to go in the system.`n`nIt's not that I don't like writing, and forgive me for parping my own horn but I don't think it's that I'm not good at it (although that sentence may have been evidence to the contrary).  It's just that I have so much else to do.`n`nI need help.`n`nHey, you know... my wife is an excellent writer.`n`nHonestly I'd be doing this before too long even if I didn't need Emily to help me with the Island.  She hates her job, I love mine, and that's unfair; it's imperative that the Island support both of us if we ever want to have our own house, or raise a family.`n`nWe've done our maths and figured out how much we need per month on which to survive without Emily's workplace sorting out our health insurance (that's the biggest expense, right there), and from that, based on historical data, we've figured out how much of an advertisement boost we'd need to get the Island up to that sort of level, and from that, how much money we'd need to get together by 'x' if we want Emily to be able to quit her job by 'y', with 'y' being \"Before September.\"`n`nIn a nutshell we need to get some bread together so that we can expand our player base enough that casual everyday donations cover us both without me having to tell you all about it every time my laptop breaks, my car breaks down, or my lion gets into an argument he just can't win.`n`nSo, you can give me money so that the Island can have more juicy plot points and a better sense of place, or you can give me money so that Emily and I can be happier and spend more time together.  Both are excellent reasons.  I've got another reason for you:`n`nIntroducing the `5Emily Bundle`0!`n`nThe `5Emily Bundle`0 costs 2,500 Donator Points, and it's worth well over three times as much.  In the Emily Bundle for 2,500 Donator Points (that's twenty-five bucks, for those of you keeping track), you get:`n`n* Permanent, unlimited free Avatar picture changes (never pay to change your Avatar picture again!)`n* Permanent, unlimited free Custom Weapon changes (custom weaponry now sticks around properly!)`n* Permanent, unlimited free Custom Armour changes (likewise!)`n* Permanent, unlimited free Custom Name Colour changes`n* Permanent, inlimited free Title changes`n* Permanent, unlimited free Mount Name changes`n* Permanent, unlimited free Commentary Race Name changes`n* Ten cigarettes`n* Ten thousand Requisition tokens`n* Two extra Chronospheres`n* All your current Chronospheres refilled`n* Ten Special Comments`n* A special, strictly-limited-and-not-to-be-repeated Medal`n`nAnd if you've not already donated, you'll also get room for a ten-thousand character Extended Bio (players who've already donated already have this).`n`nNow, the Emily Bundle is limited to two hundred players.  That should give Emily and I enough of a financial boost to get this plan underway.  If something stupidly awesome happens like the whole stock running out in a day, then I might add another fifty or a hundred or so, but no more than that (I'm not going to say it's strictly limited just to stimulate demand and then make it as common as muck - I want this to be a bit special).`n`nSo, help us recruit a writer and make the Island more awesome, more quickly - grab the Emily Bundle while it's still around to grab!`n(*) Yes, I named the pickle-wench barmaid after my wife.  Looking back, I could have made a better choice for an homage.");
            addnav("Buy the Emily Bundle!");
            if ($playerpoints >= $cost) {
                addnav("Yes! (2,500 points)", "runmodule.php?module=emilybundle&op=buy");
            } else {
                addnav(array("Just %s more points!", $cost - $playerpoints), "");
            }
            break;
        case "buy":
            set_module_pref("permanent", true, "commentaryicons_customrace");
            set_module_pref("permanent", true, "titlechange");
            set_module_pref("permanent", true, "namedmount");
            set_module_pref("permanent", true, "namecolor");
            set_module_pref("permanent", true, "avatar");
            set_module_pref("permanentarmor", true, "customeq");
            set_module_pref("permanentweapon", true, "customeq");
            $session['user']['gems'] += 10;
            $session['user']['goldinbank'] += 10000;
            $curspheres = get_module_pref("slots", "daysave");
            set_module_pref("slots", $curspheres + 2, "daysave");
            set_module_pref("days", $curspheres + 2, "daysave");
            increment_module_pref("commentsleft", 10, "specialcomments");
            require_once "modules/medals.php";
            medals_award_medal("emilybundle", "Emily Bundle Supporter", "This player bought the Emily Bundle, supporting Improbable Island and its admin!", "medal_emilybundle.png");
            $session['user']['donationspent'] += $cost;
            increment_module_setting("stock", -1);
            set_module_pref("bought", 1);
            output("You've got the Emily Bundle!  Thank you so much for supporting the Island.  Have fun!`n`n");
            //todo: medal, take points, diminish stock, output thankyou
            break;
    }
    addnav("Return");
    addnav("L?Return to the Lodge", "lodge.php");
    page_footer();
}
function scry_run()
{
    global $session;
    addcommentary();
    $area = httpget("area");
    $village = httpget("village");
    $op = httpget("op");
    $cost = $session['user']['level'] * get_module_setting("cost");
    if ($op == "pay") {
        if ($session['user']['gold'] >= $cost) {
            $session['user']['gold'] -= $cost;
            set_module_pref("talks", 0);
            set_module_pref("speaking", 1);
            debuglog("spent {$cost} gold to scry a remote village");
            redirect("runmodule.php?module=scry&op=talk&area=" . htmlentities($area, ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "&village=" . htmlentities($village, ENT_COMPAT, getsetting("charset", "ISO-8859-1")));
            page_footer();
        } else {
            page_header("Gypsy Seer's tent");
            villagenav();
            addnav("Continue looking around", "gypsy.php");
            output("`5You offer the old gypsy woman your `^%s`5 gold for her scrying services, but she informs you that such a pittance is far too little.", $session['user']['gold']);
            page_footer();
        }
    } elseif ($op == "talk") {
        $times = get_module_setting("uses");
        if ($times && get_module_pref("talks") >= $times) {
            page_header("Gypsy Seer's tent");
            output("`5Looking around dazedly, it takes you a moment to realize that you are no longer viewing the village of %s and that the gypsy woman is staring at you with her hand out.", $village);
            output("`5\"`!I'll need more gold if you want to keep taking up space for my other paying customers!`5\", she demands.`n`n");
            output("You start to demand, \"`&What other customers?`5\" but decide that it's best not to annoy someone who has such power.");
            addnav(array("Scrying (%s gold)", $cost));
            addnav(array("Scry %s", $village), "runmodule.php?module=scry&op=pay&area=" . htmlentities($area, ENT_COMPAT, getsetting("charset", "ISO-8859-1")) . "&village=" . htmlentities($village, ENT_COMPAT, getsetting("charset", "ISO-8859-1")));
            addnav("Other");
            addnav("Return to the tent", "gypsy.php");
            villagenav();
            page_footer();
        } else {
            page_header("Peering in the bowl, you view %s", $village);
            output("`5While staring into the inky water, you are able to make out the people of %s:`n", $village);
            commentdisplay("", $area, "Project", 25, "projects");
            addnav("Look up from the bowl", "gypsy.php");
            page_footer();
        }
    }
}
function clanbuffs_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "footer-hof":
            if (get_module_setting("hof")) {
                addnav("Warrior Rankings");
                addnav("Clan Buffs", "runmodule.php?module=clanbuffs&op=hof");
            }
            break;
        case "footer-clan":
            if ($session['user']['clanid'] != 0 and httpget("op") == "") {
                if ($session['user']['clanrank'] > 0) {
                    addnav("Clan Buffs", "runmodule.php?module=clanbuffs&op=enter");
                }
            }
            break;
        case "village":
        case "forest":
        case "clanhall":
            if (get_module_pref("refreshbuff")) {
                set_module_pref("refreshbuff", 0);
                include_once "modules/clanbuffs/clanbuffs_func.php";
                apply_clan_buff_for_one();
                output("`n`n`c`b`!Your clan's aura has been upgraded and refreshed!`0`b`c`n`n");
            }
            break;
        case "newday":
            if ($session['user']['clanid'] != 0 && $session['user']['clanrank'] > 0) {
                if (get_module_objpref("clans", $session['user']['clanid'], "buffactive") == 1) {
                    include_once "modules/clanbuffs/clanbuffs_func.php";
                    apply_clan_buff_for_one();
                    output("`n`^Your clan's aura protects you!`n");
                }
            }
            break;
        case "changesetting":
            if ($args['setting'] == "remakecost" && $args['module'] == "clanbuffs") {
                include_once "modules/clanbuffs/clanbuffs_func.php";
                remake_costs();
            }
            break;
    }
    return $args;
}
function human_loot_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "newday":
            if ($session['user']['race'] == "Human") {
                set_module_pref("itemstaken", 0);
                output("`0As a Human, you can obtain certain basic items free of charge from the Council Offices in NewHome.  There's some stuff there waiting for you now.`n`n");
            }
            break;
        case "counciloffices":
            if ($session['user']['location'] == "NewHome" && $session['user']['race'] == "Human" && get_module_pref("itemstaken") < 3) {
                addnav("Claim your Free Stuff", "runmodule.php?module=human_loot");
            }
            break;
    }
    return $args;
}
function applebob_dohook($hook, $args)
{
    switch ($hook) {
        case "newday":
            set_module_pref('ate_today', 0);
            break;
        case "village":
            global $session;
            if ($session['user']['location'] == get_module_setting('location')) {
                tlschema($args['schemas']['marketnav']);
                addnav($args['marketnav']);
                tlschema();
                addnav('A?Sichae\'s Apple Bobbing', 'runmodule.php?module=applebob');
            }
            break;
    }
    return $args;
}
function scrapbots_run()
{
    global $session;
    page_header("ScrapBots testing");
    if ($session['user']['alive'] == 0) {
        addnav("Daily News", "news.php");
        page_footer();
        break;
    } else {
        addnav("Scavenge");
        addnav("Scavenge x 1", "runmodule.php?module=scrapbots&scavenge=1");
        addnav("Scavenge x 10", "runmodule.php?module=scrapbots&scavenge=10");
        addnav("Village", "village.php");
        addnav("Search for an Opponent", "runmodule.php?module=scrapbots&op=findopponent");
        require_once "modules/scrapbots/lib.php";
        $op = httpget('op');
        if ($op) {
            include "scrapbots/run/case_{$op}.php";
        }
        if (httpget('reset') == 1) {
            set_module_pref("scrap", 0);
        }
        if (httpget('scavenge') == 1) {
            scrapbots_scavenge();
            output("`n`n");
        }
        if (httpget('scavenge') == 10) {
            scrapbots_scavenge(10);
            output("`n`n");
        }
        if (httpget('testfight') == 1) {
            require_once "modules/scrapbots/battle-2.php";
            scrapbots_battle(96);
        }
        scrapbots_list_player_scrap();
        scrapbots_list_combinations();
        scrapbots_list_scrapbots();
        scrapbots_list_requirements();
        addnav("Debug");
        addnav("Clear Scrap array", "runmodule.php?module=scrapbots&reset=1");
        addnav("Fight against playerid 96", "runmodule.php?module=scrapbots&testfight=1");
    }
    page_footer();
}
function peerpressure_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "newday":
            $dayspast = get_module_pref("dayspast");
            $dayspast++;
            set_module_pref("dayspast", $session['user']['level'] == 15 ? $dayspast : 0);
            break;
        case "battle-defeat":
            // If they have a special inc set for the dragon and they just
            // lost, reset it so they don't keep coming back here!
            global $options;
            if ($session['user']['specialinc'] == "module:peerpressure" && $options['type'] == "dragon") {
                $session['user']['specialinc'] = "";
            }
            break;
    }
    return $args;
}