Last modified : 2024-11-25 19:41:37 UTC
<?php

if (isset($_GET['src']) && $_GET['src'] == 'show') {
    echo 
"<b>Last modified :</b> ".date("Y-m-d H:i:s"filemtime(__FILE__))." UTC<br>\n";
    echo 
"<div style=\"font-size: 12px;\">\n";
    
highlight_string(file_get_contents(__FILE__));
    print 
"</div>\n";
    exit;
}


if (
$_SERVER['HTTP_HOST'] == 'ryapp') {
    
error_reporting(E_ALL);
    
ini_set('display_errors'true);
} else {
    
error_reporting(0);
    
ini_set('display_errors'false);
}

use 
Ryzom\Common\EGender;
use 
Ryzom\Common\EVisualSlot;
use 
Ryzom\Common\TPeople;

if (!
function_exists('_h')) {
    function 
_h($str)
    {
        return 
htmlspecialchars($str);
    }
}
function 
__($sheet$lang LANG)
{
    return 
_h(ryzom_translate($sheet$lang));
}

require 
__DIR__ '/../vendor/autoload.php';

//
// form
//
$form = [
    
'language' => is($_REQUEST['language'], is($_GET['lang'], 'en')),
    
'zoom' => is($_REQUEST['zoom'], 'body'),
    
'dir' => (int) is($_REQUEST['dir'], 0),
    
//
    
'age' => clamp((int) is($_REQUEST['age'], 0), 02),
    
'race' => clamp((int) is($_REQUEST['race'], 0), 03),
    
'gender' => clamp((int) is($_REQUEST['gender'], 0), 01),
    
'eyes' => clamp((int) is($_REQUEST['eyes'], 0), 06),
    
'tattoo' => (int) is($_REQUEST['tattoo'], 0),
    
'haircut' => (int) is($_REQUEST['haircut'], 0),
    
'haircolor' => (int) is($_REQUEST['haircolor'], 0),
    
//
    
'chest' => ['item' => (int) is($_REQUEST['slot1']['item'], 0), 'color' => (int) is($_REQUEST['slot1']['color'], 0)],
    
'head' => ['item' => (int) is($_REQUEST['slot3']['item'], 0), 'color' => (int) is($_REQUEST['slot3']['color'], 0)],
    
'legs' => ['item' => (int) is($_REQUEST['slot2']['item'], 0), 'color' => (int) is($_REQUEST['slot2']['color'], 0)],
    
'arms' => ['item' => (int) is($_REQUEST['slot4']['item'], 0), 'color' => (int) is($_REQUEST['slot4']['color'], 0)],
    
'hands' => ['item' => (int) is($_REQUEST['slot6']['item'], 0), 'color' => (int) is($_REQUEST['slot6']['color'], 0)],
    
'feet' => ['item' => (int) is($_REQUEST['slot7']['item'], 0), 'color' => (int) is($_REQUEST['slot7']['color'], 0)],
    
//
    
'handr' => (int) is($_REQUEST['slot8'], 0),
    
'handl' => (int) is($_REQUEST['slot9'], 0),
    
//
    
'gabarit' => [
        (int) 
is($_REQUEST['gabarit'][0], 7),// char height
        
(int) is($_REQUEST['gabarit'][1], 7),// torso width
        
(int) is($_REQUEST['gabarit'][2], 7),// arms width
        
(int) is($_REQUEST['gabarit'][3], 7),// legs width
        
(int) is($_REQUEST['gabarit'][4], 7),// breast size
    
],
    
'morph' => [
        (int) 
is($_REQUEST['morph'][0], 3),// morph target 1, uiFace1Fy, uiFace1Ma, uiFace1Tr, uiFace1Zo
        
(int) is($_REQUEST['morph'][1], 3),// morph target 2
        
(int) is($_REQUEST['morph'][2], 3),// morph target 3
        
(int) is($_REQUEST['morph'][3], 3),// morph target 4
        
(int) is($_REQUEST['morph'][4], 3),// morph target 5
        
(int) is($_REQUEST['morph'][5], 3),// morph target 6
        
(int) is($_REQUEST['morph'][6], 3),// morph target 7
        
(int) is($_REQUEST['morph'][7], 3),// morph target 8
    
]
];

if (!
in_array($form['zoom'], ['body''portrait'])) {
    
$form['zoom'] = 'body';
}

$form['language'] = (in_array($form['language'], ['en''fr''de''ru''es'])) ? $form['language'] : 'en';
define('LANG'$form['language']);

