<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
name="TicTacToe"
author="Soludra"
id="03829336f30e9f2dcace86e9"
language="Lua"
purpose="Play a game of Tic Tac Toe!"
date_written="2009-11-22 07:46:00"
requires="4.45"
version="1.2"
/>
<!– Triggers –>
<triggers>
</triggers>
<!– Aliases –>
<aliases>
<alias
match="^ttt=(.*)$"
enabled="y"
regexp="y"
send_to="12"
ignore_case="y"
sequence="100"
>
<send>print(%1)</send>
</alias>
</aliases>
<!– Script –>
<script>
<![CDATA[
require('tprint')
local MWidget = require("MWidget")
local CharacterGrid = MWidget.Load("CharacterGrid")
– Defines the default grid font.
local TICTACTOE_FONT = "Lucida Console"
local players = {
[1] = {
piece = 'X',
color = 0x00FF00,
lastmove = nil,
},
[2] = {
piece = 'O',
color = 0x0000FF,
lastmove = nil,
},
}
local current_player = 1
local cells_played = {}
local CheckRow = function(cell1, cell2, cell3)
if cell1.char ~= ' ' and
cell1.char == cell2.char and
cell2.char == cell3.char then
cell1.forecolor, cell2.forecolor, cell3.forecolor = 0xFF0000, 0xFF0000, 0xFF0000
return true
else
return false
end
end
local CheckWin = function()
local done = CheckRow(grid:Cell(1, 1), grid:Cell(1, 2), grid:Cell(1, 3)) or
CheckRow(grid:Cell(2, 1), grid:Cell(2, 2), grid:Cell(2, 3)) or
CheckRow(grid:Cell(3, 1), grid:Cell(3, 2), grid:Cell(3, 3)) or
CheckRow(grid:Cell(1, 1), grid:Cell(2, 1), grid:Cell(3, 1)) or
CheckRow(grid:Cell(1, 2), grid:Cell(2, 2), grid:Cell(3, 2)) or
CheckRow(grid:Cell(1, 3), grid:Cell(2, 3), grid:Cell(3, 3)) or
CheckRow(grid:Cell(1, 1), grid:Cell(2, 2), grid:Cell(3, 3)) or
CheckRow(grid:Cell(3, 1), grid:Cell(2, 2), grid:Cell(1, 3))
if done then
for y = 1,3 do
for x = 1,3 do
local hotspot = grid:Cell(x, y).hotspot
hotspot:SetHandler("mouseup", nil)
hotspot:SetHandler("mouseover", nil)
hotspot:SetHandler("cancelmouseover", nil)
end
end
end
return done
end
local CellClick = function(hotspot, event)
local grid = hotspot:GetOwner()
local cell = grid:HotspotToCell(hotspot)
if cells_played[cell] then
return
end
cells_played[cell] = true
local player = players[current_player]
if player.lastmove then
player.lastmove.backcolor = 0xFFFFFF
end
cell.char = player.piece
cell.backcolor = player.color
cell.forecolor = 0x000000
CheckWin()
player.lastmove = cell
current_player = (current_player%2) + 1
grid:Invalidate()
event.view:Refresh()
end
local CellFocus = function(hotspot, event)
local grid = hotspot:GetOwner()
local cell = grid:HotspotToCell(hotspot)
if cells_played[cell] then
return
end
cell.forecolor = players[current_player].color
cell.char = players[current_player].piece
grid:Invalidate()
event.view:Refresh()
end
local CellBlur = function(hotspot, event)
local grid = hotspot:GetOwner()
local cell = grid:HotspotToCell(hotspot)
if cells_played[cell] then
return
end
cell.forecolor = 0x000000
cell.char = ' '
grid:Invalidate()
event.view:Refresh()
end
local ResetTTT = function()
current_player = 1
grid:ResetGrid()
for y = 1, 3 do
for x = 1, 3 do
local cell = grid:Cell(x, y)
cell.forecolor = 0x000000
cell.hotspot:SetHandler("mouseover", CellFocus)
cell.hotspot:SetHandler("cancelmouseover", CellBlur)
cell.hotspot:SetHandler("mouseup", CellClick)
cell.hotspot:SetHandler("cancelmousedown", CellBlur)
end
end
v:Refresh()
end
OnPluginInstall = function()
grid = CharacterGrid.new(3, 3)
grid:Font(TICTACTOE_FONT, 15)
grid.canvas.backcolor = 0xFFFFFF
v = grid:GetView()
v:Anchor(12)
ResetTTT()
end
OnPluginClose = function()
v:Destroy()
grid:Destroy()
end
OnPluginEnable = OnPluginInstall
OnPluginDisable = OnPluginClose
]]>
</script>
</muclient>
I'm currently working on a proof-of-concept scrollbar widget, to exercise the hotspot abstraction layer. Mouse-drag events haven't quite been added yet because I'm still thinking about how I want the abstraction layer to behave, but it should otherwise be perfectly workable. A minor point to note, however, is that with raw MUSHclient miniwindows/hotspots, you always receive a cancelmouseover prior to a mousedown, and a mouseover after a mouseup (or cancelmousedown); under my framework, that doesn't happen, and it hides the intermediate events from you. If you mouse over a hotspot region under the framework and click on it, you will only receive mouseover, mousedown, mouseup (or cancelmousedown), in that order.
EDIT: I've updated the project's wiki page on GitHub to include installation directions. I'd be glad to upload my TicTacToe plugin as well if there's interest, though it's a bit messy.