diff --git a/game/room/lobby.go b/game/room/lobby.go index 150ec8c..dcb672f 100644 --- a/game/room/lobby.go +++ b/game/room/lobby.go @@ -28,6 +28,7 @@ import ( "github.com/pangbox/server/database/accounts" gamemodel "github.com/pangbox/server/game/model" gamepacket "github.com/pangbox/server/game/packet" + "github.com/pangbox/server/gameconfig" log "github.com/sirupsen/logrus" orderedmap "github.com/wk8/go-ordered-map/v2" "golang.org/x/sync/errgroup" @@ -35,10 +36,11 @@ import ( type Lobby struct { actor.Base[LobbyEvent] - logger *log.Entry - storage *Storage - players *orderedmap.OrderedMap[uint32, *LobbyPlayer] - accounts *accounts.Service + logger *log.Entry + storage *Storage + players *orderedmap.OrderedMap[uint32, *LobbyPlayer] + accounts *accounts.Service + configProvider gameconfig.Provider } type LobbyPlayer struct { @@ -47,12 +49,13 @@ type LobbyPlayer struct { Joined time.Time } -func NewLobby(ctx context.Context, logger *log.Entry, accounts *accounts.Service) *Lobby { +func NewLobby(ctx context.Context, logger *log.Entry, accounts *accounts.Service, configProvider gameconfig.Provider) *Lobby { lobby := &Lobby{ - logger: logger, - storage: new(Storage), - players: orderedmap.New[uint32, *LobbyPlayer](), - accounts: accounts, + logger: logger, + storage: new(Storage), + players: orderedmap.New[uint32, *LobbyPlayer](), + accounts: accounts, + configProvider: configProvider, } lobby.TryStart(ctx, lobby.task) return lobby diff --git a/game/room/room.go b/game/room/room.go index 66be5cb..a0bc5e3 100644 --- a/game/room/room.go +++ b/game/room/room.go @@ -582,63 +582,55 @@ func (r *Room) handleRoomGameTurnEnd(ctx context.Context, event RoomGameTurnEnd) if nextPlayer == nil { r.state.CurrentHole++ if r.state.CurrentHole > r.state.NumHoles { - for pair := r.players.Oldest(); pair != nil; pair = pair.Next() { - r.broadcast(ctx, &gamepacket.ServerEvent{ - Type: gamepacket.GameEndEvent, - Data: gamepacket.ChatMessage{ - Nickname: common.ToPString(pair.Value.Entry.Nickname), - }, - GameEnd: &gamepacket.GameEnd{ - Score: 0, // ? - Pang: pair.Value.Pang, - }, - }) - results := &gamepacket.ServerRoomFinishGame{ - NumPlayers: uint8(r.players.Len()), - Standings: make([]gamepacket.PlayerGameResult, r.players.Len()), + results := &gamepacket.ServerRoomFinishGame{ + NumPlayers: uint8(r.players.Len()), + Standings: make([]gamepacket.PlayerGameResult, r.players.Len()), + } + for i, pair := 0, r.players.Oldest(); pair != nil; pair = pair.Next() { + bonusPang := pair.Value.BonusPang + bonusPang += r.lobby.configProvider.GetCourseBonus() + results.Standings[i].ConnID = pair.Value.Entry.ConnID + results.Standings[i].Pang = pair.Value.Pang + results.Standings[i].Score = int8(pair.Value.Score) + results.Standings[i].BonusPang = bonusPang + + totalPang := bonusPang + pair.Value.Pang + + newPang, err := r.accounts.AddPang(ctx, int64(pair.Value.Entry.PlayerID), int64(totalPang)) + if err != nil { + log.WithError(err).Error("failed giving game-ending pang") } - for i, pair := 0, r.players.Oldest(); pair != nil; pair = pair.Next() { - results.Standings[i].ConnID = pair.Value.Entry.ConnID - results.Standings[i].Pang = pair.Value.Pang - results.Standings[i].Score = int8(pair.Value.Score) - results.Standings[i].BonusPang = pair.Value.BonusPang - - newPang, err := r.accounts.AddPang(ctx, int64(pair.Value.Entry.PlayerID), int64(pair.Value.Pang+pair.Value.BonusPang)) - if err != nil { - log.WithError(err).Error("failed giving game-ending pang") - } - - if err := pair.Value.Conn.SendMessage(ctx, &gamepacket.ServerPangBalanceData{PangsRemaining: uint64(newPang)}); err != nil { - log.WithError(err).Error("failed informing player of game-ending pang") - } - - // reset game state now - pair.Value.Score = 0 - pair.Value.Pang = 0 - pair.Value.BonusPang = 0 - pair.Value.GameState.HoleEnd = false - pair.Value.GameState.ShotSync = nil - - i++ + + if err := pair.Value.Conn.SendMessage(ctx, &gamepacket.ServerPangBalanceData{PangsRemaining: uint64(newPang)}); err != nil { + log.WithError(err).Error("failed informing player of game-ending pang") } - slices.SortFunc(results.Standings, func(a, b gamepacket.PlayerGameResult) bool { - return a.Score < b.Score - }) - results.Standings[0].Place = 1 - for i := 1; i < len(results.Standings); i++ { - if results.Standings[i-1].Score == results.Standings[i].Score { - // If tie: use placement of tied player(s) - results.Standings[i].Place = results.Standings[i-1].Place - } else { - // If not tie: use position in standing as placement - results.Standings[i].Place = uint8(i + 1) - } + + // reset game state now + pair.Value.Score = 0 + pair.Value.Pang = 0 + pair.Value.BonusPang = 0 + pair.Value.GameState.HoleEnd = false + pair.Value.GameState.ShotSync = nil + + i++ + } + slices.SortFunc(results.Standings, func(a, b gamepacket.PlayerGameResult) bool { + return a.Score < b.Score + }) + results.Standings[0].Place = 1 + for i := 1; i < len(results.Standings); i++ { + if results.Standings[i-1].Score == results.Standings[i].Score { + // If tie: use placement of tied player(s) + results.Standings[i].Place = results.Standings[i-1].Place + } else { + // If not tie: use position in standing as placement + results.Standings[i].Place = uint8(i + 1) } - r.broadcast(ctx, results) - r.state.Open = true - r.state.CurrentHole = 0 - r.state.GamePhase = gamemodel.LobbyPhase } + r.broadcast(ctx, results) + r.state.Open = true + r.state.CurrentHole = 0 + r.state.GamePhase = gamemodel.LobbyPhase } else { r.broadcast(ctx, &gamepacket.ServerRoomFinishHole{}) for pair := r.players.Oldest(); pair != nil; pair = pair.Next() { @@ -682,8 +674,8 @@ func (r *Room) handleRoomGameShotSync(ctx context.Context, event RoomGameShotSyn Data: *r.state.ShotSync, }) if pair := r.players.GetPair(r.state.ShotSync.ActiveConnID); pair != nil { - pair.Value.Pang += uint64(r.state.ShotSync.Pang) - pair.Value.BonusPang += uint64(r.state.ShotSync.BonusPang) + pair.Value.Pang = uint64(r.state.ShotSync.Pang) + pair.Value.BonusPang = uint64(r.state.ShotSync.BonusPang) pair.Value.Stroke++ } else { log.WithField("ConnID", r.state.ShotSync.ActiveConnID).Warn("couldn't find conn") diff --git a/game/server/server.go b/game/server/server.go index 02ca663..1714b0d 100755 --- a/game/server/server.go +++ b/game/server/server.go @@ -71,7 +71,7 @@ func New(opts Options) *Server { // Listen listens for connections on a given address and blocks indefinitely. func (s *Server) Listen(ctx context.Context, addr string) error { - s.lobby = room.NewLobby(ctx, s.logger, s.accountsService) + s.lobby = room.NewLobby(ctx, s.logger, s.accountsService, s.configProvider) return s.baseServer.Listen(s.logger, addr, func(logger *log.Entry, socket net.Conn) error { conn := Conn{ ServerConn: common.NewServerConn( diff --git a/gameconfig/config.go b/gameconfig/config.go index fa7b6c4..a6fee2a 100644 --- a/gameconfig/config.go +++ b/gameconfig/config.go @@ -26,6 +26,7 @@ type Provider interface { GetCharacterDefaults(id uint8) CharacterDefaults GetDefaultClubSetTypeID() uint32 GetDefaultPang() uint64 + GetCourseBonus(course uint8, numPlayers, numHoles int) uint64 } type CharacterDefaults struct { @@ -33,16 +34,24 @@ type CharacterDefaults struct { DefaultPartTypeIDs [24]uint32 `json:"DefaultPartTypeIDs"` } +type CourseBonusRate struct { + CourseID uint8 + CourseName string + BonusRate int +} + type Manifest struct { CharacterDefaults []CharacterDefaults `json:"CharacterDefaults"` DefaultClubSetTypeID uint32 `json:"DefaultClubSetTypeID"` DefaultPang uint64 `json:"DefaultPang"` + CourseBonusRate []CourseBonusRate `json:"CourseBonusRate"` } type configFileProvider struct { characterDefaults map[uint8]CharacterDefaults defaultClubSetTypeID uint32 defaultPang uint64 + courseBonusRate map[uint8]int } func Default() Provider { @@ -78,10 +87,14 @@ func FromManifest(manifest Manifest) Provider { characterDefaults: make(map[uint8]CharacterDefaults), defaultClubSetTypeID: manifest.DefaultClubSetTypeID, defaultPang: manifest.DefaultPang, + courseBonusRate: make(map[uint8]int), } for _, defaults := range manifest.CharacterDefaults { provider.characterDefaults[defaults.CharacterID] = defaults } + for _, course := range manifest.CourseBonusRate { + provider.courseBonusRate[course.CourseID] = course.BonusRate + } return provider } @@ -96,3 +109,14 @@ func (c *configFileProvider) GetDefaultClubSetTypeID() uint32 { func (c *configFileProvider) GetDefaultPang() uint64 { return c.defaultPang } + +func (c *configFileProvider) GetCourseBonus(course uint8, numPlayers, numHoles int) uint64 { + bonusRate, ok := c.courseBonusRate[course] + if !ok { + // Should generally not happen... + bonusRate = 20 + } + + // TODO: this is probably only true for versus + return uint64(bonusRate * numHoles * (numPlayers - 1)) +} diff --git a/gameconfig/default.json b/gameconfig/default.json index 26e4efa..9aa3131 100644 --- a/gameconfig/default.json +++ b/gameconfig/default.json @@ -1,5 +1,28 @@ { "DefaultPang": 20000, "DefaultClubSetTypeID": 268435553, - "CharacterDefaults": [] + "CharacterDefaults": [], + "CourseBonusRate": [ + {"CourseID": 0, "CourseName": "Blue Lagoon", "BonusRate": 20}, + {"CourseID": 1, "CourseName": "Blue Water", "BonusRate": 20}, + {"CourseID": 2, "CourseName": "Sepia Wind", "BonusRate": 20}, + {"CourseID": 3, "CourseName": "Wind Hill", "BonusRate": 20}, + {"CourseID": 4, "CourseName": "Wiz Wiz", "BonusRate": 20}, + {"CourseID": 5, "CourseName": "West Wiz", "BonusRate": 20}, + {"CourseID": 6, "CourseName": "Blue Moon", "BonusRate": 20}, + {"CourseID": 7, "CourseName": "Silvia Cannon", "BonusRate": 20}, + {"CourseID": 8, "CourseName": "Ice Cannon", "BonusRate": 20}, + {"CourseID": 9, "CourseName": "White Wiz", "BonusRate": 20}, + {"CourseID": 10, "CourseName": "Shining Sand", "BonusRate": 40}, + {"CourseID": 11, "CourseName": "Pink Wind", "BonusRate": 20}, + {"CourseID": 13, "CourseName": "Deep Inferno", "BonusRate": 20}, + {"CourseID": 14, "CourseName": "Ice Spa", "BonusRate": 20}, + {"CourseID": 15, "CourseName": "Lost Seaway", "BonusRate": 20}, + {"CourseID": 16, "CourseName": "Eastern Valley", "BonusRate": 20}, + {"CourseID": 17, "CourseName": "Chronicle 1. Chaos", "BonusRate": 20}, + {"CourseID": 18, "CourseName": "Ice Inferno", "BonusRate": 20}, + {"CourseID": 19, "CourseName": "Wiz City", "BonusRate": 20}, + {"CourseID": 20, "CourseName": "Abbot Mine", "BonusRate": 20}, + {"CourseID": 64, "CourseName": "Grand Zodiac", "BonusRate": 20} + ] }