//
// build character
//
$char = new \Rrs\Character();
$char->setRace($form['race']);
$char->setAge($form['age']);
$char->setDirection($form['dir']);
$char->setGabarit($form['gabarit']);
$char->setGender($form['gender']);
$char->setMorph($form['morph']);
$char->setSlot(EVisualSlot::FACE_SLOT$form['tattoo'], $form['eyes']);
$char->setFaceShot($form['zoom'] != 'body'false);
$slots = [
    
EVisualSlot::CHEST_SLOT => 'chest',
    
EVisualSlot::HEAD_SLOT => 'head',
    
EVisualSlot::LEGS_SLOT => 'legs',
    
EVisualSlot::ARMS_SLOT => 'arms',
    
EVisualSlot::HANDS_SLOT => 'hands',
    
EVisualSlot::FEET_SLOT => 'feet',
    
//
    
EVisualSlot::RIGHT_HAND_SLOT => 'handr',
    
EVisualSlot::LEFT_HAND_SLOT => 'handl',
];

foreach (
$slots as $idx => $key) {
    if (isset(
$form[$key]['color'])) {
        
$char->setSlot($idx$form[$key]['item'], $form[$key]['color']);
    } else {
        
$char->setSlot($idx$form[$key]);
    }
}
// if no helmet is selected, then use haircut
list($hcut$hcol) = $char->getSlot(EVisualSlot::HEAD_SLOT);
if (
$hcut == 0) {
    
$char->setSlot(EVisualSlot::HEAD_SLOT$form['haircut'], $form['haircolor']);
}

// override values from user supplied vpx
if (!empty($_REQUEST['vpa'])) {
    
$is_hex = (is($_REQUEST['vpax'], 'off') === 'on') && substr($_REQUEST['vpa'], 02) !== '0x';
    
$char->setVpa(($is_hex '0x' '') . $_REQUEST['vpa']);
}
if (!empty(
$_REQUEST['vpb'])) {
    
$is_hex = (is($_REQUEST['vpbx'], 'off') === 'on') && substr($_REQUEST['vpb'], 02) !== '0x';
    
$char->setVpb(($is_hex '0x' '') . $_REQUEST['vpb']);
}
if (!empty(
$_REQUEST['vpc'])) {
    
$is_hex = (is($_REQUEST['vpcx'], 'off') === 'on') && substr($_REQUEST['vpc'], 02) !== '0x';
    
$char->setVpc(($is_hex '0x' '') . $_REQUEST['vpc']);
}

//
// ajax
//
if (is($_SERVER['HTTP_X_REQUESTED_WITH'], '') && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {
    
header('Content-Type: application/json; charset=utf-8');
    
header('Access-Control-Allow-Origin: *');

    
$json = [
        
'result' => 'success',
        
'data' => [
            
'image' => render_3d_url($char),
            
'vpa' => '<br>(hex) '.strtoupper($char->getVpa(true)) . '<br>(dec) '.$char->getVpa(),
            
'vpb' => '<br>(hex) '.strtoupper($char->getVpb(true)) . '<br>(dec) '.$char->getVpb(),
            
'vpc' => '<br>(hex) '.strtoupper($char->getVpc(true)) . '<br>(dec) '.$char->getVpc(),
        ],
    ];

    echo 
json_encode($jsonJSON_UNESCAPED_UNICODE);

    die();
}

header('Content-Type: text/html; charset=utf-8');
//header('Access-Control-Allow-Origin: *');

//
// build interface
//
$tpl2 '<li>{$name}: <span id="{$id}">{$vpx}</span></li>';

$vpx '<ul>';
$vpx .= strtr($tpl2, ['{$name}' => 'VPA''{$id}' => 'vpa''{$vpx}' => '<br>(hex) '.strtoupper($char->getVpa(true)) . '<br>(dec) '.$char->getVpa()]);
$vpx .= strtr($tpl2, ['{$name}' => 'VPB''{$id}' => 'vpb''{$vpx}' => '<br>(hex) '.strtoupper($char->getVpb(true)) . '<br>(dec) '.$char->getVpb()]);
$vpx .= strtr($tpl2, ['{$name}' => 'VPC''{$id}' => 'vpc''{$vpx}' => '<br>(hex) '.strtoupper($char->getVpc(true)) . '<br>(dec) '.$char->getVpc()]);
$vpx .= '</ul>';

//$vp = $char->getVpa(true);
//$vp = preg_replace('~(..)(?!$)\.?~', '\1:', $vp);
//echo $vp;

//************************************************************************************
$langArray = [
    
'en' => __('LanguageName.uxt''en'),
    
'fr' => __('LanguageName.uxt''fr'),
    
'de' => __('LanguageName.uxt''de'),
    
'ru' => __('LanguageName.uxt''ru'),
    
'es' => __('LanguageName.uxt''es'),
];
$langTable '<table><tr>';
$langTable .= '<td>' __('uigcLanguage.uxt') . '</td>';
$langTable .= '<td>' html_select('language'$langArrayLANG) . '</td>';
$langTable .= '</tr></table>';

$tpl '<html>
<head>
    <title>{$title}</title>
    <script src="js/jquery-2.1.4.min.js"></script>
    <script src="js/main.js"></script>
    <style>
        #status {
            position: absolute;
            top: 0;
            left: 0;
            padding-top: 200px;
            width: 300px;
            height: 400px; /* -padding*/
            background-color: rgba(0, 0, 0, .5);
            color: yellowgreen;
            font-size: 26px;
            text-align: center;
        }
        #form2 input[type="text"] {
            width: 200px;
        }
    </style>
