HyperScript
Docs

← All of the Docs The basics

Complete example: demo.hs

Show Complete example: demo.hs

This is the file installed to plugins/HyperScript/scripts/disabled_demo.hs on first start, switched off until /hyperscript enable demo (source). It uses commands, every event, math, persistent variables, a GUI, lists, an async block, world effects, cooldowns, titles, a boss bar, an opt-in sidebar driven by a timer, a custom item, a stored location, a text file per player, sounds, a protected region, time and weather, a web API lookup read with json value, fall-damage protection, a countdown built from while and wait, a function, parse, another player's variables, loop all players, inventory checks, and ends with Discord examples that are commented out until config.yml is set up.

# ==============================================================
#  demo.hs - a tour of HyperScript
#  Edit this file, then run /hyperscript reload
# ==============================================================

# ---- Events --------------------------------------------------

on player join:
    if {%player%.joins} is not set:
        set {%player%.joins} to 0
        set {%player%.coins} to 100
        broadcast "&6Welcome &e%player.name% &6to the server for the first time!"
    add 1 to {%player%.joins}
    send "&aHello %player.name%! &7Visit #%{%player%.joins}%, balance &e%{%player%.coins}% coins"
    send "&7Server %server.version% | TPS %server.tps% | Online %server.online_players%"
    if {event_active}:
        send "&d&lThe double coins event is active!"

on player quit:
    log "%player.name% left with %{%player%.coins}% coins (ping %player.ping% ms)"

on block break:
    # Regions made with /protect: only admins may break blocks inside them.
    if region at event's location contains "spawn":
        if player does not have permission "demo.admin":
            cancel event
            send "&cYou cannot break blocks inside the spawn region!"
            play sound "block.anvil.land" with pitch 0.5 and volume 1.0 at player's location
            stop
    set {_reward} to random integer between 1 and 3
    if event.block contains "ore":
        set {_reward} to {_reward} * 5
    if player has permission "demo.vip":
        set {_reward} to {_reward} + 2
    if {event_active}:
        set {_reward} to {_reward} * 2
    add {_reward} to {%player%.coins}
    add 1 to {%player%.blocks}
    # Every 50th block pays a bonus.
    if {%player%.blocks} % 50 == 0:
        add 25 to {%player%.coins}
        send "&b%{%player%.blocks}% blocks mined! &6+25 bonus coins"
        play sound "entity.player.levelup" with pitch 1.2 and volume 0.8 for player

on entity death:
    # The player here is the killer; there is none when a mob dies on its own.
    if event.killer is set:
        set {_bounty} to random integer between 5 and 15
        add {_bounty} to {%player%.coins}
        send "&6+%{_bounty}% coins &7for slaying a %event.entity%"

on player chat:
    # Inside an event, its values have short names: "message" is event.message.
    if message contains "free op":
        cancel event
        send "&cThat phrase is not allowed here."

on entity damage:
    # Fires for every hit on the server, so the cheapest test comes first.
    if cause is "FALL":
        if player has permission "demo.nofall":
            cancel event
            send action bar "&aFall damage negated!" to victim

on right click:
    # At most once every 2 seconds per player; clicks in between are ignored.
    cooldown: 2 seconds
    if event.item == "compass":
        send "&bWorld &f%player.world% &7| &bMode &f%player.gamemode% &7| &bHealth &f%player.health%"

# ---- Commands ------------------------------------------------

command /coins:
    description: Show your coin balance
    usage: /coins
    aliases: bal, balance
    trigger:
        if player is not set:
            send "&cOnly players have a balance."
            stop
        send "&6Balance: &e%{%player%.coins}% coins"

