games

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package games is the seam between kbot's shared TA-format machinery and the behaviour that genuinely differs per game. The formats packages stay data-driven — a TNT or COB announces its own dialect through version words, and parsing dispatches on what the bytes say. Everything that instead depends on which GAME an install is — palette resolution rules, sound-event wiring, terrain groups, branding — lives behind the Game/Adapter interfaces here, with one implementation per game under games/totala and games/takingdoms.

A custom game built on the TA formats extends this cleanly: implement Game (usually by embedding one of the shipped games and overriding the parts that differ), Register it, and point a kbot context's `game` id at it.

Unit-meta building: the asset bridge that turns a unit's FBI (plus its weapon TDF data) into the simulation's fixed-point stat block. Both shipped games funnel through the same pipeline — the TA pass resolves Weapon1/2/3 references through the caller's weapons index, and the TA:K pass fills any slots the FBI declares inline — so detection is data-driven: a file's own shape decides which passes contribute, and a custom game's units work with either convention.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyTAKWeapons

func ApplyTAKWeapons(m *sim.UnitMeta, u *tak.Unit)

ApplyTAKWeapons fills any empty weapon slots from a TA:Kingdoms unit's inline [WEAPONn] sections. TA:K FBIs carry the weapon definitions as top-level siblings of [UNITINFO] instead of weapons/*.tdf references, so the ref-based loop in MetaFromUnitInfo finds nothing for them. Both asset bridges (native flattened-tree and studio VFS) call this after the TA pass so a unit gets identical stats on the authority and in the browser.

func CanbuildDirOptions

func CanbuildDirOptions(fs VFS) map[string][]string

CanbuildDirOptions reads TA:K's canbuild/<builder>/<unit>.tdf grants: builder (upper-case) → buildable names ordered by [Menu] Priority then name.

func DownloadMenuOptions

func DownloadMenuOptions(fs VFS) map[string][]string

