game

package
v0.0.0-...-a534920 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 14, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// TorpUnitFactor is the multiplier that converts ship TorpSpeed to units per tick
	// This matches the formula used in server/handlers.go: shipStats.TorpSpeed * 20
	TorpUnitFactor = 20

	// DefaultTorpSafety is the default safety margin for effective torpedo range
	// This ensures torpedoes reach targets before fuse expires, accounting for
	// target movement and aiming errors.
	DefaultTorpSafety = 0.85
)

Torpedo physics constants

View Source
const (
	MaxPlayers = 64
	MaxPlanets = 40
	MaxTorps   = 8
	MaxPlasma  = 1

	// Galaxy dimensions
	GalaxyWidth  = 100000
	GalaxyHeight = 100000

	// Distance constants
	ExplosionDist = 350
	DamageDist    = 2000
	PhaserDist    = 6000 // Base phaser range constant from original Netrek
	TractorDist   = 6000
	EntOrbitDist  = 900 // Maximum distance to enter orbit
	OrbitDist     = 800 // Actual orbit radius
	DockDist      = 600
	ORBSPEED      = 2 // Maximum speed to enter orbit (from original Netrek)

	// Ship explosion constants (from original Netrek)
	ShipExplosionDist    = 350  // Ships within this distance take full damage
	ShipExplosionMaxDist = 3000 // Maximum explosion damage radius
	ShipExplosionRange   = 2650 // Used in damage falloff calculation (MaxDist - ExplosionDist)

	// Plasma explosion constant
	PlasmaExplosionDist = 1500 // Plasma has larger explosion radius than torpedoes

	// Phaser hit detection constants (from original Netrek)
	ZAPPLAYERDIST = 390 // Phaser will hit player if line is this close
	ZAPPLASMADIST = 270 // Phaser will hit plasma if line is this close

	// Game timing
	FPS            = 10
	UpdateInterval = time.Millisecond * 100 // 10 FPS (10 ticks per second)

	// Physics constants
	FractionScale = 1000 // Scale factor for fractional accumulators (turn rate, acceleration)

	// Tractor/Pressor beam constants (from original Netrek daemon.c)
	TractorForceWarp = 20 // Tractor force = TractorForceWarp * TractorStr (WARP1 in original)
	TractorFuelCost  = 20 // Fuel cost per tick when using tractor/pressor
	TractorHeatCost  = 5  // Engine heat added per tick when using tractor/pressor

	// Alert level range constants (from original Netrek)
	AlertYellowRange = 14285 // YRANGE = GWIDTH/7 = 100000/7
	AlertRedRange    = 10000 // RRANGE = GWIDTH/10 = 100000/10

	// Temperature limits
	MaxEngineTempCap = 1500 // Maximum engine temperature cap

	// Ship type count for validation
	NumShipTypes = 6 // Scout, Destroyer, Cruiser, Battleship, Assault, Starbase

	// Animation timing
	ExplodeTimerFrames = 10 // Number of frames for explosion animation
)

Constants from original Netrek

View Source
const (
	TeamNone = 0
	TeamFed  = 1 << 0
	TeamRom  = 1 << 1
	TeamKli  = 1 << 2
	TeamOri  = 1 << 3
)

Team IDs

View Source
const (
	StatusFree    = 0
	StatusOutfit  = 1
	StatusAlive   = 2
	StatusExplode = 3
	StatusDead    = 4
	StatusObserve = 5
)

Player Status

View Source
const (
	TorpFree    = 0 // Projectile slot is free/unused
	TorpMove    = 1 // Projectile is alive and moving
	TorpExplode = 2 // Projectile is exploding
	TorpDet     = 3 // Projectile has been detonated
)

Projectile Status (Torpedo and Plasma)

View Source
const (
	KillNone      = 0 // No death / reset state
	KillTorp      = 1 // Killed by torpedo
	KillPhaser    = 2 // Killed by phaser
	KillPlanet    = 3 // Killed by planet
	KillExplosion = 4 // Killed by explosion
	KillQuit      = 5 // Player quit
	KillDaemon    = 6 // Server killed player
	KillPlasma    = 7 // Killed by plasma torpedo
)