command /gamble:
    description: Bet coins on a 45% chance to double them
    usage: /gamble <amount>
    permission: demo.gamble
    permission message: "&cYou are not allowed to gamble."
    aliases: bet
    trigger:
        if player is not set:
            send "&cOnly players can gamble."
            stop
        if args.count != 1 or arg.1 is not a number:
            send "&cUsage: /gamble <amount>"
            stop
        set {_bet} to arg.1
        if {_bet} <= 0:
            send "&cThe bet must be more than 0."
        else if {_bet} > {%player%.coins}:
            send "&cYou only have %{%player%.coins}% coins."
        else if random integer between 1 and 100 <= 45:
            add {_bet} to {%player%.coins}
            send "&aYou won %{_bet}% coins! &7Balance: %{%player%.coins}%"
        else:
            subtract {_bet} from {%player%.coins}
            send "&cYou lost %{_bet}% coins. &7Balance: %{%player%.coins}%"

command /event:
    description: Toggle the double coins event
    usage: /event <on|off>
    permission: demo.admin
    trigger:
        if arg.1 == "on":
            set {event_active} to true
            broadcast "&d&lDouble coins event started!"
            create bossbar "event" titled "&d&lDouble Coins Event" with color purple with progress 100 for all players
        else if arg.1 == "off":
            set {event_active} to false
            broadcast "&7The double coins event has ended."
            remove bossbar "event"
        else:
            send "&eEvent active: %{event_active}% &7- usage: /event <on|off>"

# ---- GUIs, lists, async and world effects --------------------

command /shop:
    description: Open the coin shop
    usage: /shop
    trigger:
        if player is not set:
            send "&cOnly players can open the shop."
            stop
        open gui with title "&8Coin Shop" with 3 rows for player:
            slot 12 is "diamond" named "&bDiamond" lore "&7Price: &e50 coins|&7Click to buy":
                if {%player%.coins} < 50:
                    send "&cYou need 50 coins for that."
                else:
                    subtract 50 from {%player%.coins}
                    execute console command "give %player.name% diamond 1"
                    spawn particle "dust" colored "#55ffff" count 20 at player
                    send "&aBought a diamond. &7Balance: %{%player%.coins}%"
                close gui
            slot 14 is "gold_ingot" named "&6Balance: &e%{%player%.coins}% coins"
            slot 16 is "barrier" named "&cClose":
                close gui

command /who:
    description: List online players in alphabetical order
    usage: /who
    trigger:
        send "&6Online (%server.online_players%):"
        for each {_name} in sorted server.players:
            send "&7 - &f%{_name}%"

command /sethome:
    description: Remember where you are standing
    usage: /sethome
    trigger:
        if player is not set:
            stop
        # A variable can hold a location (world and coordinates) as one value.
        set {%player%.home} to player's location
        spawn text display "&e%player.name%'s home" at player for 10 seconds
        send "&aHome set."

command /home:
    description: Return to your home
    usage: /home
    trigger:
        if {%player%.home} is not set:
            send "&cUse /sethome first."
            stop
        teleport player to {%player%.home}
        send "&aWelcome home. &7(%{%player%.home}%)"

command /highscores:
    description: Show the balances recorded with /cashout
    usage: /highscores
    trigger:
        # {scores} is a list; /cashout appends to it.
        async:
            # Sorting and filtering run off the server thread...
            set {_ranked} to reversed sorted {scores}
            set {_count} to size of {_ranked}
            set {_best} to item 1 of {_ranked}
            set {_rich} to size of (filter {_ranked} where it >= 500)
            sync:
                # ...and the result is reported back on it.
                if {_count} == 0:
                    send "&7No scores yet. Use /cashout to record yours."
                else:
                    send "&6Best score: &e%{_best}% &7(%{_count}% recorded, %{_rich}% of 500 or more)"

command /cashout:
    description: Record your current balance on the high score list
    usage: /cashout
    trigger:
        if player is not set:
            stop
        append {%player%.coins} to {scores}
        send "&aRecorded &e%{%player%.coins}% &aon the high score list."

# ---- Functions, other players and parsing --------------------

# A function can be called from any script. Written as "local function"
# it could only be used in this file.
function pay({_from}, {_to}, {_amount}):
    subtract {_amount} from {%{_from}%.coins}
    add {_amount} to {%{_to}%.coins}
    return {%{_to}%.coins}

