Skip to content

Wizards of Lua — Example Spells

Here are some small examples to help you get started with Lua scripting in Minecraft using the Wizards of Lua mod.


Create a 3x3 Platform Below You

Place slime blocks in a 3x3 area under the caster's feet:

local pos = spell.owner.pos + Vec3(0, -1, 0)
for x = -1, 1 do
  for z = -1, 1 do
    spell.pos = pos + Vec3(x, 0, z)
    spell.block = Block:new("slime_block")
  end
end

Delete the Block You're Looking At

Removes the block the player is pointing at:

local hit = spell.owner:raycastBlock(5)
if not hit then return end
spell.pos = hit.blockPos
spell.block = Block:new("air") -- deletes the block

Inspect a Block

Print the block ID, name, and data:

local hit = spell.owner:raycastBlock(5)
if hit then
  spell.pos = hit.blockPos
else
  spell.pos = spell.owner.eyePos + spell.owner.lookVec * 5
end
print("id", spell.block.type.id)
print("name", spell.block.type.name)
print("data", str(spell.block.data))

Auto-Build Ladder Up a Wall

Builds ladders up the targeted wall until blocked or the backing isn't solid:

local hit = spell.owner:raycastBlock(5)
if not hit or hit.side == "up" or hit.side == "down" then return end
local ladder = Block:new("ladder")
ladder.data.facing = hit.side
spell.pos = hit.blockPos
spell:move(hit.side)
while true do
  spell.block = ladder
  spell:move("up")
  if spell.block.type.id ~= "air" then break end
  spell:move(hit.side, -1)
  if not spell.block.opaque then break end
  spell:move(hit.side)
end

Make a Particle Cloud

Creates an ongoing cloud of smoke particles:

while true do
  spell.pos = spell.owner.pos
  spell:execute("/particle minecraft:smoke ~ ~2 ~ 1 2 1 0 20 force")
  sleep(20)
end

Tip: Use spell:executeSilent(...) to hide the command output. Use /wol spell break to stop all long running spells.


Make a Spell Visible

Fire a spell forward from your eyes:

spell.pos = spell.owner.eyePos
spell.visible = true
spell.velocity = spell.owner.lookVec * 0.1
sleep(20 * 10)

Inspect Player Inventory

Displays what's in the caster’s inventory:

local player = spell.owner
print("Inventory:", str(player.inventory))

Give Players a Diamond Sword on Login

Wipes their inventory and gives a sword when they join:

local function giveOnlyDiamondSword(player)
  --- @cast player Player
  player.inventory:clear()  
  player.mainHandItem = Item:new("diamond_sword")
end

local eventQueue = spell:collect("PlayerJoinedEvent")
while true do
  local event = eventQueue:next()
  --- @cast event PlayerJoinedEvent
  giveOnlyDiamondSword(event.player)
end

Note: This only works in multiplayer; in singleplayer, all spells stop when you leave the world.


Block Protection Zone

Prevents block breaking or placing in a radius:

local radius = 10
spell.visible = true
spell:intercept({ "BeforePlayerBlockBreakEvent", "PlayerUseBlockEvent" }, function(event)
  local pos = type(event) == "BeforePlayerBlockBreakEvent" and event.pos or event.hitResult.blockPos
  return (pos - spell.pos):magnitude() > radius
end)

while true do sleep(20) end

Auto-Toggle Gamemode Field

Switch players between survival and adventure automatically:

local radius = 10
spell.visible = true
local pos = spell.pos

while true do
  sleep(1)
  for _, p in ipairs(spell:findEntities("@a[distance=.." .. radius .. ",gamemode=survival]")) do
    ---@cast p Player
    p.gamemode = "adventure"
    spell.pos = p.pos
    spell:execute("/playsound minecraft:block.enchantment_table.use master @a[distance=..5] ~ ~ ~")
  end
  spell.pos = pos
  for _, p in ipairs(spell:findEntities("@a[distance=" .. radius .. "..,gamemode=adventure]")) do
    ---@cast p Player
    p.gamemode = "survival"
    spell.pos = p.pos
    spell:execute("/playsound minecraft:entity.illusioner.cast_spell master @a[distance=..5] ~ ~ ~")
  end
  spell.pos = pos
end

Smite Nearby Zombies

Strikes all nearby zombies with lightning:

local nearbyZombies = spell:findEntities("@e[type=zombie,distance=..20]")
for i = 1, 3 do
  for _, zombie in ipairs(nearbyZombies) do
    spell.pos = zombie.pos
    spell:execute("/execute run summon lightning_bolt")
  end
  sleep(10)
end

Night Vision for Golden Helmet Wearers

Continuously grants Night Vision to any player wearing a golden helmet and removes it once they take it off.

