Create
Return to post

Comparing difference between and

View raw
  • // Version 1.1.0
  • variables
  • {
  • global:
  • 124: _extendedGlobalCollection
  • 125: _arrayBuilder
  • 126: textBudget
  • 127: exitButtonProperties
  • player:
  • 111: IsInMenuMode
  • 112: MenuVFX
  • 113: MenuZAxis
  • 114: MenuYAxis
  • 115: MenuXAxis
  • 116: CursorPos
  • 117: CurrActionID
  • 118: ButtonExitMenu
  • 119: ButtonProperties
  • 120: CursorX
  • 121: CursorY
  • 122: MenuEyePos
  • 123: MenuOriginalFacing
  • 124: ActionIDQueue
  • 125: CurrActionID_Secondary
  • 126: ActionIDQueue_Secondary
  • 127: __iter__
  • 117: _extendedPlayerCollection
  • 118: getProperties
  • 119: buttonModification
  • 120: currActionID
  • 121: destroyButtonID
  • 122: lastMenuButtonID
  • 123: buttons
  • 124: newButton
  • 125: menuOriginalFacing
  • 126: menuFrame
  • 127: isInMenu
  • }
  • subroutines
  • {
  • 125: CreateMenuFrame
  • 126: CreateMenuButtons
  • 127: CreateMenuCursor
  • 118: createMenuButton
  • 119: destroyMenuButton
  • 120: modifyMenuButton
  • 121: getButtonProperties
  • 122: createCursor
  • 123: createBorderCorners
  • 124: createBorderEdges
  • 125: createExitButton
  • 126: doButtonUpdate
  • 127: createClickAreas
  • }
  • rule("▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒【Josbird's Cursor Menu】▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒")
  • {
  • event
  • {
  • Ongoing - Global;
  • }
  • }
  • rule("Create basic HUD elements")
  • rule("Global init")
  • {
  • event
  • {
  • Ongoing - Global;
  • }
  • actions
  • {
  • "Creates a HUD at the top of the screen, beneath the objective/game mode information, telling them which button opens the menu."
  • Create HUD Text(Filtered Array(All Players(All Teams), !Current Array Element.IsInMenuMode), Custom String(
  • "Press {0} to open menu", Input Binding String(Button(Interact))), Null, Null, Top, 1, Yellow, White, White,
  • Visible To and String, Default Visibility);
  • "Displays server load on the top right of the screen, above the kill feed."
  • disabled Create HUD Text(All Players(All Teams), Server Load Average, Null, String("Server Load Average"), Right, 0, Green, Green, White,
  • Visible To and String, Default Visibility);
  • "Credits (please do not delete!)"
  • Create HUD Text(Filtered Array(All Players(All Teams), Current Array Element.IsInMenuMode), Null, Null, Custom String(
  • "Cursor Menu created by Josbird {0} Code: GETVX", Ability Icon String(Hero(Mercy), Button(Ultimate))), Right, -100, White,
  • White, Aqua, Visible To and String, Default Visibility);
  • Global.textBudget = 128;
  • If(Workshop Setting Toggle(Custom String("Extra"), Custom String("Server load hud"), False, 0));
  • Create HUD Text(Host Player, Server Load Average, Custom String("Server Load"), Null, Right, -1, Color(Turquoise), Color(White),
  • Color(White), Visible To and String, Default Visibility);
  • Global.textBudget -= 1;
  • End;
  • Create HUD Text(Filtered Array(All Players(All Teams), Current Array Element.isInMenu), Null, Null, Custom String(
  • "Cursor Menu created by Josbird {0} Code: GETVX", Ability Icon String(Hero(Mercy), Button(Ultimate))), Right, -100, Color(
  • White), Color(White), Color(Turquoise), Visible To and String, Default Visibility);
  • Global.textBudget -= 1;
  • If(Workshop Setting Toggle(Custom String("Josbird's Cursor Menu"), Custom String("Menu prompt hud"), True, 5));
  • Create HUD Text(Filtered Array(All Players(All Teams), !Current Array Element.isInMenu), Custom String("
{0}
", Custom String(
  • "Press Interact [{0}] to open menu", Input Binding String(Button(Interact)))), Null, Null, Top, 1, Color(Yellow), Color(White),
  • Color(White), Visible To and String, Default Visibility);
  • Global.textBudget -= 1;
  • End;
  • Global._extendedGlobalCollection[1] = Workshop Setting Real(Custom String("Josbird's Cursor Menu"), Custom String("Menu Width"), 5,
  • 0, 10, 1);
  • Global._extendedGlobalCollection[2] = Workshop Setting Real(Custom String("Josbird's Cursor Menu"), Custom String("Menu Height"),
  • 2.500, 0, 5, 2);
  • Global._extendedGlobalCollection[6] = Workshop Setting Toggle(Custom String("Josbird's Cursor Menu"), Custom String(
  • "Button click sounds"), True, 3);
  • Global._extendedGlobalCollection[5] = Workshop Setting Toggle(Custom String("Josbird's Cursor Menu"), Custom String(
  • "Debug mode (show button click areas)"), False, 4);
  • Global._extendedGlobalCollection[7] = Workshop Setting Toggle(Custom String("Josbird's Cursor Menu"), Custom String(
  • "Menu disables game hud"), True, 7);
  • Global._extendedGlobalCollection[3] = Custom String("━");
  • Global._extendedGlobalCollection[4] = Custom String("┃\n");
  • Global.exitButtonProperties = Array(Custom String("exit menu"), Global._extendedGlobalCollection[1] / 2 - 0.150,
  • Global._extendedGlobalCollection[2] / 2 - 0.150, 0.350);
  • }
  • }
  • rule("Toggle menu mode")
  • rule("Create a menu button")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • Subroutine;
  • createMenuButton;
  • }
  • conditions
  • actions
  • {
  • If(Count Of(Event Player.newButton) != 13);
  • Log To Inspector(Custom String("[CursorMenu.createMenuButton] Error: incorrect number of arguments (got {0}, expected {1})",
  • Event Player.destroyButtonID, 13));
  • Else;
  • Event Player.lastMenuButtonID = Count Of(Event Player.buttons);
  • Event Player._extendedPlayerCollection[2] = 0;
  • While(Event Player._extendedPlayerCollection[2] < Count Of(Event Player.buttons));
  • If(Event Player.buttons[Event Player._extendedPlayerCollection[2]] == Null);
  • Event Player.lastMenuButtonID = Event Player._extendedPlayerCollection[2];
  • Event Player._extendedPlayerCollection[2] = Count Of(Event Player.buttons);
  • End;
  • Event Player._extendedPlayerCollection[2] += 1;
  • End;
  • Event Player.buttons[Event Player.lastMenuButtonID] = Event Player.newButton;
  • End;
  • }
  • }
  • rule("Destroy a menu button")
  • {
  • event
  • {
  • Subroutine;
  • destroyMenuButton;
  • }
  • actions
  • {
  • If(Event Player.destroyButtonID >= Count Of(Event Player.buttons) || !Event Player.buttons[Event Player.destroyButtonID]);
  • Log To Inspector(Custom String("[CursorMenu.destroyMenuButton] Error: tried to destroy an invalid button ID ({0})",
  • Event Player.destroyButtonID));
  • Else;
  • Global._arrayBuilder = Event Player.buttons[Event Player.destroyButtonID];
  • Global._arrayBuilder[15] = True;
  • Event Player.buttons[Event Player.destroyButtonID] = Global._arrayBuilder;
  • End;
  • }
  • }
  • rule("Modify a menu button")
  • {
  • event
  • {
  • Subroutine;
  • modifyMenuButton;
  • }
  • actions
  • {
  • "Dummy bots were getting menu stuff and causing server crashes, so we exclude them from these rules."
  • Is Dummy Bot(Event Player) == False;
  • "The menu is currently set to both open and close when Interact is pressed."
  • Is Button Held(Event Player, Interact) == True;
  • "I added this in because emoting prevents you from moving your aim, thus making the cursor immovable. Remove at your own peril."
  • Is Communicating Any Emote(Event Player) == False;
  • If(Count Of(Event Player.buttonModification) % 2 == 0 || Count Of(Event Player.buttonModification) < 3);
  • Log To Inspector(Custom String("[CursorMenu.modifyMenuButton] Error: incorrect number of arguments ({0})", Count Of(First Of(
  • Event Player.buttonModification))));
  • Else If(First Of(Event Player.buttonModification) >= Count Of(Event Player.buttons) || !Event Player.buttons[First Of(
  • Event Player.buttonModification)]);
  • Log To Inspector(Custom String("[CursorMenu.modifyMenuButton] Error: tried to modify an invalid button ID ({0})", First Of(
  • Event Player.buttonModification)));
  • Else;
  • Event Player._extendedPlayerCollection[2] = 1;
  • While(Event Player._extendedPlayerCollection[2] < Count Of(Event Player.buttonModification));
  • If(
  • Event Player.buttonModification[Event Player._extendedPlayerCollection[2]] < 0 || Event Player.buttonModification[Event Player._extendedPlayerCollection[2]] >= 13);
  • Log To Inspector(Custom String("[CursorMenu.modifyMenuButton] Error: tried to modify an invalid property index ({0})", Count Of(
  • Event Player.buttonModification[Event Player._extendedPlayerCollection[2]])));
  • Else;
  • Global._arrayBuilder = Event Player.buttons[First Of(Event Player.buttonModification)];
  • Global._arrayBuilder[Event Player.buttonModification[Event Player._extendedPlayerCollection[2]]] = Event Player.buttonModification[Event Player._extendedPlayerCollection[2] + 1];
  • Event Player.buttons[First Of(Event Player.buttonModification)] = Global._arrayBuilder;
  • End;
  • Event Player._extendedPlayerCollection[2] += 2;
  • End;
  • End;
  • }
  • }
  • rule("Get properties of a menu button")
  • {
  • event
  • {
  • Subroutine;
  • getButtonProperties;
  • }
  • actions
  • {
  • "If the menu is not open, opens the menu. Otherwise, closes it."
  • Event Player.IsInMenuMode = !Event Player.IsInMenuMode;
  • If(Event Player.getProperties >= Count Of(Event Player.buttons) || !Event Player.buttons[Event Player.getProperties]);
  • Log To Inspector(Custom String("[CursorMenu.getButtonProperties] Error: tried to access an invalid button ID ({0})",
  • Event Player.getProperties));
  • Else;
  • Event Player.getProperties = Array Slice(Event Player.buttons[Event Player.getProperties], 0, 13);
  • End;
  • }
  • }
  • rule("Menu activated > Start setup")
  • rule("Toggle menu")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • "Dummy bots were getting menu stuff and causing server crashes, so we exclude them from these rules."
  • Is Dummy Bot(Event Player) == False;
  • "Triggers once whenever the menu opens."
  • Event Player.IsInMenuMode == True;
  • !Is Dummy Bot(Event Player) == True;
  • Is Button Held(Event Player, Button(Interact)) == True;
  • !Is Communicating Any Emote(Event Player) == True;
  • }
  • actions
  • {
  • "Sets aim speed to minimum to reduce camera sway while in menu."
  • Set Aim Speed(Event Player, 10);
  • "These 2 rules disable primary and secondary fire for the purposes of click detection. Though personally I haven't actually thought of a use for secondary fire yet."
  • Set Primary Fire Enabled(Event Player, False);
  • Set Secondary Fire Enabled(Event Player, False);
  • "These 2 rules disable the non-menu HUD. This is optional, I just think it looks cleaner."
  • Disable Hero HUD(Event Player);
  • Disable Game Mode HUD(Event Player);
  • "This (and the following rule) set the menu eye position to follow the player's eye position. Overwrite if you plan to separate the menu from the player's current position."
  • Event Player.MenuEyePos = Eye Position(Event Player);
  • Chase Player Variable At Rate(Event Player, MenuEyePos, Eye Position(Event Player), 100000, Destination and Rate);
  • "Stores original facing direction of player for the purpose of recording mouse movement. Don't recommend changing this."
  • Event Player.MenuOriginalFacing = Facing Direction Of(Event Player);
  • "Sets the forward axis of the menu view (into and out of the screen). Change this to match the facing direction of whatever camera you use if you decouple it from the first person view. (Make sure to normalize if the direction is not a unit vector.)"
  • Event Player.MenuZAxis = Facing Direction Of(Event Player);
  • "Sets vertical axis of menu (up and down the screen)."
  • Event Player.MenuYAxis = Direction From Angles(Horizontal Angle From Direction(Event Player.MenuZAxis),
  • Vertical Angle From Direction(Event Player.MenuZAxis) + -90);
  • "Sets horizontal axis of the menu (left and right on the screen)."
  • Event Player.MenuXAxis = Cross Product(Event Player.MenuZAxis, Event Player.MenuYAxis);
  • "These three rules scale up all 3 axes to 100 meters in order to stabilize the menu in-world texts by placing them far away from the camera view. Keep this in mind if you plan to make your own texts on the screen."
  • Event Player.MenuXAxis *= 100;
  • Event Player.MenuYAxis *= 100;
  • Event Player.MenuZAxis *= 100;
  • "This is where the magic happens. The first rule initializes the cursor position and the second moves it around the screen as the player moves their aim by projecting the angle difference onto a flat plane."
  • Event Player.CursorPos = Event Player.MenuEyePos + Event Player.MenuZAxis * 3;
  • Chase Player Variable At Rate(Event Player, CursorPos,
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * -0.750 * Angle Difference(
  • Horizontal Angle From Direction(Event Player.MenuOriginalFacing), Horizontal Angle From Direction(Facing Direction Of(
  • Event Player))) + Event Player.MenuYAxis * -0.750 * Angle Difference(Vertical Angle From Direction(
  • Event Player.MenuOriginalFacing), Vertical Angle From Direction(Facing Direction Of(Event Player))), 100000,
  • Destination and Rate);
  • "The next four rules provide a simpler way to track the position of the cursor relative to the screen. Use these instead of CursorPos to compare the cursor position to coordinates of onscreen elements."
  • Event Player.CursorX = 0;
  • Event Player.CursorY = 0;
  • Chase Player Variable At Rate(Event Player, CursorX, -0.750 * Angle Difference(Horizontal Angle From Direction(
  • Event Player.MenuOriginalFacing), Horizontal Angle From Direction(Facing Direction Of(Event Player))), 100000,
  • Destination and Rate);
  • Chase Player Variable At Rate(Event Player, CursorY, -0.750 * Angle Difference(Vertical Angle From Direction(
  • Event Player.MenuOriginalFacing), Vertical Angle From Direction(Facing Direction Of(Event Player))), 100000,
  • Destination and Rate);
  • "This rule initializes the array that stores all components of the menu in order to destroy them when it closes. Don't recommend changing this."
  • Event Player.MenuVFX = Empty Array;
  • "These subroutines do the actual work of constructing the menu. See subroutines for more details."
  • Call Subroutine(CreateMenuFrame);
  • Call Subroutine(CreateMenuButtons);
  • Call Subroutine(CreateMenuCursor);
  • Event Player.isInMenu = !Event Player.isInMenu;
  • }
  • }
  • rule("Menu activated > Create frame")
  • rule("Create menu cursor")
  • {
  • event
  • {
  • Subroutine;
  • CreateMenuFrame;
  • createCursor;
  • }
  • actions
  • {
  • "This rule constructs the 10 elements that make up the frame of the menu. If you want to resize the menu, change the position and contents of these texts to what you want. Don't make it any larger as current size is optimized to be onscreen at min FoV."
  • Abort If(False);
  • "The following 8 rules create the corner pieces of the menu frame."
  • Create In-World Text(Event Player, Custom String("┌"), World Vector Of(Local Vector Of(
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * -2.500 + Event Player.MenuYAxis * 1.050,
  • Event Player, Rotation And Translation), Event Player, Rotation And Translation), 4, Do Not Clip, Visible To and Position,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Event Player, Custom String("┐"), World Vector Of(Local Vector Of(
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * 2.500 + Event Player.MenuYAxis * 1.050,
  • Event Player, Rotation And Translation), Event Player, Rotation And Translation), 4, Do Not Clip, Visible To and Position,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Event Player, Custom String("└"), World Vector Of(Local Vector Of(
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * -2.500 + Event Player.MenuYAxis * -1.450,
  • Event Player, Rotation And Translation), Event Player, Rotation And Translation), 4, Do Not Clip, Visible To and Position,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Event Player, Custom String("┘"), World Vector Of(Local Vector Of(
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * 2.500 + Event Player.MenuYAxis * -1.450,
  • Event Player, Rotation And Translation), Event Player, Rotation And Translation), 4, Do Not Clip, Visible To and Position,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • "The following 8 rules create the edge pieces of the menu frame. Recommend removing these first if you are running low on in-world text budget."
  • Create In-World Text(Event Player, Custom String("━━━━━━━━━━━━━━━━"), World Vector Of(Local Vector Of(
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * 0 + Event Player.MenuYAxis * 1.050,
  • Event Player, Rotation And Translation), Event Player, Rotation And Translation), 4, Do Not Clip, Visible To and Position,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Event Player, Custom String("━━━━━━━━━━━━━━━━"), World Vector Of(Local Vector Of(
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * 0 + Event Player.MenuYAxis * -1.450,
  • Event Player, Rotation And Translation), Event Player, Rotation And Translation), 4, Do Not Clip, Visible To and Position,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Event Player, Custom String("┃\r\n┃\r\n┃\r\n┃\r\n┃\r\n┃\r\n┃"), World Vector Of(Local Vector Of(
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * -2.500 + Event Player.MenuYAxis * -0.700,
  • Event Player, Rotation And Translation), Event Player, Rotation And Translation), 4, Do Not Clip, Visible To and Position,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Event Player, Custom String("┃\r\n┃\r\n┃\r\n┃\r\n┃\r\n┃\r\n┃"), World Vector Of(Local Vector Of(
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * 2.500 + Event Player.MenuYAxis * -0.700,
  • Event Player, Rotation And Translation), Event Player, Rotation And Translation), 4, Do Not Clip, Visible To and Position,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • "This creates a button to close the menu using a simplified version of the default button schema detailed on workshop.codes: [button text, action ID, x position, y position, click radius]."
  • Event Player.ButtonExitMenu = Array(Custom String("X"), Custom String("exit menu"), 2.350, 1.100, 0.100);
  • "Creates the inactive text of the exit button. Becomes invisible when the cursor hovers over the button."
  • Create In-World Text(Filtered Array(Event Player, Event Player.IsInMenuMode && Distance Between(Event Player.CursorPos,
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonExitMenu[2] + Event Player.MenuYAxis * Event Player.ButtonExitMenu[3])
  • > 100 * Event Player.ButtonExitMenu[4]), Event Player.ButtonExitMenu[0],
  • Event Player.MenuEyePos + Event Player.MenuYAxis * -0.200 + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonExitMenu[2] + Event Player.MenuYAxis * Event Player.ButtonExitMenu[3],
  • 3, Do Not Clip, Visible To Position and String, Red, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • "Creates the hover text of the exit button. Becomes visible when the cursor hovers over the button."
  • Create In-World Text(Filtered Array(Event Player, Event Player.IsInMenuMode && Distance Between(Event Player.CursorPos,
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonExitMenu[2] + Event Player.MenuYAxis * Event Player.ButtonExitMenu[3])
  • <= 100 * Event Player.ButtonExitMenu[4]), Event Player.ButtonExitMenu[0],
  • Event Player.MenuEyePos + Event Player.MenuYAxis * -0.200 + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonExitMenu[2] + Event Player.MenuYAxis * Event Player.ButtonExitMenu[3],
  • 3, Do Not Clip, Visible To Position and String, Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player, Total Time Elapsed % 0.032 < 0.016), Custom String("▲"), Update Every Frame(
  • Eye Position(Event Player) + 100 * (Angle Difference(Horizontal Angle From Direction(Facing Direction Of(Event Player)),
  • Horizontal Angle From Direction(Event Player.menuOriginalFacing)) * Cross Product(Facing Direction Of(Event Player),
  • Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Facing Direction Of(Event Player)) - 90)) + (Angle Difference(Vertical Angle From Direction(Facing Direction Of(Event Player)),
  • Vertical Angle From Direction(Event Player.menuOriginalFacing)) - 0.200) * Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 3, Do Not Clip, Visible To Position String and Color, Color(
  • White), Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Create In-World Text(Filtered Array(Event Player, Total Time Elapsed % 0.032 >= 0.016), Custom String("▲"), Update Every Frame(
  • Eye Position(Event Player) + 100 * (Angle Difference(Horizontal Angle From Direction(Facing Direction Of(Event Player)),
  • Horizontal Angle From Direction(Event Player.menuOriginalFacing)) * Cross Product(Facing Direction Of(Event Player),
  • Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Facing Direction Of(Event Player)) - 90)) + (Angle Difference(Vertical Angle From Direction(Facing Direction Of(Event Player)),
  • Vertical Angle From Direction(Event Player.menuOriginalFacing)) - 0.200) * Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 3, Do Not Clip, Visible To Position String and Color, Color(
  • White), Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • }
  • }
  • rule("Menu activated > Create buttons")
  • rule("Create menu border corners")
  • {
  • event
  • {
  • Subroutine;
  • CreateMenuButtons;
  • createBorderCorners;
  • }
  • actions
  • {
  • "This rule creates the actual button visuals when the menu is opened. Until we get color variables, this is where more experienced users can change button colors. In each set, 2nd action = inactive button color, 4th = hovered button color."
  • Wait(0.016, Ignore Condition);
  • " \r\nButtonProperties[0]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 0);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[0][7] && (
  • !Event Player.ButtonProperties[0][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[0][2])
  • > Event Player.ButtonProperties[0][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[0][3])
  • > Event Player.ButtonProperties[0][5] / 2)), Event Player.ButtonProperties[0][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[0][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[0][3] - 0.200), Event Player.ButtonProperties[0][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[0][7] && Event Player.ButtonProperties[0][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[0][2]) <= Event Player.ButtonProperties[0][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[0][3]) <= Event Player.ButtonProperties[0][5] / 2),
  • Event Player.ButtonProperties[0][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[0][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[0][3] - 0.200), Event Player.ButtonProperties[0][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[1]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 1);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[1][7] && (
  • !Event Player.ButtonProperties[1][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[1][2])
  • > Event Player.ButtonProperties[1][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[1][3])
  • > Event Player.ButtonProperties[1][5] / 2)), Event Player.ButtonProperties[1][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[1][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[1][3] - 0.200), Event Player.ButtonProperties[1][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[1][7] && Event Player.ButtonProperties[1][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[1][2]) <= Event Player.ButtonProperties[1][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[1][3]) <= Event Player.ButtonProperties[1][5] / 2),
  • Event Player.ButtonProperties[1][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[1][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[1][3] - 0.200), Event Player.ButtonProperties[1][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[2]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 2);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[2][7] && (
  • !Event Player.ButtonProperties[2][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[2][2])
  • > Event Player.ButtonProperties[2][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[2][3])
  • > Event Player.ButtonProperties[2][5] / 2)), Event Player.ButtonProperties[2][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[2][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[2][3] - 0.200), Event Player.ButtonProperties[2][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[2][7] && Event Player.ButtonProperties[2][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[2][2]) <= Event Player.ButtonProperties[2][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[2][3]) <= Event Player.ButtonProperties[2][5] / 2),
  • Event Player.ButtonProperties[2][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[2][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[2][3] - 0.200), Event Player.ButtonProperties[2][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[3]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 3);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[3][7] && (
  • !Event Player.ButtonProperties[3][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[3][2])
  • > Event Player.ButtonProperties[3][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[3][3])
  • > Event Player.ButtonProperties[3][5] / 2)), Event Player.ButtonProperties[3][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[3][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[3][3] - 0.200), Event Player.ButtonProperties[3][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[3][7] && Event Player.ButtonProperties[3][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[3][2]) <= Event Player.ButtonProperties[3][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[3][3]) <= Event Player.ButtonProperties[3][5] / 2),
  • Event Player.ButtonProperties[3][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[3][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[3][3] - 0.200), Event Player.ButtonProperties[3][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[4]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 4);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[4][7] && (
  • !Event Player.ButtonProperties[4][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[4][2])
  • > Event Player.ButtonProperties[4][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[4][3])
  • > Event Player.ButtonProperties[4][5] / 2)), Event Player.ButtonProperties[4][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[4][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[4][3] - 0.200), Event Player.ButtonProperties[4][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[4][7] && Event Player.ButtonProperties[4][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[4][2]) <= Event Player.ButtonProperties[4][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[4][3]) <= Event Player.ButtonProperties[4][5] / 2),
  • Event Player.ButtonProperties[4][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[4][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[4][3] - 0.200), Event Player.ButtonProperties[4][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[5]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 5);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[5][7] && (
  • !Event Player.ButtonProperties[5][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[5][2])
  • > Event Player.ButtonProperties[5][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[5][3])
  • > Event Player.ButtonProperties[5][5] / 2)), Event Player.ButtonProperties[5][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[5][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[5][3] - 0.200), Event Player.ButtonProperties[5][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[5][7] && Event Player.ButtonProperties[5][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[5][2]) <= Event Player.ButtonProperties[5][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[5][3]) <= Event Player.ButtonProperties[5][5] / 2),
  • Event Player.ButtonProperties[5][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[5][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[5][3] - 0.200), Event Player.ButtonProperties[5][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[6]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 6);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[6][7] && (
  • !Event Player.ButtonProperties[6][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[6][2])
  • > Event Player.ButtonProperties[6][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[6][3])
  • > Event Player.ButtonProperties[6][5] / 2)), Event Player.ButtonProperties[6][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[6][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[6][3] - 0.200), Event Player.ButtonProperties[6][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[6][7] && Event Player.ButtonProperties[6][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[6][2]) <= Event Player.ButtonProperties[6][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[6][3]) <= Event Player.ButtonProperties[6][5] / 2),
  • Event Player.ButtonProperties[6][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[6][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[6][3] - 0.200), Event Player.ButtonProperties[6][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[7]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 7);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[7][7] && (
  • !Event Player.ButtonProperties[7][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[7][2])
  • > Event Player.ButtonProperties[7][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[7][3])
  • > Event Player.ButtonProperties[7][5] / 2)), Event Player.ButtonProperties[7][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[7][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[7][3] - 0.200), Event Player.ButtonProperties[7][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[7][7] && Event Player.ButtonProperties[7][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[7][2]) <= Event Player.ButtonProperties[7][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[7][3]) <= Event Player.ButtonProperties[7][5] / 2),
  • Event Player.ButtonProperties[7][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[7][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[7][3] - 0.200), Event Player.ButtonProperties[7][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[8]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 8);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[8][7] && (
  • !Event Player.ButtonProperties[8][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[8][2])
  • > Event Player.ButtonProperties[8][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[8][3])
  • > Event Player.ButtonProperties[8][5] / 2)), Event Player.ButtonProperties[8][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[8][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[8][3] - 0.200), Event Player.ButtonProperties[8][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[8][7] && Event Player.ButtonProperties[8][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[8][2]) <= Event Player.ButtonProperties[8][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[8][3]) <= Event Player.ButtonProperties[8][5] / 2),
  • Event Player.ButtonProperties[8][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[8][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[8][3] - 0.200), Event Player.ButtonProperties[8][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[9]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 9);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[9][7] && (
  • !Event Player.ButtonProperties[9][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[9][2])
  • > Event Player.ButtonProperties[9][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[9][3])
  • > Event Player.ButtonProperties[9][5] / 2)), Event Player.ButtonProperties[9][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[9][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[9][3] - 0.200), Event Player.ButtonProperties[9][8], Do Not Clip, Visible To Position and String,
  • White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[9][7] && Event Player.ButtonProperties[9][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[9][2]) <= Event Player.ButtonProperties[9][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[9][3]) <= Event Player.ButtonProperties[9][5] / 2),
  • Event Player.ButtonProperties[9][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[9][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[9][3] - 0.200), Event Player.ButtonProperties[9][8], Do Not Clip, Visible To Position and String,
  • Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[10]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 10);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[10][7] && (
  • !Event Player.ButtonProperties[10][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[10][2])
  • > Event Player.ButtonProperties[10][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[10][3])
  • > Event Player.ButtonProperties[10][5] / 2)), Event Player.ButtonProperties[10][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[10][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[10][3] - 0.200), Event Player.ButtonProperties[10][8], Do Not Clip,
  • Visible To Position and String, White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[10][7] && Event Player.ButtonProperties[10][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[10][2]) <= Event Player.ButtonProperties[10][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[10][3]) <= Event Player.ButtonProperties[10][5] / 2),
  • Event Player.ButtonProperties[10][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[10][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[10][3] - 0.200), Event Player.ButtonProperties[10][8], Do Not Clip,
  • Visible To Position and String, Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[11]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 11);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[11][7] && (
  • !Event Player.ButtonProperties[11][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[11][2])
  • > Event Player.ButtonProperties[11][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[11][3])
  • > Event Player.ButtonProperties[11][5] / 2)), Event Player.ButtonProperties[11][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[11][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[11][3] - 0.200), Event Player.ButtonProperties[11][8], Do Not Clip,
  • Visible To Position and String, White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[11][7] && Event Player.ButtonProperties[11][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[11][2]) <= Event Player.ButtonProperties[11][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[11][3]) <= Event Player.ButtonProperties[11][5] / 2),
  • Event Player.ButtonProperties[11][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[11][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[11][3] - 0.200), Event Player.ButtonProperties[11][8], Do Not Clip,
  • Visible To Position and String, Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[12]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 12);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[12][7] && (
  • !Event Player.ButtonProperties[12][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[12][2])
  • > Event Player.ButtonProperties[12][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[12][3])
  • > Event Player.ButtonProperties[12][5] / 2)), Event Player.ButtonProperties[12][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[12][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[12][3] - 0.200), Event Player.ButtonProperties[12][8], Do Not Clip,
  • Visible To Position and String, White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[12][7] && Event Player.ButtonProperties[12][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[12][2]) <= Event Player.ButtonProperties[12][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[12][3]) <= Event Player.ButtonProperties[12][5] / 2),
  • Event Player.ButtonProperties[12][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[12][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[12][3] - 0.200), Event Player.ButtonProperties[12][8], Do Not Clip,
  • Visible To Position and String, Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[13]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 13);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[13][7] && (
  • !Event Player.ButtonProperties[13][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[13][2])
  • > Event Player.ButtonProperties[13][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[13][3])
  • > Event Player.ButtonProperties[13][5] / 2)), Event Player.ButtonProperties[13][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[13][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[13][3] - 0.200), Event Player.ButtonProperties[13][8], Do Not Clip,
  • Visible To Position and String, White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[13][7] && Event Player.ButtonProperties[13][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[13][2]) <= Event Player.ButtonProperties[13][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[13][3]) <= Event Player.ButtonProperties[13][5] / 2),
  • Event Player.ButtonProperties[13][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[13][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[13][3] - 0.200), Event Player.ButtonProperties[13][8], Do Not Clip,
  • Visible To Position and String, Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[14]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 14);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[14][7] && (
  • !Event Player.ButtonProperties[14][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[14][2])
  • > Event Player.ButtonProperties[14][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[14][3])
  • > Event Player.ButtonProperties[14][5] / 2)), Event Player.ButtonProperties[14][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[14][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[14][3] - 0.200), Event Player.ButtonProperties[14][8], Do Not Clip,
  • Visible To Position and String, White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[14][7] && Event Player.ButtonProperties[14][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[14][2]) <= Event Player.ButtonProperties[14][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[14][3]) <= Event Player.ButtonProperties[14][5] / 2),
  • Event Player.ButtonProperties[14][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[14][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[14][3] - 0.200), Event Player.ButtonProperties[14][8], Do Not Clip,
  • Visible To Position and String, Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • " \r\nButtonProperties[15]"
  • Abort If(Count Of(Event Player.ButtonProperties) <= 15);
  • Create In-World Text(Filtered Array(Event Player, Event Player.ButtonProperties[15][7] && (
  • !Event Player.ButtonProperties[15][6] || Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[15][2])
  • > Event Player.ButtonProperties[15][4] / 2 || Absolute Value(Event Player.CursorY - Event Player.ButtonProperties[15][3])
  • > Event Player.ButtonProperties[15][5] / 2)), Event Player.ButtonProperties[15][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[15][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[15][3] - 0.200), Event Player.ButtonProperties[15][8], Do Not Clip,
  • Visible To Position and String, White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player,
  • Event Player.ButtonProperties[15][7] && Event Player.ButtonProperties[15][6] && Absolute Value(
  • Event Player.CursorX - Event Player.ButtonProperties[15][2]) <= Event Player.ButtonProperties[15][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[15][3]) <= Event Player.ButtonProperties[15][5] / 2),
  • Event Player.ButtonProperties[15][0],
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonProperties[15][2] + Event Player.MenuYAxis * (
  • Event Player.ButtonProperties[15][3] - 0.200), Event Player.ButtonProperties[15][8], Do Not Clip,
  • Visible To Position and String, Yellow, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Event Player, Custom String("┌"), Update Every Frame(Eye Position(Event Player) + 100 * (
  • Global._extendedGlobalCollection[1] * -1 / 2 * Cross Product(Facing Direction Of(Event Player), Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90)) + (Global._extendedGlobalCollection[2] / 2 - 0.200) * Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 4, Do Not Clip, Visible To and Position, Color(White),
  • Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Create In-World Text(Event Player, Custom String("┐"), Update Every Frame(Eye Position(Event Player) + 100 * (
  • Global._extendedGlobalCollection[1] / 2 * Cross Product(Facing Direction Of(Event Player), Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90)) + (Global._extendedGlobalCollection[2] / 2 - 0.200) * Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 4, Do Not Clip, Visible To and Position, Color(White),
  • Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Create In-World Text(Event Player, Custom String("└"), Update Every Frame(Eye Position(Event Player) + 100 * (
  • Global._extendedGlobalCollection[1] * -1 / 2 * Cross Product(Facing Direction Of(Event Player), Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90)) + (Global._extendedGlobalCollection[2] * -1 / 2 - 0.200) * Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 4, Do Not Clip, Visible To and Position, Color(White),
  • Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Create In-World Text(Event Player, Custom String("┘"), Update Every Frame(Eye Position(Event Player) + 100 * (
  • Global._extendedGlobalCollection[1] / 2 * Cross Product(Facing Direction Of(Event Player), Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90)) + (Global._extendedGlobalCollection[2] * -1 / 2 - 0.200) * Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 4, Do Not Clip, Visible To and Position, Color(White),
  • Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • }
  • }
  • rule("Menu activated > Create cursor")
  • rule("Create menu border edges")
  • {
  • event
  • {
  • Subroutine;
  • CreateMenuCursor;
  • createBorderEdges;
  • }
  • actions
  • {
  • "The next four rules create the actual cursor that the player can move around. For the cursor to render over all other text, it must be the last in-world text to become visible. Thus, we create two identical cursors that alternate visibility every frame."
  • Create In-World Text(Filtered Array(Event Player, Total Time Elapsed % 0.032 > 0.016), Custom String("▲"), World Vector Of(
  • Local Vector Of(Event Player.CursorPos + Event Player.MenuYAxis * -0.200, Event Player, Rotation And Translation),
  • Event Player, Rotation And Translation), 3, Do Not Clip, Visible To and Position, White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Create In-World Text(Filtered Array(Event Player, Total Time Elapsed % 0.032 < 0.016), Custom String("▲"), World Vector Of(
  • Local Vector Of(Event Player.CursorPos + Event Player.MenuYAxis * -0.200, Event Player, Rotation And Translation),
  • Event Player, Rotation And Translation), 3, Do Not Clip, Visible To and Position, White, Default Visibility);
  • Modify Player Variable(Event Player, MenuVFX, Append To Array, Last Text ID);
  • Global._extendedGlobalCollection[8] = Custom String("");
  • Event Player._extendedPlayerCollection[2] = 0;
  • While(Event Player._extendedPlayerCollection[2] < 4.600 * Global._extendedGlobalCollection[1] - 1);
  • Global._extendedGlobalCollection[8] = Custom String("{0}{1}", Global._extendedGlobalCollection[8],
  • Global._extendedGlobalCollection[3]);
  • Event Player._extendedPlayerCollection[2] += 1;
  • End;
  • Create In-World Text(Event Player, Global._extendedGlobalCollection[8], Update Every Frame(Eye Position(Event Player) + 100 * ((
  • Global._extendedGlobalCollection[2] / 2 - 0.200) * Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(
  • Event Player)), Vertical Angle From Direction(Facing Direction Of(Event Player)) - 90) + 3 * Facing Direction Of(
  • Event Player))), 4, Do Not Clip, Visible To and Position, Color(White), Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Global._extendedGlobalCollection[9] = Custom String("");
  • Event Player._extendedPlayerCollection[2] = 0;
  • While(Event Player._extendedPlayerCollection[2] < 4.600 * Global._extendedGlobalCollection[1] - 1);
  • Global._extendedGlobalCollection[9] = Custom String("{0}{1}", Global._extendedGlobalCollection[9],
  • Global._extendedGlobalCollection[3]);
  • Event Player._extendedPlayerCollection[2] += 1;
  • End;
  • Create In-World Text(Event Player, Global._extendedGlobalCollection[9], Update Every Frame(Eye Position(Event Player) + 100 * ((
  • Global._extendedGlobalCollection[2] * -1 / 2 - 0.200) * Direction From Angles(Horizontal Angle From Direction(
  • Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(Event Player)) - 90)
  • + 3 * Facing Direction Of(Event Player))), 4, Do Not Clip, Visible To and Position, Color(White), Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Global._extendedGlobalCollection[10] = Custom String("");
  • Event Player._extendedPlayerCollection[2] = 0.300;
  • While(Event Player._extendedPlayerCollection[2] < Global._extendedGlobalCollection[2]);
  • Global._extendedGlobalCollection[10] = Custom String("{0}{1}", Global._extendedGlobalCollection[10],
  • Global._extendedGlobalCollection[4]);
  • Event Player._extendedPlayerCollection[2] += 0.300;
  • End;
  • Create In-World Text(Event Player, Global._extendedGlobalCollection[10], Update Every Frame(Eye Position(Event Player) + 100 * (
  • Global._extendedGlobalCollection[1] / 2 * Cross Product(Facing Direction Of(Event Player), Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90)) + (-0.095 * Round To Integer(Global._extendedGlobalCollection[2] / 0.300, Down) - 0.200)
  • * Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Facing Direction Of(Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 4, Do Not Clip, Visible To and Position,
  • Color(White), Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Global._extendedGlobalCollection[11] = Custom String("");
  • Event Player._extendedPlayerCollection[2] = 0.300;
  • While(Event Player._extendedPlayerCollection[2] < Global._extendedGlobalCollection[2]);
  • Global._extendedGlobalCollection[11] = Custom String("{0}{1}", Global._extendedGlobalCollection[11],
  • Global._extendedGlobalCollection[4]);
  • Event Player._extendedPlayerCollection[2] += 0.300;
  • End;
  • Create In-World Text(Event Player, Global._extendedGlobalCollection[11], Update Every Frame(Eye Position(Event Player) + 100 * (
  • Global._extendedGlobalCollection[1] * -1 / 2 * Cross Product(Facing Direction Of(Event Player), Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90)) + (-0.095 * Round To Integer(Global._extendedGlobalCollection[2] / 0.300, Down) - 0.200)
  • * Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Facing Direction Of(Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 4, Do Not Clip, Visible To and Position,
  • Color(White), Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • }
  • }
  • rule("Create exit button")
  • {
  • event
  • {
  • Subroutine;
  • createExitButton;
  • }
  • actions
  • {
  • Create Icon(Event Player, Update Every Frame(Eye Position(Event Player) + 100 * (Global.exitButtonProperties[1] * Cross Product(
  • Facing Direction Of(Event Player), Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(Event Player)),
  • Vertical Angle From Direction(Facing Direction Of(Event Player)) - 90)) + (Global.exitButtonProperties[2] - 0.250)
  • * Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Facing Direction Of(Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), X, Position and Color, Absolute Value(
  • Angle Difference(Horizontal Angle From Direction(Facing Direction Of(Event Player)), Horizontal Angle From Direction(
  • Event Player.menuOriginalFacing)) - Global.exitButtonProperties[1]) <= Global.exitButtonProperties[3] / 2 && Absolute Value(
  • Angle Difference(Vertical Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Event Player.menuOriginalFacing)) - Global.exitButtonProperties[2]) <= Global.exitButtonProperties[3] / 2 ? Color(Yellow)
  • : Color(Red), False);
  • Event Player._extendedPlayerCollection[0] = Last Created Entity;
  • }
  • }
  • rule("Menu deactivated > Clean up")
  • rule("Do button update")
  • {
  • event
  • {
  • Subroutine;
  • doButtonUpdate;
  • }
  • actions
  • {
  • Event Player._extendedPlayerCollection[2] = 0;
  • While(Event Player._extendedPlayerCollection[2] < Count Of(Event Player.buttons));
  • If(Event Player.buttons[Event Player._extendedPlayerCollection[2]]);
  • If(Event Player.buttons[Event Player._extendedPlayerCollection[2]][15]);
  • If(Event Player.buttons[Event Player._extendedPlayerCollection[2]][14]);
  • Destroy In-World Text(Event Player.buttons[Event Player._extendedPlayerCollection[2]][13]);
  • End;
  • Event Player.buttons[Event Player._extendedPlayerCollection[2]] = Null;
  • Else If((
  • !Event Player.buttons[Event Player._extendedPlayerCollection[2]][12] && Event Player.buttons[Event Player._extendedPlayerCollection[2]][14])
  • || !Event Player.isInMenu);
  • Destroy In-World Text(Event Player.buttons[Event Player._extendedPlayerCollection[2]][13]);
  • Global.textBudget += 1;
  • Global._arrayBuilder = Event Player.buttons[Event Player._extendedPlayerCollection[2]];
  • Global._arrayBuilder[14] = False;
  • Event Player.buttons[Event Player._extendedPlayerCollection[2]] = Global._arrayBuilder;
  • Else If(
  • Event Player.buttons[Event Player._extendedPlayerCollection[2]][12] && !Event Player.buttons[Event Player._extendedPlayerCollection[2]][14]);
  • Create In-World Text(Event Player, Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])
  • ][10] ? Custom String("
{0}
", First Of(Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])]))
  • : First Of(Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])]), Update Every Frame(Eye Position(
  • Event Player) + 100 * (Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][4] * Cross Product(
  • Facing Direction Of(Event Player), Direction From Angles(Horizontal Angle From Direction(Facing Direction Of(Event Player)),
  • Vertical Angle From Direction(Facing Direction Of(Event Player)) - 90)) + (Event Player.buttons[Evaluate Once(
  • Event Player._extendedPlayerCollection[2])][5] - 0.200) * Direction From Angles(Horizontal Angle From Direction(
  • Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(Event Player)) - 90)
  • + 3 * Facing Direction Of(Event Player))), Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][3],
  • Do Not Clip, Visible To Position String and Color, Event Player.buttons[Evaluate Once(
  • Event Player._extendedPlayerCollection[2])][11] && Absolute Value(Angle Difference(Horizontal Angle From Direction(
  • Facing Direction Of(Event Player)), Horizontal Angle From Direction(Event Player.menuOriginalFacing))
  • - Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][4]) <= Event Player.buttons[Evaluate Once(
  • Event Player._extendedPlayerCollection[2])][6] / 2 && Absolute Value(Angle Difference(Vertical Angle From Direction(
  • Facing Direction Of(Event Player)), Vertical Angle From Direction(Event Player.menuOriginalFacing))
  • - Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][5]) <= Event Player.buttons[Evaluate Once(
  • Event Player._extendedPlayerCollection[2])][7] / 2 ? Event Player.buttons[Evaluate Once(
  • Event Player._extendedPlayerCollection[2])][9] : Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])
  • ][8], Default Visibility);
  • Global._arrayBuilder = Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])];
  • Global._arrayBuilder[13] = Last Text ID;
  • Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])] = Global._arrayBuilder;
  • Global._arrayBuilder = Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])];
  • Global._arrayBuilder[14] = True;
  • Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])] = Global._arrayBuilder;
  • Global.textBudget -= 1;
  • End;
  • End;
  • Event Player._extendedPlayerCollection[2] += 1;
  • End;
  • }
  • }
  • rule("Create click areas")
  • {
  • event
  • {
  • Subroutine;
  • createClickAreas;
  • }
  • actions
  • {
  • Event Player._extendedPlayerCollection[2] = 0;
  • While(Event Player._extendedPlayerCollection[2] < Count Of(Event Player.buttons));
  • Create In-World Text(Event Player, Custom String("┌"), Update Every Frame(Eye Position(Event Player) + 100 * ((
  • Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][4] - Event Player.buttons[Evaluate Once(
  • Event Player._extendedPlayerCollection[2])][6] / 2) * Cross Product(Facing Direction Of(Event Player), Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90)) + (Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])
  • ][5] + Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][7] / 2 - 0.200) * Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 2, Do Not Clip, Visible To and Position,
  • !Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][12] ? Custom Color(0, 0, 0, 0) : (
  • Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][11] ? Color(Yellow) : Color(White)),
  • Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Create In-World Text(Event Player, Custom String("┘"), Update Every Frame(Eye Position(Event Player) + 100 * ((
  • Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][4] + Event Player.buttons[Evaluate Once(
  • Event Player._extendedPlayerCollection[2])][6] / 2) * Cross Product(Facing Direction Of(Event Player), Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90)) + (Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])
  • ][5] - Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][7] / 2 - 0.200) * Direction From Angles(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(Facing Direction Of(
  • Event Player)) - 90) + 3 * Facing Direction Of(Event Player))), 2, Do Not Clip, Visible To and Position,
  • !Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][12] ? Custom Color(0, 0, 0, 0) : (
  • Event Player.buttons[Evaluate Once(Event Player._extendedPlayerCollection[2])][11] ? Color(Yellow) : Color(White)),
  • Default Visibility);
  • Modify Player Variable(Event Player, menuFrame, Append To Array, Last Text ID);
  • Global.textBudget -= 1;
  • Event Player._extendedPlayerCollection[2] += 1;
  • End;
  • }
  • }
  • rule("Open menu")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • "Dummy bots were getting menu stuff and causing server crashes, so we exclude them from these rules."
  • Is Dummy Bot(Event Player) == False;
  • "Triggers once whenever the menu is closed. Technically also triggers when the game starts but that, uh, probably won't cause any problems."
  • Event Player.IsInMenuMode == False;
  • !Is Dummy Bot(Event Player) == True;
  • Event Player.isInMenu == True;
  • }
  • actions
  • {
  • "Return aim speed to normal."
  • Set Aim Speed(Event Player, 100);
  • "Reenable buttons previously reserved for menu clicking."
  • Set Primary Fire Enabled(Event Player, True);
  • Set Secondary Fire Enabled(Event Player, True);
  • "Reenable the HUD."
  • Enable Game Mode HUD(Event Player);
  • Enable Hero HUD(Event Player);
  • "Loops through all the components of the menu, destroying each one. Note that there is currently no wait in here, so if the array has a lot of elements, the server may be under a lot of stress for a moment. This may be a good place to reduce load if needed."
  • For Player Variable(Event Player, __iter__, 0, Count Of(Event Player.MenuVFX), 1);
  • "Since trying to destroy the wrong type of entity doesn't cause any errors, we simply try each type on the current entity, allowing for any type of effect or icon to be placed in MenuVFX for cleanup when the menu is closed."
  • Destroy In-World Text(Event Player.MenuVFX[Event Player.__iter__]);
  • disabled Destroy Effect(Event Player.MenuVFX[Event Player.__iter__]);
  • disabled Destroy Icon(Event Player.MenuVFX[Event Player.__iter__]);
  • disabled Destroy HUD Text(Event Player.MenuVFX[Event Player.__iter__]);
  • Set Aim Speed(Event Player, 15);
  • Event Player.menuOriginalFacing = Facing Direction Of(Event Player);
  • Set Primary Fire Enabled(Event Player, False);
  • Set Secondary Fire Enabled(Event Player, False);
  • If(Global._extendedGlobalCollection[7]);
  • Disable Hero HUD(Event Player);
  • Disable Game Mode HUD(Event Player);
  • End;
  • Event Player.menuFrame = Empty Array;
  • Call Subroutine(createCursor);
  • Wait(0.016, Ignore Condition);
  • Call Subroutine(createBorderCorners);
  • Call Subroutine(createBorderEdges);
  • Wait(0.016, Ignore Condition);
  • Call Subroutine(createExitButton);
  • Wait(0.016, Ignore Condition);
  • Call Subroutine(doButtonUpdate);
  • If(Global._extendedGlobalCollection[5]);
  • Call Subroutine(createClickAreas);
  • End;
  • }
  • }
  • rule("Force menu exit on emote")
  • rule("Menu loading hud")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • "Dummy bots were getting menu stuff and causing server crashes, so we exclude them from these rules."
  • Is Dummy Bot(Event Player) == False;
  • "I added this in because emoting prevents you from moving your aim, thus making the cursor immovable. Remove at your own peril."
  • Event Player.IsInMenuMode == True;
  • Is Communicating Any Emote(Event Player) == True;
  • Workshop Setting Toggle(Custom String("Josbird's Cursor Menu"), Custom String("Loading hud"), True, 6) == True;
  • Event Player.isInMenu == True;
  • }
  • actions
  • {
  • Event Player.IsInMenuMode = False;
  • Create HUD Text(Event Player, Custom String("loading menu..."), Null, Null, Top, 3, Color(Turquoise), Color(White), Color(White),
  • None, Default Visibility);
  • Event Player._extendedPlayerCollection[1] = Last Text ID;
  • Global.textBudget -= 1;
  • Wait(1, Ignore Condition);
  • Destroy HUD Text(Event Player._extendedPlayerCollection[1]);
  • Global.textBudget += 1;
  • }
  • }
  • rule("Cursor bounding box")
  • rule("Close menu")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • "Dummy bots were getting menu stuff and causing server crashes, so we exclude them from these rules."
  • Is Dummy Bot(Event Player) == False;
  • Event Player.IsInMenuMode == True;
  • "Checks if the cursor is more than 0.1 screen units outside of the bounding box. If you resize the screen make sure to change this as well."
  • (Absolute Value(Event Player.CursorX) > 2.600 || Absolute Value(Event Player.CursorY) > 1.350) == True;
  • !Is Dummy Bot(Event Player) == True;
  • !Event Player.isInMenu == True;
  • }
  • actions
  • {
  • "Clamps the player's horizontal facing to the range of valid screen space. Screen border values should replace the 2.500s and 1.250s here if you resize the screen."
  • Set Facing(Event Player, Direction From Angles(Min(Max(Horizontal Angle From Direction(Facing Direction Of(Event Player)),
  • Horizontal Angle From Direction(Event Player.MenuOriginalFacing) - 2.500 / 0.750), Horizontal Angle From Direction(
  • Event Player.MenuOriginalFacing) + 2.500 / 0.750), Min(Max(Vertical Angle From Direction(Facing Direction Of(Event Player)),
  • Vertical Angle From Direction(Event Player.MenuOriginalFacing) - 1.250 / 0.750), Vertical Angle From Direction(
  • Event Player.MenuOriginalFacing) + 1.250 / 0.750)), To World);
  • "Double checks every 100ms that the cursor is not still outside the bounds of the menu. This is necessary because if the player moves their aim fast enough, they could overcome the border if they were fast enough."
  • Wait(0.100, Ignore Condition);
  • Loop If Condition Is True;
  • Set Aim Speed(Event Player, 100);
  • Set Primary Fire Enabled(Event Player, True);
  • Set Secondary Fire Enabled(Event Player, True);
  • If(Global._extendedGlobalCollection[7]);
  • Enable Hero HUD(Event Player);
  • Enable Game Mode HUD(Event Player);
  • End;
  • Event Player._extendedPlayerCollection[2] = 0;
  • While(Event Player._extendedPlayerCollection[2] < Count Of(Event Player.menuFrame));
  • Destroy In-World Text(Event Player.menuFrame[Event Player._extendedPlayerCollection[2]]);
  • Global.textBudget += 1;
  • Event Player._extendedPlayerCollection[2] += 1;
  • End;
  • Destroy Icon(First Of(Event Player._extendedPlayerCollection));
  • Call Subroutine(doButtonUpdate);
  • }
  • }
  • rule("Check for button update")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • Event Player.isInMenu == True;
  • Is True For Any(Event Player.buttons, Current Array Element && (Current Array Element[15] || (
  • !Current Array Element[12] && Current Array Element[14]) || (Current Array Element[12] && !Current Array Element[14])))
  • == True;
  • }
  • actions
  • {
  • Call Subroutine(doButtonUpdate);
  • Wait(0.016, Ignore Condition);
  • }
  • }
  • rule("Detect primary fire button press")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • "Dummy bots were getting menu stuff and causing server crashes, so we exclude them from these rules."
  • Is Dummy Bot(Event Player) == False;
  • "Rather than checking for a button click in conditions, we only check for a mouse click so that the player can't press down primary fire then move the cursor onto the button."
  • Event Player.IsInMenuMode == True;
  • Is Button Held(Event Player, Primary Fire) == True;
  • Event Player.isInMenu == True;
  • Is Button Held(Event Player, Button(Primary Fire)) == True;
  • }
  • actions
  • {
  • "Clears the primary action ID queue."
  • Event Player.ActionIDQueue = Empty Array;
  • "Checks if the cursor is currently within radius of the exit button."
  • If(Distance Between(Event Player.CursorPos,
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonExitMenu[2] + Event Player.MenuYAxis * Event Player.ButtonExitMenu[3])
  • <= 100 * Event Player.ButtonExitMenu[4]);
  • "Add the exit button's action ID to the primary action ID queue."
  • Modify Player Variable(Event Player, ActionIDQueue, Append To Array, Event Player.ButtonExitMenu[1]);
  • End;
  • "For each button, checks if the cursor is within that button's click area."
  • For Player Variable(Event Player, __iter__, 0, Count Of(Event Player.ButtonProperties), 1);
  • If(Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[Event Player.__iter__][2])
  • <= Event Player.ButtonProperties[Event Player.__iter__][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[Event Player.__iter__][3])
  • <= Event Player.ButtonProperties[Event Player.__iter__][5] / 2);
  • "If so, add that button's primary action ID to the queue."
  • Modify Player Variable(Event Player, ActionIDQueue, Append To Array, Event Player.ButtonProperties[Event Player.__iter__][1]);
  • If(Absolute Value(Angle Difference(Horizontal Angle From Direction(Facing Direction Of(Event Player)),
  • Horizontal Angle From Direction(Event Player.menuOriginalFacing)) - Global.exitButtonProperties[1])
  • <= Global.exitButtonProperties[3] / 2 && Absolute Value(Angle Difference(Vertical Angle From Direction(Facing Direction Of(
  • Event Player)), Vertical Angle From Direction(Event Player.menuOriginalFacing)) - Global.exitButtonProperties[2])
  • <= Global.exitButtonProperties[3] / 2);
  • Event Player.currActionID = First Of(Global.exitButtonProperties);
  • End;
  • Event Player._extendedPlayerCollection[3] = 0;
  • While(Event Player._extendedPlayerCollection[3] < Count Of(Event Player.buttons));
  • If(Event Player.buttons[Event Player._extendedPlayerCollection[3]][11] && Absolute Value(Angle Difference(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Horizontal Angle From Direction(
  • Event Player.menuOriginalFacing)) - Event Player.buttons[Event Player._extendedPlayerCollection[3]][4])
  • <= Event Player.buttons[Event Player._extendedPlayerCollection[3]][6] / 2 && Absolute Value(Angle Difference(
  • Vertical Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Event Player.menuOriginalFacing)) - Event Player.buttons[Event Player._extendedPlayerCollection[3]][5])
  • <= Event Player.buttons[Event Player._extendedPlayerCollection[3]][7] / 2);
  • Event Player.currActionID = Event Player.buttons[Event Player._extendedPlayerCollection[3]][1];
  • End;
  • Event Player._extendedPlayerCollection[3] += 1;
  • End;
  • If(Event Player.currActionID && Global._extendedGlobalCollection[6]);
  • Play Effect(Event Player, Explosion Sound, Color(White), Event Player, 30);
  • End;
  • "Set the current action ID variable to the first button clicked for one tick."
  • Event Player.CurrActionID = First Of(Event Player.ActionIDQueue);
  • Wait(0.016, Ignore Condition);
  • Event Player.CurrActionID = Null;
  • Event Player.currActionID = Null;
  • }
  • }
  • rule("Detect secondary fire button press")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • "Dummy bots were getting menu stuff and causing server crashes, so we exclude them from these rules."
  • Is Dummy Bot(Event Player) == False;
  • "Rather than checking for a button click in conditions, we only check for a mouse click so that the player can't press down secondary fire then move the cursor onto the button."
  • Event Player.IsInMenuMode == True;
  • Is Button Held(Event Player, Secondary Fire) == True;
  • Event Player.isInMenu == True;
  • Is Button Held(Event Player, Button(Secondary Fire)) == True;
  • }
  • actions
  • {
  • "Clears the secondary action ID queue."
  • Event Player.ActionIDQueue_Secondary = Empty Array;
  • "Checks if the cursor is currently within radius of the exit button."
  • If(Distance Between(Event Player.CursorPos,
  • Event Player.MenuEyePos + Event Player.MenuZAxis * 3 + Event Player.MenuXAxis * Event Player.ButtonExitMenu[2] + Event Player.MenuYAxis * Event Player.ButtonExitMenu[3])
  • <= 100 * Event Player.ButtonExitMenu[4]);
  • "Add the exit button's action ID to the secondary action ID queue."
  • Modify Player Variable(Event Player, ActionIDQueue_Secondary, Append To Array, Event Player.ButtonExitMenu[1]);
  • End;
  • "For each button, checks if the cursor is within that button's click area."
  • For Player Variable(Event Player, __iter__, 0, Count Of(Event Player.ButtonProperties), 1);
  • If(Absolute Value(Event Player.CursorX - Event Player.ButtonProperties[Event Player.__iter__][2])
  • <= Event Player.ButtonProperties[Event Player.__iter__][4] / 2 && Absolute Value(
  • Event Player.CursorY - Event Player.ButtonProperties[Event Player.__iter__][3])
  • <= Event Player.ButtonProperties[Event Player.__iter__][5] / 2);
  • "If so, add that button's secondary action ID to the queue."
  • Modify Player Variable(Event Player, ActionIDQueue_Secondary, Append To Array,
  • Event Player.ButtonProperties[Event Player.__iter__][9]);
  • If(Absolute Value(Angle Difference(Horizontal Angle From Direction(Facing Direction Of(Event Player)),
  • Horizontal Angle From Direction(Event Player.menuOriginalFacing)) - Global.exitButtonProperties[1])
  • <= Global.exitButtonProperties[3] / 2 && Absolute Value(Angle Difference(Vertical Angle From Direction(Facing Direction Of(
  • Event Player)), Vertical Angle From Direction(Event Player.menuOriginalFacing)) - Global.exitButtonProperties[2])
  • <= Global.exitButtonProperties[3] / 2);
  • Event Player.currActionID = First Of(Global.exitButtonProperties);
  • End;
  • Event Player._extendedPlayerCollection[4] = 0;
  • While(Event Player._extendedPlayerCollection[4] < Count Of(Event Player.buttons));
  • If(Event Player.buttons[Event Player._extendedPlayerCollection[4]][11] && Absolute Value(Angle Difference(
  • Horizontal Angle From Direction(Facing Direction Of(Event Player)), Horizontal Angle From Direction(
  • Event Player.menuOriginalFacing)) - Event Player.buttons[Event Player._extendedPlayerCollection[4]][4])
  • <= Event Player.buttons[Event Player._extendedPlayerCollection[4]][6] / 2 && Absolute Value(Angle Difference(
  • Vertical Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Event Player.menuOriginalFacing)) - Event Player.buttons[Event Player._extendedPlayerCollection[4]][5])
  • <= Event Player.buttons[Event Player._extendedPlayerCollection[4]][7] / 2);
  • Event Player.currActionID = Event Player.buttons[Event Player._extendedPlayerCollection[4]][2];
  • End;
  • Event Player._extendedPlayerCollection[4] += 1;
  • End;
  • If(Event Player.currActionID && Global._extendedGlobalCollection[6]);
  • Play Effect(Event Player, Explosion Sound, Color(White), Event Player, 30);
  • End;
  • "Set the current action ID variable to the first button clicked for one tick."
  • Event Player.CurrActionID_Secondary = First Of(Event Player.ActionIDQueue_Secondary);
  • Wait(0.016, Ignore Condition);
  • Event Player.CurrActionID_Secondary = Null;
  • Event Player.currActionID = Null;
  • }
  • }
  • rule("Action ID \"exit menu\"")
  • rule("Action ID: Exit menu")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • Event Player.CurrActionID == Custom String("exit menu");
  • Event Player.currActionID == Custom String("exit menu");
  • }
  • actions
  • {
  • Play Effect(Event Player, Explosion Sound, White, Event Player, 35);
  • Event Player.IsInMenuMode = False;
  • Event Player.isInMenu = False;
  • }
  • }
  • rule("Secondary action ID \"exit menu\"")
  • rule("Cursor bounds")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • }
  • conditions
  • {
  • Event Player.CurrActionID_Secondary == Custom String("exit menu");
  • Event Player.isInMenu == True;
  • (Absolute Value(Angle Difference(Horizontal Angle From Direction(Facing Direction Of(Event Player)),
  • Horizontal Angle From Direction(Event Player.menuOriginalFacing)))
  • > Global._extendedGlobalCollection[1] / 2 + 0.050 || Absolute Value(Angle Difference(Vertical Angle From Direction(
  • Facing Direction Of(Event Player)), Vertical Angle From Direction(Event Player.menuOriginalFacing)))
  • > Global._extendedGlobalCollection[2] / 2 + 0.050) == True;
  • }
  • actions
  • {
  • Play Effect(Event Player, Explosion Sound, White, Event Player, 35);
  • Event Player.IsInMenuMode = False;
  • Set Facing(Event Player, Direction From Angles(Min(Max(Horizontal Angle From Direction(Event Player.menuOriginalFacing)
  • - Angle Difference(Horizontal Angle From Direction(Facing Direction Of(Event Player)), Horizontal Angle From Direction(
  • Event Player.menuOriginalFacing)), Horizontal Angle From Direction(Event Player.menuOriginalFacing)
  • - Global._extendedGlobalCollection[1] / 2), Horizontal Angle From Direction(Event Player.menuOriginalFacing)
  • + Global._extendedGlobalCollection[1] / 2), Min(Max(Vertical Angle From Direction(Event Player.menuOriginalFacing)
  • - Angle Difference(Vertical Angle From Direction(Facing Direction Of(Event Player)), Vertical Angle From Direction(
  • Event Player.menuOriginalFacing)), Vertical Angle From Direction(Event Player.menuOriginalFacing)
  • - Global._extendedGlobalCollection[2] / 2), Vertical Angle From Direction(Event Player.menuOriginalFacing)
  • + Global._extendedGlobalCollection[2] / 2)), To World);
  • Wait(0.016, Ignore Condition);
  • Loop If Condition Is True;
  • }
  • }
  • rule(">>>EDIT BUTTON & LABEL STARTING VALUES HERE<<<")
  • rule("Text budget warning")
  • {
  • event
  • {
  • Ongoing - Each Player;
  • All;
  • All;
  • Ongoing - Global;
  • }
  • conditions
  • {
  • "Dummy bots were getting menu stuff and causing server crashes, so we exclude them from these rules."
  • Is Dummy Bot(Event Player) == False;
  • "This rule currently resets all buttons to their initial states any time the menu is opened. If you want button states to persist between menu uses, disable this condition."
  • Event Player.IsInMenuMode == True;
  • Global.textBudget < 0;
  • }
  • actions
  • {
  • "Empty the button properties array."
  • Event Player.ButtonProperties = Empty Array;
  • "Sample button"
  • disabled Modify Player Variable(Event Player, ButtonProperties, Append To Array, Array(Array(Custom String("Label text"), Custom String(
  • "Action ID"), 0, 0, 1, 0.150, True, True, 3, Null, Null, Null)));
  • Small Message(Host Player, Custom String("{0} Warning! Text budget exceeded! {0}", Icon String(Warning)));
  • }
  • }
  • rule("▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒a")
  • rule("▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒a")
  • {
  • event
  • {
  • Ongoing - Global;
  • }
  • }
Join the Workshop.codes Discord