import { world, system, Vector3, MolangVariableMap, ChatSendAfterEvent, Dimension, BlockVolume, ScriptEventCommandMessageAfterEvent, } from "@minecraft/server"; import { Mindkeeper, StoreType } from "./Commandeer/mindKeeper"; import Pupeteer from "./Commandeer/pupeteer"; import { Vector3Add, Vector3Subtract, Vector3ToCommandString, Vector3ToFancyString, vector3, } from "./Commandeer/utils/vectorUtils"; import { delay } from "./Commandeer/utils/waitUtil"; import { ParticleColumn, PARTICLES, 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 { MinecraftBlockTypes } from "./vanilla-data/mojang-block"; import mission1part1 from "./levels/mission1/mission1part1"; import mission1part2 from "./levels/mission1/mission1part2"; import mission1part3 from "./levels/mission1/mission1part3"; import mission2part1 from "./levels/mission2/mission2part1"; import mission2part2 from "./levels/mission2/mission2part2"; // eslint-disable-next-line @typescript-eslint/no-unused-vars import Chalk from "./Commandeer/chalk"; import mission3part1 from "./levels/mission3/mission3part1"; import mission3part2 from "./levels/mission3/mission3part2"; import mission3part3 from "./levels/mission3/mission3part3"; import { runEntityEventOnTag, setNPCDialog } from "./Commandeer/utils/entityUtils"; import { animationPlaying, playAnimation, setAmimationPlaying, SetFrame } from "./Commandeer/animations/animation"; import { doNothingStupidTSIWantFilesNotAGiantAssMainFile } from "./triggers"; import { fillWall, startLevel, Wall } from "./Commandeer/utils/levelUtils"; import { drawArrow } from "./Commandeer/utils/arrow"; import { glassBreakingFrames, AirLockWaterFrames, FrontAirLockOpenFrames, BackAirLockOpenFrames, } from "./animationFrames"; // 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 = "!"; let DEVELOPER_MODE = true; export { mindKeeper, CURRENT_LEVEL, triggerManager, PREFIX, DEVELOPER_MODE }; // loadTriggers(); // loadCommands(); triggerManager.RegisterFunctionTrigger("resetPath", () => { resetLightPath(); }); async function resetLightPath() { world.getDimension("overworld").runCommand("/fill 2467 9 87 2468 9 105 air"); } let isIntroToLevel1Sqeuence = false; const introTrail: Trail = new Trail("introTrail", 2, 25 / 5); introTrail.fromTrail(startTrail); const introToLevelTrail = new Trail("introToLevelTrail", 2, 74 / 2); introToLevelTrail.fromTrail(IntroToLevel1Trail); //fill 2466 0 48 2469 -1 48 const bilalBlock: Wall = { startPos: vector3(2466, 0, 48), endPos: vector3(2469, -1, 48), }; // spawn a sphere of particle let prevCurrentLevel: number = 0; let isBreaking: boolean = false; const airlockParticles = new ParticleColumn(vector3(2475.5, 10, 92), 2, 2, 3, 0.5, PARTICLES.point); const level1Particles = new ParticleColumn(vector3(2455, -1, 49), 1.1, 2, 4, 0.7, PARTICLES.balloon_gas_particle); airlockParticles.generatePoints(); level1Particles.generatePoints(); let tickCounter = 0; system.runInterval(() => { tickCounter++; if (mindKeeper.initialised) { trailMaker.Update(); if (tickCounter % 2 == 0) { triggerManager.Update(); } const currentLevel = mindKeeper.get(CURRENT_LEVEL); if (prevCurrentLevel != currentLevel) { world.sendMessage("Current level: " + currentLevel); prevCurrentLevel = mindKeeper.get(CURRENT_LEVEL) as number; } switch (currentLevel) { case 0: // Show goto airlock text Pupeteer.setActionBar("%message.goto.airlock"); introTrail.spawnNext(); drawArrow(vector3(2478, 37, 89)); airlockParticles.update(); airlockParticles.draw(); break; case 1: Pupeteer.setActionBar("%message.enter.airlock"); break; case 2: Pupeteer.setActionBar("%message.talkto.chanel"); //Wait for the scriptevent cc:startIntro break; case 3: levelIntro.update(); break; case 4: (async () => { if (!isIntroToLevel1Sqeuence) { isIntroToLevel1Sqeuence = true; // world.sendMessage("Intro to level1 sequence start"); await lightUpPath(); await randomExplosions(); blowUpDoor(); triggerAlarm(); mindKeeper.increment(CURRENT_LEVEL); } })(); break; case 5: mindKeeper.increment(CURRENT_LEVEL); break; case 6: // Show Goto Level 1 if (isBreaking == false) { isBreaking = true; if (glassWindowState == GlassWindowState.Fixed) { glassWindowState = GlassWindowState.Broken; system.run(async () => { if (DEVELOPER_MODE) { world.sendMessage("Breaking glass"); } await delay(10); await breakGlassWindow(); mindKeeper.increment(CURRENT_LEVEL); }); } } break; case 7: introToLevelTrail.spawnNext(); Pupeteer.setActionBar("%message.follow.path.temple"); //Talk to Bilal break; case 8: Pupeteer.setActionBar("%message.goto.temple"); //Talk to Suki break; case 9: level1Particles.update(); level1Particles.draw(); Pupeteer.setActionBar("%message.goto.level1"); break; case 10: mission1part1.update(); break; case 11: mission1part2.update(); break; case 12: mission1part3.update(); //Agent is back with player break; case 13: setNPCDialog("suki1", "suki_afterlevel_1_1"); Pupeteer.setActionBar("%message.talkto.suki"); break; case 14: mission2part1.update(); break; case 15: //Talk to suki setNPCDialog("suki1", "suki_afterlevel_2_1_intermezzo"); Pupeteer.setActionBar("%message.talkto.suki"); break; case 16: mission2part2.update(); break; case 17: // Mission 2 is complete setNPCDialog("suki1", "suki_afterlevel_2_1"); Pupeteer.setActionBar("%message.talkto.suki"); break; case 18: mission3part1.update(); break; case 19: mission3part2.update(); break; case 20: mission3part3.update(); break; case 21: //talk to suki setNPCDialog("suki1", "suki_afterlevel_3_1"); setNPCDialog("bilal1", "bilal_end_1"); Pupeteer.setActionBar("%message.talkto.suki"); break; case 22: Pupeteer.setActionBar("%message.goto.door"); //wait for player to enter trigger break; case 23: Pupeteer.setActionBar("%message.goto.bilal"); setNPCDialog("bilal1", "bilal_end_1"); break; } } }); triggerManager.RegisterFunctionTrigger("lightPath", () => { lightUpPath(); }); Commands.register(PREFIX, "k3isgeweldig", () => { world.sendMessage("K3 is geweldig! - Bram"); DEVELOPER_MODE = true; }); //fill 2467 9 87 2468 9 105 redstone_block async function lightUpPath() { const overworld: Dimension = world.getDimension("overworld"); const pos1 = vector3(2467, 9, 87); const pos2 = vector3(2468, 9, 105); for (let z = pos2.z; z >= pos1.z; z--) { const volume: BlockVolume = new BlockVolume(vector3(pos1.x, pos1.y, z), vector3(pos1.x + 1, pos1.y, z)); overworld.fillBlocks(volume, MinecraftBlockTypes.RedstoneBlock); await delay(4); } // let pos2 = vector3(2468, 9, 105); } const triggerAlarm = () => runEntityEventOnTag("alarmLights", "cc:add_rotating"); const resetAlarm = () => runEntityEventOnTag("alarmLights", "cc:remove_rotating"); world.afterEvents.worldInitialize.subscribe(() => { mindKeeper.registerStore(CURRENT_LEVEL, StoreType.number); mindKeeper.registerStore(AGENT_ID, StoreType.string); // mindKeeper.set("ShowTriggers", true); triggerManager.RegisterStores(); mindKeeper.registerToWorld(); triggerManager.Load(); doNothingStupidTSIWantFilesNotAGiantAssMainFile(); // loadCommands(); }); world.beforeEvents.itemUseOn.subscribe((event) => { trailMaker.OnItemUse(event); triggerManager.OnItemUse(event); }); async function randomExplosions() { const pos1 = vector3(2465, 10, 82); const pos2 = vector3(2471, 18, 90); for (let i = 0; i < 5; i++) { const 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()); }); } } function blowUpDoor() { if (DEVELOPER_MODE) { world.sendMessage("Blowing up door"); } world.getDimension("overworld").runCommand("/clone 2463 -10 81 2470 -3 87 2463 10 81"); } function restoreDoor() { if (DEVELOPER_MODE) { 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(); mission1part1.reset(); mission1part2.reset(); mission1part3.reset(); mission2part1.reset(); mission2part2.reset(); //Set redstone block startLevel(vector3(2456, -1, 4)); startLevel(vector3(2457, -1, 4)); //Reset the combination to a random squence resetAlarm(); deactivateAirlockLights(); setNPCDialog("chanel1", "chanel_greeting_1"); setNPCDialog("bilal1", "bilal_greeting_1"); setNPCDialog("suki1", "suki_greeting_1"); fillWall(bilalBlock, MinecraftBlockTypes.Barrier); openDoor(); isIntroToLevel1Sqeuence = false; isBreaking = false; } }); system.afterEvents.scriptEventReceive.subscribe((event) => { if (event.id == "cc:getId") { const id = event.message; if (DEVELOPER_MODE) { world.sendMessage("Script got the id " + id); } mindKeeper.set(AGENT_ID, id); } if (event.id == "cc:startIntro") { if (mindKeeper.get(CURRENT_LEVEL) == 2) { mindKeeper.increment(CURRENT_LEVEL); } else { if (DEVELOPER_MODE) { world.sendMessage("Intro already started?"); } } } if (event.id == "cc:startTemple") { if (mindKeeper.get(CURRENT_LEVEL) == 7) { mindKeeper.increment(CURRENT_LEVEL); fillWall(bilalBlock, MinecraftBlockTypes.Air); } } checkNpcResponse(event, "cc:startLevel1", 8); checkNpcResponse(event, "cc:afterLevel1", 13); checkNpcResponse(event, "cc:level2Intermezzo", 15); checkNpcResponse(event, "cc:afterLevel2", 17); checkNpcResponse(event, "cc:afterLevel3", 21); }); function checkNpcResponse(event: ScriptEventCommandMessageAfterEvent, id: string, level: number) { if (event.id == id) { if (mindKeeper.get(CURRENT_LEVEL) == level) { mindKeeper.increment(CURRENT_LEVEL); } } } triggerManager.RegisterFunctionTrigger("tp", (event) => { // end center pos /setblock 2490 -12 118 // start center pos /setblock 2489 10 118 const pos = vector3(2489, 10, 118); const endPos = vector3(2490, -12, 118); world.sendMessage(Vector3ToFancyString(Vector3Subtract(endPos, pos))); //Find offset and tp player to end pos + offset so its seamless const playerPos = event.player.location; const offset = Vector3Subtract(endPos, playerPos); const finalPos = Vector3Add(pos, offset); event.player.teleport(finalPos); }); Commands.register(PREFIX, "fien", (arg) => { system.run(() => { arg.player.teleport(vector3(2468, 11, 114)); }); }); Commands.register(PREFIX, "openDoor", () => openDoor()); Commands.register(PREFIX, "closeDoor", () => closeDoor()); 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.3"); world.sendMessage("Engine is running, duh :)"); 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", () => { if (DEVELOPER_MODE) { (async () => { for (let i = 0; i < 10; i++) { randomExplosions(); await delay(1); } blowUpDoor(); })(); } }); const openDoor = () => { runEntityEventOnTag("door", "cc:add_open"); if (DEVELOPER_MODE) { world.sendMessage("Opening door"); } }; const closeDoor = () => { runEntityEventOnTag("door", "cc:remove_open"); if (DEVELOPER_MODE) { world.sendMessage("Closing door"); } }; Commands.register(PREFIX, "restore", () => { restoreDoor(); }); //#region Airlock enum GlassWindowState { Broken, Fixed, Fucked, } enum AirLockState { Open, Closed, } enum AirLockChamberState { Full, Empty, } let glassWindowState: GlassWindowState = GlassWindowState.Fixed; const doorRoot: Vector3 = vector3(2465, 11, 94); Commands.register(PREFIX, "breakGlass", () => { breakGlassWindow(); glassWindowState = GlassWindowState.Broken; }); Commands.register(PREFIX, "restoreGlass", () => { restoreGlassWindow(); glassWindowState = GlassWindowState.Fixed; }); async function breakGlassWindow() { await playAnimation(glassBreakingFrames, 5, false, doorRoot); glassWindowState = GlassWindowState.Broken; } async function restoreGlassWindow(force: boolean = false) { playAnimation(glassBreakingFrames, 5, true, doorRoot, force); glassWindowState = GlassWindowState.Fixed; } async function CycleAirLockWater(fill: boolean, delayTime: number) { if (animationPlaying) { world.sendMessage("Animation already playing"); return; } setAmimationPlaying(true); const frameCount = AirLockWaterFrames.length; for (let i = 0; i < frameCount; i++) { const frame = fill ? AirLockWaterFrames[i] : AirLockWaterFrames[frameCount - i - 1]; const blockToFill = fill ? "minecraft:water" : "minecraft:air"; await world .getDimension("overworld") .runCommandAsync( `/fill ${Vector3ToCommandString(frame.point1)} ${Vector3ToCommandString(frame.point2)} ${blockToFill}` ); await delay(delayTime); } setAmimationPlaying(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 () => { if (chamberState == AirLockChamberState.Empty) { if (DEVELOPER_MODE) { world.sendMessage("Filling airlock"); } await FillAirlockWater(); chamberState = AirLockChamberState.Full; } if (frontAirlockState == AirLockState.Closed) { await PlayFrontDoorOpenAnimation(); frontAirlockState = AirLockState.Open; } }); triggerManager.RegisterFunctionTrigger("TempleFrontDoor", async () => { if (mindKeeper.get(CURRENT_LEVEL) == 8) { closeDoor(); } if (mindKeeper.get(CURRENT_LEVEL) == 22) { openDoor(); mindKeeper.increment(CURRENT_LEVEL); } }); triggerManager.RegisterFunctionTrigger("level1start", async () => { // This is after the player talks to suki if (mindKeeper.get(CURRENT_LEVEL) == 9) { mindKeeper.increment(CURRENT_LEVEL); } }); //Player enters FrontAirLockInside //Front door closes //Water drains //Back door opens triggerManager.RegisterFunctionTrigger("FrontAirLockInside", async () => { if (frontAirlockState == AirLockState.Open) { await PlayFrontDoorCloseAnimation(); frontAirlockState = AirLockState.Closed; } if (chamberState == AirLockChamberState.Full) { activateAirlockLights(); await delay(50); await EmptyAirlockWater(); deactivateAirlockLights(); 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 () => { if (backAirlockState == AirLockState.Open) { world.sendMessage("Closing back door"); await PlayBackDoorCloseAnimation(); backAirlockState = AirLockState.Closed; } }); //#endregion Airlock const activateAirlockLights = () => runEntityEventOnTag("airlockLights", "cc:add_rotating"); const deactivateAirlockLights = () => runEntityEventOnTag("airlockLights", "cc:remove_rotating"); function resetAirLock() { SetFrontDoorClosed(); SetBackDoorClosed(); FillAirlockWater(); frontAirlockState = AirLockState.Closed; backAirlockState = AirLockState.Closed; chamberState = AirLockChamberState.Full; glassWindowState = GlassWindowState.Fixed; } Commands.register(PREFIX, "resetAirlock", () => resetAirLock); const frontDoorRoot: Vector3 = vector3(2474, 11, 94); const backDoorRoot: Vector3 = vector3(2472, 11, 100); const frameDuration = 7; const SetFrontDoorClosed = () => SetFrame(FrontAirLockOpenFrames[0], frontDoorRoot); // eslint-disable-next-line @typescript-eslint/no-unused-vars const SetFrontDoorOpen = () => SetFrame(FrontAirLockOpenFrames[FrontAirLockOpenFrames.length - 1], frontDoorRoot); const PlayFrontDoorOpenAnimation = async () => { playAnimation(FrontAirLockOpenFrames, frameDuration, false, frontDoorRoot); if (mindKeeper.get(CURRENT_LEVEL) == 0) { mindKeeper.increment(CURRENT_LEVEL); } }; const PlayFrontDoorCloseAnimation = async () => playAnimation(FrontAirLockOpenFrames, frameDuration, true, frontDoorRoot); const SetBackDoorClosed = () => SetFrame(BackAirLockOpenFrames[0], backDoorRoot); // eslint-disable-next-line @typescript-eslint/no-unused-vars const SetBackDoorOpen = () => SetFrame(BackAirLockOpenFrames[BackAirLockOpenFrames.length - 1], backDoorRoot); const PlayBackDoorOpenAnimation = async () => playAnimation(BackAirLockOpenFrames, frameDuration, false, backDoorRoot); const PlayBackDoorCloseAnimation = async () => playAnimation(BackAirLockOpenFrames, frameDuration, true, backDoorRoot, true); const FillAirlockWater = async () => CycleAirLockWater(true, frameDuration / 1.5); const EmptyAirlockWater = async () => { await CycleAirLockWater(false, frameDuration / 1.5); if (mindKeeper.get(CURRENT_LEVEL) == 1) { mindKeeper.increment(CURRENT_LEVEL); } }; triggerManager.RegisterFunctionTrigger("openFrontDoor", () => PlayFrontDoorOpenAnimation()); triggerManager.RegisterFunctionTrigger("closeFrontDoor", () => PlayFrontDoorCloseAnimation()); triggerManager.RegisterFunctionTrigger("openBackDoor", () => PlayBackDoorOpenAnimation()); triggerManager.RegisterFunctionTrigger("closeBackDoor", () => PlayBackDoorCloseAnimation()); triggerManager.RegisterFunctionTrigger("fillAirlock", () => FillAirlockWater()); triggerManager.RegisterFunctionTrigger("emptyAirlock", () => EmptyAirlockWater());