local tracked = {}
while true do
  for _, player in ipairs(spell:findEntities("@a")) do
    ---@cast player Player
    local head = player:getEquipment("head")
    local wearing = head and head.type.id == "golden_helmet"
    local id = player.name
    if wearing then
      spell:executeSilent(
        "effect give " .. id
        .. " minecraft:night_vision 20 0 true"
      )
      tracked[id] = true
    elseif tracked[id] then
      spell:executeSilent(
        "effect clear " .. id .. " minecraft:night_vision"
      )
      tracked[id] = nil
    end
  end
  sleep(20)
end

Thunder Stick: Lightning Bolt Spell

Assigns a special stick to the player. When swung, it strikes nearby hostile mobs with lightning.

local spellName = "thunder-spell"
-- Prevent duplicates by stopping existing spell with same name
spell:executeSilent("wol spell break byName " .. spellName)
spell.name = spellName

local function castLightningBolt(player)
  local oldPos = spell.pos
  spell.pos = player.pos
  local nearbyEntities = spell:findEntities("@e[type=!player,distance=..20]")
  local hostileEntities = {}
  for _, entity in ipairs(nearbyEntities) do
    if instanceOf(LivingEntity, entity) then
      ---@cast entity LivingEntity
      if entity.hostile then
        table.insert(hostileEntities, entity)
      end
    end
  end
  if #hostileEntities > 0 then
    spell.pos = player.pos
    spell:execute("/particle minecraft:instant_effect ~ ~1 ~ 0 1 0 2 50 force")
  end
  for i = 1, 3 do
    for _, entity in ipairs(hostileEntities) do
      spell.pos = entity.pos
      spell:execute("/execute run summon lightning_bolt")
    end
    sleep(10)
  end
  spell.pos = oldPos
end

local stick = Item:new("stick")
stick.name = "Thunder Stick"
local player = spell.owner
---@cast player Player
player.mainHandItem = stick
local eventQueue = spell:collect("PlayerHandSwingEvent")
while true do
  local event = eventQueue:next()
  ---@cast event PlayerHandSwingEvent
  if event.hand == "MAIN_HAND" then
    if event.player.mainHandItem and event.player.mainHandItem.name == stick.name then
      local hit = event.player:raycastBlock(5)
      if not hit or hit.type == "MISS" then
        castLightningBolt(event.player)
      end
    end
  end
end

Move Minecarts Up a Ladder and Launch Them Horizontally

This spell detects minecarts (all types) and moves them upward while they are inside a ladder block. If they reach the top of the ladder, they are launched away from the ladder, in the direction opposite to the ladder's facing. This can be used to build vertical minecart elevators with automatic directional exits at the top.

local name = "vertical-minecart-spell"

-- Prevent duplicates by stopping existing spell with same name
spell:executeSilent("wol spell break byName " .. name)
spell.name = name

print("Starting Vertical Minecart Spell")

local verticalSpeed = 0.1
local exitSpeed = 0.2

local exitDirection = {
  north = Vec3(0, 0, 1),
  south = Vec3(0, 0, -1),
  west = Vec3(1, 0, 0),
  east = Vec3(-1, 0, 0)
}

local function addAll(t1, t2)
  for k, v in ipairs(t2) do
    table.insert(t1, v)
  end
end

while true do
  -- Collect all types of minecarts
  local types = { "minecart", "chest_minecart", "furnace_minecart", "hopper_minecart", "tnt_minecart" }
  local minecarts = {}
  for _, t in ipairs(types) do
    addAll(minecarts, spell:findEntities("@e[type=" .. t .. "]"))
  end

  for _, minecart in ipairs(minecarts) do
    local currentPos = minecart.pos
    spell.pos = currentPos

    if spell.block.type.id == "ladder" then
      -- Move minecart upward on ladder
      local velocity = currentPos:floor() + Vec3(0.5, 0, 0.5) - currentPos
      velocity.y = verticalSpeed
      minecart.velocity = velocity
    else
      -- If not on a ladder, check if the block below is a ladder for exit launch
      spell.pos = currentPos + Vec3(0, -0.5, 0)
      if spell.block.type.id == "ladder" then
        minecart.velocity = exitDirection[spell.block.data.facing] * exitSpeed
      end
    end
  end
  sleep(1)
end

Safe Zone: Disable PvP in Area

Creates a circular safe zone (radius = 10 meters) around the spell’s position where players cannot damage each other:

local name = "safezone-spell"

-- Prevent duplicates by stopping existing spell with same name
spell:executeSilent("wol spell break byName " .. name)
spell.name = name

print("Starting Safezone Spell")
local radius = 10
spell:intercept({ "PlayerAttackEntityEvent" }, function(event)
  ---@cast event PlayerAttackEntityEvent
  local attacker = event.player
  local target = event.entity

  if instanceOf(Player, target) then
    local distance = (attacker.pos - spell.pos):magnitude()
    if distance <= radius then
      spell.pos = attacker.pos
      spell:execute("/title " .. attacker.name .. " actionbar \"§cPvP is disabled here!\"")
      return false -- block the attack
    end
  end
  return true
end)

while true do
  sleep(20)
end

What's next?

  • Explore the Journey mini-game (a complete example).
  • Read the Commands documentation.