465 lines
No EOL
14 KiB
JavaScript
465 lines
No EOL
14 KiB
JavaScript
// priority: 0
|
|
"use strict";
|
|
|
|
const JsonObject = Java.loadClass('com.google.gson.JsonObject');
|
|
const JsonArray = Java.loadClass('com.google.gson.JsonArray');
|
|
const JsonParser = Java.loadClass('com.google.gson.JsonParser');
|
|
const JsonElement = Java.loadClass('com.google.gson.JsonElement');
|
|
|
|
// Helper to call `JsonArray.add(JsonElement)` explicitly because "Rhino Moment".
|
|
const addJsonElement = (jsonArray, jsonElement) => {
|
|
jsonArray.getClass().getMethod("add", JsonElement).invoke(jsonArray, jsonElement);
|
|
};
|
|
|
|
//#region Mixer Recipes
|
|
/**
|
|
* Function for generating gtceu mixer recipes.
|
|
* Adding a circuit is optional.
|
|
*
|
|
* @param {*} event
|
|
* @param {string} input -Item
|
|
* @param {string} fluid_input -Fluid
|
|
* @param {string} output -Item
|
|
* @param {number} circuit -0-32
|
|
* @param {string} fluid_output -Fluid
|
|
* @param {number} duration -Ticks
|
|
* @param {number} EUt -GTValues.VA[]
|
|
* @param {number} rpm -Depreciated
|
|
* @param {string} id -Recipe ID
|
|
*/
|
|
const generateMixerRecipe = (event, input, fluid_input, output, circuit, fluid_output, duration, EUt, rpm, id) => {
|
|
const recipe = event.recipes.gtceu.mixer(id)
|
|
.itemInputs(input)
|
|
.inputFluids(fluid_input)
|
|
.itemOutputs(output)
|
|
.outputFluids(fluid_output)
|
|
.duration(duration)
|
|
.EUt(EUt)
|
|
|
|
/**
|
|
* Applies if circuit param is not empty
|
|
*/
|
|
if (circuit !== null) {
|
|
recipe.circuit(circuit)
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//#region Cutter Recipes
|
|
/**
|
|
* Function for generating gtceu cutter recipes.
|
|
*
|
|
* @param {*} event
|
|
* @param {string} input -Item
|
|
* @param {string} output -Item
|
|
* @param {number} duration -Ticks
|
|
* @param {number} EUt -GTValues.VA[]
|
|
* @param {string} id -Recipe ID
|
|
*/
|
|
const generateCutterRecipe = (event, input, output, duration, EUt, id) => {
|
|
event.recipes.gtceu.cutter(`tfg:${id}`)
|
|
.itemInputs(input)
|
|
.itemOutputs(output)
|
|
.duration(duration)
|
|
.EUt(EUt)
|
|
}
|
|
|
|
//#endregion
|
|
|
|
//#region forEachMaterial
|
|
/**
|
|
* Function for iterating through registered materials
|
|
* {@link https://github.com/GregTechCEu/GregTech-Modern/blob/1.20.1/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/Material.java}
|
|
*
|
|
* @param {(material: com.gregtechceu.gtceu.api.data.chemical.material.Material_) => void} iterator
|
|
*/
|
|
function forEachMaterial(iterator) {
|
|
for (const material of GTCEuAPI.materialManager.getRegisteredMaterials()) {
|
|
iterator(material)
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//#region Add Circuit
|
|
/**
|
|
* Function for adding circuit numbers for existing recipes
|
|
* 1) Preserves existing `inputs.item` entries.
|
|
* 2) Adds a circuit entry to the `inputs.item` array.
|
|
* 3) If `inputs.item` is missing, create it.
|
|
* 4) If a circuit already exists, update its number.
|
|
*
|
|
* Constants {@link global.ADD_CIRCUIT}
|
|
*
|
|
* @param {*} event
|
|
* @param {string} recipeId -Recipe ID
|
|
* @param {number} circuitNumber -0-32
|
|
*/
|
|
function addCircuitToRecipe(event, recipeId, circuitNumber) {
|
|
|
|
event.findRecipes({ id: recipeId }).forEach(recipe => {
|
|
const inputsEl = recipe.json.get("inputs");
|
|
let inputsObj;
|
|
if (inputsEl === null || inputsEl.isJsonNull()) {
|
|
inputsObj = new JsonObject();
|
|
} else if (inputsEl.isJsonObject()) {
|
|
inputsObj = inputsEl.getAsJsonObject();
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
// Cache existing item inputs.
|
|
const itemEl = inputsObj.get("item");
|
|
let itemArray;
|
|
if (itemEl === null || itemEl === undefined || itemEl.isJsonNull()) {
|
|
itemArray = new JsonArray();
|
|
} else if (itemEl.isJsonArray()) {
|
|
itemArray = itemEl.getAsJsonArray();
|
|
} else if (itemEl.isJsonObject()) {
|
|
itemArray = new JsonArray();
|
|
addJsonElement(itemArray, JsonParser.parseString(itemEl.getAsJsonObject().toString()));
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
// Build circuit entry as a JsonElement using JsonParser.
|
|
const circuitElement = JsonParser.parseString(JSON.stringify({
|
|
content: { type: "gtceu:circuit", configuration: circuitNumber },
|
|
chance: 0,
|
|
maxChance: 10000,
|
|
tierChanceBoost: 0
|
|
}));
|
|
|
|
// Dont duplicate circuit if one already exists.
|
|
// If it exists, just update it.
|
|
let hasCircuit = false;
|
|
for (let i = 0; i < itemArray.size(); i++) {
|
|
const el = itemArray.get(i);
|
|
if (!el.isJsonObject()) { continue; }
|
|
const obj = el.getAsJsonObject();
|
|
const content = obj.get("content");
|
|
if (content && content.isJsonObject()) {
|
|
const typeEl = content.getAsJsonObject().get("type");
|
|
if (typeEl && typeEl.isJsonPrimitive() && typeEl.getAsString() === "gtceu:circuit") {
|
|
hasCircuit = true;
|
|
content.getAsJsonObject().addProperty("configuration", circuitNumber);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasCircuit) {
|
|
addJsonElement(itemArray, circuitElement);
|
|
}
|
|
|
|
inputsObj.add("item", itemArray);
|
|
recipe.json.add("inputs", inputsObj);
|
|
});
|
|
}
|
|
//#endregion
|
|
|
|
//#region Wood Builder
|
|
|
|
/**
|
|
* Generates most basic wooden recipes.
|
|
*
|
|
* All parameters are optional. Name is used for the ID.
|
|
*
|
|
* @param {*} event
|
|
* @param {string} name -Name of the wood.
|
|
* @param {string} lumber -ID for the lumber.
|
|
* @param {string} logs -Tag or ID for all the logs.
|
|
* @param {string} log -ID for the regular log.
|
|
* @param {string} stripped_log -ID for the stripped log.
|
|
* @param {string} plank -ID for planks.
|
|
* @param {string} stair -ID for stairs.
|
|
* @param {string} slab -ID for slabs.
|
|
* @param {string} door -ID for the door.
|
|
* @param {string} trapdoor -ID for the trapdoor.
|
|
* @param {string} fence -ID for the fence.
|
|
* @param {string} fence_gate -ID for the fence gate.
|
|
* @param {string} support -ID for the support.
|
|
* @param {string} pressure_plate -ID for the pressure plate.
|
|
* @param {string} button -ID for the button.
|
|
*/
|
|
function woodBuilder(event, name, lumber, logs, log, stripped_log, plank, stair, slab, door, trapdoor, fence, fence_gate, support, pressure_plate, button) {
|
|
|
|
if (log && stripped_log && name) {
|
|
event.recipes.gtceu.lathe(`tfg:cutter/${name}_stripped_log_from_log`)
|
|
.itemInputs(log)
|
|
.itemOutputs(stripped_log)
|
|
.duration(50)
|
|
.EUt(GTValues.VA[GTValues.ULV])
|
|
|
|
event.recipes.vintageimprovements.polishing(stripped_log, log)
|
|
.speedLimits(0)
|
|
.processingTime(50 * global.VINTAGE_IMPROVEMENTS_DURATION_MULTIPLIER)
|
|
.id(`tfg:vi/lathe/stripping_${name}_log`)
|
|
}
|
|
|
|
if (logs && lumber && name) {
|
|
event.shapeless(`8x ${lumber}`,
|
|
[logs, '#forge:tools/saws']
|
|
).id(`tfg:shapeless/${name}_lumber_from_log`)
|
|
|
|
generateCutterRecipe(event, logs, `16x ${lumber}`, 50, 7, `cutter_${name}_lumber_from_log`)
|
|
}
|
|
|
|
if (plank && lumber && name) {
|
|
event.shapeless(`4x ${lumber}`,
|
|
[plank, '#forge:tools/saws']
|
|
).id(`tfg:shapeless/${name}_lumber_from_plank`)
|
|
|
|
generateCutterRecipe(event, plank, `4x ${lumber}`, 50, 7, `cutter_${name}_lumber_from_plank`)
|
|
|
|
event.shaped(plank, [
|
|
'AA',
|
|
'AA'
|
|
], {
|
|
A: lumber
|
|
}).id(`tfg:shaped/${name}_plank_from_lumber`)
|
|
}
|
|
|
|
if (slab && lumber && name) {
|
|
event.shapeless(`2x ${lumber}`,
|
|
[slab, '#forge:tools/saws']
|
|
).id(`tfg:shapeless/${name}_lumber_from_slab`)
|
|
|
|
generateCutterRecipe(event, slab, `2x ${lumber}`, 50, 7, `cutter_${name}_lumber_from_slab`)
|
|
}
|
|
|
|
if (slab && plank && name) {
|
|
event.shaped(`6x ${slab}`, [
|
|
'AAA'
|
|
], {
|
|
A: plank
|
|
}).id(`tfg:shaped/${name}_slab_from_plank`)
|
|
}
|
|
|
|
if (stair && lumber && name) {
|
|
event.shapeless(`3x ${lumber}`,
|
|
[stair, '#forge:tools/saws']
|
|
).id(`tfg:shapeless/${name}_lumber_from_stair`)
|
|
|
|
generateCutterRecipe(event, stair, `3x ${lumber}`, 50, 7, `cutter_${name}_lumber_from_stair`)
|
|
}
|
|
|
|
if (stair && plank && name) {
|
|
event.shaped(`8x ${stair}`, [
|
|
'A ',
|
|
'AA ',
|
|
'AAA'
|
|
], {
|
|
A: plank
|
|
}).id(`tfg:shaped/${name}_stair_from_plank`)
|
|
}
|
|
|
|
if (door && lumber && name) {
|
|
event.shaped(`2x ${door}`, [
|
|
'AA',
|
|
'AA',
|
|
'AA'
|
|
], {
|
|
A: lumber
|
|
}).id(`tfg:shaped/${name}_door_from_lumber`)
|
|
}
|
|
|
|
if (trapdoor && lumber && name) {
|
|
event.shaped(`3x ${trapdoor}`, [
|
|
'AAA',
|
|
'AAA'
|
|
], {
|
|
A: lumber
|
|
}).id(`tfg:shaped/${name}_trapdoor_from_lumber_and_plank`)
|
|
}
|
|
|
|
if (fence && lumber && plank && name) {
|
|
event.shaped(`8x ${fence}`, [
|
|
'ABA',
|
|
'ABA'
|
|
], {
|
|
A: lumber,
|
|
B: plank
|
|
}).id(`tfg:shaped/${name}_fence_from_lumber_and_plank`)
|
|
}
|
|
|
|
if (fence_gate && lumber && plank && name) {
|
|
event.shaped(`2x ${fence_gate}`, [
|
|
'ABA',
|
|
'ABA'
|
|
], {
|
|
A: plank,
|
|
B: lumber
|
|
}).id(`tfg:shaped/${name}_fence_gate_from_lumber_and_plank`)
|
|
}
|
|
|
|
if (support && logs && name) {
|
|
event.shapeless(`8x ${support}`,
|
|
[`2x ${logs}`, '#forge:tools/saws']
|
|
).id(`tfg:shapeless/${name}_support_from_logs`)
|
|
|
|
event.recipes.gtceu.assembler(`tfg:assembler/${name}_support_from_logs`)
|
|
.itemInputs(`2x ${logs}`)
|
|
.itemOutputs(`8x ${support}`)
|
|
.duration(50)
|
|
.circuit(4)
|
|
.EUt(GTValues.VA[GTValues.ULV])
|
|
}
|
|
|
|
if (pressure_plate && slab && name) {
|
|
event.shaped(pressure_plate, [
|
|
' B ',
|
|
'ACA',
|
|
' D '
|
|
], {
|
|
A: slab,
|
|
B: '#forge:tools/hammers',
|
|
C: '#forge:springs',
|
|
D: '#forge:tools/screwdrivers'
|
|
}).id(`tfg:shaped/${name}_pressure_plate`)
|
|
|
|
event.recipes.gtceu.assembler(`tfg:assembler/${name}_pressure_plate`)
|
|
.itemInputs(`2x ${slab}`, '#forge:small_springs')
|
|
.itemOutputs(`2x ${pressure_plate}`)
|
|
.duration(50)
|
|
.circuit(3)
|
|
.EUt(GTValues.VA[GTValues.ULV])
|
|
}
|
|
|
|
if (button && pressure_plate && name) {
|
|
event.recipes.gtceu.cutter(`tfg:cutter/${name}_button_from_pressure_plate`)
|
|
.itemInputs(pressure_plate)
|
|
.itemOutputs(`6x ${button}`)
|
|
.duration(50)
|
|
.EUt(GTValues.VA[GTValues.ULV])
|
|
|
|
event.shapeless(`3x ${button}`, [pressure_plate, '#forge:tools/saws'])
|
|
.id(`tfg:shapeless/saw_${name}_pressure_plate_to_button`)
|
|
}
|
|
}
|
|
//#endregion
|
|
|
|
//#region Sterilization
|
|
/**
|
|
* Creates recipes for sterilizing an item using chemicals or the autoclave.
|
|
*
|
|
* @param {*} event
|
|
* @param {string} input - The input item to be sterilized.
|
|
* @param {string} output - The output item after sterilization.
|
|
* @param {number} multiplier - Multiplies the fluid amounts and recipe duration. Default multiplier = 1.
|
|
* @param {string} [cleanroom] - For if a cleanroom is required. Can be null.
|
|
*
|
|
* @throws {TypeError} Throws an error if input, output, or multiplier is invalid.
|
|
*/
|
|
function sterilizeItem(event, input, output, multiplier, cleanroom) {
|
|
// Collect errors.
|
|
const errors = [];
|
|
|
|
if (input === undefined || (Array.isArray(input) && input.length !== 1) || output === undefined || (Array.isArray(output) && output.length !== 1)) {
|
|
errors.push("input or output is undefined or not equal to one item");
|
|
};
|
|
if (multiplier <= 0) {
|
|
errors.push(`invalid multiplier (${multiplier})`);
|
|
};
|
|
|
|
// If there are any errors, log them all and throw once.
|
|
if (errors.length > 0) {
|
|
const message = `sterilizeItem errors:\n - ${errors.join("\n - ")}`;
|
|
throw new TypeError(message);
|
|
};
|
|
|
|
// Set default multiplier.
|
|
let recipe_multiplier = 1;
|
|
if (multiplier !== undefined) {
|
|
recipe_multiplier = multiplier;
|
|
}
|
|
|
|
// Create recipes.
|
|
const ethanol_recipe = event.recipes.gtceu.chemical_bath(`tfg:ethanol_cleaning/${linuxUnfucker(input)}_to_${linuxUnfucker(output)}`)
|
|
.itemInputs(input)
|
|
.inputFluids(Fluid.of('gtceu:ethanol', 500 * recipe_multiplier))
|
|
.itemOutputs(output)
|
|
.duration(10 * 20 * recipe_multiplier)
|
|
.EUt(GTValues.VA[GTValues.MV]);
|
|
|
|
const hydrogen_peroxide_recipe = event.recipes.gtceu.chemical_bath(`tfg:hydrogen_peroxide_cleaning/${linuxUnfucker(input)}_to_${linuxUnfucker(output)}`)
|
|
.itemInputs(input)
|
|
.inputFluids(Fluid.of('gtceu:hydrogen_peroxide', 200 * recipe_multiplier))
|
|
.itemOutputs(output)
|
|
.duration(10 * 20 * recipe_multiplier)
|
|
.EUt(GTValues.VA[GTValues.MV]);
|
|
|
|
const sodium_dodecyl_sulfate_recipe = event.recipes.gtceu.chemical_bath(`tfg:sodium_dodecyl_sulfate_cleaning/${linuxUnfucker(input)}_to_${linuxUnfucker(output)}`)
|
|
.itemInputs(input)
|
|
.inputFluids(Fluid.of('tfg:sodium_dodecyl_sulfate', 50 * recipe_multiplier))
|
|
.itemOutputs(output)
|
|
.duration(10 * 20 * recipe_multiplier)
|
|
.EUt(GTValues.VA[GTValues.MV]);
|
|
|
|
const autoclave_recipe = event.recipes.gtceu.autoclave(`tfg:autoclave_cleaning/${linuxUnfucker(input)}_to_${linuxUnfucker(output)}`)
|
|
.itemInputs(input)
|
|
.perTick(true)
|
|
.inputFluids(Fluid.of('gtceu:steam', 100 * recipe_multiplier))
|
|
.perTick(false)
|
|
.itemOutputs(output)
|
|
.duration(240 * 20 * recipe_multiplier)
|
|
.EUt(GTValues.VA[GTValues.MV]);
|
|
|
|
if (cleanroom) {
|
|
ethanol_recipe.cleanroom(cleanroom);
|
|
hydrogen_peroxide_recipe.cleanroom(cleanroom);
|
|
sodium_dodecyl_sulfate_recipe.cleanroom(cleanroom);
|
|
autoclave_recipe.cleanroom(cleanroom);
|
|
};
|
|
};
|
|
|
|
//#endregion
|
|
//#region Cleanroom Tool
|
|
|
|
/**
|
|
* Ensures recipes have a cleanroom recipe condition set to the specified type.
|
|
*
|
|
* * For each recipe:
|
|
* * * If `recipeConditions` is an array, finds an object with `type` === `cleanroom`.
|
|
* * * If found, updates its `cleanroom` property to the given `cleanroomType`.
|
|
* * * If not found, appends a new condition object `{ type: "cleanroom", cleanroom: cleanroomType }` to the array.
|
|
* * * If `recipeConditions` is absent or not an array, creates a new JSON array containing the cleanroom condition.
|
|
*
|
|
* @throws This function will not work with other recipe conditions present besides `CleanroomType`.
|
|
*
|
|
* @param {event} event
|
|
* @param {string} recipeId - recipe ID.
|
|
* @param {'cleanroom'|'sterile_cleanroom'} cleanroomType - Cleanroom type to be assigned.
|
|
*/
|
|
function addCleanroom(event, recipeId, cleanroomType) {
|
|
event.findRecipes({ id: recipeId }).forEach(recipe => {
|
|
// Ensure recipe has a cleanroom condition matching the cleanroomType string.
|
|
// Replace existing cleanroom condition or add new one if absent.
|
|
const desiredCleanroom = cleanroomType;
|
|
const conditions = recipe.json.get("recipeConditions");
|
|
let conditionArray;
|
|
if (conditions && conditions.isJsonArray && conditions.isJsonArray()) {
|
|
conditionArray = conditions.getAsJsonArray();
|
|
} else {
|
|
conditionArray = new JsonArray();
|
|
recipe.json.add("recipeConditions", conditionArray);
|
|
}
|
|
|
|
let hasCleanroom = false;
|
|
for (let i = 0; i < conditionArray.size(); i++) {
|
|
let element = conditionArray.get(i).getAsJsonObject();
|
|
if (element.has("type") && element.get("type").getAsString() === "cleanroom") {
|
|
element.addProperty("cleanroom", desiredCleanroom);
|
|
hasCleanroom = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!hasCleanroom) {
|
|
let cond = new JsonObject();
|
|
cond.addProperty("type", "cleanroom");
|
|
cond.addProperty("cleanroom", desiredCleanroom);
|
|
addJsonElement(conditionArray, cond);
|
|
}
|
|
});
|
|
};
|
|
|
|
//#endregion
|