import { world, system, MinecraftBlockTypes, Vector3, MolangVariableMap, ChatSendAfterEvent, Dimension, TicksPerSecond, } from "@minecraft/server"; import { Mindkeeper, StoreType } from "./Commandeer/mindKeeper"; import Pupeteer from "./Commandeer/pupeteer"; import { Vector3ToCommandString, Vector3ToFancyString, vector3 } from "./Commandeer/utils/vectorUtils"; import { delay } from "./Commandeer/utils/waitUtil"; import { spawnParticle } from "./Commandeer/utils/particleUtils"; import { TrailMaker } from "./Commandeer/trail/trailMaker"; import * as CCTrigger from "./Commandeer/Trigger/CCTrigger"; import { Commands } from "./Commandeer/command/command"; import levelIntro from "./levels/levelIntro"; import { Trail } from "./Commandeer/trail/trailEngine"; import { startTrail } from "./trails/startTrail"; import { IntroToLevel1Trail } from "./trails/IntroToLevel1Trail"; import level1 from "./levels/level1/mission1"; import level2 from "./levels/level1/mission2"; import level3 from "./levels/level1/mission3"; // import { loadTriggers } from "./triggers"; const mindKeeper = new Mindkeeper(world); const trailMaker: TrailMaker.Maker = new TrailMaker.Maker(); const triggerManager = new CCTrigger.Manager(mindKeeper); const CURRENT_LEVEL = "currentLevel"; const AGENT_ID = "agentid"; const PREFIX = "!"; export { mindKeeper, CURRENT_LEVEL, triggerManager }; // loadTriggers(); // loadCommands(); triggerManager.RegisterFunctionTrigger("resetPath", (event) => { resetLightPath(); }); async function resetLightPath() { world.getDimension("overworld").runCommand("/fill 2467 9 87 2468 9 105 air"); } let introToGlassBreakTimer: number = 0; const glassBreakTime = 2 * TicksPerSecond; let isIntroToLevel1Sqeuence = false; let introTrail: Trail = new Trail("introTrail", 2, 4); introTrail.fromTrail(startTrail); let introToLevelTrail = new Trail("introToLevelTrail", 2, 2); introToLevelTrail.fromTrail(IntroToLevel1Trail); const DEVELOPER_MODE = true; let tickCounter = 0; system.runInterval(async () => { tickCounter++; if (mindKeeper.initialised) { trailMaker.Update(); if (tickCounter % 2 == 0) { triggerManager.Update(); } const currentLevel = mindKeeper.get(CURRENT_LEVEL); switch (currentLevel) { case 0: // Show goto airlock text Pupeteer.setActionBar("Go to the airlock"); introTrail.spawnNext(); break; case 1: Pupeteer.setActionBar("Enter the airlock"); // Show Enter airlock text break; case 2: levelIntro.update(); break; case 3: if (!isIntroToLevel1Sqeuence) { isIntroToLevel1Sqeuence = true; world.sendMessage("Intro to level1 sequence start"); await lightUpPath(); await randomExplosions(); blowUpDoor(); mindKeeper.increment(CURRENT_LEVEL); } break; case 4: introToGlassBreakTimer++; world.sendMessage("Glass break timer: " + introToGlassBreakTimer); if (introToGlassBreakTimer > glassBreakTime) { introToGlassBreakTimer = 0; mindKeeper.increment(CURRENT_LEVEL); } case 4: // Show Goto Level 1 if (glassWindowState == GlassWindowState.Fixed) { glassWindowState = GlassWindowState.Broken; system.run(async () => { world.sendMessage("Breaking glass"); await delay(10); breakGlassWindow(); mindKeeper.increment(CURRENT_LEVEL); }); } break; case 5: introToLevelTrail.spawnNext(); Pupeteer.setActionBar("Follow the path to the temple"); break; case 6: level1.update(); break; case 7: level2.update(); break; case 8: level3.update(); break; case 9: break; } } }); triggerManager.RegisterFunctionTrigger("lightPath", (event) => { lightUpPath(); }); //fill 2467 9 87 2468 9 105 redstone_block async function lightUpPath() { let overworld: Dimension = world.getDimension("overworld"); let pos1 = vector3(2467, 9, 87); let pos2 = vector3(2468, 9, 105); for (let z = pos2.z; z >= pos1.z; z--) { overworld.fillBlocks(vector3(pos1.x, pos1.y, z), vector3(pos1.x + 1, pos1.y, z), MinecraftBlockTypes.redstoneBlock); await delay(4); } // let pos2 = vector3(2468, 9, 105); } world.afterEvents.worldInitialize.subscribe(({ propertyRegistry }) => { mindKeeper.registerStore(CURRENT_LEVEL, StoreType.number); mindKeeper.registerStore(AGENT_ID, StoreType.string); // mindKeeper.set("ShowTriggers", true); triggerManager.RegisterStores(); mindKeeper.registerToWorld(propertyRegistry); triggerManager.Load(); // loadCommands(); }); world.beforeEvents.itemUseOn.subscribe((event) => { trailMaker.OnItemUse(event); triggerManager.OnItemUse(event); }); async function randomExplosions() { let pos1 = vector3(2465, 10, 82); let pos2 = vector3(2471, 18, 90); for (let i = 0; i < 5; i++) { let pos = vector3( pos1.x + Math.random() * (pos2.x - pos1.x), pos1.y + Math.random() * (pos2.y - pos1.y), pos1.z + Math.random() * (pos2.z - pos1.z) ); //create a particle system.run(() => { spawnParticle(pos, "minecraft:huge_explosion_emitter", new MolangVariableMap()); }); } } let originalDoorPos = vector3(2465, 10, 82); let closedDoorPos = vector3(2465, 10, 82); let openDoorPos = vector3(2465, 10, 82); let doorSize = vector3(7, 7, 7); ///clone 2463 -10 81 2470 -3 87 2463 10 81 ///clone 2463 -30 81 2470 -23 87 2463 10 81 function blowUpDoor() { world.sendMessage("Blowing up door"); world.getDimension("overworld").runCommand("/clone 2463 -10 81 2470 -3 87 2463 10 81"); } function restoreDoor() { world.sendMessage("Restoring door"); world.getDimension("overworld").runCommandAsync("/clone 2463 -30 81 2470 -23 87 2463 10 81"); } world.afterEvents.chatSend.subscribe(async (event: ChatSendAfterEvent) => { const command = event.message.split(" ")[0]; trailMaker.OnChat(event); mindKeeper.chatCommands(event); triggerManager.OnChat(event); if (command === "!reset") { world.sendMessage("Resetting"); mindKeeper.set(CURRENT_LEVEL, 0); restoreDoor(); resetAirLock(); restoreGlassWindow(true); resetLightPath(); levelIntro.reset(); level1.reset(); level2.reset(); //Reset the combination to a random squence isIntroToLevel1Sqeuence = false; } }); system.afterEvents.scriptEventReceive.subscribe((event) => { if (event.id == "cc:getId") { let id = event.message; world.sendMessage("Script got the id " + id); mindKeeper.set(AGENT_ID, id); } }); class ClonePos { point1: Vector3; point2: Vector3; constructor(point1: Vector3, point2: Vector3) { this.point1 = point1; this.point2 = point2; } } enum GlassWindowState { Broken, Fixed, } enum AirLockState { Open, Closed, } enum AirLockChamberState { Full, Empty, } enum ExplosiveDoorState { Closed, Open, } let glassWindowState: GlassWindowState = GlassWindowState.Fixed; let explosiveDoorState: ExplosiveDoorState = ExplosiveDoorState.Closed; const doorRoot: Vector3 = vector3(2465, 11, 94); const glassWindowClonePos: ClonePos = { point1: vector3(2465, 14, 94), point2: vector3(2470, 11, 94), }; const glassBreakingFrames: ClonePos[] = [ ///fill 2465 7 94 2470 4 94 { point1: vector3(2465, 7, 94), point2: vector3(2470, 4, 94), }, //fill 2465 0 94 2470 -3 94 { point1: vector3(2465, 0, 94), point2: vector3(2470, -3, 94), }, { //fill 2465 -7 94 2470 -10 94 point1: vector3(2465, -7, 94), point2: vector3(2470, -10, 94), }, //fill 2465 -14 94 2470 -17 94 { point1: vector3(2465, -14, 94), point2: vector3(2470, -17, 94), }, //fill 2465 -21 94 2470 -24 94 { point1: vector3(2465, -21, 94), point2: vector3(2470, -24, 94), }, ]; const crackedGlass: string = "cc:cracked_glass"; Commands.register(PREFIX, "breakGlass", (arg) => { breakGlassWindow(); glassWindowState = GlassWindowState.Broken; }); Commands.register(PREFIX, "restoreGlass", (arg) => { restoreGlassWindow(); glassWindowState = GlassWindowState.Fixed; }); async function breakGlassWindow() { playAnimation(glassBreakingFrames, 5, false, doorRoot); glassWindowState = GlassWindowState.Broken; } async function restoreGlassWindow(force: boolean = false) { playAnimation(glassBreakingFrames, 5, true, doorRoot, force); } const FrontAirLockOpenFrames: ClonePos[] = [ { point1: vector3(2476, 9, 94), point2: vector3(2474, 7, 94), }, { point1: vector3(2476, 5, 94), point2: vector3(2474, 3, 94), }, { point1: vector3(2476, 1, 94), point2: vector3(2474, -1, 94), }, { point1: vector3(2476, -3, 94), point2: vector3(2474, -5, 94), }, ]; const BackAirLockOpenFrames: ClonePos[] = [ { point1: vector3(2472, 9, 100), point2: vector3(2472, 7, 102), }, { point1: vector3(2472, 5, 100), point2: vector3(2472, 3, 102), }, { point1: vector3(2472, 1, 100), point2: vector3(2472, -1, 102), }, { point1: vector3(2472, -3, 100), point2: vector3(2472, -5, 102), }, ]; const AirLockWaterFrames: ClonePos[] = [ { point1: vector3(2473, 11, 95), point2: vector3(2477, 11, 103), }, { point1: vector3(2473, 12, 95), point2: vector3(2477, 12, 103), }, { point1: vector3(2473, 13, 95), point2: vector3(2477, 13, 103), }, { point1: vector3(2473, 14, 95), point2: vector3(2477, 14, 103), }, ]; async function CycleAirLockWater(fill: boolean, delayTime: number) { if (animationPlaying) { world.sendMessage("Animation already playing"); return; } animationPlaying = true; let frameCount = AirLockWaterFrames.length; for (let i = 0; i < frameCount; i++) { let frame = fill ? AirLockWaterFrames[i] : AirLockWaterFrames[frameCount - i - 1]; let blockToFill = fill ? "minecraft:water" : "minecraft:air"; await world .getDimension("overworld") .runCommandAsync( `/fill ${Vector3ToCommandString(frame.point1)} ${Vector3ToCommandString(frame.point2)} ${blockToFill}` ); await delay(delayTime); } animationPlaying = false; } let frontAirlockState: AirLockState = AirLockState.Closed; let backAirlockState: AirLockState = AirLockState.Closed; let chamberState: AirLockChamberState = AirLockChamberState.Full; //The airlock sequence is //Player enters FrontAirLockOutside //Front door opens triggerManager.RegisterFunctionTrigger("FrontAirLockOutside", async (event) => { if (chamberState == AirLockChamberState.Empty) { world.sendMessage("Filling airlock"); await FillAirlockWater(); chamberState = AirLockChamberState.Full; } if (frontAirlockState == AirLockState.Closed) { await PlayFrontDoorOpenAnimation(); frontAirlockState = AirLockState.Open; } }); triggerManager.RegisterFunctionTrigger("TempleFrontDoor", async (event) => { if (mindKeeper.get(CURRENT_LEVEL) == 5) { mindKeeper.increment(CURRENT_LEVEL); } }); //Player enters FrontAirLockInside //Front door closes //Water drains //Back door opens triggerManager.RegisterFunctionTrigger("FrontAirLockInside", async (event) => { if (frontAirlockState == AirLockState.Open) { await PlayFrontDoorCloseAnimation(); frontAirlockState = AirLockState.Closed; } if (chamberState == AirLockChamberState.Full) { await delay(7); await EmptyAirlockWater(); chamberState = AirLockChamberState.Empty; } if (backAirlockState == AirLockState.Closed) { await delay(7); await PlayBackDoorOpenAnimation(); backAirlockState = AirLockState.Open; } }); //Player enters BackAirLockOutside //Back door closes triggerManager.RegisterFunctionTrigger("BackAirLockOutside", async (event) => { if (backAirlockState == AirLockState.Open) { world.sendMessage("Closing back door"); await PlayBackDoorCloseAnimation(); backAirlockState = AirLockState.Closed; } }); // function loadCommands() { Commands.register(PREFIX, "fien", (arg) => { system.run(() => { arg.player.teleport(vector3(2468, 11, 114)); }); }); Commands.register(PREFIX, "info", (arg) => { world.sendMessage("-----------------"); world.sendMessage("Current level: " + mindKeeper.get(CURRENT_LEVEL)); world.sendMessage("Agent ID: " + mindKeeper.get(AGENT_ID)); world.sendMessage("Engine Version: 1.0.2"); world.sendMessage("Engine is running"); world.sendMessage("Active players: " + world.getPlayers().length); world.sendMessage("Current dimension: " + arg.player.dimension.id); world.sendMessage("Current position: " + Vector3ToFancyString(arg.player.location)); world.sendMessage("-----------------"); }); Commands.register(PREFIX, "kboom", (arg) => { (async () => { for (let i = 0; i < 10; i++) { randomExplosions(); await delay(1); } blowUpDoor(); })(); }); Commands.register(PREFIX, "restore", (arg) => { restoreDoor(); }); function resetAirLock() { SetFrontDoorClosed(); SetBackDoorClosed(); FillAirlockWater(); frontAirlockState = AirLockState.Closed; backAirlockState = AirLockState.Closed; chamberState = AirLockChamberState.Full; glassWindowState = GlassWindowState.Fixed; } Commands.register(PREFIX, "resetAirlock", (arg) => resetAirLock); let frontDoorRoot: Vector3 = vector3(2474, 11, 94); let backDoorRoot: Vector3 = vector3(2472, 11, 100); const frameDuration = 7; let SetFrontDoorClosed = () => SetFrame(FrontAirLockOpenFrames[0], frontDoorRoot); let SetFrontDoorOpen = () => SetFrame(FrontAirLockOpenFrames[FrontAirLockOpenFrames.length - 1], frontDoorRoot); let PlayFrontDoorOpenAnimation = async () => { playAnimation(FrontAirLockOpenFrames, frameDuration, false, frontDoorRoot); if (mindKeeper.get(CURRENT_LEVEL) == 0) { mindKeeper.increment(CURRENT_LEVEL); } }; let PlayFrontDoorCloseAnimation = async () => playAnimation(FrontAirLockOpenFrames, frameDuration, true, frontDoorRoot); let SetBackDoorClosed = () => SetFrame(BackAirLockOpenFrames[0], backDoorRoot); let SetBackDoorOpen = () => SetFrame(BackAirLockOpenFrames[BackAirLockOpenFrames.length - 1], backDoorRoot); let PlayBackDoorOpenAnimation = async () => playAnimation(BackAirLockOpenFrames, frameDuration, false, backDoorRoot); let PlayBackDoorCloseAnimation = async () => playAnimation(BackAirLockOpenFrames, frameDuration, true, backDoorRoot); let FillAirlockWater = async () => CycleAirLockWater(true, frameDuration / 1.5); let EmptyAirlockWater = async () => { await CycleAirLockWater(false, frameDuration / 1.5); if (mindKeeper.get(CURRENT_LEVEL) == 1) { mindKeeper.increment(CURRENT_LEVEL); } }; triggerManager.RegisterFunctionTrigger("openFrontDoor", (event) => PlayFrontDoorOpenAnimation()); triggerManager.RegisterFunctionTrigger("closeFrontDoor", (event) => PlayFrontDoorCloseAnimation()); triggerManager.RegisterFunctionTrigger("openBackDoor", (event) => PlayBackDoorOpenAnimation()); triggerManager.RegisterFunctionTrigger("closeBackDoor", (event) => PlayBackDoorCloseAnimation()); triggerManager.RegisterFunctionTrigger("fillAirlock", (event) => FillAirlockWater()); triggerManager.RegisterFunctionTrigger("emptyAirlock", (event) => EmptyAirlockWater()); async function SetFrame(frame: ClonePos, destination: Vector3) { await world .getDimension("overworld") .runCommandAsync( `/clone ${Vector3ToCommandString(frame.point1)} ${Vector3ToCommandString(frame.point2)} ${Vector3ToCommandString( destination )}` ); } let animationPlaying = false; async function playAnimation( frames: ClonePos[], delayTime: number, reverse: boolean, destination: Vector3, force: boolean = false ) { if (animationPlaying && !force) { world.sendMessage("Animation already playing"); return; } let frameCount = frames.length; if (!force) { animationPlaying = true; } for (let i = 0; i < frameCount; i++) { let frame = reverse ? frames[frameCount - i - 1] : frames[i]; await world .getDimension("overworld") .runCommandAsync( `/clone ${Vector3ToCommandString(frame.point1)} ${Vector3ToCommandString( frame.point2 )} ${Vector3ToCommandString(destination)}` ); await delay(delayTime); } if (!force) { animationPlaying = false; } } system.afterEvents.scriptEventReceive.subscribe((event) => { if (event.id == "cc:getId") { let id = event.message; world.sendMessage("Script got the id " + id); mindKeeper.set(AGENT_ID, id); } });