"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpawnRockAltRewards = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const cachedClasses_1 = require("../../../core/cachedClasses");
const constants_1 = require("../../../core/constants");
const decorators_1 = require("../../../decorators");
const ISCFeature_1 = require("../../../enums/ISCFeature");
const RockAltType_1 = require("../../../enums/RockAltType");
const entitiesSpecific_1 = require("../../../functions/entitiesSpecific");
const pickupsSpecific_1 = require("../../../functions/pickupsSpecific");
const projectiles_1 = require("../../../functions/projectiles");
const random_1 = require("../../../functions/random");
const rng_1 = require("../../../functions/rng");
const spawnCollectible_1 = require("../../../functions/spawnCollectible");
const utils_1 = require("../../../functions/utils");
const vector_1 = require("../../../functions/vector");
const Feature_1 = require("../../private/Feature");
const ROCK_ALT_CHANCES = {
    NOTHING: 0.68,
    BASIC_DROP: 0.0967,
    /** Also used for e.g. black hearts from skulls. */
    TRINKET: 0.025,
    COLLECTIBLE: 0.005,
};
const COIN_VELOCITY_MULTIPLIER = 2;
/** Matches the vanilla value, according to Fly's decompilation. */
const FIND_FREE_INITIAL_STEP = 70;
/** Matches the vanilla value, according to Fly's decompilation. */
const FART_RADIUS = constants_1.DISTANCE_OF_GRID_TILE * 3;
const POLYP_PROJECTILE_SPEED = 10;
const POLYP_NUM_PROJECTILES = 6;
class SpawnRockAltRewards extends Feature_1.Feature {
    itemPoolDetection;
    /** @internal */
    constructor(itemPoolDetection) {
        super();
        this.featuresUsed = [ISCFeature_1.ISCFeature.ITEM_POOL_DETECTION];
        this.itemPoolDetection = itemPoolDetection;
    }
    /**
     * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
     * breaks.
     *
     * Most of the time, this function will do nothing, similar to how most of the time, when an
     * individual urn is destroyed, nothing will spawn.
     *
     * Note that in vanilla, trinkets will not spawn if they have already been removed from the
     * trinket pool. This function cannot replicate that behavior because there is no way to check to
     * see if a trinket is still in the pool. Thus, it will always have a chance to spawn the
     * respective trinket
     * (e.g. Swallowed Penny from urns).
     *
     * When filled buckets are destroyed, 6 projectiles will always spawn in a random pattern (in
     * addition to any other rewards that are spawned). This function does not account for this, so if
     * you want to specifically emulate destroying a filled bucket, you have to account for the
     * projectiles yourself.
     *
     * The logic in this function is based on the rewards listed on the wiki:
     * https://bindingofisaacrebirth.fandom.com/wiki/Rocks
     *
     * If you want to spawn an unseeded reward, you must explicitly pass `undefined` to the
     * `seedOrRNG` parameter.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.SPAWN_ALT_ROCK_REWARDS`.
     *
     * @param positionOrGridIndex The position or grid index to spawn the reward.
     * @param rockAltType The type of reward to spawn. For example, `RockAltType.URN` will have a
     *                    chance at spawning coins and spiders.
     * @param seedOrRNG The `Seed` or `RNG` object to use. Normally, you should pass the `InitSeed` of
     *                  the grid entity that was broken. If an `RNG` object is provided, the
     *                  `RNG.Next` method will be called. If `undefined` is provided, it will default
     *                  to a random seed.
     * @returns Whether this function spawned something.
     * @public
     */
    spawnRockAltReward(positionOrGridIndex, rockAltType, seedOrRNG) {
        const room = cachedClasses_1.game.GetRoom();
        const position = (0, vector_1.isVector)(positionOrGridIndex)
            ? positionOrGridIndex
            : room.GetGridPosition(positionOrGridIndex);
        const rng = (0, rng_1.isRNG)(seedOrRNG) ? seedOrRNG : (0, rng_1.newRNG)(seedOrRNG);
        switch (rockAltType) {
            case RockAltType_1.RockAltType.URN: {
                return this.spawnRockAltRewardUrn(position, rng);
            }
            case RockAltType_1.RockAltType.MUSHROOM: {
                return this.spawnRockAltRewardMushroom(position, rng);
            }
            case RockAltType_1.RockAltType.SKULL: {
                return this.spawnRockAltRewardSkull(position, rng);
            }
            case RockAltType_1.RockAltType.POLYP: {
                return this.spawnRockAltRewardPolyp(position, rng);
            }
            case RockAltType_1.RockAltType.BUCKET_DOWNPOUR: {
                return this.spawnRockAltRewardBucketDownpour(position, rng);
            }
            case RockAltType_1.RockAltType.BUCKET_DROSS: {
                return this.spawnRockAltRewardBucketDross(position, rng);
            }
        }
    }
    /**
     * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
     * breaks of `RockAltType.URN`.
     *
     * For more information, see the documentation for the `spawnRockAltReward` function.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.SPAWN_ALT_ROCK_REWARDS`.
     */
    spawnRockAltRewardUrn(position, rng) {
        const room = cachedClasses_1.game.GetRoom();
        const chance = (0, random_1.getRandom)(rng);
        let totalChance = 0;
        totalChance += ROCK_ALT_CHANCES.NOTHING;
        if (chance < totalChance) {
            return false;
        }
        totalChance += ROCK_ALT_CHANCES.BASIC_DROP;
        if (chance < totalChance) {
            const numCoinsChance = (0, random_1.getRandom)(rng);
            const numCoins = numCoinsChance < 0.5 ? 1 : 2;
            (0, utils_1.repeat)(numCoins, () => {
                const randomVector = (0, vector_1.getRandomVector)(rng);
                const velocity = randomVector.mul(COIN_VELOCITY_MULTIPLIER);
                (0, pickupsSpecific_1.spawnCoinWithSeed)(isaac_typescript_definitions_1.CoinSubType.NULL, position, rng, velocity);
            });
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.TRINKET;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnTrinketWithSeed)(isaac_typescript_definitions_1.TrinketType.SWALLOWED_PENNY, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.COLLECTIBLE;
        if (chance < totalChance) {
            const stillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.QUARTER, isaac_typescript_definitions_1.ItemPoolType.DEVIL);
            if (stillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.QUARTER, position, rng);
                return true;
            }
            return false;
        }
        // Since the detrimental effect is the final option, we don't need to check the chance.
        const numEnemiesChance = (0, random_1.getRandom)(rng);
        const numEnemies = numEnemiesChance < 0.5 ? 1 : 2;
        (0, utils_1.repeat)(numEnemies, () => {
            const targetPos = room.FindFreePickupSpawnPosition(position, FIND_FREE_INITIAL_STEP);
            EntityNPC.ThrowSpider(position, undefined, targetPos, false, 0);
        });
        return true;
    }
    /**
     * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
     * breaks of `RockAltType.MUSHROOM`.
     *
     * For more information, see the documentation for the `spawnRockAltReward` function.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.SPAWN_ALT_ROCK_REWARDS`.
     */
    spawnRockAltRewardMushroom(position, rng) {
        const room = cachedClasses_1.game.GetRoom();
        const roomType = room.GetType();
        const chance = (0, random_1.getRandom)(rng);
        let totalChance = 0;
        totalChance += ROCK_ALT_CHANCES.NOTHING;
        if (chance < totalChance) {
            return false;
        }
        totalChance += ROCK_ALT_CHANCES.BASIC_DROP;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnPillWithSeed)(isaac_typescript_definitions_1.PillColor.NULL, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.TRINKET;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnTrinketWithSeed)(isaac_typescript_definitions_1.TrinketType.LIBERTY_CAP, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.COLLECTIBLE;
        if (chance < totalChance) {
            if (roomType === isaac_typescript_definitions_1.RoomType.SECRET) {
                const wavyCapChance = (0, random_1.getRandom)(rng);
                if (wavyCapChance < 0.0272) {
                    const stillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.WAVY_CAP, isaac_typescript_definitions_1.ItemPoolType.SECRET);
                    if (stillInPools) {
                        (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.WAVY_CAP, position, rng);
                        return true;
                    }
                }
            }
            const magicMushroomStillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.MAGIC_MUSHROOM, isaac_typescript_definitions_1.ItemPoolType.TREASURE);
            const miniMushStillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.MINI_MUSH, isaac_typescript_definitions_1.ItemPoolType.TREASURE);
            if (magicMushroomStillInPools && miniMushStillInPools) {
                const collectibleChance = (0, random_1.getRandom)(rng);
                const collectibleType = collectibleChance < 0.5
                    ? isaac_typescript_definitions_1.CollectibleType.MAGIC_MUSHROOM // 12
                    : isaac_typescript_definitions_1.CollectibleType.MINI_MUSH; // 71
                (0, spawnCollectible_1.spawnCollectible)(collectibleType, position, rng);
                return true;
            }
            if (magicMushroomStillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.MINI_MUSH, position, rng);
                return true;
            }
            if (miniMushStillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.MAGIC_MUSHROOM, position, rng);
                return true;
            }
            return false;
        }
        // Since the detrimental effect is the final option, we don't need to check the chance.
        cachedClasses_1.game.Fart(position);
        cachedClasses_1.game.ButterBeanFart(position, FART_RADIUS, undefined);
        return true;
    }
    /**
     * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
     * breaks of `RockAltType.SKULL`.
     *
     * For more information, see the documentation for the `spawnRockAltReward` function.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.SPAWN_ALT_ROCK_REWARDS`.
     */
    spawnRockAltRewardSkull(position, rng) {
        const chance = (0, random_1.getRandom)(rng);
        let totalChance = 0;
        totalChance += ROCK_ALT_CHANCES.NOTHING;
        if (chance < totalChance) {
            return false;
        }
        totalChance += ROCK_ALT_CHANCES.BASIC_DROP;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnCardWithSeed)(isaac_typescript_definitions_1.CardType.NULL, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.TRINKET;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnHeartWithSeed)(isaac_typescript_definitions_1.HeartSubType.BLACK, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.COLLECTIBLE;
        if (chance < totalChance) {
            const ghostBabyStillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.GHOST_BABY, isaac_typescript_definitions_1.ItemPoolType.TREASURE);
            const dryBabyStillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.DRY_BABY, isaac_typescript_definitions_1.ItemPoolType.TREASURE);
            if (ghostBabyStillInPools && dryBabyStillInPools) {
                const collectibleChance = (0, random_1.getRandom)(rng);
                const collectibleType = collectibleChance < 0.5
                    ? isaac_typescript_definitions_1.CollectibleType.GHOST_BABY // 163
                    : isaac_typescript_definitions_1.CollectibleType.DRY_BABY; // 265
                (0, spawnCollectible_1.spawnCollectible)(collectibleType, position, rng);
                return true;
            }
            if (ghostBabyStillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.DRY_BABY, position, rng);
                return true;
            }
            if (dryBabyStillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.GHOST_BABY, position, rng);
                return true;
            }
            return false;
        }
        // Since the detrimental effect is the final option, we don't need to check the chance.
        (0, entitiesSpecific_1.spawnNPCWithSeed)(isaac_typescript_definitions_1.EntityType.HOST, 0, 0, position, rng);
        return true;
    }
    /**
     * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
     * breaks of `RockAltType.POLYP`.
     *
     * For more information, see the documentation for the `spawnRockAltReward` function.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.SPAWN_ALT_ROCK_REWARDS`.
     */
    spawnRockAltRewardPolyp(position, rng) {
        const chance = (0, random_1.getRandom)(rng);
        let totalChance = 0;
        totalChance += ROCK_ALT_CHANCES.NOTHING;
        if (chance < totalChance) {
            return false;
        }
        totalChance += ROCK_ALT_CHANCES.BASIC_DROP;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnHeartWithSeed)(isaac_typescript_definitions_1.HeartSubType.NULL, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.TRINKET;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnTrinketWithSeed)(isaac_typescript_definitions_1.TrinketType.UMBILICAL_CORD, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.COLLECTIBLE;
        if (chance < totalChance) {
            const placentaStillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.PLACENTA, isaac_typescript_definitions_1.ItemPoolType.BOSS);
            const bloodClotStillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.BLOOD_CLOT, isaac_typescript_definitions_1.ItemPoolType.BOSS);
            if (placentaStillInPools && bloodClotStillInPools) {
                const collectibleChance = (0, random_1.getRandom)(rng);
                const collectibleType = collectibleChance < 0.5
                    ? isaac_typescript_definitions_1.CollectibleType.PLACENTA // 218
                    : isaac_typescript_definitions_1.CollectibleType.BLOOD_CLOT; // 254
                (0, spawnCollectible_1.spawnCollectible)(collectibleType, position, rng);
                return true;
            }
            if (placentaStillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.PLACENTA, position, rng);
                return true;
            }
            if (bloodClotStillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.BLOOD_CLOT, position, rng);
                return true;
            }
            return false;
        }
        // Since the detrimental effect is the final option, we don't need to check the chance.
        (0, entitiesSpecific_1.spawnEffectWithSeed)(isaac_typescript_definitions_1.EffectVariant.CREEP_RED, 0, position, rng);
        (0, projectiles_1.fireProjectilesInCircle)(undefined, position, POLYP_PROJECTILE_SPEED, POLYP_NUM_PROJECTILES);
        return true;
    }
    /**
     * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
     * breaks of `RockAltType.BUCKET_DOWNPOUR`.
     *
     * For more information, see the documentation for the `spawnRockAltReward` function.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.SPAWN_ALT_ROCK_REWARDS`.
     */
    spawnRockAltRewardBucketDownpour(position, rng) {
        const room = cachedClasses_1.game.GetRoom();
        const chance = (0, random_1.getRandom)(rng);
        let totalChance = 0;
        totalChance += ROCK_ALT_CHANCES.NOTHING;
        if (chance < totalChance) {
            return false;
        }
        totalChance += ROCK_ALT_CHANCES.BASIC_DROP;
        if (chance < totalChance) {
            const numCoinsChance = (0, random_1.getRandom)(rng);
            const numCoins = numCoinsChance < 0.5 ? 1 : 2;
            (0, utils_1.repeat)(numCoins, () => {
                const randomVector = (0, vector_1.getRandomVector)(rng);
                const velocity = randomVector.mul(COIN_VELOCITY_MULTIPLIER);
                (0, pickupsSpecific_1.spawnCoinWithSeed)(isaac_typescript_definitions_1.CoinSubType.NULL, position, rng, velocity);
            });
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.TRINKET;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnTrinketWithSeed)(isaac_typescript_definitions_1.TrinketType.SWALLOWED_PENNY, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.COLLECTIBLE;
        if (chance < totalChance) {
            const stillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.LEECH, isaac_typescript_definitions_1.ItemPoolType.TREASURE);
            if (stillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.LEECH, position, rng);
                return true;
            }
            return false;
        }
        // Since the detrimental effect is the final option, we don't need to check the chance.
        const enemiesChance = (0, random_1.getRandom)(rng);
        const entityType = enemiesChance < 0.5 ? isaac_typescript_definitions_1.EntityType.SPIDER : isaac_typescript_definitions_1.EntityType.SMALL_LEECH;
        const numEnemiesChance = (0, random_1.getRandom)(rng);
        const numEnemies = numEnemiesChance < 0.5 ? 1 : 2;
        (0, utils_1.repeat)(numEnemies, () => {
            const targetPos = room.FindFreePickupSpawnPosition(position, FIND_FREE_INITIAL_STEP);
            // If the room has water, Spiders will automatically be replaced with Striders.
            const spider = EntityNPC.ThrowSpider(position, undefined, targetPos, false, 0);
            // There is no `ThrowLeech` function exposed in the API, so we can piggyback off of the
            // `ThrowSpider` method.
            if (entityType === isaac_typescript_definitions_1.EntityType.SMALL_LEECH && spider.Type !== entityType) {
                spider.Morph(entityType, 0, 0, -1);
            }
        });
        return true;
    }
    /**
     * Helper function for emulating what happens when a vanilla `GridEntityType.ROCK_ALT` grid entity
     * breaks of `RockAltType.BUCKET_DROSS`.
     *
     * For more information, see the documentation for the `spawnRockAltReward` function.
     *
     * In order to use this function, you must upgrade your mod with
     * `ISCFeature.SPAWN_ALT_ROCK_REWARDS`.
     */
    spawnRockAltRewardBucketDross(position, rng) {
        const room = cachedClasses_1.game.GetRoom();
        const chance = (0, random_1.getRandom)(rng);
        let totalChance = 0;
        totalChance += ROCK_ALT_CHANCES.NOTHING;
        if (chance < totalChance) {
            return false;
        }
        totalChance += ROCK_ALT_CHANCES.BASIC_DROP;
        if (chance < totalChance) {
            const numCoinsChance = (0, random_1.getRandom)(rng);
            const numCoins = numCoinsChance < 0.5 ? 1 : 2;
            (0, utils_1.repeat)(numCoins, () => {
                const randomVector = (0, vector_1.getRandomVector)(rng);
                const velocity = randomVector.mul(COIN_VELOCITY_MULTIPLIER);
                (0, pickupsSpecific_1.spawnCoinWithSeed)(isaac_typescript_definitions_1.CoinSubType.NULL, position, rng, velocity);
            });
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.TRINKET;
        if (chance < totalChance) {
            (0, pickupsSpecific_1.spawnTrinketWithSeed)(isaac_typescript_definitions_1.TrinketType.BUTT_PENNY, position, rng);
            return true;
        }
        totalChance += ROCK_ALT_CHANCES.COLLECTIBLE;
        if (chance < totalChance) {
            const stillInPools = this.itemPoolDetection.isCollectibleInItemPool(isaac_typescript_definitions_1.CollectibleType.POOP, isaac_typescript_definitions_1.ItemPoolType.TREASURE);
            if (stillInPools) {
                (0, spawnCollectible_1.spawnCollectible)(isaac_typescript_definitions_1.CollectibleType.POOP, position, rng);
                return true;
            }
            return false;
        }
        // Since the detrimental effect is the final option, we don't need to check the chance.
        const enemiesChance = (0, random_1.getRandom)(rng);
        const entityType = enemiesChance < 0.5 ? isaac_typescript_definitions_1.EntityType.DRIP : isaac_typescript_definitions_1.EntityType.SMALL_LEECH;
        const numEnemiesChance = (0, random_1.getRandom)(rng);
        const numEnemies = numEnemiesChance < 0.5 ? 1 : 2;
        (0, utils_1.repeat)(numEnemies, () => {
            const targetPos = room.FindFreePickupSpawnPosition(position, FIND_FREE_INITIAL_STEP);
            const spider = EntityNPC.ThrowSpider(position, undefined, targetPos, false, 0);
            // There is no `ThrowLeech` or `ThrowDrip` functions exposed in the API, so we can piggyback
            // off of the `ThrowSpider` method.
            spider.Morph(entityType, 0, 0, -1);
        });
        return true;
    }
}
exports.SpawnRockAltRewards = SpawnRockAltRewards;
__decorate([
    decorators_1.Exported
], SpawnRockAltRewards.prototype, "spawnRockAltReward", null);
__decorate([
    decorators_1.Exported
], SpawnRockAltRewards.prototype, "spawnRockAltRewardUrn", null);
__decorate([
    decorators_1.Exported
], SpawnRockAltRewards.prototype, "spawnRockAltRewardMushroom", null);
__decorate([
    decorators_1.Exported
], SpawnRockAltRewards.prototype, "spawnRockAltRewardSkull", null);
__decorate([
    decorators_1.Exported
], SpawnRockAltRewards.prototype, "spawnRockAltRewardPolyp", null);
__decorate([
    decorators_1.Exported
], SpawnRockAltRewards.prototype, "spawnRockAltRewardBucketDownpour", null);
__decorate([
    decorators_1.Exported
], SpawnRockAltRewards.prototype, "spawnRockAltRewardBucketDross", null);
