This commit is contained in:
Tim Sarbin 2020-06-19 02:19:27 -04:00 committed by GitHub
parent be498ee869
commit 7b38a9d818
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 256 additions and 79 deletions

View File

@ -32,7 +32,9 @@ func Initialize(audioProvider AudioProvider) error {
// PlayBGM plays an infinitely looping background track
func PlayBGM(song string) error {
verifyWasInit()
singleton.PlayBGM(song)
go func() {
singleton.PlayBGM(song)
}()
return nil
}

View File

@ -13,7 +13,6 @@ func getDefaultConfig() *Configuration {
config := &Configuration{
Language: "ENG",
FullScreen: false,
Scale: 1,
TicksPerSecond: -1,
RunInBackground: true,
VsyncEnabled: true,

View File

@ -8,7 +8,6 @@ import (
type Configuration struct {
Language string
FullScreen bool
Scale float64
RunInBackground bool
TicksPerSecond int
FpsCap int

View File

@ -0,0 +1,45 @@
package d2map
import (
"math/rand"
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2wilderness"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
)
func (m *MapEngine) GenerateAct1Overworld(cacheTiles bool) {
rand.Seed(m.seed)
region, entities := loadRegion(m.seed, 0, 0, d2enum.RegionAct1Town, 1, -1, cacheTiles)
m.regions = append(m.regions, region)
m.entities.Add(entities...)
if strings.Contains(region.regionPath, "E1") {
region, entities := loadRegion(m.seed, region.tileRect.Width, 0, d2enum.RegionAct1Town, 2, -1, cacheTiles)
m.AppendRegion(region)
m.entities.Add(entities...)
} else if strings.Contains(region.regionPath, "S1") {
yOffset := region.tileRect.Height
waterXOffset := region.tileRect.Width - 16
region, entities := loadRegion(m.seed, 0, yOffset, d2enum.RegionAct1Town, 3, -1, cacheTiles)
m.AppendRegion(region)
m.entities.Add(entities...)
yOffset += region.tileRect.Height
for i := 0; i < 8; i++ {
// West Border
region, entities = loadRegion(m.seed, 0, yOffset, d2enum.RegionAct1Wilderness, d2wilderness.TreeBorderWest, 0, cacheTiles)
m.AppendRegion(region)
m.entities.Add(entities...)
// East Border
region, entities = loadRegion(m.seed, waterXOffset, yOffset, d2enum.RegionAct1Wilderness, d2wilderness.WaterBorderEast, 0, cacheTiles)
m.AppendRegion(region)
m.entities.Add(entities...)
yOffset += region.tileRect.Height
}
}
}

View File

@ -0,0 +1,53 @@
package d2wilderness
const (
TreeBorderSouth int = iota + 4
TreeBorderWest
TreeBorderNorth
TreeBorderEast
TreeBorderSouthWest
TreeBorderNorthWest
TreeBorderNorthEast
TreeBorderSouthEast
TreeBoxNorthEast
TreeBoxSouthEast
TreeBoxSouthWest
TreeBoxNorthWest
WallBorderWest
WallBorderEast
WallBorderWestFenceNorth
WallBorderNorthWest
WallBorderWestFenceSouth
WallBorderNorthFenceEast
WallBorderNorthFenceWest
WallBoxSouthEast
WallBorderNorthUndergroundPassageEntrance
WallBorderWestUndergroundPassageEntrance
WaterBorderEast
WaterBorderWest
WaterBridgeEast
DirtSquareWithRocks
FourDirtSquaresWithRocks
FenceMaze
RandomTreesAndWallBoxLarge
TreeBoxNorthSouth
ShrineWithFenceAndTrees
RandomTreesAndWallBoxSmall
TreeBoxWestEastWithNorthSouthPath
TreeBoxNorthSouthWithEastWestPath
GrassPatch1
GrassPatch2
EnemyFeature1
EnemyFeature2
EnemyFeature3
EnemyFeature4
EnemyFeature5
EnemyFeature6
Pond
House1
House2
BurnedHouse
NotTheCowLevel
UndergroundCavern
DenOfEvil
)

View File

@ -3,7 +3,6 @@ package d2map
import (
"log"
"math"
"strings"
"github.com/beefsack/go-astar"
@ -26,15 +25,16 @@ type MapEngine struct {
}
// Creates a new instance of the map engine
func CreateMapEngine() *MapEngine {
func CreateMapEngine(seed int64) *MapEngine {
engine := &MapEngine{
seed: 0,
seed: seed,
entities: NewRangeSearcher(),
}
return engine
}
// Sets the seed of the map for generation
func (m *MapEngine) SetSeed(seed int64) {
log.Printf("Setting map engine seed to %d", seed)
m.seed = seed
@ -42,6 +42,8 @@ func (m *MapEngine) SetSeed(seed int64) {
func (m *MapEngine) GetStartPosition() (float64, float64) {
var startX, startY float64
// TODO: Temporary code, only works for starting map
if len(m.regions) > 0 {
region := m.regions[0]
startX, startY = region.getStartTilePosition()
@ -68,29 +70,48 @@ func (m *MapEngine) GenerateMap(regionType d2enum.RegionIdType, levelPreset int,
m.entities.Add(entities...)
}
func (m *MapEngine) GenerateAct1Overworld(cacheTiles bool) {
//d2audio.PlayBGM("/data/global/music/Act1/town1.wav") // TODO: Temp stuff here
region, entities := loadRegion(m.seed, 0, 0, d2enum.RegionAct1Town, 1, -1, cacheTiles)
m.regions = append(m.regions, region)
m.entities.Add(entities...)
if strings.Contains(region.regionPath, "E1") {
region, entities := loadRegion(m.seed, region.tileRect.Width-1, 0, d2enum.RegionAct1Town, 2, -1, cacheTiles)
m.AppendRegion(region)
m.entities.Add(entities...)
} else if strings.Contains(region.regionPath, "S1") {
region, entities := loadRegion(m.seed, 0, region.tileRect.Height-1, d2enum.RegionAct1Town, 3, -1, cacheTiles)
m.AppendRegion(region)
m.entities.Add(entities...)
}
}
// Appends a region to the map
func (m *MapEngine) AppendRegion(region *MapRegion) {
// TODO: Stitch together region.walkableArea
log.Printf("Warning: Walkable areas are not currently implemented")
m.regions = append(m.regions, region)
// Stitch together the walk map
for x := 0; x < region.tileRect.Width*5; x++ {
otherRegion := m.GetRegionAtTile(region.tileRect.Left+(x/5), region.tileRect.Top-1)
if otherRegion == nil {
continue
}
xDiff := region.tileRect.Left - otherRegion.tileRect.Left
sourceSubtile := &region.walkableArea[0][x]
if !sourceSubtile.Walkable {
continue
}
// North West
otherX := x + xDiff - 1
otherY := (otherRegion.tileRect.Height * 5) - 1
if otherX < 0 || otherX >= len(otherRegion.walkableArea[otherY]) {
continue
}
otherRegion.walkableArea[otherY][x+xDiff].DownRight = sourceSubtile
sourceSubtile.UpLeft = &otherRegion.walkableArea[otherY][x+xDiff]
// North
otherX++
if otherX < 0 || otherX >= len(otherRegion.walkableArea[otherY]) {
continue
}
otherRegion.walkableArea[otherY][x+xDiff].Down = sourceSubtile
sourceSubtile.Up = &otherRegion.walkableArea[otherY][x+xDiff]
// NorthEast
otherX++
if otherX < 0 || otherX >= len(otherRegion.walkableArea[otherY]) {
continue
}
otherRegion.walkableArea[otherY][x+xDiff].DownLeft = sourceSubtile
sourceSubtile.UpRight = &otherRegion.walkableArea[otherY][x+xDiff]
}
}
// Returns the region located at the specified tile location
@ -104,10 +125,12 @@ func (m *MapEngine) GetRegionAtTile(x, y int) *MapRegion {
return nil
}
// Adds an entity to the map engine
func (m *MapEngine) AddEntity(entity MapEntity) {
m.entities.Add(entity)
}
// Removes an entity from the map engine
func (m *MapEngine) RemoveEntity(entity MapEntity) {
if entity == nil {
return
@ -116,6 +139,7 @@ func (m *MapEngine) RemoveEntity(entity MapEntity) {
m.entities.Remove(entity)
}
// Advances time on the map engine
func (m *MapEngine) Advance(tickTime float64) {
for _, region := range m.regions {
//if region.isVisbile(m.viewport) {
@ -130,12 +154,16 @@ func (m *MapEngine) Advance(tickTime float64) {
m.entities.Update()
}
// Finds a walkable path between two points
func (m *MapEngine) PathFind(startX, startY, endX, endY float64) (path []astar.Pather, distance float64, found bool) {
startTileX := int(math.Floor(startX))
startTileY := int(math.Floor(startY))
startSubtileX := int((startX - float64(int(startX))) * 5)
startSubtileY := int((startY - float64(int(startY))) * 5)
startRegion := m.GetRegionAtTile(startTileX, startTileY)
if startRegion == nil {
return
}
startNode := &startRegion.walkableArea[startSubtileY+((startTileY-startRegion.tileRect.Top)*5)][startSubtileX+((startTileX-startRegion.tileRect.Left)*5)]
endTileX := int(math.Floor(endX))
@ -143,7 +171,18 @@ func (m *MapEngine) PathFind(startX, startY, endX, endY float64) (path []astar.P
endSubtileX := int((endX - float64(int(endX))) * 5)
endSubtileY := int((endY - float64(int(endY))) * 5)
endRegion := m.GetRegionAtTile(endTileX, endTileY)
endNode := &endRegion.walkableArea[endSubtileY+((endTileY-endRegion.tileRect.Top)*5)][endSubtileX+((endTileX-endRegion.tileRect.Left)*5)]
if endRegion == nil {
return
}
endNodeY := endSubtileY + ((endTileY - endRegion.tileRect.Top) * 5)
endNodeX := endSubtileX + ((endTileX - endRegion.tileRect.Left) * 5)
if endNodeY < 0 || endNodeY >= len(endRegion.walkableArea) {
return
}
if endNodeX < 0 || endNodeX >= len(endRegion.walkableArea[endNodeY]) {
return
}
endNode := &endRegion.walkableArea[endNodeY][endNodeX]
path, distance, found = astar.Path(endNode, startNode)
if path != nil {

View File

@ -139,8 +139,8 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
region.tileRect = d2common.Rectangle{
Left: tileOffsetX,
Top: tileOffsetY,
Width: int(region.ds1.Width),
Height: int(region.ds1.Height),
Width: int(region.ds1.Width - 1),
Height: int(region.ds1.Height - 1),
}
entities := region.loadEntities()
@ -155,10 +155,10 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio
func (mr *MapRegion) generateWalkableMatrix() {
mr.walkableArea = make([][]PathTile, mr.tileRect.Height*5)
for y := 0; y < (mr.tileRect.Height-1)*5; y++ {
for y := 0; y < mr.tileRect.Height*5; y++ {
mr.walkableArea[y] = make([]PathTile, mr.tileRect.Width*5)
ty := int(float64(y) / 5.0)
for x := 0; x < (mr.tileRect.Width-1)*5; x++ {
for x := 0; x < mr.tileRect.Width*5; x++ {
tx := int(float64(x) / 5.0)
tile := mr.GetTile(tx, ty)
isBlocked := false
@ -188,8 +188,8 @@ func (mr *MapRegion) generateWalkableMatrix() {
}
mr.walkableArea[y][x] = PathTile{
Walkable: !isBlocked,
X: float64(x) / 5.0,
Y: float64(y) / 5.0,
X: (float64(x) / 5.0) + float64(mr.tileRect.Left),
Y: (float64(y) / 5.0) + float64(mr.tileRect.Top),
}
if !isBlocked && y > 0 && mr.walkableArea[y-1][x].Walkable {
mr.walkableArea[y][x].Up = &mr.walkableArea[y-1][x]
@ -203,7 +203,7 @@ func (mr *MapRegion) generateWalkableMatrix() {
mr.walkableArea[y][x].UpLeft = &mr.walkableArea[y-1][x-1]
mr.walkableArea[y-1][x-1].DownRight = &mr.walkableArea[y][x]
}
if !isBlocked && y > 0 && x < (mr.tileRect.Width*5) && mr.walkableArea[y-1][x+1].Walkable {
if !isBlocked && y > 0 && x < (mr.tileRect.Width*5)-1 && mr.walkableArea[y-1][x+1].Walkable {
mr.walkableArea[y][x].UpRight = &mr.walkableArea[y-1][x+1]
mr.walkableArea[y-1][x+1].DownLeft = &mr.walkableArea[y][x]
}
@ -231,7 +231,7 @@ func (mr *MapRegion) loadSpecials() {
for tileY := range mr.ds1.Tiles {
for tileX := range mr.ds1.Tiles[tileY] {
for _, wall := range mr.ds1.Tiles[tileY][tileX].Walls {
if wall.Type == 10 && wall.Style == 30 && wall.Sequence == 0 {
if wall.Type == 10 && wall.Style == 30 && wall.Sequence == 0 && mr.startX == 0 && mr.startY == 0 {
mr.startX, mr.startY = mr.getTileWorldPosition(tileX, tileY)
mr.startX += 0.5
mr.startY += 0.5

View File

@ -10,7 +10,21 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type Renderer struct{}
type Renderer struct {
renderCallback func(surface d2render.Surface) error
}
func (r *Renderer) Update(screen *ebiten.Image) error {
err := r.renderCallback(&ebitenSurface{image: screen})
if err != nil {
return err
}
return nil
}
func (r *Renderer) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return 800, 600
}
func CreateRenderer() (*Renderer, error) {
result := &Renderer{}
@ -42,15 +56,11 @@ func (r *Renderer) IsDrawingSkipped() bool {
}
func (r *Renderer) Run(f func(surface d2render.Surface) error, width, height int, title string) error {
config := d2config.Get()
return ebiten.Run(func(img *ebiten.Image) error {
err := f(&ebitenSurface{image: img})
if err != nil {
return err
}
return nil
}, width, height, config.Scale, title)
r.renderCallback = f
ebiten.SetWindowTitle(title)
ebiten.SetWindowResizable(true)
ebiten.SetWindowSize(width, height)
return ebiten.RunGame(r)
}
func (r *Renderer) CreateSurface(surface d2render.Surface) (d2render.Surface, error) {

View File

@ -1,12 +1,14 @@
package d2gamescreen
import (
"fmt"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2netpacket"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
"github.com/OpenDiablo2/OpenDiablo2/d2networking/d2client"
@ -19,22 +21,27 @@ type Game struct {
//pentSpinLeft *d2ui.Sprite
//pentSpinRight *d2ui.Sprite
//testLabel d2ui.Label
gameClient *d2client.GameClient
mapRenderer *d2map.MapRenderer
gameControls *d2player.GameControls // TODO: Hack
localPlayer *d2map.Player
gameClient *d2client.GameClient
mapRenderer *d2map.MapRenderer
gameControls *d2player.GameControls // TODO: Hack
localPlayer *d2map.Player
lastLevelType int
ticksSinceLevelCheck float64
}
func CreateGame(gameClient *d2client.GameClient) *Game {
return &Game{
gameClient: gameClient,
gameControls: nil,
localPlayer: nil,
mapRenderer: d2map.CreateMapRenderer(gameClient.MapEngine),
gameClient: gameClient,
gameControls: nil,
localPlayer: nil,
lastLevelType: -1,
ticksSinceLevelCheck: 0,
mapRenderer: d2map.CreateMapRenderer(gameClient.MapEngine),
}
}
func (v *Game) OnLoad() error {
d2audio.PlayBGM("")
return nil
}
@ -55,6 +62,27 @@ func (v *Game) Render(screen d2render.Surface) error {
func (v *Game) Advance(tickTime float64) error {
v.gameClient.MapEngine.Advance(tickTime) // TODO: Hack
v.ticksSinceLevelCheck += tickTime
if v.ticksSinceLevelCheck > 2.0 {
v.ticksSinceLevelCheck = 0
if v.localPlayer != nil {
region := v.gameClient.MapEngine.GetRegionAtTile(v.localPlayer.TileX, v.localPlayer.TileY)
if region != nil {
levelType := region.GetLevelType().Id
fmt.Printf("Level checked: %d (%s)\t%d, %d\n", levelType, region.GetLevelType().Name, v.localPlayer.TileX, v.localPlayer.TileY)
if levelType != v.lastLevelType {
v.lastLevelType = levelType
switch levelType {
case 1: // Rogue encampent
d2audio.PlayBGM("/data/global/music/Act1/town1.wav")
case 2: // Blood Moore
d2audio.PlayBGM("/data/global/music/Act1/wild.wav")
}
}
}
}
}
// Bind the game controls to the player once it exists
if v.gameControls == nil {
for _, player := range v.gameClient.Players {

View File

@ -2,7 +2,9 @@ package d2gamescreen
import (
"math"
"math/rand"
"os"
"time"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2player"
@ -127,9 +129,10 @@ func (met *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
}
if n == 0 {
rand.Seed(time.Now().UnixNano())
met.mapEngine.GenerateAct1Overworld(true)
} else {
met.mapEngine = d2map.CreateMapEngine() // necessary for map name update
met.mapEngine = d2map.CreateMapEngine(0) // necessary for map name update
met.mapEngine.GenerateMap(d2enum.RegionIdType(n), levelPreset, fileIndex, true)
met.mapRenderer.SetMapEngine(met.mapEngine)
}
@ -138,10 +141,8 @@ func (met *MapEngineTest) LoadRegionByIndex(n int, levelPreset, fileIndex int) {
}
func (met *MapEngineTest) OnLoad() error {
// TODO: Game seed comes from the game state object
d2input.BindHandler(met)
met.mapEngine = d2map.CreateMapEngine()
met.mapEngine = d2map.CreateMapEngine(0)
met.mapRenderer = d2map.CreateMapRenderer(met.mapEngine)
met.LoadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)

View File

@ -22,11 +22,12 @@ type GameClient struct {
MapEngine *d2map.MapEngine
PlayerId string
Players map[string]*d2map.Player
Seed int64
}
func Create(connectionType d2clientconnectiontype.ClientConnectionType) (*GameClient, error) {
result := &GameClient{
MapEngine: d2map.CreateMapEngine(),
MapEngine: d2map.CreateMapEngine(0),
Players: make(map[string]*d2map.Player, 0),
connectionType: connectionType,
}
@ -61,12 +62,16 @@ func (g *GameClient) OnPacketReceived(packet d2netpacket.NetPacket) error {
switch packet.PacketType {
case d2netpackettype.GenerateMap:
mapData := packet.PacketData.(d2netpacket.GenerateMapPacket)
g.MapEngine.GenerateMap(mapData.RegionType, mapData.LevelPreset, mapData.FileIndex, true)
switch mapData.RegionType {
case d2enum.RegionAct1Town:
g.MapEngine.GenerateAct1Overworld(true)
}
break
case d2netpackettype.UpdateServerInfo:
serverInfo := packet.PacketData.(d2netpacket.UpdateServerInfoPacket)
g.MapEngine.SetSeed(serverInfo.Seed)
g.PlayerId = serverInfo.PlayerId
g.Seed = serverInfo.Seed
log.Printf("Player id set to %s", serverInfo.PlayerId)
break
case d2netpackettype.AddPlayer:

View File

@ -6,18 +6,14 @@ import (
)
type GenerateMapPacket struct {
RegionType d2enum.RegionIdType `json:"regionType"`
LevelPreset int `json:"levelPreset"`
FileIndex int `json:"fileIndex"`
RegionType d2enum.RegionIdType `json:"regionType"`
}
func CreateGenerateMapPacket(regionType d2enum.RegionIdType, levelPreset int, fileIndex int) NetPacket {
func CreateGenerateMapPacket(regionType d2enum.RegionIdType) NetPacket {
return NetPacket{
PacketType: d2netpackettype.GenerateMap,
PacketData: GenerateMapPacket{
RegionType: regionType,
LevelPreset: levelPreset,
FileIndex: fileIndex,
RegionType: regionType,
},
}

View File

@ -9,7 +9,6 @@ import (
"log"
"net"
"strings"
"time"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map"
@ -40,13 +39,12 @@ func Create(openNetworkServer bool) {
singletonServer = &GameServer{
clientConnections: make(map[string]ClientConnection),
mapEngines: make([]*d2map.MapEngine, 0),
//gameState: d2player.LoadPlayerState(gameStatePath),
scriptEngine: d2script.CreateScriptEngine(),
seed: time.Now().UnixNano(),
scriptEngine: d2script.CreateScriptEngine(),
seed: 1592539977884044000, //time.Now().UnixNano(),
}
mapEngine := d2map.CreateMapEngine()
mapEngine.GenerateMap(d2enum.RegionAct1Town, 1, 0, false)
mapEngine := d2map.CreateMapEngine(singletonServer.seed)
mapEngine.GenerateAct1Overworld(true)
singletonServer.mapEngines = append(singletonServer.mapEngines, mapEngine)
singletonServer.scriptEngine.AddFunction("getMapEngines", func(call otto.FunctionCall) otto.Value {
@ -150,7 +148,7 @@ func OnClientConnected(client ClientConnection) {
log.Printf("Client connected with an id of %s", client.GetUniqueId())
singletonServer.clientConnections[client.GetUniqueId()] = client
client.SendPacketToClient(d2netpacket.CreateUpdateServerInfoPacket(singletonServer.seed, client.GetUniqueId()))
client.SendPacketToClient(d2netpacket.CreateGenerateMapPacket(d2enum.RegionAct1Town, 1, 0))
client.SendPacketToClient(d2netpacket.CreateGenerateMapPacket(d2enum.RegionAct1Town))
playerState := client.GetPlayerState()
createPlayerPacket := d2netpacket.CreateAddPlayerPacket(client.GetUniqueId(), playerState.HeroName, int(sx*5)+3, int(sy*5)+3,

7
go.mod
View File

@ -8,15 +8,10 @@ require (
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/beefsack/go-astar v0.0.0-20171024231011-f324bbb0d6f7
github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1
github.com/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200102072751-e66f1fb71e2e
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
github.com/pebbe/zmq4 v1.2.1 // indirect
github.com/hajimehoshi/ebiten v1.11.2
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff
github.com/satori/go.uuid v1.2.0
github.com/stretchr/testify v1.4.0
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 // indirect
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba // indirect
golang.org/x/sys v0.0.0-20191115151921-52ab43148777 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/sourcemap.v1 v1.0.5 // indirect
)

7
go.sum
View File

@ -24,6 +24,8 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw
github.com/hajimehoshi/bitmapfont v1.2.0/go.mod h1:h9QrPk6Ktb2neObTlAbma6Ini1xgMjbJ3w7ysmD7IOU=
github.com/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200102072751-e66f1fb71e2e h1:NRGAeXOSMrAo0f4GPaUoiF61eo0wWrfgONPSTZA6Zhg=
github.com/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200102072751-e66f1fb71e2e/go.mod h1:0SLvfr8iI2NxzpNB/olBM+dLN9Ur5a9szG13wOgQ0nQ=
github.com/hajimehoshi/ebiten v1.11.2 h1:4oixxPh5DuSNlmL/Q4LIOGFXCY8uLC+pcxOnqAGbwEY=
github.com/hajimehoshi/ebiten v1.11.2/go.mod h1:aDEhx0K9gSpXw3Cxf2hCXDxPSoF8vgjNqKxrZa/B4Dg=
github.com/hajimehoshi/ebiten v1.12.0-alpha.2.0.20200614175121-0b94e2e03645 h1:4h6uuzsCz94SOxvEZl+w8ICu90QHvn4l/G9VB7poNyw=
github.com/hajimehoshi/ebiten v1.12.0-alpha.2.0.20200614175121-0b94e2e03645/go.mod h1:T+uHfxpwulzepUikvWZ4F0G9gt8RzZnrKjH6BgoWDgw=
github.com/hajimehoshi/go-mp3 v0.2.1/go.mod h1:Rr+2P46iH6PwTPVgSsEwBkon0CK5DxCAeX/Rp65DCTE=
@ -65,6 +67,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMDZk5lNJNyJ6DvrBkTEU=
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136 h1:A1gGSx58LAGVHUUsOf7IiR0u8Xb6W51gRwfDBhkdcaw=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
@ -81,6 +84,8 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
golang.org/x/mobile v0.0.0-20191025110607-73ccc5ba0426/go.mod h1:p895TfNkDgPEmEQrNiOtIl3j98d/tGU95djDj7NfyjQ=
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba h1:NVszahdZPQTROdO0F5gnXdZhGl2lXFb9w7Ek1F2Pbmk=
golang.org/x/mobile v0.0.0-20191115022231-f0c40035f2ba/go.mod h1:p895TfNkDgPEmEQrNiOtIl3j98d/tGU95djDj7NfyjQ=
golang.org/x/mobile v0.0.0-20200222142934-3c8601c510d0 h1:nZASbxDuz7CO3227BWCCf0MC6ynyvKh6eMDoLcNXAk0=
golang.org/x/mobile v0.0.0-20200222142934-3c8601c510d0/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007 h1:JxsyO7zPDWn1rBZW8FV5RFwCKqYeXnyaS/VQPLpXu6I=
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
@ -97,6 +102,7 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777 h1:wejkGHRTr38uaKRqECZlsCsJ1/TGxIyFbH32x5zUdu4=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -109,6 +115,7 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191026034945-b2104f82a97d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200330175517-31583a0dbbc8/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=