Source code for TomeNET monster search

common.inc.php

<?php

//if (ob_get_level()) ob_end_clean();
//ob_start('ob_gzhandler');

$colors_hex = array(
    
'd' => '#000000',    // black
    
'D' => '#747474',    // dark
    
's' => '#9D9D9D',    // slate
    
'W' => '#D7D7D7',    // white
    
'w' => '#FFF',        // bright white
    
'b' => '#0000FF',    // blue
    
'g' => '#009D44',    // green
    
'r' => '#D70000',    // red
    
'u' => '#8D6600',    // umber
    
'y' => '#FFFF00',    // yellow
    
'B' => '#00FFFF',    // light blue
    
'G' => '#00FF00',    // light green
    
'R' => '#FF0000',    // pink
    
'U' => '#C79D55',    // light umber
    
'o' => '#FF8D00',    // orange
    
'v' => '#AF00FF',    // violet

    
'a' => '#AF00FF',    // acidic, monsters of bad luck (FIXME: animate)
    
'I' => '#AF00FF',    // new color for disenchantment / invulnerability (FIXME: animate)
    
'f' => '#D70000',    // fire (red) (FIXME: animate)
    
'p' => '#00FF00',    // poison (light green) (FIXME: animate)
    
'M' => '#FFF',        // manashield (white for now) (FIXME: animate)
    
'L' => '#FFFF00',    // lite (candlebearer) (FIXME: animate)
    
'c' => '#FFF',        // cold (will o' wisp) (FIXME: animate)
    
'e' => '#00FFFF',    // electric (living lightning) (FIXME: animate)
    
'Z' => '#D70000',    // ember (FIXME: animate)
    
'K' => '#009D44',    // unbreath (FIXME)
    
'C' => '#C79D55',    // confusion (FIXME)
    
'q' => '#9D9D9D',    // inertia (FIXME)
    
'A' => '#747474',    // darkness (FIXME)
    
'S' => '#FFFF00',    // sound (FIXME)
    
'k' => '#D70000',    // nuke (FIXME)
);

$colors_name = array(
    
'd' => 'black',
    
'D' => 'dark',
    
's' => 'slate',
    
'W' => 'white',
    
'w' => 'bright white',
    
'b' => 'blue',
    
'g' => 'green',
    
'r' => 'red',
    
'u' => 'umber',
    
'y' => 'yellow',
    
'B' => 'light blue',
    
'G' => 'light green',
    
'R' => 'light red',
    
'U' => 'light umber',
    
'o' => 'orange',
    
'v' => 'violet',

    
'a' => 'acidic',
    
'I' => 'invulnerability',
    
'f' => 'fiery',
    
'p' => 'poisony',
    
'M' => 'manashieldy',
    
'L' => 'lite',
    
'c' => 'cold',
    
'e' => 'electric',
    
'Z' => 'ember',
    
'K' => 'unbreath',
    
'C' => 'confusion',
    
'q' => 'inertia',
    
'A' => 'darkness',
    
'S' => 'sound',
    
'k' => 'nuke',
);

$monster_types = array(
    
'NONEBAND',
    
'BASEANGBAND',
    
'ZANGBAND',
    
'CTHANGBAND',
    
'JOKEANGBAND',
    
'PERNANGBAND',
    
'BLUEBAND',
);

$monster_types_desc = array(
    
'None',
    
'Base',
    
'Zangband',
    
'Cthulhu',
    
'Joke',
    
'Pern',
    
'Blue',
);

function 
get_hex_color($m) {
    return(
$GLOBALS['colors_hex'][$m['color']]);
}

// Old code
function get_type($m) {
    if (
array_search('BASEANGBAND'$m['flags']) !== FALSE) return 'Base';
    elseif (
array_search('ZANGBAND'$m['flags']) !== FALSE) return 'Zangband';
    elseif (
array_search('CTHANGBAND'$m['flags']) !== FALSE) return 'Cthulhu';
    elseif (
array_search('JOKEANGBAND'$m['flags']) !== FALSE) return 'Joke';
    elseif (
array_search('PERNANGBAND'$m['flags']) !== FALSE) return 'Pern';
    elseif (
array_search('BLUEBAND'$m['flags']) !== FALSE) return 'Blue';
    else return 
'?';
}

$monster_bg_colors_by_type = array(
    
'#FFF',
    
'#B7FFB4'// BASEANGBAND
    
'#FFFFB4'// ZANGBAND
    
'#B4FFF6'// CTHANGBAND
    
'#FFE6B4'// JOKEANGBAND
    
'#FFB4E0'// PERNANGBAND
    
'#B4B9FF'// BLUEBAND
);

// Old code
function get_result_bg_color($m) {
    if (
array_search('BASEANGBAND'$m['flags']) !== FALSE) return '#B7FFB4';
    if (
array_search('ZANGBAND'$m['flags']) !== FALSE) return '#FFFFB4';
    if (
array_search('CTHANGBAND'$m['flags']) !== FALSE) return '#B4FFF6';
    if (
array_search('JOKEANGBAND'$m['flags']) !== FALSE) return '#FFE6B4';
    if (
array_search('PERNANGBAND'$m['flags']) !== FALSE) return '#FFB4E0';
    if (
array_search('BLUEBAND'$m['flags']) !== FALSE) return '#B4B9FF';
    return 
'#FFF';
}

function 
is_unique($m) {
    if (
array_search('UNIQUE'$m['flags']) !== FALSE) return 'Yes';
    return 
'No';
}

function 
count_hp($m) {
    
$d explode('d'$m['hp']);
    if (
array_search('FORCE_MAXHP'$m['flags']) === FALSE) {
        
$hp '~' . ($d[0] * ($d[1] + 1) / 2);
    } else {
        
$hp $d[0] * $d[1];
    }
    return(
$hp);
}

function 
count_hp_no_tilde($m) {
    
$d explode('d'$m['hp']);
    if (
array_search('FORCE_MAXHP'$m['flags']) === FALSE) {
        
$hp $d[0] * ($d[1] + 1) / 2;
    } else {
        
$hp $d[0] * $d[1];
    }
    return(
$hp);
}

function 
parse_gpc($a) {
    if (
get_magic_quotes_gpc()) {
        return(
stripslashes($a));
    } else {
        return(
$a);
    }
}

