Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
90bebe9
Stubbed out farkle game
trixtur Oct 1, 2022
e1da347
rename quit to reload
kpayne-ddm Oct 1, 2022
4bc4c98
functionality to track the reload in cache
kpayne-ddm Oct 2, 2022
7223287
Code consistent with building the RPS game.
trixtur Oct 1, 2022
1acde4d
Added TODO about multi
trixtur Oct 1, 2022
19d4d33
fix dm bug
kpayne-ddm Oct 2, 2022
8c1f113
rework how user is unmarshalled from redis
kpayne-ddm Oct 2, 2022
0fa7d6d
fix getting users from redis
kpayne-ddm Oct 2, 2022
d2383f3
add another message on reload
kpayne-ddm Oct 2, 2022
26eabfe
Started refactor, this is the basic skeleton
trixtur Oct 2, 2022
a7e64f2
Built Get Users.
trixtur Oct 2, 2022
b27fffb
Continued work on refactor. RPS still does not function.
trixtur Oct 3, 2022
1c9832e
Fixed issue with channel. Still doesn't finish.
trixtur Oct 3, 2022
8dd2e79
Use channel when updating user.
trixtur Oct 3, 2022
aa88802
Clean RPS when finished.
trixtur Oct 3, 2022
4682b6c
Deletes game from redis.
trixtur Oct 3, 2022
bfb806b
Fixed key handling in RPS.
trixtur Oct 3, 2022
463241e
Merge branch 'main' into farkle-game
trixtur Oct 3, 2022
819ac1d
Initial work for Farkle. Lots more to do
kr0wned Oct 11, 2022
923f0c6
Merge branch 'farkle-game' of https://github.com/PyrousNET/pyrous-gob…
kr0wned Oct 11, 2022
529987e
Merge branch 'main' into farkle-game
trixtur Nov 5, 2022
41686e3
Merge branch 'farkle-game' of github.com:PyrousNET/pyrous-gobot into …
trixtur Nov 5, 2022
9768d16
Merge branch 'main' into farkle-game
trixtur Nov 6, 2022
d221746
Merge branch 'main' into farkle-game
trixtur Nov 6, 2022
a39a602
Merge branch 'main' into farkle-game
trixtur Feb 1, 2023
2c1b51d
Move web socket to config
trixtur Jan 12, 2023
c205304
Fixes the say command for DMs.
trixtur Jan 19, 2023
f8e1a46
Revert "Fixes the say command for DMs."
trixtur Jan 19, 2023
5bc840c
Revert "Revert "Fixes the say command for DMs.""
trixtur Jan 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions internal/comms/comms.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,26 +47,35 @@ func (h *MessageHandler) SendMessage(r *Response) {
}
}

dmchannel, _, _ := h.Mm.Client.CreateDirectChannel(r.UserId, h.Mm.BotUser.Id)
if r.Type != "shutdown" {
dmchannel, _, _ := h.Mm.Client.CreateDirectChannel(r.UserId, h.Mm.BotUser.Id)
if r.ReplyChannelId == dmchannel.Id {
r.Type = "dm"
}
}

if r.Type == "dm" {
if strings.HasPrefix(checkMsg[0], "/") {
commandParts := strings.Split(r.Message, "\"")
if commandParts[1] != "" {
post.Message = commandParts[1]
}
}

}