Death reasons (why player died)

View Source
const (
	StarbaseEnemyDetectRange = 12000      // Distance to start combat logic
	StarbaseTorpRange        = 8400       // Maximum torpedo firing range (14*20*30 = actual max range)
	StarbasePhaserRange      = PhaserDist // Use base phaser range (6000)
	StarbasePlasmaMaxRange   = 6000       // Maximum plasma firing range
	StarbasePlasmaMinRange   = 2000       // Minimum plasma firing range
)

Starbase combat constants

View Source
const (
	PlanetRepair = 1 << 4
	PlanetFuel   = 1 << 5
	PlanetAgri   = 1 << 6
	PlanetHome   = 1 << 8
	PlanetCore   = 1 << 11
)

PlanetFlags

View Source
const (
	ArmyKillRequirement = 2.0 // Kills required to pick up armies (classic Netrek rule)
)

Army constants

View Source
const (
	PlanetFireDist = 1500 // Distance at which planets fire at enemy ships
)

Planet combat constants

Variables

View Source
var ShipData = map[ShipType]ShipStats{
	ShipScout: {
		Name:           "Scout",
		MaxSpeed:       12,
		MaxFuel:        5000,
		MaxShields:     75,
		MaxDamage:      75,
		MaxArmies:      2,
		TorpDamage:     25,
		TorpSpeed:      16,
		TorpFuse:       16,
		PhaserDamage:   75,
		TurnRate:       570000,
		Mass:           1500,
		TractorStr:     2000,
		HasPlasma:      false,
		MaxWpnTemp:     1000,
		MaxEngTemp:     1000,
		TorpFuelMult:   7,
		PhaserFuelMult: 7,
		TractorRange:   0.7,
		AccInt:         200,
		DecInt:         270,
		RepairRate:     80,
		FuelRecharge:   8,
		WpnCool:        2,
		EngCool:        5,
		CloakCost:      17,
		ShieldFuelCost: 2,
		DetCost:        100,
	},
	ShipDestroyer: {
		Name:           "Destroyer",
		MaxSpeed:       10,
		MaxFuel:        7000,
		MaxShields:     85,
		MaxDamage:      85,
		MaxArmies:      5,
		TorpDamage:     30,
		TorpSpeed:      14,
		TorpFuse:       30,
		PhaserDamage:   85,
		PlasmaDamage:   75,
		PlasmaSpeed:    15,
		PlasmaFuse:     30,
		TurnRate:       310000,
		Mass:           1800,
		TractorStr:     2500,
		HasPlasma:      true,
		MaxWpnTemp:     1000,
		MaxEngTemp:     1000,
		TorpFuelMult:   7,
		PhaserFuelMult: 7,
		PlasmaFuelMult: 30,
		TractorRange:   0.9,
		AccInt:         200,
		DecInt:         300,
		RepairRate:     100,
		FuelRecharge:   11,
		WpnCool:        2,
		EngCool:        5,
		CloakCost:      21,
		ShieldFuelCost: 3,
		DetCost:        100,
	},
	ShipCruiser: {
		Name:           "Cruiser",
		MaxSpeed:       9,
		MaxFuel:        10000,
		MaxShields:     100,
		MaxDamage:      100,
		MaxArmies:      10,
		TorpDamage:     40,
		TorpSpeed:      12,
		TorpFuse:       40,
		PhaserDamage:   100,
		PlasmaDamage:   100,
		PlasmaSpeed:    15,
		PlasmaFuse:     35,
		TurnRate:       170000,
		Mass:           2000,
		TractorStr:     3000,
		HasPlasma:      true,
		MaxWpnTemp:     1000,
		MaxEngTemp:     1000,
		TorpFuelMult:   7,
		PhaserFuelMult: 7,
		PlasmaFuelMult: 30,
		TractorRange:   1.0,
		AccInt:         150,
		DecInt:         200,
		RepairRate:     110,
		FuelRecharge:   12,
		WpnCool:        2,
		EngCool:        5,
		CloakCost:      26,
		ShieldFuelCost: 3,
		DetCost:        100,
	},
	ShipBattleship: {
		Name:           "Battleship",
		MaxSpeed:       8,
		MaxFuel:        14000,
		MaxShields:     130,
		MaxDamage:      130,
		MaxArmies:      6,
		TorpDamage:     40,
		TorpSpeed:      12,
		TorpFuse:       40,
		PhaserDamage:   105,
		PlasmaDamage:   130,
		PlasmaSpeed:    15,
		PlasmaFuse:     35,
		TurnRate:       75000,
		Mass:           2300,
		TractorStr:     3700,
		HasPlasma:      true,
		MaxWpnTemp:     1000,
		MaxEngTemp:     1000,
		TorpFuelMult:   9,
		PhaserFuelMult: 10,
		PlasmaFuelMult: 30,
		TractorRange:   1.2,
		AccInt:         80,
		DecInt:         180,
		RepairRate:     125,
		FuelRecharge:   14,
		WpnCool:        2,
		EngCool:        5,
		CloakCost:      30,
		ShieldFuelCost: 3,
		DetCost:        100,
	},
	ShipAssault: {
		Name:           "Assault",
		MaxSpeed:       8,
		MaxFuel:        6000,
		MaxShields:     80,
		MaxDamage:      200,
		MaxArmies:      20,
		TorpDamage:     30,
		TorpSpeed:      16,
		TorpFuse:       30,
		PhaserDamage:   80,
		TurnRate:       120000,
		Mass:           2300,
		TractorStr:     2500,
		HasPlasma:      false,
		MaxWpnTemp:     1000,
		MaxEngTemp:     1200,
		TorpFuelMult:   9,
		PhaserFuelMult: 7,
		TractorRange:   0.7,
		AccInt:         100,
		DecInt:         200,
		RepairRate:     120,
		FuelRecharge:   10,
		WpnCool:        2,
		EngCool:        7,
		CloakCost:      17,
		ShieldFuelCost: 3,
		DetCost:        100,
	},
	ShipStarbase: {
		Name:           "Starbase",
		MaxSpeed:       2,
		MaxFuel:        60000,
		MaxShields:     500,
		MaxDamage:      600,
		MaxArmies:      25,
		TorpDamage:     30,
		TorpSpeed:      14,
		TorpFuse:       30,
		PhaserDamage:   120,
		PlasmaDamage:   150,
		PlasmaSpeed:    15,
		PlasmaFuse:     25,
		TurnRate:       50000,
		Mass:           5000,
		TractorStr:     8000,
		HasPlasma:      true,
		MaxWpnTemp:     1300,
		MaxEngTemp:     1000,
		TorpFuelMult:   10,
		PhaserFuelMult: 8,
		PlasmaFuelMult: 25,
		TractorRange:   1.5,
		AccInt:         100,
		DecInt:         200,
		RepairRate:     140,
		FuelRecharge:   35,
		WpnCool:        3,
		EngCool:        5,
		CloakCost:      75,
		ShieldFuelCost: 6,
		DetCost:        100,
	},
}
View Source
var ShipSafetyFactor = map[ShipType]float64{
	ShipScout:      0.65,
	ShipDestroyer:  0.70,
	ShipCruiser:    0.75,
	ShipBattleship: 0.75,
	ShipAssault:    0.65,
	ShipStarbase:   0.80,
}

