function newdaybar_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "charstats":
            require_once "lib/datetime.php";
            $gt = gametimedetails();
            setcharstat("Time", "Game Time", gmdate("g:i a", $gt['gametime']));
            setcharstat("Time", "New day in:", date("H:i:s", secondstonextgameday()));
            break;
    }
    return $args;
}
function timeandweather_getcurrent()
{
    global $session;
    require_once "lib/datetime.php";
    $tdet = gametimedetails();
    $now = $tdet['secssofartoday'];
    //debug ($now);
    timeandweather_update();
    $ret = array();
    $ret['time'] = $now;
    //get coarse timezone
    switch ($now) {
        case $now > 79200:
        case $now < 14400:
            //night
            $zone = 7;
            break;
        case $now > 77400:
            //dusk
            $zone = 6;
            break;
        case $now > 75600:
            //sunset
            $zone = 5;
            break;
        case $now > 43200:
            //afternoon
            $zone = 4;
            break;
        case $now > 18000:
            //morning
            $zone = 3;
            break;
        case $now > 16200:
            //sunrise
            $zone = 2;
            break;
        case $now > 14400:
            //dawn
            $zone = 1;
            break;
    }
    $ret['timezone'] = $zone;
    $ret['weather'] = get_module_setting("currentweather", "timeandweather");
    $change = get_module_setting("lastweather", "timeandweather") - get_module_setting("currentweather", "timeandweather");
    $ret['change'] = $change;
    //debug($ret);
    return $ret;
}
function commontimetext_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "gardentext":
            global $outdoors, $shady, $brightness, $rainy, $override_weather;
            $shady = true;
            $outdoors = true;
            $rainy = false;
            $override_weather = true;
            $td = gametimedetails();
            $gt = $td['secssofartoday'];
            // Time designations:
            // 4am-12pm = morning
            // 12pm-7pm = afternoon
            // 7pm-9pm = dusk
            // 9pm-4am = night
            if ($gt < 14400 || $gt > 75601) {
                //between 9pm and 4am, nighttime
                $brightness = "darkest";
                $args['text'] = "It is nighttime, but Common Ground is bright and lively.  Hundreds of tiny candle flames from the carnivorous Witchblooms cast a soft, warm light on human skin, a glossy sheen over KittyMorph fur, hard little gleaming flashes over Robot glass.  Every now and then a moth or a mosquito will fly too close to a flame, and its tiny remains will fall into the petals as the Witchbloom's victual.`n`n";
            } else {
                if ($gt > 14401 & $gt < 43200) {
                    //4am to 12pm, morning
                    //$brightness = "lighter";
                    $args['text'] = "It is morning on Common Ground.  Sleeping Midgets lie around the area - when they awaken, they'll wonder why their empty beer cans have gone missing even as their hangovers remain.  The grass is always just the right length, the flowerbeds always just wild enough to be alive, the trees always just tall enough to provide shade but not leafy enough to blot out the sun.  Nobody has figured out how this happens - maybe there's some grumbling old parkie who comes around and tidies up the place when nobody's looking, or perhaps folks absently pick up here and there without really realising it, or it could even be that Common Ground keeps things pleasant all by itself.`n`n";
                } else {
                    if ($gt > 43201 & $gt < 68400) {
                        //12pm to 7pm, afternoon
                        //$brightness = "lighter";
                        $args['text'] = "It is afternoon on Common Ground.  The air here somehow always has the clear, bright quality that you find on summer afternoons after rainy mornings.  The forest canopy sets soft shadows swaying as trees rustle in warm breeze.  KittyMorphs lie around chatting, as close to nude as manners permit.  Nearby, Midgets leer at the sight and then deny doing so to their friends.  To one end of Common Ground a wounded Robot stands in the sunlight, charging her solar cell as the cracks in her glass skin slowly shorten and disappear with little high-pitched clinking sounds.  Her eyes are dark - she's as close to asleep as Robots ever come.`n`n";
                    } else {
                        if ($gt > 68401 && $gt < 75600) {
                            //7pm to 9pm, dusk
                            $brightness = "darker";
                            $args['text'] = "It is dusk on Common Ground.  The air is cool and sharp, the grass almost damp.  If you listen carefully, you can hear the tiny clicks and snaps of the carnivorous Witchblooms as they struggle bravely against their own absurdity.  If they're lucky, they will generate enough of a spark to ignite their tiny candlelike flames, luring moths and other nocturnal insects to their sticky petals.  If they're unlucky, they will try again tomorrow night, lacking the common sense to die as such a ludicrous plant surely must.  A nearby Mutant, knowing a comrade when he sees one, appears to be composing a poem.  You move on quickly before he tries to show it to you.`n`n";
                        }
                    }
                }
            }
            $args['text'] .= "Not all of the Improbability Drive's creations are threatening.  Common Ground is a convenient and rather beautiful fold in space and time, distorting our accepted reality and giving us convenience and heightened diplomacy in return.  The gardens of Common Ground have entrances from every Outpost, but contestants can only leave to the Outpost from which they arrived.  Battles and disputes over ownership are pointless.  Violence, oddly enough, just doesn't work - knives go missing from holsters, gunpowder mysteriously fails to flash, heads somehow tend not to be in the right place when clubs swing for them.  It is a peaceful place.`n`n";
            break;
    }
    return $args;
}
function secondstonextgameday($details = false) : int
{
    if ($details === false) {
        $details = gametimedetails();
    }
    return strtotime("{$details['now']} + {$details['realsecstotomorrow']} seconds");
}
function pub_newpittsburgh_run()
{
    global $session;
    $td = gametimedetails();
    $gt = $td['secssofartoday'];
    //8400 seconds in a day
    //3600 seconds in an hour
    //midnight: 0
    //1am: 3600
    //2am: 7200
    //3am: 10800
    //4am: 14400
    //5am: 18000
    //6am: 21600
    //7am: 25200
    //8am: 28800
    //9am: 32400
    //10am: 36000
    //11am: 39600
    //12pm midday: 43200
    //1pm: 46800
    //2pm: 50400
    //3pm: 54000
    //4pm: 57600
    //5pm: 61200
    //6pm: 64800
    //7pm: 68400
    //8pm: 72000
    //9pm: 75600
    //10pm: 79200
    //11pm: 82800
    //11:59:59: 86399
    //midnight: 0
    page_header("Vigour Mortis");
    $op = httpget("op");
    switch ($op) {
        case "start":
            rawoutput("<table cellpadding=0 cellspacing=0><tr><td><img src='images/pubsigns/newpittsburgh.png' align='left'>");
            $phrases = array(1 => "From the corner, the pub quiz appears to have recently finished, and the quizmaster is reading out the answers - Question 1: Brains. Question 2: BRAINS!, Question 3: BRAAAAINS.", 2 => "George stares at the television, static reflected in his cold, dead eyes.", 3 => "George turns to the bar and takes stock of his inventory of pickled brainstuffs.");
            $chosenphrase = array_rand($phrases);
            output("You walk through a broken door and pick your way over shattered glass to a battered sideboard.  Around you, a number of congenial zombies shuffle in various directions, groaning and mumbling to one another.  The air is thick with the smell of rotting flesh and dust, and congealing blood stains many a tabletop.  A number of zombies cluster around a ridiculously small CRT television, which is displaying static.  The bartender, George, seems to be discussing the relative merits of brains with a local.`n`n");
            output_notl("%s`n`n", $phrases[$chosenphrase]);
            rawoutput("</td></tr></table>");
            require_once "lib/commentary.php";
            addcommentary();
            viewcommentary("pub_newpittsburgh");
            addnav("Talk to people");
            addnav("George", "runmodule.php?module=pub_newpittsburgh&op=bartender");
            modulehook("pub_newpittsburgh");
            break;
        case "continue":
            rawoutput("<table cellpadding=0 cellspacing=0><tr><td><img src='images/pubsigns/newpittsburgh.png' align='left'>");
            output("You rejoin your fellows at the cluttered tables.`n`n");
            rawoutput("</td></tr></table>");
            require_once "lib/commentary.php";
            addcommentary();
            viewcommentary("pub_newpittsburgh");
            addnav("Talk to people");
            addnav("George", "runmodule.php?module=pub_newpittsburgh&op=bartender");
            modulehook("pub_newpittsburgh");
            break;
        case "bartender":
            //add a text parser here at some point, I think...
            //maybe make this opening text time-dependent?
            $text = array();
            $text['hello'] = "George shambles over with a grimace.  \"`2Yes, mate.  What'll it be?`0\"`n`n";
            $drinks = array();
            $hook = array();
            $hook['drinks'] = $drinks;
            $hook['text'] = $text;
            $hook = modulehook("pub_newpittsburgh_bartender", $hook);
            $text = $hook['text'];
            //debug($hook);
            $drinks = $hook['drinks'];
            output_notl($text['hello']);
            foreach ($drinks as $key => $vals) {
                addnav("What'll it be?");
                if (!$vals['blockdrink']) {
                    if ($session['user']['gold'] >= $vals['price']) {
                        addnav(array("%s (%s Req)", $vals['verbosename'], $vals['price']), "runmodule.php?module=pub_newpittsburgh&op=drink&drink=" . $key);
                    } else {
                        addnav(array("%s (%s Req)", $vals['verbosename'], $vals['price']), "");
                    }
                }
            }
            if (!$hook['blockreturnnav']) {
                addnav("Never mind");
                addnav("Return to the lounge", "runmodule.php?module=pub_newpittsburgh&op=continue");
            }
            break;
        case "drink":
            $hook = array("drink" => httpget("drink"));
            $hook = modulehook("pub_newpittsburgh_drink", $hook);
            if (!$hook['blockbarnav']) {
                addnav("More!");
                addnav("Get George's attention again", "runmodule.php?module=pub_newpittsburgh&op=bartender");
            }
            if (!$hook['blockreturnnav']) {
                addnav("That's enough");
                addnav("Return to the lounge", "runmodule.php?module=pub_newpittsburgh&op=continue");
            }
            break;
    }
    addnav("Leave");
    addnav("Back to New Pittsburgh", "village.php");
    page_footer();
}
function daysave_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "newday":
            $days = get_module_pref("days");
            $slots = get_module_pref("slots");
            $lastonnextday = get_module_pref("lastlognewday");
            $time = gametimedetails();
            //debug("time:". $time['gametime']);
            $timediff = $time['gametime'] - $lastonnextday;
            //debug("timediff: $timediff");
            if ($timediff > 86400) {
                $addition = floor($timediff / 86400);
                $days += $addition;
                if ($days > $slots) {
                    $days = $slots;
                }
                if ($lastonnextday < 1) {
                    $days = 0;
                }
                set_module_pref("days", $days);
            }
            set_module_pref("lastlognewday", $time['tomorrow']);
            break;
        case "newday-runonce":
            //reset all players' Instant Buys counter
            // $sql = "SELECT acctid FROM " . db_prefix("accounts");
            // $result = db_query($sql);
            // for ($i=0;$i<db_num_rows($result);$i++){
            // $row = db_fetch_assoc($result);
            // clear_module_pref("instantbuys",false,$row['acctid']);
            // }
            break;
        case "player-logout":
            $details = gametimedetails();
            set_module_pref("lastlognewday", $details['tomorrow']);
            break;
        case "village":
            tlschema('daysavenav');
            addnav("Saved Days");
            addnav("New Day Menu", "runmodule.php?module=daysave&op=start&return=village");
            break;
        case "shades":
            tlschema('daysavenav');
            addnav("Saved Days");
            if (!$session['user']['resurrections'] && !$session['user']['dragonkills'] && get_module_pref("days")) {
                output("`JAdvice for new players: if you try to fight your way back to the Island and fail, then have a look at the New Day Menu.`0`n`n");
                addnav("`JNew Day Menu", "runmodule.php?module=daysave&op=start&return=shades");
            } else {
                addnav("New Day Menu", "runmodule.php?module=daysave&op=start&return=shades");
            }
            break;
        case "worldnav":
            tlschema('daysavenav');
            addnav("Saved Days");
            addnav("New Day Menu", "runmodule.php?module=daysave&op=start&return=worldmapen");
            break;
    }
    return $args;
}
page_header("Game Settings");
require_once "lib/superusernav.php";
superusernav();
addnav("Module Manager", "modules.php");
if ($module) {
    $cat = $info['category'];
    addnav(array("Module Category - `^%s`0", translate_inline($cat)), "modules.php?cat={$cat}");
}
addnav("Game Settings");
addnav("Standard settings", "configuration.php");
addnav("", $REQUEST_URI);
module_editor_navs('settings', 'configuration.php?op=modulesettings&module=');
if ($op == "") {
    $enum = "enumpretrans";
    require_once "lib/datetime.php";
    $details = gametimedetails();
    $offset = getsetting("gameoffsetseconds", 0);
    for ($i = 0; $i <= 86400 / getsetting("daysperday", 4); $i += 300) {
        $off = $details['realsecstotomorrow'] - ($offset - $i);
        if ($off < 0) {
            $off += 86400;
        }
        $x = strtotime("+" . $off . " secs");
        $str = sprintf_translate("In %s at %s (+%s)", reltime($x), date("h:i a", $x), date("H:i", $i));
        $enum .= ",{$i},{$str}";
    }
    rawoutput(tlbutton_clear());
    $setup = array("Game Setup,title", "loginbanner" => "Login Banner (under login prompt: 255 chars)", "maxonline" => "Max # of players online (0 for unlimited), int", "allowcreation" => "Allow creation of new characters,bool", "gameadminemail" => "Admin Email", "emailpetitions" => "Should submitted petitions be emailed to Admin Email address?,bool", "Enter languages here like this: `i(shortname 2 chars) comma (readable name of the language)`i and continue as long as you wish,note", "serverlanguages" => "Languages available on this server", "defaultlanguage" => "Default Language,enum," . getsetting("serverlanguages", "en,English,fr,Français,dk,Danish,de,Deutsch,es,Español,it,Italian"), "edittitles" => "Should DK titles be editable in user editor,bool", "motditems" => "How many items should be shown on the motdlist,int", "Main Page Display,title", "homeskinselect" => "Should the skin selection widget be shown?,bool", "homecurtime" => "Should the current realm time be shown?,bool", "homenewdaytime" => "Should the time till newday be shown?,bool", "homenewestplayer" => "Should the newest player be shown?,bool", "defaultskin" => "What skin should be the default?,theme", "impressum" => "Tell the world something about the person running this server. (e.g. name and address),textarea", "Beta Setup,title", "beta" => "Enable beta features for all players?,bool", "betaperplayer" => "Enable beta features per player?,bool", "Account Creation,title", "defaultsuperuser" => "Flags automatically granted to new players,bitfield," . ($session['user']['superuser'] | SU_ANYONE_CAN_SET) . " ," . SU_INFINITE_DAYS . ",Infinite Days," . SU_VIEW_SOURCE . ",View Source Code," . SU_DEVELOPER . ",Developer Super Powers (special inc list; god mode; auto defeat master; etc)," . SU_DEBUG_OUTPUT . ",Debug Output", "newplayerstartgold" => "Amount of gold to start a new character with,int", "maxrestartgold" => "Maximum amount of gold a player will get after a dragonkill,int", "maxrestartgems" => "Maximum number of gems a player will get after a dragonkill,int", "requireemail" => "Require users to enter their email address,bool", "requirevalidemail" => "Require users to validate their email address,bool", "blockdupeemail" => "One account per email address,bool", "spaceinname" => "Allow spaces in user names,bool", "allowoddadminrenames" => "Allow admins to enter 'illegal' names in the user editor,bool", "selfdelete" => "Allow player to delete their character,bool", "Commentary/Chat,title", "soap" => "Clean user posts (filters bad language and splits words over 45 chars long),bool", "maxcolors" => "Max # of color changes usable in one comment,range,5,40,1", "postinglimit" => "Limit posts to let one user post only up to 50% of the last posts (else turn it off),bool", "Place names and People names,title", "villagename" => "Name for the main village", "innname" => "Name of the inn", "barkeep" => "Name of the barkeep", "barmaid" => "Name of the barmaid", "bard" => "Name of the bard", "clanregistrar" => "Name of the clan registrar", "deathoverlord" => "Name of the death overlord", "Referral Settings,title", "refereraward" => "How many points will be awarded for a referral?,int", "referminlevel" => "What level does the referral need to reach to credit the referer?,int", "Random events,title", "forestchance" => "Chance for Something Special in the Forest,range,0,100,1", "villagechance" => "Chance for Something Special in any village,range,0,100,1", "innchance" => "Chance for Something Special in the Inn,range,0,100,1", "gravechance" => "Chance for Something Special in the Graveyard,range,0,100,1", "gardenchance" => "Chance for Something Special in the Gardens,range,0,100,1", "Paypal,title", "paypalemail" => "Email address of Admin's paypal account", "paypalcurrency" => "Currency type", "paypalcountry-code" => "What country's predominant language do you wish to have displayed in your PayPal screen?,enum\n\t\t,US,United States,DE,Germany,AI,Anguilla,AR,Argentina,AU,Australia,AT,Austria,BE,Belgium,BR,Brazil,CA,Canada\n\t\t,CL,Chile,C2,China,CR,Costa Rica,CY,Cyprus,CZ,Czech Republic,DK,Denmark,DO,Dominican Republic\n\t\t,EC,Ecuador,EE,Estonia,FI,Finland,FR,France,GR,Greece,HK,Hong Kong,HU,Hungary,IS,Iceland,IN,India\n\t\t,IE,Ireland,IL,Israel,IT,Italy,JM,Jamaica,JP,Japan,LV,Latvia,LT,Lithuania,LU,Luxembourg,MY,Malaysia\n\t\t,MT,Malta,MX,Mexico,NL,Netherlands,NZ,New Zealand,NO,Norway,PL,Poland,PT,Portugal,SG,Singapore,SK,Slovakia\n\t\t,SI,Slovenia,ZA,South Africa,KR,South Korea,ES,Spain,SE,Sweden,CH,Switzerland,TW,Taiwan,TH,Thailand,TR,Turkey\n\t\t,GB,United Kingdom,UY,Uruguay,VE,Venezuela", "paypaltext" => "What text should be displayed as item name in the donations screen(player name will be added after it)?", "(standard: 'Legend of the Green Dragon Site Donation from',note", "General Combat,title", "autofight" => "Allow fighting multiple rounds automatically,bool", "autofightfull" => "Allow fighting until fight is over,enum,0,Never,1,Always,2,Only when not allowed to flee", "Training,title", "automaster" => "Masters hunt down truant students,bool", "multimaster" => "Can players gain multiple levels (challenge multiple masters) per game day?,bool", "displaymasternews" => "Display news if somebody fought his master?,bool", "Clans,title", "allowclans" => "Enable Clan System?,bool", "goldtostartclan" => "Gold to start a clan,int", "gemstostartclan" => "Gems to start a clan,int", "officermoderate" => "Can clan officers who are also moderators moderate their own clan even if they cannot moderate all clans?,bool", "New Days,title", "daysperday" => "Game days per calendar day,range,1,6,1", "specialtybonus" => "Extra daily uses in specialty area,range,0,5,1", "newdaycron" => "Let the newday-runonce run via a cronjob,bool", "The directory is necessary! Do not forget to set the correct one in cron.php in your main game folder!!! ONLY experienced admins should use cron jobbing here,note", "`bAlso make sure you setup a cronjob on your machine using confixx/plesk/cpanel or any other admin panel pointing to the cron.php file in your main folder`b,note", "If you do not know what a Cronjob is... leave it turned off. If you want to know more... check out: <a href='http://wiki.dragonprime.net/index.php?title=Cronjob'>http://wiki.dragonprime.net/index.php?title=Cronjob</a>,note", "resurrectionturns" => "Modify (+ or -) the number of turns deducted after a resurrection as an absolute (number) or relative (number followed by %),text", "Forest,title", "turns" => "Forest Fights per day,range,5,30,1", "dropmingold" => "Forest Creatures drop at least 1/4 of max gold,bool", "suicide" => "Allow players to Seek Suicidally?,bool", "suicidedk" => "Minimum DKs before players can Seek Suicidally?,int", "forestgemchance" => "Player will find a gem one in X times,range,10,100,1", "disablebonuses" => "Should monsters which get buffed with extra HP/Att/Def get a gold+exp bonus?,bool", "forestexploss" => "What percentage of experience should be lost?,range,10,100,1", "Multiple Enemies,title", "multifightdk" => "Multiple monsters will attack players above which amount of dragonkills?,range,8,50,1", "multichance" => "The chance for an attack from multiple enemies is,range,0,100,1", "addexp" => "Additional experience (%) per enemy during multifights?,range,0,15", "instantexp" => "During multi-fights hand out experience instantly?,bool", "maxattacks" => "How many enemies will attack per round (max. value),range,1,10", "allowpackofmonsters" => "Allow multiple monsters of the same type to appear in a battle?,bool", "Random values for type of seeking is added to random base.,note", "multibasemin" => "The base number of multiple enemies at minimum is,range,1,100,2", "multibasemax" => "The base number of multiple enemies at maximum is,range,1,100,3", "multislummin" => "The number of multiple enemies at minimum for slumming is,range,0,100,0", "multislummax" => "The number of multiple enemies at maximum for slumming is,range,0,100,1", "multithrillmin" => "The number of multiple enemies at minimum for thrill seeking is,range,0,100,1", "multithrillmax" => "The number of multiple enemies at maximum for thrill seeking is,range,0,100,2", "multisuimin" => "The number of multiple enemies at minimum for suicide is,range,0,100,2", "multisuimax" => "The number of multiple enemies at maximum for suicide is,range,0,100,4", "Stables,title", "allowfeed" => "Does Merick have feed onhand for creatures,bool", "Companions/Mercenaries,title", "enablecompanions" => "Enable the usage of companions,bool", "companionsallowed" => "How many companions are allowed per player,int", "Modules my alter this value on a per player basis!,note", "companionslevelup" => "Are companions allowed to level up?,bool", "Bank Settings,title", "fightsforinterest" => "Max forest fights remaining to earn interest?,range,0,10,1", "maxinterest" => "Max Interest Rate (%),range,5,10,1", "mininterest" => "Min Interest Rate (%),range,0,5,1", "maxgoldforinterest" => "Over what amount of gold does the bank cease paying interest? (0 for unlimited),int", "borrowperlevel" => "Max player can borrow per level (val * level for max),range5,200,5", "allowgoldtransfer" => "Allow players to transfer gold,bool", "transferperlevel" => "Max player can receive from a transfer (val * level),range,5,100,5", "mintransferlev" => "Min level a player (0 DK's) needs to transfer gold,range,1,5,1", "transferreceive" => "Total transfers a player can receive in one day,range,0,5,1", "maxtransferout" => "Amount player can transfer to others (val * level),range,5,100,5", "innfee" => "Fee for express inn payment (x or x%),int", "Mail Settings,title", "mailsizelimit" => "Message size limit per message,int", "inboxlimit" => "Limit # of messages in inbox,int", "oldmail" => "Automatically delete old messages after (days),int", "superuseryommessage" => "Warning to give when attempting to YoM an admin?", "onlyunreadmails" => "Only unread mail count towards the inbox limit?,bool", "PvP,title", "pvp" => "Enable Slay Other Players,bool", "pvpday" => "Player Fights per day,range,1,10,1", "pvpimmunity" => "Days that new players are safe from PvP,range,1,5,1", "pvpminexp" => "Experience below which player is safe from PvP,int", "pvpattgain" => "Percent of victim experience attacker gains on win,floatrange,.25,20,.25", "pvpattlose" => "Percent of experience attacker loses on loss,floatrange,.25,20,.25", "pvpdefgain" => "Percent of attacker experience defender gains on win,floatrange,.25,20,.25", "pvpdeflose" => "Percent of experience defender loses on loss,floatrange,.25,20,.25", "Content Expiration,title", "expirecontent" => "Days to keep comments and news?  (0 = infinite),int", "expiretrashacct" => "Days to keep never logged-in accounts? (0 = infinite),int", "expirenewacct" => "Days to keep 1 level (0 dragon) accounts? (0 =infinite),int", "expireoldacct" => "Days to keep all other accounts? (0 = infinite),int", "LOGINTIMEOUT" => "Seconds of inactivity before auto-logoff,int", "High Load Optimization,title", "This has been moved to the dbconnect.php,note", "LoGDnet Setup,title", "(LoGDnet requires your PHP configuration to have file wrappers enabled!!),note", "logdnet" => "Register with LoGDnet?,bool", "serverurl" => "Server URL", "serverdesc" => "Server Description (75 chars max)", "logdnetserver" => "Master LoGDnet Server (default http://logdnet.logd.com/)", "curltimeout" => "How long we wait for responses from logdnet.logd.com (in seconds),range,1,10,1|2", "Game day Setup,title", "dayduration" => "Day Duration,viewonly", "curgametime" => "Current game time,viewonly", "curservertime" => "Current Server Time,viewonly", "lastnewday" => "Last new day,viewonly", "nextnewday" => "Next new day,viewonly", "gameoffsetseconds" => "Real time to offset new day,{$enum}", "Translation Setup,title", "enabletranslation" => "Enable the use of the translation engine,bool", "It is strongly recommended to leave this feature turned on.,note", "cachetranslations" => "Cache the translations (datacache must be turned on)?,bool", "permacollect" => "Permanently collect untranslated texts (overrides the next settings!),bool", "collecttexts" => "Are we currently collecting untranslated texts?,viewonly", "tl_maxallowed" => "Collect untranslated texts if you have fewer player than this logged in. (0 never collects),int", "charset" => "Which charset should be used for htmlentities?", "Error Notification,title", "Note: you MUST have data caching turned on if you want to use this feature.  Also the first error within any 24 hour period will not generate a notice; I'm sorry: that's really just how it is for technical reasons.,note", "show_notices" => "Show PHP Notice output?,bool", "notify_on_warn" => "Send notification on site warnings?,bool", "notify_on_error" => "Send notification on site errors?,bool", "notify_address" => "Address to notify", "notify_every" => "Only notify every how many minutes for each distinct error?,int", "Miscellaneous Settings,title", "allowspecialswitch" => "The Barkeeper may help you to switch your specialty?,bool", "maxlistsize" => "Maximum number of items to be shown in the warrior list,int");
    $secstonewday = secondstonextgameday($details);
    $useful_vals = array("dayduration" => round($details['dayduration'] / 60 / 60, 0) . " hours", "curgametime" => getgametime(), "curservertime" => date("Y-m-d h:i:s a"), "lastnewday" => date("h:i:s a", strtotime("-{$details['realsecssofartoday']} seconds")), "nextnewday" => date("h:i:s a", strtotime("+{$details['realsecstotomorrow']} seconds")) . " (" . date("H\\h i\\m s\\s", $secstonewday) . ")");
    loadsettings();
function pub_kittania_run()
{
    global $session;
    $td = gametimedetails();
    $gt = $td['secssofartoday'];
    //8400 seconds in a day
    //3600 seconds in an hour
    //midnight: 0
    //1am: 3600
    //2am: 7200
    //3am: 10800
    //4am: 14400
    //5am: 18000
    //6am: 21600
    //7am: 25200
    //8am: 28800
    //9am: 32400
    //10am: 36000
    //11am: 39600
    //12pm midday: 43200
    //1pm: 46800
    //2pm: 50400
    //3pm: 54000
    //4pm: 57600
    //5pm: 61200
    //6pm: 64800
    //7pm: 68400
    //8pm: 72000
    //9pm: 75600
    //10pm: 79200
    //11pm: 82800
    //11:59:59: 86399
    //midnight: 0
    page_header("The Sunny Spot");
    $op = httpget("op");
    switch ($op) {
        case "start":
            rawoutput("<table cellpadding=0 cellspacing=0><tr><td><img src='images/pubsigns/kittania.png' align='left'>");
            $phrases = array(1 => "flirting cheerfully with one of her patrons as she draws a pint", 2 => "wearily giving directions to a confused Rookie", 3 => "gossiping idly about the latest chef in town");
            $chosenphrase = array_rand($phrases);
            output("You climb up a short ladder and emerge into the largest treehouse you've ever seen.  Large branches are visible through the transluscent net drape of the ceiling.  A few kittymorphs chat and consume drinks while lounging in some of the many inviting hammocks, while others share a meal on reclining couches.  Large soft pillows are scattered about the floor around trays full of drink and smokeables.   The landlady Miu-Miu is a tawny, middle-aged kittymorph.  Right now she's %s.`n`nThe soft murmur of conversation is punctuated by laughter, and the smell of strange incense hangs in the air, mingling with the fresh green scent of the tree itself.`n`n", $phrases[$chosenphrase]);
            rawoutput("</td></tr></table>");
            require_once "lib/commentary.php";
            addcommentary();
            viewcommentary("pub_kittania");
            addnav("Talk to people");
            addnav("Miu-Miu", "runmodule.php?module=pub_kittania&op=bartender");
            modulehook("pub_kittania");
            break;
        case "continue":
            rawoutput("<table cellpadding=0 cellspacing=0><tr><td><img src='images/pubsigns/kittania.png' align='left'>");
            output("You rejoin your fellows in the open space.`n`n");
            rawoutput("</td></tr></table>");
            require_once "lib/commentary.php";
            addcommentary();
            viewcommentary("pub_kittania");
            addnav("Talk to people");
            addnav("Miu-Miu", "runmodule.php?module=pub_kittania&op=bartender");
            modulehook("pub_kittania");
            break;
        case "bartender":
            //add a text parser here at some point, I think...
            //maybe make this opening text time-dependent?
            $text = array();
            $text['hello'] = "Miu-Miu shows you a slightly tired smile.  \"`2Yes love, what'll you have?`0\"`n`n";
            $drinks = array();
            $hook = array();
            $hook['drinks'] = $drinks;
            $hook['text'] = $text;
            $hook = modulehook("pub_kittania_bartender", $hook);
            $text = $hook['text'];
            //debug($hook);
            $drinks = $hook['drinks'];
            output_notl($text['hello']);
            foreach ($drinks as $key => $vals) {
                addnav("What'll it be?");
                if (!$vals['blockdrink']) {
                    if ($session['user']['gold'] >= $vals['price']) {
                        addnav(array("%s (%s Req)", $vals['verbosename'], $vals['price']), "runmodule.php?module=pub_kittania&op=drink&drink=" . $key);
                    } else {
                        addnav(array("%s (%s Req)", $vals['verbosename'], $vals['price']), "");
                    }
                }
            }
            if (!$hook['blockreturnnav']) {
                addnav("Never mind");
                addnav("Return to the lounge", "runmodule.php?module=pub_kittania&op=continue");
            }
            break;
        case "drink":
            $hook = array("drink" => httpget("drink"));
            $hook = modulehook("pub_kittania_drink", $hook);
            if (!$hook['blockbarnav']) {
                addnav("More!");
                addnav("Get Miu-Miu's attention again", "runmodule.php?module=pub_kittania&op=bartender");
            }
            if (!$hook['blockreturnnav']) {
                addnav("That's enough");
                addnav("Return to the lounge", "runmodule.php?module=pub_kittania&op=continue");
            }
            break;
    }
    addnav("Leave");
    addnav("Back to Kittania", "village.php");
    page_footer();
}
function pub_squathole_run()
{
    global $session;
    $td = gametimedetails();
    $gt = $td['secssofartoday'];
    //8400 seconds in a day
    //3600 seconds in an hour
    //midnight: 0
    //1am: 3600
    //2am: 7200
    //3am: 10800
    //4am: 14400
    //5am: 18000
    //6am: 21600
    //7am: 25200
    //8am: 28800
    //9am: 32400
    //10am: 36000
    //11am: 39600
    //12pm midday: 43200
    //1pm: 46800
    //2pm: 50400
    //3pm: 54000
    //4pm: 57600
    //5pm: 61200
    //6pm: 64800
    //7pm: 68400
    //8pm: 72000
    //9pm: 75600
    //10pm: 79200
    //11pm: 82800
    //11:59:59: 86399
    //midnight: 0
    page_header("Booz");
    $op = httpget("op");
    switch ($op) {
        case "start":
            rawoutput("<table cellpadding=0 cellspacing=0><tr><td><img src='images/pubsigns/squathole_1.png' align='left'>");
            $phrases = array(1 => "A number of Midgets stand around drinking pints of Wanker, and holding what sounds like a dirty limerick contest.  None of them are quite clever enough to know what a limerick is, but they're giving it their best shot.", 2 => "A small knot of Midgets are brawling on the top of a table, spilling beer and foul secretions everywhere. It looks like they've been at it for awhile, and the pub is starting to show the damage.  The ratty blue tarp above the grouping is letting in the elements, which doesn't deter any of the fighting throng.  Bottles, mugs and fists are brandished, and one particularly angry Midget has torn off bits of a table and looks disappointed that there's no chandelier for him to swing from.", 3 => "You think the sign once read 'Mourners of Life Poetry Club,' but that surely can't be right.");
            $chosenphrase = array_rand($phrases);
            output("`0Booz, the Squat Hole pub, is basically a series of drooping tarpaulins, unsteadily propped up with branches and a few stakes.  Its mostly knee-high patrons sit on empty beer kegs, resting their drinks or their feet on other kegs.  The stench of armpit and stale beer hangs in the air.  Someone has propped a few rotting boards on top of more kegs - this is the bar.  A tiny woman scampers back and forth across it, doling out alcohol to patrons who are temporarily still upright.  Her name is Chlamydia.  You know, like the flower.`n`n%s`n`n", $phrases[$chosenphrase]);
            rawoutput("</td></tr></table>");
            require_once "lib/commentary.php";
            addcommentary();
            viewcommentary("pub_squathole");
            addnav("Talk to people");
            addnav("Chlamydia", "runmodule.php?module=pub_squathole&op=bartender");
            modulehook("pub_squathole");
            break;
        case "continue":
            rawoutput("<table cellpadding=0 cellspacing=0><tr><td><img src='images/pubsigns/squathole_1.png' align='left'>");
            output("You head back into the main section of the pub, ducking under flappy bits of tarpaulin.`n`n");
            rawoutput("</td></tr></table>");
            require_once "lib/commentary.php";
            addcommentary();
            viewcommentary("pub_squathole");
            addnav("Talk to people");
            addnav("Chlamydia", "runmodule.php?module=pub_squathole&op=bartender");
            modulehook("pub_squathole");
            break;
        case "bartender":
            //add a text parser here at some point, I think...
            //maybe make this opening text time-dependent?
            $text = array();
            $text['hello'] = "Chlamydia shows you a smile and squeaks at you.  \"`2Yes luv, wha' c'n I gitcha?`0\"`n`n";
            $drinks = array();
            $hook = array();
            $hook['drinks'] = $drinks;
            $hook['text'] = $text;
            $hook = modulehook("pub_squathole_bartender", $hook);
            $text = $hook['text'];
            //debug($hook);
            $drinks = $hook['drinks'];
            output_notl($text['hello']);
            foreach ($drinks as $key => $vals) {
                addnav("Wha' indeed?");
                if (!$vals['blockdrink']) {
                    if ($session['user']['gold'] >= $vals['price']) {
                        addnav(array("%s (%s Req)", $vals['verbosename'], $vals['price']), "runmodule.php?module=pub_squathole&op=drink&drink=" . $key);
                    } else {
                        addnav(array("%s (%s Req)", $vals['verbosename'], $vals['price']), "");
                    }
                }
            }
            if (!$hook['blockreturnnav']) {
                addnav("Never mind");
                addnav("Return to the lounge", "runmodule.php?module=pub_squathole&op=continue");
            }
            break;
        case "drink":
            $hook = array("drink" => httpget("drink"));
            $hook = modulehook("pub_squathole_drink", $hook);
            if (!$hook['blockbarnav']) {
                addnav("More!");
                addnav("Get Chlamydia's attention again", "runmodule.php?module=pub_squathole&op=bartender");
            }
            if (!$hook['blockreturnnav']) {
                addnav("That's enough");
                addnav("Return to the lounge", "runmodule.php?module=pub_squathole&op=continue");
            }
            break;
    }
    addnav("Leave");
    addnav("Back to Squat Hole", "village.php");
    page_footer();
}
/**
 * Returns the current character stats or (if the character isn't logged in) the currently online players
 * Hooks provided:
 *		charstats
 *
 * @return array The current stats for this character or the list of online players
 */
function charstats()
{
    global $session, $playermount, $companions;
    wipe_charstats();
    $u =& $session['user'];
    if ($session['loggedin']) {
        $u['hitpoints'] = round($u['hitpoints'], 0);
        $u['experience'] = round($u['experience'], 0);
        $u['maxhitpoints'] = round($u['maxhitpoints'], 0);
        // $spirits=array(-6=>"Resurrected",-2=>"Very Low",-1=>"Low","0"=>"Normal",1=>"High",2=>"Very High");
        // if ($u['alive']){ }else{ $spirits[(int)$u['spirits']] = "DEAD"; }
        //calculate_buff_fields();
        reset($session['bufflist']);
        $atk = $u['attack'];
        $def = $u['defense'];
        $buffcount = 0;
        $buffs = "";
        while (list($key, $val) = each($session['bufflist'])) {
            if (isset($val['suspended']) && $val['suspended']) {
                continue;
            }
            if (isset($val['atkmod'])) {
                $atk *= $val['atkmod'];
            }
            if (isset($val['defmod'])) {
                $def *= $val['defmod'];
            }
            // Short circuit if the name is blank
            if ($val['name'] > "" || $session['user']['superuser'] & SU_DEBUG_OUTPUT) {
                tlschema($val['schema']);
                if ($val['name'] == "") {
                    $val['name'] = "DEBUG: {$key}";
                }
                if (is_array($val['name'])) {
                    $val['name'][0] = str_replace("`%", "`%%", $val['name'][0]);
                    $val['name'] = call_user_func_array("sprintf_translate", $val['name']);
                } else {
                    //in case it's a string
                    $val['name'] = translate_inline($val['name']);
                }
                if ($val['rounds'] >= 0) {
                    // We're about to sprintf, so, let's makes sure that
                    // `% is handled.
                    //$n = translate_inline(str_replace("`%","`%%",$val['name']));
                    $b = translate_inline("`#%s `7(%s rounds left)`n", "buffs");
                    $b = sprintf($b, $val['name'], $val['rounds']);
                    $buffs .= appoencode($b, true);
                } else {
                    $buffs .= appoencode("`#{$val['name']}`n", true);
                }
                tlschema();
                $buffcount++;
            }
        }
        if ($buffcount == 0) {
            $buffs .= appoencode(translate_inline("`^None`0"), true);
        }
        $atk = round($atk, 2);
        $def = round($def, 2);
        if ($atk < $u['attack']) {
            $atk = round($u['attack'], 1) . "`\$" . round($atk - $u['attack'], 1);
        } else {
            if ($atk > $u['attack']) {
                $atk = round($u['attack'], 1) . "`@+" . round($atk - $u['attack'], 1);
            } else {
                // They are equal, display in the 1 signifigant digit format.
                $atk = round($atk, 1);
            }
        }
        if ($def < $u['defense']) {
            $def = round($u['defense'], 1) . "`\$" . round($def - $u['defense'], 1);
        } else {
            if ($def > $u['defense']) {
                $def = round($u['defense'], 1) . "`@+" . round($def - $u['defense'], 1);
            } else {
                // They are equal, display in the 1 signifigant digit format.
                $def = round($def, 1);
            }
        }
        addcharstat("Vital Info");
        //health bar
        if ($u['alive']) {
            $cur = $u['hitpoints'];
            $realmax = $u['maxhitpoints'];
            $cur_adjustment = check_temp_stat("hitpoints", 1);
            $max_adjustment = check_temp_stat("maxhitpoints", 1);
        } else {
            $cur = $u['soulpoints'];
            $realmax = $u['level'] * 5 + 50;
            $cur_adjustment = check_temp_stat("soulpoints", 1);
            $max_adjustment = "";
        }
        if ($pct > 60) {
            $ccode = "`@";
        } elseif ($pct > 25) {
            $ccode = "`^";
        } else {
            $ccode = "`\$";
        }
        $hicode = "`&";
        if (!$u['alive']) {
            $ccode = "`7";
        }
        require_once "lib/bars.php";
        $hpbar = fadebar($cur, $realmax);
        $stat = "{$ccode} {$cur} {$cur_adjustment} `0/ {$realmax} {$max_adjustment}<br />" . $hpbar;
        if ($u['alive']) {
            addcharstat("Hitpoints", $stat);
            addcharstat("Attack", $atk . check_temp_stat("attack", 1));
            addcharstat("Defence", $def . check_temp_stat("defense", 1));
        } else {
            addcharstat("Adrenaline", $stat);
            addcharstat("Attack", 10 + round(($u['level'] - 1) * 1.5));
            addcharstat("Defence", 10 + round(($u['level'] - 1) * 1.5));
        }
        // addcharstat("Turns", $u['turns'].check_temp_stat("turns",1));
        // addcharstat("Attack", $atk.check_temp_stat("attack",1));
        // addcharstat("Defence", $def.check_temp_stat("defense",1));
        if (count($companions) > 0) {
            addcharstat("Companions");
            foreach ($companions as $name => $companion) {
                if ($companion['hitpoints'] > 0 || isset($companion['cannotdie']) && $companion['cannotdie'] == true) {
                    if ($companion['hitpoints'] < 0) {
                        $companion['hitpoints'] = 0;
                    }
                    if ($companion['hitpoints'] < $companion['maxhitpoints']) {
                        $color = "`\$";
                    } else {
                        $color = "`@";
                    }
                    if (isset($companion['suspended']) && $companion['suspended'] == true) {
                        $suspcode = "`7 *";
                    } else {
                        $suspcode = "";
                    }
                    addcharstat($companion['name'], $color . $companion['hitpoints'] . "`7/`&" . $companion['maxhitpoints'] . "{$suspcode}`0");
                }
            }
        }
        addcharstat("Personal Info");
        if ($u['alive']) {
            addcharstat("Requisition", number_format($u['gold'] . check_temp_stat("gold", 1)));
            addcharstat("Cigarettes", number_format($u['gems'] . check_temp_stat("gems", 1)));
        } else {
            addcharstat("Cage Fights", $u['gravefights'] . check_temp_stat("gravefights", 1));
            addcharstat("Favour", number_format($u['deathpower'] . check_temp_stat("deathpower", 1)));
        }
        if ($u['alive']) {
            addcharstat("Level", "`b" . $u['level'] . check_temp_stat("level", 1) . "`b");
            //exp bar
            require_once "lib/experience.php";
            $min = exp_for_next_level($u['level'] - 1, $u['dragonkills']);
            $req = exp_for_next_level($u['level'], $u['dragonkills']);
            $exp = round($session['user']['experience'], 0) . check_temp_stat("experience", 1);
            if ($exp < $min) {
                $min = $exp;
            }
            if ($req - $min > 0) {
                $nonpct = floor(($req - $exp) / ($req - $min) * 100);
            } else {
                $nonpct = 0;
            }
            $pct = 100 - $nonpct;
            if ($pct > 100) {
                $pct = 100;
                $nonpct = 0;
            }
            if ($pct < 0) {
                $pct = 0;
                $nonpct = 100;
            }
            if ($exp >= $req) {
                $color = "blue";
                if ($session['user']['level'] == 1 && $session['user']['dragonkills'] == 0) {
                    $expmsg = "<br />You have enough experience to level up!  Challenge your master in the Dojo!";
                }
            } else {
                $color = "white";
            }
            addcharstat("Experience", number_format($u['experience'] . check_temp_stat("experience", 1)) . "/{$req}<br /><table style='border: solid 1px #000000;' bgcolor='red'  cellpadding='0' cellspacing='0' width='70' height='5'><tr><td width='{$pct}%' bgcolor='{$color}'></td><td width='{$nonpct}%'></td></tr></table>{$expmsg}");
            addcharstat("Equipment Info");
            addcharstat("Weapon", $u['weapon']);
            addcharstat("Armor", $u['armor']);
            if ($u['hashorse']) {
                addcharstat("Creature", $playermount['mountname'] . "`0");
            }
        }
        require_once "lib/datetime.php";
        $gt = gametimedetails();
        addcharstat("Game State");
        addcharstat("Game Time", gmdate("g:i a", $gt['gametime']));
        addcharstat("New day in:", date("H:i:s", secondstonextgameday()));
        modulehook("charstats");
        $charstat = getcharstats($buffs);
        if (!is_array($session['bufflist'])) {
            $session['bufflist'] = array();
        }
        return $charstat;
    } else {
        $ret = "";
        if ($ret = datacache("charlisthomepage")) {
        } else {
            $onlinecount = 0;
            // If a module wants to do it's own display of the online chars,
            // let it.
            $list = modulehook("onlinecharlist", array());
            if (isset($list['handled']) && $list['handled']) {
                $onlinecount = $list['count'];
                $ret = $list['list'];
            } else {
                $sql = "SELECT name,alive,location,sex,level,laston,loggedin,lastip,uniqueid 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 level DESC";
                $result = db_query($sql);
                $ret .= appoencode(sprintf(translate_inline("`bOnline Characters (%s players):`b`n"), db_num_rows($result)));
                while ($row = db_fetch_assoc($result)) {
                    $ret .= appoencode("`^{$row['name']}`n");
                    $onlinecount++;
                }
                db_free_result($result);
                if ($onlinecount == 0) {
                    $ret .= appoencode(translate_inline("`iNone`i"));
                }
            }
            savesetting("OnlineCount", $onlinecount);
            savesetting("OnlineCountLast", strtotime("now"));
            updatedatacache("charlisthomepage", $ret);
        }
        return $ret;
    }
}
function serverload_run()
{
    global $session;
    page_header("Current Server Load");
    $load = exec("uptime");
    $load = split("load average:", $load);
    $load = split(", ", $load[1]);
    if (httpget('update')) {
        serverload_update(true);
    }
    output("`bCPU Load averages`b`n");
    output("One minute: %s`nFive minutes: %s`nFifteen minutes: %s`n`n", $load[0], $load[1], $load[2]);
    addnav("Options");
    addnav("Refresh", "runmodule.php?module=serverload");
    addnav("Go to login page", "home.php");
    $online = 0;
    $noobsonline = 0;
    $loggedintoday = 0;
    $loggedinthisweek = 0;
    $joinedtoday = 0;
    $totalplayers = 0;
    $sql = "SELECT regdate, dragonkills, laston, gentimecount, gentime, loggedin FROM " . db_prefix("accounts") . "";
    $result = db_query($sql);
    for ($i = 0; $i < db_num_rows($result); $i++) {
        $totalplayers++;
        $row = db_fetch_assoc($result);
        $lastontime = strtotime($row['laston']);
        $regtime = strtotime($row['regdate']);
        $curtime = date(U);
        $sincelogon = $curtime - $lastontime;
        $sincereg = $curtime - $regtime;
        if ($sincelogon < getsetting("LOGINTIMEOUT", 900) && $row['loggedin'] == 1) {
            $online++;
        }
        if ($sincelogon < 86400) {
            $loggedintoday++;
        }
        if ($sincelogon < 604800) {
            $loggedinthisweek++;
        }
        if ($sincereg < 86400) {
            $joinedtoday++;
            if ($sincelogon < getsetting("LOGINTIMEOUT", 900) && $row['loggedin'] == 1) {
                $noobsonline++;
            }
        }
        $t_time += $row['gentime'];
        $t_count += $row['gentimecount'];
    }
    output("`bPlayer Count`b`n");
    output("Total Players: %s`n", $totalplayers);
    output("Joined today: %s`n", $joinedtoday);
    output("Logged in today: %s`n", $loggedintoday);
    output("Logged in this week: %s`n", $loggedinthisweek);
    output("Online players: %s`n", $online);
    output("New players online right now: %s`n`n", $noobsonline);
    $time = $t_time - get_module_setting("ltime");
    $count = $t_count - get_module_setting("lcount");
    $lastupdate = get_module_setting("lastupdate");
    require_once "lib/datetime.php";
    $timedetails = gametimedetails();
    output("`bRecent performance statistics since last login/logout operation`b`n");
    output("Total pages loaded: %s`n", $count);
    output("Total page gen time: %s`n", $time);
    if ($count) {
        output("Average page gen time: `b%s`b`n", $time / $count);
        $timesincelast = microtime(true) - $lastupdate;
        $pps = round($count / $timesincelast, 3);
        output("Average pages per second since last update: %s`n", $pps);
        output("Peak pages per second: %s`n", get_module_setting("peakpps"));
        $d_count = $t_count - get_module_setting("ldaycount");
        $dpps = round($d_count / $timedetails['realsecssofartoday'], 3);
        output("Average pages per second for this game day: %s`n`n", $dpps);
    }
    output_notl("`n");
    output("`bAll-time statistics`b`nNote: statistics apply to current players only.  Actual all-time numbers are at present unknowable, but are likely to be hundreds or thousands of times larger.  Our server requires many hamster wheels to run.`n");
    $tpgentime = $t_time / $t_count;
    output("All-time page loads: %s`n", number_format($t_count));
    output("All-time page generation time: %s seconds`n", number_format($t_time));
    output("All-time average pagegen time: %s`n", $tpgentime);
    output_notl("`n");
    if (get_module_setting("ldaycount") > $t_count) {
        set_module_setting("ldaycount", $t_count);
    }
    //Show player number table
    $sql = "SELECT numplayers, totalpages, totaltime FROM " . db_prefix("performance") . "";
    $result = db_query($sql);
    output("`bAverage Page Generation Times by number of online players`b`n");
    rawoutput("<table border='0' cellpadding='2' cellspacing='1' align='center' width='100%'>");
    rawoutput("<tr class='trhead'><td>Online Players</td><td>Total Count</td><td>Total Time</td><td>Average Time / Page</td></tr>");
    for ($i = 0; $i < db_num_rows($result); $i++) {
        $row = db_fetch_assoc($result);
        if ($row['totalpages'] >= 1) {
            $avg = $row['totaltime'] / $row['totalpages'];
            $max = 100;
            $bwidth = round($avg * 100);
            $bnonwidth = $max - $bwidth;
            if ($bnonwidth > 0) {
                $bar = "<table style='border: solid 1px #000000' width='{$max}' height='7' bgcolor='#333333' cellpadding=0 cellspacing=0><tr><td width='{$bwidth}' bgcolor='#00ff00'></td><td width='{$bnonwidth}'></td></tr></table>";
            } else {
                $over = $bwidth - $max;
                $total = $max + $over;
                $bar = "<table style='border: solid 1px #000000' height='7' width='{$total}' cellpadding=0 cellspacing=0><tr><td width='{$max}' bgcolor='#990000'></td><td width='{$over}' bgcolor='#ff0000'></td></tr></table>";
            }
            $improvement = "";
            if ($row['numplayers'] == $online) {
                rawoutput("<tr class='trhilight'>");
                if ($row['totaltime'] / $row['totalpages'] < $time / $count) {
                    $improvement = " (increasing)";
                } else {
                    $improvement = " (decreasing)";
                }
            } else {
                rawoutput("<tr class='" . ($i % 2 ? "trdark" : "trlight") . "'>");
            }
            rawoutput("<td>" . $row['numplayers'] . "</td><td>" . number_format($row['totalpages']) . "</td><td>" . $row['totaltime'] . "</td><td>" . $bar . round($row['totaltime'] / $row['totalpages'], 4) . $improvement . "</td></tr>");
        }
    }
    rawoutput("</table>");
    //Show time of day table
    $timeslice = floor((time() - strtotime(date("Y-m-d 00:00:00"))) / 600);
    $sql = "SELECT * FROM " . db_prefix("performancetime") . "";
    $result = db_query($sql);
    $now = date("h:i a");
    output("`n`n`bAverage Page Generation Times by Time of Day (server time)`b`nResults are calculated whenever a player logs in or out, so if it's been a while since a login/logout operation, this data may be slightly inaccurate.  All times are GMT, and the current server time is %s.`n", $now);
    rawoutput("<table border='0' cellpadding='2' cellspacing='1' align='center' width='100%'>");
    rawoutput("<tr class='trhead'><td>Time Period</td><td>Total Count</td><td>Total Time</td><td>Average Time / Page</td></tr>");
    for ($i = 0; $i < db_num_rows($result); $i++) {
        $row = db_fetch_assoc($result);
        if ($row['totalpages'] >= 1) {
            $avg = $row['totaltime'] / $row['totalpages'];
            $max = 100;
            $bwidth = round($avg * 100);
            $bnonwidth = $max - $bwidth;
            if ($bnonwidth > 0) {
                $bar = "<table style='border: solid 1px #000000' width='{$max}' height='7' bgcolor='#333333' cellpadding=0 cellspacing=0><tr><td width='{$bwidth}' bgcolor='#00ff00'></td><td width='{$bnonwidth}'></td></tr></table>";
            } else {
                $over = $bwidth - $max;
                $total = $max + $over;
                $bar = "<table style='border: solid 1px #000000' height='7' width='{$total}' cellpadding=0 cellspacing=0><tr><td width='{$max}' bgcolor='#990000'></td><td width='{$over}' bgcolor='#ff0000'></td></tr></table>";
            }
            $improvement_time = "";
            if ($row['timeslice'] == $timeslice) {
                rawoutput("<tr class='trhilight'>");
                if ($row['totaltime'] / $row['totalpages'] < $time / $count) {
                    $improvement_time = " (increasing)";
                } else {
                    $improvement_time = " (decreasing)";
                }
            } else {
                rawoutput("<tr class='" . ($i % 2 ? "trdark" : "trlight") . "'>");
            }
            $timedispstart = strtotime(date("Y-m-d 00:00:00")) + $row['timeslice'] * 600;
            $timedispend = $timedispstart + 600;
            $timedisp = date("h:i a", $timedispstart) . " to " . date("h:i a", $timedispstart + 600);
            rawoutput("<td>" . $timedisp . "</td><td>" . number_format($row['totalpages']) . "</td><td>" . $row['totaltime'] . "</td><td>" . $bar . round($row['totaltime'] / $row['totalpages'], 4) . $improvement_time . "</td></tr>");
        }
    }
    rawoutput("</table>");
    page_footer();
}
function daysave_dohook($hookname, $args)
{
    global $session;
    switch ($hookname) {
        case "newday":
            $days = get_module_pref("days");
            $slots = get_module_pref("slots");
            $lastonnextday = get_module_pref("lastlognewday");
            $time = gametimedetails();
            //debug("time:". $time['gametime']);
            $timediff = $time['gametime'] - $lastonnextday;
            //debug("timediff: $timediff");
            if ($timediff > 86400) {
                $addition = floor($timediff / 86400);
                $days += $addition;
                if ($days > $slots) {
                    $days = $slots;
                }
                if ($lastonnextday < 1) {
                    $days = 0;
                }
                set_module_pref("days", $days);
            }
            set_module_pref("lastlognewday", $time['tomorrow']);
            break;
        case "newday-runonce":
            //reset all players' Instant Buys counter
            // $sql = "SELECT acctid FROM " . db_prefix("accounts");
            // $result = db_query($sql);
            // for ($i=0;$i<db_num_rows($result);$i++){
            // $row = db_fetch_assoc($result);
            // clear_module_pref("instantbuys",false,$row['acctid']);
            // }
            break;
        case "player-logout":
            $details = gametimedetails();
            set_module_pref("lastlognewday", $details['tomorrow']);
            break;
        case "village":
            tlschema('daysavenav');
            // if ($session['user']['age'] < 2 && !$session['user']['dragonkills']){
            // require_once "modules/staminasystem/lib/lib.php";
            // if (get_stamina<10){
            // output("`J`bYou're starting to run low on Stamina.`b  As you become more exhausted, the Island becomes a more dangerous and unpredictable place.  You can replenish your Stamina by eating or drinking something.  Or, hey - did you notice the Saved Days link down there?  That might be worth a click.  Like all Rookie-advice messages, this one will likely disappear and quit pestering you pretty soon.`0`n`n");
            // addnav("`JSaved Days`0");
            // addnav("`JNew Day Menu`0","runmodule.php?module=daysave&op=start&return=village");
            // } else {
            // addnav("Saved Days");
            // addnav("New Day Menu","runmodule.php?module=daysave&op=start&return=village");
            // }
            // } else {
            addnav("Saved Days");
            addnav("New Day Menu", "runmodule.php?module=daysave&op=start&return=village");
            //}
            break;
        case "shades":
            tlschema('daysavenav');
            addnav("Saved Days");
            if (!$session['user']['resurrections'] && !$session['user']['dragonkills'] && get_module_pref("days")) {
                output("`JAdvice for new players: if you try to fight your way back to the Island and fail, then have a look at the New Day Menu.  This message, like all the other blue newbie messages, will go away and quit pestering you pretty soon.`0`n`n");
                addnav("`JNew Day Menu", "runmodule.php?module=daysave&op=start&return=shades");
            } else {
                addnav("New Day Menu", "runmodule.php?module=daysave&op=start&return=shades");
            }
            break;
        case "worldnav":
            tlschema('daysavenav');
            addnav("Saved Days");
            addnav("New Day Menu", "runmodule.php?module=daysave&op=start&return=worldmapen");
            break;
    }
    return $args;
}