Skip to content

Instantly share code, notes, and snippets.

@blam23
Created June 26, 2018 16:44
Show Gist options
  • Select an option

  • Save blam23/caaa30fd32e283e379c1517265c8881a to your computer and use it in GitHub Desktop.

Select an option

Save blam23/caaa30fd32e283e379c1517265c8881a to your computer and use it in GitHub Desktop.
--[[
Blam's Chess Script
]]--
-- Define these completely *globally* so that other scripts can see them.
local engine_manager = {
engines = {}
}
engine_manager.__index = engine_manager
do
--[[
SETUP + HELPER FUNCTIONS
]]
dofile("system/player_info.lua")
dofile("chess/animation.lua")
-- Some script-global debug stuff.
debug_mode = 1
function dbg(...)
if debug_mode == 0 then return end
local out = "^17" .. table.concat( arg, ", ")
echo(out)
end
-- 'Starts with' function, usage:
-- "hello" % "he" == true
getmetatable("").__mod = function(self, s)
if(self:sub(0,#s) == s) then return true end
return false
end
-- Generic helper functions holder
local helpers = {}
-- From system/player_info.lua
function helpers.getUserName(player)
player = player:gsub(".*%b{}", "")
player = player:gsub(".*%b[]", "")
player = player:gsub(".*%b()", "")
return player
end
-- From system/player_info.lua
function helpers.getMaster(option)
add_hook("console", "chess_playerInfoFetchConsoleIgnore", function(s,i)
return 1
end)
local return_val = nil
if (option) then
return_val = get_master().master[option]
else
return_val = get_master().master
end
remove_hooks("chess_playerInfoFetchConsoleIgnore")
return return_val
end
-- Splits up a whisper from another player into player and message.
-- Strips clans from username, does not strip colours.
function helpers.splitWhisper(msg)
local name_split = msg:find(":")
local name = msg:sub(0,name_split-1)
name = helpers.getUserName(name)
local message = msg:sub(name_split+2)
return name, message
end
--[[
END OF SETUP
]]
----------------------------------------------------------------------------------------------------
--[[
CHESS ENGINE
]]
-- Script globals for holding current stuff
local engine = nil
local const = nil
local version = nil
-- Current engine, use of multiple engines designed for
-- possible backwards compatilibity or different games.
local current_engine = {
version = "001",
const = {
-- GAME COMMANDS
NEW_GAME = "::chess_new:",
ACCEPT_GAME = "accepted",
ERROR = "!!error",
WHISPER_CMD = "::chess_cmd:",
-- ERRORS
ERR_VER_MISMATCH = "ver_mismatch",
-- NUMBERS
ID_LENGTH = 5,
NEW_GAME_ID_LENGTH = 5,
}
}
current_engine.__index = current_engine
current_engine.newGame = function()
echo("CHESSENGINE:NEWGAME")
end
current_engine.processCommand = function(command)
echo("Engine command: '" .. command .. "'")
end
engine_manager.findEngine = function(version)
for i=1,#engine_manager.engines do
if engine_manager.engines[i].version == version then
return engine_manager.engines[i]
end
end
return nil
end
engine_manager.setEngine = function(e)
engine = e
const = e.const
version = e.version
end
engine_manager.register = function(e)
table.insert(engine_manager.engines, e)
end
engine_manager.setEngineVersion = function(version)
local eng = engine_manager.findEngine(version)
if (eng == nil) then
return false
end
engine_manager.setEngine(eng)
return true
end
engine_manager.register(current_engine)
engine_manager.setEngine(current_engine)
--[[
END OF CHESS ENGINE
]]
----------------------------------------------------------------------------------------------------
--[[
SESSION HANDLER
]]
local session = {
current = {}
}
session.__index = session
function session.create()
dbg ("session.create")
local s = { }
setmetatable(s, session)
s:reset()
table.insert(session.current, s)
dbg ("returning from session.create")
return s
end
function session:reset()
dbg ("session:reset")
self.opponent = nil
self.started = false
self.client = false
self.triggers = {}
self.waiting = false
self.current_player = helpers.getMaster("nick")
self.cur_id = 0
self.processed = {}
end
function session:sendRaw(message)
dbg ("session:sendRaw " .. message)
if self.opponent == nil then
return
end
run_cmd("whisper " .. self.opponent .. " " .. message .. "\n")
end
function session:nextID()
dbg ("session:nextID")
local full_id = tostring(self.cur_id)
full_id = string.rep("0", engine.const.ID_LENGTH-#full_id) .. full_id
self.cur_id = self.cur_id + 1
return full_id
end
function session:send(message)
dbg ("session:send")
id = self:nextID()
self:sendRaw(const.WHISPER_CMD .. id .. message)
end
function session:sendError(message)
dbg ("session:sendError")
self:send(const.ERROR .. message)
end
function session:checkDuplicate(id, message)
dbg ("session:checkDuplicate")
if self.processed[id] == nil then
self.processed[id] = #message
return false
end
return self.processed[id] == #message
end
function session:process(message)
dbg ("session:process " .. message)
local id = message:sub(0,engine.const.ID_LENGTH)
local message = message:sub(engine.const.ID_LENGTH+1)
-- Whisper messaging is not quite right..
if self:checkDuplicate(id, message) then
return
end
local processed = false
if (self.waiting) then
for k,v in pairs(self.triggers) do
if message % k then
for i = 1,#v do
v[i](self, message)
processed = true
end
self.triggers.remove(k)
end
end
if #self.triggers == 0 then
self.waiting = false
end
end
if proccessed then return end
engine:processCommand(message)
end
function session:waitFor(message, func)
dbg ("session:waitFor")
if self.triggers[message] ~= nil then
self.triggers[message].insert(func)
end
self.triggers[message] = {func}
self.waiting = true
end
function session:waitError(message, func)
dbg ("session:waitError")
if message == nil then
self:waitFor(const.ERROR, func)
else
self:waitFor(const.ERROR .. message, func)
end
end
-- Game request has been accepted.
function session:gameAccepted(m)
dbg ("session:gameAccepted")
-- empty wait queue
self.triggers = {}
self.started = true
engine:newGame()
end
function session:gameNotAccepted(m)
dbg ("session:gameNotAccepted")
-- empty wait queue
self.triggers = {}
echo("^02" .. self.opponent .. " has declined your request or was unable to participate.")
end
-- Attempts to set up a new game as a client (recieved a request)
function session.newClientGame(name, version)
dbg ("session.newClientGame")
local s = session.create()
s.opponent = name
if engine_manager.setEngineVersion(version) then
s.started = true
s.client = true
engine:newGame()
s:send(const.ACCEPT_GAME)
return s
end
s.error = const.ERR_VER_MISMATCH
echo("^02Unable to start session with " .. name .. " as scripts are incompatible. ^02Please update scripts")
s:sendError(s.error)
return s
end
-- Attempts to set up a new game as a host (send the request)
function session.newHostGame(name)
dbg ("session.newHostGame")
local s = session.create()
s.opponent = name
local length_mul = math.pow(10, engine.const.NEW_GAME_ID_LENGTH - 1)
local session_id = tostring(math.floor((math.random() * length_mul) % length_mul))
session_id = string.rep("0", engine.const.NEW_GAME_ID_LENGTH-#session_id) .. session_id
s:sendRaw(const.NEW_GAME .. session_id .. engine.version)
s:waitFor(const.ACCEPT_GAME, session.gameAccepted)
s:waitError(nil, session.gameNotAccepted)
return s
end
--[[
END OF SESSION HANDLER
]]
----------------------------------------------------------------------------------------------------
--[[
HOOKS
]]
local hooks = {}
hooks.__index = hooks
-- Hook for multiplayer messaging
hooks.whisper = function(s, i)
-- No message - just in case to prevent errors.
if #s == 0 then
return 0
end
-- 4 and starts with whisper -> remove: This is an echo of a sent message.
if i == 4 and (s % "whisper ") then
dbg (">> ^06" .. s)
return 1
end
if i == 8 then
if s[0] ~= '<' then
local name, message = helpers.splitWhisper(s)
name = helpers.getUserName(name)
--echo ("Name: '" .. name .. "' ~ Current '" .. cur_session.current_player .. "'")
if name == cur_session.current_player then
return 1
end
dbg ("<< ^11" .. name .. ": " .. message)
if name == cur_session.opponent and message % const.WHISPER_CMD then
cur_session:process(message:sub(#const.WHISPER_CMD+1))
return 1
end
if ((cur_session == nil or not cur_session.started) and message % const.NEW_GAME) then
-- new session
local version = message:sub(#const.NEW_GAME + const.NEW_GAME_ID_LENGTH + 1)
-- check for duplicate messages.
local id = message:sub(0, const.NEW_GAME_ID_LENGTH)
if (id == session.last_game_id) then
return 1
end
session.last_game_id = id
-- TODO: Add prompt to confirm a new game.
session.newClientGame(name, version)
return 1
end
end
end
return 0
end
-- Hook for commands
hooks.commands = function(cmd)
if cmd == "r" then
run_cmd("clear")
run_cmd("chl 10000000")
echo("Reloading..")
run_cmd("ls chess.lua")
elseif cmd == "dbg" then
debug_mode = 1
elseif cmd == "chess" then
cur_session = session.newHostGame("Oku")
elseif cmd == "boom" then
cur_session:send("boom")
end
end
hooks.initialise = function()
add_hook("console", "chess_mp_whisper_hook", hooks.whisper)
add_hook("command", "chess_commands", hooks.commands)
end
--[[
END OF HOOKS
]]
----------------------------------------------------------------------------------------------------
hooks.initialise()
----------------------------------------------------------------------------------------------------
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment