Source: emitters.js

var BHell = (function (my) {

    /**
     * Pseudo FactoryMethod pattern for the emitters usable by the player.
     * @constructor
     * @memberOf BHell
     */
    var BHell_Emitter_Factory = my.BHell_Emitter_Factory = function () {
    };

    /**
     * Returns a new emitter suitable for the player (i.e. not aiming at it) with given parameters.
     * The emitters' JSON description has the following fields:
     *
     * - type: string identifying the emitter class (@see BHell.BHell_Emitter_Factory#create),
     * - params: parameters for the emitter (see {@link BHell.BHell_Emitter_Base} and derived classes for its content).
     *
     * @param emitter JSON description for the emitter.
     * @param x X coordinate for the parser.
     * @param y Y spawning coordinate for the parser.
     * @param w Width for the parser.
     * @param h Height for the parser.
     * @param rate Rate of fire rank for the emitter (D = 1, C = 2, B = 3, A = 4, S = 5), it multiplies the emitter's period.
     * @param power Fire power rank for the emitter (D, C, B, A, S), enables some emitters instead of others.
     * @param parent Sprites container.
     * @param bulletList Array in which the bullets will be pushed.
     * @returns {*} An instance of the requested emitter if emitter.params.ranks contains power, null otherwise.
     */
    BHell_Emitter_Factory.parseEmitter = function (emitter, x, y, w, h, rate, power, parent, bulletList) {
        var ret = null;

        var params = Object.assign({}, emitter.params);

        params.ranks = params.ranks || ["D", "C", "B", "A", "S"];

        switch (rate) {
            case "D":
                rate = 1;
                break;
            case "C":
                rate = 2;
                break;
            case "B":
                rate = 3;
                break;
            case "A":
                rate = 4;
                break;
            case "S":
                rate = 5;
                break;
            default:
                rate = 1;
                break;
        }

        if (params.ranks.indexOf(power) !== -1) {
            params.x = my.parse(emitter.params.x, x, y, w, h, Graphics.width, Graphics.height);
            params.y = my.parse(emitter.params.y, x, y, w, h, Graphics.width, Graphics.height);
            params.period = Math.round(my.parse(emitter.params.period, x, y, w, h, Graphics.width, Graphics.height) / rate);
            if (params.period === 0) {
                params.period = 1;
            }

            ret = BHell_Emitter_Factory.create(emitter, x, y, w, h, params, parent, bulletList);
        }

        return ret;
    };


    /**
     * Parses emitter.type and creates a new emitter accordingly.
     *
     * Implemented types are: "base", "spray", "rotate" and "burst".
     *
     * @param emitter JSON description of the emitter
     * @param x X coordinate for the parser.
     * @param y Y spawning coordinate for the parser.
     * @param w Width for the parser.
     * @param h Height for the parser.
     * @param params Parameters for the emitter.
     * @param parent Sprites container.
     * @param bulletList Array in which the bullets will be pushed.
     * @returns {*} An instance of the requested emitter if emitter.type could be parsed, null otherwise.
     */
    BHell_Emitter_Factory.create = function (emitter, x, y, w, h, params, parent, bulletList) {
        var ret = null;

        switch (emitter.type) {
            case "base":
                ret = new BHell_Emitter_Base(x, y, params, parent, bulletList);
                break;
            case "angle":
                params.angle = my.parse(emitter.params.angle, x, y, w, h, Graphics.width, Graphics.height);
                ret = new BHell_Emitter_Angle(x, y, params, parent, bulletList);
                break;
            case "spray":
                params.a = my.parse(emitter.params.a, x, y, w, h, Graphics.width, Graphics.height);
                params.b = my.parse(emitter.params.b, x, y, w, h, Graphics.width, Graphics.height);
                params.n = my.parse(emitter.params.n, x, y, w, h, Graphics.width, Graphics.height);
                ret = new BHell_Emitter_Spray(x, y, params, parent, bulletList);
                break;
            case "spray_random":
                params.a = my.parse(emitter.params.a, x, y, w, h, Graphics.width, Graphics.height);
                params.b = my.parse(emitter.params.b, x, y, w, h, Graphics.width, Graphics.height);
                params.n = my.parse(emitter.params.n, x, y, w, h, Graphics.width, Graphics.height);
                params.min_speed = my.parse(emitter.params.min_speed, x, y, w, h, Graphics.width, Graphics.height);
                params.max_speed = my.parse(emitter.params.max_speed, x, y, w, h, Graphics.width, Graphics.height);
                ret = new BHell_Emitter_Spray_Rnd(x, y, params, parent, bulletList);
                break;
            case "spray_alternate":
                params.a = my.parse(emitter.params.a, x, y, w, h, Graphics.width, Graphics.height);
                params.b = my.parse(emitter.params.b, x, y, w, h, Graphics.width, Graphics.height);
                params.n1 = my.parse(emitter.params.n1, x, y, w, h, Graphics.width, Graphics.height);
                params.n2 = my.parse(emitter.params.n2, x, y, w, h, Graphics.width, Graphics.height);
                ret = new BHell_Emitter_Spray_Alt(x, y, params, parent, bulletList);
                break;
            case "rotate":
                params.theta = my.parse(emitter.params.theta, x, y, w, h, Graphics.width, Graphics.height);
                params.radius = my.parse(emitter.params.radius, x, y, w, h, Graphics.width, Graphics.height);
                params.dt = my.parse(emitter.params.dt, x, y, w, h, Graphics.width, Graphics.height);
                ret = new BHell_Emitter_Rotate(x, y, params, parent, bulletList);
                break;
            case "burst":
                params.dispersion = my.parse(emitter.params.dispersion, x, y, w, h, Graphics.width, Graphics.height);
                params.shots = my.parse(emitter.params.shots, x, y, w, h, Graphics.width, Graphics.height);
                params.angle = my.parse(emitter.params.angle, x, y, w, h, Graphics.width, Graphics.height);
                ret = new BHell_Emitter_Burst(x, y, params, parent, bulletList);
                break;
        }

        return ret;
    };

    /**
     * Emitter base class. Spawns a bullet at a given frequency.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Sprite
     */
    var BHell_Emitter_Base = my.BHell_Emitter_Base = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Base.prototype = Object.create(my.BHell_Sprite.prototype);
    BHell_Emitter_Base.prototype.constructor = BHell_Emitter_Base;

    /**
     * Constructor.
     * Emitter parameters:
     *
     * - x: X offset for the emitter's movement,
     * - y: Y offset for the emitter's movement,
     * - period: shooting period,
     * - charset: Character set for the emitter (null if the emitter should be invisible),
     * - index: Character index for the emitter (ignored if charset is null, or a big character),
     * - direction: Character direction for the emitter (Uses RPGMaker's 2-4-6-8 convention),
     * - frame: Initial character frame for the emitter (0-2),
     * - animated: True if the Sprite should dynamically change over time,
     * - animation_speed: Frames after which the character frame is updated,
     * - bullet: bullet parameters (see {@link BHell.BHell_Bullet} for its content).
     *
     * @param x X coordinate of the emitter.
     * @param y Y coordinate of the emitter.
     * @param params Parameters for the emitter and the spawned bullets.
     * @param parent Container for the emitter's and bullets' sprites.
     * @param bulletList Array in which the bullets will be pushed.
     */
    BHell_Emitter_Base.prototype.initialize = function (x, y, params, parent, bulletList) {
        // Set the default parameters.
        this.offsetX = 0;
        this.offsetY = 0;
        this.period = 1;
        var charset = null;
        var index = 0;
        var direction = 2;
        var frame = 0;
        var animated = false;
        var animationSpeed = 25;

        // Override default parameters with values taken from params.
        if (params != null) {
            this.offsetX = params.x || 0;
            this.offsetY = params.y || 0;
            this.period = (params.period > 0) ? params.period : 1;
            this.bulletParams = params.bullet;

            charset = params.sprite;
            index = params.index || index;
            direction = params.direction || direction;
            frame = params.frame || frame;
            animated = params.animated || animated;
            animationSpeed = params.animation_speed || animationSpeed;
        }

        // Initialize the emitter.
        my.BHell_Sprite.prototype.initialize.call(this, charset, index, direction, frame, animated, animationSpeed);
        this.parent = parent;
        this.shooting = false; // Every emitter is a finite-state machine, this parameter switches between shooting and non-shooting states.
        this.oldShooting = false; // Previous shooting state.
        this.j = 0; // Frame counter. Used for state switching.
        this.bulletList = bulletList;
        this.x = x;
        this.y = y;
    };

    /**
     * Updates the emitter's sprite and state. Called every frame. Shoots if in shooting state.
     */
    BHell_Emitter_Base.prototype.update = function () {
        my.BHell_Sprite.prototype.update.call(this);

        if (this.shooting === true) {
            if (this.j === 0) {
                this.shoot();
            }

            this.j = (this.j + 1) % this.period;
        }
        else {
            this.j = 0;
        }

        this.oldShooting = this.shooting;
    };

    /**
     * Spawns a single bullet moving upwards. Bullet's speed and appearance are determined by this.bulletParams.
     */
    BHell_Emitter_Base.prototype.shoot = function () {
        var bullet = new my.BHell_Bullet(this.x, this.y, 3 * Math.PI / 2, this.bulletParams, this.bulletList);
        this.parent.addChild(bullet);
        this.bulletList.push(bullet);
    };

    /**
     * Moves the emitter, relative to the initialised offset.
     * @param x New x coordinate.
     * @param y New y coordinate.
     */
    BHell_Emitter_Base.prototype.move = function (x, y) {
        this.x = x + this.offsetX;
        this.y = y + this.offsetY;
    };


    /**
     * Rotating emitter. It spawns a single bullet moving upwards, while moving in a circular pattern.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Emitter_Base
     */
    var BHell_Emitter_Rotate = my.BHell_Emitter_Rotate = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Rotate.prototype = Object.create(BHell_Emitter_Base.prototype);
    BHell_Emitter_Rotate.prototype.constructor = BHell_Emitter_Rotate;

    /**
     * Constructor.
     * Additional parameters:
     *
     * - dt: rotation speed (in radians per frame),
     * - theta: initial angle (in radians),
     * - radius: rotation radius around the pivot.
     *
     * @param x X coordinate of the rotation pivot.
     * @param y Y coordinate of the rotation pivot.
     * @param params Emitter's and bullets' parameters.
     * @param parent Container for the sprites.
     * @param bulletList Array in which the bullets will be pushed.
     */
    BHell_Emitter_Rotate.prototype.initialize = function (x, y, params, parent, bulletList) {
        BHell_Emitter_Base.prototype.initialize.call(this, x, y, params, parent, bulletList);
        this.dt = 0;
        this.radius = 0;
        this.theta = 0;

        if (params != null) {
            this.dt = params.dt || this.dt;
            this.radius = params.radius || this.radius;
            this.theta = params.theta || this.theta;
        }
    };

    /**
     * Rotates the emitter around the pivot.
     * @param x Pivot's new x coordinate.
     * @param y Pivot's new y coordinate.
     */
    BHell_Emitter_Rotate.prototype.move = function (x, y) {
        this.theta += this.dt;
        if (this.theta > 2 * Math.PI)
            this.theta -= 2 * Math.PI;

        this.x = Math.cos(this.theta) * this.radius + x + this.offsetX;
        this.y = Math.sin(this.theta) * this.radius + y + this.offsetY;
    };

    /**
     * Spraying emitter. Creates a series of bullets spreading in an arc from the initial position.
     * Optionally aims towards the player.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Emitter_Base
     */
    var BHell_Emitter_Spray = my.BHell_Emitter_Spray = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Spray.prototype = Object.create(BHell_Emitter_Base.prototype);
    BHell_Emitter_Spray.prototype.constructor = BHell_Emitter_Spray;

    /**
     * Constructor.
     * Additional parameters:
     *
     * - n: Number of bullets to be spawned for each shot,
     * - a: Arc's initial angle (in radians),
     * - b: Arc's final angle (in radians),
     * - aim: if true the arc is rotated to point towards the player,
     * - always_aim: if false (and aim = true) aiming only occours when there is a raising edge (shoot(false) -> shoot(true)),
     * - aim_x aiming horizontal offset (used only if aim = true),
     * - aim_y: aiming vertical offset (used only if aim = true).
     *
     * @param x
     * @param y
     * @param params
     * @param parent
     * @param bulletList
     */
    BHell_Emitter_Spray.prototype.initialize = function (x, y, params, parent, bulletList) {
        BHell_Emitter_Base.prototype.initialize.call(this, x, y, params, parent, bulletList);
        this.n = 1;
        this.a = 0;
        this.b = 0;
        this.aim = false;
        this.alwaysAim = false;
        this.aimX = 0;
        this.aimY = 0;

        this.aimingAngle = 0;

        if (params != null) {
            this.n = params.n || this.n;
            this.a = params.a || this.a;
            this.b = params.b || this.b;
            this.aim = params.aim || this.aim;
            this.alwaysAim = params.always_aim || this.alwaysAim;
            this.aimX = params.aim_x || this.aimX;
            this.aimY = params.aim_y || this.aimY;
        }
    };

    /**
     * Spawns this.n bullets spreading in an arc. If this.aim is true, the arc is centered on the player.
     */
    BHell_Emitter_Spray.prototype.shoot = function () {
        for (var k = 0; k < this.n; k++) {
            var bullet;
            if (this.aim) {
                if (this.alwaysAim || this.oldShooting === false) {
                    var dx = my.player.x - this.x + this.aimX;
                    var dy = my.player.y - this.y + this.aimY;
                    this.aimingAngle = Math.atan2(dy, dx);
                }

                bullet = new my.BHell_Bullet(this.x, this.y, this.aimingAngle - (this.b - this.a) / 2 + (this.b - this.a) / this.n * (k + 0.5), this.bulletParams, this.bulletList);
            }
            else {
                bullet = new my.BHell_Bullet(this.x, this.y, this.a + (this.b - this.a) / this.n * (k + 0.5), this.bulletParams, this.bulletList);
            }

            this.parent.addChild(bullet);
            this.bulletList.push(bullet);
        }
    };

    /**
     * Alternating spraying emitter. Creates a series of bullets spreading in an arc from the initial position, alternating between two sets of bullets.
     * Optionally aims towards the player.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Emitter_Spray
     */
    var BHell_Emitter_Spray_Alt = my.BHell_Emitter_Spray_Alt = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Spray_Alt.prototype = Object.create(BHell_Emitter_Spray.prototype);
    BHell_Emitter_Spray_Alt.prototype.constructor = BHell_Emitter_Spray_Alt;

    /**
     * Constructor.
     * Additional parameters:
     *
     * - n1: Number of bullets to be spawned for odd shots,
     * - n2: Number of bullets to be spawned for even shots.
     *
     * @param x
     * @param y
     * @param params
     * @param parent
     * @param bulletList
     */
    BHell_Emitter_Spray_Alt.prototype.initialize = function (x, y, params, parent, bulletList) {

        this.n1 = 3;
        this.n2 = 2;
        this.odd = true;

        if (params != null) {
            this.n1 = params.n1 || this.n1;
            this.n2 = params.n2 || this.n2;
        }
        params.n = this.n1;
        BHell_Emitter_Spray.prototype.initialize.call(this, x, y, params, parent, bulletList);
    };

    BHell_Emitter_Spray_Alt.prototype.shoot = function () {
        if (this.odd) {
            this.n = this.n1;
        }
        else {
            this.n = this.n2;
        }

        BHell_Emitter_Spray.prototype.shoot.call(this);

        this.odd = !this.odd;
    };

    /**
     * Random emitter. Creates a series of random bullets inside an arc from the initial position.
     * Optionally aims towards the player.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Emitter_Spray
     */
    var BHell_Emitter_Spray_Rnd = my.BHell_Emitter_Spray_Rnd = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Spray_Rnd.prototype = Object.create(BHell_Emitter_Spray.prototype);
    BHell_Emitter_Spray_Rnd.prototype.constructor = BHell_Emitter_Spray_Rnd;

    /**
     * Constructor.
     * Additional parameters:
     *
     * - min_speed: Minimum random speed for bullets,
     * - max_speed: Maximum random speed for bullets.
     *
     * @param x
     * @param y
     * @param params
     * @param parent
     * @param bulletList
     */
    BHell_Emitter_Spray_Rnd.prototype.initialize = function (x, y, params, parent, bulletList) {
        this.min_speed = 3;
        this.max_speed = 4;

        if (params != null) {
            this.min_speed = params.min_speed || this.min_speed;
            this.max_speed = params.max_speed || this.max_speed;
        }

        BHell_Emitter_Spray.prototype.initialize.call(this, x, y, params, parent, bulletList);
    };

    BHell_Emitter_Spray_Rnd.prototype.shoot = function () {
        for (var k = 0; k < this.n; k++) {
            var bullet;
            var randomAngle = Math.random() * (this.b - this.a);
            var randomSpeed = Math.random() * (this.max_speed - this.min_speed) + this.min_speed;
            if (this.aim) {
                if (this.alwaysAim || this.oldShooting === false) {
                    var dx = my.player.x - this.x + this.aimX;
                    var dy = my.player.y - this.y + this.aimY;
                    this.aimingAngle = Math.atan2(dy, dx);
                }

                bullet = new my.BHell_Bullet(this.x, this.y, this.aimingAngle + this.a - (this.b - this.a) / 2 + randomAngle, this.bulletParams, this.bulletList);
            }
            else {
                bullet = new my.BHell_Bullet(this.x, this.y, this.a + randomAngle, this.bulletParams, this.bulletList);
            }

            bullet.speed = randomSpeed;
            this.parent.addChild(bullet);
            this.bulletList.push(bullet);
        }
    };

    /**
     * Overcoming bullets emitter. Creates a series of bullets spreading in an arc from the initial position, with the later bullets faster than the earlier ones.
     * Optionally aims towards the player.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Emitter_Spray
     */
    var BHell_Emitter_Overcome = my.BHell_Emitter_Overcome = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Overcome.prototype = Object.create(BHell_Emitter_Spray.prototype);
    BHell_Emitter_Overcome.prototype.constructor = BHell_Emitter_Overcome;

    /**
     * Constructor.
     * Additional parameters:
     *
     * - min_speed: Speed for the bullets in the first wave,
     * - max_speed: Speed for the bullets in the last wave,
     * - waves: Number of waves to shoot.
     *
     * @param x
     * @param y
     * @param params
     * @param parent
     * @param bulletList
     */
    BHell_Emitter_Overcome.prototype.initialize = function (x, y, params, parent, bulletList) {

        this.min_speed = 3;
        this.max_speed = 4;
        this.waves = 4;

        if (params != null) {
            this.min_speed = params.min_speed || this.min_speed;
            this.max_speed = params.max_speed || this.max_speed;
            this.waves = params.waves || this.waves;
        }

        this.d_speed = (this.max_speed - this.min_speed) / this.waves;
        this.current_wave = 0;
        params.bullet.speed = this.min_speed;
        BHell_Emitter_Spray.prototype.initialize.call(this, x, y, params, parent, bulletList);
    };

    BHell_Emitter_Overcome.prototype.shoot = function () {
        BHell_Emitter_Spray.prototype.shoot.call(this);
        if (!this.oldShooting) {
            this.bulletParams.speed = this.min_speed;
            this.current_wave = 0;
        }
        this.bulletParams.speed = this.min_speed + this.current_wave * this.d_speed;

        this.current_wave = (this.current_wave + 1) % this.waves;
    };

    /**
     * Fanning bullets emitter. Creates a series of bullets spreading in an arc from the initial position, rotating like a fan.
     * Optionally aims towards the player.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Emitter_Overcome
     */
    var BHell_Emitter_Fan = my.BHell_Emitter_Fan = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Fan.prototype = Object.create(BHell_Emitter_Overcome.prototype);
    BHell_Emitter_Fan.prototype.constructor = BHell_Emitter_Fan;

    /**
     * Constructor.
     * Additional parameters:
     *
     * - rotation_angle: Rotation angle between each wave.
     *
     * @param x
     * @param y
     * @param params
     * @param parent
     * @param bulletList
     */
    BHell_Emitter_Fan.prototype.initialize = function (x, y, params, parent, bulletList) {
        this.rotation_angle = 0.05;

        if (params != null) {
            this.rotation_angle = params.rotation_angle || this.rotation_angle;
        }

        BHell_Emitter_Overcome.prototype.initialize.call(this, x, y, params, parent, bulletList);
    };

    BHell_Emitter_Fan.prototype.shoot = function () {
        if (!this.oldShooting) {
            this.bulletParams.speed = this.min_speed;
            this.current_wave = 0;
        }

        this.bulletParams.speed = this.min_speed + this.current_wave * this.d_speed;
        for (var k = 0; k < this.n; k++) {
            var bullet;

            if (this.aim) {
                if (this.alwaysAim || this.oldShooting === false) {
                    var dx = my.player.x - this.x + this.aimX;
                    var dy = my.player.y - this.y + this.aimY;
                    this.aimingAngle = Math.atan2(dy, dx);
                }

                bullet = new my.BHell_Bullet(this.x, this.y, this.aimingAngle + this.rotation_angle * this.current_wave - (this.b - this.a) / 2 + (this.b - this.a) / this.n * (k + 0.5), this.bulletParams, this.bulletList);
            }
            else {
                bullet = new my.BHell_Bullet(this.x, this.y, this.a + this.rotation_angle * this.current_wave + (this.b - this.a) / this.n * (k + 0.5), this.bulletParams, this.bulletList);
            }

            this.parent.addChild(bullet);
            this.bulletList.push(bullet);
        }

        this.current_wave = (this.current_wave + 1) % this.waves;
    };

    /**
     * Angle emitter. Creates a single bullet traveling at an angle. Optionally aims at the player.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Emitter_Base
     */
    var BHell_Emitter_Angle = my.BHell_Emitter_Angle = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Angle.prototype = Object.create(BHell_Emitter_Base.prototype);
    BHell_Emitter_Angle.prototype.constructor = BHell_Emitter_Angle;

    /**
     * Constructor.
     * Additional parameters:
     *
     * - angle: the bullets' traveling angle. If aiming, it will be used as an offset for the angle between the emitter and the player,
     * - aim: if true the angle is relative to the player's position (i.e. angle = 0 and aim = true: the bullets will point
     *        towards the player, angle = 0.1 and aim = true: the bullets will be shot at 0.1 radians counterclockwise, from the player's direction)
     * - always_aim: if false (and aim = true) aiming only occours when there is a raising edge (shoot(false) -> shoot(true)),
     * - aim_x aiming horizontal offset (used only if aim = true),
     * - aim_y: aiming vertical offset (used only if aim = true).
     *
     * @param x
     * @param y
     * @param params
     * @param parent
     * @param bulletList
     */
    BHell_Emitter_Angle.prototype.initialize = function (x, y, params, parent, bulletList) {
        BHell_Emitter_Base.prototype.initialize.call(this, x, y, params, parent, bulletList);

        this.angle = 0;
        this.aim = false;
        this.alwaysAim = false;
        this.aimX = 0;
        this.aimY = 0;

        this.aimingAngle = 0;

        if (params != null) {
            this.angle = params.angle || this.angle;
            this.aim = params.aim || this.aim;
            this.alwaysAim = params.always_aim || this.alwaysAim;
            this.aimX = params.aim_x || this.aimX;
            this.aimY = params.aim_y || this.aimY;
        }
    };

    /**
     * Shoots a single bullet towards this.angle or this.angle + angle between player and emitter.
     */
    BHell_Emitter_Angle.prototype.shoot = function () {
        var bullet;
        if (this.aim) {
            if (this.alwaysAim || this.oldShooting === false) {
                var dx = my.player.x - this.x + this.aimX;
                var dy = my.player.y - this.y + this.aimY;
                this.aimingAngle = Math.atan2(dy, dx);
            }

            bullet = new my.BHell_Bullet(this.x, this.y, this.aimingAngle, this.bulletParams, this.bulletList);
        }
        else {
            bullet = new my.BHell_Bullet(this.x, this.y, this.angle, this.bulletParams, this.bulletList);
        }

        this.parent.addChild(bullet);
        this.bulletList.push(bullet);
    };

    /**
     * Burst emitter. Creates many bullets packed randomly inside a dispersion circle.
     * @constructor
     * @memberOf BHell
     * @extends BHell.BHell_Emitter_Base
     */
    var BHell_Emitter_Burst = my.BHell_Emitter_Burst = function () {
        this.initialize.apply(this, arguments);
    };

    BHell_Emitter_Burst.prototype = Object.create(BHell_Emitter_Base.prototype);
    BHell_Emitter_Burst.prototype.constructor = BHell_Emitter_Burst;

    /**
     * Constructor.
     * Additional parameters:
     *
     * - angle: Angle at which the bullets will be shot,
     * - shots: Number of bullets which will be shot,
     * - dispersion: Diameter of the dispersion circle,
     * - aim: If true the shooting angle is determined like Emitter_Angle with aim = true,
     * - always_aim: if false (and aim = true) aiming only occours when there is a raising edge (shoot(false) -> shoot(true)),
     * - aim_x aiming horizontal offset (used only if aim = true),
     * - aim_y: aiming vertical offset (used only if aim = true).
     * @param x
     * @param y
     * @param params
     * @param parent
     * @param bulletList
     */
    BHell_Emitter_Burst.prototype.initialize = function (x, y, params, parent, bulletList) {
        BHell_Emitter_Base.prototype.initialize.call(this, x, y, params, parent, bulletList);

        this.angle = 0;
        this.shots = 1;
        this.dispersion = 0;
        this.aim = false;
        this.alwaysAim = false;
        this.aimX = 0;
        this.aimY = 0;
        this.aimingAngle = 0;

        if (params != null) {
            this.angle = params.angle || this.angle;
            this.shots = params.shots || this.shots;
            this.dispersion = params.dispersion || this.dispersion;
            this.aim = params.aim || this.aim;
            this.alwaysAim = params.always_aim || this.alwaysAim;
            this.aimX = params.aim_x || this.aimX;
            this.aimY = params.aim_y || this.aimY;
        }
    };

    /**
     * Creates this.shots bullets randomly inside a circle with this.dispersion diameter.
     */
    BHell_Emitter_Burst.prototype.shoot = function () {
        var offX = 0;
        var offY = 0;

        for (var k = 0; k < this.shots; k++) {
            // Create a shot randomly inside the dispersion circle.
            var r = Math.random() * this.dispersion / 2;
            var phi = Math.random() * 2 * Math.PI;
            offX = r * Math.cos(phi);
            offY = r * Math.sin(phi);
            var bullet;
            if (this.aim) {
                if (this.alwaysAim || this.oldShooting === false) {
                    var dx = my.player.x - this.x + this.aimX;
                    var dy = my.player.y - this.y + this.aimY;
                    this.aimingAngle = Math.atan2(dy, dx);
                }
                bullet = new my.BHell_Bullet(this.x + offX, this.y + offY, this.aimingAngle, this.bulletParams, this.bulletList);
            }
            else {
                bullet = new my.BHell_Bullet(this.x + offX, this.y + offY, this.angle, this.bulletParams, this.bulletList);
            }
            this.parent.addChild(bullet);
            this.bulletList.push(bullet);
        }
    };

    return my;
}(BHell || {}));