gore

package module
v0.0.0-...-eab4078 Latest Latest
Warning

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

Go to latest
Published: Nov 9, 2026 License: GPL-2.0 Imports: 23 Imported by: 1

README ΒΆ

πŸ”₯ GORE πŸ”₯

A Minimal Go Port of doomgeneric

    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•—   β–ˆβ–ˆβ–ˆβ•—
    β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ•‘
    β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β–ˆβ–ˆβ–ˆβ–ˆβ•”β–ˆβ–ˆβ•‘
    β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘
    β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β•šβ•β• β–ˆβ–ˆβ•‘
    β•šβ•β•β•β•β•β•  β•šβ•β•β•β•β•β•  β•šβ•β•β•β•β•β• β•šβ•β•     β•šβ•β•
                    .GO

TLDR

Tired of reading already?

wget https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad
go run github.com/AndreRenaud/gore/example/termdoom@latest

πŸ’€ WHAT FRESH HELL IS THIS?

This is a minimal, platform-agnostic Go port of the legendary DOOM engine, transpiled from the doomgeneric codebase. No CGo. No platform dependencies. Just pure, unadulterated demon-slaying action powered by the glory of Go's cross-compilation.

The original C code was converted to Go using (modernc.org/ccgo/v4), by cznic (https://gitlab.com/cznic/doomgeneric.git). This was then manually cleaned up to remove a lot of manual pointer manipulation, and make things more Go-ish, whilst still maintaining compatibility with the original Doom, and its overall structure.

πŸ”« FEATURES

  • βœ… Platform Agnostic: Runs anywhere Go runs
  • βœ… Minimal Dependencies: Only requires Go standard library
  • βœ… Multiple DOOM Versions: Supports DOOM, DOOM II, Ultimate DOOM, Final DOOM
  • βœ… WAD File Support: Bring your own demons via WAD files
  • βœ… Memory Safe: Go's GC protects you from buffer overflows (but not from Cacodemons) (WIP - 95% complete)
  • βœ… Cross Compilation: Build for any target from any platform
Missing Features
  • One instance per process: Still has a lot of the original global variables, which prevent multiple instances from running
  • Random exported consts: The original C code used the standard convention of all upper case for const/enum values. This results in the Go code assuming these are exported values, when really they're internal state info
  • Nice external API for state inspection: It would be good to be able to change the running state externally, without exposing everything in such a raw way
  • unsafe: There are still some instances of unsafe in the code. It would be good to get rid of these to have better bounds access guarantees

πŸš€ INSTALLATION

Prerequisites
  • Go 1.24+
  • A WAD file
Running the examples

These examples are both very minimal, and whilst technically run the game, they are not really fully complete games in their own right (ie: Missing key bindings etc...). They all assume that a Doom wad is available in the current directory. The shareware Doom wad is available at https://www.doomworld.com/classicdoom/info/shareware.php, or bring your own from a commercial copy.

git clone https://github.com/AndreRenaud/gore
cd gore
Terminal based

This example renders the Doom output using ANSI color codes suitable for a 256-bit color capable terminal. It has very limited input support, as terminals typically do not support key-up events, or control-key support. So fire has been remapped to ,, and it is necessary to repeatedly tap keys to get them to continue, as opposed to press & hold.

go run ./example/termdoom -iwad doom1.wad

Kitty/Sixel graphics

This example renders the Doom output as real graphics in the terminal, using the kitty graphics protocol when available (kitty, Ghostty, WezTerm, iTerm2 etc...), and falling back to sixel (xterm, foot, Windows Terminal, VS Code with terminal.integrated.enableImages etc...). The image is scaled to fill the terminal while keeping its aspect ratio.

If the terminal supports the kitty keyboard protocol then real key press/release events are used, so keys can be held and modifiers work (ctrl to fire, shift to run, alt to strafe). Otherwise keys are released once the terminal stops auto-repeating them, and fire is remapped to ,.

go run ./example/termgfx -iwad doom1.wad
Web based
go run ./example/webserver

Now browse to http://localhost:8080 to play

Ebitengine
go run ./example/ebitengine

The window should pop up to run Doom

Step API (headless, deterministic)
go run ./example/stepper -iwad doom1.wad -o frame.png

Runs a few hundred tics of scripted input with no clock and no window, then writes the last frame to frame.png. See Step API below.

Getting WAD Files

You need the game data files (WAD) to run DOOM:

  • Shareware: Download doom1.wad (free)
  • Retail: Use your legally owned copy of DOOM.WAD or doom2.wad
  • Ultimate DOOM: doom.wad from Ultimate DOOM
  • Final DOOM: tnt.wad or plutonia.wad

πŸ‘£ STEP API

Run is driven by the wall clock and by keyboard events. To embed the engine somewhere that has to be deterministic (lockstep netcode, replays, rollback, tests), drive it one tic at a time instead:

gore.StepInit(nil, []string{"-iwad", "doom1.wad", "-warp", "1", "1"})
for {
    gore.StepTic(gore.TicCmd{Forward: 25, Buttons: gore.ButtonAttack})
    gore.StepRender()           // optional; never affects the simulation
    frame := gore.FrameBuffer() // 320x200 palette indices, see gore.Palette()
    sounds := gore.StepSoundEvents()
    ...
}

Game time comes from the number of tics run, so the same WAD, arguments and ticcmds always produce the same game. Checksum hashes the simulation state to check that, and SaveGameBytes/LoadGameBytes save and restore it in memory.

For multiplayer, start with -solo-net (and optionally -deathmatch) and call StepNetTic with every player's ticcmd, as each node in a lockstep game would. Players can join and leave between tics, and StepSetView picks whose view is rendered without affecting the simulation.

πŸ”§ PLATFORM IMPLEMENTATION

Similar to doomgeneric, the actual input/output is provided externally. The following interface is required:

type DoomFrontend interface {
    DrawFrame(img *image.RGBA)
    SetTitle(title string)
    GetEvent(event *DoomEvent) bool
    CacheSound(name string, data []byte)
    PlaySound(name string, channel, vol, sep int)
    PlayMusic(music io.Reader)
}
Function Purpose
DrawFrame() Render the frame to your display
SetTitle() Set the window title as appropriate to the given WAD
GetEvent() Report key presses/mouse movements
CacheSound() This will supply sound effect 8-bit 11025Hz mono audio samples
PlaySound() Play a given sound effect
PlayMusic() Play a music stream of 16-bit stereo audio at MusicSampleRate (44100Hz), replacing any current music. nil stops the music

Only DrawFrame and GetEvent are vital to implement to get a functioning game. The others can be left blank, and things will still basically function fine.

πŸ“œ LICENSE

DOOM source code is released under the GNU General Public License.
This Go port maintains the same licensing terms.

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

View Source
const (
	MusControllerInstrument = 0
	MusControllerVolume     = 3
	MusSystemAllNotesOff    = 11
)

MUS controller numbers, used by MusEventController & MusEventSystem. These are the only ones that DMX responds to.

View Source
const (
	ButtonAttack      = 1
	ButtonUse         = 2
	ButtonChange      = 4    // change weapon; weapon number in ButtonWeaponMask
	ButtonWeaponMask  = 0x38 // (weapon number) << ButtonWeaponShift
	ButtonWeaponShift = 3
	ButtonSpecial     = 0x80 // pause/savegame; never valid from a remote player
)

Button bits for TicCmd.Buttons. These are the engine's bt_* values from d_event.h, exported for step API hosts.

View Source
const AM_NUMMARKPOINTS = 10
View Source
const ANG1801 = 2147483648
View Source
const ANG18011 = 2147483648
View Source
const ANG18013 = 2147483648
View Source
const ANG18015 = 2147483648
View Source
const ANG1803 = 2147483648
View Source
const ANG1805 = 2147483648
View Source
const ANG1807 = 2147483648
View Source
const ANG1809 = 2147483648
View Source
const ANG2701 = 3221225472
View Source
const ANG2703 = 3221225472
View Source
const ANG2705 = 3221225472
View Source
const ANG451 = 536870912
View Source
const ANG453 = 536870912
View Source
const ANG455 = 536870912
View Source
const ANG457 = 536870912
View Source
const ANG901 = 1073741824
View Source
const ANG903 = 1073741824
View Source
const ANG905 = 1073741824
View Source
const ANG907 = 1073741824
View Source
const ANG909 = 1073741824
View Source
const ANGLETOFINESHIFT = 19
View Source
const ANGLETOSKYSHIFT = 22
View Source
const ANIM_ALWAYS = 0
View Source
const ANIM_LEVEL = 2
View Source
const ANIM_RANDOM = 1
View Source
const BACKUPTICS = 128
View Source
const BASETHRESHOLD = 100
View Source
const BASEYCENTER = 100
View Source
const BLACK = 0
View Source
const BODYQUESIZE = 32
View Source
const BONUSADD = 6
View Source
const BOXBOTTOM = 1
View Source
const BOXLEFT = 2
View Source
const BOXRIGHT = 3
View Source
const BOXTOP = 0
View Source
const BUTTONTIME = 35
View Source
const CF_GODMODE = 2
View Source
const CF_NOCLIP = 1
View Source
const CF_NOMOMENTUM = 4
View Source
const DEFAULT_FLOAT = 3
View Source
const DEFAULT_INT_HEX = 1
View Source
const DEFAULT_KEY = 4
View Source
const DEFAULT_RAM = 16
View Source
const DEFAULT_SPECHIT_MAGIC = 29400216
View Source
const DEFAULT_STRING = 2
View Source
const DEH_DEFAULT_BFG_CELLS_PER_SHOT = 40
View Source
const DEH_DEFAULT_BLUE_ARMOR_CLASS = 2
View Source
const DEH_DEFAULT_GOD_MODE_HEALTH = 100
View Source
const DEH_DEFAULT_GREEN_ARMOR_CLASS = 1
View Source
const DEH_DEFAULT_IDFA_ARMOR = 200
View Source
const DEH_DEFAULT_IDFA_ARMOR_CLASS = 2
View Source
const DEH_DEFAULT_IDKFA_ARMOR = 200
View Source
const DEH_DEFAULT_IDKFA_ARMOR_CLASS = 2
View Source
const DEH_DEFAULT_INITIAL_BULLETS = 50
View Source
const DEH_DEFAULT_INITIAL_HEALTH = 100
View Source
const DEH_DEFAULT_MAX_ARMOR = 200
View Source
const DEH_DEFAULT_MAX_HEALTH = 200
View Source
const DEH_DEFAULT_MAX_SOULSPHERE = 200
View Source
const DEH_DEFAULT_MEGASPHERE_HEALTH = 200
View Source
const DEH_DEFAULT_SOULSPHERE_HEALTH = 100
View Source
const DEH_DEFAULT_SPECIES_INFIGHTING = 0
View Source
const DEMOMARKER = 128
View Source
const DISTMAP = 2
View Source
const DI_EAST = 0
View Source
const DI_NODIR = 8
View Source
const DI_NORTH = 2
View Source
const DI_NORTHEAST = 1
View Source
const DI_NORTHWEST = 3
View Source
const DI_SOUTH = 6
View Source
const DI_SOUTHEAST = 7
View Source
const DI_SOUTHWEST = 5
View Source
const DI_WEST = 4
View Source
const DM_KILLERSX = 10
View Source
const DM_KILLERSY = 100
View Source
const DM_MATRIXX = 42
View Source
const DM_MATRIXY = 68
View Source
const DM_SPACINGX = 40
View Source
const DM_TOTALSX = 269
View Source
const DM_VICTIMSX = 5
View Source
const DM_VICTIMSY = 50
View Source
const DONUT_FLOORHEIGHT_DEFAULT = 0
View Source
const DONUT_FLOORPIC_DEFAULT = 22
View Source
const DOOM_191_VERSION = 111
View Source
const DOS_MEM_DUMP_SIZE = 10
View Source
const EISDIR = 21
View Source
const FASTDARK = 15
View Source
const FF_FRAMEMASK1 = 32767
View Source
const FF_FRAMEMASK3 = 32767
View Source
const FF_FULLBRIGHT1 = 32768
View Source
const FIELDOFVIEW = 2048
View Source
const FINEANGLES = 8192
View Source
const FRACBITS = 16
View Source
const FRACUNIT = 1 << FRACBITS
View Source
const FRICTION = 59392
View Source
const FUZZTABLE = 50
View Source
const F_PANINC = 4
View Source
const F_STAGE_ARTSCREEN = 1
View Source
const F_STAGE_CAST = 2
View Source
const F_STAGE_TEXT = 0
View Source
const GLOWSPEED = 8
View Source
const GRAYSRANGE = 16
View Source
const GREENRANGE = 16
View Source
const HEIGHTBITS = 12
View Source
const HU_BROADCAST = 5
View Source
const HU_MAXLINELENGTH = 80
View Source
const HU_MSGHEIGHT = 1
View Source
const HU_MSGX = 0
View Source
const HU_MSGY = 0
View Source
const HU_TITLEX = 0
View Source
const INFRATICS = 4200
View Source
const INT_MAX1 = 2147483647
View Source
const INT_MAX11 = 2147483647
View Source
const INT_MAX13 = 2147483647
View Source
const INT_MAX15 = 2147483647
View Source
const INT_MAX17 = 2147483647
View Source
const INT_MAX19 = 2147483647
View Source
const INT_MAX5 = 2147483647
View Source
const INT_MAX7 = 2147483647
View Source
const INT_MAX9 = 2147483647
View Source
const INVERSECOLORMAP = 32
View Source
const INVISTICS = 2100
View Source
const INVULNTICS = 1050
View Source
const IRONTICS = 2100
View Source
const ITEMQUESIZE = 128
View Source
const KEY_BACKSPACE1 = 127
View Source
const KEY_BACKSPACE3 = 127
View Source
const KEY_DOWNARROW1 = 175
View Source
const KEY_ENTER = 13
View Source
const KEY_EQUALS1 = 61
View Source
const KEY_ESCAPE = 27
View Source
const KEY_FIRE1 = 163
View Source
const KEY_LEFTARROW1 = 172
View Source
const KEY_MINUS1 = 45
View Source
const KEY_PAUSE1 = 255
View Source
const KEY_RIGHTARROW1 = 174
View Source
const KEY_STRAFE_L1 = 160
View Source
const KEY_STRAFE_R1 = 161
View Source
const KEY_TAB = 9
View Source
const KEY_UPARROW1 = 173
View Source
const KEY_USE1 = 162
View Source
const LIGHTLEVELS = 16
View Source
const LIGHTSCALESHIFT = 12
View Source
const LIGHTSEGSHIFT = 4
View Source
const LIGHTZSHIFT = 20
View Source
const LINEHEIGHT = 16
View Source
const MAPBLOCKUNITS = 128
View Source
const MAXBOB = 1048576
View Source
const MAXBUTTONS = 16
View Source
const MAXCEILINGS = 30
View Source
const MAXDRAWSEGS = 256
View Source
const MAXEVENTS = 64
View Source
const MAXHEALTH = 100
View Source
const MAXINTERCEPTS_ORIGINAL = 128
View Source
const MAXLIGHTSCALE = 48
View Source
const MAXLIGHTZ = 128
View Source
const MAXLINEANIMS = 64
View Source
const MAXPLATS = 30
View Source
const MAXPLAYERS = 4
View Source
const MAXSPECIALCROSS_ORIGINAL = 8
View Source
const MAXSWITCHES = 50
View Source
const MAX_ADJOINING_SECTORS = 20
View Source
const MAX_CAPTURES = 32
View Source
const MAX_JOY_BUTTONS = 20
View Source
const MAX_MOUSE_BUTTONS = 8
View Source
const MINFRAGMENT = 64
View Source
const MIN_RAM = 16
View Source
const MOUSE_SPEED_BOX_HEIGHT = 9
View Source
const MOUSE_SPEED_BOX_WIDTH = 120
View Source
const MTF_AMBUSH = 8
View Source
const MusPercussionChannel = 15

MusPercussionChannel is the MUS channel used for percussion (MIDI channel 10)

View Source
const MusTicksPerSecond = 140

MusTicksPerSecond is the playback rate of Doom MUS files

View Source
const MusicSampleRate = 44100

MusicSampleRate is the sample rate of the stream passed to DoomFrontend.PlayMusic

View Source
const NET_MAXPLAYERS = 8
View Source
const NF_SUBSECTOR1 = 32768
View Source
const NF_SUBSECTOR3 = 32768
View Source
const NF_SUBSECTOR5 = 32768
View Source
const NG_SPACINGX = 64
View Source
const NG_STATSY = 50
View Source
const NORM_SEP = 128
View Source
const NUMAMMO = 4
View Source
const NUMBONUSPALS = 4
View Source
const NUMCARDS = 6
View Source
const NUMCOLORMAPS = 32
View Source
const NUMKEYS = 256
View Source
const NUMMAPS = 9
View Source
const NUMMOBJTYPES = 137
View Source
const NUMMUSIC = 68
View Source
const NUMPOWERS = 6
View Source
const NUMPSPRITES = 2
View Source
const NUMREDPALS = 8
View Source
const NUMSFX = 109
View Source
const NUMWEAPONS = 9
View Source
const NUM_QUITMESSAGES = 8
View Source
const NUM_VIRTUAL_BUTTONS = 10
View Source
const NoState = -1
View Source
const PLATWAIT = 3
View Source
const PT_ADDLINES = 1
View Source
const PT_ADDTHINGS = 2
View Source
const PT_EARLYOUT = 4
View Source
const Pst_DEAD = 1
View Source
const Pst_LIVE = 0
View Source
const Pst_REBORN = 2
View Source
const QUEUESIZE = 128
View Source
const RADIATIONPAL = 13
View Source
const REDRANGE = 16
View Source
const SAVEGAMESIZE = 180224
View Source
const SAVEGAME_EOF = 29
View Source
const SAVESTRINGSIZE = 24
View Source
const SBARHEIGHT = 32
View Source
const SCREENHEIGHT = 200
View Source
const SCREENHEIGHT_4_3 = 240
View Source
const SCREENWIDTH = 320
View Source
const SCREENWIDTH_4_3 = 256
View Source
const SHOWNEXTLOCDELAY = 4
View Source
const SHRT_MAX1 = 32767
View Source
const SIL_BOTH = 3
View Source
const SIL_BOTTOM = 1
View Source
const SIL_TOP = 2
View Source
const SLOPEBITS = 11
View Source
const SLOPERANGE = 2048
View Source
const SLOWDARK = 35
View Source
const SLOWTURNTICS = 6
View Source
const SNDDEVICE_ADLIB = 2
View Source
const SNDDEVICE_GENMIDI = 8
View Source
const SNDDEVICE_GUS = 5
View Source
const SNDDEVICE_SB = 3
View Source
const SP_STATSX = 50
View Source
const SP_STATSY = 50
View Source
const SP_TIMEX = 16
View Source
const STARTBONUSPALS = 9
View Source
const STARTREDPALS = 1
View Source
const STOPSPEED = 4096
View Source
const STROBEBRIGHT = 5
View Source
const ShowNextLoc = 1
View Source
const StatCount = 0
View Source
const TEXTSPEED = 3
View Source
const TEXTWAIT = 250
View Source
const TICRATE = 35
View Source
const TURBOTHRESHOLD = 50
View Source
const VDOORWAIT = 150
View Source
const VERSIONSIZE = 16
View Source
const WI_SPACINGY = 33
View Source
const WI_TITLEY = 2
View Source
const ZONEID = 1919505

Variables ΒΆ

View Source
var DG_ScreenBuffer *image.RGBA
View Source
var EpiDef menu_t
View Source
var EpisodeMenu [4]menuitem_t
View Source
var ErrInvalidGENMIDI = errors.New("invalid GENMIDI lump")
View Source
var (
	ErrInvalidMusFile = errors.New("invalid MUS file")
)
View Source
var I_VideoBuffer []byte
View Source
var LoadDef menu_t
View Source
var LoadMenu [6]menuitem_t
View Source
var M_QuitResponse = func(key int32) {
	if key != key_menu_confirm {
		return
	}
	if netgame == 0 {
		if gamemode == commercial {
			s_StartSound(nil, quitsounds2[gametic>>2&7])
		} else {
			s_StartSound(nil, quitsounds[gametic>>2&7])
		}
	}
	i_Quit()
}
View Source
var MainDef menu_t
View Source
var MainMenu [6]menuitem_t
View Source
var NUMANIMS = [4]int32{
	0: int32(len(epsd0animinfo)),
	1: int32(len(epsd1animinfo)),
	2: int32(len(epsd2animinfo)),
}
View Source
var NUMCMAPS int32

C documentation

// # of commercial levels
View Source
var NewDef menu_t
View Source
var NewGameMenu [5]menuitem_t
View Source
var OptionsDef menu_t
View Source
var OptionsMenu [8]menuitem_t
View Source
var ReadDef1 menu_t
View Source
var ReadDef2 menu_t
View Source
var ReadMenu1 [1]menuitem_t
View Source
var ReadMenu2 [1]menuitem_t
View Source
var S_music [68]musicinfo_t
View Source
var S_sfx [NUMSFX]sfxinfo_t
View Source
var SaveDef menu_t
View Source
var SaveMenu [6]menuitem_t

C documentation

//
// SAVE GAME MENU
//
View Source
var SoundDef menu_t
View Source
var SoundMenu [4]menuitem_t
View Source
var TRACEANGLE angle_t

Functions ΒΆ

func CanSave ΒΆ

func CanSave() bool

CanSave reports whether the game is in a state that SaveGameBytes can capture: in a level, with the player alive. In a netgame dead players are fine (they respawn when they press use), but everyone in the game must have spawned.

func Checksum ΒΆ

func Checksum() uint32

Checksum hashes the simulation state: RNG index, level time and every map object's position, momentum, angle, health and state. Two engines that have consumed the same ticcmds from the same starting point return the same value; if they don't, they have desynced.

Cost is O(n) in the number of live map objects, since it walks the thinker list. Hashing every object is deliberate: a cheaper checksum that skipped some of them would miss desyncs.

func EnableQuitting ΒΆ

func EnableQuitting(enable bool)

func FrameBuffer ΒΆ

func FrameBuffer() []byte

FrameBuffer returns the 320x200 palette-indexed frame buffer as last drawn by StepRender. The slice is owned by the engine.

func I_GetTimeMS ΒΆ

func I_GetTimeMS() int32

func IsMusData ΒΆ

func IsMusData(data []byte) bool

IsMusData reports whether data looks like a MUS file

func LoadGameBytes ΒΆ

func LoadGameBytes(data []byte) error

LoadGameBytes restores a savegame produced by SaveGameBytes. It should be called on a freshly initialised engine. If it returns an error the engine may be left partly restored, and should be re-initialised or loaded again before use.

func Palette ΒΆ

func Palette() []byte

Palette returns the current 256 entry RGB palette (768 bytes). DOOM uses palette swaps for damage/pickup flashes, so this changes over time.

func PlayersInGame ΒΆ

func PlayersInGame() uint8

PlayersInGame returns a bitmask of the players in the game.

func Run ΒΆ

func Run(fg DoomFrontend, args []string)

func SaveGameBytes ΒΆ

func SaveGameBytes() ([]byte, error)

SaveGameBytes serialises the current level into a vanilla-format savegame, followed by a small trailer with state vanilla doesn't save (RNG indices and the tic counter). Unlike g_DoSaveGame it does not print "game saved" or otherwise touch game state.

func SetVirtualFileSystem ΒΆ

func SetVirtualFileSystem(a fs.FS)

SetVirtualFileSystem sets the virtual file system

func StepInit ΒΆ

func StepInit(fe DoomFrontend, args []string)

StepInit initialises the engine for stepping. args are regular DOOM command line arguments, e.g. {"-iwad", "doom1.wad", "-warp", "1", "1", "-skill", "3"}. Only one engine may exist per process (or per WASM instance).

func StepNetTic ΒΆ

func StepNetTic(t *NetTic)

StepNetTic runs exactly one game tic of a multiplayer game.

func StepRender ΒΆ

func StepRender()

StepRender draws the current game state into the frame buffer. It only touches renderer state, never game state, so a host can render as often or as rarely as it likes without affecting determinism.

func StepSetView ΒΆ

func StepSetView(p int32)

StepSetView chooses whose eyes and status bar StepRender draws, and whose ears hear the sounds.

This sets consoleplayer, which in vanilla DOOM only affects the user interface and sound, never the simulation. So nodes looking through different players' eyes stay in sync.

func StepTic ΒΆ

func StepTic(cmd TicCmd)

StepTic runs exactly one game tic, with cmd as the console player's input. In a multiplayer game, any other players stand still; use StepNetTic.

func Stop ΒΆ

func Stop()

Types ΒΆ

type DoomEvent ΒΆ

type DoomEvent struct {
	Type  Evtype_t
	Key   uint8
	Mouse struct {
		Button1 bool
		Button2 bool
		XPos    float64 // from 0-1
		YPos    float64 // from 0-1
	}
}

type DoomFrontend ΒΆ

type DoomFrontend interface {
	DrawFrame(img *image.RGBA)
	SetTitle(title string)
	GetEvent(event *DoomEvent) bool

	CacheSound(name string, data []byte)
	PlaySound(name string, channel, volume, sep int)

	// PlayMusic starts playing a stream of music, replacing any that is
	// already playing. The stream is signed 16-bit little-endian stereo at
	// MusicSampleRate. Pausing, volume and looping are handled within the
	// stream. A nil stream means the music should stop.
	PlayMusic(music io.Reader)
}

type Evtype_t ΒΆ

type Evtype_t int32
const Ev_joystick Evtype_t = 3
const Ev_keydown Evtype_t = 0
const Ev_keyup Evtype_t = 1
const Ev_mouse Evtype_t = 2
const Ev_quit Evtype_t = 4

type MusEvent ΒΆ

type MusEvent struct {
	Tick       uint32 // When does this event occur, in ticks (MusTicksPerSecond) from the start of the song
	Type       MusEventType
	Channel    byte
	Note       byte
	Controller byte
	Value      int // The note volume, pitch bend or controller value, depending on the event type
}

type MusEventType ΒΆ

type MusEventType byte
const (
	MusEventRelease MusEventType = iota
	MusEventPlay
	MusEventPitchBend
	MusEventSystem
	MusEventController
	MusEventEndOfMeasure
	MusEventFinish
	MusEventUnused
)

type MusMusic ΒΆ

type MusMusic struct {
	Events []MusEvent // These are guaranteed to be in order of time
	Ticks  uint32     // Total length of the song, in ticks
}

MusMusic represents the content of a MUS file. See https://doomwiki.org/wiki/MUS & https://moddingwiki.shikadi.net/wiki/MUS_Format

func NewMusMusic ΒΆ

func NewMusMusic(data []byte) (*MusMusic, error)

func (*MusMusic) Duration ΒΆ

func (m *MusMusic) Duration() time.Duration

Duration returns the total length of the song

type MusSynth ΒΆ

type MusSynth struct {
	// contains filtered or unexported fields
}

MusSynth plays a MusMusic through an emulated OPL FM synthesizer, using the instruments from a GENMIDI lump, the same way Doom's DMX library did.

It implements io.ReadSeeker, producing signed 16-bit little-endian stereo PCM. Offsets are measured in bytes of PCM output, so it can be handed straight to an audio player such as oto. It is safe to call its methods from multiple goroutines.

func NewMusSynth ΒΆ

func NewMusSynth(m *MusMusic, genmidi []byte, sampleRate int) (*MusSynth, error)

NewMusSynth creates a synthesizer for the given song, producing samples at sampleRate. genmidi is the contents of the GENMIDI lump from a WAD.

func (*MusSynth) Duration ΒΆ

func (s *MusSynth) Duration() time.Duration

Duration returns the length of the song

func (*MusSynth) OffsetToTime ΒΆ

func (s *MusSynth) OffsetToTime(offset int64) time.Duration

OffsetToTime converts a byte offset of PCM output into a time

func (*MusSynth) Position ΒΆ

func (s *MusSynth) Position() time.Duration

Position returns how far through the song the synthesizer has rendered

func (*MusSynth) Read ΒΆ

func (s *MusSynth) Read(p []byte) (int, error)

Read implements io.Reader, producing signed 16-bit little-endian stereo samples

func (*MusSynth) Seek ΒΆ

func (s *MusSynth) Seek(offset int64, whence int) (int64, error)

Seek implements io.Seeker. The offset is in bytes of PCM output, and the resulting position is clamped to the length of the song.

func (*MusSynth) SetLoop ΒΆ

func (s *MusSynth) SetLoop(loop bool)

SetLoop controls whether the song restarts once it reaches the end

func (*MusSynth) SetPaused ΒΆ

func (s *MusSynth) SetPaused(paused bool)

SetPaused pauses or resumes the song. As with DMX, pausing releases the notes being held, apart from percussion, and they're left to fade out.

func (*MusSynth) SetVolume ΒΆ

func (s *MusSynth) SetVolume(volume int)

SetVolume sets the music volume, from 0 to 127 (the default). As with DMX, this limits the volume of each channel, rather than scaling the output.

func (*MusSynth) TimeToOffset ΒΆ

func (s *MusSynth) TimeToOffset(t time.Duration) int64

TimeToOffset converts a time within the song to a byte offset suitable for Seek

type NetTic ΒΆ

type NetTic struct {
	// Cmds holds the input of each player in the game. Entries for players
	// who aren't in the game are ignored.
	Cmds [MAXPLAYERS]TicCmd
	// Leave and Join are bitmasks of players leaving and joining the game
	// before this tic runs. Leaves are applied first, so a slot can be
	// handed from one player to the next in a single tic.
	Leave, Join uint8
}

NetTic is one tic of a multiplayer game.

type SoundEvent ΒΆ

type SoundEvent struct {
	// Tic is the tic whose simulation produced the event (the value of
	// Stats.Tic once that tic has run).
	Tic int32 `json:"tic"`
	// Kind is "start", "update" (volume/separation of a playing sound
	// changed, e.g. because its source moved) or "stop".
	Kind    string `json:"kind"`
	Channel int32  `json:"ch"`
	// Name is the sound effect, e.g. "pistol"; its samples are in the WAD
	// lump "DS" + upper(Name). Set for "start" only.
	Name string `json:"name,omitempty"`
	// Volume is 0-127. Sep is the stereo separation, 0 (left) to 254
	// (right), with 128 in the centre.
	Volume int32 `json:"vol,omitempty"`
	Sep    int32 `json:"sep,omitempty"`
}

SoundEvent is something the player should hear.

func StepSoundEvents ΒΆ

func StepSoundEvents() []SoundEvent

StepSoundEvents returns the sound events since the last call.

type Stats ΒΆ

type Stats struct {
	Tic          int32  `json:"tic"`
	LevelTime    int32  `json:"levelTime"`
	GameState    string `json:"gameState"`
	Skill        int32  `json:"skill"`
	Episode      int32  `json:"episode"`
	Map          int32  `json:"map"`
	Health       int32  `json:"health"`
	Armor        int32  `json:"armor"`
	Weapon       int32  `json:"weapon"`
	Ammo         int32  `json:"ammo"` // ammo for the ready weapon, -1 if it needs none
	Dead         bool   `json:"dead"`
	Kills        int32  `json:"kills"`
	TotalKills   int32  `json:"totalKills"`
	Items        int32  `json:"items"`
	TotalItems   int32  `json:"totalItems"`
	Secrets      int32  `json:"secrets"`
	TotalSecrets int32  `json:"totalSecrets"`
	Checksum     uint32 `json:"checksum"`
}

Stats is a snapshot of interesting game state. See GetStats.

func GetPlayerStats ΒΆ

func GetPlayerStats(player int32) Stats

GetPlayerStats returns a snapshot of the current game state, from player p's point of view.

func GetStats ΒΆ

func GetStats() Stats

GetStats returns a snapshot of the current game state, from the console player's point of view.

Most fields are simple reads, but Stats.Checksum requires walking every live map object.

type TicCmd ΒΆ

type TicCmd struct {
	Forward int8 `json:"f,omitempty"` // forward (+) / backward (-) movement
	Side    int8 `json:"s,omitempty"` // strafe right (+) / left (-)
	// AngleTurn turns left (+) or right (-); 65536 is a full turn. It is
	// added to the top 16 bits of the 32-bit view angle.
	AngleTurn int16 `json:"t,omitempty"`
	Buttons   uint8 `json:"b,omitempty"` // Button* bits
}

TicCmd is one tic of a player's input, as passed to StepTic. It is the part of the engine's internal ticcmd_t that a player controls; the rest of ticcmd_t is bookkeeping for the network code.

For reference, the keyboard moves at Forward 25 (50 when running), and turns at AngleTurn 640 per tic (1280 when running).

Directories ΒΆ

Path Synopsis
example
doomocracy command
ebitengine command
mus_player command
Package main is a simple MUS music player.
Package main is a simple MUS music player.
sdldoom command
stepper command
stepper drives the engine with the step API: no clock and no keyboard.
stepper drives the engine with the step API: no clock and no keyboard.
termdoom command
termgfx command
webserver command

Jump to

Keyboard shortcuts

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