</head>
<body>

<a href="https://github.com/nimetu/dr.bmsite.net">
    <img style="position: absolute; top: 0; right: 0; border: 0;" src="images/forkme_right_darkblue_121621.png" alt="Fork me on GitHub">
</a>

{$title} <small>(<a href="?src=show">source</a>)</small>

<hr>

<form id="form" method="POST" action="?">
    <table>
        <tr>
            <td valign="top" style="position:relative;">
                {$image}
                <br>{$vpx}<br>{$image_opts}
                <div id="status"></div>
            </td>
            <td valign="top">{$options}</td>
        </tr>
    </table>
    {$lang}
</form>

<h2>Set VPX</h2>
<form id="form2" method="POST" action="?">
    <table>
        <tr>
            <td valign="top">VPA</td>
            <td>
                <input type="text" name="vpa" value="" size="100">
            </td>
            <td>
                <input type="checkbox" name="vpax"> hex
            </td>
        </tr>
        <tr>
            <td valign="top">VPB</td>
            <td>
                <input type="text" name="vpb" value="" size="100">
            </td>
            <td>
                <input type="checkbox" name="vpbx"> hex
            </td>
        </tr>
        <tr>
            <td valign="top">VPC</td>
            <td>
                <input type="text" name="vpc" value="" size="100">
            </td>
            <td>
                <input type="checkbox" name="vpcx"> hex
            </td>
        </tr>
    </table>
    <input type="submit" name="submit" value="submit">
</form>
</body>
</html>
'
;

echo 
strtr(
    
$tpl,
    [
    
'{$title}' => 'api.bmsite.net - Character Creator',
        
'{$lang}' => $langTable,
        
'{$vpx}' => $vpx,
        
'{$image_opts}' => image_options($char),
        
//
        
'{$image}' => '<img id="preview" src="' render_3d_url($char) . '" width="300" height="600">',
        
'{$options}' => option_pane($char),
        
//
    
]
);

exit;

/**
 * @param \Rrs\Character $char
 *
 * @return string
 */
function render_3d_url(\Rrs\Character $char)
{
    
// race, gender, age, eyes, hair, tattoo, gabarit, morph, dir, zoom [body, face, portrait]
    
$race_names = [=> 'fy'=> 'ma'=> 'tr'=> 'zo'];
    
$race $race_names[$char->getRace()];
    
$dir $char->getDirection();
    
// age not in vpx
    //$age = $char->getAge();

    
$vpa $char->getVpa();
    
$vpb $char->getVpb();
    
$vpc $char->getVpc();

    if (
$char->isFaceShot()) {
        
$zoom 'portrait';
    } else {
        
$zoom 'body';
    }

    return 
"https://api.bmsite.net/char/render/3d?race={$race}&dir={$dir}&zoom={$zoom}&vpa={$vpa}&vpb={$vpb}&vpc={$vpc}";
}

