import Difficulty from "@rbxts/ejt";
import { OnoeNum } from "@rbxts/serikanum";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Formula from "shared/currency/Formula";
import Item from "shared/item/Item";
import { Server } from "shared/api/APIExpose";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import FormulaBundled from "shared/item/traits/FormulaBundled";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import CruelBlankEssence from "shared/items/0/spontaneous/CruelBlankEssence";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Solitude")
    .setDescription(`<font color="rgb(255,0,0)" weight="heavy">An endless solo of nothingness.</font>\n`)
    .setDifficulty(Difficulty.Spontaneous)
    .setPrice(new CurrencyBundle().set("Funds", 1e48), 1)
    .setRequiredItemAmount(CruelBlankEssence, 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class0Shop)

    .setFormula(new Formula().log(10).div(100).add(1))
    .setFormulaX("skill")
    .setFormulaXCap(new CurrencyBundle().set("Skill", OnoeNum.fromSerika(1, 3306)))

    .trait(Conveyor)
    .setSpeed(50)

    .trait(FormulaBundled)
    .setX(() => Server.Currency.get("Skill"))
    .setRatio("Funds", 9.99)
    .setRatio("Skill", 9.99)
    .apply(Upgrader)
    .setSky(true)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Damager from "shared/item/traits/upgrader/Damager";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import MagicalCraftingTable from "shared/items/0/millisecondless/MagicalCraftingTable";
import ExcavationStone from "shared/items/excavation/ExcavationStone";
import Gold from "shared/items/excavation/Gold";
import WhiteGem from "shared/items/excavation/WhiteGem";

export = new Item(script.Name)
    .setName("Crimson Cemetery")
    .setDescription(
        "A bloody moon dyes a forgotten cemetery in crimson red. Deals %hp_add% to droplets for a %mul% gain, though space constraints may pose a challenge...",
    )
    .setDifficulty(Difficulty.Unlosable)
    .setPrice(new CurrencyBundle().set("Power", 2e21), 1, 2)
    .setRequiredItemAmount(ExcavationStone, 500)
    .setRequiredItemAmount(WhiteGem, 150)
    .setRequiredItemAmount(Gold, 3)
    .addPlaceableArea("BarrenIslands")
    .soldAt(MagicalCraftingTable)
    .setCreator("CoPKaDT")
    .persists()

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Power", 2))

    .trait(Damager)
    .setDamage(30)

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import InstantiationDelimiter from "shared/item/traits/InstantiationDelimiter";
import Item from "shared/item/Item";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Instantiation Delimiter V")
    .setDescription("Increases droplet limit in Slamo Village by 15, at the cost of %drain%.")
    .setDifficulty(Difficulty.Unlosable)
    .setPrice(new CurrencyBundle().set("Skill", 100000), 1)
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)

    .setDrain(new CurrencyBundle().set("Skill", 50))

    .trait(InstantiationDelimiter)
    .setDropletIncrease(15)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Condenser from "shared/item/traits/dropper/Condenser";
import Droplet from "shared/item/Droplet";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Reinforced Condenser")
    .setDescription(
        "Your droplet count is reaching extreme limits, and you don't want to craft another Limit Breaker. Produces %val% droplets when %quota% of those values are processed through the attached furnace.",
    )
    .setDifficulty(Difficulty.Unlosable)
    .setPrice(new CurrencyBundle().set("Funds", 140e36).set("Bitcoin", 1e9), 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Condenser)
    .addDroplets(Droplet.LiquidesterFundsDroplet, Droplet.LiquidesterPowerDroplet, Droplet.LiquidesterBitcoinDroplet)
    .setQuota(0.35)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Generator from "shared/item/traits/generator/Generator";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Reinforced Tesseract")
    .setDescription(
        "Scientists are still trying to figure out what qualifies as a tesseract. Against all odds, this particular piece of machinery produces an absurd %gain%.",
    )
    .setDifficulty(Difficulty.Unlosable)
    .setPrice(
        new CurrencyBundle().set("Funds", 300e36).set("Power", 10e21).set("Skill", 90000).set("Dark Matter", 70e9),
        1,
    )
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)

    .trait(Generator)
    .setPassiveGain(new CurrencyBundle().set("Dark Matter", 1.7e15))

    .exit();


import Difficulty from "@rbxts/ejt";
import { findBaseParts } from "@antivivi/vrldk";
import { CollectionService, Workspace } from "@rbxts/services";
import { Server } from "shared/api/APIExpose";
import { playSound } from "shared/asset/GameAssets";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Formula from "shared/currency/Formula";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import { VirtualCollision } from "shared/item/utils/VirtualReplication";
import Class0Shop from "shared/items/0/Class0Shop";

const mul = new CurrencyBundle().set("Funds", 0);