// Old compability code
if (!function_exists('stripos')) {
    function 
stripos($a$b) {
        return(
strpos(strtolower($a), strtolower($b)));
    }
}

?>

flags.php

<?php
$flags 
= array('AI_ANNOY''AI_SPECIAL''ALLOW_RUNNING''ANIMAL''AQUATIC''ASTAR''ATTR_ANY''ATTR_BASE''ATTR_BNW''ATTR_CLEAR''ATTR_MULTI''AURA_COLD''AURA_ELEC''AURA_FIRE''AVOID_PERMAWALLS''BASEANGBAND''BASH_DOOR''BLUEBAND''CAN_FLY''CAN_SPEAK''CAN_SWIM''CHAR_CLEAR''CHAR_MULTI''COLD_BLOOD''CTHANGBAND''DEATH_ORB''DEMON''DG_CURSE''DISBELIEVE''DRAGON''DRAGONRIDER''DROP_1''DROP_1D2''DROP_2D2''DROP_3D2''DROP_4D2''DROP_60''DROP_90''DROP_CHOSEN''DROP_CORPSE''DROP_GOOD''DROP_GREAT''DROP_SKELETON''DROP_USEFUL''DUN_9''ELDRITCH_HORROR''EMPTY_MIND''ESCORT''ESCORTS''EVIL''FEMALE''FORCE_DEPTH''FORCE_MAXHP''FORCE_SLEEP''FRIEND''FRIENDS''GENO_NO_THIN''GENO_PERSIST''GIANT''GOOD''HAS_EGG''HAS_LITE''HURT_LITE''HURT_ROCK''IMPRESSED''IM_ACID''IM_COLD''IM_ELEC''IM_FIRE''IM_POIS''IM_PSI''IM_TELE''IM_WATER''INVISIBLE''JOKEANGBAND''KILL_BODY''KILL_ITEM''KILL_TREES''KILL_WALL''MALE''MIMIC''MORTAL''MOVE_BODY''MULTIPLY''NAZGUL''NETHER_REALM''NEUTRAL''NEVER_ACT''NEVER_BLOW''NEVER_MOVE''NONLIVING''NO_AUTORET''NO_BLOCK''NO_CONF''NO_CUT''NO_DEATH''NO_ESCORT''NO_FEAR''NO_NEST''NO_SLEEP''NO_STUN''NO_TARGET''ONLY_DEPTH''ONLY_GOLD''ONLY_ITEM''OOD_10''OPEN_DOOR''ORC''PASS_WALL''PERNANGBAND''PET''PLURAL''POSSESSOR''POWERFUL''PSEUDO_UNIQUE''RAND_25''RAND_5''RAND_50''REFLECTING''REGENERATE''RES_ACID''RES_CHAOS''RES_COLD''RES_DARK''RES_DISE''RES_ELEC''RES_FIRE''RES_LITE''RES_MANA''RES_NETH''RES_NEXU''RES_PLAS''RES_POIS''RES_PSI''RES_SHARDS''RES_SOUND''RES_TELE''RES_TIME''RES_WATE''ROAMING''SHAPECHANGER''SMART''SPECIAL_GENE''SPIDER''STUPID''SUSCEP_ACID''SUSCEP_COLD''SUSCEP_ELEC''SUSCEP_FIRE''S_LOWEXP''TAKE_ITEM''TROLL''UNDEAD''UNIQUE''WEIRD_MIND''WILD_DESERT''WILD_EASY''WILD_GRASS''WILD_MOUNTAIN''WILD_OCEAN''WILD_ONLY''WILD_SHORE''WILD_SWAMP''WILD_TOO''WILD_TOWN''WILD_VOLCANO''WILD_WASTE''WILD_WOOD''WYRM_PROTECT''ZANGBAND');
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html><head><title>List of flags | TomeNET monster search</title></head><body bgcolor=#ffffff><h1>List of flags used in r_info.txt</h1><table border=0 cellpadding=0 cellspacing=1 width=100%><tr>
<?php
for ($i 0$n count($flags); $i $n; ++$i)
{
    echo(
'<td>' $flags[$i] . '</td>');
    if ((
$i 1) % == 0)
    {
        echo (
'</tr><tr>');
    }
}
?>
</tr></table>
<p><a href="javascript: history.go(-1)">Back</a></p>
</body></html>

index.php

<?php

$r_info_file 
'r_info.txt.gz';

require(
'common.inc.php');

// Set the timezone for date()
date_default_timezone_set('UTC');

?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<title>TomeNET monster search</title>
<link rel="stylesheet" href="monsters.css" type="text/css">
</head>
<body>
<h1>TomeNET monster search</h1>
<p><form action="<?php echo(htmlspecialchars(basename(__FILE__))); ?>" name="s" method="GET">

<?php
$get_values 
= array(
    
'name''char''color''level_min''level_max''hp_min''hp_max''spell_chance_min',
    
'spell_chance_max''spells''flags''description'
);
$htmlvalues = array();

// Try to load any previously submitted values
foreach ($get_values as $name) {
    if (isset(
$_GET[$name])) {
        
$htmlvalues[$name] = htmlspecialchars(parse_gpc($_GET[$name]));
    } else {
        
$htmlvalues[$name] = '';
    }
}

echo(
'<b>Name:</b> <input type="text" name="name" id="monster_name" autofocus value="' $htmlvalues['name'] . '">
<b>Character:</b> <input type="text" name="char" size="2" maxlength="1" value="' 
$htmlvalues['char'] . '">
<b>Color:</b> <input type="text" name="color" size="2" maxlength="1" value="' 
$htmlvalues['color'] . '"><br><br>');

// Default ticks for the checkboxes
if (!isset($_GET['type']) || !is_array($_GET['type'])) {
    
$_GET['type'] = array('base''zang''cthulhu''pern''blue''none');
}

$type_base in_array('base'$_GET['type']);
$type_zang in_array('zang'$_GET['type']);
$type_cthulhu in_array('cthulhu'$_GET['type']);
$type_pern in_array('pern'$_GET['type']);
$type_blue in_array('blue'$_GET['type']);
$type_joke in_array('joke'$_GET['type']);
$type_none in_array('none'$_GET['type']);