ShipSafetyFactor defines per-ship safety margins for torpedo firing range These more conservative factors help prevent torpedoes from expiring before reaching moving targets, especially for slower torpedo ships

View Source
var TeamHomeX = map[int]int{
	TeamFed: 20000,
	TeamRom: 20000,
	TeamKli: 80000,
	TeamOri: 80000,
}

Team home positions for respawn

View Source
var TeamHomeY = map[int]int{
	TeamFed: 80000,
	TeamRom: 20000,
	TeamKli: 20000,
	TeamOri: 80000,
}

Functions

func ApplyDamageWithShields

func ApplyDamageWithShields(p *Player, damage int) int

ApplyDamageWithShields applies damage to shields first, then hull. Returns the total amount of damage actually applied. This ensures consistent damage handling across all weapon types.

func Distance

func Distance(x1, y1, x2, y2 float64) float64

Distance calculates distance between two points

func EffectivePlasmaRange

func EffectivePlasmaRange(ship ShipType, safetyFactor float64) float64

EffectivePlasmaRange returns a conservative estimate of plasma range accounting for target movement and tactical considerations

func EffectiveTorpRange

func EffectiveTorpRange(shipStats ShipStats, safetyMargin float64) int

EffectiveTorpRange returns MaxTorpRange multiplied by a safety margin to make bots fire only when a hit is reasonably possible. The safety margin accounts for target movement and aiming imperfection.

