GOingTunneling/playerutil.go

317 lines
10 KiB
Go

package main
import (
"github.com/veandco/go-sdl2/sdl"
"math/rand"
"net"
)
func getUnusedColor(colors []PlayerColors, players map[uint32]*Player) uint32 {
for i, c := range colors {
foundPlayerWithColor := false
var colorCompare []uint8
clrR, clrG, clrB, clrA := c.tracks.RGBA()
colorCompare = append(colorCompare, uint8(clrR), uint8(clrG), uint8(clrB), uint8(clrA))
clrR, clrG, clrB, clrA = c.body.RGBA()
colorCompare = append(colorCompare, uint8(clrR), uint8(clrG), uint8(clrB), uint8(clrA))
clrR, clrG, clrB, clrA = c.cannon.RGBA()
colorCompare = append(colorCompare, uint8(clrR), uint8(clrG), uint8(clrB), uint8(clrA))
playersMutex.RLock()
for _, player := range players {
var playerColorsCompare []uint8
plrR, plrG, plrB, plrA := player.playerColors.tracks.RGBA()
playerColorsCompare = append(playerColorsCompare, uint8(plrR), uint8(plrG), uint8(plrB), uint8(plrA))
plrR, plrG, plrB, plrA = player.playerColors.body.RGBA()
playerColorsCompare = append(playerColorsCompare, uint8(plrR), uint8(plrG), uint8(plrB), uint8(plrA))
plrR, plrG, plrB, plrA = player.playerColors.cannon.RGBA()
playerColorsCompare = append(playerColorsCompare, uint8(plrR), uint8(plrG), uint8(plrB), uint8(plrA))
foundPlayerWithColor = false
if len(playerColorsCompare) == len(colorCompare) {
for i, c := range colorCompare {
if playerColorsCompare[i] == c {
foundPlayerWithColor = true
} else {
foundPlayerWithColor = false
break
}
}
if foundPlayerWithColor {
break
}
}
}
playersMutex.RUnlock()
if !foundPlayerWithColor {
return uint32(i)
}
}
return uint32(len(colors) - 1)
}
func createPlayers(amount uint8, playerColors []PlayerColors, keyMaps []KeyMap, joyMaps []JoyMap, gameMap *GameMap, players map[uint32]*Player, bases map[uint32]*Base) {
joyStickCount := sdl.NumJoysticks()
if amount > uint8(len(keyMaps)+len(joyMaps)) || amount > uint8(len(keyMaps)+joyStickCount) {
panic("Too many players, not enough inputs")
}
if amount >= uint8(len(playerColors)) {
panic("Too many players, not enough colors")
}
addedKeyboardPlayers := 0
for i := uint8(0); i < amount; i++ {
var keyMap KeyMap
var joyMap JoyMap
var joyStick *sdl.Joystick
if (config.DoAllKeymapsPlayers && i <= uint8(len(keyMaps))) || (config.DoKeymapPlayer && i == 0) || (uint8(joyStickCount) <= i) {
keyMap = keyMaps[(addedKeyboardPlayers+int(config.KeyBindOffset))%(len(keyMaps)-1)]
addedKeyboardPlayers++
} else {
joyStickIndex := i - uint8(addedKeyboardPlayers)
joyMap = joyMaps[joyStickIndex]
joyStick = sdl.JoystickOpen(int(joyStickIndex))
}
unusedColor := getUnusedColor(playerColors, players)
createPlayer(
true,
playerColors[unusedColor],
unusedColor,
nil,
keyMap,
joyMap,
joyStick,
gameMap,
players,
bases,
)
}
}
func closeThings(players map[uint32]*Player) {
playersMutex.Lock()
for _, player := range players {
if player.joyStick != nil {
player.joyStick.Close()
}
if player.window != nil {
_ = player.window.Destroy()
}
if player.logicalSurface != nil {
player.logicalSurface.Free()
}
if player.playSurface != nil {
player.playSurface.Free()
}
if player.HUDSurface != nil {
player.HUDSurface.Free()
}
}
playersMutex.Unlock()
}
func createPlayer(local bool, thisPlayerColors PlayerColors, thisPlayerColorIndex uint32, conn *net.TCPConn, keyMap KeyMap, joyMap JoyMap, joyStick *sdl.Joystick, gameMap *GameMap, players map[uint32]*Player, bases map[uint32]*Base) uint32 {
coordsAreValid := false
var posX, posY uint32
maxTries := 1000
baseSize := uint32(36) // Since the base is 36x36
minDistance := uint32(200) // Minimum distance between bases
maxDistance := uint32(500) // Maximum distance between bases
for !coordsAreValid && maxTries >= 0 {
maxTries--
posX = uint32(16 + rand.Intn(int(gameMap.width-baseSize-16)))
posY = uint32(16 + rand.Intn(int(gameMap.height-baseSize-16)))
coordsAreValid = true
baseMutex.RLock()
for _, base := range bases {
basePosX := uint32(base.gameObject.baseRect.X)
basePosY := uint32(base.gameObject.baseRect.Y)
// Calculate the distance between the edges of the bases
distanceX := max(0, max(basePosX-posX-baseSize, posX-basePosX-baseSize))
distanceY := max(0, max(basePosY-posY-baseSize, posY-basePosY-baseSize))
distanceSquared := distanceX*distanceX + distanceY*distanceY
if distanceSquared < minDistance*minDistance && distanceSquared > maxDistance*maxDistance {
coordsAreValid = false
break
}
}
baseMutex.RUnlock()
// Edge clamping to ensure the base is within the map boundaries
if posX < 16 || posX > gameMap.width-baseSize-16 || posY < 16 || posY > gameMap.height-baseSize-16 {
coordsAreValid = false
break
}
}
if maxTries < 0 {
panic("Could not place all players, increase map size")
}
gameObject := &GameObject{}
gameObject.baseRect = &sdl.Rect{
X: int32(posX),
Y: int32(posY),
W: 7,
H: 7,
}
gameObject.addColor(thisPlayerColors.tracks)
gameObject.addColor(thisPlayerColors.body)
gameObject.addColor(thisPlayerColors.cannon)
gameObject.orientation = 0 // Up
gameObject.addColoredRect(0, 1, 1, 6, 0)
gameObject.addColoredRect(4, 1, 1, 6, 0)
gameObject.addColoredRect(1, 2, 3, 4, 1)
gameObject.addColoredRect(2, 0, 1, 4, 2)
gameObject.orientation = 1 // Right
gameObject.addColoredRect(0, 0, 6, 1, 0)
gameObject.addColoredRect(0, 4, 6, 1, 0)
gameObject.addColoredRect(1, 1, 4, 3, 1)
gameObject.addColoredRect(3, 2, 4, 1, 2)
gameObject.orientation = 2 // Down
gameObject.addColoredRect(0, 0, 1, 6, 0)
gameObject.addColoredRect(4, 0, 1, 6, 0)
gameObject.addColoredRect(1, 1, 3, 4, 1)
gameObject.addColoredRect(2, 3, 1, 4, 2)
gameObject.orientation = 3 // Left
gameObject.addColoredRect(1, 0, 6, 1, 0)
gameObject.addColoredRect(1, 4, 6, 1, 0)
gameObject.addColoredRect(2, 1, 4, 3, 1)
gameObject.addColoredRect(0, 2, 4, 1, 2)
gameObject.orientation = 4 // Up-Right
gameObject.addColoredRect(3, 0, 1, 1, 0)
gameObject.addColoredRect(2, 1, 1, 1, 0)
gameObject.addColoredRect(1, 2, 1, 1, 0)
gameObject.addColoredRect(0, 3, 1, 1, 0)
gameObject.addColoredRect(6, 3, 1, 1, 0)
gameObject.addColoredRect(5, 4, 1, 1, 0)
gameObject.addColoredRect(4, 5, 1, 1, 0)
gameObject.addColoredRect(3, 6, 1, 1, 0)
gameObject.addColoredRect(3, 1, 1, 1, 1)
gameObject.addColoredRect(2, 2, 2, 1, 1)
gameObject.addColoredRect(1, 3, 2, 1, 1)
gameObject.addColoredRect(4, 3, 2, 1, 1)
gameObject.addColoredRect(2, 4, 3, 1, 1)
gameObject.addColoredRect(3, 5, 1, 1, 1)
gameObject.addColoredRect(5, 1, 1, 1, 2)
gameObject.addColoredRect(4, 2, 1, 1, 2)
gameObject.addColoredRect(3, 3, 1, 1, 2)
// Up-Left orientation (Y-axis reflection)
gameObject.orientation = 5 // Up-Left
gameObject.addColoredRect(3, 0, 1, 1, 0)
gameObject.addColoredRect(4, 1, 1, 1, 0)
gameObject.addColoredRect(5, 2, 1, 1, 0)
gameObject.addColoredRect(6, 3, 1, 1, 0)
gameObject.addColoredRect(0, 3, 1, 1, 0)
gameObject.addColoredRect(1, 4, 1, 1, 0)
gameObject.addColoredRect(2, 5, 1, 1, 0)
gameObject.addColoredRect(3, 6, 1, 1, 0)
gameObject.addColoredRect(3, 1, 1, 1, 1)
gameObject.addColoredRect(3, 2, 2, 1, 1)
gameObject.addColoredRect(4, 3, 2, 1, 1)
gameObject.addColoredRect(1, 3, 2, 1, 1)
gameObject.addColoredRect(2, 4, 3, 1, 1)
gameObject.addColoredRect(3, 5, 1, 1, 1)
gameObject.addColoredRect(1, 1, 1, 1, 2)
gameObject.addColoredRect(2, 2, 1, 1, 2)
gameObject.addColoredRect(3, 3, 1, 1, 2)
// Down-Right orientation (X-axis reflection)
gameObject.orientation = 6 // Down-Right
gameObject.addColoredRect(3, 6, 1, 1, 0)
gameObject.addColoredRect(2, 5, 1, 1, 0)
gameObject.addColoredRect(1, 4, 1, 1, 0)
gameObject.addColoredRect(0, 3, 1, 1, 0)
gameObject.addColoredRect(6, 3, 1, 1, 0)
gameObject.addColoredRect(5, 2, 1, 1, 0)
gameObject.addColoredRect(4, 1, 1, 1, 0)
gameObject.addColoredRect(3, 0, 1, 1, 0)
gameObject.addColoredRect(3, 5, 1, 1, 1)
gameObject.addColoredRect(2, 4, 2, 1, 1)
gameObject.addColoredRect(1, 3, 2, 1, 1)
gameObject.addColoredRect(4, 3, 2, 1, 1)
gameObject.addColoredRect(2, 2, 3, 1, 1)
gameObject.addColoredRect(3, 1, 1, 1, 1)
gameObject.addColoredRect(5, 5, 1, 1, 2)
gameObject.addColoredRect(4, 4, 1, 1, 2)
gameObject.addColoredRect(3, 3, 1, 1, 2)
// Down-Left orientation (XY reflection)
gameObject.orientation = 7 // Down-Left
gameObject.addColoredRect(3, 6, 1, 1, 0)
gameObject.addColoredRect(4, 5, 1, 1, 0)
gameObject.addColoredRect(5, 4, 1, 1, 0)
gameObject.addColoredRect(6, 3, 1, 1, 0)
gameObject.addColoredRect(0, 3, 1, 1, 0)
gameObject.addColoredRect(1, 2, 1, 1, 0)
gameObject.addColoredRect(2, 1, 1, 1, 0)
gameObject.addColoredRect(3, 0, 1, 1, 0)
gameObject.addColoredRect(3, 1, 1, 1, 1)
gameObject.addColoredRect(2, 2, 3, 1, 1)
gameObject.addColoredRect(1, 3, 2, 1, 1)
gameObject.addColoredRect(4, 3, 2, 1, 1)
gameObject.addColoredRect(3, 4, 2, 1, 1)
gameObject.addColoredRect(3, 5, 1, 1, 1)
gameObject.addColoredRect(1, 5, 1, 1, 2)
gameObject.addColoredRect(2, 4, 1, 1, 2)
gameObject.addColoredRect(3, 3, 1, 1, 2)
gameObject.orientation = 0
gameObject.adjustBaseRect()
if !local && (keyMap.exit != keyMap.shoot || joyMap.exitButton != joyMap.shootButton) {
panic("Input assigned to remote player")
}
knownGameMap := GameMap{width: gameMap.width, height: gameMap.height, tiles: make([][]uint8, serverConfig.MapWidth)}
for i := uint32(0); i < serverConfig.MapWidth; i++ {
knownGameMap.tiles[i] = make([]uint8, serverConfig.MapHeight)
}
playersMutex.Lock()
players[lastPlayerID] = &Player{
playerColors: thisPlayerColors,
playerColorID: thisPlayerColorIndex,
keyMap: keyMap,
joyMap: joyMap,
joyStick: joyStick,
shields: serverConfig.MaxShields,
energy: serverConfig.MaxEnergy,
gameObject: gameObject,
local: local,
connection: conn,
playerID: lastPlayerID,
knownBulletParticles: make(map[uint32]*BulletParticle),
knownBases: make(map[uint32]*Base),
knownPlayers: make(map[uint32]*Player),
knownBullets: make(map[uint32]*Bullet),
knownGameMap: &knownGameMap,
}
playersMutex.Unlock()
lastPlayerID++
return lastPlayerID - 1
}