map.php
<?php
 
###########################################################################
##  Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3      ##
###########################################################################
## This is a script that reads the positions of characters from a mangos ##
## database and then, using a previously calibrated map image, plots the ##
## global position of those characters and returns the resulting image.  ##
###########################################################################

###########################################################################
##                            CONFIGURATION                              ##
###########################################################################

# The configuration file for this script containing the settings.
include_once("config.php");
 
###########################################################################
##                               INTERNALS                               ##
###########################################################################

class Point {
    public $x;
    public $y;
 
    function __construct($x, $y) {
        $this->x = $x;
        $this->y = $y;
    }
}
 
class Character {
    public $x;
    public $y;
    public $map;
    public $class;
    public $race;
 
    function __construct($x, $y, $map, $class, $race) {
        $this->x = $x;
        $this->y = $y;
        $this->map = $map;
        $this->class = $class;
        $this->race = $race;
    }
}
 
class GPS {
 
    private $gps = array();
 
    function __construct($gps) {
        $this->gps = $gps;
    }
 
    public function getPixel($x, $y, $map) {
        return new Point(
            $this->mapValueToRange(
                $y, 
                $this->gps[$map]['y']['wow'],
                $this->gps[$map]['Y']['wow'],
                $this->gps[$map]['X']['img'],
                $this->gps[$map]['x']['img']
            ),
            $this->mapValueToRange(
                $x, 
                $this->gps[$map]['x']['wow'],
                $this->gps[$map]['X']['wow'],
                $this->gps[$map]['Y']['img'],
                $this->gps[$map]['y']['img']
            )
        );
    }
 
    ###########################################################################
    ##  Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3      ##
    ###########################################################################
    private function mapValueToRange($value, $xMin, $xMax, $yMin, $yMax) {
        return $yMin + (
            (
                $yMax - $yMin
            ) 
            *
            (
                $value - $xMin
            )
            /
            (
                $xMax - $xMin
            )
        );
    }
}
 
###########################################################################
##  Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3      ##
###########################################################################
function wasResizePNG($img, $w, $h) {
    $width = imagesx($img);
    $height = imagesy($img);
    $new = imagecreatetruecolor($w, $h);
    imagecolortransparent(
        $new,
        imagecolorallocate(
            $new,
            0,
            0,
            0
        )
    );
    imagecopyresampled(
        $new,
        $img,
        0,
        0,
        0,
        0,
        $w,
        $h,
        $width, 
        $height
    );
    imagedestroy($img);
    return $new;
}
 
###########################################################################
##  Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3      ##
###########################################################################
function wasAddBorderPNG($img, $size, $color) {
    $width = imagesx($img);
    $height = imagesy($img);
 
    $img_adj_width = $width + (2 * $size);
    $img_adj_height = $height + (2 * $size);
 
    $new = imagecreatetruecolor(
        $img_adj_width,
        $img_adj_height
    );     
    imagecolortransparent(
        $new,
        imagecolorallocate(
            $new,
            0,
            0,
            0
        )
    );
 
    $color = imagecolorallocate(
        $new,
        $color['red'],
        $color['green'],
        $color['blue']
    );
    imagefilledrectangle(
        $new,
        0,
        0,
        $img_adj_width,
        $img_adj_height,
        $color
    );
    imagecopyresized(
        $new,
        $img,
        $size,
        $size,
        0,
        0,
        $width,
        $height,
        $width,
        $height
    );
    imagedestroy($img);
    return $new;
 
}
 
####
# I. Create a new World of Warcraft - Zero calibrated GPS map.
$gps = new GPS($CALIBRATED_MAP);
 
####
# II. Query all the online users, their 2D position and the map they are on.
$characters = array();
try {
    $db = new PDO('mysql:host='.$DATABASE_HOSTNAME.';dbname='.$DATABASE_NAME.';', $DATABASE_USERNAME, $DATABASE_PASSWORD);
    $db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
    $q = $db->prepare("SELECT position_x,position_y,map,class,race FROM $DATABASE_NAME.characters WHERE online=1");
    $q->execute();
    foreach($q->fetchAll(PDO::FETCH_ASSOC) as $row) {
        array_push(
            $characters,
            new Character(
                $row['position_x'],
                $row['position_y'],
                $row['map'],
                $row['class'],
                $row['race']
            )
        );
    }
}
catch(PDOException $e) {
    print $e->getMessage();
    return;
}
 
####
# III. Output the Base64 encoded image for AJAX.
ob_start();
 
$img = imagecreatefrompng($IMAGE_DIRECTORY_PATH.'/'.$MAP_IMAGE);
imagealphablending($img, false);
imagesavealpha($img, true);
 
####
# IV. Plot all characters on the map.
array_walk($characters,
    function($character) use($gps, $img, $ALLEGIANCE, $ALLEGIANCE_COLOR, $ALLEGIANCE_BORDER_SIZE, $CLASS_ICON_SIZE, $IMAGE_DIRECTORY_PATH) { 
        $ico = wasAddBorderPNG(
            wasResizePNG(
                imagecreatefrompng(
                    $IMAGE_DIRECTORY_PATH.'/'.$character->class.'.png'
                ),
                $CLASS_ICON_SIZE['x'],
                $CLASS_ICON_SIZE['y']
            ),
            $ALLEGIANCE_BORDER_SIZE,
            $ALLEGIANCE_COLOR[
                array_shift(
                    array_keys(
                        array_filter(
                            $ALLEGIANCE,
                            function($a) use (&$character) {
                                return array_search($character->race, $a) !== FALSE;
                            }
                        )
                    )
                )
            ]
        );
        $pix = $gps->getPixel($character->x, $character->y, $character->map);
        imagecopymerge(
            $img,
            $ico,
            $pix->x - imagesx($ico)/2,
            $pix->y - imagesy($ico)/2,
            0,
            0,
            imagesx($img),
            imagesy($img),
            100
        );
        imagedestroy($ico);
    }
);
 
imagepng($img);
$png = ob_get_contents();
imagedestroy($img);
ob_end_clean();
 
####
# V. Dump the Base64 encoded map.
echo base64_encode($png);
 
?>