Advertisement
Guest User

Untitled

a guest
Jul 21st, 2017
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 93.86 KB | None | 0 0
  1.  
  2. if SERVER then
  3. AddCSLuaFile()
  4.  
  5. --From client
  6. util.AddNetworkString( "Chess ClientRequestMove" )
  7. util.AddNetworkString( "Chess ClientResign" ) --Why not just have a client-side exit func? :/
  8. util.AddNetworkString( "Chess ClientWager" )
  9. util.AddNetworkString( "Chess ClientCallDraw" )
  10. --2-way
  11. util.AddNetworkString( "Chess DrawOffer" )
  12. util.AddNetworkString( "Chess PromotionSelection" )
  13. util.AddNetworkString( "Chess Update" )
  14. --From server
  15. util.AddNetworkString( "Chess GameOver" )
  16.  
  17. CreateConVar( "chess_wagers", 1, FCVAR_ARCHIVE, "Set whether players can wager on their chess games." )
  18. CreateConVar( "chess_darkrp_wager", 1, FCVAR_ARCHIVE, "[DarkRP only] Wagers should use DarkRP wallet." )
  19. CreateConVar( "chess_debug", 0, FCVAR_ARCHIVE, "Debug mode." )
  20.  
  21. CreateConVar( "chess_limitmoves", 0, FCVAR_ARCHIVE, "Enable 50 move rule." )
  22. end
  23.  
  24. ENT.Type = "anim"
  25. ENT.Model = Model("models/weapons/w_slam.mdl")
  26. local UseHL2Model = false
  27. ENT.Models = {
  28. ["board"] = Model("models/props_phx/games/chess/board.mdl"),
  29. ["table"] = (UseHL2Model and Model( "models/props_c17/furnituretable001a.mdl" ) or Model("models/props/de_tides/restaurant_table.mdl")),
  30. ["hl2table"] = Model( "models/props_c17/furnituretable001a.mdl" ),
  31.  
  32. ["BlackPawn"] = Model("models/props_phx/games/chess/black_pawn.mdl"), ["WhitePawn"] = Model("models/props_phx/games/chess/white_pawn.mdl"),
  33. ["BlackRook"] = Model("models/props_phx/games/chess/black_rook.mdl"), ["WhiteRook"] = Model("models/props_phx/games/chess/white_rook.mdl"),
  34. ["BlackKnight"] = Model("models/props_phx/games/chess/black_knight.mdl"), ["WhiteKnight"] = Model("models/props_phx/games/chess/white_knight.mdl"),
  35. ["BlackBishop"] = Model("models/props_phx/games/chess/black_bishop.mdl"), ["WhiteBishop"] = Model("models/props_phx/games/chess/white_bishop.mdl"),
  36. ["BlackQueen"] = Model("models/props_phx/games/chess/black_queen.mdl"), ["WhiteQueen"] = Model("models/props_phx/games/chess/white_queen.mdl"),
  37. ["BlackKing"] = Model("models/props_phx/games/chess/black_king.mdl"), ["WhiteKing"] = Model("models/props_phx/games/chess/white_king.mdl"),
  38.  
  39. ["dama"] = Model("models/props_phx/games/chess/white_dama.mdl"),
  40. }
  41. ENT.Characters = {
  42. ["BlackPawn"] = Model("♟"), ["WhitePawn"] = Model("♙"),
  43. ["BlackRook"] = Model("♜"), ["WhiteRook"] = Model("♖"),
  44. ["BlackKnight"] = Model("♞"), ["WhiteKnight"] = Model("♘"),
  45. ["BlackBishop"] = Model("♝"), ["WhiteBishop"] = Model("♗"),
  46. ["BlackQueen"] = Model("♛"), ["WhiteQueen"] = Model("♕"),
  47. ["BlackKing"] = Model("♚"), ["WhiteKing"] = Model("♔"),
  48. }
  49.  
  50. ENT.PrintName = "Chess"
  51. ENT.Author = "my_hat_stinks"
  52. ENT.Information = "A chess board"
  53. ENT.Category = "Game boards"
  54.  
  55. ENT.Game = "Chess"
  56. ENT.Spawnable = true
  57. ENT.AdminOnly = true
  58. ENT.AdminSpawnable = true
  59.  
  60.  
  61. ENT.TopLeft = Vector(2.5,-15.5,-16) --Local pos of the board's corner (Used for alignment)
  62. ENT.SquareH = 19.5 ENT.SquareW = 20 --For drawing square highlights
  63. ENT.RealH = 4 ENT.RealW = 3.9 --For vector positions
  64.  
  65. ENT.MoveTime = 0.3 --Time it takes to complete a move
  66. ENT.MoveSound = Sound( "physics/wood/wood_solid_impact_soft1.wav" )
  67. ENT.CheckSound = Sound( "physics/concrete/rock_impact_hard1.wav" )
  68.  
  69. 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
  70. local PassantFlags = {1,2,4,8,16,32,64,128} --Bitflags, translate to board positions 1-8. For En Passant rule
  71.  
  72. --Status
  73. local CHESS_INACTIVE = 0
  74. local CHESS_WHITEMOVE = 1
  75. local CHESS_BLACKMOVE = 2
  76. local CHESS_WHITEPROMO = 3
  77. local CHESS_BLACKPROMO = 4
  78. local CHESS_WAGER = 5
  79.  
  80. --Captured piece squares
  81. local CHESS_WCAP1 = 10
  82. local CHESS_WCAP2 = 11
  83. local CHESS_BCAP1 = 12
  84. local CHESS_BCAP2 = 13
  85.  
  86. --Draws
  87. local CHESS_DRAW_50 = 0
  88. local CHESS_DRAW_3 = 1
  89.  
  90. ENT.StartState = CHESS_WHITEMOVE
  91.  
  92. function ENT:SetupDataTables()
  93. self:NetworkVar( "Int", 0, "BlackPassant" )
  94. self:NetworkVar( "Int", 1, "WhitePassant" )
  95.  
  96. self:NetworkVar( "Int", 2, "ChessState" )
  97. self:NetworkVar( "Bool", 0, "Playing" )
  98.  
  99. self:NetworkVar( "Float", 0, "WhiteWager" )
  100. self:NetworkVar( "Float", 1, "BlackWager" )
  101.  
  102. self:NetworkVar( "Entity", 0, "WhitePlayer" )
  103. self:NetworkVar( "Entity", 1, "BlackPlayer" )
  104. self:NetworkVar( "Entity", 2, "TableEnt" )
  105.  
  106. self:NetworkVar( "Int", 3, "MoveCount" )
  107. self:NetworkVar( "Bool", 1, "Repetition" )
  108.  
  109. self:NetworkVar( "Bool", 2, "PSWager" )
  110.  
  111. self:NetworkVar( "Float", 2, "WhiteTime" )
  112. self:NetworkVar( "Float", 3, "BlackTime" )
  113. end
  114. local ChessScale = Matrix({
  115. {0.1225,0,0,0},
  116. {0,0.1225,0,0},
  117. {0,0,0.1225,0},
  118. {0,0,0,0},
  119. })
  120.  
  121. local SpawnedEnts = {}
  122. function ENT:SpawnFunction( ply, tr, ClassName )
  123. if (not tr.Hit) then return end
  124.  
  125. local SpawnPos = tr.HitPos --+ (tr.HitNormal*16)
  126.  
  127. local board = (IsValid(self) and self) or ents.Create( ClassName )
  128. board.SavePos = SpawnPos
  129. board:SetPos( SpawnPos )
  130. board:Spawn()
  131.  
  132. SpawnedEnts[board]=true
  133.  
  134. return board
  135. end
  136. function ENT:Initialize()
  137. if SERVER then
  138. local pos,ang = self:GetPos(),self:GetAngles()
  139.  
  140. local tbl = ents.Create( "prop_physics" )
  141. tbl:SetModel( self.Models["table"] )
  142. tbl:SetPos( pos+ Vector(0,0,UseHL2Model and 15 or 0) )
  143. tbl:Spawn()
  144. tbl:SetCollisionGroup( COLLISION_GROUP_PLAYER )
  145. tbl:PhysicsInit( SOLID_BBOX )
  146. tbl:SetMoveType( MOVETYPE_NONE )
  147. tbl:SetMaxHealth( 1000000 )
  148. tbl.IsChessEntity = true
  149. local height = (tbl:OBBMaxs()[3] - tbl:OBBMins()[3])
  150.  
  151. local BlackSeat = ents.Create( "prop_vehicle_prisoner_pod" )
  152. BlackSeat:SetModel( "models/nova/chair_plastic01.mdl" )
  153. BlackSeat:SetPos( pos+ (self:GetRight()*40) )
  154. BlackSeat:SetAngles( ang )
  155. BlackSeat:Spawn()
  156. BlackSeat:SetMoveType( MOVETYPE_NONE )
  157. BlackSeat:SetCollisionGroup( COLLISION_GROUP_WORLD )
  158. BlackSeat.IsChessEntity = true
  159.  
  160. local WhiteSeat = ents.Create( "prop_vehicle_prisoner_pod" )
  161. WhiteSeat:SetModel( "models/nova/chair_plastic01.mdl" )
  162. WhiteSeat:SetPos( pos+ (self:GetRight()*-40) )
  163. ang:RotateAroundAxis( self:GetUp(),180 ) WhiteSeat:SetAngles( ang ) ang:RotateAroundAxis( self:GetUp(),180 )
  164. WhiteSeat:Spawn()
  165. WhiteSeat:SetMoveType( MOVETYPE_NONE )
  166. WhiteSeat:SetCollisionGroup( COLLISION_GROUP_WORLD )
  167. WhiteSeat.IsChessEntity = true
  168.  
  169. self.IsChessEntity = true
  170.  
  171. ang:RotateAroundAxis( self:GetRight(),90 )
  172. self.BoardHeight = Vector(0,0,height-(UseHL2Model and 6 or 3))
  173. self:SetPos( pos+Vector(0,0,height-(UseHL2Model and 6 or 3)) )
  174. self:SetAngles( ang )
  175.  
  176. self.TableEnt = tbl self:SetTableEnt( tbl )
  177. -- self:SetParent( tbl )
  178.  
  179. --Set some stuff up so we can see it's for chess
  180. self.BlackSeat = BlackSeat BlackSeat:SetNWBool("IsChessSeat", true) BlackSeat:SetNWEntity( "ChessBoard", self )
  181. self.WhiteSeat = WhiteSeat WhiteSeat:SetNWBool("IsChessSeat", true) WhiteSeat:SetNWEntity( "ChessBoard", self )
  182.  
  183. --Darkrp lets people steal seats...
  184. self.WhiteSeat.DoorData = {NonOwnable = true}
  185. self.BlackSeat.DoorData = {NonOwnable = true}
  186. if self.WhiteSeat.setKeysNonOwnable then self.WhiteSeat:setKeysNonOwnable( true ) end
  187. if self.BlackSeat.setKeysNonOwnable then self.BlackSeat:setKeysNonOwnable( true ) end
  188.  
  189. self:SetChessState( CHESS_INACTIVE )
  190. self:SetPlaying( false )
  191.  
  192.  
  193. timer.Simple( 1, function()
  194. if not IsValid(self) then return end
  195.  
  196. local phys = self:GetPhysicsObject()
  197. if IsValid(phys) then
  198. phys:EnableCollisions( false )
  199. phys:Sleep()
  200. end
  201.  
  202. local phys = tbl:GetPhysicsObject()
  203. if IsValid(phys) then
  204. phys:EnableCollisions( false )
  205. phys:Sleep()
  206. end
  207.  
  208. local phys = WhiteSeat:GetPhysicsObject()
  209. if IsValid(phys) then
  210. phys:EnableCollisions( false )
  211. phys:Sleep()
  212. end
  213.  
  214. local phys = BlackSeat:GetPhysicsObject()
  215. if IsValid(phys) then
  216. phys:EnableCollisions( false )
  217. phys:Sleep()
  218. end
  219. end)
  220. end
  221.  
  222. self.Pieces = { ["a"] = {}, ["b"] = {}, ["c"] = {}, ["d"] = {}, ["e"] = {}, ["f"] = {}, ["g"] = {}, ["h"] = {} }
  223.  
  224. self:SetModel( self.Models["board"] )
  225. //self:SetModelScale( 0.35, 0 )
  226.  
  227. self:DrawShadow( false )
  228.  
  229. local mins = self:OBBMins()*0.1
  230. local maxs = self:OBBMaxs()*0.1
  231. self:PhysicsInitBox( mins, maxs )
  232. -- self:PhysicsInitShadow( false, false )
  233. -- self:PhysicsInit( SOLID_BBOX )
  234. -- self:SetCollisionGroup( COLLISION_GROUP_WORLD )
  235. -- self:SetMoveType( MOVETYPE_NONE )
  236. -- self:SetCustomCollisionCheck( true )
  237. if CLIENT then
  238. self:EnableMatrix( "RenderMultiply", ChessScale )
  239. hook.Add( "KeyPress", self, self.GetSpectateUse )
  240. end
  241.  
  242. self:ResetBoard()
  243. end
  244. function ENT:OnRemove()
  245. if SERVER then
  246. if self:GetPlaying() then
  247. local WhitePly = self:GetPlayer( "White" )
  248. local BlackPly = self:GetPlayer( "Black" )
  249.  
  250. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  251. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  252. net.Start( "Chess GameOver" )
  253. net.WriteTable( {Color(150,255,150), "Chess removed! ", Color(255,255,255), WhiteName, Color(150,255,150), " vs ", Color(100,100,100), BlackName, Color(150,255,150)," ended prematurely!"} )
  254. net.Broadcast()
  255. self:EndGame( "Error" )
  256. end
  257.  
  258. if IsValid( self.WhiteSeat ) then self.WhiteSeat:Remove() end
  259. if IsValid( self.BlackSeat ) then self.BlackSeat:Remove() end
  260. if IsValid( self.TableEnt ) then self.TableEnt:Remove() end
  261.  
  262. for GridLet,column in pairs( self.Pieces ) do
  263. for GridNum,square in pairs( column ) do
  264. if IsValid( square.Ent ) then
  265. square.Ent:Remove()
  266. end
  267. end
  268. end
  269. end
  270. if CLIENT then
  271. if IsValid( self.PiecesEnt ) then self.PiecesEnt:Remove() end
  272. if IsValid( self:GetTableEnt() ) and IsValid( self:GetTableEnt().ClientChessTable ) then
  273. self:GetTableEnt().ClientChessTable:Remove()
  274. end
  275. end
  276. end
  277. if SERVER then
  278. hook.Add( "ShutDown", "Chess Server Shutdown", function()
  279. local Ents = ents.FindByClass( "ent_chess_board" )
  280. for _,v in pairs( Ents ) do
  281. if IsValid(v) then
  282. v:EndGame( "Error" )
  283. end
  284. end
  285. local Ents = ents.FindByClass( "ent_draughts_board" )
  286. for _,v in pairs( Ents ) do
  287. if IsValid(v) then
  288. v:EndGame( "Error" )
  289. end
  290. end
  291. end)
  292. end
  293.  
  294. function ENT:GetTableGrid( tbl, key1, key2 )
  295. if type(key1)=="number" then key1=NumToLetter[key1+1] end
  296. return tbl and tbl[key1] and tbl[key1][8-key2]
  297. end
  298. function ENT:GetTableKey( tbl, key1, key2 )
  299. if type(key1)=="string" then key1=NumToLetter[key1]-1 end
  300. return tbl and tbl[key1] and tbl[key1][8-key2]
  301. end
  302.  
  303. function ENT:GetSquare( GridLet, GridNum, tbl )
  304. tbl = tbl or self.Pieces
  305. return tbl[GridLet] and tbl[GridLet][GridNum]
  306. end
  307. function ENT:SquareTeam( square )
  308. if square.Team then return square.Team end
  309.  
  310. return (IsValid(square.Ent) and (square.Ent:GetWhite() and "White" or "Black"))
  311. end
  312. function ENT:SquareMoved( square )
  313. if square.Moved~=nil then return square.Moved end
  314.  
  315. return (IsValid(square.Ent) and square.Ent:GetMoved())
  316. end
  317. function ENT:SquareClass( square )
  318. if square.Class~=nil then return square.Class end
  319.  
  320. return (IsValid(square.Ent) and square.Ent:GetRole())
  321. end
  322. function ENT:SquareColor( GridLet, GridNum )
  323. local NumEven = ((GridNum/2) == math.floor(GridNum/2))
  324. local LetEven = ((NumToLetter[GridLet]/2) == math.floor(NumToLetter[GridLet]/2))
  325.  
  326. return (NumEven==LetEven) and "Black" or "White"
  327. end
  328.  
  329. function ENT:GetRookMoves( tbl, GridLet, GridNum, IsWhite, limit, CheckTable )
  330. limit = limit or 8
  331. local count = 0
  332. for TargetRow = GridNum+1,8 do
  333. local target = self:GetSquare( GridLet, TargetRow, CheckTable )
  334. if target then
  335. if ((self:SquareTeam(target)=="White")~=IsWhite) then
  336. tbl[GridLet][TargetRow] = true
  337. end
  338. break
  339. end
  340. tbl[GridLet][TargetRow] = true
  341. count = count+1 if count>=limit then break end
  342. end
  343. count = 0
  344. for TargetRow = GridNum-1,1,-1 do
  345. local target = self:GetSquare( GridLet, TargetRow, CheckTable )
  346. if target then
  347. if ((self:SquareTeam(target)=="White")~=IsWhite) then
  348. tbl[GridLet][TargetRow] = true
  349. end
  350. break
  351. end
  352. tbl[GridLet][TargetRow] = true
  353. count = count+1 if count>=limit then break end
  354. end
  355. count = 0
  356. for TargetColumn = NumToLetter[GridLet]+1,8 do
  357. local target = self:GetSquare( NumToLetter[TargetColumn], GridNum, CheckTable )
  358. if target then
  359. if ((self:SquareTeam(target)=="White")~=IsWhite) then
  360. tbl[NumToLetter[TargetColumn]][GridNum] = true
  361. end
  362. break
  363. end
  364. tbl[NumToLetter[TargetColumn]][GridNum] = true
  365. count = count+1 if count>=limit then break end
  366. end
  367. count = 0
  368. for TargetColumn = NumToLetter[GridLet]-1,1,-1 do
  369. local target = self:GetSquare( NumToLetter[TargetColumn], GridNum, CheckTable )
  370. if target then
  371. if ((self:SquareTeam(target)=="White")~=IsWhite) then
  372. tbl[NumToLetter[TargetColumn]][GridNum] = true
  373. end
  374. break
  375. end
  376. tbl[NumToLetter[TargetColumn]][GridNum] = true
  377. count = count+1 if count>=limit then break end
  378. end
  379. end
  380. function ENT:GetBishopMoves( tbl, GridLet, GridNum, IsWhite, limit, CheckTable )
  381. limit = limit or 8
  382. local TargetColumn, count = NumToLetter[GridLet], 0
  383. for TargetRow = GridNum+1,8 do
  384. TargetColumn = TargetColumn+1 if TargetColumn>8 then break end
  385. local target = self:GetSquare( NumToLetter[TargetColumn], TargetRow, CheckTable )
  386. if target then
  387. if ((self:SquareTeam(target)=="White")~=IsWhite) then tbl[NumToLetter[TargetColumn]][TargetRow] = true end
  388. break
  389. end
  390. tbl[NumToLetter[TargetColumn]][TargetRow] = true
  391. count = count+1 if count>=limit then break end
  392. end
  393. local TargetColumn, count = NumToLetter[GridLet], 0
  394. for TargetRow = GridNum+1,8 do
  395. TargetColumn = TargetColumn-1 if TargetColumn<1 then break end
  396. local target = self:GetSquare( NumToLetter[TargetColumn], TargetRow, CheckTable )
  397. if target then
  398. if ((self:SquareTeam(target)=="White")~=IsWhite) then tbl[NumToLetter[TargetColumn]][TargetRow] = true end
  399. break
  400. end
  401. tbl[NumToLetter[TargetColumn]][TargetRow] = true
  402. count = count+1 if count>=limit then break end
  403. end
  404. local TargetColumn, count = NumToLetter[GridLet], 0
  405. for TargetRow = GridNum-1,1,-1 do
  406. TargetColumn = TargetColumn+1 if TargetColumn>8 then break end
  407. local target = self:GetSquare( NumToLetter[TargetColumn], TargetRow, CheckTable )
  408. if target then
  409. if ((self:SquareTeam(target)=="White")~=IsWhite) then tbl[NumToLetter[TargetColumn]][TargetRow] = true end
  410. break
  411. end
  412. tbl[NumToLetter[TargetColumn]][TargetRow] = true
  413. count = count+1 if count>=limit then break end
  414. end
  415. local TargetColumn, count = NumToLetter[GridLet], 0
  416. for TargetRow = GridNum-1,1,-1 do
  417. TargetColumn = TargetColumn-1 if TargetColumn<1 then break end
  418. local target = self:GetSquare( NumToLetter[TargetColumn], TargetRow, CheckTable )
  419. if target then
  420. if ((self:SquareTeam(target)=="White")~=IsWhite) then tbl[NumToLetter[TargetColumn]][TargetRow] = true end
  421. break
  422. end
  423. tbl[NumToLetter[TargetColumn]][TargetRow] = true
  424. count = count+1 if count>=limit then break end
  425. end
  426. end
  427. function ENT:GetMove( GridLet, GridNum, IgnoreCheck, CheckTable )
  428. if not (GridLet and GridNum) then return {} end
  429. if not NumToLetter[GridLet] then return {} end
  430. if NumToLetter[GridLet]<1 or NumToLetter[GridLet]>8 then return {} end
  431. if GridNum<1 or GridNum>8 then return {} end
  432.  
  433. local square = self:GetSquare( GridLet, GridNum, CheckTable )
  434. if not square then return {} end
  435.  
  436. local class = square.Class or (IsValid(square.Ent) and square.Ent:GetRole())
  437. if not class then return {} end
  438.  
  439. local IsWhite = self:SquareTeam(square)=="White"
  440. local Moved = self:SquareMoved(square)
  441.  
  442. local ChecksPerformed = false --Castling checks for check differently, flag it as done here
  443. local tbl = { ["a"] = {}, ["b"] = {}, ["c"] = {}, ["d"] = {}, ["e"] = {}, ["f"] = {}, ["g"] = {}, ["h"] = {} }
  444. if class=="Pawn" then
  445. local TargetRow = IsWhite and GridNum+1 or GridNum-1
  446.  
  447. local CapOne = self:GetSquare( NumToLetter[NumToLetter[GridLet]-1], TargetRow, CheckTable )
  448. if CapOne then --There's a unit here
  449. local TargetWhite = self:SquareTeam(CapOne)=="White"
  450. if TargetWhite~=IsWhite then
  451. tbl[NumToLetter[NumToLetter[GridLet]-1]][TargetRow] = true
  452. end
  453. elseif (IsWhite and TargetRow==6) or ((not IsWhite) and TargetRow==3) then --Clear, EnPasse check
  454. local PassantCheck = IsWhite and self:GetBlackPassant() or self:GetWhitePassant()
  455. if (NumToLetter[GridLet]>1) and bit.band(PassantCheck, PassantFlags[ NumToLetter[GridLet]-1 ])==PassantFlags[NumToLetter[GridLet]-1] then
  456. tbl[NumToLetter[NumToLetter[GridLet]-1]][TargetRow] = "ENPASSANT"
  457. end
  458. end
  459.  
  460. local CapTwo = self:GetSquare( NumToLetter[NumToLetter[GridLet]+1], TargetRow, CheckTable )
  461. if CapTwo then
  462. local TargetWhite = self:SquareTeam(CapTwo)=="White"
  463. if TargetWhite~=IsWhite then
  464. tbl[NumToLetter[NumToLetter[GridLet]+1]][TargetRow] = true
  465. end
  466. elseif (IsWhite and TargetRow==6) or ((not IsWhite) and TargetRow==3) then --Clear, EnPasse check
  467. local PassantCheck = IsWhite and self:GetBlackPassant() or self:GetWhitePassant()
  468. if (NumToLetter[GridLet]<8) and bit.band(PassantCheck, PassantFlags[ NumToLetter[GridLet]+1 ])==PassantFlags[NumToLetter[GridLet]+1] then
  469. tbl[NumToLetter[NumToLetter[GridLet]+1]][TargetRow] = "ENPASSANT"
  470. end
  471. end
  472.  
  473. local FrontOne = self:GetSquare( GridLet, TargetRow, CheckTable )
  474. if (not FrontOne) then --It's clear, we can move
  475. tbl[GridLet][TargetRow] = true
  476. if not Moved then
  477. TargetRow = IsWhite and TargetRow+1 or TargetRow-1
  478. if (TargetRow>0 and TargetRow<9) and (not self:GetSquare( GridLet, TargetRow, CheckTable )) then tbl[GridLet][TargetRow] = "PAWNDOUBLE" end
  479. end
  480. end
  481. elseif class=="Rook" then
  482. self:GetRookMoves( tbl, GridLet, GridNum, IsWhite, 8, CheckTable )
  483. elseif class=="Bishop" then
  484. self:GetBishopMoves( tbl, GridLet, GridNum, IsWhite, 8, CheckTable )
  485. elseif class=="Queen" then
  486. self:GetRookMoves( tbl, GridLet, GridNum, IsWhite, 8, CheckTable )
  487. self:GetBishopMoves( tbl, GridLet, GridNum, IsWhite, 8, CheckTable )
  488. elseif class=="King" then
  489. self:GetRookMoves( tbl, GridLet, GridNum, IsWhite, 1, CheckTable )
  490. self:GetBishopMoves( tbl, GridLet, GridNum, IsWhite, 1, CheckTable )
  491.  
  492. ChecksPerformed = true --King performs it's own checks for Check
  493.  
  494. local InCheck = true
  495. if not IgnoreCheck then
  496. for CheckLet,File in pairs(tbl) do
  497. for CheckNum,v in pairs(File) do
  498. local Positions = table.Copy( self.Pieces )
  499. Positions[GridLet][GridNum] = nil
  500. Positions[CheckLet][CheckNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  501. if self:CheckForCheck( Positions, IsWhite ) then
  502. tbl[CheckLet][CheckNum] = nil --Puts us in check, remove it
  503. end
  504. end
  505. end
  506.  
  507. InCheck = self:CheckForCheck( self.Pieces, IsWhite )
  508. end
  509.  
  510. if (not Moved) and (not InCheck) then --Castling
  511. local Kingside = self:GetSquare( "h", GridNum, CheckTable )
  512. local Queenside = self:GetSquare( "a", GridNum, CheckTable )
  513. if Kingside and not self:SquareMoved(Kingside) then
  514. if not (self:GetSquare( "f", GridNum, CheckTable ) or self:GetSquare( "g", GridNum, CheckTable )) then
  515. local Positions = table.Copy( self.Pieces ) Positions[GridLet][GridNum] = nil Positions["f"][GridNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  516. local FSafe = not self:CheckForCheck( Positions, IsWhite )
  517. local Positions = table.Copy( self.Pieces ) Positions[GridLet][GridNum] = nil Positions["g"][GridNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  518. local GSafe = not self:CheckForCheck( Positions, IsWhite )
  519. if FSafe and GSafe then
  520. tbl["g"][GridNum] = "CASTLEKINGSIDE"
  521. end
  522. end
  523. end
  524. if Queenside and not self:SquareMoved(Queenside) then
  525. if not (self:GetSquare( "b", GridNum, CheckTable ) or self:GetSquare( "c", GridNum, CheckTable ) or self:GetSquare( "d", GridNum, CheckTable )) then
  526. local Positions = table.Copy( self.Pieces ) Positions[GridLet][GridNum] = nil Positions["c"][GridNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  527. local CSafe = not self:CheckForCheck( Positions, IsWhite )
  528. local Positions = table.Copy( self.Pieces ) Positions[GridLet][GridNum] = nil Positions["d"][GridNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  529. local DSafe = not self:CheckForCheck( Positions, IsWhite )
  530. if CSafe and DSafe then
  531. tbl["c"][GridNum] = "CASTLEQUEENSIDE"
  532. end
  533. end
  534. end
  535. end
  536. elseif class=="Knight" then
  537. local Up = NumToLetter[GridLet] + 2
  538. if Up and Up >=1 and Up<=8 then
  539. local Pos1 = self:GetSquare( NumToLetter[Up], GridNum-1, CheckTable )
  540. local Pos2 = self:GetSquare( NumToLetter[Up], GridNum+1, CheckTable )
  541. if (GridNum-1>=1) and ((not Pos1) or (self:SquareTeam(Pos1)==(IsWhite and "Black" or "White"))) then
  542. tbl[NumToLetter[Up]][GridNum-1] = true
  543. end
  544. if (GridNum+1<=8) and ((not Pos2) or (self:SquareTeam(Pos2)==(IsWhite and "Black" or "White"))) then
  545. tbl[NumToLetter[Up]][GridNum+1] = true
  546. end
  547. end
  548.  
  549. local Down = NumToLetter[GridLet] - 2
  550. if Down and Down>=1 and Down<=8 then
  551. local Pos1 = self:GetSquare( NumToLetter[Down], GridNum-1, CheckTable )
  552. local Pos2 = self:GetSquare( NumToLetter[Down], GridNum+1, CheckTable )
  553. if (GridNum-1>=1) and ((not Pos1) or (self:SquareTeam(Pos1)==(IsWhite and "Black" or "White"))) then
  554. tbl[NumToLetter[Down]][GridNum-1] = true
  555. end
  556. if (GridNum+1<=8) and ((not Pos2) or (self:SquareTeam(Pos2)==(IsWhite and "Black" or "White"))) then
  557. tbl[NumToLetter[Down]][GridNum+1] = true
  558. end
  559. end
  560.  
  561. local Let = NumToLetter[GridLet]
  562.  
  563. local Left = GridNum - 2
  564. if Left and Left>=1 and Left<=8 then
  565. local Pos1 = self:GetSquare( NumToLetter[Let-1], Left, CheckTable )
  566. local Pos2 = self:GetSquare( NumToLetter[Let+1], Left, CheckTable )
  567. if Let>1 and ((not Pos1) or (self:SquareTeam(Pos1)==(IsWhite and "Black" or "White"))) then
  568. tbl[NumToLetter[Let-1]][Left] = true
  569. end
  570. if Let<8 and ((not Pos2) or (self:SquareTeam(Pos2)==(IsWhite and "Black" or "White"))) then
  571. tbl[NumToLetter[Let+1]][Left] = true
  572. end
  573. end
  574.  
  575. local Right = GridNum + 2
  576. if Right and Right>=1 and Right<=8 then
  577. local Pos1 = self:GetSquare( NumToLetter[Let-1], Right, CheckTable )
  578. local Pos2 = self:GetSquare( NumToLetter[Let+1], Right, CheckTable )
  579. if Let>1 and ((not Pos1) or (self:SquareTeam(Pos1)==(IsWhite and "Black" or "White"))) then
  580. tbl[NumToLetter[Let-1]][Right] = true
  581. end
  582. if Let<8 and ((not Pos2) or (self:SquareTeam(Pos2)==(IsWhite and "Black" or "White"))) then
  583. tbl[NumToLetter[Let+1]][Right] = true
  584. end
  585. end
  586. end
  587.  
  588. if not IgnoreCheck then
  589. for CheckLet,File in pairs(tbl) do
  590. for CheckNum,v in pairs(File) do
  591. local Positions = table.Copy( self.Pieces )
  592. Positions[GridLet][GridNum] = nil
  593. Positions[CheckLet][CheckNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  594. if self:CheckForCheck( Positions, IsWhite ) then
  595. tbl[CheckLet][CheckNum] = nil --Puts us in check, remove it
  596. end
  597. end
  598. end
  599. end
  600.  
  601. return tbl
  602. end
  603.  
  604. function ENT:CastlingCheck( square, IsWhite )
  605. if not square then return false,false end
  606.  
  607. local GridNum = IsWhite and 1 or 8
  608. local moved = self:SquareMoved( square )
  609. local InCheck = self:CheckForCheck( self.Pieces, IsWhite )
  610. local Queenside, Kingside = false, false
  611. if (not Moved) and (not InCheck) then --Castling
  612. local Kingside = self:GetSquare( "h", GridNum, CheckTable )
  613. local Queenside = self:GetSquare( "a", GridNum, CheckTable )
  614. if Kingside and not self:SquareMoved(Kingside) then
  615. if not (self:GetSquare( "f", GridNum, CheckTable ) or self:GetSquare( "g", GridNum, CheckTable )) then
  616. local Positions = table.Copy( self.Pieces ) Positions["d"][GridNum] = nil Positions["f"][GridNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  617. local FSafe = not self:CheckForCheck( Positions, IsWhite )
  618. local Positions = table.Copy( self.Pieces ) Positions["d"][GridNum] = nil Positions["g"][GridNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  619. local GSafe = not self:CheckForCheck( Positions, IsWhite )
  620. if FSafe and GSafe then
  621. Kingside = true
  622. end
  623. end
  624. end
  625. if Queenside and not self:SquareMoved(Queenside) then
  626. if not (self:GetSquare( "b", GridNum, CheckTable ) or self:GetSquare( "c", GridNum, CheckTable ) or self:GetSquare( "d", GridNum, CheckTable )) then
  627. local Positions = table.Copy( self.Pieces ) Positions["d"][GridNum] = nil Positions["c"][GridNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  628. local CSafe = not self:CheckForCheck( Positions, IsWhite )
  629. local Positions = table.Copy( self.Pieces ) Positions["d"][GridNum] = nil Positions["d"][GridNum] = {Team = IsWhite and "White" or "Black", Class = class, Moved = true}
  630. local DSafe = not self:CheckForCheck( Positions, IsWhite )
  631. if CSafe and DSafe then
  632. Queenside = true
  633. end
  634. end
  635. end
  636. end
  637. return Queenside, Kingside
  638. end
  639.  
  640. function ENT:RefreshSquares()
  641. self.Squares = {}
  642.  
  643. local pos = self:LocalToWorld( self.TopLeft )
  644. local ang = self:GetUp():Angle()
  645.  
  646. for i=0,7 do
  647. self.Squares[i] = {}
  648. for n=0,7 do
  649. self.Squares[i][n] = Vector( pos[1]- ((self.RealH*(i))+(self.RealH/2)), pos[2]+ ((self.RealW*(n))+(self.RealW/2)), pos[3] )
  650. end
  651. end
  652. local HalfW, HalfH = (self.RealW/2), (self.RealH/2)
  653. self.Squares[CHESS_WCAP1] = {}
  654. self.Squares[CHESS_WCAP2] = {}
  655. self.Squares[CHESS_BCAP1] = {}
  656. self.Squares[CHESS_BCAP2] = {}
  657. for n=0,7 do
  658. self.Squares[CHESS_WCAP1][n] = Vector( pos[1]- ((self.RealH*(8.2))+(self.RealH/2)), pos[2]+ (self.RealW*(4))+ (HalfW*(n+1)), pos[3] )
  659. self.Squares[CHESS_WCAP2][n] = Vector( pos[1]- ((self.RealH*(9.2))+(self.RealH/2)), pos[2]+ (self.RealW*(4))+ (HalfW*(n+1)), pos[3] )
  660. end
  661. for n=0,7 do
  662. self.Squares[CHESS_BCAP1][n] = Vector( pos[1]- ((self.RealH*(-1.2))+(self.RealH/2)), pos[2]+ (self.RealW*(4))- (HalfW*(n+1)), pos[3] )
  663. self.Squares[CHESS_BCAP2][n] = Vector( pos[1]- ((self.RealH*(-2.2))+(self.RealH/2)), pos[2]+ (self.RealW*(4))- (HalfW*(n+1)), pos[3] )
  664. end
  665. end
  666. function ENT:GetSquarePos( GridLetter, GridNumber)
  667. return self:GetTableKey( self.Squares, GridLetter, GridNumber )
  668. end
  669. function ENT:ResetBoard()
  670. if SERVER then
  671. self.SurrenderOffer = nil
  672.  
  673. self:SetWhiteWager( -1 )
  674. self:SetBlackWager( -1 )
  675.  
  676. self:SetWhitePassant( 0 )
  677. self:SetBlackPassant( 0 )
  678.  
  679. self:SetWhiteTime( 600 )
  680. self:SetBlackTime( 600 )
  681.  
  682. self:SetMoveCount( 0 )
  683. self:SetRepetition( false )
  684. self.RepetitionTable = {}
  685. end
  686. self:RefreshSquares()
  687.  
  688. if self.Pieces then
  689. for _,File in pairs( self.Pieces ) do
  690. for _,Square in pairs(File) do
  691. if IsValid(Square.Ent) then Square.Ent:SetGridNum(-1) Square.Ent:Remove() end
  692. end
  693. end
  694. end
  695. self.Pieces = {
  696. ["a"] = {
  697. [1] = {Team="White",Class="Rook",Moved=false}, [2] = {Team="White",Class="Pawn",Moved=false}, [7] = {Team="Black",Class="Pawn",Moved=false}, [8] = {Team="Black",Class="Rook",Moved=false},
  698. },
  699. ["b"] = {
  700. [1] = {Team="White",Class="Knight",Moved=false}, [2] = {Team="White",Class="Pawn",Moved=false}, [7] = {Team="Black",Class="Pawn",Moved=false}, [8] = {Team="Black",Class="Knight",Moved=false},
  701. },
  702. ["c"] = {
  703. [1] = {Team="White",Class="Bishop",Moved=false}, [2] = {Team="White",Class="Pawn",Moved=false}, [7] = {Team="Black",Class="Pawn",Moved=false}, [8] = {Team="Black",Class="Bishop",Moved=false},
  704. },
  705. ["d"] = {
  706. [1] = {Team="White",Class="Queen",Moved=false}, [2] = {Team="White",Class="Pawn",Moved=false}, [7] = {Team="Black",Class="Pawn",Moved=false}, [8] = {Team="Black",Class="Queen",Moved=false},
  707. },
  708. ["e"] = {
  709. [1] = {Team="White",Class="King",Moved=false}, [2] = {Team="White",Class="Pawn",Moved=false}, [7] = {Team="Black",Class="Pawn",Moved=false}, [8] = {Team="Black",Class="King",Moved=false},
  710. },
  711. ["f"] = {
  712. [1] = {Team="White",Class="Bishop",Moved=false}, [2] = {Team="White",Class="Pawn",Moved=false}, [7] = {Team="Black",Class="Pawn",Moved=false}, [8] = {Team="Black",Class="Bishop",Moved=false},
  713. },
  714. ["g"] = {
  715. [1] = {Team="White",Class="Knight",Moved=false}, [2] = {Team="White",Class="Pawn",Moved=false}, [7] = {Team="Black",Class="Pawn",Moved=false}, [8] = {Team="Black",Class="Knight",Moved=false},
  716. },
  717. ["h"] = {
  718. [1] = {Team="White",Class="Rook",Moved=false}, [2] = {Team="White",Class="Pawn",Moved=false}, [7] = {Team="Black",Class="Pawn",Moved=false}, [8] = {Team="Black",Class="Rook",Moved=false},
  719. },
  720. [CHESS_WCAP1] = {}, [CHESS_WCAP2] = {}, [CHESS_BCAP1] = {}, [CHESS_BCAP2] = {},
  721. }
  722. self:Update()
  723. end
  724.  
  725. function ENT:Update( Move1, Move2 )
  726. if CLIENT then return end
  727. Move1,Move2 = Move1 or {},Move2 or {}
  728. net.Start( "Chess Update" )
  729. net.WriteEntity( self )
  730. net.WriteTable( self.Pieces )
  731. if Move1 then
  732. net.WriteTable( Move1 )
  733. if Move2 then net.WriteTable( Move2 ) end
  734. end
  735. net.Broadcast()
  736. end
  737.  
  738. ENT.LastTick = 0
  739. ENT.LastTickTeam = ""
  740. function ENT:Think()
  741. if SERVER then
  742. if self.Removing then return end
  743. if IsValid( self.TableEnt ) then
  744. self.TableEnt:SetHealth( 1000000 )
  745. self.TableEnt:SetVelocity( Vector(0,0,0) )
  746. --self.TableEnt:SetAngles( Angle(0,0,0) )
  747. --self.TableEnt:SetLocalAngularVelocity( Angle(0,0,0) )
  748. if self:GetPlaying() then
  749. local Ents = ents.FindInBox( self.TableEnt:LocalToWorld(self.TableEnt:OBBMins()), self.TableEnt:LocalToWorld(self.TableEnt:OBBMaxs() + (self.TableEnt:GetUp()*20)) )
  750. for _,v in pairs(Ents) do
  751. if v:GetClass():sub(1,5)=="prop_" and not v.IsChessEntity then
  752. v:Remove()
  753. elseif v:IsPlayer() and v:Alive() and not v:InVehicle() then
  754. v:SetVelocity( (v:GetPos() - self.TableEnt:GetPos())*Vector(20,20,0) )
  755. end
  756. end
  757. end
  758.  
  759. self:SetPos( self.TableEnt:GetPos() + self.BoardHeight )
  760. local a = self.TableEnt:GetAngles() a:RotateAroundAxis(self.TableEnt:GetRight(), 90)
  761. self:SetAngles( a )
  762. -- self:SetAngles( Angle(0,0,0) )
  763.  
  764. local phys = self:GetPhysicsObject()
  765. if IsValid(phys) then
  766. phys:EnableCollisions( false )
  767. phys:Sleep()
  768. end
  769. else self.Removing = true self:Remove() return end
  770. if not (IsValid(self.WhiteSeat) and IsValid(self.BlackSeat)) then self.Removing = true self:Remove() return end
  771. if self:GetChessState()~=CHESS_WAGER then
  772. self:SetWhiteWager( -1 )
  773. self:SetBlackWager( -1 )
  774. end
  775. if (not self.NextUnlock) or (CurTime()>self.NextUnlock) then
  776. self.WhiteSeat:Fire( "Unlock", 0, "" )
  777. self.BlackSeat:Fire( "Unlock", 0, "" )
  778. self.NextUnlock = CurTime()+10
  779. end
  780.  
  781. if self:GetChessState()==CHESS_WHITEMOVE or self:GetChessState()==CHESS_WHITEPROMO then
  782. if self.LastTickTeam=="White" then self:SetWhiteTime( math.max(0,self:GetWhiteTime()-(CurTime()-self.LastTick)) ) end
  783. self.LastTickTeam = "White"
  784.  
  785. if self:GetWhiteTime()<=0 then
  786. local WhitePly = self:GetPlayer( "White" )
  787. local BlackPly = self:GetPlayer( "Black" )
  788.  
  789. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  790. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  791.  
  792. self:EndGame( "Black" )
  793. net.Start( "Chess GameOver" )
  794. net.WriteTable( {Color(150,255,150), "Time's up! ", Color(100,100,100), BlackName, Color(150,255,150), self:GetElo(BlackPly), " won against ", Color(255,255,255), WhiteName, Color(150,255,150), self:GetElo(WhitePly),"."} )
  795. net.WriteString( "icon16/clock.png" )
  796. net.Broadcast()
  797. end
  798. elseif self:GetChessState()==CHESS_BLACKMOVE or self:GetChessState()==CHESS_BLACKPROMO then
  799. if self.LastTickTeam=="Black" then self:SetBlackTime( math.max(0,self:GetBlackTime()-(CurTime()-self.LastTick)) ) end
  800. self.LastTickTeam = "Black"
  801.  
  802. if self:GetBlackTime()<=0 then
  803. local WhitePly = self:GetPlayer( "White" )
  804. local BlackPly = self:GetPlayer( "Black" )
  805.  
  806. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  807. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  808.  
  809. self:EndGame( "White" )
  810. net.Start( "Chess GameOver" )
  811. net.WriteTable( {Color(150,255,150), "Time's up! ", Color(255,255,255), WhiteName, Color(150,255,150), self:GetElo(BlackPly), " won against ", Color(100,100,100), BlackName, Color(150,255,150), self:GetElo(WhitePly),"."} )
  812. net.WriteString( "icon16/clock.png" )
  813. net.Broadcast()
  814. end
  815. else
  816. self.LastTickTeam = ""
  817. end
  818. self.LastTick = CurTime()
  819. end
  820. if CLIENT then
  821. local tbl = self:GetTableEnt()
  822. if IsValid(tbl) then
  823. if tbl.ChessIsErrorModel or tbl:GetModel()=="models/error.mdl" then --Much cheaper than a file.Find
  824. tbl.ChessIsErrorModel = true
  825. self:SetParent( nil )
  826. tbl:SetNoDraw( true )
  827.  
  828. tbl.ClientChessTable = IsValid(tbl.ClientChessTable) and tbl.ClientChessTable or ClientsideModel( self.Models["hl2table"] )
  829. local ent = tbl.ClientChessTable
  830.  
  831. if not tbl.PerformedChessTableSetup then
  832. ent:SetPos( tbl:GetPos()+Vector(0,0,13) )
  833.  
  834. tbl:SetMoveType( MOVETYPE_NONE )
  835. tbl:PhysicsInit( SOLID_NONE )
  836. tbl:SetCollisionGroup( COLLISION_GROUP_WORLD )
  837.  
  838. ent:SetMoveType( MOVETYPE_NONE )
  839. ent:PhysicsInit( SOLID_VPHYSICS )
  840. ent:SetCollisionGroup( COLLISION_GROUP_WEAPON )
  841.  
  842. self:SetMoveType( MOVETYPE_NONE )
  843. self:PhysicsInit( SOLID_NONE )
  844. self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
  845.  
  846. tbl.PerformedChessTableSetup = true
  847. end
  848.  
  849. tbl:SetModel( self.Models["hl2table"] )
  850. tbl:SetPos( ent:GetPos() )
  851. tbl:SetNoDraw( true )
  852. self:SetPos( ent:GetPos()+Vector(0,0,17) )
  853. elseif IsValid( tbl.ClientChessTable ) then
  854. tbl.ClientChessTable:Remove()
  855. tbl.PerformedChessTableSetup = nil
  856. end
  857. end
  858. end
  859. end
  860.  
  861. function ENT:GetPlayer( team )
  862. if (team=="White" or team==true) then
  863. return (IsValid(self.WhiteSeat) and self.WhiteSeat:GetDriver())
  864. else
  865. return (IsValid(self.BlackSeat) and self.BlackSeat:GetDriver())
  866. end
  867. end
  868. function ENT:EndGame( winner, HideMsg )
  869. self:SetChessState( CHESS_INACTIVE )
  870. self:SetPlaying( false )
  871.  
  872. local White = self:GetPlayer( "White" )
  873. local Black = self:GetPlayer( "Black" )
  874. timer.Simple( 0.5, function()
  875. if not IsValid(self) then return end
  876. if IsValid(Black) and Black:GetVehicle()==self.BlackSeat then Black:ExitVehicle() end
  877. if IsValid(White) and White:GetVehicle()==self.WhiteSeat then White:ExitVehicle() end
  878. end)
  879.  
  880. local winnings = (self.WagerValue or 0)*2
  881. if IsValid( White ) then
  882. if winner=="White" then
  883. if IsValid(Black) then White:ChessWin( Black ) end
  884. if self.WagerValue then
  885. if self:GetPSWager() then
  886. White:PS_GivePoints( winnings )
  887. else
  888. if White.addMoney then White:addMoney( winnings ) else White:SetDarkRPVar( "money", (White:getDarkRPVar( "money" ) or 0) + winnings ) end
  889. end
  890. end
  891. elseif winner~="Black" then
  892. if winner~="Error" and IsValid(Black) then White:ChessDraw( Black ) end
  893. if self.WagerValue then
  894. if self:GetPSWager() then
  895. White:PS_GivePoints( winnings )
  896. else
  897. if White.addMoney then White:addMoney( winnings ) else White:SetDarkRPVar( "money", (White:getDarkRPVar( "money" ) or 0) + winnings ) end
  898. end
  899. end
  900. end
  901. end
  902. if IsValid( Black ) then
  903. if winner=="Black" then
  904. if IsValid(White) then Black:ChessWin( White ) end
  905. if self.WagerValue then
  906. if self:GetPSWager() then
  907. Black:PS_GivePoints( winnings )
  908. else
  909. if Black.addMoney then Black:addMoney( winnings ) else Black:SetDarkRPVar( "money", (Black:getDarkRPVar( "money" ) or 0) + winnings ) end
  910. end
  911. end
  912. elseif winner~="White" then
  913. if self.WagerValue then
  914. if self:GetPSWager() then
  915. White:PS_GivePoints( winnings )
  916. else
  917. if White.addMoney then White:addMoney( winnings ) else White:SetDarkRPVar( "money", (White:getDarkRPVar( "money" ) or 0) + winnings ) end
  918. end
  919. end
  920. end
  921. end
  922. end
  923. function ENT:DoCapture( square, EndLet, EndNum )
  924. if not square then return end
  925.  
  926. table.Empty( self.RepetitionTable ) --When it's gone, it's gone for good
  927. self:SetRepetition( false )
  928.  
  929. self:SetMoveCount( 0 )
  930.  
  931. local class = square.Class
  932.  
  933. local made = false
  934. local CapLet,CapNum
  935. if square.Team=="White" then --Black captured
  936. for i=CHESS_BCAP1,CHESS_BCAP2 do
  937. for n=1,8 do
  938. local CapSq = self:GetSquare( i, n )
  939. if not CapSq then
  940. self.Pieces[i][n] = {Team="White", Class=class, Moved=false}
  941. CapSq = self.Pieces[i][n]
  942.  
  943. made = true
  944. CapLet,CapNum = i,n
  945. break
  946. end
  947. end
  948. if made then break end
  949. end
  950. else
  951. for i=CHESS_WCAP1,CHESS_WCAP2 do
  952. for n=1,8 do
  953. local CapSq = self:GetSquare( i, n )
  954. if not CapSq then
  955. self.Pieces[i][n] = {Team="Black", Class=class, Moved=false}
  956. CapSq = self.Pieces[i][n]
  957.  
  958. made = true
  959. CapLet,CapNum = i,n
  960. break
  961. end
  962. end
  963. if made then break end
  964. end
  965. end
  966.  
  967. return {From={EndLet,EndNum}, To={CapLet,CapNum}}
  968. end
  969.  
  970. function ENT:CheckForCheck( tbl, CheckWhite )
  971. if not tbl then return true end --Assume invalid move
  972.  
  973. local king, KingLet, KingNum
  974. for GridLet,File in pairs(tbl) do
  975. for GridNum,square in pairs(File) do
  976. if square and self:SquareClass(square)=="King" and ((CheckWhite and self:SquareTeam(square)=="White") or ((not CheckWhite) and self:SquareTeam(square)=="Black")) then
  977. king = square
  978. KingLet = GridLet
  979. KingNum = GridNum
  980. break
  981. end
  982. end
  983. if king then break end
  984. end
  985. if not king then return true end --Assume invalid
  986.  
  987. for GridLet,File in pairs(tbl) do
  988. for GridNum,square in pairs(File) do
  989. if square and ((CheckWhite and self:SquareTeam(square)=="Black") or ((not CheckWhite) and self:SquareTeam(square)=="White")) then
  990. local Moves = self:GetMove( GridLet, GridNum, true, tbl )
  991. if Moves[KingLet] and Moves[KingLet][KingNum] then return true end --Something can take the king
  992. end
  993. end
  994. end
  995.  
  996. return false --King is safe
  997. end
  998. function ENT:IsCheckmate( CheckWhite )
  999. -- local IsCheck = self:CheckForCheck( self.Pieces, CheckWhite ) --We no longer check for check here, this is also a stalemate check
  1000. -- if not IsCheck then return false end
  1001.  
  1002. for GridLet,File in pairs(self.Pieces) do
  1003. for GridNum,square in pairs(File) do
  1004. if square and ((CheckWhite and self:SquareTeam(square)=="White") or ((not CheckWhite) and self:SquareTeam(square)=="Black")) then
  1005. local Moves = self:GetMove( GridLet, GridNum, false, tbl )
  1006. for MoveLet,File in pairs(Moves) do
  1007. if table.Count(File)>0 then return false end --There's a valid move, it's fine
  1008. end
  1009. end
  1010. end
  1011. end
  1012.  
  1013. return true
  1014. end
  1015. function ENT:NoMaterialCheck()
  1016. local BlackMat = {}
  1017. local WhiteMat = {}
  1018.  
  1019. for GridLet,File in pairs(self.Pieces) do
  1020. if GridLet==CHESS_WCAP1 or GridLet==CHESS_WCAP2 or GridLet==CHESS_BCAP1 or GridLet==CHESS_BCAP2 then continue end
  1021. for GridNum,square in pairs(File) do
  1022. if square then
  1023. local IsWhite = self:SquareTeam(square)=="White"
  1024. local Class = self:SquareClass(square)
  1025. if Class=="Queen" or Class=="Rook" or Class=="Pawn" then return false end --Always sufficient material
  1026. if Class=="King" then continue end --Don't count king
  1027.  
  1028. if IsWhite then
  1029. table.insert( WhiteMat, {Square=square, Class=Class, GridLet=GridLet, GridNum=GridNum} )
  1030. else
  1031. table.insert( BlackMat, {square=square, Class=Class, GridLet=GridLet, GridNum=GridNum} )
  1032. end
  1033. end
  1034. end
  1035. end
  1036.  
  1037. if #BlackMat==0 and #WhiteMat==0 then return true end --Kings only, draw
  1038. if #BlackMat==1 and #WhiteMat==0 and (BlackMat[1].Class=="Bishop" or BlackMat[1].Class=="Knight") then return true end --King versus King+Bishop/Knight
  1039. if #BlackMat==0 and #WhiteMat==1 and (WhiteMat[1].Class=="Bishop" or WhiteMat[1].Class=="Knight") then return true end --King versus King+Bishop/Knight
  1040.  
  1041. local BishopCol
  1042. for i=1,#BlackMat do
  1043. if BlackMat[i].Class~="Bishop" then return false end --Has non-bishops, it's fine
  1044. if not BishopCol then BishopCol = self:SquareColor(BlackMat[i].GridLet,BlackMat[i].GridNum) end
  1045. if BishopCol~=self:SquareColor(BlackMat[i].GridLet,BlackMat[i].GridNum) then return false end --Bishops are on different colours, it's fine
  1046. end
  1047. for i=1,#WhiteMat do
  1048. if WhiteMat[i].Class~="Bishop" then return false end
  1049. if not BishopCol then BishopCol = self:SquareColor(WhiteMat[i].GridLet,WhiteMat[i].GridNum) end
  1050. if BishopCol~=self:SquareColor(WhiteMat[i].GridLet,WhiteMat[i].GridNum) then return false end --Even if it's the enemy on a different colour, checkmate is possible
  1051. end
  1052.  
  1053. return true
  1054. end
  1055.  
  1056. function table.EqualsTable( CheckTable, MatchTable, depth )
  1057. if not (CheckTable and MatchTable) then return false end
  1058. depth = depth or 1
  1059. if depth>=15 then error("Unable to match tables: Tables too deep!") end
  1060.  
  1061. if table.Count( CheckTable ) ~= table.Count( MatchTable ) then return false end
  1062. for k,v in pairs( CheckTable ) do
  1063. if type(v)=="table" then
  1064. if type(MatchTable[k])~="table" then return false end
  1065. if not table.EqualsTable( v, MatchTable[k], depth+1 ) then return false end
  1066. elseif type(v)=="Entity" then
  1067. else
  1068. if MatchTable[k]~=v then return false end
  1069. end
  1070. end
  1071. return true
  1072. end
  1073. function ENT:DoRepetition()
  1074. local Pieces = self.Pieces
  1075. local WKing = self:GetSquare( "d", 1 )
  1076. local BKing = self:GetSquare( "d", 8 )
  1077. local WCQ, WCK = self:CastlingCheck( WKing, true ) --WhiteCastleQueenside, Kingside
  1078. local BCQ, BCK = self:CastlingCheck( BKing, false ) --BlackCastleQueenside, Kingside
  1079. for _,Saved in pairs( self.RepetitionTable ) do
  1080. if table.EqualsTable( Saved.Pieces, Pieces ) and Saved.WCQ==WCQ and Saved.WCK==WCK and Saved.BCQ==BCQ and Saved.BCK==BCK then
  1081. Saved.Count = Saved.Count+1
  1082. if Saved.Count>=3 then self:SetRepetition( true ) end
  1083. return
  1084. end
  1085. end
  1086. self:SetRepetition( false )
  1087. --No match
  1088. table.insert( self.RepetitionTable, {
  1089. WCQ = WCQ, WCK = WCK, BCQ = BCQ, BCK = BCK,
  1090. Pieces = table.Copy( Pieces ), Count = 1
  1091. })
  1092. end
  1093.  
  1094. function ENT:DoMove( StartLet, StartNum, EndLet, EndNum )
  1095. if CLIENT then return end
  1096. if not (StartLet and EndLet and StartNum and EndNum) then return end
  1097. if (StartLet==EndLet) and (StartNum==EndNum) then return end
  1098.  
  1099. local Start = self:GetSquare( StartLet, StartNum )
  1100. if not Start then return end
  1101.  
  1102. local Moves = self:GetMove( StartLet, StartNum )
  1103. if not Moves[EndLet][EndNum] then return end
  1104. local Move = Moves[EndLet][EndNum]
  1105.  
  1106. self:SetWhitePassant( 0 ) --Reset after the move verified
  1107. self:SetBlackPassant( 0 )
  1108. self:SetRepetition( false )
  1109.  
  1110. self:SetMoveCount( ((Start.Class=="Pawn") and 0) or self:GetMoveCount()+1 )
  1111. local IgnoreRepetition
  1112.  
  1113. local CapMove
  1114. if Move=="PAWNDOUBLE" then
  1115. if Start.Team=="White" then
  1116. self:SetWhitePassant( PassantFlags[NumToLetter[StartLet]] )
  1117. else
  1118. self:SetBlackPassant( PassantFlags[NumToLetter[StartLet]] )
  1119. end
  1120. elseif Move=="ENPASSANT" then
  1121. local Take = self:GetSquare( EndLet, StartNum )
  1122. if Take and Take.Class then
  1123. CapMove = self:DoCapture( Take, EndLet, StartNum )
  1124. end
  1125. self.Pieces[EndLet][StartNum] = nil
  1126. IgnoreRepetition = true --Passant state is counted, and is never the same
  1127. elseif Move=="CASTLEKINGSIDE" then
  1128. CapMove = self:DoMove( "h", StartNum, "f", StartNum )
  1129. elseif Move=="CASTLEQUEENSIDE" then
  1130. CapMove = self:DoMove( "a", StartNum, "d", StartNum )
  1131. end
  1132.  
  1133. local End = self:GetSquare( EndLet, EndNum )
  1134. if not End then
  1135. self.Pieces[EndLet] = self.Pieces[EndLet] or {}
  1136. self.Pieces[EndLet][EndNum] = self.Pieces[EndLet][EndNum] or {}
  1137. End = self.Pieces[EndLet][EndNum]
  1138. end
  1139. if End.Class then
  1140. CapMove = self:DoCapture( End, EndLet, EndNum )
  1141. end
  1142.  
  1143. End.Team=Start.Team
  1144. End.Class=Start.Class
  1145. End.Moved=true
  1146.  
  1147. self.Pieces[StartLet][StartNum] = nil
  1148.  
  1149. local ply = self:GetPlayer( End.Team )
  1150. if (EndNum==1 or EndNum==8) and End.Class=="Pawn" and IsValid(ply) then --End of the board
  1151. net.Start( "Chess PromotionSelection" )
  1152. net.WriteInt( NumToLetter[EndLet], 5 )
  1153. net.Send( ply )
  1154. self:SetChessState( End.Team=="White" and CHESS_WHITEPROMO or CHESS_BLACKPROMO )
  1155. else
  1156. self:SetChessState( End.Team=="White" and CHESS_BLACKMOVE or CHESS_WHITEMOVE )
  1157. end
  1158.  
  1159. local move = {From={StartLet,StartNum},To={EndLet,EndNum}}
  1160. self:Update( move, CapMove )
  1161.  
  1162. local IsCheck = self:CheckForCheck( self.Pieces, End.Team~="White" )
  1163. local Checkmate = self:IsCheckmate( End.Team~="White" )
  1164. if IsCheck and Checkmate then
  1165. local WhitePly = self:GetPlayer( "White" )
  1166. local BlackPly = self:GetPlayer( "Black" )
  1167.  
  1168. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  1169. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  1170. self:EndGame( End.Team )
  1171. net.Start( "Chess GameOver" )
  1172. if End.Team=="White" then
  1173. net.WriteTable( {Color(255,255,255), WhiteName, Color(150,255,150), self:GetElo(WhitePly), " has checkmated ", Color(100,100,100), BlackName, Color(150,255,150), self:GetElo(BlackPly),"!"} )
  1174. else
  1175. net.WriteTable( {Color(100,100,100), BlackName, Color(150,255,150), self:GetElo(BlackPly), " has checkmated ", Color(255,255,255), WhiteName, Color(150,255,150), self:GetElo(WhitePly),"!"} )
  1176. end
  1177. net.WriteString( "icon16/medal_gold_2.png" )
  1178. net.Broadcast()
  1179.  
  1180. return
  1181. elseif Checkmate then
  1182. local WhitePly = self:GetPlayer( "White" )
  1183. local BlackPly = self:GetPlayer( "Black" )
  1184.  
  1185. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  1186. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  1187. self:EndGame()
  1188. net.Start( "Chess GameOver" )
  1189. net.WriteTable( {Color(150,255,150), "Stalemate! ", Color(255,255,255), WhiteName, Color(150,255,150), self:GetElo(WhitePly), " drew with ", Color(100,100,100), BlackName, Color(150,255,150), self:GetElo(BlackPly),"!"} )
  1190. net.WriteString( "icon16/medal_silver_1.png" )
  1191. net.Broadcast()
  1192.  
  1193. return
  1194. end
  1195.  
  1196. local NoMaterial = self:NoMaterialCheck()
  1197. if NoMaterial then
  1198. local WhitePly = self:GetPlayer( "White" )
  1199. local BlackPly = self:GetPlayer( "Black" )
  1200.  
  1201. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  1202. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  1203. self:EndGame()
  1204. net.Start( "Chess GameOver" )
  1205. net.WriteTable( {Color(150,255,150), "Insufficient material! ", Color(255,255,255), WhiteName, Color(150,255,150), " drew with ", Color(100,100,100), BlackName, Color(150,255,150),"!"} )
  1206. net.WriteString( "icon16/medal_silver_1.png" )
  1207. net.Broadcast()
  1208.  
  1209. return
  1210. end
  1211.  
  1212. if IgnoreRepetition then
  1213. self:SetRepetition( false )
  1214. else
  1215. self:DoRepetition()
  1216. end
  1217. return move
  1218. end
  1219. function ENT:GetElo( ply )
  1220. return IsValid(ply) and " ("..ply:GetChessElo()..")" or ""
  1221. end
  1222. function ENT:GameName()
  1223. return self.Game or "a board game"
  1224. end
  1225.  
  1226. if CLIENT then
  1227. local ChessPanel, WagerPanel
  1228. function ENT:Refresh()
  1229. for GridLet,column in pairs( self.Pieces ) do
  1230. for GridNum,square in pairs( column ) do
  1231. if (not IsValid( square.Ent )) or (NumToLetter[square.Ent:GetGridLet()]~=GridLet) or (square.Ent:GetGridNum()~=GridNum) then
  1232. column[GridNum] = nil
  1233. end
  1234. end
  1235. end
  1236. end
  1237.  
  1238. function ENT:RequestMove( StartLet, StartNum, EndLet, EndNum)
  1239. if not (StartLet and StartNum and EndLet and EndNum) then return end
  1240.  
  1241. net.Start( "Chess ClientRequestMove" )
  1242. net.WriteInt( StartLet+1, 5 )
  1243. net.WriteInt( 8-StartNum, 5 )
  1244. net.WriteInt( EndLet+1, 5 )
  1245. net.WriteInt( 8-EndNum, 5 )
  1246. net.SendToServer()
  1247. end
  1248.  
  1249. local PanelCol = {
  1250. Main = Color(0,0,0,200), ToMove = Color(200,200,200,20), Text = Color(180,180,180),
  1251. White = Color(255,255,255), Black = Color(20,20,20,255),
  1252. }
  1253. surface.CreateFont( "ChessTextSmall", { font = "Arial", size = 16, weight = 600})
  1254. surface.CreateFont( "ChessText", { font = "Arial", size = 24, weight = 600})
  1255. surface.CreateFont( "ChessTextLarge", { font = "Arial", size = 32, weight = 600})
  1256. function ENT:CreateChessPanel()
  1257. local frame = vgui.Create( "DFrame" )
  1258. frame:SetSize(400,135)
  1259. frame:SetPos( (ScrW()/2)-150, ScrH()-150 )
  1260. --frame:SetDraggable( false )
  1261. frame:SetTitle( "" )
  1262. frame:ShowCloseButton( false )
  1263. frame:SetDeleteOnClose( true )
  1264. frame.Paint = function( s,w,h )
  1265. if not IsValid(self) then
  1266. s:Remove()
  1267. gui.EnableScreenClicker( false )
  1268.  
  1269. return
  1270. end
  1271.  
  1272. draw.RoundedBox( 8, 0, 0, w, h, PanelCol.Main )
  1273. end
  1274. frame:DockMargin( 0,0,0,0 )
  1275. frame:DockPadding( 5,6,5,5 )
  1276.  
  1277. local TimePnl = vgui.Create( "DPanel", frame )
  1278. TimePnl:Dock( RIGHT )
  1279. TimePnl:SetWide( 100 )
  1280. TimePnl:DockMargin( 2,2,2,2 )
  1281. TimePnl.Paint = function(s,w,h)
  1282. if not IsValid(self) then return end
  1283.  
  1284. draw.RoundedBox( 16, 0, 0, w, (h/2)-1, PanelCol.ToMove )
  1285. draw.RoundedBox( 16, 0, (h/2)+1, w, (h/2)-1, PanelCol.ToMove )
  1286.  
  1287. 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 )
  1288. 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 )
  1289. end
  1290.  
  1291. local ButtonPanel = vgui.Create( "DPanel", frame )
  1292. ButtonPanel:SetSize( 100, 20 )
  1293. ButtonPanel:Dock( LEFT )
  1294. ButtonPanel.Paint = function() end
  1295.  
  1296. local ToMove = vgui.Create( "DPanel", frame )
  1297. ToMove:SetSize(200,125)
  1298. ToMove:Dock( TOP )
  1299. ToMove.Paint = function( s,w,h )
  1300. draw.RoundedBox( 4, 0, 0, w, h, PanelCol.ToMove )
  1301. draw.SimpleText( "To move", "ChessTextSmall", 5, 0, PanelCol.Text )
  1302. local state = IsValid(self) and self:GetChessState()
  1303. if not (IsValid( self ) and state) then
  1304. draw.SimpleText( "[N/A]", "ChessTextSmall", w/2, h/2, PanelCol.Text, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
  1305. else
  1306. local str = (state==CHESS_WAGER and "Wagers") or (state==CHESS_INACTIVE and "Waiting") or ((state==CHESS_WHITEMOVE or state==CHESS_WHITEPROMO) and "White") or ((state==CHESS_BLACKMOVE or state==CHESS_BLACKPROMO) and "Black") or "N/A"
  1307. local col = (str=="White" and PanelCol.White) or (str=="Black" and PanelCol.Black) or PanelCol.Text
  1308. draw.SimpleText( str, "ChessTextLarge", w/2, h/2, col, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
  1309. end
  1310. end
  1311.  
  1312.  
  1313. frame.OfferDraw = vgui.Create( "DButton", ButtonPanel)
  1314. frame.OfferDraw:SetSize(94,25)
  1315. frame.OfferDraw:Dock( TOP )
  1316. frame.OfferDraw:SetText( "Offer Draw" )
  1317. frame.OfferDraw.DoClick = function( s )
  1318. if (IsValid(self)) and not (self:GetPlaying()) then
  1319. chat.AddText( Color(150,255,150), "You can't offer a draw before the game starts!" )
  1320. return
  1321. end
  1322. net.Start( "Chess DrawOffer" ) net.SendToServer()
  1323. s:SetText( "Draw offered" )
  1324. end
  1325.  
  1326. local Resign = vgui.Create( "DButton", ButtonPanel)
  1327. Resign:SetSize(94,25)
  1328. Resign:Dock( TOP )
  1329. Resign:SetText( "Resign" )
  1330. Resign.DoClick = function( s )
  1331. net.Start( "Chess ClientResign" ) net.SendToServer() --No client-side exit func :/
  1332. end
  1333.  
  1334.  
  1335. local MoveLimit = vgui.Create( "DButton", ButtonPanel)
  1336. MoveLimit:SetSize(94,25)
  1337. MoveLimit:Dock( TOP )
  1338. --MoveLimit:Dock( FILL )
  1339. MoveLimit:SetText( "Call 50 moves" )
  1340. MoveLimit.DoClick = function( s )
  1341. print("!!")
  1342. net.Start( "Chess ClientCallDraw" )
  1343. net.WriteUInt( CHESS_DRAW_50, 2 )
  1344. net.SendToServer()
  1345. end
  1346. MoveLimit:SetEnabled( false )
  1347. MoveLimit.Think = function( s )
  1348. MoveLimit:SetEnabled( IsValid(self) and self:GetMoveCount()>=50 )
  1349. end
  1350.  
  1351. local Repetition = vgui.Create( "DButton", ButtonPanel)
  1352. Repetition:SetSize(94,25)
  1353. Repetition:Dock( TOP )
  1354. Repetition:SetText( "Call Repetition" )
  1355. Repetition.DoClick = function( s )
  1356. net.Start( "Chess ClientCallDraw" )
  1357. net.WriteUInt( CHESS_DRAW_3, 2 )
  1358. net.SendToServer()
  1359. end
  1360. Repetition:SetEnabled( false )
  1361. Repetition.Think = function( s )
  1362. Repetition:SetEnabled( IsValid(self) and self:GetRepetition() )
  1363. end
  1364.  
  1365. local DermaMode = vgui.Create( "DButton", ButtonPanel)
  1366. DermaMode:SetSize(94,25)
  1367. DermaMode:Dock( TOP )
  1368. DermaMode:SetText( "Toggle 2D Mode" )
  1369. DermaMode.DoClick = function( s )
  1370. if IsValid(Chess_2DDermaPanel) then
  1371. Chess_2DDermaPanel:Remove()
  1372. else
  1373. Chess_Open2DBoard( self )
  1374. end
  1375. end
  1376.  
  1377. return frame
  1378. end
  1379. local function CreateWagerPanel( board )
  1380. local frame = vgui.Create( "DFrame" )
  1381. frame:SetSize(200,70)
  1382. frame:SetPos( (ScrW()/2)-100, (ScrH()/2)-75 )
  1383. --frame:SetDraggable( false )
  1384. frame:SetTitle( "" )
  1385. frame:ShowCloseButton( false )
  1386. frame:SetDeleteOnClose( true )
  1387. frame.Paint = function( s,w,h )
  1388. draw.RoundedBox( 8, 0, 0, w, h, PanelCol.Main )
  1389. end
  1390. frame.Think = function( s )
  1391. if board:GetChessState()~=CHESS_WAGER then
  1392. s:Remove()
  1393. end
  1394. end
  1395. frame:DockMargin( 0,0,0,0 )
  1396. frame:DockPadding( 5,6,5,5 )
  1397.  
  1398. local SliderPanel = vgui.Create( "DPanel", frame )
  1399. SliderPanel:SetSize(200,20)
  1400. SliderPanel:Dock( TOP )
  1401. SliderPanel:DockPadding( 2,2,2,2 )
  1402. SliderPanel.Paint = function( s,w,h )
  1403. draw.RoundedBox( 4, 0, 0, w, h, PanelCol.ToMove )
  1404. end
  1405.  
  1406. local WagerNum = vgui.Create( "DNumSlider", SliderPanel )
  1407. WagerNum:SetSize(200,20)
  1408. WagerNum:Dock( FILL )
  1409. WagerNum:SetText( "Wager" )
  1410. WagerNum.Label:SizeToContents()
  1411. WagerNum:SetMinMax( 0, math.Clamp(
  1412. ((board:GetPSWager() and LocalPlayer():PS_GetPoints()) or ((not board:GetPSWager()) and LocalPlayer():getDarkRPVar( "money" ))) or 0,
  1413. 0, 16777215) )
  1414. WagerNum:SetDark( true )
  1415. WagerNum:SetDecimals( 0 )
  1416. WagerNum:SetValue( 0 )
  1417. --WagerNum.Slider:SetLockY( 10 )
  1418. WagerNum:SizeToContents()
  1419.  
  1420. local ButtonPanel = vgui.Create( "DPanel", frame )
  1421. ButtonPanel:SetSize(200, 30)
  1422. ButtonPanel:Dock( BOTTOM )
  1423. ButtonPanel.Paint = function() end
  1424.  
  1425. local AcceptButton = vgui.Create( "DButton", ButtonPanel )
  1426. AcceptButton:SetWide( 61 )
  1427. AcceptButton:SetText( "Accept" )
  1428. AcceptButton:SetEnabled( false )
  1429. AcceptButton:Dock( LEFT )
  1430. AcceptButton.WagerVal = -1
  1431. AcceptButton.Think = function( s )
  1432. if LocalPlayer()==board:GetWhitePlayer() then
  1433. if board:GetBlackWager() and board:GetBlackWager()>=0 then
  1434. s:SetEnabled( true )
  1435. s:SetText( tostring(board:GetBlackWager()) )
  1436. s.WagerVal = board:GetBlackWager()
  1437. end
  1438. elseif LocalPlayer()==board:GetBlackPlayer() then
  1439. if board:GetWhiteWager() and board:GetWhiteWager()>=0 then
  1440. s:SetEnabled( true )
  1441. s:SetText( tostring(board:GetWhiteWager()) )
  1442. s.WagerVal = board:GetWhiteWager()
  1443. end
  1444. end
  1445. end
  1446. AcceptButton.DoClick = function()
  1447. net.Start( "Chess ClientWager" )
  1448. net.WriteUInt( math.Clamp(AcceptButton.WagerVal, 0, 16777215), 24 )
  1449. net.SendToServer()
  1450. end
  1451.  
  1452. local ExitButton = vgui.Create( "DButton", ButtonPanel )
  1453. ExitButton:SetWide( 61 )
  1454. ExitButton:SetText( "Exit" )
  1455. ExitButton:Dock( RIGHT )
  1456. ExitButton.DoClick = function( s )
  1457. net.Start( "Chess ClientResign" ) net.SendToServer() --No client-side exit func
  1458. end
  1459.  
  1460. local WagerButton = vgui.Create( "DButton", ButtonPanel )
  1461. WagerButton:SetText( "Wager" )
  1462. WagerButton:Dock( FILL )
  1463. WagerButton:DockMargin(5,0,5,0)
  1464. WagerButton.DoClick = function( s )
  1465. net.Start( "Chess ClientWager" )
  1466. net.WriteUInt( WagerNum:GetValue() or 0, 24 )
  1467. net.SendToServer()
  1468. end
  1469. frame:MakePopup()
  1470.  
  1471. return frame
  1472. end
  1473.  
  1474. local IsInChess, ScreenPos, ScreenAng, ActiveBoard
  1475. local function ChessSeatCam( ply, pos, ang, fov, nearz, farz )
  1476. local seat = ply:GetVehicle()
  1477. if (IsValid(seat) and seat:GetNWBool("IsChessSeat",false)) or ply:GetNWBool( "IsInChess", false ) then
  1478. ActiveBoard = IsValid(seat) and seat:GetNWEntity( "ChessBoard" )
  1479. if not IsValid(ActiveBoard) then
  1480. ActiveBoard = ply:GetNWEntity( "ActiveChessBoard" )
  1481. if not IsValid(ActiveBoard) then return end
  1482. end
  1483.  
  1484. if not IsValid(ChessPanel) then
  1485. ChessPanel = IsValid(ActiveBoard.ChessPanel) and ActiveBoard.ChessPanel or ActiveBoard:CreateChessPanel() --Autorefresh fix
  1486. ActiveBoard.ChessPanel = ChessPanel
  1487. end
  1488. if ActiveBoard:GetChessState()==CHESS_WAGER then
  1489. if not IsValid(WagerPanel) then
  1490. WagerPanel = IsValid(ActiveBoard.WagerPanel) and ActiveBoard.WagerPanel or CreateWagerPanel( ActiveBoard ) --Autorefresh fix
  1491. ActiveBoard.WagerPanel = WagerPanel
  1492. end
  1493. elseif IsValid( WagerPanel ) then
  1494. WagerPanel:Remove()
  1495. end
  1496.  
  1497. local ViewPos = ActiveBoard:GetPos()+Vector(0,0,30) + (IsValid(seat) and seat:GetRight()*15 or ply:GetForward()*-15) --pos+Vector(0,0,20)+ (IsValid(seat) and seat:GetRight()*-15 or ply:GetForward()*15)
  1498. local ViewAng = (ActiveBoard:GetPos()-ViewPos):Angle()
  1499. if input.IsKeyDown( KEY_LALT ) then
  1500. ViewAng = ang
  1501. gui.EnableScreenClicker(false)
  1502. else
  1503. gui.EnableScreenClicker(true)
  1504. if IsValid( ActiveBoard:GetTableEnt() ) and ActiveBoard:GetTableEnt():GetModel()==ActiveBoard.Models["hl2table"] then
  1505. local tbl = ActiveBoard:GetTableEnt()
  1506. local height = tbl:OBBMaxs()[3]-tbl:OBBMins()[3]
  1507. ViewAng = ((tbl:GetPos()+Vector(0,0,height-10))-ViewPos):Angle()
  1508. end
  1509. end
  1510. local view = {
  1511. origin = ViewPos,
  1512. angles = ViewAng,
  1513. fov = fov,
  1514. znear = nearz,
  1515. zfar = farz,
  1516. drawviewer = true,
  1517. }
  1518.  
  1519. IsInChess = true
  1520. ScreenPos = ViewPos
  1521. ScreenAng = ViewAng
  1522.  
  1523. return view
  1524. elseif IsInChess then --Exit
  1525. gui.EnableScreenClicker(false)
  1526.  
  1527. IsInChess = false
  1528. ScreenPos = nil
  1529. ScreenAng = nil
  1530. ActiveBoard = nil
  1531. else --Not in seat, and not just exited. Don't disable mouse here
  1532. if IsValid( ChessPanel ) then ChessPanel:Remove() end
  1533. if IsValid( WagerPanel ) then WagerPanel:Remove() end
  1534. IsInChess = false
  1535. ScreenPos = nil
  1536. ScreenAng = nil
  1537. ActiveBoard = nil
  1538. end
  1539. end
  1540. hook.Add( "CalcView", "ChessBoardSeatCam", ChessSeatCam ) --CalcVehicleView doesn't work
  1541.  
  1542. function ENT:ResetHighlights()
  1543. self.Highlight = {-1,-1}
  1544. self.Selected = {-1,-1}
  1545. self.Moves = {}
  1546. end
  1547.  
  1548. function ENT:GetTraceFilter()
  1549. local tbl = {self}
  1550.  
  1551. for GridLet,column in pairs( self.Pieces ) do
  1552. for GridNum,square in pairs( column ) do
  1553. if (IsValid( square.Ent )) then table.insert( tbl, square.Ent ) end
  1554. end
  1555. end
  1556.  
  1557. return tbl
  1558. end
  1559.  
  1560. local ColHover,ColText,ColSel = Color(0,255,0,50),Color(50,50,50,200),Color(150,50,50,150)
  1561. local ColBlack,ColWhite,ColMove = Color(0,0,0,120),Color(255,255,255,10),Color(50,50,150,150)
  1562. function ENT:Draw()
  1563. if self.IsInCheck then
  1564. if not self.PlayedCheckSound then
  1565. sound.Play( self.CheckSound, self:GetPos() )
  1566. self.PlayedCheckSound = true
  1567. end
  1568. else
  1569. self.PlayedCheckSound = nil
  1570. end
  1571.  
  1572. if IsValid(Chess_2DDermaPanel) then return end
  1573. if (self.LastReScaleTime or 0)+10<CurTime() then self:EnableMatrix("RenderMultiply", ChessScale) self.LastReScaleTime=CurTime() end
  1574.  
  1575. if not self.PiecesEnts then
  1576. self.PiecesEnts = {}
  1577. for i=1,16 do
  1578. self.PiecesEnts[i] = ClientsideModel( self.Models["WhitePawn"] )
  1579. self.PiecesEnts[i]:SetNoDraw( true )
  1580. self.PiecesEnts[i]:EnableMatrix( "RenderMultiply", ChessScale )
  1581. end
  1582. end
  1583.  
  1584. if FrameTime()>=0.33 and not self.SpectatingTable then --Less than 30 fps
  1585. if self.FPSFailTimeout and self.FPSFailTimeout<CurTime() then
  1586. self.FPSFailCount = 0
  1587. end
  1588.  
  1589. if (not self.FPSNextCheck) or self.FPSNextCheck<=CurTime() then
  1590. self.FPSNextCheck = CurTime()+0.1
  1591. self.FPSFailTimeout = CurTime()+2
  1592. self.FPSFailCount = (self.FPSFailCount or 0)+1
  1593. if self.FPSFailCount>=30 then
  1594. self.LowFPSCheck = CurTime()+5
  1595. end
  1596. end
  1597. end
  1598. local InChessGame = (IsValid(LocalPlayer():GetVehicle()) or LocalPlayer():GetNWBool("IsInChess",false))
  1599.  
  1600. if InChessGame or self.SpectatingTable or (not (self.LowFPSCheck and self.LowFPSCheck>CurTime())) then
  1601. local i=0
  1602. for let,column in pairs( self.Pieces ) do
  1603. for num,square in pairs( column ) do
  1604. if not (square.Team and square.Class) then continue end
  1605. i=(i or 0)+1
  1606. local pos = self:GetSquarePos( let, num )
  1607.  
  1608. if square.Moving and square.MoveStart then
  1609. local delta = math.Clamp( (RealTime()-square.MoveStart)/self.MoveTime, 0,1 )
  1610. if delta==1 or (not delta) then
  1611. square.Moving = false
  1612. sound.Play( self.MoveSound, pos )
  1613. else
  1614. local Height = (delta*6)>=3 and (6-(delta*6)) or (delta*6)
  1615. pos = Vector(
  1616. square.MoveFrom[1] + (pos[1]-square.MoveFrom[1])*delta,
  1617. square.MoveFrom[2] + (pos[2]-square.MoveFrom[2])*delta,
  1618. pos[3] + Height
  1619. )
  1620. end
  1621. end
  1622.  
  1623. if not IsValid( self.PiecesEnts[i] ) then
  1624. self.PiecesEnts[i] = ClientsideModel( self.Models["WhitePawn"] )
  1625. self.PiecesEnts[i]:SetNoDraw( true )
  1626. self.PiecesEnts[i]:EnableMatrix( "RenderMultiply", ChessScale )
  1627. end
  1628. if self.PiecesEnts[i]:GetPos()~=pos then self.PiecesEnts[i]:SetPos( pos ) end
  1629. if self.PiecesEnts[i]:GetModel()~=self.Models[ square.Team .. square.Class ] then
  1630. self.PiecesEnts[i]:SetModel( self.Models[ square.Team .. square.Class ] )
  1631. end
  1632. self.PiecesEnts[i]:DrawModel()
  1633. if self.DrawDouble and self.DrawDouble[ square.Class ] then
  1634. self.PiecesEnts[i]:SetModel( self.Models[ "dama" ] ) --Prevents invisible pieces
  1635. self.PiecesEnts[i]:SetModel( self.Models[ square.Team .. square.Class ] )
  1636. self.PiecesEnts[i]:SetPos( pos + Vector(0,0,(self.PiecesEnts[i]:OBBMaxs()[3]-self.PiecesEnts[i]:OBBMins()[3])*0.1225) )
  1637. self.PiecesEnts[i]:DrawModel()
  1638. end
  1639. end
  1640. end
  1641. end
  1642. -- self.PiecesEnt:SetNoDraw( true )
  1643. self:DrawModel()
  1644.  
  1645. if not InChessGame then
  1646. self.Highlight = nil
  1647. self.Selected = nil
  1648. self.Moves = nil
  1649. return
  1650. end
  1651.  
  1652. self.Highlight = self.Highlight or {-1,-1}
  1653. self.Selected = self.Selected or {-1,-1}
  1654. self.Moves = self.Moves or {}
  1655. local IsMouseDown = input.IsMouseDown( MOUSE_LEFT )
  1656. local MouseClick = IsMouseDown and (not self.WasMouseDown)
  1657. if ActiveBoard==self then --Don't need an IsValid check, we're valid
  1658. self.Highlight[1]=(-1) self.Highlight[2]=(-1)
  1659. local x,y = gui.MouseX(), gui.MouseY()
  1660.  
  1661. local Target = ScreenPos + (gui.ScreenToVector( x, y )*10000)
  1662.  
  1663. local tr = util.TraceLine( {start=ScreenPos, endpos=Target, filter=self:GetTraceFilter()} )
  1664.  
  1665.  
  1666.  
  1667. local pos = self:WorldToLocal( tr.HitPos )
  1668. local x,y = -1,-1
  1669. if pos[2]>self.TopLeft[2] and pos[3]>self.TopLeft[3] then
  1670. for i=0,8 do --Fall off the top
  1671. if pos[2]<(self.TopLeft[2]+(self.RealW*i)) then break end
  1672. y = i
  1673. end
  1674. for i=0,8 do
  1675. if pos[3]<(self.TopLeft[3]+(self.RealH*i)) then break end
  1676. x = i
  1677. end
  1678. end
  1679. self.Highlight = {x,y}
  1680. if MouseClick then
  1681. if self.Selected and self:GetTableGrid( self.Moves, x, y ) then
  1682. self:RequestMove( self.Selected[1], self.Selected[2], x, y )
  1683. self:ResetHighlights()
  1684. else
  1685. self:ResetHighlights()
  1686. self.Selected = {x,y}
  1687. self.Moves = self:GetMove( NumToLetter[x+1], 8-y )
  1688. end
  1689. end
  1690. else
  1691. self.Selected[1]=(-1) self.Selected[2]=(-1)
  1692. self.Highlight[1]=(-1) self.Highlight[2]=(-1)
  1693. self.Moves = {}
  1694. return
  1695. end
  1696.  
  1697. local pos = self:LocalToWorld( self.TopLeft )
  1698. local ang = self:GetUp():Angle()
  1699.  
  1700. cam.Start3D2D( pos, ang, 0.2 )
  1701. for i=0,7 do
  1702. for n=0,7 do
  1703. local square = self:GetTableGrid( self.Pieces, i,n )
  1704. if square and IsValid(square.Ent) then
  1705. draw.RoundedBox( 0, self.SquareW*i, self.SquareH*n, self.SquareW, self.SquareH, square.Ent:GetWhite() and ColWhite or ColBlack )
  1706. end
  1707. if self.Highlight[1]==i and self.Highlight[2]==n then
  1708. draw.RoundedBox( 0, self.SquareW*i, self.SquareH*n, self.SquareW, self.SquareH, ColHover )
  1709. end
  1710. if self:GetTableGrid( self.Moves, i, n ) then
  1711. draw.RoundedBox( 0, self.SquareW*i, self.SquareH*n, self.SquareW, self.SquareH, ColMove )
  1712. end
  1713. if self.Selected[1]==i and self.Selected[2]==n then
  1714. draw.RoundedBox( 0, self.SquareW*i, self.SquareH*n, self.SquareW, self.SquareH, ColSel )
  1715. end
  1716. if cvars.Bool("developer") then
  1717. draw.SimpleText( NumToLetter[i+1]..tostring(8-n), "Default", self.SquareW*i, self.SquareH*n )
  1718. end
  1719. end
  1720. end
  1721. cam.End3D2D()
  1722.  
  1723. self.WasMouseDown = input.IsMouseDown( MOUSE_LEFT )
  1724. end
  1725.  
  1726. function ENT:GetSpectateUse(ply,key)
  1727. if ply~=LocalPlayer() then return end
  1728. if key~=IN_USE then return end
  1729.  
  1730. if CurTime()<(self.Spec_LastPoll or 0)+1 then return end
  1731. self.Spec_LastPoll = CurTime()
  1732.  
  1733. local tr = util.TraceLine( {start=ply:EyePos(), endpos=ply:EyePos()+(ply:GetAimVector()*150), filter=ply} )
  1734. if (tr.Entity==self:GetTableEnt()) then
  1735. if not self.SpectatingTable then chat.AddText( HatsChat and {"LINEICON", Icon=Material( "icon16/controller.png" )} or "", Color(150,255,150), "You are now spectating this game." ) end
  1736. self.SpectatingTable = true
  1737.  
  1738. local frame = vgui.Create( "DFrame" )
  1739. frame:SetSize(300,115)
  1740. frame:SetPos( (ScrW()/2)-100, ScrH()-150 )
  1741. --frame:SetDraggable( false )
  1742. frame:SetTitle( "" )
  1743. frame:ShowCloseButton( false )
  1744. frame:SetDeleteOnClose( true )
  1745. frame.Paint = function( s,w,h )
  1746. if not (IsValid(self) and self.SpectatingTable) then
  1747. s:Remove()
  1748. gui.EnableScreenClicker( false )
  1749.  
  1750. return
  1751. end
  1752.  
  1753. draw.RoundedBox( 8, 0, 0, w, h, PanelCol.Main )
  1754. end
  1755. frame:DockMargin( 0,0,0,0 )
  1756. frame:DockPadding( 5,6,5,5 )
  1757. frame:MakePopup()
  1758.  
  1759. local TimePnl = vgui.Create( "DPanel", frame )
  1760. TimePnl:Dock( RIGHT )
  1761. TimePnl:SetWide( 100 )
  1762. TimePnl:DockMargin( 2,2,2,2 )
  1763. TimePnl.Paint = function(s,w,h)
  1764. if not IsValid(self) then return end
  1765.  
  1766. draw.RoundedBox( 16, 0, 0, w, (h/2)-1, PanelCol.ToMove )
  1767. draw.RoundedBox( 16, 0, (h/2)+1, w, (h/2)-1, PanelCol.ToMove )
  1768.  
  1769. 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 )
  1770. 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 )
  1771. end
  1772.  
  1773. local ButtonPanel = vgui.Create( "DPanel", frame )
  1774. ButtonPanel:SetSize( 100, 20 )
  1775. ButtonPanel:Dock( BOTTOM )
  1776. ButtonPanel.Paint = function() end
  1777.  
  1778. local ToMove = vgui.Create( "DPanel", frame )
  1779. ToMove:SetSize(200,80)
  1780. ToMove:Dock( FILL )
  1781. ToMove.Paint = function( s,w,h )
  1782. draw.RoundedBox( 4, 0, 0, w, h, PanelCol.ToMove )
  1783. draw.SimpleText( "To move", "ChessTextSmall", 5, 0, PanelCol.Text )
  1784. local state = IsValid(self) and self:GetChessState()
  1785. if not (IsValid( self ) and state) then
  1786. draw.SimpleText( "[N/A]", "ChessTextSmall", w/2, h/2, PanelCol.Text, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
  1787. else
  1788. local str = (state==CHESS_WAGER and "Wagers") or (state==CHESS_INACTIVE and "Waiting") or ((state==CHESS_WHITEMOVE or state==CHESS_WHITEPROMO) and "White") or ((state==CHESS_BLACKMOVE or state==CHESS_BLACKPROMO) and "Black") or "N/A"
  1789. local col = (str=="White" and PanelCol.White) or (str=="Black" and PanelCol.Black) or PanelCol.Text
  1790. draw.SimpleText( str, "ChessTextLarge", w/2, h/2, col, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER )
  1791. end
  1792. end
  1793.  
  1794. local DermaMode = vgui.Create( "DButton", ButtonPanel)
  1795. DermaMode:SetSize(94,20)
  1796. DermaMode:Dock( LEFT )
  1797. DermaMode:SetText( "Toggle 2D Mode" )
  1798. DermaMode.DoClick = function( s )
  1799. if IsValid(Chess_2DDermaPanel) then
  1800. Chess_2DDermaPanel:Remove()
  1801. else
  1802. Chess_Open2DBoard( self )
  1803. end
  1804. end
  1805.  
  1806. local StopSpec = vgui.Create( "DButton", ButtonPanel)
  1807. StopSpec:SetSize(94,20)
  1808. StopSpec:Dock( RIGHT )
  1809. StopSpec:SetText( "Stop Spectating" )
  1810. StopSpec.DoClick = function( s )
  1811. chat.AddText( HatsChat and {"LINEICON", Icon=Material( "icon16/controller.png" )} or "", Color(150,255,150), "You are no longer spectating this game." )
  1812. self.SpectatingTable = false
  1813. end
  1814. else
  1815. if self.SpectatingTable then chat.AddText( HatsChat and {"LINEICON", Icon=Material( "icon16/controller.png" )} or "", Color(150,255,150), "You are no longer spectating this game." ) end
  1816. self.SpectatingTable = false
  1817. end
  1818. end
  1819.  
  1820. net.Receive( "Chess DrawOffer", function()
  1821. if IsValid( ChessPanel ) and IsValid( ChessPanel.OfferDraw ) then
  1822. ChessPanel.OfferDraw:SetText( "Accept Draw Offer" )
  1823. end
  1824. end)
  1825.  
  1826. net.Receive( "Chess GameOver", function() --Now used for all messages
  1827. local tbl = net.ReadTable()
  1828. local emote = net.ReadString()
  1829. if HatsChat then
  1830. local Mat
  1831. if emote and emote~="" then Mat = Material(emote) end
  1832. if not Mat then
  1833. Mat = Material( "icon16/controller.png" )
  1834. end
  1835. if tostring(Mat)~="___error" then
  1836. table.insert(tbl, 1, {"LINEICON", Icon=Mat} )
  1837. end
  1838. end
  1839. chat.AddText( unpack( tbl ) )
  1840. end)
  1841. net.Receive( "Chess PromotionSelection", function()
  1842. local File = net.ReadInt( 5 )
  1843. local Frame = vgui.Create( "DFrame" )
  1844. Frame:SetSize( 100, 225 )
  1845. Frame:SetPos( (ScrW()/2) - 50, (ScrH()/2)-112 )
  1846. Frame:SetDraggable( false )
  1847. Frame:ShowCloseButton( false )
  1848. Frame:DockMargin( 5,5,5,5 )
  1849. Frame:DockPadding( 5,5,5,5 )
  1850. Frame:MakePopup()
  1851. Frame:SetTitle( "" )
  1852. Frame.Paint = function( s,w,h )
  1853. draw.RoundedBox( 4, 0, 0, w, h, Color(0,0,0,150) )
  1854. end
  1855.  
  1856. local Queen = vgui.Create( "DButton", Frame )
  1857. Queen.DoClick = function( s )
  1858. net.Start( "Chess PromotionSelection" )
  1859. net.WriteString( "Queen" )
  1860. net.WriteInt( File, 5 )
  1861. net.SendToServer()
  1862. Frame:Remove()
  1863. end
  1864. Queen:SetText( "Queen" )
  1865. Queen:Dock( TOP )
  1866. Queen:SetSize( 90, 50 )
  1867. Queen:DockMargin( 0,0,0,0 )
  1868.  
  1869. local Rook = vgui.Create( "DButton", Frame )
  1870. Rook.DoClick = function( s )
  1871. net.Start( "Chess PromotionSelection" )
  1872. net.WriteString( "Rook" )
  1873. net.WriteInt( File, 5 )
  1874. net.SendToServer()
  1875. Frame:Remove()
  1876. end
  1877. Rook:SetText( "Rook" )
  1878. Rook:Dock( TOP )
  1879. Rook:SetSize( 90, 50 )
  1880. Rook:DockMargin( 0,5,0,0 )
  1881.  
  1882. local Bishop = vgui.Create( "DButton", Frame )
  1883. Bishop.DoClick = function( s )
  1884. net.Start( "Chess PromotionSelection" )
  1885. net.WriteString( "Bishop" )
  1886. net.WriteInt( File, 5 )
  1887. net.SendToServer()
  1888. Frame:Remove()
  1889. end
  1890. Bishop:SetText( "Bishop" )
  1891. Bishop:Dock( TOP )
  1892. Bishop:SetSize( 90, 50 )
  1893. Bishop:DockMargin( 0,5,0,0 )
  1894.  
  1895. local Knight = vgui.Create( "DButton", Frame )
  1896. Knight.DoClick = function( s )
  1897. net.Start( "Chess PromotionSelection" )
  1898. net.WriteString( "Knight" )
  1899. net.WriteInt( File, 5 )
  1900. net.SendToServer()
  1901. Frame:Remove()
  1902. end
  1903. Knight:SetText( "Knight" )
  1904. Knight:Dock( TOP )
  1905. Knight:SetSize( 90, 50 )
  1906. Knight:DockMargin( 0,5,0,0 )
  1907. end)
  1908.  
  1909. net.Receive( "Chess Update", function()
  1910. local board = net.ReadEntity()
  1911. local pieces = net.ReadTable()
  1912.  
  1913. local Move1 = net.ReadTable()
  1914. local Move2 = net.ReadTable()
  1915.  
  1916. if IsValid(board) and pieces then
  1917. board.Pieces = pieces
  1918. if Move1.To then
  1919. if Move1.From then
  1920. board.Pieces[Move1.To[1]][Move1.To[2]].Moving = true
  1921. board.Pieces[Move1.To[1]][Move1.To[2]].MoveStart = RealTime()
  1922. board.Pieces[Move1.To[1]][Move1.To[2]].MoveFrom = board:GetSquarePos( Move1.From[1],Move1.From[2] )
  1923. else
  1924. sound.Play( board.MoveSound, board:GetSquarePos( Move1.To[1],Move1.To[2]) or board:GetPos() )
  1925. end
  1926. end
  1927. if Move2.To then
  1928. if Move2.From then
  1929. board.Pieces[Move2.To[1]][Move2.To[2]].Moving = true
  1930. board.Pieces[Move2.To[1]][Move2.To[2]].MoveStart = RealTime()
  1931. board.Pieces[Move2.To[1]][Move2.To[2]].MoveFrom = board:GetSquarePos( Move2.From[1],Move2.From[2] )
  1932. else
  1933. sound.Play( board.MoveSound, board:GetSquarePos( Move2.To[1],Move2.To[2]) or board:GetPos() )
  1934. end
  1935. end
  1936.  
  1937. board.IsInCheck = board:CheckForCheck( board.Pieces, Move1.To and board.Pieces[Move1.To[1]][Move1.To[2]].Team~="White" )
  1938. end
  1939. end)
  1940. end
  1941. if SERVER then
  1942. net.Receive( "Chess ClientRequestMove", function(len, ply)
  1943. if not IsValid(ply) then return end
  1944. local seat = ply:GetVehicle()
  1945. if not (IsValid(seat) and seat:GetNWBool("IsChessSeat", false)) then return end
  1946. local board = seat:GetNWEntity( "ChessBoard" )
  1947. if not IsValid(board) then return end
  1948.  
  1949. local IsWhite = (seat==board.WhiteSeat)
  1950. if (not IsWhite) and seat~=board.BlackSeat then return end
  1951.  
  1952. if (not cvars.Bool( "chess_debug" )) and ((IsWhite and board:GetChessState()~=CHESS_WHITEMOVE) or ((not IsWhite) and board:GetChessState()~=CHESS_BLACKMOVE)) then return end
  1953.  
  1954. local StartLet, StartNum = NumToLetter[math.Clamp(net.ReadInt(5),1,8)], math.Clamp(net.ReadInt(5),1,8)
  1955. local EndLet, EndNum = NumToLetter[math.Clamp(net.ReadInt(5),1,8)], math.Clamp(net.ReadInt(5),1,8)
  1956.  
  1957. local StartSquare = board:GetSquare( StartLet, StartNum )
  1958. if not StartSquare then return end
  1959.  
  1960. if (not cvars.Bool( "chess_debug" )) and ((IsWhite and board:SquareTeam(StartSquare)~="White") or ((not IsWhite) and board:SquareTeam(StartSquare)~="Black")) then return end
  1961.  
  1962. board:DoMove( StartLet, StartNum, EndLet, EndNum )
  1963. end)
  1964.  
  1965. net.Receive( "Chess ClientResign", function( len,ply ) if IsValid(ply) then
  1966. ply.CanExitChess = true
  1967. ply:ExitVehicle()
  1968. end end)
  1969. net.Receive( "Chess DrawOffer", function( len,ply )
  1970. if not IsValid(ply) then return end
  1971. local seat = ply:GetVehicle()
  1972. if not (IsValid(seat) and seat:GetNWBool("IsChessSeat", false)) then return end
  1973. local board = seat:GetNWEntity( "ChessBoard" )
  1974. if not IsValid(board) then return end
  1975.  
  1976. local IsWhite = (seat==board.WhiteSeat)
  1977. if (not IsWhite) and seat~=board.BlackSeat then return end
  1978.  
  1979. if board.SurrenderOffer==(IsWhite and "Black" or "White") then
  1980. local WhitePly = board:GetPlayer( "White" )
  1981. local BlackPly = board:GetPlayer( "Black" )
  1982.  
  1983. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  1984. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  1985. board:EndGame()
  1986. net.Start( "Chess GameOver" )
  1987. net.WriteTable( {Color(255,255,255), WhiteName, Color(150,255,150), board:GetElo(WhitePly), " and ", Color(100,100,100), BlackName, Color(150,255,150), board:GetElo(BlackPly), " have agreed to draw."} )
  1988. net.WriteString( "icon16/medal_silver_1.png" )
  1989. net.Broadcast()
  1990. else
  1991. board.SurrenderOffer = IsWhite and "White" or "Black"
  1992. net.Start( "Chess DrawOffer" )
  1993. net.Send( board:GetPlayer( IsWhite and "Black" or "White" ) )
  1994. end
  1995. end)
  1996. net.Receive( "Chess ClientCallDraw", function( len,ply )
  1997. if not IsValid(ply) then return end
  1998. local seat = ply:GetVehicle()
  1999. if not (IsValid(seat) and seat:GetNWBool("IsChessSeat", false)) then return end
  2000. local board = seat:GetNWEntity( "ChessBoard" )
  2001. if not IsValid(board) then return end
  2002.  
  2003. local IsWhite = (seat==board.WhiteSeat)
  2004. if (not IsWhite) and seat~=board.BlackSeat then return end
  2005.  
  2006. local DrawType = net.ReadUInt( 2 )
  2007. if DrawType==CHESS_DRAW_50 then
  2008. if not cvars.Bool("chess_limitmoves") then ply:ChatPrint( "This option is disabled on this server." ) return end
  2009. if board:GetMoveCount()<50 then ply:ChatPrint( "This option is available when 50 moves pass without a pawn move or capture." ) return end
  2010. local WhitePly = board:GetPlayer( "White" )
  2011. local BlackPly = board:GetPlayer( "Black" )
  2012.  
  2013. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  2014. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  2015. board:EndGame()
  2016. net.Start( "Chess GameOver" )
  2017. if IsWhite then
  2018. net.WriteTable( {Color(150,255,150), "50 moves! ", Color(255,255,255), WhiteName, Color(150,255,150), board:GetElo(WhitePly), " has called a draw against ", Color(100,100,100), BlackName, Color(150,255,150), board:GetElo(BlackPly),"!"} )
  2019. else
  2020. net.WriteTable( {Color(150,255,150), "50 moves! ", Color(100,100,100), BlackName, Color(150,255,150), board:GetElo(BlackPly), " has called a draw against ", Color(255,255,255), WhiteName, Color(150,255,150), board:GetElo(WhitePly),"!"} )
  2021. end
  2022. net.WriteString( "icon16/medal_bronze_1.png" )
  2023. net.Broadcast()
  2024. elseif DrawType==CHESS_DRAW_3 then
  2025. if not board:GetRepetition() then ply:ChatPrint( "This option is avilable when the board is in the same position three times." ) return end
  2026. local WhitePly = board:GetPlayer( "White" )
  2027. local BlackPly = board:GetPlayer( "Black" )
  2028.  
  2029. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  2030. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  2031. board:EndGame()
  2032. net.Start( "Chess GameOver" )
  2033. if IsWhite then
  2034. net.WriteTable( {Color(150,255,150), "Threefold repetion! ", Color(255,255,255), WhiteName, Color(150,255,150), board:GetElo(WhitePly), " has called a draw against ", Color(100,100,100), BlackName, Color(150,255,150), board:GetElo(BlackPly),"!"} )
  2035. else
  2036. net.WriteTable( {Color(150,255,150), "Threefold repetion! ", Color(100,100,100), BlackName, Color(150,255,150), board:GetElo(BlackPly), " has called a draw against ", Color(255,255,255), WhiteName, Color(150,255,150), board:GetElo(WhitePly),"!"} )
  2037. end
  2038. net.WriteString( "icon16/medal_bronze_1.png" )
  2039. net.Broadcast()
  2040. end
  2041. end)
  2042. net.Receive( "Chess ClientWager", function( len,ply )
  2043. if not IsValid(ply) then return end
  2044. local seat = ply:GetVehicle()
  2045. if not (IsValid(seat) and seat:GetNWBool("IsChessSeat", false)) then return end
  2046. local board = seat:GetNWEntity( "ChessBoard" )
  2047. if not IsValid(board) then return end
  2048.  
  2049. if board:GetChessState()~=CHESS_WAGER then return end
  2050.  
  2051. local IsWhite = (seat==board.WhiteSeat)
  2052. if (not IsWhite) and seat~=board.BlackSeat then return end
  2053.  
  2054. local wager = net.ReadUInt( 24 )
  2055. if (not wager) or wager<0 then return end
  2056. if board:GetPSWager() then
  2057. if not ply:PS_HasPoints( wager ) then return end
  2058. else
  2059. if wager>(ply:getDarkRPVar( "money" ) or 0) then return end
  2060. end
  2061.  
  2062. if IsWhite then
  2063. if board:GetBlackWager()>=0 and wager==board:GetBlackWager() then
  2064. board:SetPlaying( true )
  2065. board:SetChessState( board.StartState )
  2066.  
  2067. local PlyName = ply:Nick() or "[N/A]"
  2068. local OtherPly = board:GetPlayer( "Black" )
  2069. local OtherName = IsValid(OtherPly) and OtherPly:Nick() or "[N/A]"
  2070. net.Start( "Chess GameOver" )
  2071. if IsWhite then
  2072. net.WriteTable( {Color(255,255,255), PlyName, Color(150,255,150), board:GetElo(ply), " has challenged ", Color(100,100,100), OtherName, Color(150,255,150), board:GetElo(OtherPly)," to "..board:GameName().."!"} )
  2073. else
  2074. net.WriteTable( {Color(100,100,100), PlyName, Color(150,255,150), board:GetElo(ply), " has challenged ", Color(255,255,255), OtherName, Color(150,255,150), board:GetElo(OtherPly)," to "..board:GameName().."!"} )
  2075. end
  2076. net.Broadcast()
  2077.  
  2078. board.WagerValue = wager
  2079.  
  2080. if board:GetPSWager() then
  2081. OtherPly:PS_TakePoints( board.WagerValue )
  2082. ply:PS_TakePoints( board.WagerValue )
  2083. else
  2084. if OtherPly.addMoney then OtherPly:addMoney( -board.WagerValue ) else OtherPly:SetDarkRPVar( "money", (OtherPly:getDarkRPVar( "money" ) or 0) - board.WagerValue ) end
  2085. if ply.addMoney then ply:addMoney( -board.WagerValue ) else ply:SetDarkRPVar( "money", (ply:getDarkRPVar( "money" ) or 0) - board.WagerValue ) end
  2086. end
  2087. else
  2088. board:SetWhiteWager( wager )
  2089. end
  2090. else
  2091. if board:GetWhiteWager()>=0 and wager==board:GetWhiteWager() then
  2092. board:SetPlaying( true )
  2093. board:SetChessState( board.StartState )
  2094.  
  2095. local PlyName = ply:Nick() or "[N/A]"
  2096. local OtherPly = board:GetPlayer( "White" )
  2097. local OtherName = IsValid(OtherPly) and OtherPly:Nick() or "[N/A]"
  2098. net.Start( "Chess GameOver" )
  2099. if IsWhite then
  2100. net.WriteTable( {Color(255,255,255), PlyName, Color(150,255,150), board:GetElo(ply), " has challenged ", Color(100,100,100), OtherName, Color(150,255,150), board:GetElo(OtherPly)," to "..board:GameName().."!"} )
  2101. else
  2102. net.WriteTable( {Color(100,100,100), PlyName, Color(150,255,150), board:GetElo(ply), " has challenged ", Color(255,255,255), OtherName, Color(150,255,150), board:GetElo(OtherPly)," to "..board:GameName().."!"} )
  2103. end
  2104. net.Broadcast()
  2105.  
  2106. board.WagerValue = wager
  2107.  
  2108. if board:GetPSWager() then
  2109. OtherPly:PS_TakePoints( board.WagerValue )
  2110. ply:PS_TakePoints( board.WagerValue )
  2111. else
  2112. if OtherPly.addMoney then OtherPly:addMoney( -board.WagerValue ) else OtherPly:SetDarkRPVar( "money", (OtherPly:getDarkRPVar( "money" ) or 0) - board.WagerValue ) end
  2113. if ply.addMoney then ply:addMoney( -board.WagerValue ) else ply:SetDarkRPVar( "money", (ply:getDarkRPVar( "money" ) or 0) - board.WagerValue ) end
  2114. end
  2115. else
  2116. board:SetBlackWager( wager )
  2117. end
  2118. end
  2119. end)
  2120.  
  2121. local PromotionClass = {["Queen"] = true, ["Bishop"] = true, ["Rook"] = true, ["Knight"] = true}
  2122. net.Receive( "Chess PromotionSelection", function( len, ply )
  2123. if not IsValid(ply) then return end
  2124. local seat = ply:GetVehicle()
  2125. if not (IsValid(seat) and seat:GetNWBool("IsChessSeat", false)) then return end
  2126. local board = seat:GetNWEntity( "ChessBoard" )
  2127. if not IsValid(board) then return end
  2128.  
  2129. local IsWhite = (board:GetPlayer("White")==ply)
  2130. if (not IsWhite) and (board:GetPlayer("Black")~=ply) then return end
  2131. if (IsWhite and board:GetChessState()~=CHESS_WHITEPROMO) or ((not IsWhite) and board:GetChessState()~=CHESS_BLACKPROMO) then return end
  2132.  
  2133. local GridNum = (IsWhite and 8) or 1
  2134.  
  2135. local Class = net.ReadString()
  2136. local GridLetter = NumToLetter[net.ReadInt(5)]
  2137. if not (GridLetter and Class) then return end
  2138. if not PromotionClass[Class] then return end
  2139.  
  2140. local square = board:GetSquare( GridLetter, GridNum )
  2141. if not square then return end
  2142. if (IsWhite and board:SquareTeam( square )~="White") or ((not IsWhite) and board:SquareTeam( square )~="Black") then return end
  2143. if square.Class~="Pawn" then return end
  2144.  
  2145. if IsValid(square.Ent) then square.Ent:SetGridNum(-1) square.Ent:Remove() end
  2146.  
  2147. square.Class = Class
  2148.  
  2149. board:Update( {To={GridLet,GridNum}} )
  2150.  
  2151. local IsCheck = board:CheckForCheck( board.Pieces, square.Team~="White" )
  2152. local Checkmate = board:IsCheckmate( square.Team~="White" )
  2153. if IsCheck and Checkmate then
  2154. local WhitePly = board:GetPlayer( "White" )
  2155. local BlackPly = board:GetPlayer( "Black" )
  2156.  
  2157. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  2158. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  2159. board:EndGame( square.Team )
  2160. net.Start( "Chess GameOver" )
  2161. if square.Team=="White" then
  2162. net.WriteTable( {Color(255,255,255), WhiteName, Color(150,255,150), board:GetElo(WhitePly), " has checkmated ", Color(100,100,100), BlackName, Color(150,255,150), board:GetElo(BlackPly),"!"} )
  2163. else
  2164. net.WriteTable( {Color(100,100,100), BlackName, Color(150,255,150), board:GetElo(BlackPly), " has checkmated ", Color(255,255,255), WhiteName, Color(150,255,150), board:GetElo(WhitePly),"!"} )
  2165. end
  2166. net.WriteString( "icon16/medal_gold_2.png" )
  2167. net.Broadcast()
  2168. elseif Checkmate then
  2169. local WhitePly = board:GetPlayer( "White" )
  2170. local BlackPly = board:GetPlayer( "Black" )
  2171.  
  2172. local WhiteName = IsValid(WhitePly) and WhitePly:Nick() or "[Anonymous White]"
  2173. local BlackName = IsValid(BlackPly) and BlackPly:Nick() or "[Anonymous Black]"
  2174. board:EndGame()
  2175. net.Start( "Chess GameOver" )
  2176. net.WriteTable( {Color(150,255,150), "Stalemate! ", Color(255,255,255), WhiteName, Color(150,255,150), board:GetElo(WhitePly), " drew with ", Color(100,100,100), BlackName, Color(150,255,150), board:GetElo(BlackPly),"!"} )
  2177. net.WriteString( "icon16/medal_silver_1.png" )
  2178. net.Broadcast()
  2179. else
  2180. board:SetChessState( IsWhite and CHESS_BLACKMOVE or CHESS_WHITEMOVE )
  2181. end
  2182. end)
  2183. hook.Add( "PlayerEnteredVehicle", "Chess PlayerEnter BeginGame", function( ply, seat )
  2184. if not (IsValid(ply) and IsValid(seat)) then return end
  2185. if not seat:GetNWBool("IsChessSeat", false) then return end
  2186.  
  2187. local board = seat:GetNWEntity( "ChessBoard" )
  2188. if not IsValid(board) then return end
  2189.  
  2190. ply.CanExitChess = false
  2191. ply:GodEnable()
  2192.  
  2193. ply:SetNWBool( "IsInChess", true )
  2194. ply:SetNWEntity( "ActiveChessBoard", board )
  2195.  
  2196. local IsWhite = (seat==board.WhiteSeat)
  2197. if (not IsWhite) and seat~=board.BlackSeat then return end
  2198. if IsWhite then board:SetWhitePlayer( ply ) else board:SetBlackPlayer( ply ) end
  2199.  
  2200. local OtherSeat = IsWhite and board.BlackSeat or board.WhiteSeat
  2201. if (not IsValid(OtherSeat)) or OtherSeat==seat then return end
  2202.  
  2203. local OtherPly = OtherSeat:GetDriver()
  2204. if cvars.Bool( "chess_debug" ) or (IsValid( OtherPly ) and not board:GetPlaying()) then
  2205. board:ResetBoard()
  2206. local IsDarkRP = gmod.GetGamemode().Name=="DarkRP"
  2207. if (not cvars.Bool( "chess_debug" )) and IsDarkRP and cvars.Bool( "chess_darkrp_wager" ) and cvars.Bool( "chess_wagers" ) then
  2208. board:SetPlaying( false )
  2209. board:SetChessState( CHESS_WAGER )
  2210. board:SetPSWager( false )
  2211.  
  2212. if IsValid(OtherPly) and OtherPly:IsBot() then if IsWhite then board:SetBlackWager(0) else board:SetWhiteWager(0) end end
  2213. if IsValid(ply) and ply:IsBot() then if IsWhite then board:SetWhiteWager(0) else board:SetBlackWager(0) end end
  2214. elseif (not cvars.Bool( "chess_debug" )) and cvars.Bool( "chess_wagers" ) and PS and PS.Items then --There's probably a better check for pointshop
  2215. board:SetPlaying( false )
  2216. board:SetPSWager( true )
  2217. board:SetChessState( CHESS_WAGER )
  2218.  
  2219. if IsValid(OtherPly) and OtherPly:IsBot() then if IsWhite then board:SetBlackWager(0) else board:SetWhiteWager(0) end end
  2220. if IsValid(ply) and ply:IsBot() then if IsWhite then board:SetWhiteWager(0) else board:SetBlackWager(0) end end
  2221. else
  2222. board:SetPlaying( true )
  2223. board:SetChessState( board.StartState )
  2224. board:SetPSWager( false )
  2225. board.WagerValue = nil
  2226.  
  2227. local PlyName = ply:Nick() or "[N/A]"
  2228. local OtherName = IsValid(OtherPly) and OtherPly:Nick() or "[N/A]"
  2229. net.Start( "Chess GameOver" )
  2230. if IsWhite then
  2231. net.WriteTable( {Color(255,255,255), PlyName, Color(150,255,150), board:GetElo(ply), " has challenged ", Color(100,100,100), OtherName, Color(150,255,150), board:GetElo(OtherPly)," to "..board:GameName().."!"} )
  2232. else
  2233. net.WriteTable( {Color(100,100,100), PlyName, Color(150,255,150), board:GetElo(ply), " has challenged ", Color(255,255,255), OtherName, Color(150,255,150), board:GetElo(OtherPly)," to "..board:GameName().."!"} )
  2234. end
  2235. net.Broadcast()
  2236. end
  2237. end
  2238. end)
  2239. hook.Add( "CanExitVehicle", "Chess CanExitVehicle Anti-minge", function( seat, ply ) --Backwards :p
  2240. if not (IsValid(ply) and IsValid(seat)) then return end
  2241. if not seat:GetNWBool("IsChessSeat", false) then return end
  2242.  
  2243. local board = seat:GetNWEntity( "ChessBoard" )
  2244. if not IsValid(board) then return end
  2245.  
  2246. if board:GetPlaying() and (not ply.CanExitChess) then return false end
  2247. end)
  2248. hook.Add( "PlayerLeaveVehicle", "Chess PlayerLeave ResignGame", function( ply, seat )
  2249. if not (IsValid(ply) and IsValid(seat)) then return end
  2250. if not seat:GetNWBool("IsChessSeat", false) then return end
  2251.  
  2252. ply:SetPos( seat:GetPos() - (seat:GetForward()*10) )
  2253. --ply:SetAngles( seat:GetAngles() ) --Doesn't work?
  2254. ply:GodDisable()
  2255.  
  2256. ply:SetNWBool( "IsInChess", false )
  2257. ply:SetNWEntity( "ActiveChessBoard", nil )
  2258.  
  2259. local board = seat:GetNWEntity( "ChessBoard" )
  2260. if not IsValid(board) then return end
  2261.  
  2262. if board:GetPlaying() and (not ply.CanExitChess) then
  2263. timer.Simple(0, function() if IsValid(ply) and IsValid(seat) then ply:EnterVehicle(seat) end end)
  2264. return
  2265. end
  2266.  
  2267. local IsWhite = (seat==board.WhiteSeat)
  2268. if (not IsWhite) and seat~=board.BlackSeat then return end
  2269. if IsWhite then board:SetWhitePlayer( NULL ) else board:SetBlackPlayer( NULL ) end
  2270.  
  2271. board:SetChessState( CHESS_INACTIVE )
  2272. if not board:GetPlaying() then return end
  2273. board:SetPlaying( false )
  2274.  
  2275. local OtherSeat = IsWhite and board.BlackSeat or board.WhiteSeat
  2276. if (not IsValid(OtherSeat)) or OtherSeat==seat then return end
  2277.  
  2278. local OtherPly = OtherSeat:GetDriver()
  2279.  
  2280. local PlyName = IsValid(ply) and ply:Nick() or "[N/A]"
  2281. local OtherName = IsValid(OtherPly) and OtherPly:Nick() or (IsWhite and "[Anonymous Black]" or "[Anonymous White]")
  2282.  
  2283. board:EndGame( IsWhite and "Black" or "White", true )
  2284. net.Start( "Chess GameOver" )
  2285. if IsWhite then
  2286. net.WriteTable( {Color(255,255,255), PlyName, Color(150,255,150), board:GetElo(ply), " has surrendered to ", Color(100,100,100), OtherName, Color(150,255,150), board:GetElo(OtherPly),"!"} )
  2287. else
  2288. net.WriteTable( {Color(100,100,100), PlyName, Color(150,255,150), board:GetElo(ply), " has surrendered to ", Color(255,255,255), OtherName, Color(150,255,150), board:GetElo(OtherPly),"!"} )
  2289. end
  2290. net.WriteString( "icon16/medal_bronze_3.png" )
  2291. net.Broadcast()
  2292.  
  2293. board:SetChessState( CHESS_INACTIVE )
  2294. board:SetPlaying( false )
  2295.  
  2296. if IsValid( OtherPly ) then OtherPly:ExitVehicle() end
  2297. end)
  2298. hook.Add( "PlayerDisconnected", "Chess PlayerDisconnect ResignGame", function( ply, seat )
  2299. if not (IsValid(ply)) then return end
  2300.  
  2301. local seat = ply:GetVehicle()
  2302. if not (IsValid(seat) and seat:GetNWBool("IsChessSeat", false)) then return end
  2303.  
  2304. ply:SetNWBool( "IsInChess", false )
  2305. ply:SetNWEntity( "ActiveChessBoard", nil )
  2306.  
  2307. local board = seat:GetNWEntity( "ChessBoard" )
  2308. if not IsValid(board) then return end
  2309.  
  2310. local IsWhite = (seat==board.WhiteSeat)
  2311. if (not IsWhite) and seat~=board.BlackSeat then return end
  2312. if IsWhite then board:SetWhitePlayer( NULL ) else board:SetBlackPlayer( NULL ) end
  2313.  
  2314. board:SetChessState( CHESS_INACTIVE )
  2315. if not board:GetPlaying() then return end
  2316. board:SetPlaying( false )
  2317.  
  2318. local OtherSeat = IsWhite and board.BlackSeat or board.WhiteSeat
  2319. if (not IsValid(OtherSeat)) or OtherSeat==seat then return end
  2320.  
  2321. local OtherPly = OtherSeat:GetDriver()
  2322.  
  2323. local PlyName = IsValid(ply) and ply:Nick() or "[N/A]"
  2324. local OtherName = IsValid(OtherPly) and OtherPly:Nick() or (IsWhite and "[Anonymous Black]" or "[Anonymous White]")
  2325.  
  2326. board:EndGame( IsWhite and "Black" or "White", true )
  2327. net.Start( "Chess GameOver" )
  2328. if IsWhite then
  2329. net.WriteTable( {Color(255,255,255), PlyName, Color(150,255,150), board:GetElo(ply), " rage quit against ", Color(100,100,100), OtherName, Color(150,255,150), board:GetElo(OtherPly),"!"} )
  2330. else
  2331. net.WriteTable( {Color(100,100,100), PlyName, Color(150,255,150), board:GetElo(ply), " rage quit against ", Color(255,255,255), OtherName, Color(150,255,150), board:GetElo(OtherPly),"!"} )
  2332. end
  2333. net.WriteString( "icon16/medal_gold_2.png" )
  2334. net.Broadcast()
  2335.  
  2336. board:SetChessState( CHESS_INACTIVE )
  2337. board:SetPlaying( false )
  2338.  
  2339. if IsValid( OtherPly ) then OtherPly:ExitVehicle() end
  2340. end)
  2341. hook.Add( "CanPlayerSuicide", "Chess PlayerSuicide Prevention", function( ply )
  2342. if not (IsValid(ply)) then return end
  2343.  
  2344. local seat = ply:GetVehicle()
  2345. if not (IsValid(seat) and seat:GetNWBool("IsChessSeat", false)) then return end
  2346.  
  2347. return false
  2348. end)
  2349.  
  2350. local SaveSystem = {}
  2351. local SaveFile = game.GetMap()
  2352. SaveSystem.Load = function( self )
  2353. if not SaveFile then SaveFile=game.GetMap() end
  2354. if not file.IsDir( "chessboard", "DATA" ) then file.CreateDir( "chessboard", "DATA" ) end
  2355. local data = file.Read( "chessboard/"..SaveFile..".txt", "DATA" )
  2356.  
  2357. if data then
  2358. local tbl = util.JSONToTable(data) or {}
  2359. for _,v in pairs(tbl) do
  2360. local ent = ents.Create( v.class )
  2361. if IsValid(ent) then
  2362. ent.SavePos = SpawnPos
  2363. ent:SetPos( v.pos )
  2364. ent:Spawn()
  2365. end
  2366. end
  2367. end
  2368.  
  2369. if file.Exists( "chessboard/savedata.txt", "DATA" ) then --Read old system
  2370. local data = file.Read( "chessboard/savedata.txt", "DATA" )
  2371.  
  2372. if data then
  2373. local tbl = util.JSONToTable(data) or {}
  2374. for _,v in pairs(tbl) do
  2375. local ent = ents.Create( v.class )
  2376. if IsValid(ent) then ent.SavePos = SpawnPos ent:SetPos( v.pos ) ent:Spawn() end
  2377. end
  2378. end
  2379.  
  2380. file.Delete( "chessboard/savedata.txt", "DATA" )
  2381. self:Save()
  2382. end
  2383. return true
  2384. end
  2385. SaveSystem.Save = function( self )
  2386. if not SaveFile then SaveFile=game.GetMap() end
  2387.  
  2388. local SaveTbl = {}
  2389. local Ents = ents.FindByClass( "ent_chess_board" )
  2390. for _,v in pairs( Ents ) do
  2391. if IsValid(v) then
  2392. table.insert( SaveTbl, {class=v:GetClass(), pos = (v.BoardHeight and (v:GetPos()-v.BoardHeight)) or v.SavePos or v:GetPos()} )
  2393. end
  2394. end
  2395. local Ents = ents.FindByClass( "ent_draughts_board" )
  2396. for _,v in pairs( Ents ) do
  2397. if IsValid(v) then
  2398. table.insert( SaveTbl, {class=v:GetClass(), pos = (v.BoardHeight and (v:GetPos()-v.BoardHeight)) or v.SavePos or v:GetPos()} )
  2399. end
  2400. end
  2401.  
  2402. if not file.IsDir( "chessboard", "DATA" ) then file.CreateDir( "chessboard", "DATA" ) end
  2403. file.Write( "chessboard/"..SaveFile..".txt", util.TableToJSON(SaveTbl) )
  2404. return true
  2405. end
  2406. hook.Add( "InitPostEntity", "Chess InitPostEntity LoadBoards", function() SaveSystem:Load() end)
  2407. hook.Add( "PostCleanupMap", "Chess PostCleanup LoadBoards", function() SaveSystem:Load() end)
  2408.  
  2409. local SaveCommands = {
  2410. ["/chesssave"] = true, ["/savechess"] = true, ["!chesssave"] = true, ["!savechess"] = true,
  2411. ["/draughtssave"] = true, ["/savedraughts"] = true, ["!draughtssave"] = true, ["!savedraughts"] = true,
  2412. ["/checkerssave"] = true, ["/savecheckers"] = true, ["!checkerssave"] = true, ["!savecheckers"] = true,
  2413. }
  2414. hook.Add( "PlayerSay", "Chess PlayerSay SaveBoards", function( ply, str, tm )
  2415. if not IsValid(ply) then return end
  2416. if not ply:IsSuperAdmin() then return end
  2417.  
  2418. if SaveCommands[str:lower()] then
  2419. local saved = SaveSystem:Save()
  2420. ply:ChatPrint( saved and "Saved game board positions" or "Save failed!" )
  2421. end
  2422. end)
  2423. local function ChessSave( ply, c, a )
  2424. if IsValid(ply) and not ply:IsSuperAdmin() then ply:ChatPrint( "You can't do this" ) end
  2425.  
  2426. local saved = SaveSystem:Save()
  2427. if IsValid(ply) then
  2428. ply:ChatPrint( saved and "Saved game board positions" or "Save failed!" )
  2429. else
  2430. print( saved and "Saved game board positions" or "Save failed!" )
  2431. end
  2432. end
  2433. concommand.Add( "chess_save", ChessSave ) concommand.Add( "draughts_save", ChessSave ) concommand.Add( "checkers_save", ChessSave )
  2434. end
  2435.  
  2436. hook.Add( "GravGunPickupAllowed", "Chess DarkRP PreventGrav", function( ply, ent )
  2437. if IsValid(ent) and ent.IsChessEntity then return false end
  2438. end)
  2439. hook.Add( "canPocket", "Chess DarkRP PreventPocket", function( ply, ent )
  2440. if IsValid(ent) and ent.IsChessEntity then return false,"Please do not interfere with Chess." end
  2441. end)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement