<commit_before>/**
 * Creates an utility to manage sprites.
 *
 * @param Image The image data of the sprite
 */
var Sprite = function(img) {
    this.img = img;
    this.descriptors = [];
};

Sprite.prototype = {
    registerIds: function(array) {
        for(var i = array.length - 1; i >= 0; i--) {
            this.registerId(
                array[i].id,
                array[i].position,
                array[i].width,
                array[i].height
            );
        }

        return this;
    },

    registerId: function(id, position, width, height) {
        this.descriptors.push({
            id: id,
            position: position,
            width: width,
            height: height,
        });

        return this;
    },

    draw: function(ctx, id, position) {
        var spritePart = this.get(id);
        if(spritePart === null) {
            return this;
        }
        return this.drawPart(ctx, spritePart, position);
    },

    // Use this if you don't want the lookup time
    drawPart: function(ctx, part, position) {
        ctx.drawImage(
            this.img,
            part.position.x,
            part.position.y,
            part.width,
            part.height,
            position.x,
            position.y,
            part.width,
            part.height
        );
        if(Game.debug) {
            ctx.save();
            // Box
            ctx.beginPath();
            ctx.strokeStyle = 'rgba(20, 0, 60, 0.3)';
            var w = ctx.measureText(part.id).width;
            ctx.rect(position.x, position.y, part.width, part.height);
            ctx.stroke();
            // Text shadow
            ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
            ctx.beginPath();
            ctx.rect(position.x, position.y, w + 10, 20);
            ctx.fill();
            // Name
            ctx.fillStyle = '#eee';
            ctx.textAlign = 'center';
            ctx.font = '15px';
            ctx.fillText(part.id, position.x + w / 2 + 5, position.y + 15);
            ctx.restore();
        }
        return this;
    },

    get: function(id) {
        // TODO Return an object which is able to draw itself
        // So it can be used without the parent sprite at hand like
        // var part = sprite.get('id');
        // ....
        // part.draw(ctx, position);
        return Arrays.search(this.descriptors, 'id', id);
    },
};
<commit_msg>Allow drawing sprite parts directly<commit_after>/**
 * Creates an utility to manage sprites.
 *
 * @param Image The image data of the sprite
 */
var Sprite = function(img) {
    this.img = img;
    this.descriptors = [];
};

Sprite.prototype = {
    registerIds: function(array) {
        for(var i = array.length - 1; i >= 0; i--) {
            this.registerId(
                array[i].id,
                array[i].position,
                array[i].width,
                array[i].height
            );
        }

        return this;
    },

    registerId: function(id, position, width, height) {
        this.descriptors.push({
            id: id,
            position: position,
            width: width,
            height: height,
        });

        return this;
    },

    draw: function(ctx, part, position) {
        if(!(id instanceof SpritePart)) {
            part = this.get(id);
        }

        if(part === null) {
            // TODO Error?
            return this;
        }
        return this.drawPart(ctx, part, position);
    },

    // Use this if you don't want the lookup time
    drawPart: function(ctx, part, position) {
        ctx.drawImage(
            this.img,
            part.position.x,
            part.position.y,
            part.width,
            part.height,
            position.x,
            position.y,
            part.width,
            part.height
        );
        if(Game.debug) {
            ctx.save();
            // Box
            ctx.beginPath();
            ctx.strokeStyle = 'rgba(20, 0, 60, 0.3)';
            var w = ctx.measureText(part.id).width;
            ctx.rect(position.x, position.y, part.width, part.height);
            ctx.stroke();
            // Text shadow
            ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
            ctx.beginPath();
            ctx.rect(position.x, position.y, w + 10, 20);
            ctx.fill();
            // Name
            ctx.fillStyle = '#eee';
            ctx.textAlign = 'center';
            ctx.font = '15px';
            ctx.fillText(part.id, position.x + w / 2 + 5, position.y + 15);
            ctx.restore();
        }
        return this;
    },

    get: function(id) {
        return new SpritePart(this, Arrays.search(this.descriptors, 'id', id));
    },
};

var SpritePart = function(sprite, descriptor) {
    this.sprite = sprite;
    this.id = descriptor.id;
    this.position = descriptor.position;
    this.width = descriptor.width;
    this.height = descriptor.height;
};

SpritePart.prototype = {
    draw: function(ctx, position) {
        this.sprite.drawPart(ctx, this, position);
        return this;
    }
};

{'fraction_non_alphanumeric': 0.1304003170828379, 'fraction_numerical': 0.009512485136741973, 'mean_word_length': 1.4067715784453982, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6133064', 'n_tokens_mistral': 1528, 'n_tokens_neox': 1466, 'n_words': 352}