/*
**  Usage:
**      new_sprite = sprite_recolor(old_sprite, old_color, new_color,
**                   tran_color, htol, stol, vtol, blend);
**
**  Description:
**      Creates a duplicate of a sprite while replacing
**      one color with a new color in all frames.
**
**  Arguments:
**      old_sprite    sprite index
**      old_color     original color
**      new_color     replacement color
**      tran_color    sprite's transparency color
**      htol          hue tolerance, real
**      stol          saturation tolerance, real
**      vtol          value tolerance, real
**      blend         blend shading, true / false
**
**  Returns:
**      new_sprite    sprite index, or
**                    (-1) on error
**
**  Notes:
**      (tran_color) must be supplied, it is the color used
**      for (new_sprite)'s transparency mask.
**
**      Three tolerance arguments (htol,stol,vtol) contol exactly
**      which colors are replaced. A higher tolerance will match
**      a broader range of hue, saturation, or value. Values
**      around (htol = 20; stol = 240; vtol = 240) work well.
**
**      If (blend) is set to true (recommeded), changed colors
**      will retain their original shading.
**
**      This function creates new sprites. It should only be
**      called once per color replacement, such as the Create Event
**      of an instance. You should be careful to delete created
**      sprites when you are done with them. This function draws
**      to the frame buffer and should NEVER be called during the
**      Draw Event. Sprite colors in 16-bit color mode are not
**      exact. They can shift from expected values in-game. Use
**      the tolerance controls to compensate. Finally, this
**      function is not fast. It is very slow with large sprites
**      and/or sprites with many frames. I'm working on a better
**      method.
**
**  copyright (c) 2006, John Leffingwell
**  www.planetxot.com
*/

var new_sprite, old_sprite, old_color, new_color, tran_color, threshold, blend;
old_sprite = argument0;
old_color = argument1;
new_color = argument2;
tran_color = argument3;
htol = argument4;
stol = argument5;
vtol = argument6;
blend = argument7;

var precise, transparent, smooth, preload, xorig, yorig, images, width, height;
var old_h, old_s, old_v, new_h, new_s, new_v, diff_h, diff_s, diff_v, i, sx, sy;
var test_color, test_h, test_s, test_v;

precise = sprite_get_precise(old_sprite);
transparent = sprite_get_transparent(old_sprite);
smooth = sprite_get_smooth(old_sprite);
preload = sprite_get_preload(old_sprite);
xorig = sprite_get_xoffset(old_sprite);
yorig = sprite_get_yoffset(old_sprite);
images = sprite_get_number(old_sprite);
width = sprite_get_width(old_sprite);
height = sprite_get_height(old_sprite);

old_h = color_get_hue(old_color);
old_s = color_get_saturation(old_color);
old_v = color_get_value(old_color);
new_h = color_get_hue(new_color);
new_s = color_get_saturation(new_color);
new_v = color_get_value(new_color);

for(i = 0; i < images; i += 1) {
    draw_set_color(tran_color);
    draw_rectangle(0, 0, width + 1, height + 1, false);
    draw_sprite(old_sprite, i, xorig, yorig);
    for(sy = 0; sy < height; sy += 1) {
        for(sx = 0; sx < width; sx += 1) {
            test_color = draw_getpixel(sx, sy);
            test_h = color_get_hue(test_color);
            test_s = color_get_saturation(test_color);
            test_v = color_get_value(test_color);
            diff_h = test_h - old_h;
            diff_s = test_s - old_s;
            diff_v = test_v - old_v;
            if (abs(diff_h) > 128) diff_h = sign(diff_h) * 256 - diff_h;
            if (abs(diff_h) < htol && abs(diff_s) < stol && abs(diff_v) < vtol) {
                if (blend) new_color = make_color_hsv((new_h + diff_h + 256) mod 256, min(max(0, new_s + diff_s), 255), min(max(0, new_v + diff_v), 255));
                draw_point_color(sx, sy, new_color);
            }
        }
    }
    if (i == 0) {
        new_sprite = sprite_create_from_screen(0, 0, width, height, precise, transparent, smooth, preload, xorig, yorig);
        if (new_sprite < 0) return -1;
    }else{
        sprite_add_from_screen(new_sprite, 0, 0, width, height);
    }
}
return new_sprite;