echo(
"<b>Monster type:</b>\n");
if (
$type_base) echo('<input type="checkbox" name="type[]" id="base" value="base" CHECKED>');
else echo(
'<input type="checkbox" name="type[]" id="base" value="base">');
echo(
'<label for="base"><span style="background-color: #B7FFB4">Base</span></label>');
if (
$type_zang) echo('<input type=checkbox name="type[]" id="zang" value="zang" CHECKED>');
else echo(
'<input type=checkbox name="type[]" id="zang" value="zang">');
echo(
'<label for="zang"><span style="background-color: #FFFFB4">Zangband</span></label>');
if (
$type_cthulhu) echo('<input type=checkbox name="type[]" id="cthulhu" value="cthulhu" CHECKED>');
else echo(
'<input type=checkbox name="type[]" id="cthulhu" value="cthulhu">');
echo(
'<label for="cthulhu"><span style="background-color: #B4FFF6">Cthulhu</span></label>');
if (
$type_pern) echo('<input type=checkbox name="type[]" id="pern" value="pern" CHECKED>');
else echo(
'<input type=checkbox name="type[]" id="pern" value="pern">');
echo(
'<label for="pern"><span style="background-color: #FFB4E0">Pernband</span></label>');
if (
$type_blue) echo('<input type=checkbox name="type[]" id="blue" value="blue" CHECKED>');
else echo(
'<input type=checkbox name="type[]" id="blue" value="blue">');
echo(
'<label for="blue"><span style="background-color: #B4B9FF">Blueband</span></label>');
if (
$type_joke) echo('<input type=checkbox name="type[]" id="joke" value="joke" CHECKED>');
else echo(
'<input type=checkbox name="type[]" id="joke" value="joke">');
echo(
'<label for="joke"><span style="background-color: #FFE6B4">Joke</span></label>');
if (
$type_none) echo('<input type=checkbox name="type[]" id="none" value="none" CHECKED>');
else echo(
'<input type=checkbox name="type[]" id="none" value="none">');
echo(
'<label for="none"><span style="background-color: #FFE6B4">None</span></label><br><br>');

