1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-12 10:40:42 +00:00
OpenDiablo2/d2game/d2gamescreen/game.go
David Carrell 3bdbd5c358
rely on App to know how to navigate between screens using a callback interface with explicit methods (#592)
remove unused struct vars that were only stored in order to pass to the next screens

consolidate create game code to single method

export ScreenMode consts and SetScreenMode method to allow app to create the correct screens

Co-authored-by: carrelda <carrelda@git>
2020-07-14 13:11:23 -04:00

192 lines
6.0 KiB
Go

package d2gamescreen
import (
"fmt"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapentity"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2maprenderer"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
)
const hideZoneTextAfterSeconds = 2.0
// Game represents the Gameplay screen
type Game struct {
gameClient *d2client.GameClient
mapRenderer *d2maprenderer.MapRenderer
gameControls *d2player.GameControls // TODO: Hack
localPlayer *d2mapentity.Player
lastRegionType d2enum.RegionIdType
ticksSinceLevelCheck float64
escapeMenu *EscapeMenu
renderer d2interface.Renderer
inputManager d2interface.InputManager
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
// CreateGame creates the Gameplay screen and returns a pointer to it
func CreateGame(navigator Navigator, renderer d2interface.Renderer, inputManager d2interface.InputManager, audioProvider d2interface.AudioProvider, gameClient *d2client.GameClient, term d2interface.Terminal) *Game {
result := &Game{
gameClient: gameClient,
gameControls: nil,
localPlayer: nil,
lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(renderer, gameClient.MapEngine, term),
escapeMenu: NewEscapeMenu(navigator, renderer, audioProvider),
inputManager: inputManager,
audioProvider: audioProvider,
renderer: renderer,
terminal: term,
}
result.escapeMenu.onLoad()
if err := inputManager.BindHandler(result.escapeMenu); err != nil {
fmt.Println("failed to add gameplay screen as event handler")
}
return result
}
// OnLoad loads the resources for the Gameplay screen
func (v *Game) OnLoad(_ d2screen.LoadingState) {
v.audioProvider.PlayBGM("")
}
// OnUnload releases the resources of Gameplay screen
func (v *Game) OnUnload() error {
if err := v.inputManager.UnbindHandler(v.gameControls); err != nil { // TODO: hack
return err
}
if err := v.inputManager.UnbindHandler(v.escapeMenu); err != nil { // TODO: hack
return err
}
if err := v.gameClient.Close(); err != nil {
return err
}
return nil
}
// Render renders the Gameplay screen
func (v *Game) Render(screen d2interface.Surface) error {
if v.gameClient.RegenMap {
v.gameClient.RegenMap = false
v.mapRenderer.RegenerateTileCache()
}
if err := screen.Clear(color.Black); err != nil {
return err
}
v.mapRenderer.Render(screen)
if v.gameControls != nil {
v.gameControls.Render(screen)
}
return nil
}
// Advance runs the update logic on the Gameplay screen
func (v *Game) Advance(tickTime float64) error {
if (v.escapeMenu != nil && !v.escapeMenu.isOpen) || len(v.gameClient.Players) != 1 {
v.gameClient.MapEngine.Advance(tickTime) // TODO: Hack
}
if v.gameControls != nil {
if err := v.gameControls.Advance(tickTime); err != nil {
return err
}
}
v.ticksSinceLevelCheck += tickTime
if v.ticksSinceLevelCheck > 1.0 {
v.ticksSinceLevelCheck = 0
if v.localPlayer != nil {
tilePosition := v.localPlayer.Position.Tile()
tile := v.gameClient.MapEngine.TileAt(int(tilePosition.X()), int(tilePosition.Y()))
if tile != nil {
musicInfo := d2common.GetMusicDef(tile.RegionType)
v.audioProvider.PlayBGM(musicInfo.MusicFile)
// skip showing zone change text the first time we enter the world
if v.lastRegionType != d2enum.RegionNone && v.lastRegionType != tile.RegionType {
//TODO: Should not be using RegionType as an index - this will return incorrect LevelDetails record for most of the zones.
v.gameControls.SetZoneChangeText(fmt.Sprintf("Entering The %s", d2datadict.LevelDetails[int(tile.RegionType)].LevelDisplayName))
v.gameControls.ShowZoneChangeText()
v.gameControls.HideZoneChangeTextAfter(hideZoneTextAfterSeconds)
}
v.lastRegionType = tile.RegionType
}
}
}
// Bind the game controls to the player once it exists
if v.gameControls == nil {
v.bindGameControls()
}
// Update the camera to focus on the player
if v.localPlayer != nil && !v.gameControls.FreeCam {
worldPosition := v.localPlayer.Position.World()
rx, ry := v.mapRenderer.WorldToOrtho(worldPosition.X(), worldPosition.Y())
v.mapRenderer.MoveCameraTo(rx, ry)
}
return nil
}
func (v *Game) bindGameControls() {
for _, player := range v.gameClient.Players {
if player.Id != v.gameClient.PlayerId {
continue
}
v.localPlayer = player
v.gameControls = d2player.NewGameControls(v.renderer, player, v.gameClient.MapEngine, v.mapRenderer, v, v.terminal)
v.gameControls.Load()
if err := v.inputManager.BindHandler(v.gameControls); err != nil {
fmt.Printf("failed to add gameControls as input handler for player: %s\n", player.Id)
}
break
}
}
// OnPlayerMove sends the player move action to the server
func (v *Game) OnPlayerMove(x, y float64) {
worldPosition := v.localPlayer.Position.World()
err := v.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(v.gameClient.PlayerId, worldPosition.X(), worldPosition.Y(), x, y))
if err != nil {
fmt.Printf("failed to send MovePlayer packet to the server, playerId: %s, x: %g, x: %g\n", v.gameClient.PlayerId, x, y)
}
}
// OnPlayerCast sends the casting skill action to the server
func (v *Game) OnPlayerCast(missileID int, targetX, targetY float64) {
err := v.gameClient.SendPacketToServer(d2netpacket.CreateCastPacket(v.gameClient.PlayerId, missileID, targetX, targetY))
if err != nil {
fmt.Printf(
"failed to send CastSkill packet to the server, playerId: %s, missileId: %d, x: %g, x: %g\n",
v.gameClient.PlayerId, missileID, targetX, targetY,
)
}
}