if r.Message != "" {
switch r.Type {
case "post":
err = h.Mm.SendMsgToChannel(r.Message, r.ReplyChannelId, post)
case "command":
err = h.Mm.SendCmdToChannel(r.Message, r.ReplyChannelId, post)
case "dm":
c, _, err := h.Mm.Client.CreateDirectChannel(r.UserId, h.Mm.BotUser.Id)
if err != nil {
panic(err)
}

post.ChannelId = c.Id
post.ChannelId = dmchannel.Id
_, _, err = h.Mm.Client.CreatePost(post)
case "shutdown":
c, _, err := h.Mm.Client.CreateDirectChannel(r.UserId, h.Mm.BotUser.Id)
Expand Down
256 changes: 251 additions & 5 deletions internal/handler/games/farkle.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,260 @@
package games

import "fmt"
import (
"encoding/json"
"fmt"
"github.com/pyrousnet/pyrous-gobot/internal/cache"
"reflect"
"math/rand"
"time"
"strings"

"github.com/google/uuid"
"github.com/pyrousnet/pyrous-gobot/internal/users"
)

type Farkle struct {
GameID string `json:"game-id"` //ID of this farkle game
FarklePlaying bool `json:"farkle-playing"` //If the game has started
FarkleMembers []string `json:"farkle-members"` //Members of the farkle game
FarkleTotal int `json:"farkle-total"` //TODO: How to track scores
FarkleTemp int `json:"farkle-temp"` //Track current rolling total
DiceHolder string `json:"dice-holder"` //User currently holding the dice
DiceThrown []int `json:"dice-thrown"` //Current dice list
DiceToThrow int `json:"dice-to-throw"` //Number of dice which can be thrown
Name string `json:"name"` //Name of the farkle user.
}

var DICE = 6;

func (h BotGameHelp) Farkle(request BotGame) (response HelpResponse) {
response.Help = "Play Farkle in the current channel."
response.Description = `Play a game of Farkle!\n
Usage: $farklestart - Create a new game of Farkle.
Usage: $farklejoin - Join a game of Farkle already created.
Usage: $farkle - Throw your dice in the current game of Farkle (if they are yours to throw).
Usage: $farkle n # - Attempt to rethrow # of dice.
Usage: $farkle y - Keeps all the dice and ends your turn.` //TODO: $ should come from settings

return response
}

func (bg BotGame) Farkle(event BotGame) (response Response, err error) {
response.Type = "command"
response.Message = fmt.Sprintf("/echo %s would like to play a game of Farkle.", event.sender)
response.Type = "multi"
var choice, channel string

fmt.Sscanf(event.body, "%s %s", &channel, &choice) //TODO: Do we want to allow joining from other channels?
foundChannel, cErr := event.mm.GetChannelByName(channel)
if cErr == nil && foundChannel != nil {
response.Channel = foundChannel.Id
} else {
foundChannel = event.ReplyChannel
}
playerUser, _, err := users.GetUser(strings.TrimLeft(event.sender, "@"), event.cache) //Gets the current user's details
if err != nil {
return Response{}, err
}
player, perr := getPlayer(playerUser, foundChannel.Id, event.cache)
opponent, oErr := findApponent(event, player, foundChannel.Id)
if perr != nil || !playing(player) {
if oErr == nil && playing(opponent) {
channelId, ok, _ := event.cache.Get(opponent.RpsPlaying)
if ok && event.ReplyChannel != nil && channelId == foundChannel.Id {
player.RpsPlaying = opponent.RpsPlaying
response.Type = "dm"
response.Message = fmt.Sprintf("Would you like to throw Rock, Paper or Scissors (Usage: $rps %s rock)", event.ReplyChannel.Name)
}
} else { //TODO: This is the logic to start a game.
id, e := uuid.NewRandom()
event.cache.Put(id.String(), event.ReplyChannel.Id)
response.Message = fmt.Sprintf("Would you like to throw Rock, Paper or Scissors (Usage: $rps %s rock)##%s is looking for an opponent in RPS.", event.ReplyChannel.Name, event.sender)
if e != nil {
return response, e
}
player.RpsPlaying = id.String() //TODO: This is where the player is setup.
}
}

if event.body != "" {
switch strings.ToLower(choice) {
case "rock", "paper", "scissors":
player.Rps = strings.ToLower(choice)
response.Type = "dm"
response.Message = fmt.Sprintf("I have you down for: %s", strings.Title(strings.ToLower(choice)))
default:
response.Type = "dm"
response.Message = fmt.Sprintf(`Uh, %s isn't an option. Try rock, paper or scissors'`, choice)
}
}

if oErr == nil && opponent.Name != "" {
winners, hasWinner := getWinner(player, opponent)
if hasWinner {
channelId, ok, _ := event.cache.Get(player.RpsPlaying)
response.Type = "command"
if ok {
response.Channel = channelId.(string)
if len(winners) > 1 {
response.Message = fmt.Sprintf("/echo The RPS game between %s and %s ended in a draw.", player.Name, opponent.Name)
} else {
response.Message = fmt.Sprintf("/echo The RPS game between %s and %s ended with %s winning.", player.Name, opponent.Name, winners[0].Name)
}
}

deleteGame(player.RpsPlaying, event.cache)
deleteRps(player, foundChannel.Id, event.cache)
deleteRps(opponent, foundChannel.Id, event.cache)
return response, err
}

updateRps(opponent, foundChannel.Id, event.cache)
}

updateRps(player, foundChannel.Id, event.cache)

return response, err
}

func checkGame(players Farkle) (Farkle, error) {
}

func playing(player Farkle) bool {
return player.GameID != ""
}

func getPlayer(player users.User, chanId string, c cache.Cache) (Farkle, error) {
key := fmt.Sprintf("%s-%s-%s", "farkle", player.Name, chanId)
var farkle Farkle
r, ok, _ := c.Get(key)
if ok {
if reflect.TypeOf(r).String() != "[]uint8" {
json.Unmarshal([]byte(r.(string)), &farkle)
} else {
json.Unmarshal(r.([]byte), &farkle)
}
return farkle, nil
}
return Farkle{Name: player.Name}, fmt.Errorf("not found")
}


// TODO - for kr0w?
//TODO: modify or remove the following functions.

return response, nil
func sameGame(player RPS, opponent RPS) bool {
return player.RpsPlaying == "" || player.RpsPlaying == opponent.RpsPlaying
}

func differentUser(player RPS, opponent RPS) bool {
return player.Name != opponent.Name
}

func findApponent(event BotGame, forPlayer RPS, chanId string) (RPS, error) {
us, ok, err := users.GetUsers(event.cache)
rpsUs, ok, gPerr := getPlayers(us, chanId, event.cache)
var opponent RPS
var found = false

if us == nil {
return RPS{}, fmt.Errorf("no opponent")
}

if ok {
for _, u := range rpsUs {
if playing(u) && sameGame(forPlayer, u) && differentUser(forPlayer, u) {
opponent = u
found = true
}
}
} else {
return RPS{}, gPerr
}

if !found {
err = fmt.Errorf("no opponent")
}
return opponent, err
}

func getWinner(player RPS, opponent RPS) ([]RPS, bool) {
var hasWinner bool = false
var winners []RPS

if player.Rps == "" {
return []RPS{}, false
}

if opponent.Rps == "" {
return []RPS{}, false
}

if player.Rps == opponent.Rps {
winners = append(winners, player)
winners = append(winners, opponent)
hasWinner = true
} else if strings.ToLower(player.Rps) == "rock" {
if strings.ToLower(opponent.Rps) == "paper" {
winners = append(winners, opponent)
hasWinner = true
} else if strings.ToLower(opponent.Rps) == "scissors" {
winners = append(winners, player)
hasWinner = true
}
} else if strings.ToLower(player.Rps) == "paper" {
if strings.ToLower(opponent.Rps) == "scissors" {
winners = append(winners, opponent)
hasWinner = true
} else if strings.ToLower(opponent.Rps) == "rock" {
winners = append(winners, player)
hasWinner = true
}
} else if strings.ToLower(player.Rps) == "scissors" {
if strings.ToLower(opponent.Rps) == "rock" {
winners = append(winners, opponent)
hasWinner = true
} else if strings.ToLower(opponent.Rps) == "paper" {
winners = append(winners, player)
hasWinner = true
}
}

return winners, hasWinner
}

func getPlayers(pUsers []users.User, chanId string, c cache.Cache) ([]RPS, bool, error) {
var rpsUsers []RPS
for _, u := range pUsers {
key := fmt.Sprintf("%s-%s-%s", "rps", u.Name, chanId)
r, ok, _ := c.Get(key)
var rps RPS
if ok {
if reflect.TypeOf(r).String() != "[]uint8" {
json.Unmarshal([]byte(r.(string)), &rps)
} else {
json.Unmarshal(r.([]byte), &rps)
}

rpsUsers = append(rpsUsers, rps)
}
}
if len(rpsUsers) == 0 {
return []RPS{}, false, nil
}
return rpsUsers, true, nil
}

func updateRps(playerRps RPS, chanId string, c cache.Cache) (RPS, error) {
key := fmt.Sprintf("%s-%s-%s", "rps", playerRps.Name, chanId)
p, _ := json.Marshal(playerRps)
c.Put(key, p)
return playerRps, nil
}

func deleteRps(playerRps RPS, chanId string, c cache.Cache) {
key := fmt.Sprintf("%s-%s-%s", "rps", playerRps.Name, chanId)
c.Clean(key)
}
func deleteGame(uuid string, c cache.Cache) {
c.Clean(uuid)
}


11 changes: 6 additions & 5 deletions internal/mmclient/mmclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ type MMClient struct {
}

type Server struct {
HOST string `yaml:"host"`
PROTOCOL string `yaml:"protocol"`
PORT string `yaml:"port"`
CACHE_URI string `yaml:"cache_uri"`
HOST string `yaml:"host"`
PROTOCOL string `yaml:"protocol"`
PORT string `yaml:"port"`
CACHE_URI string `yaml:"cache_uri"`
WS_PROTOCOL string `yaml:"ws_protocol"`
}

// Documentation for the Go driver can be found
Expand Down Expand Up @@ -240,7 +241,7 @@ func (c *MMClient) SendMsgToChannel(msg string, channelId string, prePost *model

func (c *MMClient) NewWebSocketClient() (*model.WebSocketClient, error) {
var err error
uri := fmt.Sprintf("wss://%s:%s", c.Server.HOST, c.Server.PORT)
uri := fmt.Sprintf("%s://%s:%s", c.Server.WS_PROTOCOL, c.Server.HOST, c.Server.PORT)

ws, appErr := model.NewWebSocketClient4(uri, c.Client.AuthToken)
if appErr != nil {
Expand Down
9 changes: 5 additions & 4 deletions internal/settings/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import (

type Config struct {
Server struct {
HOST string `yaml:"host"`
PROTOCOL string `yaml:"protocol"`
PORT string `yaml:"port"`
CACHE_URI string `yaml:"cache_uri"`
HOST string `yaml:"host"`
PROTOCOL string `yaml:"protocol"`
PORT string `yaml:"port"`
CACHE_URI string `yaml:"cache_uri"`
WS_PROTOCOL string `yaml:"ws_protocol"`
} `yaml:"server"`
Bot struct {
SAMPLE_NAME string `yaml:"sample_name"`
Expand Down