command /pay <player> <amount>:
    description: Give some of your coins to another player
    usage: /pay <player> <amount>
    trigger:
        if player is not set:
            stop
        # Arguments arrive as text; parse turns "52" into the number 52.
        set {_amount} to parse arg.2 as integer
        if {_amount} is not set or {_amount} < 1:
            send "&c'%arg.2%' is not an amount."
            stop
        # A name that starts with a player is that player's own variable,
        # whether they are online or not.
        if {%arg.1%.joins} is not set:
            send "&c%arg.1% has never played here."
            stop
        if {%player%.coins} < {_amount}:
            send "&cYou only have %{%player%.coins}% coins."
            stop
        set {_total} to pay(player.name, arg.1, {_amount})
        send "&aSent &e%{_amount}% &acoins to %arg.1%."
        send "&e%player.name% &asent you &e%{_amount}% &acoins. You now have &e%{_total}%&a." to arg.1

command /bonus <amount>:
    description: Give every online player some coins
    usage: /bonus <amount>
    permission: op
    trigger:
        set {_amount} to parse arg.1 as integer
        if {_amount} is not set:
            send "&cUsage: /bonus <amount>"
            stop
        # "player" is still whoever ran the command; "loop-player" is each player in turn.
        loop all players:
            add {_amount} to {%loop-player%.coins}
        send "&6Everybody received &e%{_amount}% &6coins from %player.name%!" to all players

command /sell:
    description: Sell 8 cobblestone for 4 coins
    usage: /sell
    trigger:
        if player does not have 8 cobblestone:
            send "&cYou need 8 cobblestone to sell."
            stop
        remove 8 cobblestone from player
        add 4 to {%player%.coins}
        send "&aSold 8 cobblestone for &e4 coins&a."

on player death:
    subtract 5 from {%player%.coins}
    send "&cYou died and lost 5 coins."

# ---- Cooldowns, titles, scoreboards and particle shapes ------

command /kit:
    description: Claim a starter kit once an hour
    usage: /kit
    cooldown: 1 hour
    cooldown message: "&cYou must wait %cooldown% before using /kit again!"
    trigger:
        if player is not set:
            send "&cOnly players can claim a kit."
            stop
        give 1 diamond to player
        give 16 bread to player
        send title "&6Kit claimed!" with subtitle "&eCome back in an hour" to player with fadein 10 stay 60 fadeout 20
        send action bar "&a+1 Diamond  +16 Bread" to player
        draw particle circle with radius 1.5 using particle "flame" at player's location

command /sidebar:
    description: Show or hide the stats sidebar
    usage: /sidebar
    trigger:
        if player is not set:
            stop
        if {%player%.sidebar}:
            set {%player%.sidebar} to false
            clear player's scoreboard
            send "&7Sidebar hidden."
        else:
            set {%player%.sidebar} to true
            send "&aSidebar shown."

# Runs once a second for every online player; only those who asked get the sidebar.
every 1 second for all players:
    if {%player%.sidebar}:
        set title of player's scoreboard to "&e&lHYPERSCRIPT"
        set line 1 of player's scoreboard to "&7Coins: &a%{%player%.coins}%"
        set line 2 of player's scoreboard to "&7Ping: &f%player.ping% ms"
        set line 3 of player's scoreboard to "&7Online: &f%server.online_players%"
        set line 4 of player's scoreboard to "&7TPS: &f%server.tps%"

# ---- Custom items, files and text ----------------------------

command /excalibur:
    description: Receive a named sword, once a day
    usage: /excalibur
    cooldown: 1 day
    trigger:
        if player is not set:
            send "&cOnly players can wield it."
            stop
        give player 1 diamond sword named "&6Excalibur" with lore "&7A legendary blade", "&7Forged in fire."
        # Items are values too: remember what was handed out.
        set {%player%.last_reward} to diamond sword named "&6Excalibur"
        send "&aYou received &f%{%player%.last_reward}%&a."

