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:
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