echo(
'<table border="0" cellpadding="0" cellspacing="2">
<col>
<col width="30">
<col>
<col width="30">
<col>
<tr>
    <td><input type="text" name="level_min" size="5" maxlength="3" value="' 
$htmlvalues['level_min'] . '"></td>
    <td align="center">&#8804;</td>
    <td align="center"><b>Level</b></td>
    <td align="center">&#8804;</td><td><input type="text" name="level_max" size="5" maxlength="3" value="' 
$htmlvalues['level_max'] . '"></td>
</tr>
<tr>
    <td><input type="text" name="hp_min" size="5" maxlength="5" value="' 
$htmlvalues['hp_min'] . '"></td>
    <td align="center">&#8804;</td>
    <td align="center"><b>HP</b></td>
    <td align="center">&#8804;</td>
    <td><input type="text" name="hp_max" size="5" maxlength="5" value="' 
$htmlvalues['hp_max'] . '"></td>
</tr>
<tr>
    <td><input type="text" name="spell_chance_min" size="5" maxlength="2" value="' 
$htmlvalues['spell_chance_min'] . '"></td>
    <td align="center">&#8804;</td>
    <td align="center"><b>1_IN_x</b></td>
    <td align="center">&#8804;</td>
    <td><input type="text" name="spell_chance_max" size="5" maxlength="2" value="' 
$htmlvalues['spell_chance_max'] . '"><br></td>
</tr>
</table>

<table border="0" cellpadding="0" cellspacing="2">
<col width="100">
<col>
<tr>
    <td><b>Spells:</b></td>
    <td><input type="text" name="spells" value="' 
$htmlvalues['spells'] . '" size="40"></td>
</tr>
<tr>
    <td>&nbsp;</td>
    <td><small>(e.g. BR_NETH (breaths nether) or !S_HI_DRAGON (doesn\'t summon high dragons)) (<a href="spells.php">list of spells</a>)</small></td>
</tr>
<tr>
    <td><b>Flags:</b></td>
    <td><input type="text" name="flags" value="' 
$htmlvalues['flags'] . '" size="40"></td>
</tr>
<tr>
    <td>&nbsp;</td>
    <td><small>(e.g. ATTR_MULTI (multi-colored) or !UNIQUE (not unique)) (<a href="flags.php">list of flags</a>)</small></td>
</tr>
<tr>
    <td><b>Description:</b></td>
    <td><input type="text" name="description" value="' 
$htmlvalues['description'] . '" size="40"></td>
</tr>
</table>'
);

?>

<input type="submit" name="submit" value="Search">
<input type="reset" name="reset" value="Reset">
</form>

<p><a href="../index.php">Back to mikaelh's TomeNET site</a></p>

<?php
/* Flush before loading the monsters */
flush();

/* Load the monsters (takes some time ...) */
require('parser.php');

function 
filter_monsters_by_name_contains_string(&$monsters$value) {
    
$parts explode(' '$value);
    foreach (
$monsters as &$monster) {
        
$name $monster['name'];
        foreach (
$parts as $part) {
            if (
stripos($name$part) === FALSE) {
                
$monster['matches'] = FALSE;
                continue(
2);
            }
        }
    }
}

function 
filter_monsters_by_string_match(&$monsters$key$value) {
    foreach (
$monsters as &$monster) {
        if (
$monster[$key] != $value) {
            
$monster['matches'] = FALSE;
        }
    }
}

function 
filter_monsters_by_type(&$monsters$allowed_types_bitmask) {
    foreach (
$monsters as &$monster) {
        if (!(
$monster['type_bit'] & $allowed_types_bitmask)) {
            
$monster['matches'] = FALSE;
        }
    }
}

function 
filter_monsters_by_greater_or_equal(&$monsters$key$value) {
    foreach (
$monsters as &$monster) {
        if (
$monster[$key] < $value) {
            
$monster['matches'] = FALSE;
        }
    }
}

function 
filter_monsters_by_less_or_equal(&$monsters$key$value) {
    foreach (
$monsters as &$monster) {
        if (
$monster[$key] > $value) {
            
$monster['matches'] = FALSE;
        }
    }
}

function 
filter_monsters_by_hp_greater_or_equal(&$monsters$value) {
    foreach (
$monsters as &$monster) {
        if (
count_hp_no_tilde($monster) < $value) {
            
$monster['matches'] = FALSE;
        }
    }
}

function 
filter_monsters_by_hp_less_or_equal(&$monsters$value) {
    foreach (
$monsters as &$monster) {
        if (
count_hp_no_tilde($monster) > $value) {
            
$monster['matches'] = FALSE;
        }
    }
}

function 
filter_monsters_by_spells(&$monsters$spells) {
    foreach (
$monsters as &$monster) {
        foreach (
$spells as $spell) {
            if (
$spell{0} == '!') {
                if (
in_array(substr($spell1), $monster['spells'])) {
                    
$monster['matches'] = FALSE;
                    continue(
2);
                }
            } else {
                if (!
in_array($spell$monster['spells'])) {
                    
$monster['matches'] = FALSE;
                    continue(
2);
                }
            }
        }
    }
}

function 
filter_monsters_by_flags(&$monsters$flags) {
    foreach (
$monsters as &$monster) {
        foreach (
$flags as $flag) {
            if (
$flag{0} == '!') {
                if (
in_array(substr($flag1), $monster['flags'])) {
                    
$monster['matches'] = FALSE;
                    continue(
2);
                }
            } else {
                if (!
in_array($flag$monster['flags'])) {
                    
$monster['matches'] = FALSE;
                    continue(
2);
                }
            }
        }
    }
}

function 
filter_monsters_by_desc_contains_string(&$monsters$value) {
    
$parts explode(' '$value);
    foreach (
$monsters as &$monster) {
        
$desc $monster['description'];
        foreach (
$parts as $part) {
            if (
stripos($desc$part) === FALSE) {
                
$monster['matches'] = FALSE;
                continue(
2);
            }
        }
    }
}

function 
get_search_results($monsters) {
    global 
$monster_types_bits;
    
$start microtime(TRUE);

    
// Determine which checkboxes have been ticked
    
if (isset($_GET['type'])) {
        
$GET_type $_GET['type'];
    } else {
        
$GET_type = array();
    }

    if (isset(
$_GET['name']) && strlen(trim($_GET['name'])) > 0) {
        
filter_monsters_by_name_contains_string($monsterstrim(parse_gpc($_GET['name'])));
    }
    if (isset(
$_GET['char']) && strlen(trim($_GET['char'])) > 0) {
        
filter_monsters_by_string_match($monsters'symbol'substr(trim(parse_gpc($_GET['char'])), 01));
    }
    if (isset(
$_GET['color']) && strlen(trim($_GET['color'])) > 0) {
        
filter_monsters_by_string_match($monsters'color'substr(trim(parse_gpc($_GET['color'])), 01));
    }
    if (
count($GET_type) > 0) {
        
$allowed_types_bitmask 0;
        if (
in_array('base'$GET_type)) $allowed_types_bitmask |= $monster_types_bits['BASEANGBAND'];
        if (
in_array('zang'$GET_type)) $allowed_types_bitmask |= $monster_types_bits['ZANGBAND'];
        if (
in_array('cthulhu'$GET_type)) $allowed_types_bitmask |= $monster_types_bits['CTHANGBAND'];
        if (
in_array('pern'$GET_type)) $allowed_types_bitmask |= $monster_types_bits['PERNANGBAND'];
        if (
in_array('blue'$GET_type)) $allowed_types_bitmask |= $monster_types_bits['BLUEBAND'];
        if (
in_array('joke'$GET_type)) $allowed_types_bitmask |= $monster_types_bits['JOKEANGBAND'];
        if (
in_array('none'$GET_type)) $allowed_types_bitmask |= $monster_types_bits['NONEBAND'];
        
filter_monsters_by_type($monsters$allowed_types_bitmask);
    }
    if (isset(
$_GET['level_min']) && strlen(trim($_GET['level_min'])) > 0) {
        
$min_level = (int) $_GET['level_min'];
        
filter_monsters_by_greater_or_equal($monsters'depth'$min_level);
    }
    if (isset(
$_GET['level_max']) && strlen(trim($_GET['level_max'])) > 0) {
        
$max_level = (int) $_GET['level_max'];
        
filter_monsters_by_less_or_equal($monsters'depth'$max_level);
    }
    if (isset(
$_GET['hp_min']) && strlen(trim($_GET['hp_min'])) > 0) {
        
$min_hp = (int) $_GET['hp_min'];
        
filter_monsters_by_hp_greater_or_equal($monsters$min_hp);
    }
    if (isset(
$_GET['hp_max']) && strlen(trim($_GET['hp_max'])) > 0) {
        
$max_hp = (int) $_GET['hp_max'];
        
filter_monsters_by_hp_less_or_equal($monsters$max_hp);
    }
    if (isset(
$_GET['spell_chance_min']) && strlen(trim($_GET['spell_chance_min'])) > 0) {
        
$min_spell_chance = (int) $_GET['spell_chance_min'];
        
filter_monsters_by_greater_or_equal($monsters'spell_chance'$min_spell_chance);
    }
    if (isset(
$_GET['spell_chance_max']) && strlen(trim($_GET['spell_chance_max'])) > 0) {
        
$max_spell_chance = (int) $_GET['spell_chance_max'];
        
filter_monsters_by_less_or_equal($monsters'spell_chance'$max_spell_chance);
    }
    if (isset(
$_GET['spells']) && strlen(trim($_GET['spells'])) > 0) {
        
$spells explode(' 'trim(parse_gpc($_GET['spells'])));
        
$spells_uppercased = array();
        foreach (
$spells as $spell) {
            
$spells_uppercased[] = strtoupper(trim($spell));
        }
        
filter_monsters_by_spells($monsters$spells_uppercased);
    }
    if (isset(
$_GET['flags']) && strlen(trim($_GET['flags'])) > 0) {
        
$flags explode(' 'trim(parse_gpc($_GET['flags'])));
        
$flags_uppercased = array();
        foreach (
$flags as $flag) {
            
$flags_uppercased[] = strtoupper(trim($flag));
        }
        
filter_monsters_by_flags($monsters$flags_uppercased);
    }
    if (isset(
$_GET['description']) && strlen(trim($_GET['description'])) > 0) {
        
filter_monsters_by_desc_contains_string($monsterstrim($_GET['description']));
    }

    
$results = array();
    foreach (
$monsters as $monster) {
        if (
$monster['matches']) {
            
$results[] = $monster;
        }
    }

    
$end microtime(TRUE);
    
//echo(($end - $start) * 1000 . " milliseconds");

    
return $results;
}

function 
show_search_results($results) {
    
$monster_bg_colors_by_type $GLOBALS['monster_bg_colors_by_type'];
    
$start microtime(TRUE);
    
$num_results count($results);
    echo(
'<p><b>Number of results: ' $num_results "</b></p>\n");

    
// Split the list into 3 columns
    
$n_rows ceil($num_results 3);
    
$num_rows = array($n_rows$n_rows$n_rows);

    if (
$num_results == 1) {
        
// Columns 2 and 3 will be shorter
        
$num_rows[1]--;
        
$num_rows[2]--;
    } elseif (
$num_results == 2) {
        
// Column 3 will be shorter
        
$num_rows[2]--;
    }

    
$col_1 = array();
    
$col_2 = array();
    
$col_3 = array();

    for (
$i 0$n $num_rows[0]; $i $n$i++) {
        
$col_1[] = $results[$i];
    }
    for (
$n $num_rows[0] + $num_rows[1]; $i $n$i++) {
        
$col_2[] = $results[$i];
    }
    for (
$n $num_rows[0] + $num_rows[1] + $num_rows[2]; $i $n$i++) {
        
$col_3[] = $results[$i];
    }

    
$cols = array($col_1$col_2$col_3);

    
$output "<p><table border=\"0\" cellpadding=\"0\" cellspacing=\"1\">\n" .
        
"<col width=\"20\"><col width=\"300\"><col width=\"40\">\n" .
        
"<col width=\"20\"><col width=\"300\"><col width=\"40\">\n" .
        
"<col width=\"20\"><col width=\"300\"><col width=\"40\">\n" .
        
"<tr><th>&nbsp;</th><th><b>Name</b></th><th><b>Lvl</b></th><th>&nbsp;</th><th><b>Name</b></th><th><b>Lvl</b></th><th>&nbsp;</th><th><b>Name</b></th><th><b>Lvl</b></th></tr>\n";
    
$n count($results);
    if (
$n$output .= "<tr>\n";
    for (
$i 0$i $n; ++$i) {
        
$result $cols[$i 3][floor($i 3)];

        
$output .= '<td class="symbol" style="color: ' get_hex_color($result) . '">'  $result['symbol'] . '</td><td style="background-color: ' .
            
$monster_bg_colors_by_type[$result['type']] . '"><a href="monster.php?' $result['number'] . '">' htmlspecialchars($result['name']) . '</a></td><td>' $result['depth'] . "</td>\n";

        if ((
$i 1) % == 0) {
            
$output .= "</tr><tr>\n";
        }
    }
    if (
$n$output .= "</tr>\n";
    
$output .= "</table></p>\n";
    echo(
$output);
    
$end microtime(TRUE);
    
//echo(($end - $start) * 1000 . " milliseconds");
}

$results get_search_results($monsters);
show_search_results($results);
?>

<p style="font-size: 0.75em">TomeNET monster search v. 0.1.7<br>
r_info.txt was last updated on <?php echo(date("d.m.Y"filemtime($r_info_file))); ?>.<br>
<a href="source.php">Source code</a>

<script>
document.getElementById('monster_name').focus();
</script>

</body></html>

makeflags.php

<?php
require('parser.php');
$flags = array();

foreach (
$monsters as $monster)
{
    foreach (
$monster['flags'] as $flag)
    {
        if (!
in_array($flag$flags))
        {
            
$flags[] = $flag;
        }
    }
}

sort($flags);

echo(
"\$flags = array('" implode("', '"$flags) . "');\n");
?>

makespells.php

<?php
require('parser.php');
$spells = array();

foreach (
$monsters as $monster)
{
    foreach (
$monster['spells'] as $spell)
    {
        if (!
in_array($spell$spells))
        {
            
$spells[] = $spell;
        }
    }
}

sort($spells);

echo(
"\$spells = array('" implode("', '"$spells) . "');\n");
?>

monster.php

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<link rel="stylesheet" href="monsters.css" type="text/css">
<?php

/* Flush the link to stylesheet before loading monsters */
flush();

require(
'common.inc.php');
require(
'parser.php');

function 
get_depth($l) {
    return((
$l 50) . 'ft');
}

function 
symbol_info($m) {
    if (
array_search('SHAPECHANGER'$m['flags']) !== FALSE) return 'shapechanger';
    if (
array_search('CHAR_CLEAR'$m['flags']) !== FALSE) return 'absorbs symbol';
    return 
'Symbol ' $m['symbol'];
}

function 
color_info($m) {
    if (
array_search('ATTR_MULTI'$m['flags']) !== FALSE && array_search('ATTR_ANY'$m['flags']) !== FALSE) return 'truly multi-colored';
    if (
array_search('ATTR_MULTI'$m['flags']) !== FALSE) return 'multi-colored ' $m['color'];
    if (
array_search('ATTR_CLEAR'$m['flags']) !== FALSE) return 'absorbs color';
    return 
'Color ' $m['color'];
}

function 
show_info_html($m) {
    
$monster_types_desc $GLOBALS['monster_types_desc'];
    echo(
"<div class=\"monster\">\n");
    echo(
"<h1>" $m['name'] . "</h1>\n");

    echo(
"<span class=\"header\">Id:</span> " $m['number']);
    echo(
" <span class=\"header\">Name:</span> " $m['name'] . " <span class=\"symbol\" style=\"color: " get_hex_color($m) . "\">&nbsp;"  $m['symbol'] . "&nbsp;</span> (" symbol_info($m) . ", " color_info($m) .")<br>\n");

    
// Some monsters lack a description
    
echo("<span class=\"header\">Description:</span> " $m['description'] . "<br>\n");

    echo(
"<span class=\"header\">Type:</span> " $monster_types_desc[$m['type']]);
    echo(
" <span class=\"header\">Unique:</span> " is_unique($m) . "<br>\n");

    echo(
"<span class=\"header\">HP:</span> " count_hp($m) . " (" $m['hp'] . ")");
    echo(
" <span class=\"header\">AC:</span> " $m['ac']);
    echo(
" <span class=\"header\">Experience:</span> " $m['exp']);
    echo(
" <span class=\"header\">Speed:</span> " $m['speed'] . "<br>\n");

    echo(
"<span class=\"header\">Depth:</span> " $m['depth'] . " (" get_depth($m['depth']) . ")");
    echo(
" <span class=\"header\">Rarity:</span> " $m['rarity']);
    echo(
" <span class=\"header\">Vision:</span> " $m['vision']);
    echo(
" <span class=\"header\">Alertness:</span> " $m['alertness'] . "<br>\n");

    echo(
"<span class=\"header\">Body:</span><br>");
    echo(
"<div class=\"sub\">\n");
    echo(
"<span class=\"header\">Weight:</span> " $m['weight']);
    echo(
" <span class=\"header\">Weapons:</span> " $m['weapons']);
    echo(
" <span class=\"header\">Torso:</span> " $m['torso']);
    echo(
" <span class=\"header\">Arm:</span> " $m['arms']);
    echo(
" <span class=\"header\">Finger:</span> " $m['finger']);
    echo(
" <span class=\"header\">Head:</span> " $m['head']);
    echo(
" <span class=\"header\">Leg:</span> " $m['leg'] . "<br>\n");
    echo(
"</div>\n");

    echo(
"<span class=\"header\">Objects:</span><br>\n");
    echo(
"<div class=\"sub\">\n");
    echo(
"<span class=\"header\">Treasure:</span> " $m['treasure']);
    echo(
" <span class=\"header\">Combat:</span> "  $m['combat']);
    echo(
" <span class=\"header\">Magic:</span> " $m['magic']);
    echo(
" <span class=\"header\">Tool:</span> " $m['tool'] . "<br>\n");
    echo(
"</div>\n");

    echo(
"<span class=\"header\">Attack methods:</span><br>\n");
    foreach (
$m['attacks'] as $a) {
        echo(
"\t<div style=\"padding-left: 1em;\">");
        echo(
$a['method'] . ": ");
        echo(
$a['effect']);
        if (!empty(
$a['damage'])) echo(" (" $a['damage'] . ")");
        echo(
"</div>\n");
    }

    if (
$m['spell_chance'] != 0) {
        echo(
"<span class=\"header\">Spell chance:</span> 1 spell every " $m['spell_chance'] . " turns (1_IN_" $m['spell_chance'] . ")<br>\n");
    }
    echo(
"<span class=\"header\">Spells (and breaths, arrows or missiles): (" count($m['spells']) . ")</span><br>\n");
    echo(
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
    echo(
"\t<col width=\"200\">\n");
    echo(
"\t<col width=\"200\">\n");
    echo(
"\t<col width=\"200\">\n");
    echo(
"\t<tr>\n");
    
$i 0;
    foreach (
$m['spells'] as $s) {
        echo(
"\t\t<td>" $s "</td>\n");
        if (!(++
$i 3)) echo("\t</tr>\n\t<tr>\n");
    }
    while (
$i 3) {
        echo(
"\t\t<td>&nbsp;</td>\n");
        ++
$i;
    }
    echo(
"\t</tr>\n</table>\n");

    echo(
"<span class=\"header\">Flags: (" count($m['flags']) . ")</span><br>\n");
    echo(
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n");
    echo(
"\t<col width=\"200\">\n");
    echo(
"\t<col width=\"200\">\n");
    echo(
"\t<col width=\"200\">\n");
    echo(
"\t<tr>\n");
    
$i 0;
    foreach (
$m['flags'] as $f) {
        echo(
"\t\t<td>" $f "</td>\n");
        if (!(++
$i 3)) echo("\t</tr>\n\t<tr>\n");
    }
    while (
$i 3) {
        echo(
"\t\t<td>&nbsp;</td>\n");
        ++
$i;
    }
    echo(
"\t</tr>\n</table>\n");
    echo(
"</div>\n");
}

if (
array_key_exists($_SERVER['QUERY_STRING'], $monsters)) {
    
$monster $monsters[$_SERVER['QUERY_STRING']];
?>
<title><?php echo(htmlentities($monster['name'])) ?> | TomeNET monster search</title>
</head>
<body>
<?php show_info_html($monster); ?>
<a href="javascript: history.go(-1)">Back</a>
</body></html>
<?php
} else {
    
header('Location: http://muuttuja.org/tomenet/monsters/');
}
?>

parser.php

<?php

/* TomeNET r_info.txt parser by mikaelh */

/* Some settings */
if (!isset($server_settings)) $server_settings = array('RPG_SERVER''ENABLE_MAIA');
if (!isset(
$use_compression)) $use_compression TRUE;
if (!isset(
$use_serialized)) $use_serialized FALSE;

if (!isset(
$r_info_file)) {
    
$r_info_file 'r_info.txt';
    if (
$use_compression$r_info_file .= '.gz';
}

$found_serialized FALSE;

if (
$use_serialized) {
    if (
substr($r_info_file, -3) == '.gz') {
        
$serialized_file basename($r_info_file'.gz') . '.serialized.gz';
    } else {
        
$serialized_file $r_info_file '.serialized';
    }

    if (
file_exists($serialized_file)) {
        
$found_serialized TRUE;
        
$r_info_file $serialized_file;
    }
}

if (
file_exists($r_info_file)) {
    
$r_info_contents "";
    if (
$use_compression) {
        
$fp gzopen($r_info_file'rb');

        if (
$fp === FALSE) {
            echo(
'ERROR in ' __FILE__ ' on line ' __LINE__ ': File ' $r_info_file "could not be opened\n");
            die();
        }

        while (!
gzeof($fp)) {
            
$r_info_contents .= gzread($fp8192);
        }

        
gzclose($fp);
    } else {
        
$fp fopen($r_info_file'rb');

        if (
$fp === FALSE) {
            echo(
'ERROR in ' __FILE__ ' on line ' __LINE__ ': File ' $r_info_file "could not be opened\n");
            die();
        }

        while (!
feof($fp)) {
            
$r_info_contents .= fread($fp8192);
        }

        
fclose($fp);
    }
} else {
    echo(
'ERROR in ' __FILE__ ' on line ' __LINE__ ': File ' $r_info_file " doesn't exists!\n");
    die();
}

$monster_types_enum = array(
    
'NONEBAND' => 0,
    
'BASEANGBAND' => 1,
    
'ZANGBAND' => 2,
    
'CTHANGBAND' => 3,
    
'JOKEANGBAND' => 4,
    
'PERNANGBAND' => 5,
    
'BLUEBAND' => 6,
);

$monster_types_bits = array(
    
'BASEANGBAND' => 0x01,
    
'ZANGBAND' => 0x02,
    
'CTHANGBAND' => 0x04,
    
'JOKEANGBAND' => 0x08,
    
'PERNANGBAND' => 0x10,
    
'BLUEBAND' => 0x20,
    
'NONEBAND' => 0x40,
);

function 
parse_r_info($r_info_contents$server_settings) {
    global 
$info_version;
    
$monster_types_enum $GLOBALS['monster_types_enum'];
    
$monster_types_bits $GLOBALS['monster_types_bits'];
    
$r_info explode("\n"$r_info_contents);

    
$monsters = array();
    
$cur_monster = -1;
    
$cur_attack 0;

    
// Defaults for monster entries
    // Description is empty
    // No body parts
    // 20% chance for object drop rates
    // Empty arrays for attacks, flags and spells
    
$monster_defaults = array(
        
'number' => 0,
        
'name' => NULL,

        
'symbol' => NULL,
        
'color' => NULL,

        
'speed' => 0,
        
'hp' => NULL,
        
'vision' => 0,
        
'ac' => 0,
        
'alertness' => 0,

        
'depth' => 0,
        
'rarity' => 0,
        
'weight' => 0,
        
'exp' => 0,

        
'treasure' => 20,
        
'combat' => 20,
        
'magic' => 20,
        
'tool' => 20,

        
'weapons' => 0,
        
'torso' => 0,
        
'arms' => 0,
        
'finger' => 0,
        
'head' => 0,
        
'leg' => 0,

        
'description' => '',

        
'attacks' => array(),
        
'flags' => array(),
        
'spells' => array(),

        
'spell_chance' => 0,
        
'type' => 0,
        
'type_bit' => $monster_types_bits['NONEBAND'],

        
'matches' => TRUE,
    );
    
$monster $monster_defaults;

    foreach (
$r_info as $row) {
        
$row trim($row);

        if (empty(
$row) || $row[0] == '#') {
            continue;
        }

        while (
$row[0] == '$') {
            
/* Process a server setting condition */
            
$next_dol strpos($row'$'1);
            
$next_neg strpos($row'!'1);

            if ((
$next_neg === FALSE || $next_neg $next_dol) && $next_dol !== FALSE) {
                if (
$next_dol === FALSE) {
                    echo(
'ERROR in ' __FILE__ ' on line ' __LINE__ ": Invalid server setting condition\n");
                    echo(
$row "\n");
                    die();
                }

                
$negation FALSE;
                
$server_cond substr($row1$next_dol 1);
                
$row substr($row$next_dol 1);
            } else {
                
$negation TRUE;
                
$server_cond substr($row1$next_neg 1);
                
$row substr($row$next_neg 1);
            }

            if (!
in_array($server_cond$server_settings) ^ $negation) {
                continue;
            }
        }

        if (
$row[1] == ':') {
            
$row_type $row[0];
            
$row_data explode(':'$row);

            switch (
$row_type) {
                case 
'V':
                    
$info_version substr($row2);
                    break;

                case 
'N':
                    
// store previous monster
                    
if ($cur_monster >= 0) {
                        
$monsters[$cur_monster] = $monster;
                    }
                    
$cur_monster = (int) $row_data[1];
                    
$cur_attack 0;

                    
$monster $monster_defaults;

                    
$monster['number'] = (int) $row_data[1];
                    
$monster['name'] = $row_data[2];
                    break;

                case 
'G':
                    
$monster['symbol'] = $row_data[1];
                    
$monster['color'] = $row_data[2];
                    break;

                case 
'I':
                    
$monster['speed'] = (int) $row_data[1];
                    
$monster['hp'] = $row_data[2];
                    
$monster['vision'] = (int) $row_data[3];
                    
$monster['ac'] = (int) $row_data[4];
                    
$monster['alertness'] = (int) $row_data[5];
                    break;

                case 
'W':
                    
$monster['depth'] = (int) $row_data[1];
                    
$monster['rarity'] = (int) $row_data[2];
                    
$monster['weight'] = (int) $row_data[3];
                    
$monster['exp'] = (int) $row_data[4];
                    break;

                case 
'E':
                    
$monster['weapons'] = (int) $row_data[1];
                    
$monster['torso'] = (int) $row_data[2];
                    
$monster['arms'] = (int) $row_data[3];
                    
$monster['finger'] = (int) $row_data[4];
                    
$monster['head'] = (int) $row_data[5];
                    
$monster['leg'] = (int) $row_data[6];
                    break;

                case 
'O':
                    
$monster['treasure'] = (int) $row_data[1];
                    
$monster['combat'] = (int) $row_data[2];
                    
$monster['magic'] = (int) $row_data[3];
                    
$monster['tool'] = (int) $row_data[4];
                    break;

                case 
'B':
                    
$monster['attacks'][$cur_attack++] = array('method' => $row_data[1], 'effect' => $row_data[2], 'damage' => isset($row_data[3]) ? $row_data[3] : NULL);
                    break;

                case 
'F':
                    
$flags explode('|'$row_data[1]);
                    foreach (
$flags as $flag)
                    {
                        
$flag trim($flag);
                        if (empty(
$flag)) continue;
                        
$monster['flags'][] = $flag;
                        if (isset(
$monster_types_enum[$flag])) {
                            
$monster['type'] = $monster_types_enum[$flag];
                            
$monster['type_bit'] = $monster_types_bits[$flag];
                        }
                    }
                    break;

                case 
'S':
                    
$spells explode('|'$row_data[1]);
                    foreach (
$spells as $spell)
                    {
                        
$spell trim($spell);
                        if (empty(
$spell)) continue;
                        if (
strpos($spell'1_IN_') !== FALSE)
                        {
                            
$monster['spell_chance'] = (int) substr($spell5);
                            continue;
                        }
                        
$monster['spells'][] = $spell;
                    }
                    break;

                case 
'D':
                    if (
$monster['description'] != '')
                    {
                        
$monster['description'] .= "\n" substr($row2);
                    } else {
                        
$monster['description'] = substr($row2);
                    }
                    break;

                default:
                    echo(
"WARNING: Unknown row type in r_info.txt: $row_type\n");
            }
        }
    }

    
// store last monster
    
if ($cur_monster >= 0) {
        
$monsters[$cur_monster] = $monster;
    }

    
// HACK - Replace NULL value for "Player"
    
$monsters[0]['hp'] = '1d1';

    return 
$monsters;
}

if (
$use_serialized && $found_serialized) {
    
$monsters unserialize($r_info_contents);
} else {
    
$monsters parse_r_info($r_info_contents$server_settings);
}

/* Don't pollute the enviroment */
unset($r_info_contents);

?>

r_info_sort.php

<?php
$use_compression 
FALSE;

require(
'parser.php');

function 
monster_level_sort($a$b) {
    if (
array_key_exists('depth'$a) < array_key_exists('depth'$b)) {
        return -
1;
    }
    elseif (
array_key_exists('depth'$a) > array_key_exists('depth'$b)) {
        return 
1;
    }
    elseif (
$a['depth'] < $b['depth']) {
        return -
1;
    }
    elseif (
$a['depth'] > $b['depth']) {
        return 
1;
    }
    elseif (
$a['number'] < $b['number']) {
        return -
1;
    }
    elseif (
$a['number'] > $b['number']) {
        return 
1;
    }
    else {
        return 
0;
    }
}

usort($monsters'monster_level_sort');

$fp fopen('r_info_sorted.txt''w');
fwrite($fp'V:' $info_version "\n");

foreach (
$monsters as $m) {
    
fwrite($fp'N:' $m['number'] . ':' $m['name'] . "\n");
    
fwrite($fp'G:' $m['symbol'] . ':' $m['color'] . "\n");
    if (isset(
$m['speed'])) fwrite($fp'I:' $m['speed'] . ':' $m['hp'] . ':' $m['vision'] . ':' $m['ac'] . ':' $m['alertness'] . "\n");
    
fwrite($fp'W:' $m['depth'] . ':' $m['rarity'] . ':' $m['weight'] . ':' $m['exp'] . "\n");
    if (isset(
$m['weapons'])) fwrite($fp'E:' $m['weapons'] . ':' $m['torso'] . ':' .  $m['arms'] . ':' $m['finger'] . ':' $m['head'] . ':' $m['leg'] . "\n");
    if (isset(
$m['treasure'])) fwrite($fp'O:' $m['treasure'] . ':' $m['combat'] . ':' $m['magic'] . ':' $m['tool'] . "\n");
    foreach (
$m['attacks'] as $a) {
        if (!empty(
$a['damage'])) {
            
fwrite($fptrim('B:' $a['method'] . ':' $a['effect'] . ':' $a['damage']) . "\n");
        } else {
            
fwrite($fptrim('B:' $a['method'] . ':' $a['effect']) . "\n");
        }
    }
    if (
count($m['flags']) > 0fwrite($fp'F:' implode('|'$m['flags']) . "\n");
    if (!empty(
$m['spell_chance'])) fwrite($fp'S:1_IN_' $m['spell_chance'] . "\n");
    if (
count($m['spells']) > 0fwrite($fp'S:' implode('|'$m['spells']) . "\n");
    if (!empty(
$m['description'])) {
        foreach (
explode("\n"$m['description']) as $d) {
            
fwrite($fp'D:' $d "\n");
        }
    }
}
?>

spells.php

<?php
$spells 
= array('ARROW_1''ARROW_2''ARROW_3''ARROW_4''BA_ACID''BA_CHAO''BA_COLD''BA_DARK''BA_ELEC''BA_FIRE''BA_MANA''BA_NETH''BA_NUKE''BA_POIS''BA_WATE''BLIND''BLINK''BOULDER''BO_ACID''BO_COLD''BO_DISE''BO_ELEC''BO_FIRE''BO_ICEE''BO_MANA''BO_NETH''BO_PLAS''BO_POIS''BO_WATE''BRAIN_SMASH''BR_ACID''BR_CHAO''BR_COLD''BR_CONF''BR_DARK''BR_DISE''BR_DISI''BR_ELEC''BR_FIRE''BR_GRAV''BR_INER''BR_LITE''BR_MANA''BR_NETH''BR_NEXU''BR_NUKE''BR_PLAS''BR_POIS''BR_SHAR''BR_SOUN''BR_TIME''BR_WALL''CONF''CURSE''DARKNESS''DRAIN_MANA''FORGET''HASTE''HEAL''HOLD''MIND_BLAST''MISSILE''MOAN''RAISE_DEAD''ROCKET''SCARE''SHRIEK''SLOW''S_ANGEL''S_ANIMAL''S_ANIMALS''S_ANT''S_BUG''S_DEMON''S_DRAGON''S_DRAGONRIDER''S_HI_DEMON''S_HI_DRAGON''S_HI_MONSTERS''S_HI_UNDEAD''S_HI_UNIQUE''S_HOUND''S_HYDRA''S_KIN''S_MONSTER''S_MONSTERS''S_NAZGUL''S_RNG''S_SPIDER''S_UNDEAD''S_UNIQUE''TELE_AWAY''TELE_LEVEL''TELE_TO''TPORT''TRAPS''UNMAGIC');
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html><head><title>List of spells | TomeNET monster search</title></head><body bgcolor=#ffffff><h1>List of spells used in r_info.txt</h1><table border=0 cellpadding=0 cellspacing=1 width=100%><tr>
<?php
for ($i 0$n count($spells); $i $n$i++)
{
    echo(
'<td>' $spells[$i] . '</td>');
    if ((
$i 1) % == 0)
    {
        echo (
'</tr><tr>');
    }
}
?>
</tr></table>
<p><a href="javascript: history.go(-1)">Back</a></p>
</body></html>