import { system, world, ItemStack, ItemFoodComponent, ItemDurabilityComponent, EntityInventoryComponent, Direction, TimeOfDay, DimensionTypes, EntityEquippableComponent, EquipmentSlot, EntityTypeFamilyComponent, PlayerCursorInventoryComponent, EntityItemComponent, EntityHealthComponent, ItemEnchantableComponent, Player } from '@minecraft/server';
import { MessageFormData, ActionFormData, FormRejectError, FormCancelationReason, ModalFormData } from '@minecraft/server-ui';

/******************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */


function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
    var e = new Error(message);
    return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};

const asyncWait = async (ticks) => {
    return new Promise((resolve) => {
        system.runTimeout(() => {
            resolve();
        }, ticks);
    });
};
const runUntilSuccess = (target, command, expectedCount, stopIf) => {
    return new Promise((resolve) => {
        const handler = system.runInterval(() => {
            const result = target.runCommand(command);
            if (result.successCount === expectedCount || stopIf()) {
                resolve();
                system.clearRun(handler);
            }
        }, 1);
    });
};
const TRANSLATE$1 = (translate, with_, ...with__) => {
    return {
        translate,
        with: typeof with_ === 'string' ? [with_, ...with__] : with_,
    };
};

const DefaultShowDialogOptions = Object.freeze({
    lockPlayerCamera: true,
    busyRetriesCount: 5,
    busyRetriesTick: 5,
});
/**
 * Base class for all the script dialogues
 *
 * @category Script dialogue
 */
class ScriptDialogue {
    constructor() { }
    /**
     * Opens the script dialogue. It requires the {@link ShowDialogueOptions#player player} as one of the options.
     *
     * You can configure displaying features by setting the optional values in the {@link ShowDialogueOptions options}
     * @param options used to configure what and how to display the script dialogue.
     *
     * @see {@link ShowDialogueOptions}
     */
    async open(options) {
        const resolvedOptions = this.resolveShowDialogueOptions(options);
        try {
            if (resolvedOptions.lockPlayerCamera) {
                this.lockPlayerCamera(resolvedOptions);
            }
            try {
                const showable = await this.getShowable(resolvedOptions);
                const response = await this.show(showable, resolvedOptions);
                if (response.canceled) {
                    return new DialogueCanceledResponse(response.cancelationReason);
                }
                return await this.processResponse(response, resolvedOptions);
            }
            catch (e) {
                if (e && e instanceof FormRejectError) {
                    return new DialogueRejectedResponse(e.reason, e);
                }
                else {
                    return new DialogueRejectedResponse(undefined, e);
                }
            }
        }
        finally {
            if (resolvedOptions.lockPlayerCamera) {
                await this.unlockPlayerCamera(resolvedOptions);
            }
        }
    }
    async show(showable, options) {
        let i = 0;
        for (;;) {
            const response = await showable.show(options.player);
            if (response.canceled && response.cancelationReason === FormCancelationReason.UserBusy) {
                if (i < options.busyRetriesCount) {
                    i++;
                    await asyncWait(options.busyRetriesTick);
                    if (options.player.isValid()) {
                        continue;
                    }
                }
            }
            return response;
        }
    }
    lockPlayerCamera(options) {
        options.player.runCommand(`inputpermission set "${options.player.name}" camera disabled`);
        options.player.runCommand(`inputpermission set "${options.player.name}" movement disabled`);
    }
    async unlockPlayerCamera(options) {
        await runUntilSuccess(options.player, `inputpermission set "${options.player.name}" camera enabled`, 1, () => !options.player.isValid());
        await runUntilSuccess(options.player, `inputpermission set "${options.player.name}" movement enabled`, 1, () => !options.player.isValid());
    }
    resolveShowDialogueOptions(options) {
        return {
            ...DefaultShowDialogOptions,
            ...options,
        };
    }
}
/**
 * Base class for script dialogue responses
 *
 * @category Responses
 */
class ScriptDialogueResponse {
}
/**
 * Dialogue response when the script dialogue was canceled.
 *
 * Typically this happens if the player was busy when trying to open the script dialogue or if the user
 * pressed the close button (x).
 *
 * Valid reasons can be seen in {@link @minecraft/server-ui!FormCancelationReason FormCancelationReason}
 *
 * @category Responses
 */
class DialogueCanceledResponse extends ScriptDialogueResponse {
    /**
     * Reason the script dialogue was cancel.
     */
    reason;
    /**
     * @internal
     */
    constructor(reason) {
        super();
        this.reason = reason;
    }
}
/**
 * Dialogue response when the script dialogue was rejected, throwing an exception.
 *
 * Reasons can be seen in {@link @minecraft/server-ui!FormRejectReason FormRejectReason} if any reason could be
 * determined.
 *
 * Known reasons can be seen in {@link @minecraft/server-ui!FormRejectReason FormRejectReason}
 * @category Responses
 */
class DialogueRejectedResponse extends ScriptDialogueResponse {
    /**
     * Reason the script dialogue was rejected if there was any, else the {@link exception} needs to be checked
     * to further determine what was the error.
     */
    reason;
    /**
     * Exception that was throw to rejected the script dialogue.
     */
    exception;
    /**
     * @internal
     */
    constructor(reason, exception) {
        super();
        this.reason = reason;
        this.exception = exception;
    }
}
/**
 * Response for button script dialogues.
 *
 * Contains the selected button's name.
 *
 * @category Responses
 * @category Dual button script dialogue
 * @category Multi button script dialogue
 */
class ButtonDialogueResponse extends ScriptDialogueResponse {
    /**
     * Selected button's name.
     *
     * @see {@link DualButton#name}
     * @see {@link MultiButton#name}
     */
    selected;
    callback;
    /**
     * @internal
     */
    constructor(selected, callback) {
        super();
        this.selected = selected;
        this.callback = callback;
    }
}
class MissingButtonsException extends Error {
    constructor() {
        super('Missing buttons');
    }
}

/**
 * Creates a new dual button script dialogue
 *
 * @category Creation
 * @category Dual button script dialogue
 * @param title Title of the dual button script dialogue
 * @param topButton Contents of the top button
 * @param bottomButton Contents of the bottom button
 */
const dualButtonScriptDialogue = (title, topButton, bottomButton) => {
    return new DualButtonScriptDialogue(title, undefined, topButton, bottomButton);
};
/**
 * Dual button script dialogue class.
 *
 * User's don't need to instantiate this class directly, instead they can use {@link dualButtonScriptDialogue}.
 *
 * Allows the users to optionally set a value for the body by calling {@link DualButtonScriptDialogue#setBody setBody}.
 *
 * @category Dual button script dialogue
 */
class DualButtonScriptDialogue extends ScriptDialogue {
    title;
    body;
    topButton;
    bottomButton;
    /**
     * @internal
     */
    constructor(title, body, topButton, bottomButton) {
        super();
        this.title = title;
        this.body = body;
        this.topButton = topButton;
        this.bottomButton = bottomButton;
    }
    /**
     * Sets content of the script dialogue
     * @param body
     */
    setBody(body) {
        return new DualButtonScriptDialogue(this.title, body, this.topButton, this.bottomButton);
    }
    getShowable(_options) {
        const data = new MessageFormData();
        data.title(this.title);
        if (this.body) {
            data.body(this.body);
        }
        data.button1(this.bottomButton.text);
        data.button2(this.topButton.text);
        return data;
    }
    async processResponse(response, _options) {
        const selectedButton = response.selection === 0 ? this.bottomButton : this.topButton;
        let callbackResponse = undefined;
        if (selectedButton.callback) {
            callbackResponse = await selectedButton.callback(selectedButton.name);
        }
        return new ButtonDialogueResponse(selectedButton.name, callbackResponse);
    }
}

/**
 * Initializes a empty multi button script dialogue.
 *
 * Buttons needs to be added using {@link MultiButtonDialogue#addButton} or {@link MultiButtonDialogue#addButtons}
 *
 * @category Creation
 * @category Multi button script dialogue
 * @param title
 */
const multiButtonScriptDialogue = (title) => {
    return new MultiButtonDialogue(title, undefined, []);
};
/**
 * Class used to build multi button script dialogues.
 *
 * Use {@link multiButtonScriptDialogue} to initialize one.
 *
 * @category Multi button script dialogue
 * @see {@link multiButtonScriptDialogue}
 */
class MultiButtonDialogue extends ScriptDialogue {
    title;
    body;
    buttons;
    /**
     * @internal
     */
    constructor(title, body, buttons) {
        super();
        this.title = title;
        this.body = body;
        this.buttons = buttons;
    }
    /**
     * Sets the content body of the multi button dialogue
     * @param body
     */
    setBody(body) {
        return new MultiButtonDialogue(this.title, body, this.buttons);
    }
    /**
     * Adds a button to the multi button script dialogue.
     * @param name name of the button
     * @param text content of the button
     * @param iconPath path to an icon to show in the button
     */
    addButton(name, text, iconPath, callback) {
        return new MultiButtonDialogue(this.title, this.body, [
            ...this.buttons,
            {
                name,
                text,
                iconPath,
                callback,
            },
        ]);
    }
    /**
     * Adds multiple buttons to the multi button script dialogue.
     * @param buttons array of buttons
     */
    addButtons(buttons) {
        return new MultiButtonDialogue(this.title, this.body, [
            ...this.buttons,
            ...buttons,
        ]);
    }
    getShowable(_options) {
        if (this.buttons.length === 0) {
            throw new MissingButtonsException();
        }
        const formData = new ActionFormData();
        formData.title(this.title);
        if (this.body) {
            formData.body(this.body);
        }
        this.buttons.forEach((button) => {
            formData.button(button.text, button.iconPath);
        });
        return formData;
    }
    async processResponse(response, _options) {
        const selectedButton = this.buttons[response.selection];
        let callbackResponse = undefined;
        if (selectedButton.callback) {
            callbackResponse = await selectedButton.callback(selectedButton.name);
        }
        return new ButtonDialogueResponse(selectedButton.name, callbackResponse);
    }
}

/**
 * Initializes a empty input script dialogue.
 *
 * Elements needs to be added using {@link InputScriptDialogue#addElement} or {@link InputScriptDialogue#addElements}
 *
 * @category Creation
 * @category Input script dialogue
 *
 * @param title Title for the script dialogue
 */
const inputScriptDialogue = (title) => {
    return new InputScriptDialogue(title, []);
};
/**
 * Creates a new dropdown element to use in a input script dialogue.
 *
 * @category Input script dialogue
 * @param name
 * @param label
 */
const inputDropdown = (name, label) => {
    return new InputDropdown(name, label, [], 0);
};
/**
 * Creates a new slider element to use in a input script dialogue.
 *
 * @category Input script dialogue
 * @param name
 * @param label
 * @param minimumValue
 * @param maximumValue
 * @param valueStep
 * @param defaultValue
 */
const inputSlider = (name, label, minimumValue, maximumValue, valueStep, defaultValue) => {
    return new InputSlider(name, label, minimumValue, maximumValue, valueStep, defaultValue);
};
/**
 * Creates a new toggle element to use in a input script dialogue.
 *
 * @category Input script dialogue
 * @param name
 * @param label
 * @param defaultValue
 */
const inputToggle = (name, label, defaultValue) => {
    return new InputToggle(name, label, defaultValue);
};
/**
 * Base for all input elements displayed in the input script dialogue.
 *
 * You don't need to instantiate this class directly, instead you can use any of the builder function
 * depending the type you want to use.
 *
 * @category Input script dialogue
 * @see {@link inputDropdown}
 * @see {@link inputSlider}
 * @see {@link inputToggle}
 * @see {@link inputText}
 */
class InputElement {
    /**
     * @internal
     */
    name;
    /**
     * @internal
     */
    label;
    /**
     * @internal
     */
    constructor(name, label) {
        this.name = name;
        this.label = label;
    }
}
/**
 * Base for all input elements that have a fixed default value.
 *
 * You don't need to instantiate this class directly, instead you can use any of the builder function
 * depending the type you want to use.
 *
 * @category Input script dialogue
 * @see {@link inputDropdown}
 * @see {@link inputSlider}
 * @see {@link inputToggle}
 * @see {@link inputText}
 */
class InputWithDefaultValue extends InputElement {
    /**
     * @internal
     */
    defaultValue;
    /**
     * @internal
     */
    constructor(name, label, defaultValue) {
        super(name, label);
        this.defaultValue = defaultValue;
    }
}
/**
 * @internal
 */
class InputDropdownOption {
    label;
    value;
    constructor(label, value) {
        this.label = label;
        this.value = value;
    }
}
/**
 * Input element's representation of a dropdown.
 *
 * Instantiate by using {@link inputDropdown}
 *
 * @category Input script dialogue
 * @see {@link inputDropdown}
 */
class InputDropdown extends InputElement {
    /**
     * @internal
     */
    options;
    /**
     * @internal
     */
    defaultValueIndex;
    /**
     * @internal
     */
    constructor(name, label, options, defaultValueIndex) {
        super(name, label);
        this.defaultValueIndex = defaultValueIndex ?? 0;
        this.options = options;
    }
    /**
     * Sets the default index of the option you would like to use
     * @param defaultValueIndex
     */
    setDefaultValueIndex(defaultValueIndex) {
        return new InputDropdown(this.name, this.label, [...this.options], defaultValueIndex);
    }
    /**
     * Adds an option to the dropdown
     * @param label
     * @param value
     */
    addOption(label, value) {
        return new InputDropdown(this.name, this.label, [...this.options, new InputDropdownOption(label, value)], this.defaultValueIndex);
    }
}
/**
 * Input element's representation of a slider.
 *
 * Instantiate by using {@link inputSlider}
 *
 * @category Input script dialogue
 * @see {@link inputSlider}
 */
class InputSlider extends InputWithDefaultValue {
    /**
     * @internal
     */
    minimumValue;
    /**
     * @internal
     */
    maximumValue;
    /**
     * @internal
     */
    valueStep;
    /**
     * @internal
     */
    constructor(name, label, minimumValue, maximumValue, valueStep, defaultValue) {
        super(name, label, defaultValue ?? minimumValue);
        this.minimumValue = minimumValue;
        this.maximumValue = maximumValue;
        this.valueStep = valueStep;
    }
}
/**
 * Input element's representation of text field.
 *
 * Instantiate by using {@link inputText}
 *
 * @category Input script dialogue
 * @see {@link inputText}
 */
class InputText extends InputWithDefaultValue {
    /**
     * @internal
     */
    placeholderText;
    /**
     * @internal
     */
    constructor(name, label, placeholderText, defaultValue) {
        super(name, label, defaultValue ?? '');
        this.placeholderText = placeholderText;
    }
}
/**
 * Input element's representation of toggle.
 *
 * Instantiate by using {@link inputToggle}
 *
 * @category Input script dialogue
 * @see {@link inputToggle}
 */
class InputToggle extends InputWithDefaultValue {
    /**
     * @internal
     */
    constructor(name, label, defaultValue) {
        super(name, label, !!defaultValue);
    }
}
/**
 * Class used to build input script dialogues.
 *
 * Use {@link inputScriptDialogue} to initialize one.
 *
 * @category Input script dialogue
 * @see {@link inputScriptDialogue}
 */
class InputScriptDialogue extends ScriptDialogue {
    elements;
    title;
    // work around TS2848: The right-hand side of an instanceof expression must not be an instantiation expression.
    InputDropdown = (InputDropdown);
    InputSlider = (InputSlider);
    InputText = (InputText);
    InputToggle = (InputToggle);
    /**
     * @internal
     */
    constructor(title, elements) {
        super();
        this.title = title;
        this.elements = elements;
    }
    /**
     * Adds an input element to the input script dialogue.
     * @param element
     *
     * @see {@link inputDropdown}
     * @see {@link inputSlider}
     * @see {@link inputToggle}
     * @see {@link inputText}
     */
    addElement(element) {
        return new InputScriptDialogue(this.title, [...this.elements, element]);
    }
    /**
     * Adds multiple input element to the input script dialogue.
     * @param elements
     *
     * @see {@link inputDropdown}
     * @see {@link inputSlider}
     * @see {@link inputToggle}
     * @see {@link inputText}
     */
    addElements(elements) {
        return new InputScriptDialogue(this.title, [...this.elements, ...elements]);
    }
    getShowable(_options) {
        if (this.elements.length === 0) {
            throw new MissingElementsError();
        }
        const data = new ModalFormData();
        data.title(this.title);
        this.elements.forEach((element) => {
            if (element instanceof this.InputDropdown) {
                if (element.options.length === 0) {
                    throw new MissingDropdownOptionsError(element.name);
                }
                data.dropdown(element.label, element.options.map((o) => o.label), element.defaultValueIndex);
            }
            else if (element instanceof this.InputSlider) {
                data.slider(element.label, element.minimumValue, element.maximumValue, element.valueStep, element.defaultValue);
            }
            else if (element instanceof this.InputText) {
                data.textField(element.label, element.placeholderText, element.defaultValue);
            }
            else if (element instanceof this.InputToggle) {
                data.toggle(element.label, element.defaultValue);
            }
        });
        return data;
    }
    async processResponse(response, _options) {
        const formValues = response.formValues ?? this.elements.map((_e) => undefined);
        const values = this.elements.map((element, index) => {
            const name = element.name;
            let value = 0;
            const formValue = formValues[index];
            if (element instanceof this.InputDropdown) {
                value = element.options[element.defaultValueIndex].value;
                if (formValue !== undefined) {
                    value = element.options[formValue].value;
                }
            }
            else if (element instanceof this.InputSlider ||
                element instanceof this.InputText ||
                element instanceof this.InputToggle) {
                value = element.defaultValue;
                if (formValue !== undefined) {
                    value = formValue;
                }
            }
            return {
                [name]: value,
            };
        });
        return new InputScriptDialogueResponse(Object.assign({}, ...values));
    }
}
/**
 * Script dialogue response from a input script dialogue.
 * Holds a map with the values used by each of the element's name.
 *
 * @category Input script dialogue
 * @category Responses
 */
class InputScriptDialogueResponse {
    /**
     * Map with the values of the script dialogue..
     */
    values;
    constructor(values) {
        this.values = values;
    }
}
class MissingElementsError extends Error {
    constructor() {
        super('Missing input elements');
    }
}
class MissingDropdownOptionsError extends Error {
    constructor(name) {
        super(`Missing dropdown options for ${name}`);
    }
}

const debug = (what) => {
    const players = world.getPlayers({
        tags: ["debug"]
    });
    if (players.length > 0) {
        const text = typeof what === 'string' ? what : what();
        for (const player of players) {
            void player.dimension.runCommandAsync(`w ${player.name} debug: ${text}`);
        }
    }
};

