;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Connect 4: By Imk0tter & Kylar ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; menu Nicklist { Connect4:Connect4::SendRequest $1 } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Open Handeling ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ctcp 1:CONNECT4.REQUEST*:*: { .timer 1 0 Connect4::ReceiveRequest $nick $ctime } ctcp 1:CONNECT4.REJECT*:*: { .timer 1 0 Connect4::RequestFailed $nick .timerCONNECT4.REQUEST. $+ $nick off } ctcp 1:CONNECT4.ACCEPT*:*: { if ($timer(CONNECT4.REQUEST. $+ $nick)) { .timerCONNECT4.REQUEST. $+ $nick off var %id $Connect4::UnusedID sockopen %id $2 $3 } } alias Connect4::SendRequest { ctcp $1 CONNECT4.REQUEST .timerCONNECT4.REQUEST. $+ $1 1 10 Connect4::RequestFailed $1 } alias Connect4::RequestFailed { var %x $input($1 denied your Connect4 request,o) } alias Connect4::ReceiveRequest { var %request $input(Would you like to start a Connect4 game with $1?,y) if (%request && $calc($ctime - $2) < 10) { .timerRequestTimeout $+ $1 off if ($sock(CONNECT4.LISTEN. $+ $1)) sockclose CONNECT4.LISTEN. $+ $nick socklisten Connect4.LISTEN. $+ $1 ctcp $1 CONNECT4.ACCEPT $ip $sock(Connect4.LISTEN. $+ $1).port .timerConnect4LISTEN 1 10 Connect4::AcceptFailed $1 } elseif (%request) { var %x $input(Request has expired,o) } else { ctcp $1 CONNECT4.REJECT } } alias Connect4::AcceptFailed { sockclose Connect4.LISTEN. $+ $nick Connect4::SendRequest $1 } on 1:socklisten:CONNECT4.LISTEN*: { .timerConnect4LISTEN off var %id $Connect4::UnusedID sockaccept %id Connect4::InitClient 1 %id sockclose $sockname } on 1:sockopen:CONNECT4.*: { Connect4::InitClient 2 $sockname } alias Connect4::InitClient { ;; Params: Server/client, client ID ;; Initiates the GUI and base variables var %Client $1,%id $2 hadd -m %id Turn 1 hadd -m %id Client %Client Connect4::Init %id ;; Send opponent name sockwrite -n %id 2 $+ $nick .timer $+ %id $+ KEEPALIVE 0 60 sockwrite -n %id 4 } alias Connect4::UnusedID { ;parameters: none ;Finds an ID that can be used as a hash table and window name. var %id Connect4. $+ $ticks while (($hget(%id)) || ($window(@ $+ %id)) || ($sock(%id))) { var %id Connect4. $+ $ticks } return %id } alias Connect4::Init { ;parameters: ;Initialises all values for the board, and GUI. hadd $1 Pieces $str(0,42) hadd $1 Wins 0 hadd $1 Losses 0 Connect4::InitGUI $1 } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Data Handeling ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; on 1:sockread:CONNECT4.*: { var %data,%id $sockname sockread %data goto $left(%data,1) ;;Place Piece :1 var %x $mid(%data,2) if (!$Connect4::TrySetPiece(%id,%x,2)) .timer 1 0 Connect4::Unverify %id return ;;Player sends name :2 hadd -m %id Opponent $mid(%data,2) Connect4::DrawNames %id return ;;ResetBoard Packet :3 Connect4::ResetBoard $sockname 1 return :4 return } alias Connect4::TrySetPiece { var %id $1, %x $2,%y 0,%pieces $hget(%id, pieces),%piece $3 while (%y < 8 && $mid(%pieces,$calc(%y * 7 + %x + 1),1)) { inc %y } if (%y > 5) || (%piece == 2 && $hget(%id,Client) == $hget(%id,Turn)) { return $false } var %pos $calc(%y * 7 + %x + 1) hadd -m %id pieces $left(%pieces,$calc(%pos - 1)) $+ %piece $+ $mid(%pieces,$calc(%pos + 1)) Connect4::DrawPiece -n %id %x %y 20 if (%piece == 2) hadd -m %id Turn $hget(%id,Client) else hadd -m %id Turn $iif($hget(%id,Client) == 1,2,1) Connect4::DrawNames %id if ($Connect4::CheckForWin(%id)) { var %winState $token($v1,1,32) var %winPos $token($v1,2-,32) if (%winState == 1) Connect4::RegisterWin %id %winPos if (%winState == 2) Connect4::RegisterLoss %id %winPos if (%winState == 3) Connect4::RegisterDraw %id } return $true } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; GUI ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; alias Connect4::InitGUI { ;parameters: ;Calculates the default values for the GUI, ;opens the window, then draws it. var %windowPadding 5 var %squareSize 40 hadd $1 squareSize %squareSize var %board.x %windowPadding var %board.y %windowPadding var %board.w $calc(%squareSize * 7) var %board.h $calc(%squareSize * 6) hadd $1 board.x %board.x hadd $1 board.y %board.y hadd $1 board.w %board.w hadd $1 board.h %board.h var %sideBar.x $calc(%board.x + %board.w + %windowPadding) var %sideBar.y %windowPadding var %sideBar.w 200 var %sideBar.h %board.h hadd $1 sideBar.x %sideBar.x hadd $1 sideBar.y %sideBar.y hadd $1 sideBar.w %sideBar.w hadd $1 sideBar.h %sideBar.h var %closeButton.w 80 var %closeButton.h 21 var %closeButton.x $calc(%sideBar.x + (%sideBar.w - %closeButton.w) / 2) var %closeButton.y $calc(%sideBar.y + %sideBar.h - %closeButton.h) hadd $1 closeButton.x %closeButton.x hadd $1 closeButton.y %closeButton.y hadd $1 closeButton.w %closeButton.w hadd $1 closeButton.h %closeButton.h var %window.w $calc(%sidebar.x + %sidebar.w + %windowPadding) var %window.h $calc(%board.y + %board.h + %windowPadding) hadd $1 window.w %window.w hadd $1 window.h %window.h window -aBdfp @ $+ $1 -1 -1 %window.w %window.h Connect4::Draw $1 } alias Connect4::Draw { ;parameters: [-n] ;Draws the whole Connect 4 Window. var %n if ($1 == -n) { var %n 1 tokenize 32 $2- } var %white $rgb(255, 255, 255) ;Clear the background drawrect -nrf @ $+ $1 %white 1 0 0 $hget($1,window.w) $hget($1,window.h) Connect4::DrawBoard -n $1 Connect4::DrawSideBarStatus -n $1 -1 Connecting... Connect4::DrawScore -n $1 Connect4::DrawCloseButton -n $1 if (!%n) { drawdot @ $+ $1 } } alias Connect4::DrawBoard { ;parameters: var %n if ($1 == -n) { var %n 1 tokenize 32 $2- } var %x $hget($1,board.x) var %y $hget($1,board.y) var %w $hget($1,board.w) var %h $hget($1,board.h) ;Draw board drawrect -nrf @ $+ $1 $rgb(240,240,240) 1 %x %y %w %h ;Draw board border drawrect -nr @ $+ $1 $rgb(200,200,200) 1 %x %y %w %h var %column 0 while (%column < 7) { var %row 0 while (%row < 6) { Connect4::DrawPiece -n $1 %column %row $2 inc %row } inc %column } if (!%n) { drawdot @ $+ $1 } } alias Connect4::DrawPiece { ;parameters: [-n] var %n if ($1 == -n) { var %n 1 tokenize 32 $2- } var %alpha $4 var %pieces $hget($1,pieces) var %piece $mid(%pieces,$calc($3 * 7 + $2 + 1),1) var %x $hget($1,board.x) var %y $hget($1,board.y) var %squareSize $hget($1,squareSize) inc %x $calc(%squareSize * $2) inc %y $calc(%squareSize * (5 - $3)) inc %alpha 20 if (%piece == 0) { var %colour $rgb(255, 255, 255) } elseif (%piece == 1) { var %colour $rgb($calc(0 + %alpha), $calc(0 + %alpha), $calc(0 + %alpha)) } elseif (%piece == 2) { var %colour $rgb(255, $calc(0 + %alpha), $calc(0 + %alpha)) } inc %x 4 inc %y 4 dec %squareSize 8 ;Draw piece drawrect -nrfe @ $+ $1 %colour 1 %x %y %squareSize %squareSize ;Draw border around piece drawrect -nre @ $+ $1 $iif(%alpha == 40,65535,$rgb(200,200,200)) 1 %x %y %squareSize %squareSize ; DrawBorder normal around last piece if ($hget($1,lastMove)) { drawrect -nre @ $+ $1 $rgb(200,200,200) 1 $token($v1,1,32) $token($v1,2,32) %squareSize %squareSize } hadd -m $1 lastMove %x %y if (!%n) { drawdot @ $+ $1 } } alias Connect4::DrawCloseButton { ;parameters: var %n if ($1 == -n) { var %n 1 tokenize 32 $2- } var %x $hget($1,closeButton.x) var %y $hget($1,closeButton.y) var %w $hget($1,closeButton.w) var %h $hget($1,closeButton.h) drawrect -nrd @ $+ $1 $rgb(0,0,0) 1 %x %y %w %h 3 3 var %text Close var %font Tahoma var %fontSize 13 var %colour $rgb(0,0,0) var %x $int($calc(%x + (%w - $width(%text,%font,%fontSize)) / 2)) var %y $int($calc(%y + (%h - $height(%text,%font,%fontSize)) / 2)) drawtext -nr @ $+ $1 %colour %font %fontSize %x %y %text if (!%n) { drawdot @ $+ $1 } } alias Connect4::DrawNames { ;parameters: var %n if ($1 == -n) { var %n 1 tokenize 32 $2- } var %id $1 var %turn $hget($1,Turn) var %x $hget($1,sideBar.x) var %y $hget($1,sideBar.y) var %w $hget($1,sideBar.w) var %h 100 var %center.x $calc(%x + %w / 2) var %center.y $calc(%y + %h / 2) var %colour $rgb(200,200,200) var %colour2 $rgb(160,160,240) var %colour3 $rgb(130,130,130) var %colour4 $rgb(240,160,160) var %size 20 var %font "Tahoma" drawrect -nrf @ $+ %id %Colour 1 %x %y %w %h drawrect -nr @ $+ %id %colour3 1 %x %y %w %h drawrect -nr @ $+ %id %colour3 1 %x %y %w $calc(%h / 2) inc %y 13 var %text $me var %x $calc(%center.x - $width(%text,Tahoma,%size) / 2 - 5) drawtext -nrbo @ $+ %id %colour3 $iif($hget(%id,Turn) == $hget(%id,Client),%colour2,%colour) %font %size %x %y %text inc %y 50 var %text $hget(%id,Opponent) var %x $calc(%center.x - $width(%text,Tahoma,%size) / 2 - 5) drawtext -nrbo @ $+ %id %colour3 $iif($v1 == $v2,%colour,%colour4) %font %size %x %y %text if (!%n) { drawdot @ $+ $1 } } alias Connect4::DrawSideBarStatus { ;Params: [-n] if ($1 == -n) { var %n 1 tokenize 32 $2- } var %id $1 var %turn $hget(%id,Turn) var %x $hget(%id,sideBar.x) var %y $hget(%id,sideBar.y) var %w $hget(%id,sideBar.w) var %h 100 var %center.x $calc(%x + %w / 2) var %center.y $calc(%y + %h / 2) var %colour $rgb(200,200,200) var %colour2 $iif($2 < 0,$rgb(130,130,130),$2) var %size 20 var %font "Tahoma" var %text $3- drawrect -nrf @ $+ %id %colour 1 %x %y %w %h drawrect -nr @ $+ %id %colour2 1 %x %y %w %h var %x $calc(%center.x - $width(%text,Tahoma,%size) / 2 - 5) var %y $calc(%center.y / 2 + 12) drawtext -nrbo @ $+ %id %colour2 %colour %font %size %x %y %text if (!%n) drawdot @ $+ %id } alias Connect4::DrawScore { var %n if ($1 == -n) { var %n 1 tokenize 32 $2- } var %id $1 var %turn $hget($1,Turn) var %x $hget($1,sideBar.x) var %y $hget($1,sideBar.y) + 105 var %w $hget($1,sideBar.w) var %h 100 var %center.x $calc(%x + %w / 2) var %center.y $calc(%y + %h / 2) var %colour $rgb(200,200,200) var %colour3 $rgb(130,130,130) var %size 15 var %font "Tahoma" drawrect -nrf @ $+ %id %Colour 1 %x %y %w %h drawrect -nr @ $+ %id %colour3 1 %x %y %w %h drawrect -nr @ $+ %id %colour3 1 %x %y %w $calc(%h / 2) var %wins $hget(%id,Wins) var %losses $hget(%id,Losses) inc %y 13 var %text Wins: $hget(%id,Wins) var %x $calc(%center.x - $width(%text,Tahoma,%size) / 2 - 5) drawtext -nrbo @ $+ %id %colour3 %colour %font %size %x %y %text inc %y 50 var %text Losses: $hget(%id,Losses) var %x $calc(%center.x - $width(%text,Tahoma,%size) / 2 - 5) drawtext -nrbo @ $+ %id %colour3 %Colour %font %size %x %y %text if (!%n) { drawdot @ $+ $1 } } alias Connect4::DrawEndGameText { ;;Params: var %n if ($1 == -n) { var %n 1 tokenize 32 $2- } var %id $1 var %x $hget($1,board.x) var %y $hget($1,board.y) var %w $hget($1,board.w) var %h $hget($1,board.h) if ($2 == Win) { var %text You Win! var %colour $rgb(0,0,255) } elseif ($2 == Lose) { var %text You Lose! var %colour $rgb(255,0,0) } elseif ($2 == Draw) { var %text Draw! var %colour $rgb(0,0,0) } else { return } var %font Tahoma var %size 50 var %x $calc(%x + (%w - $width(%text,%font,%size)) / 2) var %y $calc(%y + (%h - $height(%text,%font,%size)) / 2) drawtext -nr @ $+ $1 %colour %font %size %x %y %text Connect4::DrawScore $1 if (!%n) { drawdot @ $+ $1 } } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Register Win ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; alias Connect4::CheckForWin { ;parameters: var %pieces $hget($1,Pieces) ;Add spaces between each row var %rows $regsubex(%pieces,/(.{7})/g,\1 $+ $chr(32)) ;Horizontal if ($len($token($remove($regsubex(%rows,/(1|2)\1{3}/,\1 $+ $chr(2)),$chr(32)),1,2)) < 42) { var %pos $v1,%pos2 %pos + 1, %pos3 %pos2 + 1, %pos4 %pos3 + 1 return $regml(1) %pos %pos2 %pos3 %pos4 } ;Vertical elseif ($len($token($remove($regsubex(%rows,/(1|2)(.{7}\1){3}/,\1 $+ $chr(2)),$chr(32)),1,2)) < 42) { var %pos $v1,%pos2 %pos + 7, %pos3 %pos2 + 7, %pos4 %pos3 + 7 return $regml(1) %pos %pos2 %pos3 %pos4 } ;Diagonal, bottom left to top right elseif ($len($token($remove($regsubex(%rows,/(1|2)(.{8}\1){3}/,\1 $+ $chr(2)),$chr(32)),1,2)) < 42) { var %pos $v1,%pos2 %pos + 8, %pos3 %pos2 + 8, %pos4 %pos3 + 8 return $regml(1) $v1 %pos %pos2 %pos3 %pos4 } ;Diagonal, up left elseif ($len($token($remove($regsubex(%rows,/(1|2)(.{6}\1){3}/,\1 $+ $chr(2)),$chr(32)),1,2)) < 42) { var %pos $v1,%pos2 %pos + 6, %pos3 %pos2 + 6, %pos4 %pos3 + 6 return $regml(1) $v1 %pos %pos2 %pos3 %pos4 } ;Board is full elseif (!$regex(%pieces,/0/)) { return 3 } } alias Connect4::RegisterWin { ;parameters var %id $1 hinc -m %id Wins var %l $hget(%id,lastMove),%size $hget(%id,squareSize) - 8 Connect4::DrawBoard -n %id 160 Connect4::DrawSideBarStatus -n %id $rgb(50,50,255) Winner! var %a 1 ;echo @Debug WINN:::: $2- while ($token($2-,%a,32)) { var %y $int($calc(($v1 - 1) / 7)) var %x $int($calc(($v1 - 1) % 7)) Connect4::DrawPiece -n %id %x %y 40 inc %a } drawRect -nre @ $+ %id 65535 1 $token(%l,1,32) $token(%l,2,32) %size %size Connect4::DrawEndGameText %id Win hadd -m %id Turn 0 } alias Connect4::RegisterLoss { ;paramters var %id $1 hinc -m %id Losses var %l $hget(%id,lastMove),%size $hget(%id,squareSize) - 8 Connect4::DrawBoard -n %id 160 Connect4::DrawSideBarStatus -n %id $rgb(255,50,50) Loser! var %a 1 while ($token($2-,%a,32)) { var %y $int($calc(($v1 - 1) / 7)) var %x $int($calc(($v1 - 1) % 7)) Connect4::DrawPiece -n %id %x %y 40 inc %a } drawRect -nre @ $+ %id 65535 1 $token(%l,1,32) $token(%l,2,32) %size %size Connect4::DrawEndGameText %id Lose .timer $+ %id $+ RESET -m 1 7500 Connect4::ResetBoard %id 0 hadd -m %id Turn 0 } alias Connect4::RegisterDraw { ;paramters var %id $1 var %firstMove $iif($hget(%id,Turn) == $hget(%id,Client),0,1) Connect4::DrawEndGameText -n %id Draw Connect4::DrawBoard -n %id 160 Connect4::DrawSideBarStatus %id $rgb(240,240,240) Tie! if (!%firstMove) { .timer $+ %id $+ RESET 1 5 Connect4::ResetBoard %id 0 } hadd -m %id Turn 0 } alias Connect4::ResetBoard { ;;Params: var %id $1 if ($window(@ $+ %id)) { hadd -m %id Pieces $str(0,42) Connect4::DrawBoard -n %id 0 if ($2) hadd -m %id Turn $hget($1,Client) else { hadd -m %id Turn $iif($hget($1,Client) == 1,2,1) sockwrite -n %id 3 } Connect4::DrawNames %id } } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Mouse events ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; menu @Connect4.* { sclick: if ($hget($mid($active,2))) Connect4::Click $mid($active,2) dclick: if ($hget($mid($active,2))) Connect4::Click $mid($active,2) } alias Connect4::Click { var %id $1 ;parameters: ;Called when mouse is clicked in a Connect 4 window. var %board.x $hget($1,board.x) var %board.y $hget($1,board.y) var %board.w $hget($1,board.w) var %board.h $hget($1,board.h) var %squareSize $hget($1,squaresize) if ($inrect($mouse.x, $mouse.y, %board.x, %board.y, %board.w, %board.h)) { var %column $int($calc(($mouse.x - %board.x) / %squareSize)) var %row $calc(5 - $int($calc(($mouse.y - %board.y) / %squareSize))) ;; Imk0tter code :P if ($hget(%id,Turn) == $hget(%id,Client)) { if ($Connect4::TrySetPiece(%id,%column,1)) { sockwrite -n %id 1 $+ %column } } ;; End Imk0tter } elseif ($inroundrect($mouse.x,$mouse.y,$hget($1,closeButton.x),$hget($1,closeButton.y),$hget($1,closeButton.w),$hget($1,closeButton.h),3,3)) { Connect4::DisconnectClient %id } } ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Closing events ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; on 1:sockclose:CONNECT4.*: { Connect4::DisconnectClient $sockname } alias Connect4::DisconnectClient { ;Parameters var %id $1,%closedWindow $2 if ($sock(%id)) sockclose %id if (!%closedwindow) { Connect4::DrawSidebarStatus -n %id $rgb(255,0,0) Disconnected... Connect4::DrawBoard %id 160 } if ($hget(%id)) hfree %id if ($timer(%id $+ RESET)) .timer $+ %id $+ RESET off if ($timer(%id $+ KEEPALIVE)) .timer $+ %id $+ KEEPALIVE off ;Draw "Disconnected..." text } on 1:close:@: { if (@Connect4.* iswm $target) { var %id $mid($target,2) Connect4::DisconnectClient %id 1 } } alias Connect4::Unverify { ;; Parameters: ID Connect4::DisconnectClient %id var %id $1, %x $input($hget(%id,Opponent) has sent a false move.. Disconnecting client.,o) }