func EffectiveTorpRangeDefault

func EffectiveTorpRangeDefault(shipStats ShipStats) int

EffectiveTorpRangeDefault returns the effective torpedo range using the default safety margin.

func EffectiveTorpRangeForShip

func EffectiveTorpRangeForShip(shipType ShipType, shipStats ShipStats) int

EffectiveTorpRangeForShip returns the effective torpedo range using ship-specific safety margins. This provides more conservative ranges for bots to prevent torpedo fuse expiry.

func GetPlasmaRangeTable

func GetPlasmaRangeTable() map[ShipType]float64

GetPlasmaRangeTable returns a map of ship types to their maximum plasma ranges for debugging and documentation purposes

func GetShipExplosionDamage

func GetShipExplosionDamage(shipType ShipType) int

GetShipExplosionDamage returns the explosion damage for a ship type Based on original Netrek: SB=200, SC=75, all others=100

func InitINLPlanetFlags

func InitINLPlanetFlags(gs *GameState)

InitINLPlanetFlags sets up planet flags for INL (International Netrek League) mode This distributes AGRI, FUEL, and REPAIR flags strategically across the galaxy

func InitPlanets

func InitPlanets(gs *GameState)

InitPlanets initializes the 40 planets with their positions and teams Data exactly matches the original Netrek game

func Max

func Max(a, b int) int

Max returns the maximum of two integers

func MaxPlasmaRange

func MaxPlasmaRange(fuseTicks int, speedUnitsPerTick float64) float64

MaxPlasmaRange calculates the maximum distance a plasma torpedo can travel before its fuse expires, given the fuse time (in ticks) and speed (units per tick)

func MaxPlasmaRangeForShip

func MaxPlasmaRangeForShip(ship ShipType) float64

MaxPlasmaRangeForShip calculates the maximum plasma range for a specific ship type

func MaxTorpRange

func MaxTorpRange(shipStats ShipStats) int

MaxTorpRange returns the absolute maximum distance a torpedo can fly before its fuse expires (no safety margin). Formula: (TorpSpeed * TorpUnitFactor) * TorpFuse

func Min

func Min(a, b int) int

Min returns the minimum of two integers

func NormalizeAngle

func NormalizeAngle(angle float64) float64

NormalizeAngle keeps angle between 0 and 2*PI

func PhaserRange

func PhaserRange(stats ShipStats) float64

PhaserRange returns the effective phaser range for a ship. Formula from original Netrek: PHASEDIST * phaserdamage / 100

Types

type GameState

type GameState struct {
	Mu sync.RWMutex // Made public for access from server package

	Players [MaxPlayers]*Player
	Planets [MaxPlanets]*Planet
	Torps   []*Torpedo
	Plasmas []*Plasma

	Frame     int64
	TickCount int   // Tick counter for periodic events
	T_mode    bool  // Tournament mode
	T_start   int64 // Tournament start time (frame)
	T_remain  int   // Tournament time remaining (seconds)
	GameOver  bool
	Winner    int    // Winning team (if GameOver)
	WinType   string // "genocide" or "conquest"

	// Team statistics
	TeamPlanets [4]int // Planet count per team
	TeamPlayers [4]int // Active player count per team

	// Tournament statistics
	TournamentStats map[int]*TournamentPlayerStats // Player ID -> stats
}

GameState holds the entire game state

func NewGameState

func NewGameState() *GameState

NewGameState creates a new game state with INL mode enabled by default

func NewGameStateWithMode

func NewGameStateWithMode(inlMode bool) *GameState

NewGameStateWithMode creates a new game state with optional INL mode

type Planet

type Planet struct {
	ID     int     `json:"id"`
	Name   string  `json:"name"`
	Label  string  `json:"label"` // 3-letter label for display
	X      float64 `json:"x"`
	Y      float64 `json:"y"`
	Owner  int     `json:"owner"` // Team that owns it
	Armies int     `json:"armies"`
	Info   int     `json:"info"`  // Information mask (who has scouted)
	Flags  int     `json:"flags"` // Planet flags (repair, fuel, agri, etc)
}

Planet represents a planet

type Plasma

type Plasma struct {
	ID     int     `json:"id"`
	Owner  int     `json:"owner"` // Player ID
	X      float64 `json:"x"`
	Y      float64 `json:"y"`
	Dir    float64 `json:"dir"`
	Speed  float64 `json:"speed"`
	Damage int     `json:"damage"`
	Fuse   int     `json:"fuse"`   // Ticks until explosion
	Status int     `json:"status"` // Free, Move, Explode, Det
	Team   int     `json:"team"`
}

Plasma represents a plasma torpedo (reuses Torpedo struct)

type Player

type Player struct {
	ID     int      `json:"id"`
	Name   string   `json:"name"`
	Team   int      `json:"team"`
	Ship   ShipType `json:"ship"`
	Status int      `json:"status"`

	// Position and movement
	X        float64 `json:"x"`
	Y        float64 `json:"y"`
	Dir      float64 `json:"dir"` // Direction in radians
	Speed    float64 `json:"speed"`
	DesSpeed float64 `json:"desSpeed"`
	DesDir   float64 `json:"desDir"`
	SubDir   int     `json:"-"` // Fractional turn accumulator (not sent to client)
	AccFrac  int     `json:"-"` // Fractional acceleration accumulator (not sent to client)

	// Ship status
	Shields     int     `json:"shields"`
	Damage      int     `json:"damage"`
	Fuel        int     `json:"fuel"`
	Armies      int     `json:"armies"`
	Kills       float64 `json:"kills"`
	KillsStreak float64 `json:"killsStreak"` // Second kill counter that resets on death
	Deaths      int     `json:"deaths"`

	// Weapons
	WTemp     int `json:"wtemp"` // Weapon temperature
	ETemp     int `json:"etemp"` // Engine temperature
	NumTorps  int `json:"numTorps"`
	NumPlasma int `json:"numPlasma"`

	// Flags
	Shields_up     bool `json:"shields_up"`
	Cloaked        bool `json:"cloaked"`
	Repairing      bool `json:"repairing"`     // In repair mode
	RepairRequest  bool `json:"repairRequest"` // Slowing down to repair
	RepairCounter  int  `json:"-"`             // Counter for repair timing (not sent to client)
	Bombing        bool `json:"bombing"`
	Beaming        bool `json:"beaming"`
	BeamingUp      bool `json:"beamingUp"`      // True if beaming up, false if beaming down
	EngineOverheat bool `json:"engineOverheat"` // Engine temp exceeded max (PFENG in original)
	Tractoring     int  `json:"tractoring"`     // Player ID being tractored, -1 if none
	Pressoring     int  `json:"pressoring"`     // Player ID being pressored, -1 if none

	// Lock-on
	LockType   string `json:"lockType"`   // "none", "player", or "planet"
	LockTarget int    `json:"lockTarget"` // ID of locked target

	// Orbiting
	Orbiting int `json:"orbiting"` // Planet ID, -1 if not orbiting

	// Death tracking
	ExplodeTimer   int  `json:"explodeTimer"` // Frames left in explosion animation
	KilledBy       int  `json:"killedBy"`     // Player ID who killed us
	WhyDead        int  `json:"whyDead"`      // Reason for death (KillTorp, KillPhaser, etc)
	RespawnMsgSent bool `json:"-"`            // True if "cannot respawn" message was sent (not sent to client)

	// Engine overheat tracking
	OverheatTimer int `json:"-"` // Frames left in overheat state (not sent to client)

	// Alert status
	AlertLevel string `json:"alertLevel"` // "green", "yellow", or "red"

	// Network
	Connected     bool      `json:"connected"`
	LastUpdate    time.Time `json:"-"`
	OwnerClientID int       `json:"-"` // Client ID that owns this slot (-1 if unowned/bot)

	// Bot fields
	IsBot               bool    `json:"isBot"`
	BotTarget           int     `json:"-"` // Current target player ID
	BotTargetLockTime   int     `json:"-"` // Ticks remaining for target lock
	BotTargetValue      float64 `json:"-"` // Current target's value score
	BotPlanetApproachID int     `json:"-"` // Planet ID bot is trying to approach (-1 if none)
	BotDefenseTarget    int     `json:"-"` // Planet ID bot is actively defending (-1 if none)
	BotGoalX            float64 `json:"-"` // Navigation goal
	BotGoalY            float64 `json:"-"`
	BotHasGoal          bool    `json:"-"` // Whether a patrol goal is set (avoids (0,0) sentinel)
	BotShieldFrame      int64   `json:"-"` // Last frame shields were assessed (avoids redundant per-tick calls)
	BotCooldown         int     `json:"-"` // Frames until next action

	// Refit system - ship type to use on next respawn (-1 means no pending refit)
	NextShipType int `json:"-"` // Ship type to use on next respawn
}