export = new Item(script.Name)
    .setName("Ring Of Fortune")
    .setDescription(
        "It's fate! You were destined to boost Funds gain, with that multiplier increasing by Skill. Just pass droplets through the correct ring. Or else...",
    )
    .setDifficulty(Difficulty.Unlosable)
    .setPrice(new CurrencyBundle().set("Funds", 90e36), 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .setFormula(new Formula().pow(0.1))
    .setFormulaX("skill")

    .trait(Upgrader)
    .applyFormula(
        (v, item) => item.setMul(mul.set("Funds", v)),
        () => Server.Currency.get("Skill"),
    )
    .exit()

    .onLoad((model) => {
        for (const part of findBaseParts(model, "SadLaser")) {
            CollectionService.AddTag(part, "Laser");
            let debounce = false;
            VirtualCollision.onDropletTouched(model, part, (dropletModel) => {
                if (debounce === true) return;
                debounce = true;
                task.delay(1, () => (debounce = false));
                const explosion = new Instance("Explosion");
                explosion.ExplosionType = Enum.ExplosionType.NoCraters;
                explosion.BlastRadius = 50;
                explosion.BlastPressure = 2500000;
                explosion.DestroyJointRadiusPercent = 0;
                explosion.Position = dropletModel.Position;
                playSound("Explosion.mp3", dropletModel);
                explosion.Parent = Workspace;
            });
        }
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Droplet from "shared/item/Droplet";
import Dropper from "shared/item/traits/dropper/Dropper";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Sexdecuple Coin Miner")
    .setDescription(
        "We are reaching slightly ridiculous names now. Produces %val% droplets per second. Your choice to harvest for Bitcoin or Skill...",
    )
    .setDifficulty(Difficulty.Unlosable)
    .setPrice(new CurrencyBundle().set("Skill", 40000).set("Bitcoin", 500e6), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class0Shop)
    .persists("Skillification")

    .trait(Dropper)
    .setDroplet(Droplet.SexdecupleCoin)
    .setDropRate(1)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Droplet from "shared/item/Droplet";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Dropper from "shared/item/traits/dropper/Dropper";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Strong Skill Factory")
    .setDescription("Produce %val% droplets every 2 seconds.")
    .setDifficulty(Difficulty.Unlosable)
    .setPrice(new CurrencyBundle().set("Skill", 330000), 1)
    .setPrice(new CurrencyBundle().set("Skill", 660000), 2)
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)

    .trait(Dropper)
    .setDroplet(Droplet.SkillestDroplet)
    .setDropRate(0.5)

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import DropperBooster from "shared/item/traits/boost/DropperBooster";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import MagicalCraftingTable from "shared/items/0/millisecondless/MagicalCraftingTable";
import Gold from "shared/items/excavation/Gold";
import CorruptedGrass from "shared/items/0/happylike/CorruptedGrass";
import Quartz from "shared/items/excavation/Quartz";

export = new Item(script.Name)
    .setName("Boombox Elevator")
    .setDescription(
        "Elevate your droplets while listening to some vibey tunes! If you place droppers in front of the boombox, they might also enjoy these tunes and have better production as well...",
    )
    .setDifficulty(Difficulty.Vibeness)
    .setPrice(new CurrencyBundle().set("Skill", 10000000).set("Power", 250e24).set("Dark Matter", 25e27), 1)
    .setRequiredItemAmount(Quartz, 2)
    .setRequiredItemAmount(Gold, 6)
    .setRequiredItemAmount(CorruptedGrass, 2)
    .addPlaceableArea("BarrenIslands")
    .soldAt(MagicalCraftingTable)
    .setCreator("sanjay2133")
    .persists()

    .trait(Conveyor)
    .setSpeed(3)

    .trait(DropperBooster)
    .setDropRateMul(1.25)

    .exit();


import { getAllInstanceInfo } from "@antivivi/vrldk";
import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import MagicalCraftingTable from "shared/items/0/millisecondless/MagicalCraftingTable";
import Jade from "shared/items/excavation/Jade";
import Quartz from "shared/items/excavation/Quartz";

export = new Item(script.Name)
    .setName("Shrinkflow Conveyor")
    .setDescription("Shrinks your droplets to a smaller size, but lowers its value by x0.9 on ALL currencies.")
    .setDifficulty(Difficulty.Vibeness)
    .setPrice(new CurrencyBundle().set("Dark Matter", 1e27), 1)
    .setRequiredItemAmount(Jade, 1)
    .setRequiredItemAmount(Quartz, 1)
    .setCreator("superGirlygamer8o")
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(MagicalCraftingTable)
    .persists()

    .trait(Conveyor)
    .setSpeed(5)

    .trait(Upgrader)
    .setMul(CurrencyBundle.ones().mulConstant(0.9))
    .exit()

    .onLoad((model) => {
        const modelInfo = getAllInstanceInfo(model);

        const onUpgraded = modelInfo.upgraderTriggered;
        if (onUpgraded === undefined)
            throw `Tried to load Shrinkflow Conveyor on model without OnUpgraded event: ${model.GetFullName()}`;

        onUpgraded.connect((droplet) => {
            droplet.Size = droplet.Size.mul(0.75);
        });
    });


import Difficulty from "@rbxts/ejt";
import { OnoeNum } from "@rbxts/serikanum";
import { Server } from "shared/api/APIExpose";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Formula from "shared/currency/Formula";
import Item from "shared/item/Item";
import Generator from "shared/item/traits/generator/Generator";
import Class0Shop from "shared/items/0/Class0Shop";

const amt = new OnoeNum(100e12);
const base = new CurrencyBundle().set("Power", amt);

export = new Item(script.Name)
    .setName("Timelost Desert")
    .setDescription(
        "The hands of time are frozen for you, allowing you to produce unparalled amounts of Power. Produces %gain%, this amount increasing with Skill and Total Playtime.",
    )
    .setDifficulty(Difficulty.Vibeness)
    .setPrice(new CurrencyBundle().set("Skill", 4000000), 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)
    .setCreator("CoPKaDT")

    .setFormula(new Formula().pow(0.25))
    .setFormulaX("(skill * time)")

    .trait(Generator)
    .setPassiveGain(base)
    .applyFormula(
        (v, item) => {
            return item.setPassiveGain(base.set("Power", amt.mul(v)));
        },
        () => Server.Currency.get("Skill").mul(Server.empireData.playtime),
    )

    .exit();


import Difficulty from "@rbxts/ejt";
import Charger from "shared/item/traits/generator/Charger";
import Item from "shared/item/Item";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Vibe Pillar")
    .setDescription("Uses the power of vibes to charge tesseracts in a 10 stud radius by %mul%.")
    .setDifficulty(Difficulty.Vibeness)
    .setPrice(new CurrencyBundle().set("Funds", 100e39).set("Skill", 12000000), 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)
    .setCreator("emoronq2k")

    .trait(Charger)
    .setMul(new CurrencyBundle().set("Dark Matter", 2))
    .setRadius(10)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Damager from "shared/item/traits/upgrader/Damager";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Vibrant Disco")
    .setDescription("Let your droplets groove to the beat as they get healed by %hp_add%!")
    .setDifficulty(Difficulty.Vibeness)
    .setPrice(new CurrencyBundle().set("Funds", 142.5e42).set("Bitcoin", 250e9), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class0Shop)
    .setCreator("sanjay2133")
    .persists()

    .trait(Upgrader)

    .trait(Damager)
    .setDamage(-40)

    .trait(Conveyor)
    .setSpeed(3)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Generator from "shared/item/traits/generator/Generator";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Advanced Tesseract")
    .setDescription(
        "Apparently taps into the fifth dimension to produce %gain%. Don't let that smile deceive you, it has connections with the underworld.",
    )
    .setDifficulty(Difficulty.Vintage)
    .setPrice(new CurrencyBundle().set("Funds", 600e27).set("Skill", 35), 1)
    .setPrice(new CurrencyBundle().set("Funds", 1.2e30).set("Skill", 35), 2)
    .setPrice(new CurrencyBundle().set("Funds", 2.4e30).set("Skill", 35), 3)
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)

    .trait(Generator)
    .setPassiveGain(new CurrencyBundle().set("Dark Matter", 2507331))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Generator from "shared/item/traits/generator/Generator";
import DropperBooster from "shared/item/traits/boost/DropperBooster";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Canistering Generator")
    .setDescription(
        "Boosts the drop rate of any dropper adjacent to the canister's vent by 2.5 times! Also produces %gain%.",
    )
    .setDifficulty(Difficulty.Vintage)
    .setPrice(new CurrencyBundle().set("Power", 200e15).set("Bitcoin", 76000), 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Generator)
    .setPassiveGain(new CurrencyBundle().set("Power", 400e6))

    .trait(DropperBooster)
    .setDropRateMul(2.5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Droplet from "shared/item/Droplet";
import Dropper from "shared/item/traits/dropper/Dropper";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Classic Dropper")
    .setDescription("A slightly nostalgic Slamo Village dropper producing %val% droplets per second.")
    .setDifficulty(Difficulty.Vintage)
    .setPrice(new CurrencyBundle().set("Skill", 25), 1)
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)
    .setCreator("emoronq2k")

    .trait(Dropper)
    .setDroplet(Droplet.ClassicDroplet)
    .setDropRate(0.5)

    .exit();


//!native
//!optimize 2
import { buildRichText, formatRichText, getAllInstanceInfo } from "@antivivi/vrldk";
import Difficulty from "@rbxts/ejt";
import { packet } from "@rbxts/fletchette";
import { OnoeNum } from "@rbxts/serikanum";
import StringBuilder from "@rbxts/stringbuilder";
import { Server } from "shared/api/APIExpose";
import { IS_EDIT } from "shared/Context";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import { CURRENCY_CATEGORIES, CURRENCY_DETAILS } from "shared/currency/CurrencyDetails";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import perItemPacket from "shared/item/utils/perItemPacket";
import Class0Shop from "shared/items/0/Class0Shop";

declare global {
    interface InstanceInfo {
        /**
         * The last scanned droplet text output (only populated in edit mode for testing).
         */
        scannerOutput?: string;
    }
}

const textChangedPacket =
    perItemPacket(packet<(placementId: string, dropletId: string, value: string, color: string) => void>());

const ALL_CURRENCIES_COLOR = new Color3(0.3, 0.37, 1);
const ZERO = new OnoeNum(0);
const ONE = new OnoeNum(1);

function isNeutralValue(constant: OnoeNum, operation: "add" | "mul" | "pow") {
    switch (operation) {
        case "add":
            return constant.equals(ZERO);
        case "mul":
        case "pow":
            return constant.equals(ONE);
    }
}

function getOperationString(constant: OnoeNum, operation: "add" | "mul" | "pow", inverse: boolean) {
    switch (operation) {
        case "add":
            if (inverse) {
                constant = constant.unary();
            }
            if (constant.moreThan(0)) {
                return $tuple("+", constant);
            } else if (constant.lessThan(0)) {
                return $tuple("-", constant.abs());
            }
            return $tuple("", constant.abs());
        case "mul":
            if (constant.moreThan(1)) {
                if (inverse) {
                    return $tuple("÷", constant);
                }
                return $tuple("x", constant);
            } else if (constant.lessThan(1)) {
                if (inverse) {
                    return $tuple("x", constant.reciprocal());
                }
                return $tuple("÷", constant.reciprocal());
            }
            return $tuple("", constant);
        case "pow":
            if (constant.moreThan(1)) {
                if (inverse) {
                    return $tuple("√", constant);
                }
                return $tuple("^", constant);
            } else if (constant.lessThan(1)) {
                if (inverse) {
                    return $tuple("^", constant.reciprocal());
                }
                return $tuple("√", constant.reciprocal());
            }
            return $tuple("", constant);
    }
}

function valueToString(
    builder: StringBuilder,
    constant: OnoeNum | CurrencyBundle,
    operation: "add" | "mul" | "pow",
    inverse: boolean,
) {
    if ("mantissa" in constant) {
        if (isNeutralValue(constant, operation)) return false;
        const [opString, opValue] = getOperationString(constant, operation, inverse);
        buildRichText(builder, opString + opValue.toString(), ALL_CURRENCIES_COLOR, undefined, "Bold");
        return true;
    }

    return currenciesToString(builder, constant.amountPerCurrency, operation, inverse);
}

function currenciesToString(
    builder: StringBuilder,
    amountPerCurrency: CurrencyMap,
    operation: "add" | "mul" | "pow",
    inverse: boolean,
) {
    let hasAnyValues = false;
    const entries = new Array<{ name: Currency; details: CurrencyDetails; amount: OnoeNum }>();

    for (const [name, details] of CurrencyBundle.SORTED_DETAILS) {
        if (details.page === CURRENCY_CATEGORIES.Internal) continue;

        let amount = amountPerCurrency.get(name);
        if (amount === undefined || isNeutralValue(amount, operation)) continue;

        entries.push({ name, details, amount });
        hasAnyValues = true;
    }

    if (!hasAnyValues) return false;

    for (let i = 0; i < entries.size(); i++) {
        const { name, details, amount } = entries[i];
        const [opString, opValue] = getOperationString(amount, operation, inverse);

        buildRichText(builder, opString + CurrencyBundle.getFormatted(name, opValue), details.color, undefined, "Bold");

        if (i < entries.size() - 1) {
            builder.append(i === entries.size() - 2 ? " and " : ", ");
        }
    }

    return true;
}

export = new Item(script.Name)
    .setName("Droplet Scanner")
    .setDescription(
        "Outputs the value of droplets passing through the scanner, showing the details of each upgrade it has received.",
    )
    .setDifficulty(Difficulty.Vintage)
    .setPrice(new CurrencyBundle().set("Power", 1e18).set("Bitcoin", 10000), 1, 5)
    .placeableEverywhere()
    .soldAt(Class0Shop)
    .persists()

    .trait(Upgrader)
    .exit()

    .onLoad((model, item) => {
        const modelInfo = getAllInstanceInfo(model);

        const onUpgraded = modelInfo.upgraderTriggered;
        if (onUpgraded === undefined)
            throw `Tried to load Droplet Scanner on model without OnUpgraded event: ${model.GetFullName()}`;

        onUpgraded.connect((dropletModel) => {
            const dropletValue = Server.Revenue.calculateDropletValue(dropletModel, true);
            dropletValue.applyFinal();
            dropletValue.applySource();

            const builder = new StringBuilder();
            builder.append("RAW WORTH: ").append(dropletValue.baseValue.toString(true));

            for (const [name, operative] of dropletValue.factors) {
                const inverse = operative.inverse === true;
                let hasAnyContent = false;
                const contentBuilder = new StringBuilder();

                if (operative.add !== undefined) {
                    if (valueToString(contentBuilder, operative.add, "add", inverse)) {
                        hasAnyContent = true;
                    }
                }

                if (operative.mul !== undefined) {
                    if (hasAnyContent) contentBuilder.append(" ");
                    if (valueToString(contentBuilder, operative.mul, "mul", inverse)) {
                        hasAnyContent = true;
                    }
                }

                if (operative.pow !== undefined) {
                    if (hasAnyContent) contentBuilder.append(" ");
                    if (valueToString(contentBuilder, operative.pow, "pow", inverse)) {
                        hasAnyContent = true;
                    }
                }

                if (hasAnyContent) {
                    builder.append("\n").append(name.upper()).append(": ").append(contentBuilder.toString());
                }
            }

            const dropletModelInfo = getAllInstanceInfo(dropletModel);
            const health = dropletModelInfo.health;
            if (health !== 100 && health !== undefined) {
                builder
                    .append("\nHEALTH: ")
                    .append(formatRichText(OnoeNum.toString(health), CURRENCY_DETAILS.Health.color));
            }

            builder.append("\nTOTAL: ").append(dropletValue.coalesce().toString(true));

            const outputText = builder.toString();

            // Expose output in edit mode for testing
            if (IS_EDIT) {
                modelInfo.scannerOutput = outputText;
            }

            textChangedPacket.toAllClients(
                model,
                dropletValue.instanceInfo.dropletId!,
                outputText,
                dropletModel.Color.Lerp(new Color3(1, 1, 1), 0.2).ToHex(),
            );
        });
    })
    .onClientLoad((model) => {
        const titleLabel = model
            .WaitForChild("TitlePart")
            .WaitForChild("SurfaceGui")
            .WaitForChild("TextLabel") as TextLabel;
        const valueLabel = model
            .WaitForChild("ValuePart")
            .WaitForChild("SurfaceGui")
            .WaitForChild("ScrollingFrame")
            .WaitForChild("TextLabel") as TextLabel;
        let titleText = "NOTHING READ";
        let valueText = "NO WORTH";
        titleLabel.Text = titleText;
        valueLabel.Text = valueText;

        textChangedPacket.fromServer(model, (dropletId, value, color) => {
            titleText = `LAST READ:\n<font color="#${color}">${dropletId.upper()}</font>`;
            valueText = value;
            if (titleLabel !== undefined) titleLabel.Text = titleText;
            if (valueLabel !== undefined) valueLabel.Text = valueText;
        });
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Droplet from "shared/item/Droplet";
import Dropper from "shared/item/traits/dropper/Dropper";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Lunary Dropper")
    .setDescription(
        "You need some Funds. Producing %val% droplets every 2 seconds, it's unclear how this ancient dropper is still in such good condition.",
    )
    .setDifficulty(Difficulty.Vintage)
    .setPrice(new CurrencyBundle().set("Funds", 44.4e27).set("Skill", 2), 1)
    .setPrice(new CurrencyBundle().set("Funds", 72.7e27).set("Skill", 4), 2)
    .setPrice(new CurrencyBundle().set("Funds", 444e27).set("Skill", 8), 3)
    .setPrice(new CurrencyBundle().set("Funds", 727e27).set("Skill", 16), 4)
    .setPrice(new CurrencyBundle().set("Funds", 4.44e30).set("Skill", 32), 5)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Dropper)
    .setDroplet(Droplet.LunaryDroplet)
    .setDropRate(0.5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Damager from "shared/item/traits/upgrader/Damager";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("memories...")
    .setDescription("Feels so oddly familiar to you, it gives you the shivers. .. ...restores %hp_add% to droplets.")
    .setDifficulty(Difficulty.Vintage)
    .setPrice(new CurrencyBundle().set("Funds", 400e27), 1)
    .setPrice(new CurrencyBundle().set("Funds", 4e30), 2)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class0Shop)
    .setCreator("CoPKaDT")

    .trait(Upgrader)

    .trait(Damager)
    .setDamage(-25)

    .trait(Conveyor)
    .setSpeed(2)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Damager from "shared/item/traits/upgrader/Damager";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Smiling Killer")
    .setDescription("The smile holds no remorse. Deals %hp_add% to droplets, but gives a %mul% boost.")
    .setDifficulty(Difficulty.Vintage)
    .setPrice(new CurrencyBundle().set("Funds", 100e27).set("Skill", 6).set("Bitcoin", 40000), 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Funds", 1.6).set("Power", 1.8).set("Bitcoin", 1.35).set("Skill", 1.6))

    .trait(Damager)
    .setDamage(55)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Droplet from "shared/item/Droplet";
import Dropper from "shared/item/traits/dropper/Dropper";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Advanced Skill Factory")
    .setDescription("Alright, it's time to actually pick up the pace. Produce %val% droplets every 2 seconds.")
    .setDifficulty(Difficulty.Walkthrough)
    .setPrice(new CurrencyBundle().set("Funds", 22.5e33).set("Skill", 70), 1)
    .setPrice(new CurrencyBundle().set("Funds", 135e33).set("Skill", 200), 2)
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)

    .trait(Dropper)
    .setDroplet(Droplet.SkillerDroplet)
    .setDropRate(0.5)

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Formula from "shared/currency/Formula";
import { Server } from "shared/api/APIExpose";
import Class0Shop from "shared/items/0/Class0Shop";

const mul = new CurrencyBundle().set("Funds", 0);

export = new Item(script.Name)
    .setName("Funds Accelerator")
    .setDescription("Progress is slow? No longer. Boosts Funds gain, with that multiplier increasing by Funds.")
    .setDifficulty(Difficulty.Walkthrough)
    .setPrice(new CurrencyBundle().set("Funds", 450e33).set("Skill", 1200), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class0Shop)
    .persists("Skillification")

    .setFormula(new Formula().div(1e30).add(1).pow(0.1))
    .setFormulaX("funds")

    .trait(Upgrader)
    .applyFormula(
        (v, item) => item.setMul(mul.set("Funds", v)),
        () => Server.Currency.get("Funds"),
    )

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import InstantiationDelimiter from "shared/item/traits/InstantiationDelimiter";
import Item from "shared/item/Item";
import InstantiationDelimiterIII from "shared/items/negative/skip/InstantiationDelimiterIII";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Instantiation Delimiter IV")
    .setDescription("The final Barren Islands delimiter. Increases droplet limit by 80. Does not drain.")
    .setDifficulty(Difficulty.Walkthrough)
    .setPrice(new CurrencyBundle().set("Power", 800e18).set("Skill", 1500), 1)
    .setRequiredItemAmount(InstantiationDelimiterIII, 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(InstantiationDelimiter)
    .setDropletIncrease(80)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import LaserFan from "shared/item/traits/other/LaserFan";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Laser Turbine")
    .setDescription(
        `We heard you missed your old Laser Fans, so here's an "upgraded" model! Each fan blade gives %mul% compounding but can only hit droplets on raised conveyors.`,
    )
    .setDifficulty(Difficulty.Walkthrough)
    .setPrice(new CurrencyBundle().set("Funds", 100e33), 1)
    .setPrice(new CurrencyBundle().set("Funds", 300e33), 2)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)
    .setCreator("simple13579")

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Funds", 1.2))

    .trait(LaserFan)
    .setSpeed(5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Formula from "shared/currency/Formula";
import Item from "shared/item/Item";
import { Server } from "shared/api/APIExpose";
import Furnace from "shared/item/traits/Furnace";
import FormulaBundled from "shared/item/traits/FormulaBundled";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Robotic Cauldron")
    .setDescription(
        `When Move-Your-Droplets™ tried branching out from producing conveyors, they experimented with all sorts of different machinery.
Their final creation before going back to their ways was this abomination of a cauldron on legs.
Scales with Power, maxing out at %cap%. Also provides a flat %flat% boost.`,
    )
    .setDifficulty(Difficulty.Walkthrough)
    .setPrice(new CurrencyBundle().set("Funds", 1.5e36).set("Power", 6e18), 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .setFormula(new Formula().add(1).log(5).mul(840).add(500))
    .setFormulaX("power")
    .setFormulaXCap(new CurrencyBundle().set("Power", 10e24))

    .trait(FormulaBundled)
    .setRatio("Power", 1)
    .setRatio("Funds", 1200)
    .setFlat("Skill", 5)
    .setX(() => Server.Currency.get("Power"))
    .apply(Furnace)
    .setIsCauldron(true)

    .exit();


import { getAllInstanceInfo } from "@antivivi/vrldk";
import Difficulty from "@rbxts/ejt";
import { Lighting } from "@rbxts/services";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Droplet from "shared/item/Droplet";
import Item from "shared/item/Item";
import Boostable from "shared/item/traits/boost/Boostable";
import Dropper from "shared/item/traits/dropper/Dropper";
import MagicalCraftingTable from "shared/items/0/millisecondless/MagicalCraftingTable";

export = new Item(script.Name)
    .setName("Solar Powered Dropper")
    .setDescription("Produces %val% droplets every 2 seconds, but has increased drop rate in the day!")
    .setDifficulty(Difficulty.Walkthrough)
    .setPrice(new CurrencyBundle().set("Funds", 1e33).set("Skill", 45), 1)
    .setCreator("superGirlygamer8o")
    .addPlaceableArea("BarrenIslands")
    .soldAt(MagicalCraftingTable)
    .persists()

    .trait(Dropper)
    .setDroplet(Droplet.SolarDroplet)
    .setDropRate(0.5)
    .exit()

    .onLoad((model, item) => {
        const drop = model.WaitForChild("Drop");
        const instanceInfo = getAllInstanceInfo(drop);
        const modifier: ItemBoost = {
            ignoresLimitations: false,
            dropRateMul: 1, // Default multiplier
        };
        Boostable.addBoost(instanceInfo, "Solar", modifier);
        item.repeat(
            model,
            () => {
                modifier.dropRateMul = (12 - math.abs(Lighting.ClockTime - 12)) / 6 + 1;
            },
            1,
        );
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Damager from "shared/item/traits/upgrader/Damager";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item("AdvancedHealthPack")
    .setName("Advanced Health Pack")
    .setDescription("Looks extremely similar to a Basic Health Pack, yet twice as potent, giving droplets %hp_add%.")
    .setDifficulty(Difficulty.Win)
    .setPrice(new CurrencyBundle().set("Funds", 12.51e24), 1)
    .setPrice(new CurrencyBundle().set("Funds", 24.51e24), 2)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Upgrader)

    .trait(Damager)
    .setDamage(-100)

    .trait(Conveyor)
    .setSpeed(2)

    .exit();


import Difficulty from "@rbxts/ejt";
import { OnoeNum } from "@rbxts/serikanum";
import { packet, property } from "@rbxts/fletchette";
import { Server } from "shared/api/APIExpose";
import { playSound } from "shared/asset/GameAssets";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import { CURRENCY_DETAILS } from "shared/currency/CurrencyDetails";
import Droplet from "shared/item/Droplet";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import setDropletVelocity from "shared/item/utils/setDropletVelocity";
import perItemPacket from "shared/item/utils/perItemPacket";
import { VirtualCollision } from "shared/item/utils/VirtualReplication";
import Class0Shop from "shared/items/0/Class0Shop";

declare global {
    interface PlacedItem {
        currency?: Currency;
    }
}

const clickedPacket = perItemPacket(packet<(placementId: string) => void>());
const modePacket = property<Currency>();
const getSortingPoint = (model: Model) => model.WaitForChild("SortingPoint") as BasePart;

export = new Item(script.Name)
    .setName("Currency Strict Conveyor")
    .setDescription(
        "A conveyor that sorts droplets based on their currency. It has two outputs: one for the selected currency and another for all other currencies. Click the button to change the selected currency.",
    )
    .setDifficulty(Difficulty.Win)
    .setPrice(new CurrencyBundle().set("Power", 5e12), 1, 5)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class0Shop)

    .trait(Conveyor)
    .setSpeed(5)
    .exit()

    .onLoad((model) => {
        const forward = model.GetPivot().LookVector.Unit;

        const placedItem = Server.Item.getPlacedItem(model.Name)!;
        placedItem.currency ??= "Funds";
        const modes = ["Funds", "Power", "Bitcoin", "Skill"] as Currency[];
        modePacket.set(placedItem.currency);

        clickedPacket.fromClient(model, (player) => {
            if (!Server.Permissions.hasPermission(player, "build")) return;

            let currentIndex = 0;
            for (let i = 0; i < modes.size(); i++) {
                if (modes[i] === placedItem.currency) {
                    currentIndex = i;
                    break;
                }
            }
            const nextIndex = (currentIndex + 1) % modes.size();
            const currency = modes[nextIndex];
            placedItem.currency = currency;
            modePacket.set(currency);
            clickedPacket.toAllClients(model);
        });

        const touched = new Set<BasePart>();

        VirtualCollision.onDropletTouched(model, getSortingPoint(model), (part, instanceInfo) => {
            if (instanceInfo.dropletId === undefined || touched.has(part)) return;
            const droplet = Droplet.getDroplet(instanceInfo.dropletId);
            if (droplet === undefined) throw "Unknown droplet ID: " + instanceInfo.dropletId;

            touched.add(part);
            task.delay(0.5, () => touched.delete(part));

            const value = droplet.value;
            let bestCurrency: Currency | undefined;
            let bestAmount: OnoeNum | undefined;
            for (const [currency, amount] of value.amountPerCurrency) {
                if (bestAmount === undefined || amount.moreThan(bestAmount)) {
                    bestCurrency = currency;
                    bestAmount = amount;
                }
            }

            if (bestCurrency !== placedItem.currency) return;

            setDropletVelocity(part, forward.mul(part.Mass).mul(40));
        });
    })
    .onClientLoad((model) => {
        const modeButton = model.WaitForChild("Mode") as BasePart;
        (modeButton.WaitForChild("ClickDetector") as ClickDetector).MouseClick.Connect(() => {
            clickedPacket.toServer(model);
        });

        modePacket.observe((currency) => {
            modeButton.Color = CURRENCY_DETAILS[currency].color;
        });

        clickedPacket.fromServer(model, () => {
            playSound("SwitchFlick.mp3", modeButton);
        });
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Damager from "shared/item/traits/upgrader/Damager";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Efficient Killing Upgrader")
    .setDescription("Small yet deadly. Does %hp_add% to droplets, but boosts Funds and Power by 1.95x.")
    .setDifficulty(Difficulty.Win)
    .setPrice(new CurrencyBundle().set("Funds", 3.85e24), 1)
    .setPrice(new CurrencyBundle().set("Funds", 5.81e24), 2)
    .setPrice(new CurrencyBundle().set("Funds", 8.63e24), 3)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Funds", 1.95).set("Power", 1.95))

    .trait(Damager)
    .setDamage(35)

    .trait(Conveyor)
    .setSpeed(5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Droplet from "shared/item/Droplet";
import Dropper from "shared/item/traits/dropper/Dropper";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Hydrating Dropper")
    .setDescription("Produces %val% droplets every 2 seconds, with droplets having %health%.")
    .setDifficulty(Difficulty.Win)
    .setPrice(new CurrencyBundle().set("Power", 70e12), 1)
    .setPrice(new CurrencyBundle().set("Power", 130e12), 2)
    .setPrice(new CurrencyBundle().set("Power", 210e12), 3)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Dropper)
    .setDroplet(Droplet.HydratingDroplet)
    .setDropRate(0.5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Generator from "shared/item/traits/generator/Generator";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Improved Tesseract")
    .setDescription("Just a tesseract doing its tesseract things for %gain%. Don't mind it, please.")
    .setDifficulty(Difficulty.Win)
    .setPrice(new CurrencyBundle().set("Skill", 4), 1)
    .setPrice(new CurrencyBundle().set("Skill", 10), 2)
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)

    .trait(Generator)
    .setPassiveGain(new CurrencyBundle().set("Dark Matter", 96))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Inclined Refiner")
    .setDescription("Inclines up then down. %add% to droplets passing through this upgrader in Slamo Village.")
    .setDifficulty(Difficulty.Win)
    .setPrice(new CurrencyBundle().set("Funds", 4.1e24).set("Skill", 1), 1)
    .setCreator("MHPlayer12")
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)

    .trait(Upgrader)
    .setAdd(new CurrencyBundle().set("Funds", 1000))

    .trait(Conveyor)
    .setSpeed(5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import MagicalCraftingTable from "shared/items/0/millisecondless/MagicalCraftingTable";
import Crystal from "shared/items/excavation/Crystal";
import Iron from "shared/items/excavation/Iron";

export = new Item(script.Name)
    .setName("Overhead Upgrader")
    .setDescription("Why would you craft something so weirdly shaped? Who knows. %mul% value to droplets.")
    .setDifficulty(Difficulty.Win)
    .setPrice(new CurrencyBundle().set("Skill", 6), 1)
    .setPrice(new CurrencyBundle().set("Skill", 270), 2)
    .setRequiredItemAmount(Crystal, 15)
    .setRequiredItemAmount(Iron, 3)
    .setCreator("filipthesuperstar")
    .addPlaceableArea("SlamoVillage")
    .soldAt(MagicalCraftingTable)
    .persists()

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Skill", 2))

    .trait(Conveyor)
    .setSpeed(5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Droplet from "shared/item/Droplet";
import Dropper from "shared/item/traits/dropper/Dropper";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Coin Miner")
    .setDescription("Start producing Bitcoin with %val% droplets per second.")
    .setDifficulty(Difficulty.Winsome)
    .setPrice(new CurrencyBundle().set("Funds", 20e24).set("Power", 305e12), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class0Shop)
    .persists("Skillification")

    .trait(Dropper)
    .setDroplet(Droplet.BasicCoin)
    .setDropRate(1)

    .exit();


import { loadAnimation } from "@antivivi/vrldk";
import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Clicker from "shared/item/traits/action/Clicker";
import Boostable from "shared/item/traits/boost/Boostable";
import Generator from "shared/item/traits/generator/Generator";
import MagicalCraftingTable from "shared/items/0/millisecondless/MagicalCraftingTable";
import WinsomeCoagulate from "shared/items/0/winsome/WinsomeCoagulate";

export = new Item(script.Name)
    .setName("Friend Clicker")
    .setDescription("Your friend is here to help! Place in front of your structure for %cps%.")
    .setDifficulty(Difficulty.Winsome)
    .setPrice(new CurrencyBundle().set("Purifier Clicks", 1000), 1)
    .setPrice(new CurrencyBundle().set("Purifier Clicks", 3000), 2)
    .setRequiredItemAmount(WinsomeCoagulate, 5)
    .addPlaceableArea("BarrenIslands")
    .soldAt(MagicalCraftingTable)
    .persists()

    .trait(Clicker)
    .setClickRate(1)
    .setClickValue(1000)
    .replicateClicks()

    .trait(Boostable)
    .trait(Generator)
    .exit()

    .onClientLoad((model, item) => {
        const friend = model.WaitForChild("Friend") as Model;
        const animationController = friend.FindFirstChildOfClass("AnimationController");
        if (animationController === undefined) return;
        const animTrack = loadAnimation(animationController, 16920778613);
        if (animTrack !== undefined) {
            item.trait(Clicker).fromServerClicked(model, () => animTrack.Play());
        }
    });


import Difficulty from "@rbxts/ejt";
import Item from "shared/item/Item";

export = new Item(script.Name)
    .setName("Lost Pendant")
    .setDescription("Located atop a peculiar hill. Seems to have no materialistic value.")
    .setDifficulty(Difficulty.Winsome)
    .persists();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Furnace from "shared/item/traits/Furnace";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Purifying Cauldron")
    .setDescription("A massive %mul% boost. Though, this also costs a pretty massive price.")
    .setDifficulty(Difficulty.Winsome)
    .setPrice(new CurrencyBundle().set("Dark Matter", 36000), 1)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Furnace)
    .setMul(new CurrencyBundle().set("Purifier Clicks", 26))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import { Server } from "shared/api/APIExpose";
import Generator from "shared/item/traits/generator/Generator";
import UpgradeBoard from "shared/item/traits/UpgradeBoard";
import UpgradeBoardI from "shared/items/negative/trueease/UpgradeBoardI";

export = new Item(script.Name)
    .setName("Slamo Board Automater")
    .setDescription(
        "Feel bad? Just remember the numerous war crimes this Slamo has committed in its life. It'll automate Upgrade Board I for you as part of its community service.",
    )
    .setDifficulty(Difficulty.Winsome)
    .setPrice(new CurrencyBundle().set("Power", 400e12).set("Skill", 4), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .persists("Skillification")

    .trait(Generator)
    .setPassiveGain(new CurrencyBundle().set("Dark Matter", 0.1))
    .exit()

    .onLoad((model, item) => {
        const upgrades = UpgradeBoardI.trait(UpgradeBoard).upgrades;

        item.repeat(
            model,
            () => {
                for (const upgrade of upgrades) {
                    Server.NamedUpgrade.buyUpgrade(upgrade.id, undefined, undefined, true);
                }
            },
            0.1,
        );
    });


import Difficulty from "@rbxts/ejt";
import { OnoeNum } from "@rbxts/serikanum";
import { Server } from "shared/api/APIExpose";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Furnace from "shared/item/traits/Furnace";
import Packets from "shared/Packets";
import Class0Shop from "shared/items/0/Class0Shop";

const isMeetsRequirement = (skill: OnoeNum) => skill !== undefined && !skill.lessThan(requirement);
const requirement = new OnoeNum(10);

export = new Item(script.Name)
    .setName("Sub-Hydrating Furnace")
    .setDescription("Processes droplets for x2 Funds value, but is x5 with more than 10 Skill.")
    .setDifficulty(Difficulty.Winsome)
    .setPrice(new CurrencyBundle().set("Skill", 2).set("Funds", 10e24), 1)
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class0Shop)

    .trait(Furnace)
    .exit()

    .onInit((item) => {
        const furnace = item.trait(Furnace);
        const CurrencyService = Server.Currency;
        item.repeat(
            undefined,
            () => {
                const meetsRequirement = isMeetsRequirement(CurrencyService.get("Skill"));
                const mul = new OnoeNum(meetsRequirement ? 5 : 2);
                furnace.setMul(new CurrencyBundle().set("Funds", mul));
            },
            0.5,
        );
    })
    .onClientLoad((model, item) => {
        const children = model.GetChildren();
        const glows = new Array<BasePart>();
        for (const glow of children) {
            if (glow.IsA("BasePart") && glow.Name === "Glow") {
                glows.push(glow);
            }
        }
        item.repeat(model, () => {
            const meetsRequirement = isMeetsRequirement(new OnoeNum(Packets.balance.get().get("Skill") ?? 0));
            for (const glow of glows) {
                glow.Transparency = meetsRequirement ? 0 : 0.5;
            }
        });
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Generator from "shared/item/traits/generator/Generator";
import Item from "shared/item/Item";
import Class0Shop from "shared/items/0/Class0Shop";

export = new Item(script.Name)
    .setName("Transient Tesseract")
    .setDescription("Trying its best to exist. Produces %gain%.")
    .setDifficulty(Difficulty.Winsome)
    .setPrice(new CurrencyBundle().set("Skill", 7), 1, 3)
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class0Shop)

    .trait(Generator)
    .setPassiveGain(new CurrencyBundle().set("Dark Matter", 6496))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Charm from "shared/item/traits/Charm";
import Glass from "shared/items/0/millisecondless/Glass";
import MagicalCraftingTable from "shared/items/0/millisecondless/MagicalCraftingTable";
import WinsomeCoagulate from "shared/items/0/winsome/WinsomeCoagulate";
import EnchantedGrass from "shared/items/negative/tlg/EnchantedGrass";

export = new Item(script.Name)
    .setName("Winsome Charm")
    .setDescription(
        "If you're ever feeling down, just know that Winsome is here for you. +3% chance to inflict critical hits with tools.",
    )
    .setDifficulty(Difficulty.Winsome)
    .setPrice(new CurrencyBundle().set("Funds", 1), 1)
    .setRequiredItemAmount(WinsomeCoagulate, 2)
    .setRequiredItemAmount(Glass, 1)
    .setRequiredItemAmount(EnchantedGrass, 10)
    .soldAt(MagicalCraftingTable)

    .trait(Charm)
    .setCriticalAdd(3)

    .exit();


import Difficulty from "@rbxts/ejt";
import Item from "shared/item/Item";

export = new Item(script.Name)
    .setName("Winsome Speck")
    .setDescription(
        "A common substance secreted by Slamos while they are asleep. While the Skill level of the average Slamo is generally slightly above Winsome, excess Skill released by this peculiar species usually breaks down into this exact form.",
    )
    .setDifficulty(Difficulty.Winsome)
    .persists();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Shop from "shared/item/traits/Shop";

export = new Item(script.Name)
    .setName("Class 1 Shop")
    .setDescription("Buy your favorite Joyful to Effortlessless items here!")
    .setDifficulty(Difficulty.Joyful)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .setPrice(new CurrencyBundle().set("Wins", 0.1), 1, 5)
    .persists()

    .trait(Shop)
    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Droplet Coaster")
    .setDescription("A roller coaster for droplets. Creates a great trade-off, modifying droplets by %mul%.")
    .setDifficulty(Difficulty.Coasterifying)
    .setPrice(new CurrencyBundle().set("Power", 1e27), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)
    .setCreator("eeeesdfew")

    .trait(Conveyor)
    .setSpeed(10)

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Power", 3).set("Funds", 0.45))

    .exit();


import Difficulty from "@rbxts/ejt";
import { getAllInstanceInfo } from "@antivivi/vrldk";
import { Players } from "@rbxts/services";
import { IS_EDIT } from "shared/Context";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import { getPlayerCharacter } from "shared/hamster/getPlayerCharacter";
import Droplet from "shared/item/Droplet";
import Item from "shared/item/Item";
import Dropper from "shared/item/traits/dropper/Dropper";
import Massless from "shared/item/traits/status/Massless";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

const AntiGravityDropper = new Item(script.Name)
    .setName("Anti-Gravity Dropper")
    .setDescription(
        "A dropper that defies gravity - its droplets float upward! Drops %val% droplets every 2 seconds when players are jumping or airborne nearby. Manufactured in The Factory™.",
    )
    .setDifficulty(Difficulty.DoSomething)
    .setPrice(new CurrencyBundle().set("Funds", 450), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)
    .setCreator("pog213123")

    .trait(Dropper)
    .setDroplet(Droplet.BalloonDroplet)

    .trait(Upgrader)
    .trait(Massless)
    .exit()

    .onLoad((model, item) => {
        const modelPosition = model.GetPivot().Position;
        const dropInfo = getAllInstanceInfo(model.WaitForChild("Drop"));

        item.repeat(
            model,
            () => {
                let isAirborne = false;

                if (IS_EDIT) {
                    // In edit mode, always allow the dropper to work
                    isAirborne = true;
                } else {
                    for (const player of Players.GetPlayers()) {
                        const character = getPlayerCharacter(player);
                        if (!character || !character.PrimaryPart) continue;

                        const position = character.PrimaryPart.Position;
                        const distance = modelPosition.sub(position).Magnitude;

                        // Check if player is within 50 studs
                        if (distance > 50) continue;

                        const humanoid = character.FindFirstChildOfClass("Humanoid");
                        if (!humanoid) continue;

                        // Check if player is jumping or in the air
                        const state = humanoid.GetState();

                        if (
                            state === Enum.HumanoidStateType.Freefall ||
                            state === Enum.HumanoidStateType.Flying ||
                            state === Enum.HumanoidStateType.Jumping
                        ) {
                            isAirborne = true;
                        }
                    }
                }

                dropInfo.dropRate = isAirborne ? 0.5 : 0; // 0.5 = every 2 seconds
                if (dropInfo.dropRate === 0) {
                    dropInfo.lastDrop = tick(); // Reset timer when no one is airborne
                }
            },
            0.5,
        );
    });

const massless = AntiGravityDropper.trait(Massless);
AntiGravityDropper.trait(Dropper).onDropletProduced((droplet) => massless.decorate(droplet));

export = AntiGravityDropper;


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Furnace from "shared/item/traits/Furnace";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Aquatic Furnace")
    .setDescription(
        `A furnace that only works on low levels.
%mul% value.`,
    )
    .setDifficulty(Difficulty.DoSomething)
    .setPrice(new CurrencyBundle().set("Skill", 400), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class1Shop)
    .setCreator("sanjay2133")

    .trait(Furnace)
    .setMul(new CurrencyBundle().set("Funds", 1000000).set("Power", 10000).set("Skill", 100))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Formula from "shared/currency/Formula";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import ObbyUpgrader from "shared/item/traits/upgrader/ObbyUpgrader";
import NamedUpgrades from "shared/namedupgrade/NamedUpgrades";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Compressed Obby Upgrader")
    .setDescription("A conveyor with a built-in obby that has some pretty cool upgrades if you complete it!")
    .setDifficulty(Difficulty.DoSomething)
    .setPrice(new CurrencyBundle().set("Funds", 5e57), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)
    .setCreator("sanjay2133")

    .trait(Conveyor)
    .setSpeed(5)

    .trait(ObbyUpgrader)
    .setReward(1)
    .setBoost(NamedUpgrades.GreedOfTheObbyI, "Funds", new Formula().mul(0.1).add(1))
    .setBoost(NamedUpgrades.PowerOfTheObbyI, "Power", new Formula().mul(0.1).add(1))
    .setBoost(NamedUpgrades.DecentralityOfTheObbyI, "Bitcoin", new Formula().mul(0.1).add(1))
    .setBoost(NamedUpgrades.MasteryOfTheObbyI, "Skill", new Formula().mul(0.1).add(1))

    .exit();


import Difficulty from "@rbxts/ejt";
import { Workspace } from "@rbxts/services";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import { getAllPlayerCharacters } from "shared/hamster/getPlayerCharacter";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Damager from "shared/item/traits/upgrader/Damager";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Exclamation Refiner")
    .setDescription(
        "This will make you say '!!!' for sure. Droplets passing through the neon part get a %mul% boost. The part deals 25 damage but gives a 2x Power, Funds boost. Standing on the exclamation mark powers up the killbrick: x1.5 damage, x2.5 boost.",
    )
    .setDifficulty(Difficulty.DoSomething)
    .setPrice(new CurrencyBundle().set("Funds", 11e63), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)
    .setCreator("carl.npc")

    .trait(Conveyor)
    .setSpeed(5)

    .trait(Upgrader)
    .trait(Damager)
    .setDamage(25)

    .exit()

    .onLoad((model, item) => {
        const damager = item.trait(Damager);

        // Detect if a player is standing on TouchPart
        const touchPart = model.FindFirstChild("TouchPart") as BasePart | undefined;
        if (!touchPart) return;

        const cframe = touchPart.CFrame.add(new Vector3(0, 4.5, 0));
        const size = touchPart.Size.add(new Vector3(0, 9, 0));
        const overlapParams = new OverlapParams();
        overlapParams.FilterType = Enum.RaycastFilterType.Include;

        let isPowered = false;
        item.repeat(
            model,
            () => {
                const filterDescendantsInstances = new Array<Instance>();
                for (const character of getAllPlayerCharacters()) {
                    filterDescendantsInstances.push(character);
                }
                overlapParams.FilterDescendantsInstances = filterDescendantsInstances;
                const parts = Workspace.GetPartBoundsInBox(cframe, size, overlapParams);
                let found = false;
                for (const inst of filterDescendantsInstances) {
                    const hrp = inst.FindFirstChild("HumanoidRootPart") as BasePart | undefined;
                    if (hrp && parts.includes(hrp)) {
                        found = true;
                        break;
                    }
                }
                isPowered = found;
                // Store state for Upgrader/Damager
                model.SetAttribute("ExclamationPowered", isPowered);
            },
            0.5,
        );

        // Listen for powered state and adjust damage
        const update = () => {
            const powered = model.GetAttribute("ExclamationPowered") as boolean | undefined;
            damager.setDamage(powered ? 25 * 1.5 : 25);
        };
        model.GetAttributeChangedSignal("ExclamationPowered").Connect(update);
        update();
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import FormulaBundled from "shared/item/traits/FormulaBundled";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";
import EffervescentDropletSpray from "shared/items/negative/exist/EffervescentDropletSpray";

export = new Item(script.Name)
    .setName("Industrial Droplet Spray")
    .setDescription(
        "The sequel to the Effervescent Droplet Spray, this spray provides the same boost but has a much higher cap.",
    )
    .setDifficulty(Difficulty.DoSomething)
    .setPrice(new CurrencyBundle().set("Purifier Clicks", 2500), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)
    .setCreator("shooerThe")

    .setFormula(EffervescentDropletSpray.formula!)
    .setFormulaX(EffervescentDropletSpray.formulaX!)
    .setFormulaXCap(EffervescentDropletSpray.formulaXCap!.powConstant(2))

    .trait(Conveyor)
    .setSpeed(5)

    .trait(FormulaBundled)
    .setRatios(EffervescentDropletSpray.trait(FormulaBundled).ratio!)
    .setX(EffervescentDropletSpray.trait(FormulaBundled).x!)
    .apply(Upgrader)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Generator from "shared/item/traits/generator/Generator";
import Bismuth from "shared/items/excavation/Bismuth";
import Crystal from "shared/items/excavation/Crystal";
import Diamond from "shared/items/excavation/Diamond";
import Emerald from "shared/items/excavation/Emerald";
import Gold from "shared/items/excavation/Gold";
import Ion from "shared/items/excavation/Ion";
import Jade from "shared/items/excavation/Jade";
import Obsidian from "shared/items/excavation/Obsidian";
import Ruby from "shared/items/excavation/Ruby";
import Sapphire from "shared/items/excavation/Sapphire";
import Starlight from "shared/items/excavation/Starlight";
import Uranium from "shared/items/excavation/Uranium";

export = new Item(script.Name)
    .setName("Iridiscent Tesseract")
    .setDescription("A singular tesseract of empyrean composition. Activates matter unknown to mortals.")
    .setDifficulty(Difficulty.DoSomething)
    .setPrice(new CurrencyBundle().set("Wins", 1), 1)
    .setRequiredItemAmount(Crystal, 100)
    .setRequiredItemAmount(Gold, 100)
    .setRequiredItemAmount(Jade, 75)
    .setRequiredItemAmount(Obsidian, 75)
    .setRequiredItemAmount(Ruby, 50)
    .setRequiredItemAmount(Emerald, 25)
    .setRequiredItemAmount(Sapphire, 25)
    .setRequiredItemAmount(Diamond, 10)
    .setRequiredItemAmount(Starlight, 10)
    .setRequiredItemAmount(Ion, 10)
    .setRequiredItemAmount(Uranium, 5)
    .setRequiredItemAmount(Bismuth, 1)
    .setCreator("sanjay2133")
    .persists()

    .trait(Generator)
    .setPassiveGain(new CurrencyBundle().set("Skill", 10).set("Dark Matter", 20))

    .exit();


import Difficulty from "@rbxts/ejt";
import { getAllInstanceInfo } from "@antivivi/vrldk";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import { getAllPlayerCharacters } from "shared/hamster/getPlayerCharacter";
import Droplet from "shared/item/Droplet";
import Item from "shared/item/Item";
import Dropper from "shared/item/traits/dropper/Dropper";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Movement Detection Dropper")
    .setDescription("Drops %val% droplets every 2 seconds as long as you are moving near it.")
    .setDifficulty(Difficulty.DoSomething)
    .setPrice(new CurrencyBundle().set("Funds", 400), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)
    .setCreator("BeeBoun")

    .trait(Dropper)
    .setDroplet(Droplet.MovementDroplet)

    .exit()

    .onLoad((model, item) => {
        const modelPosition = model.GetPivot().Position;
        const dropInfo = getAllInstanceInfo(model.WaitForChild("Drop"));

        const lastPositions = new Map<Model, Vector3>();
        item.repeat(
            model,
            () => {
                let moving = false;

                for (const character of getAllPlayerCharacters()) {
                    if (!character) continue;

                    const position = character.GetPivot().Position;
                    if (modelPosition.sub(position).Magnitude > 50) continue;

                    const lastPosition = lastPositions.get(character);
                    // Check for significant movement (more than 2 studs)
                    if (!lastPosition || position.sub(lastPosition).Magnitude > 2) {
                        moving = true;
                        lastPositions.set(character, position);
                    }
                }

                for (const [character] of lastPositions) {
                    if (character === undefined || character.Parent === undefined) {
                        lastPositions.delete(character);
                        continue;
                    }
                }

                dropInfo.dropRate = moving ? 0.5 : 0; // Set drop rate based on movement
                if (dropInfo.dropRate === 0) {
                    dropInfo.lastDrop = tick(); // Make them wait the full 2 seconds
                }
            },
            0.5,
        );
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Furnace from "shared/item/traits/Furnace";
import Item from "shared/item/Item";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Silent Memory")
    .setDescription("The price you pay for a basic furnace placeable in Sky Pavilion.")
    .setDifficulty(Difficulty.DoSomething)
    .setPrice(new CurrencyBundle().set("Funds", 200e45), 1)
    .addPlaceableArea("SkyPavilion")
    .soldAt(Class1Shop)
    .setCreator("CoPKaDT")

    .trait(Furnace)
    .setMul(new CurrencyBundle().set("Funds", 1))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Fragmental Upgrader")
    .setDescription("Forged from the fragments of all previous progress. Multiplies droplet value by an absurd %mul%.")
    .setDifficulty(Difficulty.Effortlessless)
    .setPrice(new CurrencyBundle().set("Skill", 1e39).set("Bitcoin", 1e54), 1)
    .setCreator("CoPKaDT")
    .addPlaceableArea("SlamoVillage")
    .soldAt(Class1Shop)
    .persists()

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Skill", 10))

    .trait(Conveyor)
    .setSpeed(5)

    .exit();


import Difficulty from "@rbxts/ejt";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Abrupt Bridge")
    .setDescription(
        "A bridge in the sky and a river, cutting off like nothing was ever there. %mul% for droplets passing underneath the bridge.",
    )
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Skill", 230e9), 1)
    .setCreator("CoPKaDT")
    .addPlaceableArea("BarrenIslands", "SkyPavilion")
    .soldAt(Class1Shop)

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Skill", 3))

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Massless from "shared/item/traits/status/Massless";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Anti-Gravity Converter")
    .setDescription(
        "Let your droplets defy gravity with this converter. Don't let them off-track, though, or they might just float away forever. Applies %massless% to droplets, giving a x1.2 boost to ALL currencies.",
    )
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Funds", 20), 1)
    .setPrice(new CurrencyBundle().set("Funds", 20e24), 2)
    .setPrice(new CurrencyBundle().set("Funds", 20e48), 3)
    .setPrice(new CurrencyBundle().set("Funds", 20e72), 4)
    .setPrice(new CurrencyBundle().set("Funds", 20e96), 5)
    .setCreator("sanjay2133")
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)

    .trait(Conveyor)
    .setSpeed(4)

    .trait(Upgrader)
    .trait(Massless)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Anti-Gravity Conveyor")
    .setDescription("A convenient conveyor suspended mid-air. This is Class 1.")
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Funds", 5), 1)
    .setPrice(new CurrencyBundle().set("Funds", 5e24), 2)
    .setPrice(new CurrencyBundle().set("Funds", 5e48), 3)
    .setPrice(new CurrencyBundle().set("Funds", 5e72), 4)
    .setPrice(new CurrencyBundle().set("Funds", 5e96), 5)
    .setCreator("sanjay2133")
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Anti-Gravity Upgrader")
    .setDescription(
        "Place this under an Anti-Gravity Converter for droplets passing through it to be boosted by %mul%.",
    )
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Funds", 1000), 1)
    .setPrice(new CurrencyBundle().set("Funds", 1000e21), 2)
    .setCreator("shooerThe")
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Funds", 3))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Childhood Slide")
    .setDescription(
        "After all these years, you still remember the joy of sliding down a slide. This slide is no different, except it boosts your droplets by %mul%.",
    )
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Skill", 20), 1)
    .setCreator("CoPKaDT")
    .addPlaceableArea("BarrenIslands")
    .soldAt(Class1Shop)

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Funds", 2).set("Skill", 2))

    .trait(Conveyor)
    .setSpeed(7)

    .exit();


import { getAllInstanceInfo } from "@antivivi/vrldk";
import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import setDropletVelocity from "shared/item/utils/setDropletVelocity";
import Class1Shop from "shared/items/1/Class1Shop";
import Quartz from "shared/items/excavation/Quartz";
import MagicalWood from "shared/items/negative/tlg/MagicalWood";

export = new Item(script.Name)
    .setName("Droplet Ascender")
    .setDescription("Moves droplets directly to the sky level.")
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Funds", 60), 1)
    .setPrice(new CurrencyBundle().set("Funds", 60e24), 2)
    .setPrice(new CurrencyBundle().set("Funds", 60e48), 3)
    .setPrice(new CurrencyBundle().set("Funds", 60e72), 4)
    .setPrice(new CurrencyBundle().set("Funds", 60e96), 5)
    .setRequiredItemAmount(Quartz, 1)
    .setRequiredItemAmount(MagicalWood, 20)
    .setCreator("sanjay2133")
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)

    .trait(Conveyor)
    .setSpeed(5)

    .trait(Upgrader)
    .setSky(true)

    .exit()

    .onLoad((model) => {
        const forward = model.GetPivot().LookVector.Unit;
        const modelInfo = getAllInstanceInfo(model);
        const onUpgraded = modelInfo.upgraderTriggered;
        if (onUpgraded === undefined)
            throw `Tried to load Droplet Ascender on model without OnUpgraded event: ${model.GetFullName()}`;

        onUpgraded.connect((droplet) => {
            const baseDirection = forward.mul(12).add(new Vector3(0, 49, 0)).Unit;
            setDropletVelocity(droplet, baseDirection.mul(50));
        });
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import { Grounder } from "shared/item/traits/status/Massless";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Gravity Grounder")
    .setDescription("Brings anti-gravity droplets to the ground, removing the %massless% effect and its buffs.")
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Funds", 500), 1)
    .setPrice(new CurrencyBundle().set("Funds", 500e24), 2)
    .setPrice(new CurrencyBundle().set("Funds", 500e48), 3)
    .setPrice(new CurrencyBundle().set("Funds", 500e72), 4)
    .setPrice(new CurrencyBundle().set("Funds", 500e96), 5)
    .setCreator("sanjay2133")
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)

    .trait(Conveyor)
    .setSpeed(4)

    .trait(Upgrader)
    .trait(Grounder)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Joyful Park")
    .setDescription(
        "Droplets that pass through this enchanting park gain a massive %pow%, %mul% boost. It's time to relax.",
    )
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Wins", 1), 1)
    .setCreator("CoPKaDT")
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)

    .trait(Upgrader)
    .setPow(new CurrencyBundle().set("Funds", 1.02))
    .setMul(
        new CurrencyBundle()
            .set("Funds", 2)
            .set("Power", 3)
            .set("Skill", 4)
            .set("Bitcoin", 6)
            .set("Purifier Clicks", 20),
    )

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Damager from "shared/item/traits/upgrader/Damager";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import MagicalCraftingTable from "shared/items/0/millisecondless/MagicalCraftingTable";
import CorruptedGrass from "shared/items/0/happylike/CorruptedGrass";
import EnchantedGrass from "shared/items/negative/tlg/EnchantedGrass";
import Jade from "shared/items/excavation/Jade";

export = new Item(script.Name)
    .setName("Moss Upgrader")
    .setDescription(`%add% but deals %hp_add% damage to droplets passing through this mossy mess.`)
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Skill", 1), 1)
    .setRequiredItemAmount(EnchantedGrass, 20)
    .setRequiredItemAmount(CorruptedGrass, 5)
    .setRequiredItemAmount(Jade, 1)
    .setCreator("superGirlygamer8o")
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(MagicalCraftingTable)
    .persists()

    .trait(Upgrader)
    .setAdd(new CurrencyBundle().set("Dark Matter", 987654321))

    .trait(Damager)
    .setDamage(80)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import TheAmplifier from "shared/items/0/blessing/TheAmplifier";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("The Amplified")
    .setDescription(
        `Recover all your progress back to The Amplifier, and now obtain a boost as if you had 4 of them.
%mul% boost to droplets.`,
    )
    .setDifficulty(Difficulty.Joyful)
    .setPrice(new CurrencyBundle().set("Skill", 30), 1)
    .setRequiredItemAmount(TheAmplifier, 1)
    .setCreator("butterman_toast")
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class1Shop)

    .trait(Upgrader)
    .setMul(TheAmplifier.trait(Upgrader).mul!.powConstant(4))

    .trait(Conveyor)
    .setSpeed(5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Anti-Gravity Anti-Clockwise Conveyor")
    .setDescription(
        "A fusion of anti-gravity technology and anti-clockwise engineering. Floats mid-air while turning your droplets counter-clockwise.",
    )
    .setDifficulty(Difficulty.Placid)
    .setPrice(new CurrencyBundle().set("Wins", 1), 1, 3)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class1Shop)

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Baseplate")
    .setDescription(
        "Stop wasting time rebuilding everything from scratch. Provides a %mul% boost to droplets passing through.",
    )
    .setDifficulty(Difficulty.Placid)
    .setPrice(new CurrencyBundle().set("Wins", 1), 1, 3)
    .setCreator("CoPKaDT")
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class1Shop)

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Funds", 1.2).set("Power", 1.2).set("Skill", 1.2))

    .trait(Conveyor)
    .setSpeed(4)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import OmniUpgrader from "shared/item/traits/upgrader/OmniUpgrader";

export = new Item(script.Name)
    .setName("Combinative Synthesizer")
    .setDescription(
        "A minimalistic, deceptive upgrader. The boosts? Calculate them yourself, the lasers' colors represent the statistics that they boost. Get out that calculator!",
    )
    .setDifficulty(Difficulty.Placid)
    .setPrice(new CurrencyBundle().set("Skill", 50e12), 1)
    .setCreator("sanjay2133")
    .addPlaceableArea("BarrenIslands")
    .trait(OmniUpgrader)
    .setMuls(
        new Map([
            // Funds lasers
            ["0.5FundsLaser", new CurrencyBundle().set("Funds", 0.5)],
            ["0.75FundsLaser", new CurrencyBundle().set("Funds", 0.75)],
            ["1FundsLaser", new CurrencyBundle().set("Funds", 1)],
            ["1.25FundsLaser", new CurrencyBundle().set("Funds", 1.25)],
            ["1.5FundsLaser", new CurrencyBundle().set("Funds", 1.5)],
            ["1.75FundsLaser", new CurrencyBundle().set("Funds", 1.75)],
            // Bitcoin lasers
            ["0.5BitcoinLaser", new CurrencyBundle().set("Bitcoin", 0.5)],
            ["0.75BitcoinLaser", new CurrencyBundle().set("Bitcoin", 0.75)],
            ["1BitcoinLaser", new CurrencyBundle().set("Bitcoin", 1)],
            ["1.25BitcoinLaser", new CurrencyBundle().set("Bitcoin", 1.25)],
            ["1.75BitcoinLaser", new CurrencyBundle().set("Bitcoin", 1.75)],
            ["2.5BitcoinLaser", new CurrencyBundle().set("Bitcoin", 2.5)],
            // Power lasers
            ["0.25PowerLaser", new CurrencyBundle().set("Power", 0.25)],
            ["0.5PowerLaser", new CurrencyBundle().set("Power", 0.5)],
            ["0.75PowerLaser", new CurrencyBundle().set("Power", 0.75)],
            ["1PowerLaser", new CurrencyBundle().set("Power", 1)],
            ["1.25PowerLaser", new CurrencyBundle().set("Power", 1.25)],
            ["1.5PowerLaser", new CurrencyBundle().set("Power", 1.5)],
            ["1.75PowerLaser", new CurrencyBundle().set("Power", 1.75)],
            ["2.5PowerLaser", new CurrencyBundle().set("Power", 2.5)],
            ["2.75PowerLaser", new CurrencyBundle().set("Power", 2.75)],
            // Skill lasers
            ["0.25SkillLaser", new CurrencyBundle().set("Skill", 0.25)],
            ["0.5SkillLaser", new CurrencyBundle().set("Skill", 0.5)],
            ["0.75SkillLaser", new CurrencyBundle().set("Skill", 0.75)],
            ["1SkillLaser", new CurrencyBundle().set("Skill", 1)],
            ["1.25SkillLaser", new CurrencyBundle().set("Skill", 1.25)],
            ["1.5SkillLaser", new CurrencyBundle().set("Skill", 1.5)],
            ["1.75SkillLaser", new CurrencyBundle().set("Skill", 1.75)],
            ["2SkillLaser", new CurrencyBundle().set("Skill", 2)],
        ]),
    )

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Jade from "shared/items/excavation/Jade";

export = new Item(script.Name)
    .setName("Illuminated Refiner")
    .setDescription(
        "A high-end refiner that uses light to purify materials at an incredible rate. Requires Bitcoin to operate.",
    )
    .setDifficulty(Difficulty.Placid)
    .setPrice(new CurrencyBundle().set("Wins", 0.01))
    .setRequiredItemAmount(Jade, 5)
    .addPlaceableArea("BarrenIslands")
    .setCreator("sanjay2133")
    .persists()

    .trait(Upgrader)
    .setAdd(new CurrencyBundle().set("Bitcoin", 200))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import CorruptedGrass from "shared/items/0/happylike/CorruptedGrass";
import StaleWood from "shared/items/negative/tfd/StaleWood";
import Jade from "shared/items/excavation/Jade";

export = new Item(script.Name)
    .setName("Industrial Underpass")
    .setDescription(
        "The next iteration, naturally. Each laser gives %add%. If you ever actually need this, you're screwed.",
    )
    .setDifficulty(Difficulty.Placid)
    .setPrice(new CurrencyBundle().set("Bitcoin", 1e6))
    .setRequiredItemAmount(StaleWood, 300)
    .setRequiredItemAmount(CorruptedGrass, 1)
    .setRequiredItemAmount(Jade, 5)
    .addPlaceableArea("BarrenIslands")
    .setCreator("simple13579")
    .persists()

    .trait(Upgrader)
    .setAdd(new CurrencyBundle().set("Bitcoin", 200))

    .exit();


import Difficulty from "@rbxts/ejt";
import Item from "shared/item/Item";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Glass from "shared/items/0/millisecondless/Glass";
import Quartz from "shared/items/excavation/Quartz";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Minimal Inverse")
    .setDescription(
        "Maintain placidity. Add %add% to your droplets on this turnaround, while converting them to the elevated level.",
    )
    .setDifficulty(Difficulty.Placid)
    .setPrice(new CurrencyBundle().set("Skill", 1_500_000_000))
    .setCreator("sanjay2133")
    .setRequiredItemAmount(Glass, 10)
    .setRequiredItemAmount(Quartz, 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class1Shop)

    .trait(Upgrader)
    .setAdd(new CurrencyBundle().set("Skill", 0.5))

    .exit();


import Difficulty from "@rbxts/ejt";
import Dropper from "shared/item/traits/dropper/Dropper";
import Item from "shared/item/Item";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Droplet from "shared/item/Droplet";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Placid Dropper")
    .setDescription("The most generic dropper in existence. Produces droplets.")
    .setDifficulty(Difficulty.Placid)
    .setPrice(new CurrencyBundle().set("Wins", 1), 1, 3)
    .setCreator("hisroblcogood")
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class1Shop)

    .trait(Dropper)
    .setDropRate(1)
    .setDroplet(Droplet.PlacidDroplet)

    .exit();


import Difficulty from "@rbxts/ejt";
import { Server } from "shared/api/APIExpose";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Formula from "shared/currency/Formula";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

const mul = new CurrencyBundle();

export = new Item(script.Name)
    .setName("Tesseract Injector")
    .setDescription(
        "An upgrader that uses the energy of Tesseracts, allowing it to boost Bitcoin at an extremely small rate.",
    )
    .setDifficulty(Difficulty.Placid)
    .setPrice(new CurrencyBundle().set("Bitcoin", 100e27))
    .addPlaceableArea("SlamoVillage")
    .setCreator("WelshRedBird")
    .persists("Winification")
    .soldAt(Class1Shop)

    .setFormula(new Formula().pow(0.01))
    .setFormulaX("Dark Matter")
    .setFormulaXCap(new CurrencyBundle().set("Dark Matter", 1e42))

    .trait(Upgrader)
    .applyFormula(
        (v, item) => item.setMul(mul.set("Bitcoin", v)),
        () => Server.Currency.get("Dark Matter"),
    )

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Furnace from "shared/item/traits/Furnace";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Anti-Gravity Furnace")
    .setDescription(`A furnace that manipulates gravity to process droplets in a unique way. %mul% value.`)
    .setDifficulty(Difficulty.PressAKey)
    .setPrice(new CurrencyBundle().set("Skill", 600), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .soldAt(Class1Shop)
    .setCreator("eeeesdfew")

    .trait(Furnace)
    .setMul(new CurrencyBundle().set("Funds", 2000000).set("Power", 20000).set("Skill", 200))

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Item from "shared/item/Item";

export = new Item(script.Name)
    .setName("Dual Conveyor")
    .setDescription("A double conveyor for both ground and raised heights.")
    .setDifficulty(Difficulty.PressAKey)
    .setPrice(new CurrencyBundle().set("Funds", 35e39), 10)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")

    .trait(Conveyor)
    .setSpeed(5)

    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Dual Gravity Upgrader")
    .setDescription("%mul%...")
    .setDifficulty(Difficulty.PressAKey)
    .setPrice(new CurrencyBundle().set("Funds", 3.16e22), 1)
    .setPrice(new CurrencyBundle().set("Funds", 10e45), 2)
    .setCreator(".fish0000")
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)
    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Funds", 4).set("Power", 3).set("Bitcoin", 1.75))
    .exit();


import Difficulty from "@rbxts/ejt";
import { getAllInstanceInfo } from "@antivivi/vrldk";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import eat from "shared/hamster/eat";
import Item from "shared/item/Item";
import Boostable from "shared/item/traits/boost/Boostable";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";

export = new Item(script.Name)
    .setName("Leg Powered Upgrader")
    .setDescription(
        "Run on the treadmill to activate this upgrader. While powered, increases droplet value by %mul%. Requires effort!",
    )
    .setDifficulty(Difficulty.PressAKey)
    .setPrice(new CurrencyBundle().set("Skill", 1500), 1)
    .setCreator("sanjay2133")
    .addPlaceableArea("BarrenIslands", "SlamoVillage")
    .persists()

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Funds", 2))

    .trait(Conveyor)
    .setSpeed(8)
    .exit()

    .onLoad((model, item) => {
        const thitbox = model.WaitForChild("TreadmillHitbox") as BasePart;
        thitbox.CanTouch = true;
        eat(thitbox.Touched.Connect(() => {}));

        const modelInfo = getAllInstanceInfo(model);
        const modifier: ItemBoost = {
            ignoresLimitations: false,
            upgradeCompound: {
                mul: new CurrencyBundle().set("Funds", 0),
            },
        };
        Boostable.addBoost(modelInfo, "Treadmill", modifier);

        item.repeat(
            model,
            () => {
                const touchingParts = thitbox.GetTouchingParts();
                let hasCharacter = false;
                for (const part of touchingParts) {
                    const humanoid = part.Parent?.FindFirstChildOfClass("Humanoid");
                    if (humanoid !== undefined) {
                        hasCharacter = true;
                        break;
                    }
                }
                modifier.upgradeCompound!.mul = hasCharacter
                    ? new CurrencyBundle().set("Funds", 1)
                    : new CurrencyBundle().set("Funds", 0);
            },
            0.5,
        );
    });


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Class1Shop from "shared/items/1/Class1Shop";

export = new Item(script.Name)
    .setName("Full Conversion Ramp")
    .setDescription(
        "Good job on making it to Walk A Slope. You are hereby rewarded with a slope that allows walking in full width.",
    )
    .setDifficulty(Difficulty.WalkASlope)
    .setPrice(new CurrencyBundle().set("Power", 4e27), 1)
    .addPlaceableArea("BarrenIslands", "SlamoVillage", "SkyPavilion")
    .soldAt(Class1Shop)
    .setCreator("sanjay2133")

    .trait(Conveyor)
    .setSpeed(3)

    .exit();


import Difficulty from "@rbxts/ejt";
import Item from "shared/item/Item";
import Shop from "shared/item/traits/Shop";

export = new Item(script.Name)
    .setName("Time Shop")
    .setDifficulty(Difficulty.Easy)
    .persists()

    .trait(Shop)
    .exit();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Furnace from "shared/item/traits/Furnace";

export = new Item(script.Name)
    .setName("All-Consuming Tub")
    .setDescription("Seems to absorb everything placed inside it, even time itself.")
    .setDifficulty(Difficulty.Anguish)
    .addPlaceableArea("MinerHaven")
    .setLevelReq(0)

    .trait(Furnace)
    .setMul(new CurrencyBundle().set("Time", 1))

    .exit();


import Difficulty from "@rbxts/ejt";
import { simpleInterval } from "@antivivi/vrldk";
import { Players } from "@rbxts/services";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import { getPlayerCharacter } from "shared/hamster/getPlayerCharacter";
import Item from "shared/item/Item";

export = new Item(script.Name)
    .setName("Marketplace Terminal")
    .setDescription(
        "A high-tech terminal that provides access to the marketplace. Stand within 15 studs to automatically open the trading interface.",
    )
    .setDifficulty(Difficulty.Easy)
    .setPrice(new CurrencyBundle().set("Funds", 1000), 1)
    .addPlaceableArea("IntermittentIsles")
    .persists()
    .unbreakable()

    .onClientLoad((model) => {
        model.AddTag("MarketplaceTerminal");
        const modelPosition = model.GetPivot().Position;

        // Add visual effects on client side
        const primaryPart = model.PrimaryPart;
        if (!primaryPart) return;

        // Create a subtle glow effect
        const pointLight = new Instance("PointLight");
        pointLight.Color = Color3.fromRGB(99, 255, 138);
        pointLight.Brightness = 0.5;
        pointLight.Range = 10;
        pointLight.Parent = primaryPart;

        const screens = new Array<BasePart>();
        for (const part of model.GetChildren()) {
            if (part.IsA("BasePart") && part.Name === "Screen") {
                screens.push(part);
            }
        }

        const cleanup = simpleInterval(() => {
            let isPlayerNearby = false;
            for (const player of Players.GetPlayers()) {
                const character = getPlayerCharacter(player);
                if (character) {
                    const distance = character.GetPivot().Position.sub(modelPosition).Magnitude;
                    if (distance <= 15) {
                        isPlayerNearby = true;
                        break;
                    }
                }
            }

            for (const screen of screens) {
                if (isPlayerNearby) {
                    screen.Material = Enum.Material.Neon;
                    screen.Color = Color3.fromRGB(217, 255, 227);
                } else {
                    screen.Material = Enum.Material.Glass;
                    screen.Color = Color3.fromRGB(0, 0, 0);
                }
            }
        }, 1);

        model.Destroying.Once(cleanup);
    });


import Difficulty from "@rbxts/ejt";
import Item from "shared/item/Item";

export = new Item(script.Name)
    .setName("Remnant Of Light")
    .setDescription("A dazzlingly shiny orb, a reminder of the once brilliant empire from an age long past.")
    .setDifficulty(Difficulty.Easy)
    .persists();


import Difficulty from "@rbxts/ejt";
import CurrencyBundle from "shared/currency/CurrencyBundle";
import Item from "shared/item/Item";
import Conveyor from "shared/item/traits/conveyor/Conveyor";
import Upgrader from "shared/item/traits/upgrader/Upgrader";
import TimeShop from "shared/items/2/TimeShop";

export = new Item(script.Name)
    .setName("Time Accelerator")
    .setDescription("Pass droplets through this to boost them by %mul%.")
    .setDifficulty(Difficulty.Horrific)
    .setPrice(new CurrencyBundle().set("Time", 15), 1)
    .addPlaceableArea("MinerHaven")
    .soldAt(TimeShop)
    .setLevelReq(0)

    .trait(Upgrader)
    .setMul(new CurrencyBundle().set("Time", 10000))

    .trait(Conveyor)
    .setSpeed(4)

    .exit();