Browse Source

Initial commit

pull/1/head
Gregory Rudolph 3 years ago
commit
d70b69d71f
Signed by: rudi
GPG Key ID: EF64F3CBD1A1EBDD
  1. 1
      .gitignore
  2. 56
      ghostTypes.go
  3. 103
      ghosts.json
  4. 5
      go.mod
  5. 6
      go.sum
  6. 195
      main.go
  7. 51
      types.go

1
.gitignore vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
Phasmobot

56
ghostTypes.go

@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
func setupGhostTypes() {
var c []Spookster
confFile, _ := ioutil.ReadFile("ghosts.json")
err := json.Unmarshal([]byte(confFile), &c)
if err != nil {
return
}
ghostTypes = c
fmt.Printf("Loaded %+v ghost types\n", len(ghostTypes))
}
func (g *Game) EliminateGhosts(newEvidence int) {
var types []Spookster
var evidence []int
for _, v := range g.PossibleGhosts {
possible := false
for _, e := range v.Evidence {
if e == newEvidence {
possible = true
}
}
if possible {
types = append(types, v)
evidence = append(evidence, v.Evidence...)
}
}
g.PossibleGhosts = types
g.PossibleEvidence = removeDuplicateValues(evidence)
games[g.Identifier] = *g
}
// https://www.geeksforgeeks.org/how-to-remove-duplicate-values-from-slice-in-golang/
func removeDuplicateValues(intSlice []int) []int {
keys := make(map[int]bool)
list := []int{}
// If the key(values of the slice) is not equal
// to the already present value in new slice (list)
// then we append it. else we jump on another element.
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
return list
}

103
ghosts.json

@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
[
{
"GhostType": "Banshee",
"GhostName": "",
"Evidence": [0, 1, 4],
"Strengths": "A Banshee will only target one person at a time.",
"Weaknesses": "Banshees fear the Crucifix Cross and will be less aggressive when near one.",
"Description": "A Banshee is a natural hunter and will attack anything. It has been known to stalk it’s prey one at a time until making it’s kill."
},
{
"GhostType": "Demon",
"GhostName": "",
"Evidence": [3, 2, 1],
"Description": "A Demon is one of the worst Ghosts you can encounter. It has been known to attack without a reason.",
"Strengths": "Demons will attack more often than any other Ghost.",
"Weaknesses": "Asking a Demon successful questions on the Ouija Board won’t lower the users sanity."
}, {
"GhostType": "Jinn",
"GhostName": "",
"Evidence": [0, 2, 5],
"Description": "A Jinn is a territorial Ghost that will attack when threatened. It has also been known to be able to travel at significant speed.",
"Strengths": "A Jinn will travel at a a faster speed if it’s victim is far away.",
"Weaknesses": "Turning off the locations power source will prevent the Jinn from using it’s ability."
}, {
"GhostType": "Mare",
"GhostName": "",
"Evidence": [2, 5, 1],
"Description": "A Mare is the source of all nightmares, making it most powerful in the darkness.",
"Strengths": "A Mare will have an increased chance to attack in the dark.",
"Weaknesses": "Turning the lights ON around the Mare will lower it’s chance to attack."
}, {
"GhostType": "Oni",
"GhostName": "",
"Evidence": [0, 3, 2],
"Description": "Oni’s are a cousin to the Demon and possess extreme strength. There have been rumors that they become more active around their prey.",
"Strengths": "Oni’s are more active when people are nearby and have been seen moving objects at great speed.",
"Weaknesses": "Being more active will make the Oni easier to find and identify."
}, {
"GhostType": "Phantom",
"GhostName": "",
"Evidence": [0, 5, 1],
"Description": "A Phantom is a Ghost that can possess the living, most commonly summoned by a Ouija Board. It also induces fear into those around it.",
"Strengths": "Looking at a Phantom will considerably drop your sanity.",
"Weaknesses": "Taking a photo of the Phantom will make it temporarily disappear."
}, {
"GhostType": "Poltergeist",
"GhostName": "",
"Evidence": [2, 4, 5],
"Description": "One of the most famous Ghosts, a Poltergeist, also known as a noisy ghost that can manipulate objects around it to spread fear into it’s victims.",
"Strengths": "A Poltergeist can throw huge amounts of objects at once.",
"Weaknesses": "A Poltergeist is almost ineffective in an empty room."
}, {
"GhostType": "Revenant",
"GhostName": "",
"Evidence": [0, 3, 4],
"Description": "They are slow but violent ghosts that will attack everyone indiscriminately. They also travel at a greater speed like Jinn while hunting.",
"Strengths": "Travels faster while hunting.",
"Weaknesses": "If you are hidden from the Revenant, their speed drops, and they travel slowly."
}, {
"GhostType": "Shade",
"GhostName": "",
"Evidence": [0, 3, 5],
"Description": "A Shade is known to be a Shy Ghost. There is evidence that a Shade will stop all paranormal activity if there are multiple people nearby.",
"Strengths": "Being shy means the Ghost will be harder to find.",
"Weaknesses": "The Ghost will not enter hunting mode if there is multiple people nearby."
}, {
"GhostType": "Spirit",
"GhostName": "",
"Evidence": [3, 2, 4],
"Description": "A Spirit is the most common Ghost you will come across however it is still very powerful and dangerous. They are usually discovered at one of their hunting grounds after an unexplained death.",
"Strengths": "None.",
"Weaknesses": "Using Smudge Sticks on a Spirit will stop it attacking for a long period of time."
}, {
"GhostType": "Wraith",
"GhostName": "",
"Evidence": [4, 1, 2],
"Description": "A Wraith is one of the most dangerous Ghosts you will find. It is also the only known Ghost that has the ability of flight and has sometimes been known to travel through walls.",
"Strengths": "Wraiths almost never touch the ground meaning it can’t be tracked by footsteps.",
"Weaknesses": "Wraiths have a toxic reaction to Salt."
}, {
"GhostType": "Yurei",
"GhostName": "",
"Evidence": [5, 3, 1],
"Description": "A Yurei is a Ghost that has returned to the physical world, usually for the purpose of revenge or pure hatred.",
"Strengths": "Yurei’s have been known to have a stronger effect on peoples sanity.",
"Weaknesses": "Smudging the Yurei’s room will cause it to not wander around the location for a long time."
}, {
"GhostType": "Yokai",
"GhostName": "",
"Evidence": [2, 5, 3],
"Description": "A Yokai is a common type of ghost that is attracted to human voices. They can usually be found haunting family homes.",
"Strengths": "Talking near a Yokai will anger it and increase it's chance of attacking.",
"Weaknesses": "When hunting a Yokai can only hear voices close to it."
}, {
"GhostType": "Hantu",
"GhostName": "",
"Evidence": [4, 5, 3],
"Description": "A Hantu is a rare ghost that can be found in hot climates. They are known to attack often during cold weather.",
"Strengths": "Lower temperatures can cause the Hantu to move at faster speeds.",
"Weaknesses": "A Hantu will move slower in warmer areas."
}
]

