This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 8064ba84d8
commit 73479cff9e
7338 changed files with 1718883 additions and 14 deletions

View File

@@ -0,0 +1,214 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SERVER then
AddCSLuaFile()
AddCSLuaFile( "chess/sh_player_ext.lua" )
AddCSLuaFile( "chess/cl_top.lua" )
AddCSLuaFile( "chess/cl_dermaboard.lua" )
include( "chess/sh_player_ext.lua" )
include( "chess/sv_sql.lua" )
else
include( "chess/sh_player_ext.lua" )
include( "chess/cl_top.lua" )
include( "chess/cl_dermaboard.lua" )
end
if SERVER then
function ChessBoard_DoOverrides()
if GAMEMODE.Name=="Cinema" then --Cinema overrides
hook.Add("CanPlayerEnterVehicle", "EnterSeat", function(ply, vehicle) --Overrides default func
if vehicle:GetClass() != "prop_vehicle_prisoner_pod" then return end
if vehicle.Removing then return false end
return (vehicle:GetOwner() == ply) or vehicle:GetNWBool( "IsChessSeat", false )
end)
end
end
hook.Add( "Initialize", "ChessBoardOverrides", ChessBoard_DoOverrides )
CreateConVar( "chess_wagers", 1, FCVAR_ARCHIVE, "Set whether players can wager on their chess games." )
CreateConVar( "chess_darkrp_wager", 1, FCVAR_ARCHIVE, "[DarkRP only] Wagers should use DarkRP wallet." )
CreateConVar( "chess_debug", 0, FCVAR_ARCHIVE, "Debug mode." )
CreateConVar( "chess_limitmoves", 1, FCVAR_ARCHIVE, "Enable 50 move rule." )
else -- CLIENT
CreateConVar( "chess_gridletters", 1, FCVAR_ARCHIVE, "Show grid letters." )
end
-- DarkRP --
------------
hook.Add("canArrest", "Chess PreventArrest", function( cop, target )
if not (IsValid(target) and target:GetNWBool("IsInChess", false)) then return end
local board = target:GetNWEntity( "ActiveChessBoard", nil )
if not (IsValid(board) and board:GetPlaying()) then return end
if target~=board:GetWhitePlayer() and target~=board:GetBlackPlayer() then return end
return false,"Cannot arrest players during a game in progress" -- Prevent arrest during Chess
end)
-- Admin Commands --
--------------------
local function SetupCommands()
if serverguard then
/////////////////
// Serverguard //
/////////////////
serverguard.permission:Add("Set Chess Elo")
if SERVER then
// Update function
local function SGUpdate(player, target, newElo, isDraughts)
if type(target)=="Player" and IsValid(target) then
if isDraughts then
target:SetDraughtsElo( newElo )
else
target:SetChessElo( newElo )
end
Chess_UpdateElo( target )
serverguard.Notify(nil,
SERVERGUARD.NOTIFY.GREEN, serverguard.player:GetName(player),
SERVERGUARD.NOTIFY.WHITE, isDraughts and " has set the Checkers Elo rating of " or " has set the Chess Elo rating of ",
SERVERGUARD.NOTIFY.RED, serverguard.player:GetName(target),
SERVERGUARD.NOTIFY.WHITE, " to ",
SERVERGUARD.NOTIFY.RED, tostring(newElo),
SERVERGUARD.NOTIFY.WHITE, "."
)
elseif (string.SteamID(target)) then
local success,reason = Chess_SetElo( target, newElo, isDraughts )
local queryObj = serverguard.mysql:Select("serverguard_users");
queryObj:Where("steam_id", target)
queryObj:Limit(1)
queryObj:Callback(function(result, status, lastID)
local name = target
if (type(result) == "table" and #result > 0) then
name = result[1].name or name
end
if success then
serverguard.Notify(nil,
SERVERGUARD.NOTIFY.GREEN, serverguard.player:GetName(player),
SERVERGUARD.NOTIFY.WHITE, isDraughts and " has set the Checkers Elo rating of " or " has set the Chess Elo rating of ",
SERVERGUARD.NOTIFY.RED, name,
SERVERGUARD.NOTIFY.WHITE, " to ",
SERVERGUARD.NOTIFY.RED, tostring(newElo),
SERVERGUARD.NOTIFY.WHITE, "."
)
else
serverguard.Notify(player, SERVERGUARD.NOTIFY.RED, ("Could not set elo. (%s)"):format(tostring(reason)) )
end
end)
queryObj:Execute()
else
serverguard.Notify(player, SGPF("cant_find_player_with_identifier"))
end
end
// Chess command
local command = {}
command.help = "Set a player's Chess Elo rating."
command.command = "setelo"
command.arguments = {"player", "elo"}
command.permissions = {"Set Chess Elo"}
command.aliases = {"setelochess", "chesselo", "setchess", "setchesselo"}
function command:Execute(player, silent, arguments)
local target = util.FindPlayer(arguments[1], player, true)
local newElo = tonumber(arguments[2]) or 1400
SGUpdate( player, IsValid(target) and target or arguments[1], newElo, false )
end
serverguard.command:Add(command)
// Draughts command
local command = {}
command.help = "Set a player's Checkers Elo rating."
command.command = "setelocheckers"
command.arguments = {"player", "elo"}
command.permissions = {"Set Chess Elo"}
command.aliases = {"setcheckers", "setcheckerselo", "checkerselo", "setelodraughts", "setdraughts", "setdraughtselo", "draughtselo"}
function command:Execute(player, silent, arguments)
local target = util.FindPlayer(arguments[1], player, true)
local newElo = tonumber(arguments[2]) or 1400
SGUpdate( player, IsValid(target) and target or arguments[1], newElo, true )
end
serverguard.command:Add(command)
end
end
if ulx then
/////////
// ULX //
/////////
// Update
local function ULXUpdate(calling_ply, target, newElo, isDraughts)
if CLIENT then return end
if type(target)=="Player" and IsValid(target) then
if isDraughts then
target:SetDraughtsElo( newElo )
else
target:SetChessElo( newElo )
end
Chess_UpdateElo( target )
ulx.fancyLogAdmin( calling_ply, "#A set the #s Elo rating of #T to #i.", isDraughts and "Checkers" or "Chess", target, newElo )
elseif (string.SteamID(target or "")) then
local success,reason = Chess_SetElo( target, newElo, isDraughts )
if success then
ulx.fancyLogAdmin( calling_ply, "#A set the #s Elo rating of #s to #i.", isDraughts and "Checkers" or "Chess", target, newElo )
else
ULib.tsayError( calling_ply, ("Could not set elo. (%s)"):format(tostring(reason)) )
end
else
ULib.tsayError( calling_ply, "Invalid SteamID or Player." )
end
end
// Autocomplete
local function AutoComplete(...) return ULib.cmds.PlayerArg.complete(ULib.cmds.PlayerArg, ...) end
// Chess command
local function SetChessElo( calling_ply, steamid, newElo )
local target = ULib.getUser( steamid or "", true, calling_ply )
ULXUpdate( calling_ply, IsValid(target) and target or steamid, newElo, false )
end
local setchess = ulx.command( "Chess", "ulx chesselo", SetChessElo, {"!setelo", "!setelochess", "!chesselo", "!setchess", "!setchesselo"}, false, false, true )
setchess:addParam{ type=ULib.cmds.StringArg, hint="Player or SteamID", autocomplete_fn=AutoComplete }
setchess:addParam{ type=ULib.cmds.NumArg, hint="New Elo", min=0, default=1400 }
setchess:defaultAccess( ULib.ACCESS_SUPERADMIN )
setchess:help( "Set Chess Elo rating for user." )
// Draughts command
local function SetDraughtsElo( calling_ply, steamid, newElo )
local target = ULib.getUser( steamid, true, calling_ply )
ULXUpdate( calling_ply, IsValid(target) and target or steamID, newElo, true )
end
local setdraughts = ulx.command( "Chess", "ulx checkerselo", SetDraughtsElo, {"!setelocheckers", "!setcheckers", "!setcheckerselo", "!checkerselo", "!setelodraughts", "!setdraughts", "!setdraughtselo", "!draughtselo"}, false, false, true )
setdraughts:addParam{ type=ULib.cmds.StringArg, hint="Player or SteamID", autocomplete_fn=AutoComplete }
setdraughts:addParam{ type=ULib.cmds.NumArg, hint="New Elo", min=0, default=1400 }
setdraughts:defaultAccess( ULib.ACCESS_SUPERADMIN )
setdraughts:help( "Set Checkers Elo rating for user." )
end
end
hook.Add( "Initialize", "ChessBoardPermissions", SetupCommands )

View File

@@ -0,0 +1,174 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PanelCol = {
Main = Color(0,0,0,200), Hover = Color(0,255,0,50), Selected = Color(150,50,50,170),
Move = Color(10,25,150,150), HasMoved = Color(50,50,50,100), Text = Color(0,0,0,255),
GridWhite = Color(255, 248, 220), GridBlack = Color(210, 180, 140),
White = Color(180,180,180), Black = Color(0,0,0),
}
-- local ColText = Color(50,50,50,200)
-- local ColBlack,ColWhite = Color(0,0,0,120),Color(255,255,255,10)
local NumToLetter = {"a", "b", "c", "d", "e", "f", "g", "h", ["a"]=1, ["b"]=2, ["c"]=3, ["d"]=4, ["e"]=5, ["f"]=6, ["g"]=7, ["h"]=8} --Used extensively for conversions
surface.CreateFont( "ChessPieces", { font = "Arial", size = 64, weight = 300})
function Chess_Open2DBoard( board )
if not IsValid(board) then return end
if IsValid( Chess_2DDermaPanel ) then Chess_2DDermaPanel:Remove() end
Chess_2DDermaPanel = vgui.Create( "DFrame" )
local frame = Chess_2DDermaPanel
frame:SetTitle( "2D Game Board" )
frame:SetSize( 740, 760 )
frame:SetPos( (ScrW()/2)-370, (ScrH()/2)-380 )
frame.Paint = function( s,w,h )
if not IsValid(board) then
s:Remove()
end
draw.RoundedBox( 8, 0, 0, w, h, PanelCol.Main )
end
frame:MakePopup()
local pnlBoard = vgui.Create( "DPanel", frame )
pnlBoard:SetSize( 720, 720 )
pnlBoard:SetPos(10,30)
pnlBoard.Squares = {}
pnlBoard.Paint = function() end
local function DoTiles(swapped)
if pnlBoard.Squares then
for _,v in pairs(pnlBoard.Squares) do
for _,pnl in pairs(v) do
pnl:Remove()
end
end
end
for i=0,7 do
pnlBoard.Squares[i] = {}
for n=0,7 do
local pnl = vgui.Create( "DModelPanel", pnlBoard )
pnlBoard.Squares[i][n] = pnl
pnl:SetPos( (swapped and 7-i or i)*90, (swapped and 7-n or n)*90 )
pnl:SetSize(90,90)
pnl.GridCol = (((i+n)%2)==1) and PanelCol.GridBlack or PanelCol.GridWhite
pnl.GridPos = {i,n}
pnl.oPaint = pnl.Paint
pnl.Paint = function(s,w,h)
surface.SetDrawColor( s.GridCol )
surface.DrawRect( 0,0, w,h )
if not IsValid(board) then return end
if s:IsHovered() then
surface.SetDrawColor( PanelCol.Hover )
surface.DrawRect( 0,0, w,h )
end
if board.Selected and board.Selected[1]==s.GridPos[1] and board.Selected[2]==s.GridPos[2] then
surface.SetDrawColor( PanelCol.Selected )
surface.DrawRect( 0,0, w,h )
end
if board:GetTableGrid( board.Moves, s.GridPos[1], s.GridPos[2]) then
surface.SetDrawColor( PanelCol.Move )
surface.DrawRect( 0,0, w,h )
end
local col,square = board.Pieces[ NumToLetter[s.GridPos[1]+1] ]
if col then
square = col[8-s.GridPos[2]]
if square then
if not (square.Team and square.Class) then return end
if square.Moving then
surface.SetDrawColor( PanelCol.HasMoved )
surface.DrawRect( 0,0, w,h )
end
if board.Characters then
draw.SimpleText( board.Characters[square.Team .. square.Class], "ChessPieces", w/2, h/2, PanelCol.Text, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
else
s:SetModel( board.Models[square.Team .. square.Class] )
return s.oPaint( s,w,h )
end
end
end
if cvars.Bool("chess_gridletters") then
local str = (NumToLetter[i+1]..tostring(8-n)):upper()
draw.SimpleText( str, "ChessTextSmall", 5, h-20, PanelCol.Black )
end
end
pnl.DoClick = function(s)
if not IsValid(board) then return end
if board.Selected and board:GetTableGrid( board.Moves, pnl.GridPos[1], pnl.GridPos[2] ) then
board:RequestMove( board.Selected[1], board.Selected[2], pnl.GridPos[1], pnl.GridPos[2] )
board:ResetHighlights()
elseif board.Selected and board.Selected[1]==s.GridPos[1] and board.Selected[2]==s.GridPos[2] then
board:ResetHighlights()
else
board:ResetHighlights()
board.Selected = {s.GridPos[1],s.GridPos[2]}
board.Moves = board:GetMove( NumToLetter[s.GridPos[1]+1], 8-s.GridPos[2] )
end
end
pnl.LayoutEntity = function( s, ent )
ent:SetPos( Vector(20,20,20) )
ent:SetAngles( Angle(0,-50,0) )
end
pnl:SetModel( board.Models["WhitePawn"] )
end
end
end
local swap = vgui.Create( "DButton", frame )
swap:SetImage( "icon16/arrow_rotate_clockwise.png" )
swap:SetSize( 18,18 )
swap:SetPos( 620,6 )
swap:SetText( "" )
swap.DoClick = function(s)
s.Swapped = not s.Swapped
DoTiles( s.Swapped )
end
swap.Paint = function() end
local toggleGridLetters = vgui.Create( "DCheckBox", frame )
toggleGridLetters:SetImage( "icon16/font.png" )
toggleGridLetters:SetSize( 18,18 )
toggleGridLetters:SetPos( 600,6 )
toggleGridLetters:SetText( "" )
toggleGridLetters:SetConVar( "chess_gridletters" )
toggleGridLetters.OnChange = function(s,newvalue)
s:SetAlpha( s:GetChecked() and 255 or 100 )
end
toggleGridLetters.Paint = function() end
toggleGridLetters.PerformLayout = function(s) -- DCheckBox overwrites DButton's PerformLayout, re-apply it
if IsValid(s.m_Image) then
s.m_Image:SetPos( 4, ( s:GetTall() - s.m_Image:GetTall() ) * 0.5 )
s:SetTextInset( s.m_Image:GetWide() + 16, 0 )
end
DLabel.PerformLayout( s )
end
swap.Swapped = false
DoTiles( swap.Swapped )
end

View File

@@ -0,0 +1,149 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local Top10
local function ChessTop10( typ )
if IsValid(Top10) then Top10:Remove() end
typ = typ or "Chess"
Top10 = vgui.Create( "DFrame" )
Top10:SetSize( 450, 245 )
Top10:SetPos( (ScrW()/2)-150, (ScrH()/2)-100 )
Top10:SetTitle( "Top 10 Chess Elo ratings" )
Top10:MakePopup()
Top10.Column = "Elo"
local pnl = vgui.Create("DPanel", Top10)
pnl.Paint = function() end
pnl:SetTall(20)
pnl:Dock(BOTTOM)
Top10.Rank = vgui.Create( "DLabel", pnl )
Top10.Rank:Dock( LEFT )
Top10.Rank:SetTall( 20 )
Top10.Rank:SetWide( 150 )
Top10.Rank:SetText("")
Top10.Updated = vgui.Create( "DLabel", pnl )
Top10.Updated:Dock( RIGHT )
Top10.Updated:SetTall( 150 )
Top10.Updated:SetText("")
Top10.List = vgui.Create( "DListView", Top10 )
local List = Top10.List
List:Dock( FILL )
List:AddColumn( "Rank" )
List:AddColumn( "Name" )
List:AddColumn( "SteamID" )
List:AddColumn( "Elo" )
List:AddLine( "", "Loading..." )
-- PrintTable( List.Columns )
List:OnRequestResize( List.Columns[1], 10 )
List:OnRequestResize( List.Columns[2], 150 )
List:OnRequestResize( List.Columns[3], 100 )
List:OnRequestResize( List.Columns[4], 10 )
net.Start( "Chess Top10" ) net.WriteString( typ ) net.SendToServer()
end
local function DraughtsTop10()
ChessTop10( "Draughts" )
end
concommand.Add( "chess_top", function( p,c,a ) ChessTop10() end)
concommand.Add( "checkers_top", function( p,c,a ) DraughtsTop10() end)
local ChatCommands = {
["!chess"]=ChessTop10, ["!chesstop"]=ChessTop10, ["!topchess"]=ChessTop10,
["/chess"]=ChessTop10, ["/chesstop"]=ChessTop10, ["/topchess"]=ChessTop10,
["!draughts"]=DraughtsTop10, ["!draughtstop"]=DraughtsTop10, ["!topdraughts"]=DraughtsTop10,
["/draughts"]=DraughtsTop10, ["/draughtstop"]=DraughtsTop10, ["/topdraughts"]=DraughtsTop10,
["!checkers"]=DraughtsTop10, ["!checkerstop"]=DraughtsTop10, ["!topcheckers"]=DraughtsTop10,
["/checkers"]=DraughtsTop10, ["/checkerstop"]=DraughtsTop10, ["/topcheckers"]=DraughtsTop10,
}
hook.Add( "OnPlayerChat", "Chess Top10 PlayerChat", function( ply, str, tm, dead )
if ChatCommands[str:lower()] then
if ply==LocalPlayer() then
ChatCommands[str:lower()]()
end
return true
end
end)
local function SecondsToTime(num)
if updateTime>=86400 then
return ("%i day%s"):format( math.floor(updateTime/86400), updateTime>=172800 and "s" or "")
elseif updateTime>=3600 then
return ("%i hour%s"):format( math.floor(updateTime/3600), updateTime>=7200 and "s" or "")
elseif updateTime>=60 then
return ("%i minute%s"):format( math.floor(updateTime/60), updateTime>=120 and "s" or "")
else
return ("%i second%s"):format(updateTime, updateTime>=2 and "s" or "")
end
end
local lastTable = {}
local lastRank = {}
local lastUpdate = {}
net.Receive( "Chess Top10", function()
if not (IsValid(Top10) and IsValid(Top10.List)) then return end
Top10.List:Clear()
local typ = net.ReadString() or "[Error]"
Top10:SetTitle( "Top 10 "..typ.." Elo ratings" )
local tbl = net.ReadTable()
if (not tbl) or (#tbl==0) then -- Rate limit exceeded
if lastTable[typ] then
for i=1,#lastTable[typ] do
Top10.List:AddLine( tonumber(lastTable[typ][i].Rank), lastTable[typ][i].Username, lastTable[typ][i].SteamID, tonumber(lastTable[typ][i]["Elo" ]) )
end
Top10.Rank:SetText( "You are rank "..lastRank[typ] )
if lastUpdate[typ] then
updateTime = math.floor(CurTime() - lastUpdate[typ])
if updateTime>0 then
Top10.Updated:SetText( ("Updated %s ago."):format(SecondsToTime(updateTime)) )
end
Top10.Updated:SizeToContents()
end
else
Top10.List:AddLine( "", "ERROR: Rate limit exceeded." )
Top10.List:AddLine( "", "Please try again in a few minutes." )
end
return
end
for i=1,#tbl do
Top10.List:AddLine( tonumber(tbl[i].Rank), tbl[i].Username, tbl[i].SteamID, tonumber(tbl[i]["Elo" ]) )
end
local rank = (net.ReadString() or "N/A")
Top10.Rank:SetText( "You are rank "..rank )
lastUpdate[typ] = tonumber(net.ReadString())
if lastUpdate[typ] then
updateTime = math.floor(CurTime() - lastUpdate[typ])
if updateTime>0 then
Top10.Updated:SetText( ("Updated %s ago."):format(SecondsToTime(updateTime)) )
end
Top10.Updated:SizeToContents()
end
lastTable[typ] = tbl
lastRank[typ] = rank
end)

View File

@@ -0,0 +1,123 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PLAYER = FindMetaTable( "Player" )
if not PLAYER then return end
function PLAYER:GetChessElo()
return self:GetNWInt( "ChessElo", 1400 ) or 1400
end
function PLAYER:GetDraughtsElo()
return self:GetNWInt( "DraughtsElo", 1400 ) or 1400
end
if CLIENT then return end
function PLAYER:SetChessElo( num )
self:SetNWInt( "ChessElo", num or Chess_GetElo(ply:SteamID()) or 1400 )
Chess_SetElo( self:SteamID(), num, false )
end
function PLAYER:SetDraughtsElo( num )
self:SetNWInt( "DraughtsElo", num or Chess_GetElo(ply:SteamID(), true) or 1400 )
Chess_SetElo( self:SteamID(), num, true )
end
function PLAYER:RefreshChessElo()
-- Convert old PData stuff
if self:GetPData("ChessElo") then
Chess_SetElo( self:SteamID(), self:GetPData("ChessElo"), false )
self:RemovePData("ChessElo")
end
if self:GetPData("DraughtsElo") then
Chess_SetElo( self:SteamID(), self:GetPData("DraughtsElo"), true )
self:RemovePData("DraughtsElo")
end
self:SetChessElo( Chess_GetElo(self:SteamID()) or 1400)
self:SetDraughtsElo( Chess_GetElo(self:SteamID(), true) or 1400)
end
hook.Add( "PlayerInitialSpawn", "Chess InitialSpawn InitElo", function(ply)
ply:RefreshChessElo()
end)
function PLAYER:ExpectedChessWin( against )
return (1/ (1+( 10^( (against:GetChessElo() - self:GetChessElo())/400 ) )) )
end
function PLAYER:ExpectedDraughtsWin( against )
return (1/ (1+( 10^( (against:GetDraughtsElo() - self:GetDraughtsElo())/400 ) )) )
end
function PLAYER:GetChessKFactor() --Imitating FIDE's K-factor ranges
local games = tonumber(self:GetPData( "ChessGamesPlayed", 0 )) or 0
if games<30 then
self:SetPData( "ChessEloKFactor", 15 )
return 30
end
local k = self:GetChessElo()>=2400 and 10 or self:GetPData( "ChessEloKFactor", 15 ) or 15
self:SetPData( "ChessEloKFactor", k )
return k
end
function PLAYER:GetDraughtsKFactor() --Imitating FIDE's K-factor ranges
local games = self:GetPData( "DraughtsGamesPlayed", 0 )
if games<30 then
self:SetPData( "DraughtsEloKFactor", 15 )
return 30
end
local k = self:GetDraughtsElo()>=2400 and 10 or self:GetPData( "DraughtsEloKFactor", 15 ) or 15
self:SetPData( "DraughtsEloKFactor", k )
return k
end
function PLAYER:DoChessElo( score, against )
local mod = math.ceil(self:GetChessKFactor() * (score - self:ExpectedChessWin(against)))
local NewElo = math.floor( self:GetChessElo() + mod )
self:SetChessElo( NewElo )
if IsValid(against) then
mod = mod*(-1)
local NewElo = math.floor( against:GetChessElo() + mod )
against:SetChessElo( NewElo )
local rank,count = Chess_GetRank(against)
against:ChatPrint( "Your chess Elo rating changed by "..tostring(mod).." to "..tostring(NewElo).."!" ..(rank and " You are #"..tostring(rank).." on this server." or "") )
end
local rank,count = Chess_GetRank(self)
self:ChatPrint( "Your chess Elo rating changed by "..tostring(mod).." to "..tostring(NewElo).."!" ..(rank and " You are #"..tostring(rank).." on this server." or "") )
Chess_UpdateElo( self )
end
function PLAYER:ChessWin( against )
if not IsValid(against) then return end
self:DoChessElo(1, against)
end
function PLAYER:ChessDraw( against ) self:DoChessElo(0.5, against) end
function PLAYER:DoDraughtsElo( score, against )
local mod = math.ceil(self:GetDraughtsKFactor() * (score - self:ExpectedDraughtsWin(against)))
local NewElo = math.floor( self:GetDraughtsElo() + mod )
self:SetDraughtsElo( NewElo )
if IsValid(against) then
mod = mod*(-1)
local NewElo = math.floor( against:GetDraughtsElo() + mod )
against:SetDraughtsElo( NewElo )
local rank = Chess_GetRank(self, "Draughts")
against:ChatPrint( "Your draughts Elo rating changed by "..tostring(mod).." to "..tostring(NewElo).."!" ..(rank and " You are #"..tostring(rank).." on this server." or "") )
end
local rank = Chess_GetRank(self, "Draughts")
self:ChatPrint( "Your draughts Elo rating changed by "..tostring(mod).." to "..tostring(NewElo).."!" ..(rank and " You are #"..tostring(rank).." on this server." or "") )
Chess_UpdateElo( self )
end
function PLAYER:DraughtsWin( against ) self:DoDraughtsElo(1, against) end
function PLAYER:DraughtsDraw( against ) self:DoDraughtsElo(0.5, against) end

View File

@@ -0,0 +1,212 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local nextTopUpdate = {}
local playerResults = {}
local function InitChessLeaderboard()
sql.Begin()
local query = sql.Query( [[CREATE TABLE ChessLeaderboard (SteamID varchar(255), Username varchar(255), Elo int, DraughtsElo int);]] )
sql.Commit()
if query==false then else print("Chess: Created Elo table") end
end
InitChessLeaderboard()
function Chess_UpdateElo( ply )
if not IsValid(ply) then return end
local SelStr = [[SELECT * FROM ChessLeaderboard WHERE SteamID==]].. sql.SQLStr(ply:SteamID()) ..[[;]]
sql.Begin()
local Select = sql.Query( SelStr )
sql.Commit()
local UpdateStr
if Select==false then
Error( "Chess: Save failed for player "..ply:Nick().." - Query error. "..sql.LastError().."\n" )
elseif Select==nil then
UpdateStr = [[INSERT INTO ChessLeaderboard (SteamID, Username, Elo, DraughtsElo) VALUES (]]..sql.SQLStr(ply:SteamID())..[[,]]..sql.SQLStr(ply:Nick())..[[,]]..sql.SQLStr(ply:GetChessElo())..[[,]]..sql.SQLStr(ply:GetDraughtsElo())..[[);]]
else
UpdateStr = [[UPDATE ChessLeaderboard SET Username=]]..sql.SQLStr(ply:GetName())..[[,Elo=]]..sql.SQLStr(ply:GetChessElo())..[[,DraughtsElo=]]..sql.SQLStr(ply:GetDraughtsElo())..[[ WHERE SteamID==]]..sql.SQLStr(ply:SteamID())..[[;]]
end
sql.Begin()
local Update = sql.Query( UpdateStr )
sql.Commit()
if Update==false then
Error( "Chess: Update failed for player "..ply:Nick().." - Query error. "..sql.LastError().."\n" )
end
nextTopUpdate = {}
playerResults = {}
end
function Chess_SetElo( steamID, newElo, isDraughts )
if not tonumber(newElo) then return false,"Elo must be a number." end
if type(steamID)=="Player" then
if not IsValid(steamID) then return end
steamID = steamID:SteamID()
end
local ply = player.GetBySteamID(steamID)
local SelStr = [[SELECT * FROM ChessLeaderboard WHERE SteamID==]].. sql.SQLStr(steamID) ..[[;]]
sql.Begin()
local Select = sql.Query( SelStr )
sql.Commit()
local UpdateStr
if Select==nil then
UpdateStr = [[INSERT INTO ChessLeaderboard (SteamID, Username, Elo, DraughtsElo) VALUES (]]..sql.SQLStr(steamID)..[[,]]..sql.SQLStr(IsValid(ply) and ply:Nick() or "N/A")..[[,]]..sql.SQLStr(IsValid(ply) and ply:GetChessElo() or 1400)..[[,]]..sql.SQLStr(IsValid(ply) and ply:GetDraughtsElo() or 1400)..[[);]]
end
if isDraughts then
UpdateStr = [[UPDATE ChessLeaderboard SET DraughtsElo=]]..sql.SQLStr(tonumber(newElo))..[[ WHERE SteamID==]]..sql.SQLStr(steamID)..[[;]]
else
UpdateStr = [[UPDATE ChessLeaderboard SET Elo=]]..sql.SQLStr(tonumber(newElo))..[[ WHERE SteamID==]]..sql.SQLStr(steamID)..[[;]]
end
sql.Begin()
local Update = sql.Query( UpdateStr )
sql.Commit()
if Update==false then
Error( "Chess: Update failed for player "..steamID.." - Query error. "..sql.LastError().."\n" )
return false
end
nextTopUpdate = {}
playerResults = {}
end
function Chess_GetElo( steamID, isDraughts )
if type(steamID)=="Player" then
if not IsValid(steamID) then return end
steamID = steamID:SteamID()
end
local SelStr = [[SELECT * FROM ChessLeaderboard WHERE SteamID==]].. sql.SQLStr(steamID) ..[[;]]
sql.Begin()
local Select = sql.Query( SelStr )
sql.Commit()
if Select==nil then
return false, "Player does not have an Elo rating"
end
if isDraughts then
return Select[1].DraughtsElo or 1400
else
return Select[1].Elo or 1400 -- Chess
end
end
function Chess_GetRank( ply, typ )
local query = string.gsub([[SELECT (
SELECT COUNT(*)+1
FROM ChessLeaderboard ordered
WHERE (ordered.{ELO}) > (uo.{ELO})
) AS Rank, (SELECT COUNT(*) FROM ChessLeaderboard) AS Count
FROM ChessLeaderboard uo WHERE SteamID==]]..sql.SQLStr(ply:SteamID())..[[;]], "{ELO}", (typ=="Draughts" and [[DraughtsElo]] or [[Elo]]) )
sql.Begin()
local rank = sql.Query( query )
sql.Commit()
if not (rank and rank[1] and rank[1].Rank and rank[1].Count) then return false end
return rank and rank[1] and rank[1].Rank, rank and rank[1] and rank[1].Count
end
util.AddNetworkString( "Chess Top10" )
local ValidType = {["Chess"] = true, ["Draughts"] = true}
local TopTable = {}
net.Receive( "Chess Top10", function( len, ply )
if not IsValid(ply) then return end
local typ = net.ReadString()
if not (typ and ValidType[typ]) then typ = "Chess" end
if not playerResults[typ] then playerResults[typ] = {} end
if playerResults[typ][ply] and (CurTime()<(playerResults[typ][ply].nextUpdate or 0)) then
net.Start( "Chess Top10" )
net.WriteString( typ )
net.Send( ply )
return
end
if CurTime()>(nextTopUpdate[typ] or 0) then
local query = string.gsub([[SELECT Username, SteamID, {ELO} as Elo, (
SELECT COUNT(*)+1
FROM ChessLeaderboard ordered
WHERE (ordered.{ELO}) > (uo.{ELO})
) AS Rank
FROM ChessLeaderboard uo ORDER BY {ELO} DESC LIMIT 10;]], "{ELO}", (typ=="Draughts" and [[DraughtsElo]] or [[Elo]]) )
sql.Begin()
local Top10 = sql.Query( query )
sql.Commit()
if Top10==false then
Error( "Chess: Top10 retrieval failed - Query error. "..sql.LastError().."\n" )
return
elseif Top10==nil then
Error( "Chess: Top10 retrieval failed - No data." )
return
end
TopTable = Top10
table.Empty(playerResults[typ])
nextTopUpdate[typ] = CurTime() + 120
end
local str = ""
if (not playerResults[typ][ply]) or CurTime()<(playerResults[typ][ply].nextUpdate) then
local rank,total = Chess_GetRank(ply, typ)
playerResults[typ][ply] = {rank = rank, total = total}
end
local res = playerResults[typ][ply]
str = (res.rank and res.total and res.rank.." of "..res.total) or res.rank or "N/A"
net.Start( "Chess Top10" )
net.WriteString( typ )
net.WriteTable( TopTable )
net.WriteString( str )
net.WriteString(math.floor(nextTopUpdate[typ] - 120))
net.Send( ply )
playerResults[typ][ply].nextUpdate = CurTime() + 30
end)
-- function TestElo()
-- local typ = ""
-- local query = string.gsub([[SELECT *,(
-- SELECT COUNT(*)+1
-- FROM ChessLeaderboard ordered
-- WHERE (ordered.{ELO}) > (uo.{ELO})
-- ) AS Rank, (SELECT COUNT(*) FROM ChessLeaderboard) AS Count
-- FROM ChessLeaderboard uo ORDER BY {ELO} DESC;]], "{ELO}", (typ=="Draughts" and [[DraughtsElo]] or [[Elo]]) )
-- sql.Begin()
-- local Top10 = sql.Query( query )
-- sql.Commit()
-- if Top10 then
-- print( Top10 )
-- PrintTable( Top10 )
-- print( Top10[1].Rank, type(Top10[1].Rank) )
-- else
-- print( sql.LastError() )
-- end
-- end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,684 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SERVER then
AddCSLuaFile()
end
ENT.Type = "anim"
ENT.Model = Model("models/weapons/w_slam.mdl")
ENT.Base = "ent_chess_board"
ENT.Models = {
["board"] = Model("models/props_phx/games/chess/board.mdl"),
["table"] = Model("models/props/de_tides/restaurant_table.mdl"),
["hl2table"] = Model( "models/props_c17/furnituretable001a.mdl" ),
["dama"] = Model("models/props_phx/games/chess/white_pawn.mdl"),
["WhiteMan"] = Model("models/props_phx/games/chess/white_dama.mdl"), ["BlackMan"] = Model("models/props_phx/games/chess/black_dama.mdl"),
["WhiteKing"] = Model("models/props_phx/games/chess/white_dama.mdl"), ["BlackKing"] = Model("models/props_phx/games/chess/black_dama.mdl"),
}
ENT.Characters = { -- Notepad's being weird and not showing these characters. If you can't see them, they'll still show up in-game.
["WhiteMan"] = Model(""), ["BlackMan"] = Model(""),
["WhiteKing"] = Model(""), ["BlackKing"] = Model(""),
}
ENT.DrawDouble = {
["King"] = true,
}
ENT.PrintName = "Draughts/Checkers"
ENT.Author = "my_hat_stinks"
ENT.Information = "A draughts (checkers) board"
ENT.Category = "Game boards"
ENT.Game = "Draughts"
ENT.Spawnable = true
ENT.AdminOnly = true
ENT.AdminSpawnable = true
--Status
local CHESS_INACTIVE = 0
local CHESS_WHITEMOVE = 1
local CHESS_BLACKMOVE = 2
local CHESS_WHITEPROMO = 3 local CHESS_WHITEJUMP = 3
local CHESS_BLACKPROMO = 4 local CHESS_BLACKJUMP = 4
local CHESS_WAGER = 5
--Captured piece squares
local CHESS_WCAP1 = 10
local CHESS_WCAP2 = 11
local CHESS_BCAP1 = 12
local CHESS_BCAP2 = 13
-- Draw Offer
local PLAYER_NONE = 0 -- Nobody offering to draw
local PLAYER_WHITE = 1 -- White offering to draw
local PLAYER_BLACK = 2 -- Black offering to draw
local NumToLetter = {"a", "b", "c", "d", "e", "f", "g", "h", ["a"]=1, ["b"]=2, ["c"]=3, ["d"]=4, ["e"]=5, ["f"]=6, ["g"]=7, ["h"]=8} --Used extensively for conversions
ENT.StartState = CHESS_BLACKMOVE
function ENT:SetupDataTables()
-- self:NetworkVar( "Int", 0, "BlackPassant" )
-- self:NetworkVar( "Int", 1, "WhitePassant" )
self:NetworkVar( "Int", 2, "ChessState" )
self:NetworkVar( "Bool", 0, "Playing" )
self:NetworkVar( "Int", 3, "DrawOffer" )
self:NetworkVar( "Float", 0, "WhiteWager" )
self:NetworkVar( "Float", 1, "BlackWager" )
self:NetworkVar( "Entity", 0, "WhitePlayer" )
self:NetworkVar( "Entity", 1, "BlackPlayer" )
self:NetworkVar( "Entity", 2, "TableEnt" )
-- self:NetworkVar( "Int", 3, "MoveCount" )
-- self:NetworkVar( "Bool", 1, "Repetition" )
self:NetworkVar( "Bool", 2, "PSWager" )
self:NetworkVar( "Float", 2, "WhiteTime" )
self:NetworkVar( "Float", 3, "BlackTime" )
--Draughts vars
self:NetworkVar( "Bool", 1, "JumpMove" )
self:NetworkVar( "Int", 0, "JumpLet" )
self:NetworkVar( "Int", 1, "JumpNum" )
end
function ENT:Initialize()
self.ChessDerived = true
self.IsDraughts = true
return self.BaseClass.Initialize( self )
end
function ENT:GetManMoves( tbl, GridLet, GridNum, IsWhite )
local CapMove = false
--Forward Right
local TargetRow = GridNum+ (IsWhite and 1 or (-1))
local TargetColumn = NumToLetter[GridLet]+1
if TargetRow<=8 and TargetRow>=1 and TargetColumn<=8 and TargetColumn>=1 then
local target = self:GetSquare( NumToLetter[TargetColumn], TargetRow )
if target then
if ((self:SquareTeam(target)=="White")~=IsWhite) then --Enemy piece
local CapRow = TargetRow+ (IsWhite and 1 or (-1))
local CapCol = TargetColumn+1
if CapRow<=8 and CapRow>=1 and CapCol<=8 and CapCol>=1 then --In range
local target = self:GetSquare( NumToLetter[CapCol], CapRow )
if not target then --Empty space
tbl[NumToLetter[CapCol]][CapRow] = {"CAPTURE", NumToLetter[TargetColumn], TargetRow} --Capture move
CapMove = true --Flag as capture move
end
end
end
else
tbl[NumToLetter[TargetColumn]][TargetRow] = true --Standard valid move
end
end
--Forward Left
local TargetRow = GridNum+ (IsWhite and 1 or (-1))
local TargetColumn = NumToLetter[GridLet]-1
if TargetRow<=8 and TargetRow>=1 and TargetColumn<=8 and TargetColumn>=1 then
local target = self:GetSquare( NumToLetter[TargetColumn], TargetRow )
if target then
if ((self:SquareTeam(target)=="White")~=IsWhite) then
local CapRow = TargetRow+ (IsWhite and 1 or (-1))
local CapCol = TargetColumn-1
if CapRow<=8 and CapRow>=1 and CapCol<=8 and CapCol>=1 then
local target = self:GetSquare( NumToLetter[CapCol], CapRow )
if not target then
tbl[NumToLetter[CapCol]][CapRow] = {"CAPTURE", NumToLetter[TargetColumn], TargetRow}
CapMove = true
end
end
end
else
tbl[NumToLetter[TargetColumn]][TargetRow] = true --Standard valid move
end
end
return CapMove
end
function ENT:GetKingMoves( tbl, GridLet, GridNum, IsWhite )
local CapMove = self:GetManMoves( tbl, GridLet, GridNum, IsWhite ) --Forward moves
--Back Right
local TargetRow = GridNum+ (IsWhite and (-1) or (1))
local TargetColumn = NumToLetter[GridLet]+1
if TargetRow<=8 and TargetRow>=1 and TargetColumn<=8 and TargetColumn>=1 then
local target = self:GetSquare( NumToLetter[TargetColumn], TargetRow )
if target then
if ((self:SquareTeam(target)=="White")~=IsWhite) then
local CapRow = TargetRow+ (IsWhite and (-1) or (1))
local CapCol = TargetColumn+1
if CapRow<=8 and CapRow>=1 and CapCol<=8 and CapCol>=1 then
local target = self:GetSquare( NumToLetter[CapCol], CapRow )
if not target then
tbl[NumToLetter[CapCol]][CapRow] = {"CAPTURE", NumToLetter[TargetColumn], TargetRow}
CapMove = true
end
end
end
else
tbl[NumToLetter[TargetColumn]][TargetRow] = true --Standard valid move
end
end
--Back Left
local TargetRow = GridNum+ (IsWhite and (-1) or (1))
local TargetColumn = NumToLetter[GridLet]-1
if TargetRow<=8 and TargetRow>=1 and TargetColumn<=8 and TargetColumn>=1 then
local target = self:GetSquare( NumToLetter[TargetColumn], TargetRow )
if target then
if ((self:SquareTeam(target)=="White")~=IsWhite) then
local CapRow = TargetRow+ (IsWhite and (-1) or (1))
local CapCol = TargetColumn-1
if CapRow<=8 and CapRow>=1 and CapCol<=8 and CapCol>=1 then
local target = self:GetSquare( NumToLetter[CapCol], CapRow )
if not target then
tbl[NumToLetter[CapCol]][CapRow] = {"CAPTURE", NumToLetter[TargetColumn], TargetRow}
CapMove = true
end
end
end
else
tbl[NumToLetter[TargetColumn]][TargetRow] = true --Standard valid move
end
end
return CapMove
end
function ENT:GetMove( GridLet, GridNum, IgnoreCap )
if not (GridLet and GridNum) then return {} end
if not NumToLetter[GridLet] then return {} end
if NumToLetter[GridLet]<1 or NumToLetter[GridLet]>8 then return {} end
if GridNum<1 or GridNum>8 then return {} end
local square = self:GetSquare( GridLet, GridNum )
if not square then return {} end
local class = square.Class or (IsValid(square.Ent) and square.Ent:GetRole())
if not class then return {} end
if self:GetJumpMove() and self:GetJumpLet()~=0 and self:GetJumpNum()~=0 and (NumToLetter[GridLet]~=self:GetJumpLet() or GridNum~=self:GetJumpNum()) then return {} end
local IsWhite = self:SquareTeam(square)=="White"
local Moved = self:SquareMoved(square)
local CanJump = IgnoreCap or self:CanCapture( IsWhite )
local tbl = { ["a"] = {}, ["b"] = {}, ["c"] = {}, ["d"] = {}, ["e"] = {}, ["f"] = {}, ["g"] = {}, ["h"] = {} }
if class=="King" then
self:GetKingMoves( tbl, GridLet, GridNum, IsWhite )
else
self:GetManMoves( tbl, GridLet, GridNum, IsWhite )
end
if CanJump then
for CheckLet,File in pairs(tbl) do
for CheckNum,v in pairs(File) do
if v==true then
tbl[CheckLet][CheckNum] = nil --We can capture, but this isn't a capture move
end
end
end
end
return tbl
end
function ENT:ResetBoard()
if SERVER then
self:SetDrawOffer( PLAYER_NONE )
self:SetWhiteWager( -1 )
self:SetBlackWager( -1 )
self:SetWhiteTime( 600 )
self:SetBlackTime( 600 )
self:SetJumpMove( false )
self:SetJumpLet( 0 )
self:SetJumpNum( 0 )
end
self:RefreshSquares()
if self.Pieces then
for _,File in pairs( self.Pieces ) do
for _,Square in pairs(File) do
if IsValid(Square.Ent) then Square.Ent:SetGridNum(-1) Square.Ent:Remove() end
end
end
end
self.Pieces = {
["a"] = {
[1] = {Team="White",Class="Man",Moved=false}, [3] = {Team="White",Class="Man",Moved=false}, [7] = {Team="Black",Class="Man",Moved=false},
},
["b"] = {
[2] = {Team="White",Class="Man",Moved=false}, [6] = {Team="Black",Class="Man",Moved=false}, [8] = {Team="Black",Class="Man",Moved=false},
},
["c"] = {
[1] = {Team="White",Class="Man",Moved=false}, [3] = {Team="White",Class="Man",Moved=false}, [7] = {Team="Black",Class="Man",Moved=false},
},
["d"] = {
[2] = {Team="White",Class="Man",Moved=false}, [6] = {Team="Black",Class="Man",Moved=false}, [8] = {Team="Black",Class="Man",Moved=false},
},
["e"] = {
[1] = {Team="White",Class="Man",Moved=false}, [3] = {Team="White",Class="Man",Moved=false}, [7] = {Team="Black",Class="Man",Moved=false},
},
["f"] = {
[2] = {Team="White",Class="Man",Moved=false}, [6] = {Team="Black",Class="Man",Moved=false}, [8] = {Team="Black",Class="Man",Moved=false},
},
["g"] = {
[1] = {Team="White",Class="Man",Moved=false}, [3] = {Team="White",Class="Man",Moved=false}, [7] = {Team="Black",Class="Man",Moved=false},
},
["h"] = {
[2] = {Team="White",Class="Man",Moved=false}, [6] = {Team="Black",Class="Man",Moved=false}, [8] = {Team="Black",Class="Man",Moved=false},
},
[CHESS_WCAP1] = {}, [CHESS_WCAP2] = {}, [CHESS_BCAP1] = {}, [CHESS_BCAP2] = {},
}
self:Update()
end
function ENT:CanCapture( White )
for Let,column in pairs( self.Pieces ) do
for Num,square in pairs( column ) do
if square.Team==(White and "White" or "Black") then
local moves = self:GetMove( Let, Num, true )
for _,column in pairs( moves ) do
for _,move in pairs( column ) do
if type(move)=="table" and move[1]=="CAPTURE" then return true end
end
end
end
end
end
return false
end
function ENT:CanMove( White )
for Let,column in pairs( self.Pieces ) do
for Num,square in pairs( column ) do
if square.Team==(White and "White" or "Black") then
local moves = self:GetMove( Let, Num )
for _,column in pairs( moves ) do
for _,move in pairs( column ) do
if move then return true end
end
end
end
end
end
return false
end
function ENT:NoMaterialCheck()
local BlackMat = {}
local WhiteMat = {}
for GridLet,File in pairs(self.Pieces) do
if GridLet==CHESS_WCAP1 or GridLet==CHESS_WCAP2 or GridLet==CHESS_BCAP1 or GridLet==CHESS_BCAP2 then continue end
for GridNum,square in pairs(File) do
if square then
local IsWhite = self:SquareTeam(square)=="White"
if IsWhite then
table.insert( WhiteMat, {Square=square, Class=Class, GridLet=GridLet, GridNum=GridNum} )
else
table.insert( BlackMat, {square=square, Class=Class, GridLet=GridLet, GridNum=GridNum} )
end
end
end
end
if (#BlackMat+#WhiteMat)==0 then self:EndGame() return false end
if #WhiteMat==0 then self:EndGame("Black") return false end
if #BlackMat==0 then self:EndGame("White") return false end
return true
end
function ENT:EndGame( winner, NoMsg )
self:SetChessState( CHESS_INACTIVE )
self:SetPlaying( false )
local White = self:GetPlayer( "White" )
local Black = self:GetPlayer( "Black" )
local WhiteName = IsValid(White) and White:Nick() or "[Anonymous White]"
local BlackName = IsValid(Black) and Black:Nick() or "[Anonymous Black]"
if not NoMsg then
net.Start( "Chess GameOver" )
if winner=="White" then
net.WriteTable( {" ", Color(255,255,255), WhiteName, Color(150,255,150), " has won against ", Color(100,100,100), BlackName, Color(150,255,150), "!"} )
else
net.WriteTable( {" ", Color(100,100,100), BlackName, Color(150,255,150), " has won against ", Color(255,255,255), WhiteName, Color(150,255,150), "!"} )
end
net.WriteString( "icon16/medal_gold_2.png" )
net.Broadcast()
end
timer.Simple( 0.5, function()
if not IsValid(self) then return end
if IsValid(Black) and Black:GetVehicle()==self.BlackSeat then Black:ExitVehicle() end
if IsValid(White) and White:GetVehicle()==self.WhiteSeat then White:ExitVehicle() end
end)
local winnings = (self.WagerValue or 0)*2
if IsValid( White ) then
if winner=="White" then
if IsValid(Black) then White:DraughtsWin( Black ) end
if self.WagerValue then
if self:GetPSWager() then
White:PS_GivePoints( winnings )
else
if White.addMoney then White:addMoney( winnings ) else White:SetDarkRPVar( "money", (White:getDarkRPVar( "money" ) or 0) + winnings ) end
end
end
elseif winner~="Black" then
if IsValid(Black) and winner~="Error" then White:DraughtsDraw( Black ) end
if self.WagerValue then
if self:GetPSWager() then
White:PS_GivePoints( self.WagerValue )
else
if White.addMoney then White:addMoney( self.WagerValue ) else White:SetDarkRPVar( "money", (White:getDarkRPVar( "money" ) or 0) + self.WagerValue ) end
end
end
end
end
if IsValid( Black ) then
if winner=="Black" then
if IsValid(White) then Black:DraughtsWin( White ) end
if self.WagerValue then
if self:GetPSWager() then
Black:PS_GivePoints( winnings )
else
if Black.addMoney then Black:addMoney( winnings ) else Black:SetDarkRPVar( "money", (Black:getDarkRPVar( "money" ) or 0) + winnings ) end
end
end
elseif winner~="White" then
if self.WagerValue then
if self:GetPSWager() then
White:PS_GivePoints( self.WagerValue )
else
if White.addMoney then White:addMoney( self.WagerValue ) else White:SetDarkRPVar( "money", (White:getDarkRPVar( "money" ) or 0) + self.WagerValue ) end
end
end
end
end
end
function ENT:DoCapture( square, EndLet, EndNum )
if not square then return end
local class = square.Class
local made = false
local CapLet,CapNum
if square.Team=="White" then --Black captured
for i=CHESS_BCAP1,CHESS_BCAP2 do
for n=1,8 do
local CapSq = self:GetSquare( i, n )
if not CapSq then
self.Pieces[i][n] = {Team="White", Class=class, Moved=false}
CapSq = self.Pieces[i][n]
made = true
CapLet,CapNum = i,n
break
end
end
if made then break end
end
else
for i=CHESS_WCAP1,CHESS_WCAP2 do
for n=1,8 do
local CapSq = self:GetSquare( i, n )
if not CapSq then
self.Pieces[i][n] = {Team="Black", Class=class, Moved=false}
CapSq = self.Pieces[i][n]
made = true
CapLet,CapNum = i,n
break
end
end
if made then break end
end
end
return {From={EndLet,EndNum}, To={CapLet,CapNum}}
end
function ENT:DoMove( StartLet, StartNum, EndLet, EndNum )
if CLIENT then return end
if not (StartLet and EndLet and StartNum and EndNum) then return end
if (StartLet==EndLet) and (StartNum==EndNum) then return end
local Start = self:GetSquare( StartLet, StartNum )
if not Start then return end
local Moves = self:GetMove( StartLet, StartNum )
if not Moves[EndLet][EndNum] then return end
local Move = Moves[EndLet][EndNum]
local CapMove
if type(Move)=="table" then
if Move[1]=="CAPTURE" then
local CapLet, CapNum = Move[2], Move[3]
local square = self:GetSquare( CapLet, CapNum )
if CapLet and CapNum then
CapMove = self:DoCapture( square, CapLet, CapNum )
self.Pieces[CapLet][CapNum] = nil
end
end
end
local End = self:GetSquare( EndLet, EndNum )
if not End then
self.Pieces[EndLet] = self.Pieces[EndLet] or {}
self.Pieces[EndLet][EndNum] = self.Pieces[EndLet][EndNum] or {}
End = self.Pieces[EndLet][EndNum]
end
End.Team=Start.Team
End.Class=Start.Class
End.Moved=true
self.Pieces[StartLet][StartNum] = nil
local ply = self:GetPlayer( End.Team )
if (EndNum==1 or EndNum==8) and End.Class=="Man" then --End of the board, promote
End.Class = "King"
// self:SetChessState( End.Team=="White" and CHESS_BLACKMOVE or CHESS_WHITEMOVE )
//
// self:SetJumpMove( false )
// self:SetJumpLet( 0 )
// self:SetJumpNum( 0 )
end
if type(Move)=="table" and Move[1]=="CAPTURE" then
self:SetJumpMove(false)
if self:CanCapture( End.Team=="White" ) then
local GetMoves = self:GetMove(EndLet, EndNum)
local Cap = false
for _,column in pairs( GetMoves ) do
for _,move in pairs(column) do
if move and move~=true then
Cap=true
end
end
end
if Cap then
self:SetJumpMove( true )
self:SetJumpLet( NumToLetter[EndLet] )
self:SetJumpNum( EndNum )
else
self:SetChessState( End.Team=="White" and CHESS_BLACKMOVE or CHESS_WHITEMOVE )
self:SetJumpMove( false )
self:SetJumpLet( 0 )
self:SetJumpNum( 0 )
end
else
self:SetChessState( End.Team=="White" and CHESS_BLACKMOVE or CHESS_WHITEMOVE )
self:SetJumpMove( false )
self:SetJumpLet( 0 )
self:SetJumpNum( 0 )
end
else --Standard move, other player's turn
self:SetChessState( End.Team=="White" and CHESS_BLACKMOVE or CHESS_WHITEMOVE )
self:SetJumpMove( false )
self:SetJumpLet( 0 )
self:SetJumpNum( 0 )
end
local move = {From={StartLet,StartNum},To={EndLet,EndNum}}
self:Update( move, CapMove )
self:NoMaterialCheck()
if self:GetChessState()==CHESS_BLACKMOVE and not self:CanMove( false ) then self:EndGame( "White" ) end
if self:GetChessState()==CHESS_WHITEMOVE and not self:CanMove( true ) then self:EndGame( "Black" ) end
return move
end
function ENT:GetElo( ply )
return IsValid(ply) and " ("..ply:GetDraughtsElo()..")" or ""
end
if CLIENT then
local PanelCol = {
Main = Color(0,0,0,200), ToMove = Color(200,200,200,20), Text = Color(180,180,180),
White = Color(255,255,255), Black = Color(20,20,20,255),
}
local StateToString = {[CHESS_INACTIVE] = "Waiting", [CHESS_WHITEMOVE] = "White", [CHESS_BLACKMOVE] = "Black", [CHESS_WHITEPROMO] = "White (jumping)", [CHESS_BLACKPROMO] = "Black (jumping)", [CHESS_WAGER] = "Wagers"}
function ENT:CreateChessPanel()
self:EndSpectating()
local frame = vgui.Create( "DFrame" )
frame:SetSize(400,115)
frame:SetPos( (ScrW()/2)-100, ScrH()-150 )
--frame:SetDraggable( false )
frame:SetTitle( "" )
frame:ShowCloseButton( false )
frame:SetDeleteOnClose( true )
frame.Paint = function( s,w,h )
if not IsValid(self) then
s:Remove()
gui.EnableScreenClicker( false )
return
end
draw.RoundedBox( 8, 0, 0, w, h, PanelCol.Main )
end
frame:DockMargin( 0,0,0,0 )
frame:DockPadding( 5,6,5,5 )
local TimePnl = vgui.Create( "DPanel", frame )
TimePnl:Dock( RIGHT )
TimePnl:SetWide( 100 )
TimePnl:DockMargin( 2,2,2,2 )
TimePnl.Paint = function(s,w,h)
if not IsValid(self) then return end
draw.RoundedBox( 16, 0, 0, w, (h/2)-1, PanelCol.ToMove )
draw.RoundedBox( 16, 0, (h/2)+1, w, (h/2)-1, PanelCol.ToMove )
draw.SimpleText( string.FormattedTime( math.Round(self:GetWhiteTime() or 300,1), "%02i:%02i" ), "ChessText", w/2, h/4, PanelCol.White, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
draw.SimpleText( string.FormattedTime( math.Round(self:GetBlackTime() or 300,1), "%02i:%02i" ), "ChessText", w/2, (h/4)+(h/2), PanelCol.Black, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
end
local ButtonPanel = vgui.Create( "DPanel", frame )
ButtonPanel:SetSize( 100, 20 )
ButtonPanel:Dock( LEFT )
ButtonPanel.Paint = function() end
local ToMove = vgui.Create( "DPanel", frame )
ToMove:SetSize(200,80)
ToMove:Dock( FILL )
ToMove.Paint = function( s,w,h )
draw.RoundedBox( 4, 0, 0, w, h, PanelCol.ToMove )
draw.SimpleText( "To move", "ChessTextSmall", 5, 0, PanelCol.Text )
local state = IsValid(self) and self:GetChessState()
if not (IsValid( self ) and state) then
draw.SimpleText( "[N/A]", "ChessTextSmall", w/2, h/2, PanelCol.Text, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
else
local str = (StateToString[state] or "N/A")..( (self:GetPlaying() and self:GetJumpMove() and " (jump)") or "" )
local col = ((state==CHESS_WHITEMOVE or state==CHESS_WHITEPROMO) and PanelCol.White) or ((state==CHESS_BLACKMOVE or state==CHESS_BLACKPROMO) and PanelCol.Black) or PanelCol.Text
draw.SimpleText( str, "ChessTextLarge", w/2, h/2, col, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
end
end
frame.OfferDraw = vgui.Create( "DButton", ButtonPanel)
frame.OfferDraw:SetSize(94,35)
frame.OfferDraw:Dock( TOP )
frame.OfferDraw:SetText( "Offer Draw" )
frame.OfferDraw.DoClick = function( s )
if (IsValid(self)) and not (self:GetPlaying()) then
chat.AddText( Color(150,255,150), "You can't offer a draw before the game starts!" )
return
end
net.Start( "Chess DrawOffer" ) net.SendToServer()
-- s:SetText( "Draw offered" )
end
frame.OfferDraw.Think = function(s)
if IsValid(self) and self:GetDrawOffer()~=PLAYER_NONE then
if s.TextChanged then return end
s.TextChanged = true
if LocalPlayer()==self:GetWhitePlayer() then
if self:GetDrawOffer()==PLAYER_WHITE then
s:SetText( "Draw Offered" )
elseif self:GetDrawOffer()==PLAYER_BLACK then
s:SetText( "Accept Draw Offer" )
end
elseif LocalPlayer()==self:GetBlackPlayer() then
if self:GetDrawOffer()==PLAYER_WHITE then
s:SetText( "Accept Draw Offer" )
elseif self:GetDrawOffer()==PLAYER_BLACK then
s:SetText( "Draw Offered" )
end
end
elseif s.TextChanged then
s.TextChanged = false
s:SetText( "Offer Draw" )
end
end
local Resign = vgui.Create( "DButton", ButtonPanel)
Resign:SetSize(94,35)
Resign:Dock( TOP )
Resign:SetText( "Resign" )
Resign.DoClick = function( s )
net.Start( "Chess ClientResign" ) net.SendToServer() --No client-side exit func :/
end
local DermaMode = vgui.Create( "DButton", ButtonPanel)
DermaMode:SetSize(94,35)
DermaMode:Dock( TOP )
DermaMode:SetText( "Toggle 2D Mode" )
DermaMode.DoClick = function( s )
if IsValid(Chess_2DDermaPanel) then
Chess_2DDermaPanel:Remove()
else
Chess_Open2DBoard( self )
end
end
return frame
end
end

View File

@@ -0,0 +1,241 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--Easy placement and saving for Chess boards
if SERVER then AddCSLuaFile() end
SWEP.Base = "weapon_base"
SWEP.Category = "Game boards"
SWEP.Author = "my_hat_stinks"
SWEP.Instructions = "Left click to place a board, right click to remove a board, reload for menu"
SWEP.Spawnable = true
SWEP.AdminOnly = true
SWEP.AdminSpawnable = true
SWEP.Slot = 4
SWEP.PrintName = "Chess Admin Tool"
SWEP.ViewModelFOV = 80
SWEP.Weight = 5
SWEP.AutoSwitchTo = false
SWEP.AutoSwitchFrom = false
SWEP.WorldModel = "models/weapons/w_toolgun.mdl"
SWEP.ViewModel = "models/weapons/c_toolgun.mdl"
SWEP.UseHands = true
SWEP.Primary.Recoil = 1
SWEP.Primary.Damage = 5
SWEP.Primary.NumShots = 1
SWEP.Primary.Cone = 0
SWEP.Primary.Delay = 1
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = -1
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = "none"
SWEP.Primary.ClipMax = -1
SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = -1
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = "none"
SWEP.Secondary.ClipMax = -1
SWEP.DeploySpeed = 1.5
SWEP.PrimaryAnim = ACT_VM_PRIMARYATTACK
SWEP.ReloadAnim = ACT_VM_RELOAD
SWEP.HoldType = "pistol"
SWEP.GameEntities = {
{"Chess", "ent_chess_board", {["board"] = Model("models/props_phx/games/chess/board.mdl"), ["table"] = Model("models/props/de_tides/restaurant_table.mdl")}},
{"Draughts/Checkers", "ent_draughts_board", {["board"] = Model("models/props_phx/games/chess/board.mdl"), ["table"] = Model("models/props/de_tides/restaurant_table.mdl")}},
}
function SWEP:SetupDataTables()
self:NetworkVar( "Int", 0, "EntID" )
end
function SWEP:Initialize()
self:SetEntID( 1 ) --Chess by default
end
function SWEP:PrimaryAttack()
if SERVER and IsValid( self.Owner ) then
if not self.Owner:IsAdmin() then
self.Owner:ChatPrint( "You are not allowed to use this tool!" )
self:Remove()
return
end
local tr = self.Owner:GetEyeTrace()
if tr.Hit and tr.HitPos then
local ent = ents.Create( self.GameEntities[self:GetEntID()][2] )
ent:SetPos( tr.HitPos )
ent:Spawn()
end
end
end
function SWEP:SecondaryAttack()
if SERVER and IsValid( self.Owner ) then
if not self.Owner:IsAdmin() then
self.Owner:ChatPrint( "You are not allowed to use this tool!" )
self:Remove()
return
end
local tr = self.Owner:GetEyeTrace()
if IsValid(tr.Entity) and tr.Entity.IsChessEntity then tr.Entity:Remove() end
end
end
function SWEP:Reload()
if CLIENT then self:OpenMenu() end
end
function SWEP:OpenMenu()
if SERVER then return end
if IsValid(self.Menu) then self.Menu:Remove() end
self.Menu = vgui.Create( "DFrame" )
self.Menu:SetTitle( "Chess Admin Tool" )
self.Menu:SetSize( 300, 80 )
self.Menu:SetPos( ScrW()/2-150, ScrH()/2-50 )
self.Menu:MakePopup()
local drop = vgui.Create( "DComboBox", self.Menu )
drop:Dock( TOP )
drop:SetValue( "Select Board" )
for i=1,#self.GameEntities do
drop:AddChoice( self.GameEntities[i][1], i )
end
drop.OnSelect = function( s, ind, val, data )
RunConsoleCommand( "chess_admin_toolent", tostring(data) )
end
local btnpnl = vgui.Create( "DPanel", self.Menu )
btnpnl:Dock( BOTTOM )
btnpnl:SetTall( 20 )
btnpnl.Paint = function() end
local close = vgui.Create( "DButton", btnpnl )
close:SetWidth( 98 )
close:Dock( RIGHT )
close:SetText( "Close" )
close.DoClick = function(s) if IsValid(self) and IsValid(self.Menu) then self.Menu:Remove() end end
local rem = vgui.Create( "DButton", btnpnl )
rem:SetWidth( 98 )
rem:Dock( LEFT )
rem:SetText( "Remove tool" )
rem.DoClick = function(s)
RunConsoleCommand( "chess_admin_toolremove" )
if IsValid(self) and IsValid(self.Menu) then self.Menu:Remove() end
end
local sv = vgui.Create( "DButton", btnpnl )
sv:SetWidth( 98 )
sv:Dock( FILL )
sv:SetText( "Save boards" )
sv.DoClick = function(s)
RunConsoleCommand( "chess_save" )
end
end
function SWEP:OnRemove()
if CLIENT and self.Ghosts then
for _,v in pairs(self.Ghosts) do if IsValid(v) then v:Remove() end end
end
end
function SWEP:Holster()
if CLIENT then
if self.Ghosts then
for _,v in pairs(self.Ghosts) do if IsValid(v) then v:Remove() end end
end
return true
end
return true
end
if SERVER then
local function SetToolEnt( tool, index )
if tool.GameEntities[index] then tool:SetEntID( index ) end
end
concommand.Add( "chess_admin_toolent", function(p,c,a)
if IsValid(p:GetActiveWeapon()) and p:GetActiveWeapon():GetClass()=="chess_admin_tool" then
SetToolEnt( p:GetActiveWeapon(), tonumber(a[1]) )
end
end)
concommand.Add( "chess_admin_toolremove", function(p,c,a)
if IsValid(p:GetActiveWeapon()) and p:GetActiveWeapon():GetClass()=="chess_admin_tool" then p:GetActiveWeapon():Remove() end
end)
end
if CLIENT then
surface.CreateFont( "ChessAdmin", {
font="Arial", size=40,
})
local ColBox = Color(0,0,0,150)
local ColText = Color(255,255,255,255)
local ColGhost = Color(0,255,0,150)
function SWEP:DrawHUD()
local w,h = ScrW(), ScrH()
local txt = "Board: ".. tostring( self.GameEntities[self:GetEntID()][1] )
surface.SetFont( "ChessAdmin" )
local tw, th = surface.GetTextSize( txt )
surface.SetDrawColor( ColBox )
surface.DrawRect( (w/2) - ((tw/2)+3), h - (th+6), tw+6, th+6 )
draw.DrawText( txt, "ChessAdmin", w/2, h-(th)-3, ColText, TEXT_ALIGN_CENTER )
end
function SWEP:DoGhosts()
local tr = self.Owner:GetEyeTrace()
if (not tr.Hit) then return end
self.Ghosts = self.Ghosts or {}
local mdltbl = self.GameEntities[self:GetEntID()][3]
if not mdltbl then return end
self.Ghosts[1] = IsValid(self.Ghosts[1]) and self.Ghosts[1] or ClientsideModel( mdltbl.table, RENDERGROUP_BOTH )
self.Ghosts[1]:SetPos( tr.HitPos )
self.Ghosts[1]:SetRenderMode( RENDERMODE_TRANSALPHA )
self.Ghosts[1]:SetColor( ColGhost )
local h = 30 --(self.Ghosts[1]:OBBMaxs()[3] - self.Ghosts[1]:OBBMins()[3])
self.Ghosts[2] = IsValid(self.Ghosts[2]) and self.Ghosts[2] or ClientsideModel( mdltbl.board, RENDERGROUP_BOTH )
self.Ghosts[2]:SetPos( tr.HitPos+Vector(0,0,h or 50) )
self.Ghosts[2]:SetAngles( Angle(-90,0,0) )
self.Ghosts[2]:SetModelScale( 0.35, 0 )
self.Ghosts[2]:SetRenderMode( RENDERMODE_TRANSALPHA )
self.Ghosts[2]:SetColor( ColGhost )
self.Ghosts[3] = IsValid(self.Ghosts[3]) and self.Ghosts[3] or ClientsideModel( "models/nova/chair_plastic01.mdl", RENDERGROUP_BOTH )
self.Ghosts[3]:SetPos( tr.HitPos+ (self.Ghosts[2]:GetRight()*40) )
self.Ghosts[3]:SetRenderMode( RENDERMODE_TRANSALPHA )
self.Ghosts[3]:SetColor( ColGhost )
self.Ghosts[4] = IsValid(self.Ghosts[4]) and self.Ghosts[4] or ClientsideModel( "models/nova/chair_plastic01.mdl", RENDERGROUP_BOTH )
self.Ghosts[4]:SetPos( tr.HitPos+ (self.Ghosts[2]:GetRight()*-40) )
self.Ghosts[4]:SetAngles( Angle(0,180,0) )
self.Ghosts[4]:SetRenderMode( RENDERMODE_TRANSALPHA )
self.Ghosts[4]:SetColor( ColGhost )
end
function SWEP:PostDrawViewModel()
if LocalPlayer()~=self.Owner then return self.BaseClass.PostDrawViewModel( self ) end
self:DoGhosts()
end
function SWEP:DrawWorldModel()
if LocalPlayer()~=self.Owner then return self.BaseClass.DrawWorldModel( self ) end
self:DrawModel()
self:DoGhosts()
end
end