function 
image_options(\Rrs\Character $char)
{
    
$tplRow '<tr><td>{$name}</td><td>{$value}</td>';

    
$zoomArray = [
        
'body' => 'body',
        
'portrait' => 'portrait',
    ];
    if (
$char->isFaceShot()) {
        
$zoom 'portrait';
    } else {
        
$zoom 'body';
    }

    
$html '';

    
//************************************************************************************
    // image options
    //************************************************************************************
    
$angles = [
        
=> '0 (front)',
        
45 => 45,
        
90 => 90,
        
135 => 135,
        
180 => '180 (back)',
        
225 => 225,
        
270 => 270,
        
315 => 315,
    ];
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => 'Zoom''{$value}' => html_select('zoom'$zoomArray$zoom)]
    );

    
$html .= strtr(
        
$tplRow,
        [
            
'{$name}' => 'Direction',
            
'{$value}' => html_select('dir'$angles, (int) $char->getDirection())
        ]
    );

    return 
'<table>' $html '</table>';
}

/**
 * @param \Rrs\Character $char
 *
 * @return string
 */
function option_pane(\Rrs\Character $char)
{
    
$race strtolower(TPeople::toString($char->getRace()));
    
$gender $char->getGender() == 'm' 'f';

    
$raceArray = [
        
=> 'Fyros',
        
=> 'Matis',
        
=> 'Tryker',
        
=> 'Zorai',
    ];
    
$ageArray = [
        
=> 'age=0',
        
=> 'age=1',
        
=> 'age=2',
    ];
    
$genderArray = [
        
=> 'male',
        
=> 'female',
    ];

    
$tplRow '<tr><td>{$name}</td><td>{$value}</td>';
    
$sep '<tr><td>---</td><td></td></tr>';

    
$btnSubmit strtr(
        
$tplRow,
        [
            
'{$name}' => '<input type="submit" name="submit" value="submit">',
            
'{$value}' => ''
        
]
    );

    
//************************************************************************************
    // page 1
    //************************************************************************************
    
$html '';
    
$html .= strtr($tplRow, ['{$name}' => '''{$value}' => __('uiAppear_Infos2.uxt')]);
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => __('uiR2EdRace.uxt'), '{$value}' => html_select('race'$raceArray$char->getRace())]
    );
    
// age is not in vpx
    //$html .= strtr($tplRow, ['{$name}' => 'Age', '{$value}' => html_select('age', $ageArray, $char->getAge())]);
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => 'Gender''{$value}' => html_select('gender'$genderArray$char->getGender())]
    );

    
$hairColors = [];
    for (
$i 0$i 6$i++) {
        
$hairColors[$i] = sprintf('%s_ho%s_haircolor%d.sitem'$race$gender$i);
    }

    
$slot EVisualSlot::HEAD_SLOT;
    list(
$haircut$haircolor) = $char->getSlot($slot);
    
$haircuts = [=> '-'] + slot_items($char$slot'hair');
    if (!isset(
$haircuts[$haircut])) {
        
$haircut 0;
    }

    
$sb '<table><tr>';
    
$sb .= '<td>' html_select("haircolor"$hairColors$haircolortruefalse) . '</td>';
    
$sb .= '<td>' html_select("haircut"$haircuts$haircuttrue) . '</td>';
    
$sb .= '</tr></table>';
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => 'Haircut''{$value}' => $sb]
    );

    
//************************************************************************************
    
$tattooArray = [];
    for (
$i 0$i 64$i++) {
        
$txt sprintf('%s_ho%s_tatoo%d.sitem'$race$gender$i);
        
$tattooArray[$i] = __($txt);
    }
    list(
$tattoo$eyes) = $char->getSlot(EVisualSlot::FACE_SLOT);
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => 'Eye color''{$value}' => html_select('eyes'range(071), $eyes)]
    );
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => 'Tattoo''{$value}' => html_select('tattoo'$tattooArray$tattoo)]
    );

    
//************************************************************************************
    // page
    //************************************************************************************
    
$html .= strtr($tplRow, ['{$name}' => '''{$value}' => __('uiAppear_Infos2.uxt')]);
    
$slots = [
        
EVisualSlot::HEAD_SLOT => 'uiHelmet.uxt',
        
EVisualSlot::CHEST_SLOT => 'uiTorso.uxt',
        
EVisualSlot::ARMS_SLOT => 'uiArms.uxt',
        
EVisualSlot::HANDS_SLOT => 'uiGloves.uxt',
        
EVisualSlot::LEGS_SLOT => 'uiLegs.uxt',
        
EVisualSlot::FEET_SLOT => 'uiFeet.uxt',
    ];
    
$colors = [
        
RyzomExtra::COLOR_RED => RyzomExtra::uxt_color(RyzomExtra::COLOR_RED) . '.uxt',
        
RyzomExtra::COLOR_BEIGE => RyzomExtra::uxt_color(RyzomExtra::COLOR_BEIGE) . '.uxt',
        
RyzomExtra::COLOR_GREEN => RyzomExtra::uxt_color(RyzomExtra::COLOR_GREEN) . '.uxt',
        
RyzomExtra::COLOR_TURQUOISE => RyzomExtra::uxt_color(RyzomExtra::COLOR_TURQUOISE) . '.uxt',
        
RyzomExtra::COLOR_BLUE => RyzomExtra::uxt_color(RyzomExtra::COLOR_BLUE) . '.uxt',
        
RyzomExtra::COLOR_PURPLE => RyzomExtra::uxt_color(RyzomExtra::COLOR_PURPLE) . '.uxt',
        
RyzomExtra::COLOR_WHITE => RyzomExtra::uxt_color(RyzomExtra::COLOR_WHITE) . '.uxt',
        
RyzomExtra::COLOR_BLACK => RyzomExtra::uxt_color(RyzomExtra::COLOR_BLACK) . '.uxt',
    ];

    
// FIXME: split helmet and haircut - different colors
    
foreach ($slots as $slot => $txt) {
        list(
$item$color) = $char->getSlot($slot);

        
$items = [=> '-'] + slot_items($char$slot'item');

        
$sb '<table><tr>';
        
$sb .= '<td>' html_select("slot{$slot}[color]"$colors$colortruefalse) . '</td>';
        
$sb .= '<td>' html_select("slot{$slot}[item]"$items$itemtrue) . '</td>';
        
$sb .= '</tr></table>';

        
$html .= strtr($tplRow, ['{$name}' => __($txt), '{$value}' => $sb]);
    }
    
//***********************************************************************************
    
list($item) = $char->getSlot(EVisualSlot::RIGHT_HAND_SLOT);
    
$items = [=> '-'] + slot_items($charEVisualSlot::RIGHT_HAND_SLOT);
    
$html .= strtr(
        
$tplRow,
        [
            
'{$name}' => 'Right hand',
            
'{$value}' => html_select(
                
'slot' EVisualSlot::RIGHT_HAND_SLOT,
                
$items,
                
$item,
                
true
            
)
        ]
    );
    list(
$item) = $char->getSlot(EVisualSlot::LEFT_HAND_SLOT);
    
$items = [=> '-'] + slot_items($charEVisualSlot::LEFT_HAND_SLOT);
    
$html .= strtr(
        
$tplRow,
        [
            
'{$name}' => 'Left hand',
            
'{$value}' => html_select(
                
'slot' EVisualSlot::LEFT_HAND_SLOT,
                
$items,
                
$item,
                
true
            
)
        ]
    );

    
$html .= $btnSubmit;

    
//************************************************************************************
    // page
    //************************************************************************************
    
$tmp '<table>';
    
$tmp .= '<tr><td>' __('uiAppear_Infos3.uxt') . '</td><td>' __('uiAppear_Infos4.uxt') . '</td></tr>';
    
$tmp .= '<tr><td valign="top">' render_gabarit($char) . '</td><td valign="top">' render_morph(
            
$char
        
) . '</td></tr>';
    
$tmp .= '</table>';
    
$html .= strtr($tplRow, ['{$name}' => '''{$value}' => $tmp]);
    
//$html .= strtr($tplRow, ['{$name}' => '', '{$value}' => __('uiAppear_Infos3.uxt')]);
    //$html .= strtr($tplRow, ['{$name}' => '', '{$value}' => render_gabarit($char)]);
    //************************************************************************************
    //$html .= strtr($tplRow, ['{$name}' => '', '{$value}' => __('uiAppear_Infos4.uxt')]);
    //$html .= strtr($tplRow, ['{$name}' => '', '{$value}' => render_morph($char)]);

    
$html .= $btnSubmit;

    return 
'<table>' $html '</table>';
}

/**
 * @param \Rrs\Character $char
 *
 * @return string
 */
function render_gabarit(\Rrs\Character $char)
{
    
$tplRow '<tr><td>{$name}</td><td>{$value}</td></tr>';
    
$gabarit $char->getGabarit();
    
$html '';
    
$html .= '<table>';
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => __('uiHeight.uxt'), '{$value}' => html_select('gabarit[0]'range(0141), $gabarit[0])]
    );
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => __('uiTorso.uxt'), '{$value}' => html_select('gabarit[1]'range(0141), $gabarit[1])]
    );
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => __('uiArms.uxt'), '{$value}' => html_select('gabarit[2]'range(0141), $gabarit[2])]
    );
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => __('uiLegs.uxt'), '{$value}' => html_select('gabarit[3]'range(0141), $gabarit[3])]
    );
    
$html .= strtr(
        
$tplRow,
        [
'{$name}' => __('uiBreasts.uxt'), '{$value}' => html_select('gabarit[4]'range(0141), $gabarit[4])]
    );
    
$html .= '</table>';
    return 
$html;
}

/**
 * @param \Rrs\Character $char
 *
 * @return string
 */
function render_morph(\Rrs\Character $char)
{
    
$race TPeople::toString($char->getRace());
    
$tplRow '<tr><td>{$name}</td><td>{$value}</td></tr>';

    
// uiFace1Fy
    
$uiMorph 'uiFace%d' ucfirst($race) . '.uxt';
    
$morph $char->getMorph();
    
$html '<table>';
    for (
$i 0$i 8$i++) {
        
$html .= strtr(
            
$tplRow,
            [
                
'{$name}' => __(sprintf($uiMorph$i 1)),
                
'{$value}' => html_select("morph[{$i}]"range(071), $morph[$i])
            ]
        );
    }
    
$html .= '</table>';
    return 
$html;
}


/**
 * @param string     $name
 * @param array      $options
 * @param int|string $selected
 * @param bool       $trans
 * @param bool       $verbose
 *
 * @return string
 */
function html_select($name, array $options$selected$trans false$verbose true)
{
    
$ret '<select name="' $name '">';
    foreach (
$options as $k => $v) {
        if (
$v === '-') {
            
$txt '-';
        } else {
            
$txt = ($trans __($v) : _h($v));
            if (
substr($txt010) == 'NotFound:(') {
                
$txt _h($v);
            } elseif (
$verbose && $txt != $v) {
                
$txt '[' _h($v) . '] ' $txt;
            }
        }
        
$ret .= '<option value="' _h($k) . '"' . ($selected == $k ' selected="selected"' '') . '>' .
            
$txt '</option>';
    }
    
$ret .= '</select>';
    
//$ret = '['.$selected.']'.$ret;
    
return $ret;
}

/**
 * FIXME: filter items for race and gender?
 *
 * @param \Rrs\Character $char
 * @param int            $index
 * @param string         $what [all, hair, item]
 *
 * @return mixed
 */
function slot_items(\Rrs\Character $char$index$what 'all')
{
    static 
$visual null;

    if (
$visual === null) {
        
$visual ryzom_extra_load_vs();
    }

    if (
$what !== 'all' && $index == EVisualSlot::HEAD_SLOT) {
        
$ret = [];
        
$race strtolower(TPeople::toString($char->getRace()));
        
$gender strtolower(EGender::toString($char->getGender()));
        foreach (
$visual[$index] as $index => $sheet) {
            
// FIXME: fy_hof_haircolor0.sitem ... color5
            
if (is_haircut($sheet)) {
                if (
$what == 'hair') {
                    
// 'fy_hom_'
                    
$prefix sprintf('%s_ho%s_'$race$gender);
                    
// 'fy_cheveux'
                    
$prefix2 sprintf('%s_cheveux'$race);
                    
$pos stripos($sheet$prefix);
                    
$pos2 stripos($sheet$prefix2);
                    if (
$pos === || $pos2 === 0) {
                        
$ret[$index] = $sheet;
                    }
                }
            } elseif (
$what == 'item') {
                
$ret[$index] = $sheet;
            }
        }
        
//$items = filter_haircut($char, $slot);
        
return $ret;
    }

    return 
$visual[$index];
}

/**
 * @param string $sheet
 *
 * @return bool
 */
function is_haircut($sheet)
{
    return 
strstr($sheet'_hair_') || strstr($sheet'_cheveux');
}

/**
 * @param int $var
 * @param int $min
 * @param int $max
 *
 * @return mixed
 */
function clamp($var$min$max)
{
    if (
$var $min) {
        return 
$min;
    }
    if (
$var $max) {
        return 
$max;
    }
    return 
$var;
}

/**
 * @param mixed $var
 * @param mixed $default
 *
 * @return mixed
 */
function is(&$var$default null)
{
    return (isset(
$var) ? $var $default);
}