5
go.mod

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
module git.nightmare.haus/rudi/Phasmobot
go 1.16
require github.com/bwmarrin/discordgo v0.23.2

6
go.sum

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
github.com/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4=
github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

195
main.go

@ -0,0 +1,195 @@ @@ -0,0 +1,195 @@
package main
import (
"flag"
"fmt"
"os"
"os/signal"
"strings"
"syscall"
"github.com/bwmarrin/discordgo"
)
var (
dg *discordgo.Session
token string
gitCommit string
ghostTypes []Spookster
games = make(map[string]Game)
fingeyEmoji = "🖐"
freezingEmoji = "❄"
spiritBoxEmoji = "📻"
ghostWritingEmoji = "📖"
emf5Emoji = "🚥"
ghostOrbsEmoji = "⚪"
)
func init() {
flag.StringVar(&token, "t", "", "Bot Token")
flag.Parse()
}
func main() {
if token == "" {
fmt.Println("No token provided. Please run: phasmobot -t <bot token>")
}
go setupGhostTypes()
var err error
dg, err = discordgo.New("Bot " + token)
if err != nil {
fmt.Println("Unable to create bot using token.")
}
err = dg.Open()
if err != nil {
fmt.Println("Unable to create bot using token.")
}
dg.AddHandler(ready)
dg.AddHandler(messageCreate)
dg.AddHandler(readReactions)
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
<-sc
dg.Close()
}
func ready(s *discordgo.Session, event *discordgo.Ready) {
// Set the playing status.
s.UpdateGameStatus(0, fmt.Sprintf("PhasmoBot %+v", gitCommit))
}
func readReactions(s *discordgo.Session, m *discordgo.MessageReactionAdd) {
if _, ok := games[m.ChannelID]; !ok {
return
}
if m.UserID == s.State.User.ID {
return
}
fmt.Println("Checking reaction from ", m.UserID)
g := games[m.ChannelID]
if m.Emoji.Name == fingeyEmoji {
g.Evidence = append(g.Evidence, EMF5)
} else if m.Emoji.Name == freezingEmoji {
g.Evidence = append(g.Evidence, FreezingTemps)
} else if m.Emoji.Name == spiritBoxEmoji {
g.Evidence = append(g.Evidence, SpiritBox)
} else if m.Emoji.Name == ghostWritingEmoji {
g.Evidence = append(g.Evidence, GhostWriting)
} else if m.Emoji.Name == emf5Emoji {
g.Evidence = append(g.Evidence, EMF5)
} else if m.Emoji.Name == ghostOrbsEmoji {
g.Evidence = append(g.Evidence, GhostOrbs)
} else {
go s.MessageReactionRemove(m.ChannelID, g.PostID, m.Emoji.ID, m.UserID)
}
go s.MessageReactionRemove(m.ChannelID, g.PostID, fingeyEmoji, "@me")
go s.MessageReactionRemove(m.ChannelID, g.PostID, freezingEmoji, "@me")
go s.MessageReactionRemove(m.ChannelID, g.PostID, spiritBoxEmoji, "@me")
go s.MessageReactionRemove(m.ChannelID, g.PostID, ghostWritingEmoji, "@me")
go s.MessageReactionRemove(m.ChannelID, g.PostID, emf5Emoji, "@me")
go s.MessageReactionRemove(m.ChannelID, g.PostID, ghostOrbsEmoji, "@me")
g.EliminateGhosts(g.Evidence[len(g.Evidence)-1])
for _, v := range g.PossibleEvidence {
switch v {
case 0:
go s.MessageReactionAdd(m.ChannelID, g.PostID, emf5Emoji)
case 1:
go s.MessageReactionAdd(m.ChannelID, g.PostID, freezingEmoji)
case 2:
go s.MessageReactionAdd(m.ChannelID, g.PostID, spiritBoxEmoji)
case 3:
go s.MessageReactionAdd(m.ChannelID, g.PostID, ghostWritingEmoji)
case 4:
go s.MessageReactionAdd(m.ChannelID, g.PostID, fingeyEmoji)
case 5:
go s.MessageReactionAdd(m.ChannelID, g.PostID, ghostOrbsEmoji)
}
}
if len(g.Evidence) == 3 {
s.GuildMemberNickname(m.GuildID, "@me", "")
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("%+v was a %+v", g.Ghost.GhostName, g.PossibleGhosts[0].GhostType))
}
games[m.ChannelID] = g
}
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
if m.Author.ID == s.State.User.ID {
return
}
if !strings.HasPrefix(m.Content, "!") {
return
}
if _, ok := games[m.ChannelID]; !ok || strings.HasPrefix(m.Content, "!reset") {
games[m.ChannelID] = Game{}
}
g := games[m.ChannelID]
parts := strings.Split(m.Content, " ")
if strings.HasPrefix(m.Content, "!map") {
g.MapName = parts[1]
}
if strings.HasPrefix(m.Content, "!name") {
g.Ghost.GhostName = strings.Join(parts[1:], " ")
s.GuildMemberNickname(m.GuildID, "@me", g.Ghost.GhostName)
}
if strings.HasPrefix(m.Content, "!difficulty") {
g.Difficulty = parts[1]
}
if strings.HasPrefix(m.Content, "!room") {
g.RoomID = parts[1]
}
if strings.HasPrefix(m.Content, "!o") {
if strings.Contains(m.Content, "emf") {
g.Objective = append(g.Objective, EMF)
}
if strings.Contains(m.Content, "photo") {
g.Objective = append(g.Objective, Photo)
}
if strings.Contains(m.Content, "event") {
g.Objective = append(g.Objective, Event)
}
if strings.Contains(m.Content, "crucifix") {
g.Objective = append(g.Objective, Crucifix)
}
if strings.Contains(m.Content, "motion") {
g.Objective = append(g.Objective, Motion)
}
if strings.Contains(m.Content, "clean") {
g.Objective = append(g.Objective, SmudgeCleanse)
}
if strings.Contains(m.Content, "hunt") {
g.Objective = append(g.Objective, SmudgeHunt)
}
if strings.Contains(m.Content, "salt") {
g.Objective = append(g.Objective, Salt)
}
if strings.Contains(m.Content, "candle") {
g.Objective = append(g.Objective, Candle)
}
if strings.Contains(m.Content, "sanity") {
g.Objective = append(g.Objective, LowSanity)
}
if strings.Contains(m.Content, "escape") {
g.Objective = append(g.Objective, MemberEscape)
}
if strings.Contains(m.Content, "death") {
g.Objective = append(g.Objective, NoDeaths)
}
}
if len(g.Objective) == 3 {
post, _ := s.ChannelMessageSend(m.ChannelID, "The investigation begins! Click below to log evidence.")
g.PossibleGhosts = append(g.PossibleGhosts, ghostTypes...)
g.PostID = post.ID
s.MessageReactionAdd(m.ChannelID, post.ID, fingeyEmoji)
s.MessageReactionAdd(m.ChannelID, post.ID, freezingEmoji)
s.MessageReactionAdd(m.ChannelID, post.ID, spiritBoxEmoji)
s.MessageReactionAdd(m.ChannelID, post.ID, ghostWritingEmoji)
s.MessageReactionAdd(m.ChannelID, post.ID, emf5Emoji)
s.MessageReactionAdd(m.ChannelID, post.ID, ghostOrbsEmoji)
}
games[m.ChannelID] = g
}

51
types.go

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
package main
// Evidence Types
const (
EMF5 = iota // 0
FreezingTemps // 1
SpiritBox // 2
GhostWriting // 3
Fingerprints // 4
GhostOrbs // 5
)
// Bonus Objectives
const (
Photo = iota
Event
Motion
Crucifix
EMF
SmudgeCleanse
SmudgeHunt
Salt
Candle
LowSanity
MemberEscape
NoDeaths
)
// Game for Phasbot
type Game struct {
Identifier string
PostID string
MapName string
Ghost Spookster
PossibleGhosts []Spookster
PossibleEvidence []int
Difficulty string
RoomID string
Evidence []int
Objective []int
}
// Ghost type (but didn't want to call it ghost bc variable name)
type Spookster struct {
GhostType string
GhostName string
Evidence []int
Strengths string
Weaknesses string
Description string
}
Loading…
Cancel
Save