Documentation
¶
Index ¶
- Constants
- Variables
- func ApplyDamageWithShields(p *Player, damage int) int
- func Distance(x1, y1, x2, y2 float64) float64
- func EffectivePlasmaRange(ship ShipType, safetyFactor float64) float64
- func EffectiveTorpRange(shipStats ShipStats, safetyMargin float64) int
- func EffectiveTorpRangeDefault(shipStats ShipStats) int
- func EffectiveTorpRangeForShip(shipType ShipType, shipStats ShipStats) int
- func GetPlasmaRangeTable() map[ShipType]float64
- func GetShipExplosionDamage(shipType ShipType) int
- func InitINLPlanetFlags(gs *GameState)
- func InitPlanets(gs *GameState)
- func Max(a, b int) int
- func MaxPlasmaRange(fuseTicks int, speedUnitsPerTick float64) float64
- func MaxPlasmaRangeForShip(ship ShipType) float64
- func MaxTorpRange(shipStats ShipStats) int
- func Min(a, b int) int
- func NormalizeAngle(angle float64) float64
- func PhaserRange(stats ShipStats) float64
- type GameState
- type Planet
- type Plasma
- type Player
- type ShipStats
- type ShipType
- type Torpedo
- type TournamentPlayerStats
Constants ¶
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
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
const ( TeamNone = 0 TeamFed = 1 << 0 TeamRom = 1 << 1 TeamKli = 1 << 2 TeamOri = 1 << 3 )
Team IDs
const ( StatusFree = 0 StatusOutfit = 1 StatusAlive = 2 StatusExplode = 3 StatusDead = 4 StatusObserve = 5 )
Player Status
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)
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)
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
const ( PlanetRepair = 1 << 4 PlanetFuel = 1 << 5 PlanetAgri = 1 << 6 PlanetHome = 1 << 8 PlanetCore = 1 << 11 )
PlanetFlags
const (
ArmyKillRequirement = 2.0 // Kills required to pick up armies (classic Netrek rule)
)
Army constants
const (
PlanetFireDist = 1500 // Distance at which planets fire at enemy ships
)
Planet combat constants
Variables ¶
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, }, }
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
var TeamHomeX = map[int]int{ TeamFed: 20000, TeamRom: 20000, TeamKli: 80000, TeamOri: 80000, }
Team home positions for respawn
Functions ¶
func ApplyDamageWithShields ¶
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 EffectivePlasmaRange ¶
EffectivePlasmaRange returns a conservative estimate of plasma range accounting for target movement and tactical considerations
func EffectiveTorpRange ¶
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 ¶
EffectiveTorpRangeDefault returns the effective torpedo range using the default safety margin.
func EffectiveTorpRangeForShip ¶
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 ¶
GetPlasmaRangeTable returns a map of ship types to their maximum plasma ranges for debugging and documentation purposes
func GetShipExplosionDamage ¶
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 MaxPlasmaRange ¶
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 ¶
MaxPlasmaRangeForShip calculates the maximum plasma range for a specific ship type
func MaxTorpRange ¶
MaxTorpRange returns the absolute maximum distance a torpedo can fly before its fuse expires (no safety margin). Formula: (TorpSpeed * TorpUnitFactor) * TorpFuse
func NormalizeAngle ¶
NormalizeAngle keeps angle between 0 and 2*PI
func PhaserRange ¶
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 ¶
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 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