DownloadMenuOptions reads download/*.tdf [MENUENTRY*] sections — the add-on mechanism both games' mods use — returning builder (upper-case) → added names ordered by (MENU, BUTTON, file order).

func GlobalPalette

func GlobalPalette(fs VFS, embedded []byte) *gaf.Palette

GlobalPalette loads the install's global palette (palettes/palette.pal) with the embedded TA palette as fallback, never returning nil. Shared by both games: TA uses it for everything, TA:K as the last-resort fallback when a side palette is missing.

func IDs

func IDs() []string

IDs lists the registered game ids in sorted order, for help text and error messages.

func MergeBuildOptions

func MergeBuildOptions(base, extras []string) []string

MergeBuildOptions appends extras onto base, deduplicating while keeping first-seen order.

func MetaFromUnitInfo

func MetaFromUnitInfo(name string, info *ta.UnitInfo, resolveWeapon func(ref string) (ta.Weapon, bool)) *sim.UnitMeta

MetaFromUnitInfo converts a parsed FBI [UNITINFO] block into the simulation's fixed-point stat block. resolveWeapon maps an FBI weapon reference (Weapon1/2/3) to its parsed TDF section, returning ok=false for an unknown ref. Both asset bridges — the native flattened-tree provider and the studio VFS provider — funnel through here so a unit gets identical stats regardless of where the bytes were read from.

func Register

func Register(g Game)

Register adds a game to the registry. The shipped games register themselves from their package init; a custom game does the same from its own package.

func SidedataBuildOptions

func SidedataBuildOptions(fs VFS) map[string][]string

SidedataBuildOptions reads TA's [CANBUILD] table: builder (upper-case) → ordered buildable names (lower-case).

func UnitMetaFromFBI

func UnitMetaFromFBI(name string, fbi []byte, resolve WeaponResolver) (*sim.UnitMeta, error)

UnitMetaFromFBI parses raw FBI bytes and builds the full stat block: the TA reference pass first, then the TA:K inline-weapon pass for any slots still empty.

Types

type Adapter

type Adapter interface {
	Game() Game

	PaletteResolver

	// CursorPalette returns the palette for the cursors GAF, or nil when the
	// game uses the global palette (the caller then falls back to it).
	CursorPalette() *gaf.Palette

	// UnitSounds resolves a unit's sound-event map for its FBI sound
	// category: TA-style event keys (select1, ok1, arrived1, …) to .wav
	// stems. Returns nil when the category resolves to nothing.
	UnitSounds(category string) map[string]string

	// Tilesets lists the map editor's terrain groups: TA's fixed world list,
	// TA:K's kingdoms from sidedata.
	Tilesets() []Tileset

	// MapTerrainGroup names the terrain group a map belongs to when the
	// game tracks it outside the map file itself — TA:K reads the kingdom=
	// affinity from the sibling .ota. "" when the game has no such notion
	// (TA's planet lives in the .ota planet= the caller already parses).
	MapTerrainGroup(mapPath string) string

	// BuildOptions lists the unit names (lower-case, ordered as the game's
	// menus order them) a builder unit can construct, resolved from the
	// game's canbuild data plus any download-menu add-ons. Empty for
	// non-builders.
	BuildOptions(unit string) []string
}

Adapter is a Game bound to a mounted install: every per-game decision the shared studio/server code needs, answered against that install's data.

type Game

type Game interface {
	// ID is the kbot context identifier ("totala", "takingdoms").
	ID() string
	// Name is the human-readable title.
	Name() string
	// NewAdapter binds the game's rules to one mounted install. Adapters
	// cache parsed game data (sidedata, sound tables) for their lifetime,
	// so sessions should hold one adapter, not re-create them per request.
	NewAdapter(fs VFS) Adapter
}

Game identifies one supported game and builds per-session adapters for it. Implementations are stateless singletons; all per-install caching lives on the Adapter.

func Lookup

func Lookup(id string) (Game, bool)

Lookup returns the Game registered under an exact id, with ok=false for unknown ids — for callers that must reject rather than fall back (CLI argument validation, config checks).

func Resolve

func Resolve(id string) Game

Resolve returns the Game for a kbot context id. Unknown ids — including "custom" contexts that haven't registered their own Game — resolve to the registered "totala" implementation, the baseline TA-format behaviour a custom game is assumed to start from.

type PaletteResolver

type PaletteResolver interface {
	// TexturePalette returns the palette for a 3DO model texture GAF (by VFS path).
	TexturePalette(gafPath string) *gaf.Palette
	// ModelColorPalette returns the palette for a 3DO model's colour-keyed
	// primitives (by object/model name).
	ModelColorPalette(object string) color.Palette
	// FeaturePalette returns the palette for a feature / anim sprite GAF.
	FeaturePalette(gafName string) *gaf.Palette
	// TerrainPalette returns the palette for a map's terrain + baked minimap
	// (by map VFS path).
	TerrainPalette(mapPath string) color.Palette
	// TextureRenderOptions returns how 3DO model textures resolve
	// transparency, given the resolved palette. TA renders unit textures
	// fully opaque (palette[TI] is a real colour); TA:Kingdoms texture
	// atlases reserve a transparent key colour which must be punched out.
	TextureRenderOptions(pal *gaf.Palette) gaf.RenderOptions
	// TextureSidePrefix returns the side name-prefix (lowercase, e.g. "ara")
	// for a 3DO model name, or "" when sides don't apply.
	TextureSidePrefix(object string) string
	// TexturePaletteForSide returns the texture palette for an explicit side
	// prefix (the ?side= a client passes with a texture fetch), or nil when
	// the side is unknown / sides don't apply.
	TexturePaletteForSide(side string) *gaf.Palette
}

PaletteResolver decides which palette applies to each kind of game asset. Rendering code consults the resolver and never special-cases the game.

Total Annihilation keys everything off one global palette. TA:Kingdoms has no global palette — gamedata/sidedata.tdf assigns each side a `nameprefix`, a texture `palette` and a `buildpalette`, and terrain uses a per-kingdom table; its resolver maps an asset's name prefix to its palette.

type Tileset

type Tileset struct {
	Slug           string `json:"slug"`
	Label          string `json:"label"`
	DefaultTileset string `json:"defaultTileset"`
}

Tileset is one terrain set selectable when creating a new map. JSON tags match the studio's /api/studio/tilesets response shape so adapters' results serialize directly.

type VFS

type VFS interface {
	ReadFile(path string) ([]byte, error)
	Exists(path string) bool
	List() []string
}

VFS is the read surface an Adapter resolves game data against — the mounted install (or workspace overlay) a session owns. filesystem.VirtualFileSystem satisfies it.

type WeaponResolver

type WeaponResolver func(ref string) (ta.Weapon, bool)

WeaponResolver maps an FBI weapon reference (Weapon1/2/3) to its parsed weapons/*.tdf section, returning ok=false for an unknown ref.

Directories

Path Synopsis
Package takingdoms implements games.Game for Total Annihilation: Kingdoms.
Package takingdoms implements games.Game for Total Annihilation: Kingdoms.
Package totala implements games.Game for Total Annihilation: one global palette for every asset class, sound events from gamedata/sound.tdf, and the classic fixed world list for the map editor.
Package totala implements games.Game for Total Annihilation: one global palette for every asset class, sound events from gamedata/sound.tdf, and the classic fixed world list for the map editor.

Jump to

Keyboard shortcuts

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