const GET_RAW_PROP = (target, identifier) => {
    return target.getDynamicProperty(identifier);
};
const SET_RAW_PROP = (target, identifier, value) => {
    target.setDynamicProperty(identifier, value);
};
const GET_PROP = (target, identifier, defaultValue) => {
    const value = target.getDynamicProperty(identifier);
    if (typeof value === 'string') {
        return JSON.parse(value);
    }
    if (defaultValue) {
        return defaultValue;
    }
    const message = `Invalid identifier ${identifier}`;
    debug(message);
    throw new Error(message);
};
const SET_PROP = (target, identifier, value) => {
    target.setDynamicProperty(identifier, JSON.stringify(value));
};
// export const mutateDynamicProperty = <T>(target: WithDynamicProperty, identifier: string, mutator: DynamicPropertyMutator<T>) => {
//   const input = target.getDynamicProperty(identifier);
//   const output = mutator(typeof input === 'string' ? JSON.parse(input) : undefined);
//   target.setDynamicProperty(identifier, JSON.stringify(output));
// }
//
// export class DynamicPropertyContext<T> {
//   private _value: T;
//   private target: WithDynamicProperty;
//   private identifier: string;
//
//   constructor(target: WithDynamicProperty, identifier: string, defaultValue: T) {
//     this.target = target;
//     this.identifier = identifier;
//     const value = target.getDynamicProperty(identifier);
//     this._value = typeof value === 'string' ? JSON.parse(value) : undefined;
//   }
//
//   public get value() {
//     return this._value;
//   }
//
//   private set value(value: T) {
//     this._value = value;
//   }
//
//   mutate(mutator: DynamicPropertyMutator<T>) {
//     this.value = mutator(this.value);
//   }
//
//   commit() {
//     this.target.setDynamicProperty(this.identifier, JSON.stringify(this.value));
//   }
// }

const TRANSLATE = (key, ...params) => ({
    translate: key,
    with: params.length > 0 ? typeof params[0] === 'string' ? params : RAW_TEXT(...params) : undefined
});
const RAW_TEXT = (...rawText) => ({
    rawtext: rawText
});
const TEXT = (value) => ({
    text: value.toString()
});