command /note:
    description: Save a note to a text file, or read it back
    usage: /note [text]
    trigger:
        if player is not set:
            stop
        # One file per player, named by UUID so nothing a player types ends up in the path.
        set {_path} to "plugins/HyperScript/notes/%player.uuid%.txt"
        if args.count > 0:
            set file at {_path} to args
            send "&aNote saved."
        else if file at {_path} exists:
            set {_note} to read file at {_path}
            set {_words} to split {_note} by " "
            set {_count} to size of {_words}
            set {_shout} to uppercase (first 20 characters of {_note})
            send "&eYour note (%{_count}% words): &f%{_note}%"
            send "&7Starts with: &f%{_shout}%"
        else:
            send "&7You have no note yet. Write one with /note <text>"

# ---- Worlds, regions, sounds and web requests ----------------

command /day:
    description: Set the time to day and clear the weather in your world
    usage: /day
    permission: demo.admin
    trigger:
        if player is not set:
            send "&cRun this as a player, so there is a world to change."
            stop
        set time in world "%player.world%" to 1000
        set weather in world "%player.world%" to clear
        broadcast "&e%player.name% set the time to day in %player.world%!"
        play sound "block.note_block.pling" with pitch 2.0 and volume 0.5 for all players in world "%player.world%"

command /protect:
    description: Protect the area within 5 blocks of you as the spawn region
    usage: /protect
    permission: demo.admin
    trigger:
        if player is not set:
            stop
        create region "spawn" from player.x - 5, 0, player.z - 5 to player.x + 5, 255, player.z + 5
        send "&aSpawn region set around you. Remove it with /unprotect."

command /unprotect:
    description: Remove the spawn region
    usage: /unprotect
    permission: demo.admin
    trigger:
        delete region "spawn"
        send "&7Spawn region removed."

command /lookup <player>:
    description: Look up a player's UUID using Mojang's web API
    cooldown: 5 seconds
    trigger:
        if args.count != 1:
            send "&cUsage: /lookup <player>"
            reset cooldown
            stop
        send "&eFetching data from the API..."
        # Web requests wait for an answer, so they belong in an async block.
        async:
            set {_response} to send get request to "https://api.mojang.com/users/profiles/minecraft/" + urlencoded arg.1
            # The answer is JSON such as {"id":"...","name":"..."}; pick the id out of it.
            set {_uuid} to json value "id" of {_response}
            sync:
                if {_uuid} is set:
                    send "&aUUID of %arg.1%: &f%{_uuid}%"
                else:
                    send "&cPlayer profile not found."

command /countdown:
    description: Count down from 3, one number a second
    usage: /countdown
    cooldown: 10 seconds
    trigger:
        set {_n} to 3
        # 'wait' pauses this trigger only; the server carries on as normal meanwhile.
        while {_n} > 0:
            send title "&e%{_n}%" to player with fadein 0 stay 20 fadeout 5
            play sound "block.note_block.pling" for player
            wait 1 second
            subtract 1 from {_n}
        send title "&aGo!" to player

# ---- Server list, tab list and chat (remove the leading '#' to use) ----
#
# on server ping:
#     set motd to random item of ["&6HyperScript demo server", "&bNow with double coins!"]
#     set max players to 100
#
# on player join:
#     set join message to "&a+ &f%player.name%"
#     set tab header of player to "&6&lMy Server"
#     set tab footer of player to "&7Online: %server.online_players%"
#
# on player chat:
#     set chat format to "&7[&bMember&7] &f%player.name%&7: &f%event.message%"

# ---- Resource packs (remove the leading '#' and use your own pack) ----
#
# on player join:
#     send resource pack "https://example.com/pack.zip" with hash "da39a3ee5e6b4b0d3255bfef95601890afd80709" to player
#
# on resource pack decline:
#     send "&cYou declined the resource pack. Some custom items may look wrong."
#
# on resource pack successfully loaded:
#     send "&aResource pack loaded!"

# ---- Discord (remove the leading '#' after setting up config.yml) ----
#
# Webhooks need a URL under discord.webhooks in config.yml:
#
# on player join:
#     send webhook "alerts" with content "%player.name% joined the server" as "HyperScript"
#
# Slash commands need discord.bot.enabled and a bot token:
#
# on discord command "/online":
#     reply "%server.online_players% player(s) online: %server.players%"