/* eslint-disable no-unused-vars */ // Priority: 1000 const artMachineTickRate = 200; const artMachineProgTime = 20; const booleanProperty = Java.loadClass( "net.minecraft.world.level.block.state.properties.BooleanProperty" ); const integerProperty = Java.loadClass( "net.minecraft.world.level.block.state.properties.IntegerProperty" ); const directionProperty = Java.loadClass( "net.minecraft.world.level.block.state.properties.DirectionProperty" ); const CropGrowthUtils = Java.loadClass( "cool.bot.dewdropfarmland.utils.CropHandlerUtils" ); function rnd(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } function rnd50() { return Math.random() < 0.5; } function rnd75() { return Math.random() < 0.75; } function rnd25() { return Math.random() < 0.25; } function rnd10() { return Math.random() < 0.1; } function rnd5() { return Math.random() < 0.05; } global.surviveCheck = (level, pos) => { const FARMLAND = Java.loadClass("net.minecraft.world.level.block.FarmBlock"); let blockState = level.getBlockState(pos.below()); let mcBlock = blockState.block; if (mcBlock instanceof FARMLAND) { return true; } else return false; }; let increaseDataStage = (block, count) => { let nbt = block.getEntityData(); let currentStage = nbt.data.stage; currentStage += count || 1; nbt.merge({ data: { stage: currentStage } }); global.setBlockEntityData(block, nbt) }; let increaseStage = (input, count) => { let num = Number(input); num += count || 1; return num; }; let decreaseStage = (input) => { let num = Number(input); num -= 1; return num; }; const successParticles = (level, block) => { const { x, y, z } = block; level.spawnParticles( "minecraft:happy_villager", true, x + 0.5, y + 0.5, z + 0.5, 0.1 * rnd(1, 4), 0.1 * rnd(1, 4), 0.1 * rnd(1, 4), 10, 0.1 ); }; const itemHasTag = (item, tag) => { const tagString = tag.startsWith("#") ? tag.substring(1) : tag; return item.hasTag(tagString); }; const setQuality = (nbt, stage, itemQuality) => { if ( (Number(nbt.data.quality) === 0 && Number(stage) === 0) || Number(itemQuality) < Number(nbt.data.quality) ) nbt.merge({ data: { quality: Number(itemQuality) } }); }; const getCanTakeItems = ( item, recipe, properties, hasTag, inputCount, recipes, nbt ) => { if (properties.get("working") == "true" || properties.get("mature") == "true") return false; let itemCheck = recipe !== undefined; if (hasTag) { Array.from(recipes.keys()).forEach((key) => { if (key.startsWith("#")) { if (itemHasTag(item, key)) { if (nbt.data.recipe.equals("") || nbt.data.recipe == undefined) { nbt.merge({ data: { recipe: key, originalInputs: [] } }); itemCheck = true; } if (inputCount != -1 && nbt.data.recipe.equals(key)) { let inputArray = nbt.data.originalInputs.copy(); let usedItem = item.copy(); usedItem.count = inputCount; inputArray.push(usedItem); nbt.merge({ data: { originalInputs: inputArray } }); itemCheck = true; } } } }); } return itemCheck }; global.convertFromLegacy = (recipes, level, block) => { let nbt = block.getEntityData(); let newRecipe; if (block.id.equals("society:tapper") && !nbt.data.contains("recipe")) { let newProperties = level.getBlock(block.pos).getProperties(); newProperties.working = false; newProperties.mature = false; nbt.merge({ data: { stage: 0, recipe: "" } }); global.setBlockEntityData(block, nbt) block.set(block.id, newProperties); return; } if (nbt.data.contains("recipe") || !nbt.data.contains("type")) return; if (nbt.data.type > 0) { newRecipe = Array.from(recipes.keys())[Number(nbt.data.type) - 1]; } if (['society:cheese_press', 'society:mayonnaise_machine', 'society:fish_smoker', 'society:seed_maker'].includes(block.id)) { nbt.merge({ data: { quality: 0 } }); global.setBlockEntityData(block, nbt) } if (newRecipe) { let newProperties = level.getBlock(block.pos).getProperties(); newProperties.working = false; newProperties.mature = true; nbt.merge({ data: { recipe: newRecipe } }); global.setBlockEntityData(block, nbt) block.set(block.id, newProperties); } }; global.artisanHarvest = ( block, recipes, stageCount, outputMult, isCheesePress, artisanHopper, server, player ) => { let newProperties = block.getProperties(); if (block.properties.get("mature").toLowerCase() === "true") { let harvestOutput; let hopperOutputs = []; if (!artisanHopper) { global.giveExperience(server, player, "farming", stageCount * 20); server.runCommandSilent( `playsound stardew_fishing:dwop block @a ${player.x} ${player.y} ${player.z}` ); } let nbt = block.getEntityData(); let hasQuality = nbt.data.quality !== undefined && Number(nbt.data.quality) > 0; recipes.get(nbt.data.recipe).output.forEach((id) => { harvestOutput = Item.of( id, hasQuality ? `{quality_food:{quality:${Number(nbt.data.quality)}}}` : null ); // Artisan Cheese Press upgrade: auto age cheese wheels only if ( isCheesePress && (id.includes("wheel") || id.includes("block")) && block.properties.get("upgraded").toLowerCase() === "true" ) { harvestOutput = Item.of(`society:aged_${id.path}`); } if (outputMult > 1 && !recipes.get(nbt.data.recipe).multExempt) { harvestOutput.count = harvestOutput.count * outputMult; } if (!artisanHopper) { block.popItemFromFace(harvestOutput, block.properties.get("facing")); } else { hopperOutputs.push(harvestOutput); } nbt.merge({ data: { stage: 0, recipe: "", originalInputs: [] } }); if (nbt.data.quality) { nbt.merge({ data: { stage: 0, recipe: "", quality: 0 } }); } global.setBlockEntityData(block, nbt) newProperties.working = false; newProperties.mature = false; if (newProperties.duration) newProperties.duration = "0"; block.set(block.id, newProperties); }); if (artisanHopper) return hopperOutputs; } }; // Converted global.artisanInsert = ( block, item, level, recipes, stageCount, stockSound, multipleInputs, hasTag, artisanHopper, server, player ) => { let newProperties = block.getProperties(); let nbt = block.getEntityData(); let stage = nbt.data.stage; const itemNbt = item.nbt; let itemQuality; let hasQuality = nbt.data.quality !== undefined || ['society:cheese_press', 'society:mayonnaise_machine', 'society:fish_smoker', 'society:seed_maker'].includes(block.id); let useCount = multipleInputs && item.count >= stageCount - Number(stage) ? stageCount - Number(stage) : 1; const recipe = recipes.get(`${item.id}`); if ( multipleInputs && recipe && nbt.data.recipe !== "" && nbt.data.recipe !== item.id ) return; if ( getCanTakeItems( item, recipe, block.properties, hasTag, multipleInputs ? useCount : -1, recipes, nbt ) ) { newProperties = block.getProperties(); successParticles(level, block); server.runCommandSilent( `playsound ${stockSound} block @a ${block.x} ${block.y} ${block.z}` ); if (!(hasTag && recipe === undefined)) nbt.merge({ data: { recipe: item.id } }); newProperties.working = false; newProperties.mature = false; if (hasQuality && itemNbt && itemNbt.quality_food) { itemQuality = String(itemNbt.quality_food.quality); } else if (hasQuality) { itemQuality = "0"; } if (multipleInputs) { if (item.count >= stageCount - Number(stage)) { nbt.merge({ data: { stage: stageCount } }); } else { increaseDataStage(block); } if (itemQuality) setQuality(nbt, stage, itemQuality); } else if (itemQuality) { nbt.merge({ data: { quality: Number(itemQuality) } }); } if (!multipleInputs || nbt.data.stage === stageCount) { newProperties.working = true; nbt.merge({ data: { stage: 0 } }); } global.setBlockEntityData(block, nbt) block.set(block.id, newProperties); if (player && !player.isCreative()) item.count -= useCount; if (artisanHopper) return useCount; } }; global.handleBERightClick = ( stockSound, clickEvent, recipes, stageCount, multipleInputs, hasTag, outputMult, disableInput, isCheesePress ) => { const { item, block, hand, player, level, server } = clickEvent; // Prevent Deployers from using artisan machines if (player.isFake()) return; if (hand == "OFF_HAND") return; if (hand == "MAIN_HAND") { global.convertFromLegacy(recipes, level, block); global.artisanHarvest( block, recipes, stageCount, outputMult, isCheesePress, false, server, player ); if (!disableInput) { global.artisanInsert( block, item, level, recipes, stageCount, stockSound, multipleInputs, hasTag, false, server, player ); } } }; global.setDebt = (server, UUID, amount) => { for (let index = 0; index < server.persistentData.debts.length; index++) { if (String(UUID) === String(server.persistentData.debts[index].uuid)) { server.persistentData.debts[index].amount = amount; break; } } }; global.getOpposite = (facing, pos) => { switch (facing) { case "north": return pos.offset(0, 0, 1); case "south": return pos.offset(0, 0, -1); case "west": return pos.offset(1, 0, 0); case "east": return pos.offset(-1, 0, 0); } }; global.getFacing = (facing, pos) => { switch (facing) { case "north": return pos.offset(0, 0, -1); case "south": return pos.offset(0, 0, 1); case "west": return pos.offset(-1, 0, 0); case "east": return pos.offset(1, 0, 0); } }; global.getTapperLog = (level, block) => level.getBlock( global.getOpposite(block.properties.get("facing"), block.getPos()) ); global.getFermentingBarrel = (level, block) => level.getBlock( global.getFacing(block.getProperties().get("facing"), block.getPos()) ); global.handleTapperRandomTick = (tickEvent, returnFluidData) => { const { block, level, server } = tickEvent; let newProperties = block.getProperties(); let nbt = block.getEntityData(); const attachedBlock = global.getTapperLog(level, block); let foundFluidData = undefined; let hasError = false; if (attachedBlock.hasTag("society:tappable_blocks")) { if ( !nbt.data.recipe || !nbt.data.recipe.equals(attachedBlock.id) || global.hasMultipleTappers(level, block) ) { hasError = true; } if ( returnFluidData || (block.properties.get("working").toLowerCase() === "false" && block.properties.get("mature").toLowerCase() === "false") ) { if (global.tapperRecipes) { const recipe = global.tapperRecipes.get(`${attachedBlock.getId()}`); let nbt = block.getEntityData(); if (returnFluidData && !foundFluidData && recipe) { foundFluidData = { fluid: recipe.fluidOutput, time: recipe.time }; nbt.merge({ data: { recipe: `${attachedBlock.getId()}` } }); hasError = false; } if ( !returnFluidData && getCanTakeItems( attachedBlock.getId(), recipe, block.properties, false ) ) { newProperties = block.getProperties(); successParticles(level, block); server.runCommandSilent( `playsound vinery:cabinet_close block @a ${block.x} ${block.y} ${block.z}` ); newProperties.mature = false; newProperties.working = true; nbt.merge({ data: { recipe: `${attachedBlock.getId()}`, stage: 0 } }); hasError = false; } global.setBlockEntityData(block, nbt) } } if (returnFluidData) { if (hasError) newProperties.error = true; else newProperties.error = false; block.set(block.id, newProperties); return foundFluidData; } if (hasError) newProperties.error = true; else newProperties.error = false; block.set(block.id, newProperties); } else { newProperties.error = true; block.set(block.id, newProperties); if (returnFluidData) return undefined; } }; const getMushroomLogData = (level, centerPos, radius) => { const { x, y, z } = centerPos; let scanBlock; let scannedBlocks = 0; let regularOutputs = []; let dominantOutputs = []; let airBlocks = 0; for (let pos of BlockPos.betweenClosed( new BlockPos(x - radius, y - radius, z - radius), [x + radius, y + radius, z + radius] )) { if (!level.isLoaded(pos)) continue; scanBlock = level.getBlock(pos); if (scanBlock.hasTag("society:mushroom_log_detects")) { scannedBlocks++; if (scanBlock.hasTag("society:mushroom_log_dominant")) { if (!dominantOutputs.includes(scanBlock.id)) dominantOutputs.push(scanBlock.id); } else { if (!regularOutputs.includes(scanBlock.id)) regularOutputs.push(scanBlock.id); } } else if (scanBlock.id === "minecraft:air") airBlocks++; } return { count: airBlocks < 100 ? 4 : scannedBlocks, possibleOutputs: dominantOutputs.length > 0 ? dominantOutputs : regularOutputs, }; }; global.handleMushroomLogRandomTick = (tickEvent) => { const { block, level, server } = tickEvent; let newProperties = block.getProperties(); if ( block.properties.get("working").toLowerCase() === "false" && block.properties.get("mature").toLowerCase() === "false" ) { const leafCount = global.getTaggedBlocksInRadius( level, "society:mushroom_log_leaves", new BlockPos(block.x, block.y + 4, block.z), 8 ); const logData = getMushroomLogData(level, block.pos, 8); if (!logData || logData.count == 0 || logData.possibleOutputs.length == 0) return; let baseCount = Math.max( 1, Math.floor(Math.min(8, logData.count / 4) + Math.min(8, leafCount / 4)) ); if (global.mushroomLogRecipes) { let rolledRecipe = logData.possibleOutputs[ Math.floor(Math.random() * logData.possibleOutputs.length) ]; const recipe = global.mushroomLogRecipes.get(`${rolledRecipe}`); let nbt = block.getEntityData(); if (getCanTakeItems(rolledRecipe, recipe, block.properties, false)) { newProperties = block.getProperties(); successParticles(level, block); server.runCommandSilent( `playsound species:block.alphacene_foliage.place block @a ${block.x} ${block.y} ${block.z}` ); newProperties.mature = false; newProperties.working = true; let quality = 0; if (logData.count > 20 && logData.count / 40 > Math.random()) quality = 1; if (logData.count > 40 && logData.count / 60 > Math.random()) quality = 2; if (logData.count > 60 && logData.count / 80 > Math.random()) quality = 3; nbt.merge({ data: { recipe: `${rolledRecipe}`, stage: 0, baseCount: baseCount, quality: quality }, }); } global.setBlockEntityData(block, nbt) block.set(block.id, newProperties); } } }; global.hasMultipleTappers = (level, block) => { const attachedBlock = global.getTapperLog(level, block); const offsetsToCheck = [ [1, 0], [0, 1], [-1, 0], [0, -1], ]; let tapperCount = 0; offsetsToCheck.forEach((offset) => { if ( ["society:tapper", "society:auto_tapper"].includes( level.getBlock( new BlockPos( attachedBlock.x + offset[0], attachedBlock.y, attachedBlock.z + offset[1] ) ).id ) ) tapperCount++; }); return tapperCount > 1; }; global.handleBERandomTick = (tickEvent, rndFunction, stageCount) => { const { block } = tickEvent; const { x, y, z } = block; const stage = block.getEntityData().data.stage; const mature = stage >= stageCount - 1; let newProperties = block.getProperties(); if (block.properties.get("working").toLowerCase() === "true" && rndFunction) { tickEvent.level.spawnParticles( "minecraft:campfire_cosy_smoke", true, x + 0.5, y + 1, z + 0.5, 0.1 * rnd(1, 2), 0.1 * rnd(1, 2), 0.1 * rnd(1, 2), rnd(1, 4), 0.1 ); newProperties.working = !mature; newProperties.mature = mature; increaseDataStage(block); block.set(block.id, newProperties); } }; global.handleBETick = (entity, recipes, stageCount, halveTime, forced) => { const { level, block } = entity; let dayTime = level.dayTime(); let morningModulo = dayTime % 24000; if ( forced || (morningModulo >= artMachineProgTime && morningModulo < artMachineProgTime + artMachineTickRate) ) { let blockProperties = level.getBlock(block.pos).getProperties(); if (blockProperties.get("working").toLowerCase() === "false") return; global.convertFromLegacy(recipes, level, block); let nbt = block.getEntityData(); let mature; let recipe = recipes && recipes.get(nbt.data.recipe); let resolvedStage = (recipe && recipe.time) || stageCount; const nbtStage = nbt.data.stage; if (halveTime && blockProperties.get("upgraded").toLowerCase() == "true") { mature = Number(nbtStage) >= resolvedStage / 2 - 1; } else { mature = Number(nbtStage) >= resolvedStage - 1; } let newProperties = level.getBlock(block.pos).getProperties(); newProperties.mature = mature; if (mature) newProperties.working = false; increaseDataStage(block); block.set(block.id, newProperties); } }; global.isSameQuality = (itemA, itemB) => { if (!itemA.nbt && !itemB.nbt) return true; if ((itemA.nbt && !itemB.nbt) || (!itemA.nbt && itemB.nbt)) return false; if (!itemA.nbt.quality_food && !itemB.nbt.quality_food) return false; return itemA.nbt.quality_food.quality === itemB.nbt.quality_food.quality; }; global.inventoryHasRoom = (block, item) => { let belowItem; if (block.inventory && item && item !== Item.of("minecraft:air")) { for (let j = 0; j < block.inventory.slots; j++) { belowItem = block.inventory.getStackInSlot(j); if ( belowItem.id === Item.of(item).id && global.isSameQuality(belowItem, Item.of(item)) && belowItem.count + Item.of(item).count < block.inventory.getSlotLimit(j) / (64 / block.inventory.getStackInSlot(j).maxStackSize) ) { return true; } } for (let j = 0; j < block.inventory.slots; j++) { belowItem = block.inventory.getStackInSlot(j); if (belowItem === Item.of("minecraft:air")) { return true; } } } return false; }; global.inventoryBelowHasRoom = (level, block, item) => { const belowPos = block.getPos().below(); const belowBlock = level.getBlock(belowPos.x, belowPos.y, belowPos.z); return global.inventoryHasRoom(belowBlock, item); }; global.inventoryBelowHasRoomForAll = (level, block, items) => { const belowPos = block.getPos().below(); const belowBlock = level.getBlock(belowPos.x, belowPos.y, belowPos.z); let hasRoom = true; items.forEach((item) => { if (!global.inventoryHasRoom(belowBlock, item)) hasRoom = false; }); return hasRoom; }; /** * @returns result code: * -1 - Failure - Operation attempted but couldn't be inserted * 0 - Neutral - Operation not attempted due to no below inventory or item * 1 - Success - Item successfully inserted */ global.insertInto = (block, item) => { let belowItem; if (block.inventory && item && item !== Item.of("minecraft:air")) { for (let j = 0; j < block.inventory.slots; j++) { belowItem = block.inventory.getStackInSlot(j); if ( belowItem.id === Item.of(item).id && global.isSameQuality(belowItem, Item.of(item)) && belowItem.count + Item.of(item).count < block.inventory.getSlotLimit(j) / (64 / block.inventory.getStackInSlot(j).maxStackSize) ) { block.inventory.insertItem(j, item, false); return 1; } } for (let j = 0; j < block.inventory.slots; j++) { belowItem = block.inventory.getStackInSlot(j); if (belowItem === Item.of("minecraft:air")) { block.inventory.insertItem(j, item, false); return 1; } } return -1; } return 0; }; global.insertBelow = (level, block, item) => { const belowPos = block.getPos().below(); const belowBlock = level.getBlock(belowPos.x, belowPos.y, belowPos.z); return global.insertInto(belowBlock, item); }; /** * @returns result code: * -1 - Failure - Operation attempted but not enough items * 0 - Neutral - Operation not attempted due to no inventory * 1 - Success - inventory has items of id, and of at least count */ global.inventoryHasItems = (inventory, id, count) => { if (inventory) { const slots = inventory.getSlots(); let slotStack; for (let i = 0; i < slots; i++) { slotStack = inventory.getStackInSlot(i); if (slotStack.item.id === id && slotStack.count >= count) { return 1; } } return -1; } return 0; }; global.hasInventoryItems = (inventory, id, count) => { if (inventory) { const slots = inventory.getSlots(); let slotStack; let foundCount = 0; for (let i = 0; i < slots; i++) { slotStack = inventory.getStackInSlot(i); if (slotStack.item.id === id) { foundCount += slotStack.count; } if (foundCount >= count) return true; } } return false; }; /** * @returns result code: * -1 - Failure - Operation attempted but nothing to use * 0 - Neutral - Operation not attempted due to no inventory * 1 - Success - Item successfully consumed */ global.useInventoryItems = (inventory, id, count) => { if (inventory) { const slots = inventory.getSlots(); let slotStack; for (let i = 0; i < slots; i++) { slotStack = inventory.getStackInSlot(i); if (slotStack.item.id === id && slotStack.count >= count) { inventory.extractItem(i, count, false); return 1; } } return -1; } return 0; }; global.inventoryUseItems = (inventory, id, count) => { if (!inventory) return 0; const slots = inventory.getSlots(); let remaining = count; let total = 0; for (let i = 0; i < slots; i++) { let stack = inventory.getStackInSlot(i); if (stack.item.id === id) total += stack.count; } if (total < count) return -1; for (let i = 0; i < slots; i++) { if (remaining <= 0) break; let stack = inventory.getStackInSlot(i); if (stack.item.id === id) { let toExtract = Math.min(stack.count, remaining); inventory.extractItem(i, toExtract, false); remaining -= toExtract; } } return 1; }; /** All fluid handlers expect the following initialData with a capacity of 10000 * * blockInfo.initialData({ Fluid: 0, FluidType: "" }); */ global.getFluid = (blockInfo) => { if (!blockInfo || !blockInfo.persistentData) { return Fluid.of("minecraft:water", 0); } const foundFluid = blockInfo.persistentData.getString("FluidType"); if (!foundFluid) return Fluid.of("minecraft:water", 0); if (foundFluid === "minecraft:empty") { return Fluid.of("minecraft:water", 0); } let foundFluidLevel = blockInfo.persistentData.getInt("Fluid"); if (!foundFluidLevel) foundFluidLevel = 0; return Fluid.of(foundFluid, foundFluidLevel); }; global.onFill = (blockInfo, fluid, sim) => { const fluidData = blockInfo.persistentData.getInt("Fluid"); const filled = Math.min(10000 - fluidData, fluid.getAmount()); if (!sim) { const storedFluidId = blockInfo.persistentData.getString("FluidType"); const incomingFluidId = fluid.getId(); if (storedFluidId === "" || fluidData === 0) { blockInfo.persistentData.putString("FluidType", incomingFluidId); blockInfo.persistentData.putInt("Fluid", fluidData + filled); } else if (storedFluidId === incomingFluidId) { blockInfo.persistentData.putInt("Fluid", fluidData + filled); } else { return (filled = 0); } } return filled; }; global.onDrain = (blockInfo, fluid, sim) => { const fluidData = blockInfo.persistentData.getInt("Fluid"); const drained = Math.min(fluidData, fluid.getAmount()); if (!sim) blockInfo.persistentData.putInt("Fluid", fluidData - drained); return drained; }; // Text display utils global.clearOldTextDisplay = (block, level, id) => { const { x, y, z } = block; level.getEntitiesWithin(AABB.ofBlock(block).inflate(3)) .filter((entityType) => entityType.type === "minecraft:text_display") .forEach((entity) => { entity.getTags().forEach((tag) => { if (tag === `${id}-${x}-${y}-${z}`) { entity.kill(); } }); }); }; global.rotationFromFacing = (facing) => { switch (facing) { case "north": return 180; case "east": return 270; case "south": return 360; default: case "west": return 90; } }; global.spawnTextDisplay = (block, y, id, text) => { let entity; const { x, z } = block; entity = block.createEntity("minecraft:text_display"); let newNbt = entity.getNbt(); newNbt.text = `${text.toJson()}`; newNbt.background = 0; newNbt.Rotation = [ NBT.f(global.rotationFromFacing(block.properties.get("facing"))), NBT.f(0), ]; entity.setNbt(newNbt); entity.setX(x + 0.5); entity.setY(y); entity.setZ(z + 0.5); entity.addTag(`${id}-${x}-${block.y}-${z}`); entity.spawn(); }; global.giveExperience = (server, player, category, xp, excludeMastery) => { if (!player.isFake()) { server.runCommandSilent( `puffish_skills experience add ${player.username} society:${category} ${xp}` ); if (!excludeMastery && player.stages.has("mastery_unlocked")) { server.runCommandSilent( `puffish_skills experience add ${player.username} society:mastery ${xp}` ); } } }; /** * If you can figure out a way to simplify this in a way that doesn't * make it more difficult to read you get an artifact in-game. */ global.getProcessedItem = (item, dropAmount) => { let processOutput = global.mayonnaiseMachineRecipes.get(item); if (processOutput) return { divisor: 1, item: Item.of(processOutput.output[0]), preserveQuality: true }; // Wine Keg processOutput = global.wineKegRecipes.get(item); if (processOutput) return { divisor: 3, item: Item.of(processOutput.output[0]), preserveQuality: false }; // Oil Maker processOutput = global.oilMakerRecipes.get(item); if (processOutput) return { divisor: 1, item: Item.of(processOutput.output[0]), preserveQuality: false }; // Loom processOutput = global.loomRecipes.get(item); if (processOutput && dropAmount >= 5) return { divisor: 5, item: Item.of(processOutput.output[0]), preserveQuality: false }; // Recycling Machine processOutput = global.recyclingMachineRecipes.get(item); if (processOutput) return { divisor: 1, item: Item.of(processOutput.output[0]), preserveQuality: false }; return { divisor: 1, item: item, preserveQuality: true }; }; const stoneRockTable = [ { block: "society:stone_boulder", weight: 163 }, { block: "minecraft:coal_ore", weight: 25 }, { block: "minecraft:copper_ore", weight: 20 }, { block: "minecraft:iron_ore", weight: 15 }, { block: "create:zinc_ore", weight: 13 }, { block: "minecraft:lapis_ore", weight: 2 }, { block: "society:geode_node", weight: 2, sturdy: true }, { block: "society:earth_crystal", weight: 2, sturdy: true }, { block: "society:oak_supply_crate", weight: 2 }, ]; const iceRockTable = [ { block: "society:ice_boulder", weight: 164 }, { block: "minecraft:iron_ore", weight: 25 }, { block: "create:zinc_ore", weight: 15 }, { block: "oreganized:lead_ore", weight: 10 }, { block: "minecraft:diamond_ore", weight: 4 }, { block: "society:earth_crystal", weight: 2, sturdy: true }, { block: "society:omni_geode_node", weight: 1, sturdy: true }, { block: "society:sparkstone_ore", weight: 2 }, { block: "society:spruce_supply_crate", weight: 2 }, ]; const sandstoneRockTable = [ { block: "society:sandstone_boulder", weight: 163 }, { block: "minecraft:gold_ore", weight: 20 }, { block: "oreganized:lead_ore", weight: 10 }, { block: "minecraft:redstone_ore", weight: 6 }, { block: "minecraft:diamond_ore", weight: 4 }, { block: "society:sparkstone_ore", weight: 4 }, { block: "society:fire_quartz", weight: 2, sturdy: true }, { block: "society:magma_geode_node", weight: 2, sturdy: true }, { block: "society:omni_geode_node", weight: 2, sturdy: true }, { block: "society:palm_supply_crate", weight: 2 }, { block: "oreganized:silver_ore", weight: 2 }, { block: "society:iridium_ore", weight: 1 }, ]; const blackstoneRockTable = [ { block: "society:blackstone_boulder", weight: 148 }, { block: "minecraft:deepslate_gold_ore", weight: 20 }, { block: "oreganized:deepslate_lead_ore", weight: 10 }, { block: "minecraft:deepslate_redstone_ore", weight: 15 }, { block: "minecraft:deepslate_diamond_ore", weight: 4 }, { block: "society:deepslate_sparkstone_ore", weight: 10 }, { block: "society:fire_quartz", weight: 2, sturdy: true }, { block: "society:magma_geode_node", weight: 2, sturdy: true }, { block: "society:omni_geode_node", weight: 4, sturdy: true }, { block: "oreganized:deepslate_silver_ore", weight: 4 }, { block: "society:grimwood_supply_crate", weight: 2 }, { block: "society:deepslate_iridium_ore", weight: 2 }, ]; const endstoneRockTable = [ { block: "society:end_stone_boulder", weight: 194 }, { block: "society:deepslate_sparkstone_ore", weight: 14 }, { block: "society:omni_geode_node", weight: 4, sturdy: true }, { block: "society:deepslate_iridium_ore", weight: 3 }, ]; const rollReplaceTable = (table, hasRope) => { let roll = 0; const totalWeight = table.reduce( (acc, current) => (hasRope && current.sturdy ? acc : acc + current.weight), 0 ); let currentWeight = 0; if (totalWeight > 1) { roll = rnd(0, totalWeight); for (let index = 0; index < table.length; index++) { currentWeight += table[index].weight; if (currentWeight >= roll) { return table[index].block; } } } return "minecraft:obsidian"; }; global.handleSkullCavernRegen = (level, block) => { if ( !level.persistentData || !level.persistentData.chunkParityMap || !block.id.equals("society:cavern_air") ) return; let belowPos; let belowBlock; let belowBelowPos; let hasRope; let toggleBit = level.persistentData.chunkParityMap[ level.getChunkAt(block.getPos()).pos.toString() ].toggleBit; if (block && block.getProperties() && block.getProperties().get("chunkbit")) { if (String(toggleBit) != block.getProperties().get("chunkbit")) { belowPos = block.getPos().below(); belowBlock = level.getBlock(belowPos.x, belowPos.y, belowPos.z); belowBelowPos = belowBlock.getPos().below(); hasRope = level.getBlock(belowBelowPos.x, belowBelowPos.y, belowBelowPos.z).id === "farmersdelight:rope"; let newBlock; switch (Number(block.properties.get("type"))) { case 4: newBlock = rollReplaceTable(endstoneRockTable, hasRope); break; case 3: newBlock = rollReplaceTable(blackstoneRockTable, hasRope); break; case 2: newBlock = rollReplaceTable(sandstoneRockTable, hasRope); break; case 1: newBlock = rollReplaceTable(iceRockTable, hasRope); break; default: case 0: newBlock = rollReplaceTable(stoneRockTable, hasRope); break; } block.set(newBlock); } } }; const getCardinalMultipartJsonBasic = (name) => { const path = `society:block/kubejs/${name}`; return [ { when: { facing: "north" }, apply: { model: path, y: 0, uvlock: false }, }, { when: { facing: "east" }, apply: { model: path, y: 90, uvlock: false }, }, { when: { facing: "south" }, apply: { model: path, y: 180, uvlock: false }, }, { when: { facing: "west" }, apply: { model: path, y: -90, uvlock: false }, }, ]; }; const getCardinalMultipartJsonBasicUpgradable = (name, upgraded) => { const path = `society:block/kubejs/${name}`; return [ { when: { facing: "north", upgraded: upgraded }, apply: { model: path, y: 0, uvlock: false }, }, { when: { facing: "east", upgraded: upgraded }, apply: { model: path, y: 90, uvlock: false }, }, { when: { facing: "south", upgraded: upgraded }, apply: { model: path, y: 180, uvlock: false }, }, { when: { facing: "west", upgraded: upgraded }, apply: { model: path, y: -90, uvlock: false }, }, ]; }; global.cropList = [ "minecraft:wheat", "minecraft:pumpkin_stem", "minecraft:melon_stem", "minecraft:beetroots", "snowyspirit:ginger", "supplementaries:flax", "herbalbrews:coffee_plant", "herbalbrews:rooibos_plant", "herbalbrews:tea_plant", "herbalbrews:yerba_mate_plant", "minecraft:sweet_berry_bush", "farm_and_charm:tomato_crop", "farm_and_charm:strawberry", "farm_and_charm:lettuce_crop", "farm_and_charm:barley_crop", "farm_and_charm:onion_crop", "farm_and_charm:tomato_crop_body", "farm_and_charm:corn_crop", "farm_and_charm:oat_crop", "brewery:hops_crop", "brewery:hops_crop_body", "nethervinery:crimson_grape_bush", "nethervinery:warped_grape_bush", "vinery:savanna_grape_bush_white", "vinery:jungle_grape_bush_red", "vinery:savanna_grape_bush_red", "vinery:white_grape_bush", "vinery:red_grape_bush", "vinery:taiga_grape_bush_red", "vinery:taiga_grape_bush_white", "vinery:jungle_grape_bush_white", "vinery:jungle_grape_bush_red", "vintagedelight:ghost_pepper_crop", "vintagedelight:cucumber_crop", "farmersdelight:cabbages", "farmersdelight:budding_tomatoes", "farmersdelight:tomatoes", "farmersdelight:rice", "farmersdelight:rice_panicles", "society:ancient_fruit", "society:cranberry", "society:sparkpod", "windswept:wild_berry_bush", "society:mana_fruit", "etcetera:cotton", "society:tubabacco_leaf", "brewery:hop_trellis", "society:blueberry", "veggiesdelight:cauliflower_crop", "veggiesdelight:garlic_crop", "veggiesdelight:bellpepper_crop", "society:eggplant", "society:potato", "society:carrot", "society:peanut", "society:sweet_potato", "society:onion", "veggiesdelight:turnip_crop", "veggiesdelight:zucchini_crop", "veggiesdelight:broccoli_crop", ]; const qualityToInt = (quality) => { switch (quality) { case "DIAMOND": return 3; case "GOLD": return 2; case "IRON": return 1; case "NONE": default: return 0; } }; const getFertilizer = (crop) => { let block = crop .getLevel() .getBlock(crop.getPos().below()); if (block.hasTag("dew_drop_farmland_growth:bountiful_fertilized_farmland")) return -1; if (block.hasTag("dew_drop_farmland_growth:low_quality_fertilized_farmland")) return 1; if (block.hasTag("dew_drop_farmland_growth:high_quality_fertilized_farmland")) return 2; if ( block.hasTag( "dew_drop_farmland_growth:pristine_quality_fertilized_farmland" ) ) return 3; return 0; }; const LevelData = Java.loadClass( "de.cadentem.quality_food.capability.LevelData" ); global.getCropQuality = (crop) => { let resolvedCrop = crop if (crop.id === "farmersdelight:rice_panicles") resolvedCrop = crop.getLevel().getBlock(crop.getPos().below()); const fertilizer = getFertilizer(resolvedCrop); if (fertilizer == -1) return 0; const qualityName = LevelData.get( resolvedCrop.getLevel(), resolvedCrop.getPos(), false ); let seedQuality = qualityToInt(qualityName); if (fertilizer > 1 && seedQuality < 1) seedQuality = 1; const goldChance = 0.2 * ((seedQuality * 4.6) / 10) + 0.2 * fertilizer * ((seedQuality * 4.6 + 2) / 12) + 0.01; // // Debug Quality // console.log(crop) // console.log("Seed quality " + seedQuality); // console.log("Fertilizer quality " + fertilizer); // console.log("Chance for gold: " + goldChance); if (fertilizer >= 2 && Math.random() < goldChance / 2) return 3; if (Math.random() < goldChance) return 2; if (Math.random() < goldChance * 2) return 1; return 0; }; const getCardinalMultipartJson = (name, disableExclamation) => { const path = `society:block/kubejs/${name}/${name}`; let exclamationJson = [ { when: { mature: true }, apply: { model: "society:block/kubejs/machine_done" }, }, ]; if (disableExclamation) { exclamationJson = []; } let offJson = [ { when: { working: false, upgraded: false, facing: "north" }, apply: { model: `${path}_off`, y: 0, uvlock: false }, }, { when: { working: false, upgraded: false, facing: "east" }, apply: { model: `${path}_off`, y: 90, uvlock: false }, }, { when: { working: false, upgraded: false, facing: "south" }, apply: { model: `${path}_off`, y: 180, uvlock: false }, }, { when: { working: false, upgraded: false, facing: "west" }, apply: { model: `${path}_off`, y: -90, uvlock: false }, }, { when: { working: false, upgraded: true, facing: "north" }, apply: { model: `${path}_off_upgraded`, y: 0, uvlock: false }, }, { when: { working: false, upgraded: true, facing: "east" }, apply: { model: `${path}_off_upgraded`, y: 90, uvlock: false }, }, { when: { working: false, upgraded: true, facing: "south" }, apply: { model: `${path}_off_upgraded`, y: 180, uvlock: false }, }, { when: { working: false, upgraded: true, facing: "west" }, apply: { model: `${path}_off_upgraded`, y: -90, uvlock: false }, }, ]; let doneJson = [ { when: { mature: true, upgraded: false, facing: "north" }, apply: { model: `${path}_done`, y: 0, uvlock: false }, }, { when: { mature: true, upgraded: false, facing: "east" }, apply: { model: `${path}_done`, y: 90, uvlock: false }, }, { when: { mature: true, upgraded: false, facing: "south" }, apply: { model: `${path}_done`, y: 180, uvlock: false }, }, { when: { mature: true, upgraded: false, facing: "west" }, apply: { model: `${path}_done`, y: -90, uvlock: false }, }, { when: { mature: true, upgraded: true, facing: "north" }, apply: { model: `${path}_done_upgraded`, y: 0, uvlock: false }, }, { when: { mature: true, upgraded: true, facing: "east" }, apply: { model: `${path}_done_upgraded`, y: 90, uvlock: false }, }, { when: { mature: true, upgraded: true, facing: "south" }, apply: { model: `${path}_done_upgraded`, y: 180, uvlock: false }, }, { when: { mature: true, upgraded: true, facing: "west" }, apply: { model: `${path}_done_upgraded`, y: -90, uvlock: false }, }, ]; return [ { apply: { model: `society:block/kubejs/${name}/${name}_particle` }, }, { when: { mature: true }, apply: { model: "society:block/kubejs/machine_done" }, }, { when: { working: true, upgraded: false, facing: "north" }, apply: { model: path, y: 0, uvlock: false }, }, { when: { working: true, upgraded: false, facing: "east" }, apply: { model: path, y: 90, uvlock: false }, }, { when: { working: true, upgraded: false, facing: "south" }, apply: { model: path, y: 180, uvlock: false }, }, { when: { working: true, upgraded: false, facing: "west" }, apply: { model: path, y: -90, uvlock: false }, }, { when: { working: true, upgraded: true, facing: "north" }, apply: { model: `${path}_upgraded`, y: 0, uvlock: false }, }, { when: { working: true, upgraded: true, facing: "east" }, apply: { model: `${path}_upgraded`, y: 90, uvlock: false }, }, { when: { working: true, upgraded: true, facing: "south" }, apply: { model: `${path}_upgraded`, y: 180, uvlock: false }, }, { when: { working: true, upgraded: true, facing: "west" }, apply: { model: `${path}_upgraded`, y: -90, uvlock: false }, }, ] .concat(exclamationJson) .concat(offJson) .concat(doneJson); }; global.getTaggedBlocksInRadius = ( level, scanTag, centerPos, radius, returnTagged ) => { const { x, y, z } = centerPos; let scanBlock; let scannedBlocks = 0; let taggedBlocks = []; for (let pos of BlockPos.betweenClosed( new BlockPos(x - radius, y - radius, z - radius), [x + radius, y + radius, z + radius] )) { if (!level.isLoaded(pos)) continue; scanBlock = level.getBlock(pos); if (scanBlock.hasTag(scanTag)) { scannedBlocks++; if (returnTagged) taggedBlocks.push(scanBlock.id); } } if (returnTagged) return taggedBlocks; return scannedBlocks; }; global.setBlockEntityData = (block, nbt) => { block.setEntityData(nbt); block.getEntity().setChanged(); };