const MUTATED_SPAWNED = "jig_bmu:spawn.mutated_spawn";
const FACTION_MUTANT_SPAWNED = "jig_bmu:spawn.faction_mutant";
const MUTANTS = [
    { mutant: "jig_bmu:allay", maxhp: 100, difficulty: "jig_bmu:d.thr", difficulty_num: 3, tameable: "jig_bmu:alla.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:string.no" },
    { mutant: "jig_bmu:armadillo", maxhp: 80, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:arma.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.armo" },
    { mutant: "jig_bmu:axolotl", maxhp: 64, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.axol" },
    { mutant: "jig_bmu:bat", maxhp: 50, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.batx" },
    { mutant: "jig_bmu:bee", maxhp: 170, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.beee" },
    { mutant: "jig_bmu:blaze", maxhp: 50, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.blae" },
    { mutant: "jig_bmu:bogged", maxhp: 230, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.bogd" },
    { mutant: "jig_bmu:cave_spider", maxhp: 150, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:facn.ride", spawnsNaturally: "jig_bmu:spawn.cavr" },
    { mutant: "jig_bmu:cerberus", maxhp: 750, difficulty: "jig_bmu:d.bos", difficulty_num: 5, tameable: "jig_bmu:cerb.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:tame.ride", spawnsNaturally: "jig_bmu:string.no" },
    { mutant: "jig_bmu:cow", maxhp: 20, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:facn.ride", spawnsNaturally: "jig_bmu:spawn.coww" },
    { mutant: "jig_bmu:creeper", maxhp: 220, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.crer" },
    { mutant: "jig_bmu:dolphin", maxhp: 400, difficulty: "jig_bmu:d.bos", difficulty_num: 5, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.doln" },
    { mutant: "jig_bmu:drowned", maxhp: 120, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.drod" },
    { mutant: "jig_bmu:dan_drowned", maxhp: 700, difficulty: "jig_bmu:d.bos", difficulty_num: 5, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.dand" },
    { mutant: "jig_bmu:enderman", maxhp: 200, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.ende" },
    { mutant: "jig_bmu:endermite", maxhp: 35, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.endm" },
    { mutant: "jig_bmu:evoker", maxhp: 300, difficulty: "jig_bmu:d.thr", difficulty_num: 3, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.evor" },
    { mutant: "jig_bmu:farmageddon", maxhp: 800, difficulty: "jig_bmu:d.bos", difficulty_num: 5, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.farn" },
    { mutant: "jig_bmu:goat", maxhp: 60, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:anyt.ride", spawnsNaturally: "jig_bmu:spawn.goat" },
    { mutant: "jig_bmu:hoglin", maxhp: 220, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:hogl.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:tame.ride", spawnsNaturally: "jig_bmu:spawn.hogn" },
    { mutant: "jig_bmu:horse", maxhp: 40, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:hors.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:tame.ride", spawnsNaturally: "jig_bmu:spawn.hore" },
    { mutant: "jig_bmu:husk", maxhp: 180, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:facn.ride", spawnsNaturally: "jig_bmu:spawn.husk" },
    { mutant: "jig_bmu:megamooshroom", maxhp: 200, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:anyt.ride", spawnsNaturally: "jig_bmu:spawn.mooo" },
    { mutant: "jig_bmu:mooshroom", maxhp: 20, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:facn.ride", spawnsNaturally: "jig_bmu:spawn.moom" },
    { mutant: "jig_bmu:ocelot", maxhp: 60, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:ocel.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:tame.ride", spawnsNaturally: "jig_bmu:spawn.ocet" },
    { mutant: "jig_bmu:pig", maxhp: 15, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:facn.ride", spawnsNaturally: "jig_bmu:spawn.pigg" },
    { mutant: "jig_bmu:piglin", maxhp: 50, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.pign" },
    { mutant: "jig_bmu:piglin_brute", maxhp: 400, difficulty: "jig_bmu:d.fou", difficulty_num: 4, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.pige" },
    { mutant: "jig_bmu:pillager", maxhp: 200, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.pilr" },
    { mutant: "jig_bmu:ravager", maxhp: 400, difficulty: "jig_bmu:d.fou", difficulty_num: 4, tameable: "jig_bmu:rava.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:tame.ride", spawnsNaturally: "jig_bmu:spawn.ravr" },
    { mutant: "jig_bmu:silverfish", maxhp: 25, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.silh" },
    { mutant: "jig_bmu:skeleton", maxhp: 230, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.sken" },
    { mutant: "jig_bmu:skeleton_horse", maxhp: 60, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:anyt.ride", spawnsNaturally: "jig_bmu:spawn.skee" },
    { mutant: "jig_bmu:sniffer", maxhp: 100, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:string.no" },
    { mutant: "jig_bmu:sandra", maxhp: 1000, difficulty: "jig_bmu:d.bos", difficulty_num: 5, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:anyt.ride", spawnsNaturally: "jig_bmu:string.no" },
    { mutant: "jig_bmu:snow_golem", maxhp: 300, difficulty: "jig_bmu:d.thr", difficulty_num: 3, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.snom" },
    { mutant: "jig_bmu:spider", maxhp: 120, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:facn.ride", spawnsNaturally: "jig_bmu:spawn.spir" },
    { mutant: "jig_bmu:iron_golem", maxhp: 800, difficulty: "jig_bmu:d.bos", difficulty_num: 5, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:string.no" },
    { mutant: "jig_bmu:stray", maxhp: 200, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.stry" },
    { mutant: "jig_bmu:turtle", maxhp: 8, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.ture" },
    { mutant: "jig_bmu:vex", maxhp: 14, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:string.no" },
    { mutant: "jig_bmu:villager", maxhp: 200, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:string.no" },
    { mutant: "jig_bmu:vindicator", maxhp: 250, difficulty: "jig_bmu:d.thr", difficulty_num: 3, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.vinr" },
    { mutant: "jig_bmu:warden", maxhp: 1200, difficulty: "jig_bmu:d.bos", difficulty_num: 5, tameable: "jig_bmu:ward.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:tame.ride", spawnsNaturally: "jig_bmu:string.no" },
    { mutant: "jig_bmu:witch", maxhp: 250, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.with" },
    { mutant: "jig_bmu:wither_skeleton", maxhp: 250, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.witn" },
    { mutant: "jig_bmu:wolf", maxhp: 80, difficulty: "jig_bmu:d.one", difficulty_num: 1, tameable: "jig_bmu:wolf.tame", canmutate: "jig_bmu:string.ye", canride: "jig_bmu:tame.ride", spawnsNaturally: "jig_bmu:spawn.wolf" },
    { mutant: "jig_bmu:zoglin", maxhp: 250, difficulty: "jig_bmu:d.thr", difficulty_num: 3, tameable: "jig_bmu:zogl.tame", canmutate: "jig_bmu:string.no", canride: "jig_bmu:tame.ride", spawnsNaturally: "jig_bmu:spawn.zogn" },
    { mutant: "jig_bmu:zombie", maxhp: 160, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:facn.ride", spawnsNaturally: "jig_bmu:spawn.zome" },
    { mutant: "jig_bmu:zombie_juju", maxhp: 420, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.zomj" },
    { mutant: "jig_bmu:zombie_pigman", maxhp: 210, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:string.no", spawnsNaturally: "jig_bmu:spawn.zomn" },
    { mutant: "jig_bmu:zombie_villager", maxhp: 200, difficulty: "jig_bmu:d.two", difficulty_num: 2, tameable: "jig_bmu:string.no", canmutate: "jig_bmu:string.no", canride: "jig_bmu:facn.ride", spawnsNaturally: "jig_bmu:spawn.zomr" },
];
const MutantEffects = [
    { mutant: "jig_bmu:cave_spider", effect: "poison", duration_e: 4, strength_e: 0, duration_n: 8, strength_n: 1, duration_h: 16, strength_h: 2 },
    { mutant: "jig_bmu:drowned", effect: "mining_fatigue", duration_e: 10, strength_e: 0, duration_n: 10, strength_n: 1, duration_h: 10, strength_h: 2 },
    { mutant: "jig_bmu:dolphin", effect: "nausea", duration_e: 5, strength_e: 0, duration_n: 10, strength_n: 0, duration_h: 15, strength_h: 0 },
    { mutant: "jig_bmu:husk", effect: "hunger", duration_e: 10, strength_e: 0, duration_n: 10, strength_n: 1, duration_h: 10, strength_h: 2 },
    { mutant: "jig_bmu:stray", effect: "weakness", duration_e: 10, strength_e: 0, duration_n: 10, strength_n: 1, duration_h: 10, strength_h: 2 },
    { mutant: "jig_bmu:wither_skeleton", effect: "wither", duration_e: 10, strength_e: 0, duration_n: 15, strength_n: 0, duration_h: 20, strength_h: 0 },
];
const isMutant = (mutant) => {
    return MUTANTS.some((m) => m.mutant === mutant);
};
const mutation_information = [
    { mob: "jig_bmu:invalid", mutate_into: "jig_bmu:zombie_juju" },
    { mob: "minecraft:axolotl", mutate_into: "jig_bmu:axolotl" },
    { mob: "minecraft:bat", mutate_into: "jig_bmu:bat" },
    { mob: "minecraft:allay", mutate_into: "jig_bmu:allay" },
    { mob: "minecraft:armadillo", mutate_into: "jig_bmu:armadillo" },
    { mob: "minecraft:axolotl", mutate_into: "jig_bmu:axolotl" },
    { mob: "minecraft:iron_golem", mutate_into: "jig_bmu:iron_golem" },
    { mob: "minecraft:bee", mutate_into: "jig_bmu:bee" },
    { mob: "minecraft:bogged", mutate_into: "jig_bmu:bogged" },
    { mob: "minecraft:blaze", mutate_into: "jig_bmu:blaze" },
    { mob: "minecraft:cave_spider", mutate_into: "jig_bmu:cave_spider" },
    { mob: "minecraft:creeper", mutate_into: "jig_bmu:creeper" },
    { mob: "minecraft:dolphin", mutate_into: "jig_bmu:dolphin" },
    { mob: "minecraft:drowned", mutate_into: "jig_bmu:drowned" },
    { mob: "jig_bmu:drowned", mutate_into: "jig_bmu:dan_drowned" },
    { mob: "minecraft:enderman", mutate_into: "jig_bmu:enderman" },
    { mob: "minecraft:evocation_illager", mutate_into: "jig_bmu:evoker" },
    { mob: "jig_bmu:vindicator", mutate_into: "jig_bmu:evoker" },
    { mob: "minecraft:wither", mutate_into: "jig_bmu:farmageddon" },
    { mob: "minecraft:goat", mutate_into: "jig_bmu:goat" },
    { mob: "minecraft:hoglin", mutate_into: "jig_bmu:hoglin" },
    { mob: "minecraft:horse", mutate_into: "jig_bmu:horse" },
    { mob: "minecraft:husk", mutate_into: "jig_bmu:husk" },
    { mob: "jig_bmu:mooshroom", mutate_into: "jig_bmu:megamooshroom" },
    { mob: "minecraft:cow", mutate_into: "jig_bmu:cow" },
    { mob: "jig_bmu:cow", mutate_into: "jig_bmu:mooshroom" },
    { mob: "minecraft:mooshroom", mutate_into: "jig_bmu:mooshroom" },
    { mob: "jig_bmu:piglin", mutate_into: "jig_bmu:piglin_brute" },
    { mob: "jig_bmu:pig", mutate_into: "jig_bmu:piglin" },
    { mob: "minecraft:pig", mutate_into: "jig_bmu:pig" },
    { mob: "minecraft:piglin", mutate_into: "jig_bmu:piglin" },
    { mob: "minecraft:turtle", mutate_into: "jig_bmu:turtle" },
    { mob: "minecraft:ocelot", mutate_into: "jig_bmu:ocelot" },
    { mob: "minecraft:piglin_brute", mutate_into: "jig_bmu:piglin_brute" },
    { mob: "jig_bmu:pillager", mutate_into: "jig_bmu:vindicator" },
    { mob: "minecraft:pillager", mutate_into: "jig_bmu:pillager" },
    { mob: "minecraft:ravager", mutate_into: "jig_bmu:ravager" },
    { mob: "minecraft:skeleton", mutate_into: "jig_bmu:skeleton" },
    { mob: "minecraft:skeleton_horse", mutate_into: "jig_bmu:skeleton_horse" },
    { mob: "minecraft:snow_golem", mutate_into: "jig_bmu:snow_golem" },
    { mob: "minecraft:spider", mutate_into: "jig_bmu:spider" },
    { mob: "minecraft:stray", mutate_into: "jig_bmu:stray" },
    { mob: "minecraft:vex", mutate_into: "jig_bmu:vex" },
    { mob: "minecraft:villager", mutate_into: "jig_bmu:villager" },
    { mob: "minecraft:villager_v2", mutate_into: "jig_bmu:villager" },
    { mob: "minecraft:vindicator", mutate_into: "jig_bmu:vindicator" },
    { mob: "minecraft:warden", mutate_into: "jig_bmu:warden" },
    { mob: "minecraft:witch", mutate_into: "jig_bmu:witch" },
    { mob: "minecraft:wither_skeleton", mutate_into: "jig_bmu:wither_skeleton" },
    { mob: "jig_bmu:wolf", mutate_into: "jig_bmu:cerberus" },
    { mob: "minecraft:wolf", mutate_into: "jig_bmu:wolf" },
    { mob: "minecraft:zoglin", mutate_into: "jig_bmu:zoglin" },
    { mob: "minecraft:zombie", mutate_into: "jig_bmu:zombie" },
    { mob: "minecraft:zombie_pigman", mutate_into: "jig_bmu:zombie_pigman" },
    { mob: "minecraft:zombie_villager", mutate_into: "jig_bmu:zombie_villager" },
    { mob: "minecraft:zombie_villager_v2", mutate_into: "jig_bmu:zombie_villager" },
    { mob: "minecraft:silverfish", mutate_into: "jig_bmu:silverfish" },
    { mob: "minecraft:endermite", mutate_into: "jig_bmu:endermite" },
    { mob: "jig_bmu:endermite", mutate_into: "minecraft:enderman" },
    { mob: "jig_bmu:sniffer", mutate_into: "jig_bmu:sandra" },
    { mob: "minecraft:sniffer", mutate_into: "jig_bmu:sniffer" },
    //lom mutants
    { mob: "jig:lom_axolotl", mutate_into: "jig_bmu:axolotl" },
    { mob: "jig:lom_baby_iron_golem", mutate_into: "jig_bmu:iron_golem" },
    { mob: "jig:lom_bee", mutate_into: "jig_bmu:bee" },
    { mob: "jig:lom_blaze", mutate_into: "jig_bmu:blaze" },
    { mob: "jig:lom_cave_spider", mutate_into: "jig_bmu:cave_spider" },
    { mob: "jig:lom_creeper", mutate_into: "jig_bmu:creeper" },
    { mob: "jig:lom_dolphin", mutate_into: "jig_bmu:dolphin" },
    { mob: "jig:lom_drowned", mutate_into: "jig_bmu:drowned" },
    { mob: "jig:lom_enderman", mutate_into: "jig_bmu:enderman" },
    { mob: "jig:lom_evocation_illager", mutate_into: "jig_bmu:evoker" },
    { mob: "jig:lom_farmageddon", mutate_into: "jig_bmu:farmageddon" },
    { mob: "jig:lom_goat", mutate_into: "jig_bmu:goat" },
    { mob: "jig:lom_hoglin", mutate_into: "jig_bmu:hoglin" },
    { mob: "jig:lom_horse", mutate_into: "jig_bmu:horse" },
    { mob: "jig:lom_husk", mutate_into: "jig_bmu:husk" },
    { mob: "jig:lom_iron_golem", mutate_into: "jig_bmu:iron_golem" },
    { mob: "jig:lom_megamooshroom", mutate_into: "jig_bmu:megamooshroom" },
    { mob: "jig:lom_ocelot", mutate_into: "jig_bmu:ocelot" },
    { mob: "jig:lom_piglin_brute", mutate_into: "jig_bmu:piglin_brute" },
    { mob: "jig:lom_pillager", mutate_into: "jig_bmu:pillager" },
    { mob: "jig:lom_ravager", mutate_into: "jig_bmu:ravager" },
    { mob: "jig:lom_skeleton_horse", mutate_into: "jig_bmu:skeleton_horse" },
    { mob: "jig:lom_skeleton", mutate_into: "jig_bmu:skeleton" },
    { mob: "jig:lom_snow_golem", mutate_into: "jig_bmu:snow_golem" },
    { mob: "jig:lom_spider", mutate_into: "jig_bmu:spider" },
    { mob: "jig:lom_stray", mutate_into: "jig_bmu:stray" },
    { mob: "jig:lom_vex", mutate_into: "jig_bmu:vex" },
    { mob: "jig:lom_villager_v2", mutate_into: "jig_bmu:villager" },
    { mob: "jig:lom_vindicator", mutate_into: "jig_bmu:vindicator" },
    { mob: "jig:lom_witch", mutate_into: "jig_bmu:witch" },
    { mob: "jig:lom_wither_skeleton", mutate_into: "jig_bmu:wither_skeleton" },
    { mob: "jig:lom_wolf", mutate_into: "jig_bmu:wolf" },
    { mob: "jig:lom_zoglin", mutate_into: "jig_bmu:zoglin" },
    { mob: "jig:lom_zombie_pigman", mutate_into: "jig_bmu:zombie_pigman" },
    { mob: "jig:lom_zombie_villager_v2", mutate_into: "jig_bmu:zombie_villager" },
    { mob: "jig:lom_zombie", mutate_into: "jig_bmu:zombie" },
    { mob: "jig:lom_minion_cow", mutate_into: "jig_bmu:cow" },
    { mob: "jig:lom_minion_mooshroom", mutate_into: "jig_bmu:mooshroom" },
    { mob: "jig:lom_minion_pig", mutate_into: "jig_bmu:pig" },
    { mob: "jig:lom_minion_piglin", mutate_into: "jig_bmu:piglin" },
    { mob: "jig:lom_minion_turtle", mutate_into: "jig_bmu:turtle" },
];
const TARGET_BATON = [
    {
        item: "jig_bmu:baton_ecru",
        particle: "jig_bmu:target_ecru",
        otherparticle: "jig_bmu:untarget_ecru",
        targetTag: "jig_team_ecru_target",
    },
    {
        item: "jig_bmu:baton_llano",
        particle: "jig_bmu:target_llano",
        otherparticle: "jig_bmu:untarget_llano",
        targetTag: "jig_team_llano_target",
    },
    {
        item: "jig_bmu:baton_sang",
        particle: "jig_bmu:target_sang",
        otherparticle: "jig_bmu:untarget_sang",
        targetTag: "jig_team_sang_target",
    },
    {
        item: "jig_bmu:baton_beryl",
        particle: "jig_bmu:target_beryl",
        otherparticle: "jig_bmu:untarget_beryl",
        targetTag: "jig_team_beryl_target",
    },
    {
        item: "jig_bmu:baton_used_ecru",
        particle: "jig_bmu:target_ecru",
        otherparticle: "jig_bmu:untarget_ecru",
        targetTag: "jig_team_ecru_target",
    },
    {
        item: "jig_bmu:baton_used_llano",
        particle: "jig_bmu:target_llano",
        otherparticle: "jig_bmu:untarget_llano",
        targetTag: "jig_team_llano_target",
    },
    {
        item: "jig_bmu:baton_used_sang",
        particle: "jig_bmu:target_sang",
        otherparticle: "jig_bmu:untarget_sang",
        targetTag: "jig_team_sang_target",
    },
    {
        item: "jig_bmu:baton_used_beryl",
        particle: "jig_bmu:target_beryl",
        otherparticle: "jig_bmu:untarget_beryl",
        targetTag: "jig_team_beryl_target",
    },
];
const TARGET_TOTEM = [
    {
        item: "jig_bmu:totem_ecru",
        particle: "jig_bmu:target_ecru",
        targetTag: "jig_team_ecru_target",
    },
    {
        item: "jig_bmu:totem_llano",
        particle: "jig_bmu:target_llano",
        targetTag: "jig_team_llano_target",
    },
    {
        item: "jig_bmu:totem_sang",
        particle: "jig_bmu:target_sang",
        targetTag: "jig_team_sang_target",
    },
    {
        item: "jig_bmu:totem_beryl",
        particle: "jig_bmu:target_beryl",
        targetTag: "jig_team_beryl_target",
    },
];
const factionTags = ["jig_team_ecru", "jig_team_llano", "jig_team_beryl", "jig_team_sang"];
const particleData = {
    jig_team_ecru_target: "jig_bmu:long_target_ecru",
    jig_team_llano_target: "jig_bmu:long_target_llano",
    jig_team_beryl_target: "jig_bmu:long_target_beryl",
    jig_team_sang_target: "jig_bmu:long_target_sang",
};
const factions = ["ecru", "llano", "sang", "beryl"];
const fullVariations = factions.flatMap((base) => [base, `u_${base}`]);
const generateArmorSets = () => {
    return fullVariations.map((variation) => ({
        helmet: `jig_bmu:helmet_${variation}`,
        chestplate: `jig_bmu:chestplate_${variation}`,
        leggings: `jig_bmu:leggings_${variation}`,
        boots: `jig_bmu:boots_${variation}`,
        effect: {
            particle: "none",
            strength: variation.startsWith("u_") ? 1 : 0,
            see_it: false,
            effect: "resistance",
            areaEffect: false,
        },
    }));
};
const armorSets = generateArmorSets();
const armorSetMap = new Map();
armorSets.forEach((set) => {
    const baseType = set.helmet.split("_").slice(-1)[0];
    armorSetMap.set(baseType, set);
});
const PLAYER_KILLED_MUTANTS_PROP = "jig_bmu:mutant.killed";
const foodEffects = new Map([
    [
        "jig_bmu:m_brain_golden",
        {
            randomEffects: [
                { name: "resistance", chance: 0.66, duration: 300, amplifier: 2 },
                { name: "speed", chance: 0.66, duration: 300, amplifier: 2 },
                { name: "strength", chance: 0.66, duration: 300, amplifier: 2 },
                { name: "jump_boost", chance: 0.66, duration: 300, amplifier: 2 },
                { name: "regeneration", chance: 0.66, duration: 300, amplifier: 2 },
                { name: "health_boost", chance: 0.66, duration: 300, amplifier: 3 },
                { name: "absorption", chance: 0.66, duration: 300, amplifier: 2 }
            ]
        }
    ],
    [
        "jig_bmu:m_brain_green",
        {
            randomEffects: [
                { name: "resistance", chance: 0.50, duration: 240, amplifier: 1 },
                { name: "speed", chance: 0.50, duration: 240, amplifier: 1 },
                { name: "strength", chance: 0.50, duration: 240, amplifier: 1 },
                { name: "jump_boost", chance: 0.50, duration: 240, amplifier: 1 },
                { name: "regeneration", chance: 0.50, duration: 240, amplifier: 1 },
                { name: "health_boost", chance: 0.50, duration: 240, amplifier: 2 },
                { name: "absorption", chance: 0.50, duration: 240, amplifier: 2 }
            ]
        }
    ],
    [
        "jig_bmu:m_brain",
        {
            randomEffects: [
                { name: "resistance", chance: 0.33, duration: 160, amplifier: 0 },
                { name: "speed", chance: 0.33, duration: 160, amplifier: 0 },
                { name: "strength", chance: 0.33, duration: 160, amplifier: 0 },
                { name: "jump_boost", chance: 0.33, duration: 160, amplifier: 0 },
                { name: "regeneration", chance: 0.33, duration: 160, amplifier: 0 },
                { name: "health_boost", chance: 0.33, duration: 160, amplifier: 1 },
                { name: "absorption", chance: 0.33, duration: 160, amplifier: 0 }
            ]
        }
    ],
    [
        "jig_bmu:m_brain_blob",
        {
            randomEffects: [
                { name: "resistance", chance: 0.25, duration: 5, amplifier: 0 },
                { name: "speed", chance: 0.25, duration: 5, amplifier: 0 },
                { name: "strength", chance: 0.25, duration: 5, amplifier: 0 },
                { name: "jump_boost", chance: 0.25, duration: 5, amplifier: 0 },
                { name: "regeneration", chance: 0.25, duration: 5, amplifier: 0 },
                { name: "health_boost", chance: 0.25, duration: 5, amplifier: 0 },
                { name: "absorption", chance: 0.25, duration: 5, amplifier: 0 }
            ]
        }
    ]
]);

const settingsMenuDialogue = (player, descriptor, settings, prefix) => __awaiter(void 0, void 0, void 0, function* () {
    const elements = Object.keys(descriptor)
        .filter((key) => !("hidden" in descriptor[key]) || !descriptor[key].hidden)
        .map((key) => {
        var _a, _b, _c;
        const labelKey = `${prefix}.setting.${key}`;
        const params = (_a = descriptor[key].labelParams) !== null && _a !== void 0 ? _a : [];
        const label = TRANSLATE$1(labelKey, ...params);
        const setting = descriptor[key];
        switch (setting.kind) {
            case "dropdown": {
                let dropdown = inputDropdown(key, label);
                setting.options.forEach((o) => {
                    dropdown = dropdown.addOption(TRANSLATE$1(`${labelKey}.${o}`), o);
                });
                return dropdown.setDefaultValueIndex(setting.options.indexOf((_b = settings[key]) !== null && _b !== void 0 ? _b : setting.value));
            }
            case "toggle":
                return inputToggle(key, label, !!settings[key]);
            case "slider":
                return inputSlider(key, label, setting.min, setting.max, setting.step, (_c = settings[key]) !== null && _c !== void 0 ? _c : setting.value);
            case "submenu":
                return inputToggle(key, label, false);
        }
    });
    return yield inputScriptDialogue(TRANSLATE$1(`${prefix}.title`))
        .addElements(elements)
        .open({ player });
});
class SettingSubmenu {
    constructor(descriptor, settings) {
        this.descriptor = descriptor;
        this.settings = settings;
    }
    getBoolean(key) {
        return this.settings[key];
    }
    getString(key) {
        return this.settings[key];
    }
    getNumber(key) {
        return this.settings[key];
    }
}
class Settings {
    constructor(target, propIdentifier, descriptor, options = {}) {
        this.target = target;
        this.propIdentifier = propIdentifier;
        this.descriptor = descriptor;
        this.options = options;
        this.listeners = [];
        this.keys = Object.keys(descriptor);
        const scriptEventMap = {};
        for (const key in descriptor) {
            const setting = descriptor[key];
            if (setting.kind === "toggle") {
                if (setting.toggleOnScriptEvent) {
                    if (setting.toggleOnScriptEvent in scriptEventMap) {
                        scriptEventMap[setting.toggleOnScriptEvent].add(key);
                    }
                    else {
                        scriptEventMap[setting.toggleOnScriptEvent] = new Set(key);
                    }
                }
                if (setting.toggleOffScriptEvent) {
                    if (setting.toggleOffScriptEvent in scriptEventMap) {
                        scriptEventMap[setting.toggleOffScriptEvent].add(key);
                    }
                    else {
                        scriptEventMap[setting.toggleOffScriptEvent] = new Set(key);
                    }
                }
            }
        }
        system.afterEvents.scriptEventReceive.subscribe((event) => {
            if (event.id in scriptEventMap) {
                const keys = scriptEventMap[event.id];
                for (const key of keys) {
                    const setting = descriptor[key];
                    if ("toggleOnScriptEvent" in setting && setting.toggleOnScriptEvent === event.id) {
                        this.setBoolean(key, true);
                    }
                    else if ("toggleOffScriptEvent" in setting && setting.toggleOffScriptEvent === event.id) {
                        this.setBoolean(key, false);
                    }
                }
            }
        });
    }
    getBoolean(key) {
        return this.getSettings()[key];
    }
    getString(key) {
        return this.getSettings()[key];
    }
    getNumber(key) {
        return this.getSettings()[key];
    }
    getSubmenu(key) {
        if (this.descriptor[key].kind !== "submenu") {
            throw new Error(`Invalid key for submenu setting ${String(key)}`);
        }
        return new SettingSubmenu(this.descriptor[key].options, this.getSettings()[key]);
    }
    setBoolean(key, value) {
        const settings = this.getSettings();
        settings[key] = value;
        this.updateSettings(settings);
    }
    setString(key, value) {
        const settings = this.getSettings();
        settings[key] = value;
        this.updateSettings(settings);
    }
    getSettings() {
        const settings = GET_PROP(this.target, this.propIdentifier, {});
        this.internalProcessSettings(this.descriptor, settings);
        return settings;
    }
    open(player) {
        return __awaiter(this, void 0, void 0, function* () {
            const currentSettings = this.getSettings();
            if (this.options.onOpen) {
                this.options.onOpen(player, currentSettings);
            }
            const mutableSettings = JSON.parse(JSON.stringify(currentSettings));
            const response = yield this.openDescriptor(player, this.propIdentifier, this.descriptor, currentSettings, [], mutableSettings, this.options.shouldOpenSubmenu);
            if (response) {
                this.updateSettings(response);
                if (this.options.onSave) {
                    this.options.onSave(player, response);
                }
            }
        });
    }
    subscribeOnSettingsChange(listener) {
        this.listeners.push(listener);
        return listener;
    }
    unsubscribeOnSettingsChange(listener) {
        const index = this.listeners.indexOf(listener);
        if (index !== -1) {
            this.listeners.splice(index, 1);
        }
    }
    internalProcessSettings(descriptor, settings) {
        for (const key in descriptor) {
            if (descriptor[key].kind === "submenu") {
                if (settings[key] === undefined || typeof settings[key] !== "object") {
                    settings[key] = {};
                }
                this.internalProcessSettings(descriptor[key].options, settings[key]);
            }
            else if (settings[key] === undefined || typeof settings[key] !== typeof descriptor[key].value) {
                settings[key] = descriptor[key].value;
            }
        }
    }
    openDescriptor(player, prefix, descriptor, settings, keypath, mutableSettings, shouldOpenSubmenu) {
        return __awaiter(this, void 0, void 0, function* () {
            const response = yield settingsMenuDialogue(player, descriptor, settings, prefix);
            const submenus = {};
            if (response instanceof InputScriptDialogueResponse) {
                const values = Object.assign({}, response.values);
                for (const key in descriptor) {
                    if (descriptor[key].kind === "submenu") {
                        if (values[key]) {
                            submenus[key] = descriptor[key];
                        }
                        values[key] = settings[key];
                    }
                    else {
                        // update mutable settings
                        let current = mutableSettings;
                        keypath.forEach(key => {
                            current = current[key];
                        });
                        current[key] = values[key];
                    }
                }
                for (const key in submenus) {
                    if (submenus[key]) {
                        let shouldOpen = true;
                        if (shouldOpenSubmenu) {
                            const path = (keypath.length > 0 ? (keypath.join('.') + `.${key}`) : key);
                            shouldOpen = shouldOpenSubmenu(path, player, mutableSettings);
                        }
                        if (shouldOpen) {
                            const subValues = yield this.openDescriptor(player, `${prefix}.${key}`, submenus[key].options, values[key], [...keypath, key], mutableSettings, shouldOpenSubmenu);
                            if (subValues) {
                                values[key] = subValues;
                            }
                        }
                    }
                }
                return values;
            }
            return undefined;
        });
    }
    updateSettings(settings) {
        const old = this.getSettings();
        SET_PROP(this.target, this.propIdentifier, settings);
        this.fireListener(old, settings);
    }
    fireListener(prev, current) {
        for (const key in prev) {
            if (prev[key] !== current[key]) {
                this.listeners.forEach((listener) => listener({
                    old: prev,
                    new: current,
                }));
                break;
            }
        }
    }
}

const ADMIN_SETTINGS_KEY = 'jig_bmu:admin-settings';
const SettingsTemplate = {
    mutantsSpawn: {
        kind: "dropdown",
        value: 'easy',
        options: ['easy',
            //'hundred', 
            'normal', 'hard']
    },
    //amountSpawn: {
    //  kind: "dropdown",
    //  value: 'normal',
    //  options: ['easy', 'normal', 'hard']
    //},
    showTargetParticle: {
        kind: "dropdown",
        value: 'on',
        options: ['off', 'on', 'over']
    },
    showPlayerFactionParticles: {
        kind: "toggle",
        value: true
    },
    allowChangingFaction: {
        kind: "toggle",
        value: true
    },
    turnOffFactions: {
        kind: "toggle",
        value: false
    },
    overpowerFactionless: {
        labelParams: ["\n"],
        kind: "slider",
        value: 0,
        min: -5,
        max: 5,
        step: 1
    },
    overpowerFaction: {
        kind: "slider",
        value: 0,
        min: -5,
        max: 5,
        step: 1
    },
    advancedSpawning: {
        kind: 'submenu',
        options: Object.assign({ spawnRate: {
                kind: "slider",
                min: 25,
                max: 100,
                step: 25,
                value: 100,
            } }, Object.fromEntries(Object.values(MUTANTS).filter(m => m.spawnsNaturally !== 'jig_bmu:string.no').map(m => [
            m.mutant,
            {
                kind: "toggle",
                value: true
            }
        ])))
    }
};
const adminSettings = new Settings(world, ADMIN_SETTINGS_KEY, SettingsTemplate, {
    onOpen: (player, settings) => {
        // stuff that happens when opening
    },
    onSave: (player, settings) => {
        // stuff that happens when saving
        player.runCommand('tellraw @s {"rawtext":[{"translate":"jig_bmu:guide.settings_updated_message"}]}');
    },
    shouldOpenSubmenu: (submenu, player, currentSettings) => {
        if (submenu === 'advancedSpawning') {
            if (currentSettings.mutantsSpawn === 'easy') {
                player.runCommand('tellraw @s {"rawtext":[{"translate":"jig_bmu:guide.settings_spawning_is_never"}]}');
                return false;
            }
        }
        return true;
    },
});

const SETTINGS_LOCKED = "jig_bmu:settings-locked";
const showDialogueOnItemUse = ({ itemTypeId, soundOnOpen, soundOnClose, title, content, exit, }) => {
    system.afterEvents.scriptEventReceive.subscribe((event) => {
        if (event.id === "jig_bmu:lock_settings") {
            SET_RAW_PROP(world, SETTINGS_LOCKED, true);
        }
        else if (event.id === "jig_bmu:unlock_settings") {
            SET_RAW_PROP(world, SETTINGS_LOCKED, false);
        }
    });
    world.afterEvents.itemUse.subscribe((event) => __awaiter(void 0, void 0, void 0, function* () {
        const { source: player, itemStack } = event;
        if (itemStack.typeId === itemTypeId) {
            const menu_sound_options = {
                pitch: 1.0,
                volume: 0.0,
            };
            if (soundOnOpen) {
                player.playSound(soundOnOpen);
            }
            let playSoundOnClose = true;
            let factionAnnounce = player.getTags();
            let foundFactionTag = factionTags.find((tag) => factionAnnounce.includes(tag)) || "";
            let actualFactionName = foundFactionTag ? foundFactionTag.split("_").pop() : "";
            mainMenu: while (true) {
                const response = yield multiButtonScriptDialogue(title)
                    .setBody({ rawtext: [{ translate: `jig_bmu:guide_${foundFactionTag}`, with: ["\n"] }] })
                    .addButton("guide", "jig_bmu:guide_control", "textures/jig/bmu/myui/guide")
                    .addButton("faction", "jig_bmu:guide_faction", "textures/jig/bmu/myui/faction")
                    .addButton("bestiary", "jig_bmu:guide_bestiary", "textures/jig/bmu/items/bestiary")
                    .addButton("settings", "jig_bmu:guide_settings", "textures/jig/bmu/myui/settings")
                    .addButton("credits", "jig_bmu:guide_credits", "textures/jig/bmu/myui/credits")
                    .addButton("updates", "jig_bmu:guide_update", "textures/jig/bmu/myui/updates")
                    .addButton("exit", exit)
                    .open({ player });
                if (response instanceof ButtonDialogueResponse) {
                    const selected = response.selected;
                    const extraInfoOptions = ["guide"];
                    if (extraInfoOptions.includes(selected)) {
                        while (true) {
                            const suboptionResponse = yield multiButtonScriptDialogue(`jig_bmu:guide.${selected}.name`)
                                .setBody({
                                rawtext: [{ translate: `jig_bmu:info.${selected}.preamble`, with: ["\n"] }],
                            })
                                .addButton("spawning", "jig_bmu:guide.mutant_spawning", "textures/jig/bmu/items/eggs/zombie")
                                .addButton("essence", "jig_bmu:guide.mutant_essence", "textures/jig/bmu/items/mutant_essence")
                                .addButton("faction_info", "jig_bmu:guide.faction_info", "textures/jig/bmu/myui/battles")
                                .addButton("eq_and_deco", "jig_bmu:guide.eq_and_deco", "textures/jig/bmu/myui/deco")
                                .addButton("back", "jig_bmu:guide_back")
                                .open({ player });
                            if (suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "spawning" || suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "essence" || suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "faction_info" || suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "eq_and_deco") {
                                const response = yield multiButtonScriptDialogue(`jig_bmu:info.${suboptionResponse.selected}.name`)
                                    .setBody({
                                    rawtext: [
                                        { translate: `jig_bmu:info.${suboptionResponse.selected}.preamble`, with: ["\n"] },
                                        { text: "§r\n\n" },
                                        { translate: `jig_bmu:info.${suboptionResponse.selected}.recipes_01`, with: ["\n"] },
                                        { text: "§r\n\n" },
                                        { translate: `jig_bmu:info.${suboptionResponse.selected}.recipes_02`, with: ["\n"] },
                                        { text: "§r\n\n" },
                                        { translate: `jig_bmu:info.${suboptionResponse.selected}.recipes_03`, with: ["\n"] },
                                        { text: "§r\n\n" },
                                        { translate: `jig_bmu:info.${suboptionResponse.selected}.recipes_04`, with: ["\n"] },
                                    ],
                                })
                                    .addButton("back", "jig_bmu:guide_back")
                                    .open({ player });
                                if (response instanceof ButtonDialogueResponse && response.selected === "back") {
                                    continue;
                                }
                            }
                            else if (suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "back") {
                                continue mainMenu;
                            }
                            break;
                        }
                    }
                    else if (selected === "faction") {
                        let showChangeFaction = adminSettings.getBoolean("allowChangingFaction");
                        let showFactionsAtAll = adminSettings.getBoolean("turnOffFactions");
                        let tag_list = player.getTags();
                        const teamTags = ["jig_team_ecru", "jig_team_llano", "jig_team_beryl", "jig_team_sang"];
                        const foundFactionTag = tag_list.some(tag => teamTags.includes(tag));
                        if (showFactionsAtAll) {
                            yield multiButtonScriptDialogue("jig_bmu:faction_disabled_title")
                                .setBody(TRANSLATE(`jig_bmu:info_body_disabled`, "\n"))
                                .addButton(`disabled`, `jig_bmu:info_team_disabled`, `textures/jig/bmu/myui/leave`)
                                .open({ player });
                            player.removeTag(`jig_team_ecru`);
                            player.removeTag(`jig_team_llano`);
                            player.removeTag(`jig_team_beryl`);
                            player.removeTag(`jig_team_sang`);
                            break;
                        }
                        else if (!showChangeFaction && foundFactionTag) {
                            yield multiButtonScriptDialogue("jig_bmu:faction_locked_title")
                                .setBody(TRANSLATE(`jig_bmu:info_body_${actualFactionName}`, "\n"))
                                .addButton(`${actualFactionName}`, `jig_bmu:info_team_${actualFactionName}`, `textures/jig/bmu/myui/${actualFactionName}`)
                                .open({ player });
                            continue;
                        }
                        else if (foundFactionTag) {
                            const response = yield multiButtonScriptDialogue("jig_bmu:faction_title")
                                .setBody("jig_bmu:faction_info")
                                .addButton("ecru", "jig_bmu:guide_ecru", "textures/jig/bmu/myui/ecru")
                                .addButton("llano", "jig_bmu:guide_llano", "textures/jig/bmu/myui/llano")
                                .addButton("beryl", "jig_bmu:guide_beryl", "textures/jig/bmu/myui/beryl")
                                .addButton("sang", "jig_bmu:guide_sang", "textures/jig/bmu/myui/sang")
                                .addButton("leave", "jig_bmu:guide_leave", "textures/jig/bmu/myui/leave")
                                .open({ player });
                            if (response instanceof ButtonDialogueResponse) {
                                const selected = response.selected;
                                const extraInfoOptions = ["ecru", "llano", "beryl", "sang", "leave"];
                                if (extraInfoOptions.includes(selected)) {
                                    player.removeTag(`jig_team_ecru`);
                                    player.removeTag(`jig_team_llano`);
                                    player.removeTag(`jig_team_beryl`);
                                    player.removeTag(`jig_team_sang`);
                                    if (selected != "leave") {
                                        player.addTag(`jig_team_${selected}`);
                                    }
                                    const suboptionResponse = yield multiButtonScriptDialogue(`jig_bmu:guide.${selected}.name`)
                                        .setBody({
                                        rawtext: [
                                            { translate: `jig_bmu:info.${selected}.info`, with: ["\n"] },
                                            { text: "§r\n\n" },
                                            { translate: `jig_bmu:info.${selected}.team_01`, with: ["\n"] },
                                        ],
                                    })
                                        .addButton("finish", `jig_bmu:back_to_${selected}`, `textures/jig/bmu/myui/${selected}`)
                                        .open({ player });
                                    if (suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "finish") {
                                        player.runCommand("/clear @s jig_common:emblem_ecru");
                                        player.runCommand("/clear @s jig_common:emblem_llano");
                                        player.runCommand("/clear @s jig_common:emblem_beryl");
                                        player.runCommand("/clear @s jig_common:emblem_sang");
                                        if (selected != "leave") {
                                            let whichEmblems = new ItemStack(`jig_common:emblem_${selected}`, 64);
                                            player.dimension.playSound("random.levelup", player.location);
                                            player.dimension.spawnItem(whichEmblems, player.location);
                                        }
                                        player.onScreenDisplay.setTitle(TRANSLATE(`jig_bmu:title_${selected}`));
                                        break;
                                    }
                                }
                            }
                        }
                        else if (!foundFactionTag) {
                            const response = yield multiButtonScriptDialogue("jig_bmu:faction_title")
                                .setBody("jig_bmu:faction_info")
                                .addButton("ecru", "jig_bmu:guide_ecru", "textures/jig/bmu/myui/ecru")
                                .addButton("llano", "jig_bmu:guide_llano", "textures/jig/bmu/myui/llano")
                                .addButton("beryl", "jig_bmu:guide_beryl", "textures/jig/bmu/myui/beryl")
                                .addButton("sang", "jig_bmu:guide_sang", "textures/jig/bmu/myui/sang")
                                .open({ player });
                            if (response instanceof ButtonDialogueResponse) {
                                const selected = response.selected;
                                const extraInfoOptions = ["ecru", "llano", "beryl", "sang", "leave"];
                                if (extraInfoOptions.includes(selected)) {
                                    player.removeTag(`jig_team_ecru`);
                                    player.removeTag(`jig_team_llano`);
                                    player.removeTag(`jig_team_beryl`);
                                    player.removeTag(`jig_team_sang`);
                                    player.addTag(`jig_team_${selected}`);
                                    const suboptionResponse = yield multiButtonScriptDialogue(`jig_bmu:guide.${selected}.name`)
                                        .setBody({
                                        rawtext: [
                                            { translate: `jig_bmu:info.${selected}.info`, with: ["\n"] },
                                            { text: "§r\n\n" },
                                            { translate: `jig_bmu:info.${selected}.team_01`, with: ["\n"] },
                                        ],
                                    })
                                        .addButton("finish", `jig_bmu:back_to_${selected}`, `textures/jig/bmu/myui/${selected}`)
                                        .open({ player });
                                    if (suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "finish") {
                                        player.runCommand("/clear @s jig_common:emblem_ecru");
                                        player.runCommand("/clear @s jig_common:emblem_llano");
                                        player.runCommand("/clear @s jig_common:emblem_beryl");
                                        player.runCommand("/clear @s jig_common:emblem_sang");
                                        let whichEmblems = new ItemStack(`jig_common:emblem_${selected}`, 64);
                                        player.dimension.playSound("random.levelup", player.location);
                                        player.dimension.spawnItem(whichEmblems, player.location);
                                        player.onScreenDisplay.setTitle(TRANSLATE(`jig_bmu:title_${selected}`));
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    else if (selected === "bestiary") {
                        const dialogue = yield multiButtonScriptDialogue(`jig_bmu:guide.bestiary.name`)
                            .setBody({
                            rawtext: [
                                { translate: `jig_bmu:info.bestiary.info`, with: ["\n"] },
                                { text: "§r\n\n" },
                                { translate: `jig_bmu:info.bestiary.team_01`, with: ["\n"] },
                            ],
                        })
                            .addButton("get_bestiary", "jig_bmu:get_bestiary", `textures/jig/bmu/items/bestiary`)
                            .addButton("back", "jig_bmu:guide_back")
                            .open({ player });
                        if (dialogue instanceof ButtonDialogueResponse && dialogue.selected === "get_bestiary") {
                            player.runCommand("/clear @s jig_bmu:bestiary");
                            let whichEmblems = new ItemStack(`jig_bmu:bestiary`, 1);
                            player.onScreenDisplay.setTitle(TRANSLATE(`jig_bmu:title_bestiary`));
                            player.dimension.playSound("random.levelup", player.location);
                            player.dimension.spawnItem(whichEmblems, player.location);
                            break;
                        }
                        if (dialogue instanceof ButtonDialogueResponse && dialogue.selected === "back") {
                            continue;
                        }
                    }
                    else if (selected === "settings") {
                        const splashResponse = yield adminSettingsSplash(player);
                        if (splashResponse instanceof ButtonDialogueResponse) {
                            if (splashResponse.selected === "proceed") {
                                const adminMenuResponse = adminSettings.open(player);
                                if (adminMenuResponse instanceof InputScriptDialogueResponse) {
                                    playSoundOnClose = false;
                                }
                            }
                            else if (splashResponse.selected === "back") {
                                continue;
                            }
                        }
                    }
                    else if (selected === "credits") {
                        const suboptionResponse = yield multiButtonScriptDialogue(`jig_bmu:guide.${selected}.name`)
                            .setBody({
                            rawtext: [
                                { translate: `jig_bmu:info.${selected}.preamble`, with: ["\n"] },
                                { text: "§r\n\n" },
                                { translate: `jig_bmu:info.${selected}.recipes_01`, with: ["\n"] },
                                { text: "§r\n\n" },
                                { translate: `jig_bmu:info.${selected}.recipes_02`, with: ["\n"] },
                                { text: "§r\n\n" },
                                { translate: `jig_bmu:info.${selected}.recipes_03`, with: ["\n"] },
                                { text: "§r\n\n" },
                                { translate: `jig_bmu:info.${selected}.recipes_04`, with: ["\n"] },
                            ],
                        })
                            .addButton("back", "jig_bmu:guide_back")
                            .open({ player });
                        if (suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "back") {
                            continue;
                        }
                    }
                    else if (selected === "updates") {
                        const suboptionResponse = yield multiButtonScriptDialogue(`jig_bmu:guide_update.name`)
                            .setBody({
                            rawtext: [
                                { translate: `jig_bmu:update_info.v1.x`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_aa`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_ab`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_ac`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_ad`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_ae`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_af`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_ag`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_ah`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_ai`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_aj`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_ak`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_al`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.4_am`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_aa`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ab`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ac`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ad`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ae`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_af`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ag`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ah`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ai`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_aj`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ak`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_al`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_am`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_an`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ao`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ap`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_aq`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ar`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_as`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_at`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_au`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_av`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_aw`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ax`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ay`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_az`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_ba`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bb`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bc`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bd`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_be`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bf`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bg`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bh`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bi`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bj`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bk`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bl`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.3_bm`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.2`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.2_aa`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.2_ab`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.2_ac`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_aa`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ab`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ac`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ad`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ae`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_af`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ag`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ah`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ai`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_aj`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ak`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_al`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_am`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_an`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ao`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ap`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_aq`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_ar`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_as`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.1_at`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.0`, with: ["\n"] },
                                { translate: `jig_bmu:update_info.v1.0_aa`, with: ["\n"] },
                            ],
                        })
                            .addButton("back", "jig_bmu:guide_back")
                            .open({ player });
                        if (suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "back") {
                            continue;
                        }
                    }
                }
                break;
            }
            if (soundOnClose && playSoundOnClose) {
                player.playSound(soundOnClose, menu_sound_options);
            }
        }
    }));
};
const BESTIARY = "jig_bmu:bestiary";
const BESTIARY_SETTINGS_TEMPLATE = {
    filter: {
        labelParams: ["\n"],
        kind: 'dropdown',
        value: 'all',
        options: [
            'all',
            'locked',
            'unlocked',
            'spawn-no-naturally',
            'spawn-naturally',
            'tameable',
            'rideable',
            'rideable-tame',
            'rideable-faction',
            'boss'
        ]
    },
    sort: {
        kind: 'dropdown',
        value: 'alphabetical',
        options: [
            'alphabetical',
            'health',
            'difficulty'
        ]
    },
    sortOrder: {
        kind: 'dropdown',
        value: 'asc',
        options: ['asc', 'desc', 'unlocked_asc', 'unlocked_desc', 'locked_asc', 'locked_desc']
    }
};
world.afterEvents.itemUse.subscribe((event) => __awaiter(void 0, void 0, void 0, function* () {
    const { source: player, itemStack } = event;
    if (itemStack.typeId === BESTIARY) {
        const menu_sound_options = {
            pitch: 1.0,
            volume: 0.5,
        };
        player.playSound("jig_bmu.mut.zombie.say", menu_sound_options);
        const killedMutants = GET_PROP(player, PLAYER_KILLED_MUTANTS_PROP, []);
        const mutantSpawn = adminSettings.getString("mutantsSpawn");
        const advancedSpawningSettings = adminSettings.getSubmenu("advancedSpawning");
        const BESTIARY_SETTINGS = 'jig_bmu:bestiary-settings';
        const bestiarySettingsHandler = new Settings(player, BESTIARY_SETTINGS, BESTIARY_SETTINGS_TEMPLATE);
        mainMenu: while (true) {
            const settings = bestiarySettingsHandler.getSettings();
            const filterBySettings = (data) => {
                const isUnlocked = !!killedMutants.find((km) => km.name === data.mutant);
                switch (settings.filter) {
                    case "all":
                        return true;
                    case "locked":
                        return !isUnlocked;
                    case "unlocked":
                        return isUnlocked;
                    case "spawn-no-naturally":
                        return data.spawnsNaturally === 'jig_bmu:string.no';
                    case "spawn-naturally":
                        return data.spawnsNaturally !== 'jig_bmu:string.no';
                    case "tameable":
                        return isUnlocked && data.tameable !== 'jig_bmu:string.no';
                    case "rideable":
                        return isUnlocked && data.canride !== 'jig_bmu:string.no';
                    case "rideable-tame":
                        return isUnlocked && data.canride === 'jig_bmu:tame.ride' || data.canride === 'jig_bmu:anyt.ride';
                    case "rideable-faction":
                        return isUnlocked && data.canride === 'jig_bmu:facn.ride' || data.canride === 'jig_bmu:anyt.ride';
                    case "boss":
                        return data.difficulty === 'jig_bmu:d.bos';
                }
            };
            const sortBySettings = (m1, m2) => {
                let s1;
                let s2;
                const sortOrder = settings.sortOrder; // Use the sortOrder directly from settings
                // Determine the lock status of each mutant
                const isM1Unlocked = !!killedMutants.find((km) => km.name === m1.mutant);
                const isM2Unlocked = !!killedMutants.find((km) => km.name === m2.mutant);
                // Handle sorting based on sortOrder
                switch (sortOrder) {
                    case "asc":
                    case "desc":
                        // Basic ascending/descending order
                        s1 = settings.sort === "alphabetical" ? m1.mutant : settings.sort === "health" ? m1.maxhp : m1.difficulty_num;
                        s2 = settings.sort === "alphabetical" ? m2.mutant : settings.sort === "health" ? m1.maxhp : m1.difficulty_num;
                        return sortOrder === "asc" ? (s1 < s2 ? -1 : s1 > s2 ? 1 : 0) : (s1 > s2 ? -1 : s1 < s2 ? 1 : 0);
                    case "unlocked_asc":
                    case "unlocked_desc":
                        // Unlocked first, then locked
                        if (isM1Unlocked !== isM2Unlocked) {
                            return isM1Unlocked ? -1 : 1; // Unlocked comes first
                        }
                        s1 = settings.sort === "alphabetical" ? m1.mutant : settings.sort === "health" ? m1.maxhp : m1.difficulty_num;
                        s2 = settings.sort === "alphabetical" ? m2.mutant : settings.sort === "health" ? m1.maxhp : m1.difficulty_num;
                        return sortOrder === "unlocked_asc" ? (s1 < s2 ? -1 : s1 > s2 ? 1 : 0) : (s1 > s2 ? -1 : s1 < s2 ? 1 : 0);
                    case "locked_asc":
                    case "locked_desc":
                        // Locked first, then unlocked
                        if (isM1Unlocked !== isM2Unlocked) {
                            return isM1Unlocked ? 1 : -1; // Locked comes first
                        }
                        s1 = settings.sort === "alphabetical" ? m1.mutant : settings.sort === "health" ? m1.maxhp : m1.difficulty_num;
                        s2 = settings.sort === "alphabetical" ? m2.mutant : settings.sort === "health" ? m1.maxhp : m1.difficulty_num;
                        return sortOrder === "locked_asc" ? (s1 < s2 ? -1 : s1 > s2 ? 1 : 0) : (s1 > s2 ? -1 : s1 < s2 ? 1 : 0);
                    default:
                        return 0; // Default case to ensure fallback
                }
            };
            const mutants = MUTANTS.filter(filterBySettings).sort(sortBySettings);
            const dialogue = multiButtonScriptDialogue("jig_bmu:bestiary_title")
                .setBody({ rawtext: [{ translate: `jig_bmu:bestiary_info`, with: ["\n"] }] })
                .addButtons(mutants
                .map((mutant) => {
                const mutantName = mutant.mutant.replace("jig_bmu:", ""); // Remove the prefix
                const text = `entity.jig_bmu:${mutantName}.name`;
                const killed = !!killedMutants.find((km) => km.name === mutant.mutant);
                if (killed) {
                    return {
                        name: mutantName,
                        text: { rawtext: [{ translate: text }] },
                        iconPath: `textures/jig/bmu/items/eggs/${mutantName}`,
                    };
                }
                else {
                    return {
                        name: mutantName,
                        text: { rawtext: [{ translate: text }] },
                        iconPath: `textures/jig/bmu/items/eggs/unknown`,
                    };
                }
            }))
                .addButton('settings', mutants.length === MUTANTS.length ? TRANSLATE('jig_bmu:bestiary.settings') : TRANSLATE('jig_bmu:bestiary.settings.mutants_filtered', TEXT(MUTANTS.length - mutants.length), TEXT("\n")), `textures/jig/bmu/myui/settings`)
                .addButton("close", "jig_bmu:guide_close");
            // Open the dialogue
            const response = yield dialogue.open({ player });
            if (response instanceof ButtonDialogueResponse && response.selected != "close") {
                if (response.selected === 'settings') {
                    yield bestiarySettingsHandler.open(player);
                    continue mainMenu;
                }
                const selected = response.selected;
                const selectedMutant = MUTANTS.find((mutant) => mutant.mutant === `jig_bmu:${selected}`);
                if (selectedMutant) {
                    const killed = !!killedMutants.find((km) => km.name === selectedMutant.mutant);
                    let mobName = `jig_bmu:${selected}`;
                    const lookup_mutated = mutation_information.find((mutant) => mutant.mutate_into === mobName);
                    let originalMob = "unknown";
                    if (lookup_mutated) {
                        if (lookup_mutated.mob.startsWith("jig_bmu:")) {
                            originalMob = `entity.${lookup_mutated.mob}.name`;
                        }
                        else if (lookup_mutated.mob.startsWith("minecraft:")) {
                            originalMob = `entity.${lookup_mutated.mob.replace("minecraft:", "")}.name`;
                        }
                    }
                    let spawnNaturally = selectedMutant.spawnsNaturally;
                    if (selectedMutant.spawnsNaturally !== 'jig_bmu:string.no' && !advancedSpawningSettings.getBoolean(selectedMutant.mutant)) {
                        spawnNaturally = 'jig_bmu:string.di';
                    }
                    if (mutantSpawn === 'easy') {
                        spawnNaturally = 'jig_bmu:string.di';
                    }
                    if (killed) {
                        const suboptionResponse = yield multiButtonScriptDialogue(`entity.jig_bmu:${selected}.name`)
                            .setBody({
                            rawtext: [
                                { translate: `jig_bmu:info.unlocked`, with: ["\n"] },
                                { text: "\n" },
                                { translate: `entity.jig_bmu:${selected}.name`, with: ["\n"] },
                                { text: "§r\n§7" },
                                { translate: `${selectedMutant.difficulty}`, with: ["\n"] },
                                { text: "§r\n\n§7" },
                                { translate: `jig_bmu:${selected}.description`, with: ["\n"] },
                                { text: "§r\n\n" },
                                { translate: `jig_bmu:bestiary.max_hp` },
                                { translate: `${selectedMutant.maxhp}`, with: ["\n"] },
                                { text: "§r\n" },
                                { translate: `jig_bmu:bestiary.tameable` },
                                { translate: `${selectedMutant.tameable}`, with: ["\n"] },
                                { text: "§r\n" },
                                { translate: `jig_bmu:bestiary.rideable` },
                                { translate: `${selectedMutant.canride}`, with: ["\n"] },
                                { text: "§r\n" },
                                { translate: `jig_bmu:bestiary.mutate_from` },
                                { translate: `${originalMob}`, with: ["\n"] },
                                { text: "§r\n" },
                                { translate: `jig_bmu:bestiary.can_mutate` },
                                { translate: `${selectedMutant.canmutate}`, with: ["\n"] },
                                { text: "§r\n" },
                                { translate: `jig_bmu:bestiary.naturally` },
                                { translate: `${spawnNaturally}`, with: ["\n"] },
                            ],
                        })
                            .addButton("back", "jig_bmu:guide_back")
                            .open({ player });
                        if (suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "back") {
                            continue mainMenu; // Continue to the previous menu
                        }
                        else {
                            break; // Exit the loop
                        }
                    }
                    else {
                        const suboptionResponse = yield multiButtonScriptDialogue(`jig_bmu:guide.name.unknown`)
                            .setBody({
                            rawtext: [
                                { translate: `jig_bmu:bestiary.what_to_do`, with: ["\n"] },
                                { translate: `entity.jig_bmu:${selected}.name`, with: ["\n"] },
                                { translate: `jig_bmu:bestiary.what_to_do_more`, with: ["\n"] },
                                { text: "§r\n§7" },
                                { translate: `${selectedMutant.difficulty}`, with: ["\n"] },
                                { text: "§r\n\n" },
                                { translate: `jig_bmu:bestiary.mutate_from`, with: ["\n"] },
                                { translate: `${originalMob}` },
                                { text: "§r\n" },
                                { translate: `jig_bmu:bestiary.naturally` },
                                { translate: `${spawnNaturally}`, with: ["\n"] },
                            ],
                        })
                            .addButton("back", "jig_bmu:guide_back")
                            .open({ player });
                        if (suboptionResponse instanceof ButtonDialogueResponse && suboptionResponse.selected === "back") {
                            continue mainMenu; // Continue to the previous menu
                        }
                        else {
                            break; // Exit the loop
                        }
                    }
                }
            }
            else {
                break; // Exit the loop
            }
        }
    }
}));
const adminSettingsSplash = (player) => __awaiter(void 0, void 0, void 0, function* () {
    if (!GET_RAW_PROP(world, SETTINGS_LOCKED)) {
        return yield dualButtonScriptDialogue(TRANSLATE("jig_bmu:admin-splash.title"), {
            name: "proceed",
            text: TRANSLATE("jig_bmu:admin-splash.proceed"),
        }, {
            name: "back",
            text: TRANSLATE("jig_bmu:guide_back"),
        })
            .setBody(TRANSLATE("jig_bmu:admin-splash.body", TEXT("\n")))
            .open({ player });
    }
    return yield multiButtonScriptDialogue(TRANSLATE("jig_bmu:admin-splash-locked.title"))
        .setBody(TRANSLATE("jig_bmu:admin-splash-locked.body", TEXT("\n")))
        .addButton("back", TRANSLATE("jig_bmu:admin-splash-locked.button"))
        .open({ player });
});

const giveASingleItem = ({ itemTypeId }) => {
    const propertyGiven = itemTypeId + '_given';
    world.afterEvents.playerSpawn.subscribe((event) => __awaiter(void 0, void 0, void 0, function* () {
        if (event.player.getDynamicProperty(propertyGiven) === undefined) {
            const playerPosition = event.player.location;
            const item = new ItemStack(itemTypeId, 1);
            item.setLore(["By Jigarbov Productions"]);
            event.player.runCommand('scoreboard objectives add jig_bmu:jig_computer.addon_stats dummy');
            event.player.runCommand('tellraw @s {"rawtext":[{"translate":"jig_bmu:installed_msg"}]}');
            event.player.dimension.spawnItem(item, playerPosition);
            event.player.setDynamicProperty(propertyGiven, 1);
        }
    }));
};

// Based off https://stackoverflow.com/a/1349426/688379
const RANDOM_ID_CHARACTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const makeRandomId = (length = 16) => {
    return [...new Array(length)].map(() => RANDOM_ID_CHARACTERS.charAt(Math.floor(Math.random() * RANDOM_ID_CHARACTERS.length))).join('');
};
const makeRandomNumber = (min, max) => {
    return min + Math.floor(Math.random() * (max - min + 1));
};
const makeRandomNumberDecimal = (min, max) => {
    return min + Math.random() * (max - min);
};
const randomElement = (array) => {
    return array[makeRandomNumber(0, array.length - 1)];
};

const transformItem = (oldItem, newType) => {
    if (oldItem.typeId === newType) {
        return oldItem.clone();
    }
    const newTool = new ItemStack(newType, oldItem.amount);
    // Basic stuff
    newTool.keepOnDeath = oldItem.keepOnDeath;
    newTool.lockMode = oldItem.lockMode;
    newTool.nameTag = oldItem.nameTag;
    newTool.setLore(oldItem.getLore());
    newTool.setCanDestroy(oldItem.getCanDestroy());
    newTool.setCanPlaceOn(oldItem.getCanPlaceOn());
    // Copy all dynamic props
    oldItem.getDynamicPropertyIds().forEach(prop => {
        newTool.setDynamicProperty(prop, oldItem.getDynamicProperty(prop));
    });
    // Copy applicable components
    oldItem.getComponents().forEach(component => {
        if (newTool.hasComponent(component.typeId)) {
            const newToolComponent = newTool.getComponent(component.typeId);
            switch (newToolComponent.typeId) {
                case ItemDurabilityComponent.componentId:
                    {
                        const newDurability = newToolComponent;
                        const oldDurability = component;
                        newDurability.damage = Math.min(oldDurability.damage, newDurability.maxDurability);
                    }
                    break;
                case ItemFoodComponent.componentId:
                    // no - op - nothing to setup
                    break;
            }
        }
    });
    return newTool;
};
const IDENTIFIER_PROP = 'jig_bmu:item_id';
const addIdentifier = (item) => {
    if (!GET_RAW_PROP(item, IDENTIFIER_PROP)) {
        SET_RAW_PROP(item, IDENTIFIER_PROP, makeRandomId());
        return true;
    }
    return false;
};
const getIdentifier = (item) => {
    return GET_RAW_PROP(item, IDENTIFIER_PROP);
};
const updateItem = (entity, itemId, updater) => {
    const inventory = entity.getComponent(EntityInventoryComponent.componentId);
    if (inventory === null || inventory === void 0 ? void 0 : inventory.container) {
        for (let i = 0; i < inventory.container.size; ++i) {
            const item = inventory.container.getItem(i);
            if (item && item.getDynamicProperty(IDENTIFIER_PROP) === itemId) {
                const updatedItem = updater(item);
                if (updatedItem) {
                    inventory.container.setItem(i, updatedItem);
                }
                break;
            }
        }
    }
};

// Utility function to apply random effects based on probability
function applyRandomEffects(player, effects) {
    effects.forEach(effect => {
        const { name, chance, duration, amplifier } = effect;
        if (Math.random() < chance) {
            try {
                player.addEffect(name, duration * 20, { amplifier });
                debug(`Applied random effect: ${name} for ${duration}s with amplifier ${amplifier}`);
            }
            catch (error) {
                if (error instanceof Error) {
                    debug(`Failed to apply random effect: ${name} - ${error.message}`);
                }
                else {
                    debug(`Failed to apply random effect: ${name} - Unknown error`);
                }
            }
        }
    });
}
function registerItemCompleteUseHandler() {
    world.afterEvents.itemCompleteUse.subscribe(({ itemStack: item, source: player }) => {
        const foodEffect = foodEffects.get(item.typeId);
        // If the item has a defined effect, apply it
        if (foodEffect) {
            const { effect, duration, amplifier, returnItem, commands, functions, randomEffects } = foodEffect;
            try {
                // Apply the effect to the player
                if (effect) {
                    player.addEffect(effect, duration * 20, { amplifier: amplifier - 1 });
                    debug(`Applied ${effect} for ${duration}s with amplifier ${amplifier}`);
                }
            }
            catch (error) {
                if (error instanceof Error) {
                    debug(`Failed to apply effect: ${error.message}`);
                }
                else {
                    debug("Failed to apply effect: Unknown error");
                }
            }
            // Apply random effects if specified
            if (randomEffects) {
                applyRandomEffects(player, randomEffects);
            }
            // Add the return item to the inventory if specified
            if (returnItem) {
                try {
                    const inventory = player.getComponent("inventory");
                    if (inventory && inventory.container) {
                        const added = inventory.container.addItem(new ItemStack(returnItem, 1));
                        if (!added) {
                            debug(`Could not add ${returnItem} to inventory!`);
                        }
                    }
                    else {
                        debug("Player does not have a valid inventory component or container.");
                    }
                }
                catch (error) {
                    if (error instanceof Error) {
                        debug(`Failed to add return item: ${error.message}`);
                    }
                    else {
                        debug("Failed to add return item: Unknown error");
                    }
                }
            }
            // Execute optional commands
            if (commands) {
                commands.forEach(command => {
                    try {
                        player.runCommand(command);
                    }
                    catch (error) {
                        if (error instanceof Error) {
                            debug(`Command failed: ${command} - ${error.message}`);
                        }
                        else {
                            debug(`Command failed: ${command} - Unknown error`);
                        }
                    }
                });
            }
            // Execute optional custom functions
            if (functions) {
                functions.forEach(functioN => {
                    try {
                        functioN(player, item);
                    }
                    catch (error) {
                        if (error instanceof Error) {
                            debug(`Custom function error: ${error.message}`);
                        }
                        else {
                            debug("Custom function error: Unknown error");
                        }
                    }
                });
            }
        }
    });
}

const directionToVector3 = (direction) => {
    switch (direction) {
        case Direction.Up:
            return { x: 0, y: +1, z: 0 };
        case Direction.Down:
            return { x: 0, y: -1, z: 0 };
        case Direction.East:
            return { x: 1, y: 0, z: 0 };
        case Direction.West:
            return { x: -1, y: 0, z: 0 };
        case Direction.North:
            return { x: 0, y: 0, z: -1 };
        case Direction.South:
            return { x: 0, y: 0, z: 1 };
    }
};
const vector3Step = (vector3, direction, step = 1) => {
    const directionVector = directionToVector3(direction);
    return {
        x: vector3.x + directionVector.x * step,
        y: vector3.y + directionVector.y * step,
        z: vector3.z + directionVector.z * step,
    };
};

// Casts a ray from the middle of the block instead of from an edge of it
const getBlockFromRay = (dimensionLocation, direction, options) => {
    var _a;
    const location = {
        x: Math.floor(dimensionLocation.x) + 0.5,
        y: Math.floor(dimensionLocation.y) + 0.5,
        z: Math.floor(dimensionLocation.z) + 0.5,
    };
    return dimensionLocation.dimension.getBlockFromRay(vector3Step(location, direction, (_a = options === null || options === void 0 ? void 0 : options.steps) !== null && _a !== void 0 ? _a : 0), directionToVector3(direction));
};

const FREQUENCY_CHECK = 100;
const MUTANT_SPAWN_NEVER = "easy";
const MUTANT_SPAWN_AT_NIGHT = "normal";
const MUTANT_SPAWN_HUNDRED_DAYS = "hundred";
const MUTANT_AMOUNT_FEW = "easy";
const MUTANT_AMOUNT_HANDFUL = "normal";
const MUTANT_AMOUNT_A_LOT = "hard";
const CURRENT_DAY_PROP = "jig_bmu:spawn.current_day";
const LAST_WORLD_DAY = "jig_bmu:spawn.last_world_day;";
const LAST_PROCESSED_TICK = "jig_bmu:spawn.last_tick";
const HUNDRED_DAY_SPAWNED = "jig_bmu:spawn.hundred_day_spawn";
const MUTANT_AMOUNTS = {
    [MUTANT_AMOUNT_FEW]: 2,
    [MUTANT_AMOUNT_HANDFUL]: 5,
    [MUTANT_AMOUNT_A_LOT]: 10,
};
const MUTANT_DAY_CONFIG = [
    // Day 1
    {
        h6: {
            random: [
                "pig",
                "cow",
                "mooshroom"
            ],
        },
    },
    // Day 2
    {
        h6: {
            random: [
                "zombie",
                "skeleton"
            ],
        },
        h11: {
            exact: [
                "farmageddon"
            ],
        },
    },
    // Day 3
    {
        h7: {
            random: [
                "blaze",
                "spider",
                "zombie"
            ],
        },
    },
    // Day 4
    {
        h8: {
            random: [
                "pillager",
                "ravager"
            ],
        },
        h12: {
            exact: [
                "dan_drowned",
            ],
        },
    },
];
const initMutantSpawn = () => {
    // Listen for settings change - if the 100th setting change, restart data.
    adminSettings.subscribeOnSettingsChange(event => {
        if (event.old.mutantsSpawn !== event.new.mutantsSpawn
            // this option is disabled
            // @ts-ignore: Unreachable code error
            && event.new.mutantsSpawn === "hundred") {
            SET_RAW_PROP(world, CURRENT_DAY_PROP, 0);
            SET_RAW_PROP(world, LAST_WORLD_DAY, 0);
            SET_RAW_PROP(world, LAST_PROCESSED_TICK, 0);
        }
    });
    // Start loop to spawn mutants on the hundred days mode
    system.runInterval(() => {
        const mutantSpawn = adminSettings.getString("mutantsSpawn");
        // this option is disabled
        // @ts-ignore: Unreachable code error
        if (mutantSpawn === MUTANT_SPAWN_HUNDRED_DAYS) {
            // Spawn
            spawnMutants();
        }
    }, FREQUENCY_CHECK);
    world.afterEvents.entitySpawn.subscribe((event) => {
        const entity = event.entity;
        const entityType = entity.typeId;
        if (!entity.isValid() || !isMutant(entityType)) {
            return;
        }
        const mutantSpawn = adminSettings.getString("mutantsSpawn");
        const isAllNatural = entity.getProperty('jig_bmu:all_natural');
        let despawn = false;
        if (isAllNatural) {
            if (mutantSpawn === MUTANT_SPAWN_NEVER) {
                despawn = true;
            }
            else if (mutantSpawn === MUTANT_SPAWN_AT_NIGHT && world.getTimeOfDay() < TimeOfDay.Night) {
                despawn = true;
                // this option is disabled
                // @ts-ignore: Unreachable code error
            }
            else if (mutantSpawn === MUTANT_SPAWN_HUNDRED_DAYS) {
                despawn = true;
            }
            else {
                const advancedSpawningSettings = adminSettings.getSubmenu("advancedSpawning");
                const shouldSpawn = advancedSpawningSettings.getBoolean(entity.typeId);
                if (!shouldSpawn) {
                    despawn = true;
                }
                else {
                    // Natural spawn and isn't blocked - use the spawnRate to check if we should despawn
                    const spawnRate = advancedSpawningSettings.getNumber("spawnRate");
                    if (spawnRate < makeRandomNumber(1, 100)) {
                        despawn = true;
                    }
                }
            }
        }
        if (despawn) {
            despawnMutant(entity);
        }
        else {
            // Not despawned - check additional buffs
            const EFFECT_DURATION = 20000000; // Define as a constant
            function calculateAmplifier(value) {
                return Math.abs(value) - 1; // Ensure the amplifier is positive and reduced by one
            }
            function applyEffect(entity, effectType, value, context) {
                const amplifier = calculateAmplifier(value);
                entity.addEffect(effectType, EFFECT_DURATION, { amplifier, showParticles: false });
            }
            const isMutant = !!GET_RAW_PROP(entity, FACTION_MUTANT_SPAWNED); // Ensure GET_RAW_PROP returns a boolean
            if (isMutant) {
                const factionOverpower = adminSettings.getNumber('overpowerFaction');
                if (factionOverpower > 0) {
                    applyEffect(entity, 'strength', factionOverpower);
                }
                else if (factionOverpower < 0) {
                    applyEffect(entity, 'weakness', factionOverpower);
                }
            }
            else {
                const overpowerFactionless = adminSettings.getNumber('overpowerFactionless');
                if (overpowerFactionless > 0) {
                    applyEffect(entity, 'strength', overpowerFactionless);
                }
                else if (overpowerFactionless < 0) {
                    applyEffect(entity, 'weakness', overpowerFactionless);
                }
            }
        }
    });
    system.afterEvents.scriptEventReceive.subscribe((e) => {
        if (e.id === "jig_bmu:force-spawn") {
            const day = parseInt(e.message);
            SET_RAW_PROP(world, CURRENT_DAY_PROP, isNaN(day) ? 0 : day);
            SET_RAW_PROP(world, LAST_WORLD_DAY, 0);
            SET_RAW_PROP(world, LAST_PROCESSED_TICK, 0);
            spawnMutants();
        }
    });
};
const despawnMutant = (entity) => {
    entity.remove();
};
const spawnMutants = () => {
    var _a, _b, _c;
    let currentDay = (_a = GET_RAW_PROP(world, CURRENT_DAY_PROP)) !== null && _a !== void 0 ? _a : 0;
    const lastProcessedWorldDay = (_b = GET_RAW_PROP(world, LAST_WORLD_DAY)) !== null && _b !== void 0 ? _b : 0;
    const lastProcessedTick = (_c = GET_RAW_PROP(world, LAST_PROCESSED_TICK)) !== null && _c !== void 0 ? _c : 0;
    // days starts at 6am
    const currentWorldDay = world.getDay();
    if (lastProcessedWorldDay < currentWorldDay) {
        // Start the day
        currentDay = currentDay + 1;
        SET_RAW_PROP(world, CURRENT_DAY_PROP, currentDay);
        SET_RAW_PROP(world, LAST_WORLD_DAY, currentWorldDay);
    }
    if (currentDay > MUTANT_DAY_CONFIG.length) {
        SET_RAW_PROP(world, LAST_WORLD_DAY, 0);
        return;
    }
    const timeOfDay = world.getTimeOfDay();
    // Take into account some ticks after noon to ensure we process the 12h config
    if (timeOfDay <= 6200) {
        // Round the lastProcessedTick up to the last hour
        const lastProcessedHour = Math.floor(lastProcessedTick / 1000) * 1000;
        if (lastProcessedHour + 1000 <= world.getAbsoluteTime()) {
            const config = MUTANT_DAY_CONFIG[currentDay - 1];
            // Needs processing
            if (timeOfDay < 1000) {
                // 6 hrs
                debug(`Spawning 6hrs at ${world.getTimeOfDay()}`);
                if (config.h6) {
                    processMutantHourConfig(config.h6);
                }
            }
            else if (timeOfDay < 2000) {
                // 7 hrs
                debug(`Spawning 7hrs at ${world.getTimeOfDay()}`);
                if (config.h7) {
                    processMutantHourConfig(config.h7);
                }
            }
            else if (timeOfDay < 3000) {
                // 8 hrs
                debug(`Spawning 8hrs at ${world.getTimeOfDay()}`);
                if (config.h8) {
                    processMutantHourConfig(config.h8);
                }
            }
            else if (timeOfDay < 4000) {
                // 9 hrs
                debug(`Spawning 9hrs at ${world.getTimeOfDay()}`);
                if (config.h9) {
                    processMutantHourConfig(config.h9);
                }
            }
            else if (timeOfDay < 5000) {
                // 10 hrs
                debug(`Spawning 10hrs at ${world.getTimeOfDay()}`);
                if (config.h10) {
                    processMutantHourConfig(config.h10);
                }
            }
            else if (timeOfDay < 6000) {
                // 11 hrs
                debug(`Spawning 11hrs at ${world.getTimeOfDay()}`);
                if (config.h11) {
                    processMutantHourConfig(config.h11);
                }
            }
            else if (timeOfDay < 7000) {
                // 12 hrs
                debug(`Spawning 12hrs at ${world.getTimeOfDay()}`);
                if (config.h12) {
                    processMutantHourConfig(config.h12);
                }
            }
            SET_RAW_PROP(world, LAST_PROCESSED_TICK, world.getAbsoluteTime());
        }
    }
};
const canonicalize = (data) => {
    return data.map(d => d.startsWith("jig_bmu:") ? d : `jig_bmu:${d}`);
};
const processMutantHourConfig = (config) => {
    const validPlayers = world.getAllPlayers().filter((p) => p.isValid());
    if (config.exact) {
        spawnMutantList(canonicalize(config.exact), [...Array(config.exact.length)].map((_) => randomElement(validPlayers)));
    }
    if (config.random) {
        // Determine how many to spawn change this to "adminSettingDropdown("amountSpawn") as keyof typeof MUTANT_AMOUNTS" if the setting gets added
        const baseCount = MUTANT_AMOUNTS[MUTANT_AMOUNT_HANDFUL];
        const multiplier = Math.min(validPlayers.length, 4);
        spawnMutantList(resolveSpawnList(canonicalize(config.random), baseCount * multiplier), validPlayers);
    }
};
const resolveSpawnList = (mutants, count) => {
    return [...new Array(count)].map(() => randomElement(mutants));
};
const spawnMutantList = (mutants, players) => {
    const remainder = mutants.length % players.length;
    for (let i = 0; i < mutants.length - remainder; ++i) {
        spawnMutant(mutants[i], players[i % players.length]);
    }
    for (let i = 0; i < remainder; ++i) {
        spawnMutant(mutants[mutants.length - remainder + i], randomElement(players));
    }
};
const SPAWN_TRIES = 40;
const spawnMutant = (mutant, player) => {
    for (let i = 0; i < SPAWN_TRIES; ++i) {
        const distance = makeRandomNumber(24, 44);
        const x = makeRandomNumberDecimal(-1, 1);
        const y = makeRandomNumberDecimal(0, 1); // only use values above the player
        const z = makeRandomNumberDecimal(-1, 1);
        if (x === 0 && z === 0 && y === 0) {
            continue;
        }
        const length = Math.sqrt(x * x + y * y + z * z);
        const spawnLocation = {
            x: player.location.x + (x / length) * distance,
            y: player.location.y + (y / length) * distance,
            z: player.location.z + (z / length) * distance,
        };
        const hit = getBlockFromRay(Object.assign({ dimension: player.dimension }, spawnLocation), Direction.Down);
        if (hit) {
            const block = hit.block.above(1);
            if (block && (block.isLiquid || block.isAir)) {
                const spawned = player.dimension.spawnEntity(mutant, block.center());
                SET_RAW_PROP(spawned, HUNDRED_DAY_SPAWNED, true);
                break;
            }
        }
    }
};

const initMutantStickers = () => {
    const entities = {
        'jig_bmu:allay': [{ itemId: 'jig_bmu:sticker_allay', specialItemId: 'jig_bmu:sticker_s_allay' }],
        'jig_bmu:armadillo': [{ itemId: 'jig_bmu:sticker_armadillo', specialItemId: 'jig_bmu:sticker_s_armadillo' }],
        'jig_bmu:axolotl': [{ itemId: 'jig_bmu:sticker_axolotl', specialItemId: 'jig_bmu:sticker_s_axolotl' }],
        'jig_bmu:bat': [{ itemId: 'jig_bmu:sticker_bat', specialItemId: 'jig_bmu:sticker_s_bat' }],
        'jig_bmu:bee': [{ itemId: 'jig_bmu:sticker_bee', specialItemId: 'jig_bmu:sticker_s_bee' }],
        'jig_bmu:blaze': [{ itemId: 'jig_bmu:sticker_blaze', specialItemId: 'jig_bmu:sticker_s_blaze' }],
        'jig_bmu:bogged': [{ itemId: 'jig_bmu:sticker_bogged', specialItemId: 'jig_bmu:sticker_s_bogged' }],
        'jig_bmu:ocelot': [{ itemId: 'jig_bmu:sticker_cat', specialItemId: 'jig_bmu:sticker_s_cat' }],
        'jig_bmu:cave_spider': [{ itemId: 'jig_bmu:sticker_cave_spider', specialItemId: 'jig_bmu:sticker_s_cave_spider' }],
        'jig_bmu:cerberus': [{ itemId: 'jig_bmu:sticker_cerberus', specialItemId: 'jig_bmu:sticker_s_cerberus' }],
        'jig_bmu:cow': [{ itemId: 'jig_bmu:sticker_cow', specialItemId: 'jig_bmu:sticker_s_cow' }],
        'jig_bmu:creeper': [{ itemId: 'jig_bmu:sticker_creeper', specialItemId: 'jig_bmu:sticker_s_creeper' }],
        'jig_bmu:dan_drowned': [{ itemId: 'jig_bmu:sticker_dan_drowned', specialItemId: 'jig_bmu:sticker_s_dan_drowned' }],
        'jig_bmu:drowned': [{ itemId: 'jig_bmu:sticker_drowned', specialItemId: 'jig_bmu:sticker_s_drowned' }],
        'jig_bmu:enderman': [{ itemId: 'jig_bmu:sticker_enderman', specialItemId: 'jig_bmu:sticker_s_enderman' }],
        'jig_bmu:endermite': [{ itemId: 'jig_bmu:sticker_endermite', specialItemId: 'jig_bmu:sticker_s_endermite' }],
        'jig_bmu:evoker': [{ itemId: 'jig_bmu:sticker_evoker', specialItemId: 'jig_bmu:sticker_s_evoker' }],
        'jig_bmu:goat': [{ itemId: 'jig_bmu:sticker_goat', specialItemId: 'jig_bmu:sticker_s_goat' }],
        'jig_bmu:hoglin': [{ itemId: 'jig_bmu:sticker_hoglin', specialItemId: 'jig_bmu:sticker_s_hoglin' }],
        'jig_bmu:skeleton_horse': [{ itemId: 'jig_bmu:sticker_horse_skeleton', specialItemId: 'jig_bmu:sticker_s_horse_skeleton' }],
        'jig_bmu:horse': [{ itemId: 'jig_bmu:sticker_horse', specialItemId: 'jig_bmu:sticker_s_horse' }],
        'jig_bmu:husk': [{ itemId: 'jig_bmu:sticker_husk', specialItemId: 'jig_bmu:sticker_s_husk' }],
        'jig_bmu:iron_golem': [{ itemId: 'jig_bmu:sticker_iron_golem', specialItemId: 'jig_bmu:sticker_s_iron_golem' }],
        'jig_bmu:megamooshroom': [{ itemId: 'jig_bmu:sticker_moocelium', specialItemId: 'jig_bmu:sticker_s_moocelium' }],
        'jig_bmu:mooshroom': [
            { itemId: 'jig_bmu:sticker_mooshroom', specialItemId: 'jig_bmu:sticker_s_mooshroom', conditions: [{ component: 'minecraft:variant', componentValue: 0 }] },
            { itemId: 'jig_bmu:sticker_brown_mooshroom', specialItemId: 'jig_bmu:sticker_s_brown_mooshroom', conditions: [{ component: 'minecraft:variant', componentValue: 1 }] }
        ],
        'jig_bmu:pig': [{ itemId: 'jig_bmu:sticker_pig', specialItemId: 'jig_bmu:sticker_s_pig' }],
        'jig_bmu:piglin_brute': [{ itemId: 'jig_bmu:sticker_piglin_brute', specialItemId: 'jig_bmu:sticker_s_piglin_brute' }],
        'jig_bmu:piglin': [{ itemId: 'jig_bmu:sticker_piglin', specialItemId: 'jig_bmu:sticker_s_piglin' }],
        'jig_bmu:pillager': [{ itemId: 'jig_bmu:sticker_pillager', specialItemId: 'jig_bmu:sticker_s_pillager' }],
        'jig_bmu:ravager': [{ itemId: 'jig_bmu:sticker_ravager', specialItemId: 'jig_bmu:sticker_s_ravager' }],
        'jig_bmu:sandra': [{ itemId: 'jig_bmu:sticker_sandra', specialItemId: 'jig_bmu:sticker_s_sandra' }],
        'jig_bmu:silverfish': [{ itemId: 'jig_bmu:sticker_silverfish', specialItemId: 'jig_bmu:sticker_s_silverfish' }],
        'jig_bmu:skeleton': [{ itemId: 'jig_bmu:sticker_skeleton', specialItemId: 'jig_bmu:sticker_s_skeleton' }],
        'jig_bmu:sniffer': [{ itemId: 'jig_bmu:sticker_sniffer', specialItemId: 'jig_bmu:sticker_s_sniffer' }],
        'jig_bmu:snow_golem': [{ itemId: 'jig_bmu:sticker_snowman', specialItemId: 'jig_bmu:sticker_s_snowman' }],
        'jig_bmu:spider': [{ itemId: 'jig_bmu:sticker_spider', specialItemId: 'jig_bmu:sticker_s_spider' }],
        'jig_bmu:stray': [{ itemId: 'jig_bmu:sticker_stray', specialItemId: 'jig_bmu:sticker_s_stray' }],
        'jig_bmu:dolphin': [{ itemId: 'jig_bmu:sticker_undead_dolphin', specialItemId: 'jig_bmu:sticker_s_undead_dolphin' }],
        'jig_bmu:turtle': [{ itemId: 'jig_bmu:sticker_undead_turtle', specialItemId: 'jig_bmu:sticker_s_undead_turtle' }],
        'jig_bmu:vex': [{ itemId: 'jig_bmu:sticker_vex', specialItemId: 'jig_bmu:sticker_s_vex' }],
        'jig_bmu:villager': [{ itemId: 'jig_bmu:sticker_villager', specialItemId: 'jig_bmu:sticker_s_villager' }],
        'jig_bmu:vindicator': [{ itemId: 'jig_bmu:sticker_vindicator', specialItemId: 'jig_bmu:sticker_s_vindicator' }],
        'jig_bmu:warden': [{ itemId: 'jig_bmu:sticker_warden', specialItemId: 'jig_bmu:sticker_s_warden' }],
        'jig_bmu:witch': [{ itemId: 'jig_bmu:sticker_witch', specialItemId: 'jig_bmu:sticker_s_witch' }],
        'jig_bmu:wither_skeleton': [{ itemId: 'jig_bmu:sticker_wither_skeleton', specialItemId: 'jig_bmu:sticker_s_wither_skeleton' }],
        'jig_bmu:farmageddon': [{ itemId: 'jig_bmu:sticker_wither', specialItemId: 'jig_bmu:sticker_s_wither' }],
        'jig_bmu:wolf': [{ itemId: 'jig_bmu:sticker_wolf', specialItemId: 'jig_bmu:sticker_s_wolf' }],
        'jig_bmu:zoglin': [{ itemId: 'jig_bmu:sticker_zoglin', specialItemId: 'jig_bmu:sticker_s_zoglin' }],
        'jig_bmu:zombie_pigman': [{ itemId: 'jig_bmu:sticker_zombie_piglin', specialItemId: 'jig_bmu:sticker_s_zombie_piglin' }],
        'jig_bmu:zombie_villager': [{ itemId: 'jig_bmu:sticker_zombie_villager', specialItemId: 'jig_bmu:sticker_s_zombie_villager' }],
        'jig_bmu:zombie': [{ itemId: 'jig_bmu:sticker_zombie', specialItemId: 'jig_bmu:sticker_s_zombie' }],
        'jig_bmu:zombie_juju': [{ itemId: 'jig_bmu:sticker_zombie_juju', specialItemId: 'jig_bmu:sticker_s_zombie_juju' }]
    };
    // 3) Finally paste this to execute
    const chunkObject = (obj, chunkSize) => {
        const keys = Object.keys(obj);
        const chunks = [];
        for (let i = 0; i < keys.length; i += chunkSize) {
            const chunk = {};
            keys.slice(i, i + chunkSize).forEach(key => {
                chunk[key] = obj[key];
            });
            chunks.push(chunk);
        }
        return chunks;
    };
    const entityChunks = chunkObject(entities, 4);
    // Debug: Number of chunks created
    //debug(`Created ${entityChunks.length} chunks for processing.`);
    // Send a separate scriptevent for each chunk with 1 tick delay between them
    entityChunks.forEach((entityChunk, index) => {
        const m = {
            id: (Math.random()).toString(16),
            type: 'request',
            endpoint: 'addStickers',
            params: [1, entityChunk], // Use only a chunk of entities
            callback: undefined,
        };
        // Calculate delay: start with 10 ticks and increase by 1 tick for each subsequent chunk
        const delay = 10 + index; // 1 tick additional delay for each chunk
        // Debug: Command to be executed
        //debug(`Scheduling scriptevent for chunk ${index + 1} with delay ${delay} ticks and payload length: ${JSON.stringify(m).length}`);
        system.runTimeout(() => void world
            .getDimension("overworld")
            .runCommandAsync(`scriptevent mineapi:jig_pcs ${JSON.stringify(m)}`), delay);
        // Debug: Command executed
        //debug(`Command scheduled to run for chunk ${index + 1} with delay ${delay} ticks.`);
    });
    // Debug: Initialization complete
    //debug("Mutant stickers initialization complete.");
};

const BOOK_ID = "jig_bmu:guide_book";
showDialogueOnItemUse({
    itemTypeId: BOOK_ID,
    title: {
        translate: "jig_bmu:guide.name",
    },
    content: {
        rawtext: [{ translate: "jig_bmu:info.part_01", with: ["\n"] }],
    },
    exit: {
        translate: "jig_bmu:guide_exit",
    },
    soundOnOpen: "random.click",
    soundOnClose: "jig_bmu.mut.zombie.death",
});
system.runInterval(() => {
    let showParticles = adminSettings.getString("showTargetParticle");
    if (showParticles != "off") {
        for (const dType of DimensionTypes.getAll()) {
            const dimension = world.getDimension(dType.typeId);
            const entities = dimension.getEntities({
                excludeFamilies: ["inanimate"],
                excludeTypes: ["item"],
                tags: ["jig_team_been_targetted"],
            }); // Get all entities once
            entity: for (const entity of entities) {
                try {
                    for (const tag in particleData) {
                        if (entity.hasTag(tag)) {
                            let particle = particleData[tag];
                            if (showParticles === "over") {
                                particle = particle.replace(/long/g, "over");
                            }
                            entity.dimension.spawnParticle(particle, entity.location);
                            break entity; // Break after finding the relevant tag to prevent unnecessary checks
                        }
                    }
                }
                catch (err) {
                    // Can't display particles outside of the world bounds
                }
            }
        }
    }
}, 4);
system.runInterval(() => {
    var _a, _b, _c, _d, _e;
    const validPlayers = world.getAllPlayers().filter((p) => p.isValid());
    for (const player of validPlayers) {
        const equipment = player.getComponent(EntityEquippableComponent.componentId);
        const helmetItem = ((_a = equipment.getEquipment(EquipmentSlot.Head)) === null || _a === void 0 ? void 0 : _a.typeId) || "";
        const chestItem = ((_b = equipment.getEquipment(EquipmentSlot.Chest)) === null || _b === void 0 ? void 0 : _b.typeId) || "";
        const legsItem = ((_c = equipment.getEquipment(EquipmentSlot.Legs)) === null || _c === void 0 ? void 0 : _c.typeId) || "";
        const bootsItem = ((_d = equipment.getEquipment(EquipmentSlot.Feet)) === null || _d === void 0 ? void 0 : _d.typeId) || "";
        const mainHandItem = ((_e = equipment.getEquipment(EquipmentSlot.Mainhand)) === null || _e === void 0 ? void 0 : _e.typeId) || "";
        let factionAnnounce = player.getTags();
        let foundFactionTag = factionTags.find((tag) => factionAnnounce.includes(tag)) || "";
        let showParticles = adminSettings.getBoolean("showPlayerFactionParticles");
        if (showParticles) {
            try {
                player.dimension.spawnParticle(`jig_bmu:${foundFactionTag}`, player.location);
            }
            catch (err) {
                // Can't display particles outside of the world bounds
            }
        }
        // Check if all four armor pieces are equipped
        if (helmetItem && chestItem && legsItem && bootsItem) {
            const items = [helmetItem, chestItem, legsItem, bootsItem];
            // Extract base type and check if all pieces belong to the same team
            const baseTypes = items.map((item) => {
                const parts = item.split("_");
                return parts[parts.length - 1]; // Get the last part, e.g., 'ecru'
            });
            const uniqueBaseTypes = new Set(baseTypes);
            const allSameBaseType = uniqueBaseTypes.size === 1;
            const isUSet = items.every((item) => item.includes("_u_"));
            if (allSameBaseType) {
                // All items are from the same team
                baseTypes[0];
                const effectStrength = isUSet ? 1 : 0;
                // Apply the resistance effect
                player.addEffect("resistance", 220, { amplifier: effectStrength, showParticles: false });
            }
        }
        // Check if the player has one of the swords equipped in the main hand
        const swords = ["jig_bmu:sword_beryl", "jig_bmu:sword_ecru", "jig_bmu:sword_llano", "jig_bmu:sword_sang"];
        if (swords.includes(mainHandItem)) {
            // Apply the strength effect with strength 0 and no particles
            player.addEffect("strength", 220, { amplifier: 0, showParticles: false });
        }
    }
}, 10);
world.beforeEvents.itemUse.subscribe((event) => {
    if (BATONS.includes(event.itemStack.typeId) || USED_BATONS.includes(event.itemStack.typeId)) {
        // check the factions
        const targetFaction = "jig_team_" +
            (event.itemStack.typeId.startsWith(BATON_USED_BASE)
                ? event.itemStack.typeId.substring(BATON_USED_BASE.length)
                : event.itemStack.typeId.substring(BATON_BASE.length));
        const player = event.source;
        // Ray casting
        const result = player.dimension.getEntitiesFromRay(player.getHeadLocation(), player.getViewDirection(), {
            maxDistance: 24,
        }).filter(r => r.entity.id !== event.source.id); // Filter out the player
        if (result.length > 0) {
            const entity = result[0].entity;
            let cancelItemUse = false;
            if (!event.source.hasTag(targetFaction)) {
                // Not the same faction - can't use their baton
                event.cancel = true;
                system.runTimeout(() => {
                    if (player.isValid()) {
                        player.onScreenDisplay.setActionBar(TRANSLATE("jig_bmu:wrong.team.baton"));
                        player.playSound("block.false_permissions", {
                            pitch: 2.0,
                            volume: 0.5,
                        });
                    }
                }, 1);
                return;
            }
            if (entity.typeId === "minecraft:item") {
                cancelItemUse = true;
            }
            else if (entity.hasTag(targetFaction)) {
                cancelItemUse = true;
            }
            else {
                const familyComponent = entity.getComponent(EntityTypeFamilyComponent.componentId);
                if (familyComponent &&
                    (familyComponent.hasTypeFamily(targetFaction) || familyComponent.hasTypeFamily("inanimate"))) {
                    cancelItemUse = true;
                }
            }
            if (cancelItemUse) {
                event.cancel = true;
                system.runTimeout(() => {
                    if (player.isValid()) {
                        player.playSound("block.false_permissions", {
                            pitch: 2.0,
                            volume: 0.5,
                        });
                    }
                }, 1);
            }
        }
        else {
            event.cancel = true;
        }
    }
});
world.afterEvents.itemUse.subscribe((event) => {
    var _a;
    const player = event.source;
    player.dimension;
    const targetBaton = TARGET_BATON.find((baton) => baton.item === event.itemStack.typeId);
    if (targetBaton) {
        const sound = `random.orb`;
        const errorsound = `random.pop2`;
        const options = {
            pitch: 1.5,
            volume: 0.5,
        };
        const erroroptions = {
            pitch: 2.0,
            volume: 0.5,
        };
        const result = player.dimension.getEntitiesFromRay(player.getHeadLocation(), player.getViewDirection()).filter(r => r.entity.id !== player.id);
        if (result.length > 0) {
            const entityHit = result[0].entity;
            if (entityHit) {
                const entityLocation = entityHit.location;
                const playerLocation = player.location;
                const t = 0.9; // weight factor closer to the entity
                const newPosition = {
                    x: playerLocation.x + t * (entityLocation.x - playerLocation.x),
                    y: playerLocation.y + t * (entityLocation.y - playerLocation.y),
                    z: playerLocation.z + t * (entityLocation.z - playerLocation.z),
                };
                // Toggle the tag on the entity
                if (entityHit.hasTag(targetBaton.targetTag)) {
                    entityHit.removeTag(targetBaton.targetTag);
                    entityHit.removeTag("jig_team_been_targetted");
                    // Spawn particle at the new position
                    world.playSound(errorsound, player.location, erroroptions);
                    entityHit.dimension.spawnParticle(targetBaton.otherparticle, newPosition);
                }
                else {
                    entityHit.addTag(targetBaton.targetTag);
                    (_a = world.scoreboard
                        .getObjective("jig_bmu:jig_computer.addon_stats")) === null || _a === void 0 ? void 0 : _a.addScore(`jig_bmu:targetted_${targetBaton.targetTag}`, 1);
                    entityHit.addTag("jig_team_been_targetted");
                    // Spawn particle at the new position
                    world.playSound(sound, player.location, options);
                    entityHit.dimension.spawnParticle(targetBaton.particle, newPosition);
                }
            }
        }
    }
});
world.afterEvents.projectileHitEntity.subscribe((event) => {
    const projectile = event.projectile;
    const source = event.source; // Entity that fired the projectile
    const hitEntityInfo = event.getEntityHit(); // Information about the hit entity
    const hitEntity = hitEntityInfo === null || hitEntityInfo === void 0 ? void 0 : hitEntityInfo.entity;
    const MUTATED = "jig_bmu:mutated";
    // Helper function to check if an entity belongs to the same team
    const isSameTeam = (entity, factionTag) => {
        var _a;
        if (entity instanceof Player) {
            // Check tags for players
            return entity.hasTag(factionTag);
        }
        else {
            // Check family component for other entities
            const familyComponent = entity.getComponent(EntityTypeFamilyComponent.componentId);
            return (_a = familyComponent === null || familyComponent === void 0 ? void 0 : familyComponent.hasTypeFamily(factionTag)) !== null && _a !== void 0 ? _a : false;
        }
    };
    // Logic for Mutation Feature
    const handleMutation = () => {
        var _a;
        const item = projectile.typeId;
        if (item === "jig_bmu:shot_essence" && projectile.isValid() && GET_RAW_PROP(projectile, MUTATED) !== true) {
            const hitEntityLocation = (hitEntity === null || hitEntity === void 0 ? void 0 : hitEntity.isValid()) ? hitEntity.location : event.location;
            const mutation = mutation_information.find((info) => info.mob === (hitEntity === null || hitEntity === void 0 ? void 0 : hitEntity.typeId));
            if (mutation) {
                const spawned = hitEntity === null || hitEntity === void 0 ? void 0 : hitEntity.dimension.spawnEntity(mutation.mutate_into, hitEntityLocation);
                if (spawned) {
                    SET_RAW_PROP(spawned, MUTATED_SPAWNED, true);
                }
                // Prevent further mutation
                SET_RAW_PROP(projectile, MUTATED, true);
                (_a = world.scoreboard.getObjective("jig_bmu:jig_computer.addon_stats")) === null || _a === void 0 ? void 0 : _a.addScore("jig_bmu:mutants_mutated", 1);
                event.dimension.spawnParticle("jig_bmu:mutant_poof", hitEntityLocation);
                event.dimension.spawnParticle("jig_bmu:explosion_emitter", hitEntityLocation);
                event.dimension.playSound("mob.zombie.remedy", hitEntityLocation);
                if (hitEntity === null || hitEntity === void 0 ? void 0 : hitEntity.isValid()) {
                    hitEntity.remove();
                }
            }
        }
    };
    // Logic for Auto Totem Feature
    const handleAutoTotem = () => {
        if (!(source instanceof Player) || !(hitEntity === null || hitEntity === void 0 ? void 0 : hitEntity.isValid())) {
            return; // Skip if the source is not a player or the hit entity is invalid
        }
        const sourceEquipment = source.getComponent(EntityEquippableComponent.componentId);
        const mainhand = sourceEquipment.getEquipmentSlot(EquipmentSlot.Mainhand);
        const offhand = sourceEquipment.getEquipmentSlot(EquipmentSlot.Offhand);
        // Check if the source has a TARGET_TOTEM item in mainhand or offhand
        const totem = TARGET_TOTEM.find((totem) => {
            var _a, _b;
            return ((mainhand === null || mainhand === void 0 ? void 0 : mainhand.getItem()) && ((_a = mainhand.getItem()) === null || _a === void 0 ? void 0 : _a.typeId) === totem.item) ||
                ((offhand === null || offhand === void 0 ? void 0 : offhand.getItem()) && ((_b = offhand.getItem()) === null || _b === void 0 ? void 0 : _b.typeId) === totem.item);
        });
        if (totem) {
            const targetTag = totem.targetTag;
            const factionTag = targetTag.replace("_target", ""); // Extract team tag (e.g., "jig_team_ecru")
            // Validate that the source has the corresponding team tag
            if (!source.hasTag(factionTag)) {
                return; // Skip if the player doesn't have the correct team tag
            }
            // Apply target tag and particle to the hit entity if not on the same team
            if (!isSameTeam(hitEntity, factionTag)) {
                hitEntity.addTag(targetTag);
                hitEntity.addTag("jig_team_been_targetted");
                event.dimension.spawnParticle(totem.particle, hitEntity.location);
            }
        }
    };
    // Logic for Targeting the Shooter
    const handleShooterTargeting = () => {
        if (!(hitEntity instanceof Player) || !(source === null || source === void 0 ? void 0 : source.isValid())) {
            return; // Skip if the hit entity is not a player or the source is invalid
        }
        const hitEquipment = hitEntity.getComponent(EntityEquippableComponent.componentId);
        const mainhand = hitEquipment.getEquipmentSlot(EquipmentSlot.Mainhand);
        const offhand = hitEquipment.getEquipmentSlot(EquipmentSlot.Offhand);
        // Check if the hit player has a TARGET_TOTEM item in mainhand or offhand
        const totem = TARGET_TOTEM.find((totem) => {
            var _a, _b;
            return ((mainhand === null || mainhand === void 0 ? void 0 : mainhand.getItem()) && ((_a = mainhand.getItem()) === null || _a === void 0 ? void 0 : _a.typeId) === totem.item) ||
                ((offhand === null || offhand === void 0 ? void 0 : offhand.getItem()) && ((_b = offhand.getItem()) === null || _b === void 0 ? void 0 : _b.typeId) === totem.item);
        });
        if (totem) {
            const targetTag = totem.targetTag;
            const factionTag = targetTag.replace("_target", ""); // Extract team tag (e.g., "jig_team_ecru")
            // Validate that the hit player has the corresponding team tag
            if (!hitEntity.hasTag(factionTag)) {
                return; // Skip if the player doesn't have the correct team tag
            }
            // Apply target tag and particle to the shooter if not on the same team
            if (!isSameTeam(source, factionTag)) {
                source.addTag(targetTag);
                source.addTag("jig_team_been_targetted");
                event.dimension.spawnParticle(totem.particle, source.location);
            }
        }
    };
    // Execute all features
    handleMutation();
    handleAutoTotem();
    handleShooterTargeting();
});
world.afterEvents.entityHitEntity.subscribe((event) => {
    const attacker = event.damagingEntity;
    const target = event.hitEntity;
    // Helper function to check if an entity belongs to the same team
    const isSameTeam = (entity, factionTag) => {
        var _a;
        if (entity instanceof Player) {
            return entity.hasTag(factionTag);
        }
        else {
            const familyComponent = entity.getComponent(EntityTypeFamilyComponent.componentId);
            return (_a = familyComponent === null || familyComponent === void 0 ? void 0 : familyComponent.hasTypeFamily(factionTag)) !== null && _a !== void 0 ? _a : false;
        }
    };
    // Feature: Apply Effect from Table
    const applyMutantEffect = () => {
        const mutantEffect = MutantEffects.find((effect) => effect.mutant === (attacker === null || attacker === void 0 ? void 0 : attacker.typeId));
        if (!mutantEffect || !target)
            return;
        const difficultyKey = getDifficultyKey();
        const duration = mutantEffect[`duration_${difficultyKey}`] * 20; // Convert seconds to ticks
        const strength = mutantEffect[`strength_${difficultyKey}`];
        target.addEffect(mutantEffect.effect, duration, { amplifier: strength, showParticles: true });
    };
    // Feature: Turn Mob into Egg if Using Baton
    const handleBatonUsage = () => {
        if (!(attacker instanceof Player) || !isMutant(target === null || target === void 0 ? void 0 : target.typeId) || !target.isValid())
            return;
        const equipment = attacker.getComponent(EntityEquippableComponent.componentId);
        const mainhand = equipment.getEquipmentSlot(EquipmentSlot.Mainhand);
        const item = mainhand.getItem();
        if (item && (BATONS.includes(item.typeId) || USED_BATONS.includes(item.typeId))) {
            const faction = item.typeId.startsWith(BATON_USED_BASE)
                ? item.typeId.substring(BATON_USED_BASE.length)
                : item.typeId.substring(BATON_BASE.length);
            const targetFaction = "jig_team_" + faction;
            const familyComponent = target.getComponent(EntityTypeFamilyComponent.componentId);
            if (attacker.hasTag(targetFaction) && (familyComponent === null || familyComponent === void 0 ? void 0 : familyComponent.hasTypeFamily(targetFaction))) {
                const mutant = target.typeId;
                const eggType = mutant.replace("jig_bmu:", "jig_bmu:" + faction[0] + "_");
                const itemStack = new ItemStack(eggType, 1);
                itemStack.nameTag = target.nameTag;
                const healthComponent = target.getComponent(EntityHealthComponent.componentId);
                const healthAmount = Math.max(1, Math.round(healthComponent.currentValue));
                itemStack.setLore([EGG_HEALTH_PREFIX + healthAmount]);
                target.dimension.spawnParticle(`jig_bmu:team_${faction}_egg`, target.location);
                target.dimension.spawnItem(itemStack, target.location);
                target.remove();
            }
        }
    };
    // Feature: Auto Totem Logic
    const handleAutoTotem = () => {
        if (attacker instanceof Player && target.isValid()) {
            const equipment = attacker.getComponent(EntityEquippableComponent.componentId);
            const mainhand = equipment.getEquipmentSlot(EquipmentSlot.Mainhand);
            const offhand = equipment.getEquipmentSlot(EquipmentSlot.Offhand);
            const totem = TARGET_TOTEM.find((totem) => {
                var _a, _b;
                return ((mainhand === null || mainhand === void 0 ? void 0 : mainhand.getItem()) && ((_a = mainhand.getItem()) === null || _a === void 0 ? void 0 : _a.typeId) === totem.item) ||
                    ((offhand === null || offhand === void 0 ? void 0 : offhand.getItem()) && ((_b = offhand.getItem()) === null || _b === void 0 ? void 0 : _b.typeId) === totem.item);
            });
            if (totem) {
                const targetTag = totem.targetTag;
                const factionTag = targetTag.replace("_target", "");
                if (!attacker.hasTag(factionTag))
                    return;
                if (!isSameTeam(target, factionTag)) {
                    target.addTag(targetTag);
                    target.addTag("jig_team_been_targetted");
                    target.dimension.spawnParticle(totem.particle, target.location);
                }
            }
        }
        if (target instanceof Player && (attacker === null || attacker === void 0 ? void 0 : attacker.isValid())) {
            const equipment = target.getComponent(EntityEquippableComponent.componentId);
            const mainhand = equipment.getEquipmentSlot(EquipmentSlot.Mainhand);
            const offhand = equipment.getEquipmentSlot(EquipmentSlot.Offhand);
            const totem = TARGET_TOTEM.find((totem) => {
                var _a, _b;
                return ((mainhand === null || mainhand === void 0 ? void 0 : mainhand.getItem()) && ((_a = mainhand.getItem()) === null || _a === void 0 ? void 0 : _a.typeId) === totem.item) ||
                    ((offhand === null || offhand === void 0 ? void 0 : offhand.getItem()) && ((_b = offhand.getItem()) === null || _b === void 0 ? void 0 : _b.typeId) === totem.item);
            });
            if (totem) {
                const targetTag = totem.targetTag;
                const factionTag = targetTag.replace("_target", "");
                if (!target.hasTag(factionTag))
                    return;
                if (!isSameTeam(attacker, factionTag)) {
                    attacker.addTag(targetTag);
                    attacker.addTag("jig_team_been_targetted");
                    attacker.dimension.spawnParticle(totem.particle, attacker.location);
                }
            }
        }
    };
    // Execute all features
    applyMutantEffect();
    handleBatonUsage();
    handleAutoTotem();
});
const BATON_BASE = "jig_bmu:baton_";
const BATON_USED_BASE = "jig_bmu:baton_used_";
const BATONS = factions.map((f) => `${BATON_BASE}${f}`);
const USED_BATONS = factions.map((f) => `${BATON_USED_BASE}${f}`);
// Baton
world.afterEvents.itemUse.subscribe((event) => {
    const item = event.itemStack;
    const player = event.source;
    if (BATONS.includes(item.typeId)) {
        const normalBaton = item.typeId;
        const usedBaton = BATON_USED_BASE + normalBaton.substring(BATON_BASE.length);
        addIdentifier(item);
        const itemId = getIdentifier(item);
        const updatedItem = transformItem(item, usedBaton);
        const equipment = player.getComponent(EntityEquippableComponent.componentId);
        equipment.setEquipment(EquipmentSlot.Mainhand, updatedItem);
        const runId = system.runInterval(() => {
            if (player.isValid()) {
                let restoreItem = false;
                const equipment = player.getComponent(EntityEquippableComponent.componentId);
                const mainHandItem = equipment.getEquipment(EquipmentSlot.Mainhand);
                if (!mainHandItem || mainHandItem.typeId !== usedBaton) {
                    restoreItem = true;
                }
                if (player.isSneaking) {
                    restoreItem = true;
                }
                if (restoreItem) {
                    // check if the item is in the cursor, if so, just skip the restore
                    const cursorSlot = player.getComponent(PlayerCursorInventoryComponent.componentId);
                    if (cursorSlot && cursorSlot.isValid()) {
                        const item = cursorSlot.item;
                        if (item && getIdentifier(item) === itemId) {
                            return;
                        }
                    }
                    updateItem(player, itemId, (itemStack) => {
                        return transformItem(itemStack, normalBaton);
                    });
                    system.clearRun(runId);
                }
            }
            else {
                system.clearRun(runId);
            }
        }, 5);
    }
});
world.beforeEvents.entityRemove.subscribe((event) => {
    if (event.removedEntity.typeId === "minecraft:item") {
        const entityComponent = event.removedEntity.getComponent(EntityItemComponent.componentId);
        if ((entityComponent === null || entityComponent === void 0 ? void 0 : entityComponent.isValid()) &&
            entityComponent.itemStack &&
            USED_BATONS.includes(entityComponent.itemStack.typeId)) {
            const itemId = getIdentifier(entityComponent.itemStack);
            const normalBaton = BATON_BASE + entityComponent.itemStack.typeId.substring(BATON_USED_BASE.length);
            system.runTimeout(() => {
                world
                    .getAllPlayers()
                    .filter((p) => p.isValid())
                    .forEach((p) => {
                    updateItem(p, itemId, (input) => {
                        return transformItem(input, normalBaton);
                    });
                });
            }, 5);
        }
    }
});
world.afterEvents.playerSpawn.subscribe((event) => {
    // Check if we have an used baton and restore
    const inventory = event.player.getComponent(EntityInventoryComponent.componentId);
    if (inventory.container) {
        for (let i = 0; i < inventory.container.size; i++) {
            const item = inventory.container.getItem(i);
            if (item && USED_BATONS.includes(item.typeId)) {
                const usedBaton = item.typeId;
                const normalBaton = BATON_BASE + usedBaton.substring(BATON_USED_BASE.length);
                inventory.container.setItem(i, transformItem(item, normalBaton));
            }
        }
    }
});
const EGG_HEALTH_PREFIX = "Health: ";
const currentDifficulty = "normal"; // Set the current difficulty
function getDifficultyKey() {
    switch (currentDifficulty) {
        case "easy":
            return "e";
        case "normal":
            return "n";
        case "hard":
            return "h";
        default:
            return "e"; // Fallback to easy if difficulty is unknown
    }
}
//  world.afterEvents.entityHurt.subscribe((event) => {
//  if (
//    !(event.damageSource.damagingEntity instanceof Player) ||
//    !isMutant(event.hurtEntity.typeId) ||
//    !event.hurtEntity.isValid()
//  ) {
//    return;
//  }
//
//  const player = event.damageSource.damagingEntity;
//
//  const equipment = player.getComponent(EntityEquippableComponent.componentId) as EntityEquippableComponent;
//  const mainhand = equipment.getEquipmentSlot(EquipmentSlot.Mainhand);
//  const item = mainhand.getItem();
//  if (item && (BATONS.includes(item.typeId) || USED_BATONS.includes(item.typeId))) {
//    const faction = item.typeId.startsWith(BATON_USED_BASE)
//      ? item.typeId.substring(BATON_USED_BASE.length)
//      : item.typeId.substring(BATON_BASE.length);
//    const targetFaction = "jig_team_" + faction;
//    const familyComponent = event.hurtEntity.getComponent(EntityTypeFamilyComponent.componentId) as
//      | EntityTypeFamilyComponent
//      | undefined;
//
//    if (player.hasTag(targetFaction) && familyComponent && familyComponent.hasTypeFamily(targetFaction)) {
//      const damageAmount = event.damage;
//      const mutant = event.hurtEntity.typeId;
//      const eggType = mutant.replace("jig_bmu:", "jig_bmu:" + faction[0] + "_");
//      const itemStack = new ItemStack(eggType, 1);
//      itemStack.nameTag = event.hurtEntity.nameTag;
//      let healthComponent = event.hurtEntity.getComponent(EntityHealthComponent.componentId) as EntityHealthComponent;
//      let healthAmount = healthComponent.currentValue;
//
//      // Round the healthAmount to the nearest whole number
//      let roundedHealthAmount = Math.round(healthAmount + damageAmount);
//
//      // Ensure the rounded value is not zero
//      if (roundedHealthAmount === 0) {
//        roundedHealthAmount = 1;
//      }
//      itemStack.setLore([EGG_HEALTH_PREFIX + roundedHealthAmount]);
//
//      event.hurtEntity.dimension.spawnItem(itemStack, event.hurtEntity.location);
//      event.hurtEntity.remove();
//    }
//  }
//});
world.beforeEvents.itemUseOn.subscribe((event) => {
    const eggFactionMap = factions.map((f) => `jig_bmu:${f[0]}_`);
    const foundFaction = eggFactionMap.find((f) => event.itemStack.typeId.startsWith(f));
    const isItemFrame = event.block.typeId === 'minecraft:frame' || event.block.typeId === 'minecraft:glow_frame';
    if (foundFaction && !isItemFrame) {
        event.cancel = true;
        const baseEntityId = event.itemStack.typeId.replace(foundFaction, "jig_bmu:");
        const faction = factions.find((f) => f[0] === foundFaction[foundFaction.length - 2]);
        const beFaction = "jig_bmu:be_" + faction;
        const entityId = `${baseEntityId}<${beFaction}>`;
        const player = event.source;
        const location = {
            x: event.faceLocation.x + event.block.location.x,
            y: event.faceLocation.y + event.block.location.y,
            z: event.faceLocation.z + event.block.location.z,
        };
        const item = event.itemStack;
        system.runTimeout(() => {
            if (player.isValid()) {
                const equipment = player.getComponent(EntityEquippableComponent.componentId);
                let removeItem = false;
                let GameMode = player.getGameMode();
                if (GameMode != "creative") {
                    if (item.amount > 1) {
                        item.amount = item.amount - 1;
                    }
                    else {
                        removeItem = true;
                    }
                }
                const updatedItem = removeItem ? undefined : item;
                equipment.setEquipment(EquipmentSlot.Mainhand, updatedItem);
                if (adminSettings.getBoolean("turnOffFactions")) {
                    // Factions are off  - spawn required items
                    let trophyId = baseEntityId.replace('jig_bmu:', 'jig_bmu:mut_b_');
                    debug(baseEntityId);
                    switch (baseEntityId) {
                        case 'jig_bmu:turtle':
                            trophyId = 'jig_bmu:mut_b_sea_turtle';
                            break;
                        case 'jig_bmu:beeswarm':
                            trophyId = 'minecraft:beehive';
                            break;
                        case 'jig_bmu:zombie_villager':
                            trophyId = 'jig_bmu:mut_b_zvillager';
                            break;
                        case 'jig_bmu:zombie_juju':
                            trophyId = 'jig_bmu:mut_b_juju';
                            break;
                        case 'jig_bmu:zombie_pigman':
                            trophyId = 'jig_bmu:mut_b_zpiglin';
                            break;
                    }
                    player.dimension.spawnItem(new ItemStack(trophyId), location);
                    player.dimension.spawnItem(new ItemStack(`jig_common:emblem_${faction}`), location);
                    player.dimension.spawnItem(new ItemStack('jig_bmu:mutant_essence', 3), location);
                }
                else {
                    const entity = player.dimension.spawnEntity(entityId, location);
                    SET_RAW_PROP(entity, FACTION_MUTANT_SPAWNED, true);
                    if (item.nameTag) {
                        entity.nameTag = item.nameTag;
                    }
                    if (item.getLore().length > 0 && item.getLore()[0].startsWith(EGG_HEALTH_PREFIX)) {
                        const health = parseInt(item.getLore()[0].substring(EGG_HEALTH_PREFIX.length));
                        if (!isNaN(health)) {
                            entity.getComponent(EntityHealthComponent.componentId).setCurrentValue(health);
                        }
                    }
                }
            }
        }, 1);
    }
});
world.afterEvents.entityDie.subscribe((event) => {
    var _a, _b;
    const deadEntity = event.deadEntity;
    if (!deadEntity.isValid())
        return;
    const dDimension = deadEntity.dimension;
    const dLocation = deadEntity.location;
    const deadByPlayer = ((_a = event.damageSource.damagingEntity) === null || _a === void 0 ? void 0 : _a.typeId) === "minecraft:player";
    if (!dDimension || !dLocation || !deadByPlayer)
        return;
    // Get the EntityTypeFamilyComponent
    const familyComponent = deadEntity.getComponent(EntityTypeFamilyComponent.componentId);
    if (!familyComponent)
        return;
    // Check if the dead entity belongs to the "monster" or "mutant" family
    const isMonster = familyComponent.hasTypeFamily("monster");
    const isMutant = familyComponent.hasTypeFamily("mutant");
    if (!isMonster && !isMutant)
        return;
    let MONSTER_ESSENCE_DROP_RATE = 0.1;
    let MUTANT_ESSENCE_DROP_RATE = 0.8;
    let lootingLevel = 0; // Default to 0 if no Looting enchantment
    const player = event.damageSource.damagingEntity;
    const equipment = player.getComponent(EntityEquippableComponent.componentId);
    if (equipment) {
        const mainHand = equipment.getEquipmentSlot(EquipmentSlot.Mainhand);
        if (mainHand.hasItem()) {
            const itemEnchantable = (_b = mainHand.getItem()) === null || _b === void 0 ? void 0 : _b.getComponent(ItemEnchantableComponent.componentId);
            if (itemEnchantable) {
                const looting = itemEnchantable.getEnchantment("looting");
                if (looting) {
                    lootingLevel = looting.level; // Store looting level
                    // Increases change by 0.01 per level
                    MONSTER_ESSENCE_DROP_RATE += looting.level * 0.10;
                    MUTANT_ESSENCE_DROP_RATE += looting.level * 0.055;
                }
            }
        }
    }
    // There's a chance to spawn a mutant essence at the location of the dead entity
    if (isMonster && Math.random() < MONSTER_ESSENCE_DROP_RATE) {
        // 10% chance if it's a monster
        const count = Math.floor(Math.random() * (1 + lootingLevel + 1)); // +1 ensures a chance for 1 even at Looting 0
        if (count >= 1) {
            spawnMutantEssence(dDimension, dLocation, count);
        }
    }
    if (isMutant && Math.random() < MUTANT_ESSENCE_DROP_RATE) {
        // 80% chance if it's a mutant
        const count = Math.floor(Math.random() * (3 + lootingLevel)); // Ensures a chance for 1 even at Looting 0
        if (count >= 1) {
            spawnMutantEssence(dDimension, dLocation, count);
        }
    }
});
function spawnMutantEssence(dimension, location, count) {
    if (!world.gameRules.doMobLoot) {
        return;
    }
    const essence = new ItemStack("jig_bmu:mutant_essence", count);
    try {
        dimension.spawnItem(essence, {
            x: location.x,
            y: location.y,
            z: location.z,
        });
    }
    catch (err) {
        // Silently ignore this error
    }
}
const mobConfigs = {
    "jig_bmu:iron_golem": {
        typeId: "jig_bmu:iron_golem",
        impulseY: 1,
        knockbackHorizontal: 1,
        knockbackVertical: 1,
    },
    "jig_bmu:endermite": {
        typeId: "jig_bmu:endermite",
        impulseY: 0, // Not used for endermite
        knockbackHorizontal: 4.4, // These values are calculated randomly
        knockbackVertical: 1,
        randomKnockback: true,
    },
    "jig_bmu:sandra": {
        typeId: "jig_bmu:sandra",
        impulseY: 2,
        knockbackHorizontal: 2,
        knockbackVertical: 2,
        radiusSquared: 5 * 5,
    },
    "jig_bmu:zombie_juju": {
        typeId: "jig_bmu:zombie_juju",
        impulseY: 0.5,
        knockbackHorizontal: 0.5,
        knockbackVertical: 0.5,
    },
    "jig_bmu:dan_drowned": {
        typeId: "jig_bmu:dan_drowned",
        impulseY: 0.2,
        knockbackHorizontal: 1,
        knockbackVertical: 0.2
    },
    "jig_bmu:zombie_pigman": {
        typeId: "jig_bmu:zombie_pigman",
        impulseY: 0.3,
        knockbackHorizontal: 0.5,
        knockbackVertical: 0.3,
    },
    "jig_bmu:zombie": {
        typeId: "jig_bmu:zombie",
        impulseY: 0.25,
        knockbackHorizontal: 0.25,
        knockbackVertical: 0.25,
    },
    "jig_bmu:piglin_brute": {
        typeId: "jig_bmu:piglin_brute",
        impulseY: 0.6,
        knockbackHorizontal: 0.6,
        knockbackVertical: 0.6,
    },
    "jig_bmu:ravager": {
        typeId: "jig_bmu:ravager",
        impulseY: 0.4,
        knockbackHorizontal: 0.6,
        knockbackVertical: 0.4,
    },
    "jig_bmu:zoglin": {
        typeId: "jig_bmu:zoglin",
        impulseY: 0.3,
        knockbackHorizontal: 0.5,
        knockbackVertical: 0.3,
    },
    "jig_bmu:vindicator": {
        typeId: "jig_bmu:vindicator",
        impulseY: 0.3,
        knockbackHorizontal: 0.4,
        knockbackVertical: 0.3,
    },
    "jig_bmu:cerberus": {
        typeId: "jig_bmu:cerberus",
        impulseY: 0.3,
        knockbackHorizontal: 0.4,
        knockbackVertical: 0.3,
    },
};
world.afterEvents.entityHurt.subscribe((event) => {
    const damagingEntity = event.damageSource.damagingEntity;
    const hurtEntity = event.hurtEntity;
    // Early exit if entities are missing
    if (!damagingEntity || !hurtEntity)
        return;
    // Check if the entities are still valid
    if (!damagingEntity.isValid() || !hurtEntity.isValid()) {
        return;
    }
    // Define a set of valid entity types that support getViewDirection
    const validEntityTypes = new Set([
        "jig_bmu:iron_golem",
        "jig_bmu:endermite",
        "jig_bmu:sandra",
        "jig_bmu:zombie_juju",
        "jig_bmu:dan_drowned",
        "jig_bmu:zombie_pigman",
        "jig_bmu:zombie",
        "jig_bmu:piglin_brute",
        "jig_bmu:ravager",
        "jig_bmu:zoglin",
        "jig_bmu:vindicator",
        // Add other entity types that should have getViewDirection
    ]);
    // Only proceed if the entity type is in the valid set
    if (!validEntityTypes.has(damagingEntity.typeId)) {
        return; // Exit if the entity type is not valid
    }
    // Get the view direction of the damaging entity
    const direction = damagingEntity.getViewDirection();
    const direction_x = direction.x;
    const direction_z = direction.z;
    const mobConfig = mobConfigs[damagingEntity.typeId];
    if (!mobConfig)
        return; // If mob is not configured, exit
    // Utility function to apply impulse or knockback
    function applyImpulseOrKnockback(entity, x, z, y, horizontal, vertical) {
        // Check if the entity is still valid
        if (!entity.isValid()) {
            return;
        }
        if (entity.typeId === "minecraft:player") {
            entity.applyKnockback(x, z, horizontal, vertical);
        }
        else {
            entity.applyImpulse({ x, y, z });
        }
    }
    if (mobConfig.randomKnockback) {
        const variable_horizontal = Math.random() * (6.7 - 4.4) + 4.4; // Random value between 4.4 and 6.7
        const variable_vertical = Math.random() / 7; // Random value between 0 and 1
        hurtEntity.applyKnockback(direction_x, direction_z, variable_horizontal, variable_vertical);
        return;
    }
    if (mobConfig.radiusSquared !== undefined) {
        const position_of_mob = damagingEntity.location;
        const position_of_target = hurtEntity.location;
        // Calculate the distance in 3D space
        const deltaX = position_of_target.x - position_of_mob.x;
        const deltaY = position_of_target.y - position_of_mob.y;
        const deltaZ = position_of_target.z - position_of_mob.z;
        const distanceSquared = deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ;
        // Check if the target is within the radius in 3D space
        if (distanceSquared <= mobConfig.radiusSquared) {
            applyImpulseOrKnockback(hurtEntity, direction_x, direction_z, mobConfig.impulseY, mobConfig.knockbackHorizontal, mobConfig.knockbackVertical);
        }
    }
    else {
        applyImpulseOrKnockback(hurtEntity, direction_x, direction_z, mobConfig.impulseY, mobConfig.knockbackHorizontal, mobConfig.knockbackVertical);
    }
});
world.afterEvents.entityDie.subscribe((event) => {
    if (isMutant(event.deadEntity.typeId) && event.damageSource.damagingEntity instanceof Player) {
        const player = event.damageSource.damagingEntity;
        const killedMutants = GET_PROP(player, PLAYER_KILLED_MUTANTS_PROP, []);
        let update = false;
        let mutant = killedMutants.find((km) => km.name === event.deadEntity.typeId);
        if (!mutant) {
            mutant = { name: event.deadEntity.typeId };
            killedMutants.push(mutant);
            update = true;
        }
        if (update) {
            SET_PROP(player, PLAYER_KILLED_MUTANTS_PROP, killedMutants);
        }
    }
});
initMutantSpawn();
//delete this if you are giving your book in a different way
giveASingleItem({
    itemTypeId: BOOK_ID,
});
registerItemCompleteUseHandler();
initMutantStickers();
//# sourceMappingURL=bmu_main.js.map