Player represents a player in the game

type ShipStats

type ShipStats struct {
	Name         string
	MaxSpeed     int
	MaxFuel      int
	MaxShields   int
	MaxDamage    int
	MaxArmies    int
	TorpDamage   int
	TorpSpeed    int
	TorpFuse     int
	PhaserDamage int
	PlasmaDamage int
	PlasmaSpeed  int
	PlasmaFuse   int // Plasma torpedo fuse time (in ticks)
	TurnRate     int // Turn rate in original units (higher = faster turning)
	Mass         int
	TractorStr   int
	HasPlasma    bool
	// Temperature limits
	MaxWpnTemp int // Maximum weapon temperature
	MaxEngTemp int // Maximum engine temperature
	// Fuel cost multipliers (from original Netrek)
	TorpFuelMult   int // Multiplier for torpedo fuel cost (damage * mult)
	PhaserFuelMult int // Multiplier for phaser fuel cost (damage * mult)
	PlasmaFuelMult int // Multiplier for plasma fuel cost (damage * mult)
	// Tractor/Pressor range multiplier
	TractorRange float64 // Multiplier for tractor/pressor range
	// Movement physics
	AccInt int // Acceleration integer (higher = faster acceleration)
	DecInt int // Deceleration integer (higher = faster deceleration)
	// Ship systems
	RepairRate     int // Repair rate (damage points per tick when repairing)
	FuelRecharge   int // Fuel recharge rate (fuel points per tick)
	WpnCool        int // Weapon cooling rate (temp units per tick)
	EngCool        int // Engine cooling rate (temp units per tick)
	CloakCost      int // Fuel cost per tick when cloaked
	ShieldFuelCost int // Fuel cost per tick when shields are up
	DetCost        int // Fuel cost for detonating enemy torpedoes
}

ShipStats holds the specifications for each ship type

type ShipType

type ShipType int

Ship Types

const (
	ShipScout ShipType = iota
	ShipDestroyer
	ShipCruiser
	ShipBattleship
	ShipAssault
	ShipStarbase
)

type Torpedo

type Torpedo struct {
	ID     int     `json:"id"`
	Owner  int     `json:"owner"` // Player ID
	X      float64 `json:"x"`
	Y      float64 `json:"y"`
	Dir    float64 `json:"dir"`
	Speed  float64 `json:"speed"`
	Damage int     `json:"damage"`
	Fuse   int     `json:"fuse"`   // Ticks until explosion
	Status int     `json:"status"` // Free, Move, Explode, Det
	Team   int     `json:"team"`
}

Torpedo represents a torpedo in space

type TournamentPlayerStats

type TournamentPlayerStats struct {
	Kills        int
	Deaths       int
	PlanetsTaken int
	PlanetsLost  int
	TorpsFired   int
	PhasersFired int
	DamageDealt  int
	DamageTaken  int
}

TournamentPlayerStats tracks player performance in tournament mode

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL