github.com/sorucoder/tic80@v1.3.0/tic80.go (about)

     1  package tic80
     2  
     3  import (
     4  	"reflect"
     5  	"unsafe"
     6  )
     7  
     8  // Memory Areas
     9  var (
    10  	IO_RAM   = (*[0x18000]byte)(unsafe.Pointer(uintptr(0x00000)))
    11  	FREE_RAM = (*[0x28000]byte)(unsafe.Pointer(uintptr(0x18000)))
    12  )
    13  
    14  // toTextData transforms a Go string into a form useable by TIC-80.
    15  func toTextData(goString *string) unsafe.Pointer {
    16  	textData := new([]byte)
    17  	*textData = make([]byte, 0, len(*goString)+1)
    18  	for _, goRune := range *goString {
    19  		if goRune > 0 {
    20  			switch {
    21  			case goRune <= 0x7F:
    22  				*textData = append(*textData, byte(goRune))
    23  			default:
    24  				*textData = append(*textData, byte('?'))
    25  			}
    26  		}
    27  	}
    28  	*textData = append(*textData, 0)
    29  	buffer, _ := toByteData(textData)
    30  	return buffer
    31  }
    32  
    33  // toByteData transforms a Go slice of bytes into a form useable by TIC-80.
    34  func toByteData(goBytes *[]byte) (buffer unsafe.Pointer, count int) {
    35  	if goBytes != nil {
    36  		sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(goBytes))
    37  		buffer = unsafe.Pointer(sliceHeader.Data)
    38  		// See https://tinygo.org/docs/guides/compatibility/#reflectsliceheader-and-reflectstringheader.
    39  		count = int(sliceHeader.Len)
    40  	}
    41  	return
    42  }
    43  
    44  // paletteSet represents a subset of the color palette.
    45  type paletteSet uint16
    46  
    47  func (mask *paletteSet) Clear() {
    48  	*mask = 0
    49  }
    50  
    51  // AddColor adds a color to the set.
    52  func (mask *paletteSet) AddColor(color int) {
    53  	*mask |= paletteSet(1 << (color % 16))
    54  }
    55  
    56  // RemoveColor removes a color from the set.
    57  func (mask *paletteSet) RemoveColor(color int) {
    58  	*mask &^= paletteSet(1 << (color % 16))
    59  }
    60  
    61  // Colors returns a slice containing the colors.
    62  func (mask *paletteSet) Colors() []byte {
    63  	if *mask > 0 {
    64  		set := make([]byte, 0, 16)
    65  		for color := 0; color < 16; color++ {
    66  			if *mask&paletteSet(1<<color) > 0 {
    67  				set = append(set, byte(color))
    68  			}
    69  		}
    70  		return set
    71  	}
    72  	return nil
    73  }
    74  
    75  // ButtonCode represents a button id for use with [tic80.Btn] and [tic80.Btnp]
    76  type ButtonCode int
    77  
    78  // Gamepad Players
    79  const (
    80  	GAMEPAD_1 ButtonCode = 8 * iota
    81  	GAMEPAD_2
    82  	GAMEPAD_3
    83  	GAMEPAD_4
    84  )
    85  
    86  // Gamepad Buttons
    87  const (
    88  	BUTTON_UP ButtonCode = iota
    89  	BUTTON_DOWN
    90  	BUTTON_LEFT
    91  	BUTTON_RIGHT
    92  	BUTTON_A
    93  	BUTTON_B
    94  	BUTTON_X
    95  	BUTTON_Y
    96  )
    97  
    98  // KeyCode represents a keyboard id for use with [tic80.Key] and [tic80.Keyp]
    99  type KeyCode int
   100  
   101  // Keyboard keys.
   102  const (
   103  	KEY_A KeyCode = iota + 1
   104  	KEY_B
   105  	KEY_C
   106  	KEY_D
   107  	KEY_E
   108  	KEY_F
   109  	KEY_G
   110  	KEY_H
   111  	KEY_I
   112  	KEY_J
   113  	KEY_K
   114  	KEY_L
   115  	KEY_M
   116  	KEY_N
   117  	KEY_O
   118  	KEY_P
   119  	KEY_Q
   120  	KEY_R
   121  	KEY_S
   122  	KEY_T
   123  	KEY_U
   124  	KEY_V
   125  	KEY_W
   126  	KEY_X
   127  	KEY_Y
   128  	KEY_Z
   129  	KEY_ZERO
   130  	KEY_ONE
   131  	KEY_TWO
   132  	KEY_THREE
   133  	KEY_FOUR
   134  	KEY_FIVE
   135  	KEY_SIX
   136  	KEY_SEVEN
   137  	KEY_EIGHT
   138  	KEY_NINE
   139  	KEY_MINUS
   140  	KEY_EQUALS
   141  	KEY_LEFTBRACKET
   142  	KEY_RIGHTBRACKET
   143  	KEY_BACKSLASH
   144  	KEY_SEMICOLON
   145  	KEY_APOSTROPHE
   146  	KEY_GRAVE
   147  	KEY_COMMA
   148  	KEY_PERIOD
   149  	KEY_SLASH
   150  	KEY_SPACE
   151  	KEY_TAB
   152  	KEY_RETURN
   153  	KEY_BACKSPACE
   154  	KEY_DELETE
   155  	KEY_INSERT
   156  	KEY_PAGEUP
   157  	KEY_PAGEDOWN
   158  	KEY_HOME
   159  	KEY_END
   160  	KEY_UP
   161  	KEY_DOWN
   162  	KEY_LEFT
   163  	KEY_RIGHT
   164  	KEY_CAPSLOCK
   165  	KEY_CTRL
   166  	KEY_SHIFT
   167  	KEY_ALT
   168  )
   169  
   170  // FontOptions provides additional options to [tic80.Font].
   171  type FontOptions struct {
   172  	transparentColors paletteSet
   173  	characterWidth    int
   174  	characterHeight   int
   175  	fixed             bool
   176  	scale             int
   177  	alternateFont     bool
   178  }
   179  
   180  var defaultFontOptions FontOptions = FontOptions{
   181  	transparentColors: 0,
   182  	characterWidth:    8,
   183  	characterHeight:   8,
   184  	fixed:             false,
   185  	scale:             1,
   186  	alternateFont:     false,
   187  }
   188  
   189  // NewFontOptions constructs a [tic80.FontOptions] object with the defaults.
   190  // See the [API] for more details.
   191  //
   192  // [API]: https://github.com/nesbox/TIC-80/wiki/font
   193  func NewFontOptions() *FontOptions {
   194  	options := new(FontOptions)
   195  	*options = defaultFontOptions
   196  	return options
   197  }
   198  
   199  // AddTransparentColor adds an additional color to the list of colors to render as transparent.
   200  func (options *FontOptions) AddTransparentColor(color int) *FontOptions {
   201  	options.transparentColors.AddColor(color)
   202  	return options
   203  }
   204  
   205  // RemoveTransparentColor removes a color to the list of colors to render as transparent.
   206  func (options *FontOptions) RemoveTransparentColor(color int) *FontOptions {
   207  	options.transparentColors.RemoveColor(color)
   208  	return options
   209  }
   210  
   211  // SetOpaque removes all colors to render transparent.
   212  func (options *FontOptions) SetOpaque() *FontOptions {
   213  	options.transparentColors.Clear()
   214  	return options
   215  }
   216  
   217  // SetCharacterSize sets the maximum size of each character in pixels.
   218  func (options *FontOptions) SetCharacterSize(width, height int) *FontOptions {
   219  	options.characterWidth = width
   220  	options.characterHeight = height
   221  	return options
   222  }
   223  
   224  // SetScale sets the scale as a whole-number multiplier.
   225  func (options *FontOptions) SetScale(scale int) *FontOptions {
   226  	options.scale = scale
   227  	return options
   228  }
   229  
   230  // ToggleFixed toggles monospacing.
   231  func (options *FontOptions) ToggleFixed() *FontOptions {
   232  	options.fixed = !options.fixed
   233  	return options
   234  }
   235  
   236  // TogglePage toggles which font page to use (usually between large and small font).
   237  func (options *FontOptions) TogglePage() *FontOptions {
   238  	options.alternateFont = !options.alternateFont
   239  	return options
   240  }
   241  
   242  // MapOptions provides additional options to [tic80.Map].
   243  type MapOptions struct {
   244  	x                 int
   245  	y                 int
   246  	width             int
   247  	height            int
   248  	screenX           int
   249  	screenY           int
   250  	transparentColors paletteSet
   251  	scale             int
   252  }
   253  
   254  var defaultMapOptions MapOptions = MapOptions{
   255  	x:                 0,
   256  	y:                 0,
   257  	width:             30,
   258  	height:            17,
   259  	screenX:           0,
   260  	screenY:           0,
   261  	transparentColors: 0,
   262  	scale:             1,
   263  }
   264  
   265  // NewMapOptions constructs a [tic80.MapOptions] object with the defaults.
   266  // See the [API] for more details.
   267  //
   268  // [API]: https://github.com/nesbox/TIC-80/wiki/map
   269  func NewMapOptions() *MapOptions {
   270  	options := new(MapOptions)
   271  	*options = defaultMapOptions
   272  	return options
   273  }
   274  
   275  // AddTransparentColor adds an additional color to the list of colors to render as transparent.
   276  func (options *MapOptions) AddTransparentColor(color int) *MapOptions {
   277  	options.transparentColors.AddColor(color)
   278  	return options
   279  }
   280  
   281  // RemoveTransparentColor removes a color to the list of colors to render as transparent.
   282  func (options *MapOptions) RemoveTransparentColor(color int) *MapOptions {
   283  	options.transparentColors.RemoveColor(color)
   284  	return options
   285  }
   286  
   287  // SetOpaque removes all colors to render transparent.
   288  func (options *MapOptions) SetOpaque() *MapOptions {
   289  	options.transparentColors.Clear()
   290  	return options
   291  }
   292  
   293  // SetOffset sets the map coordinates in which to start drawing the map.
   294  func (options *MapOptions) SetOffset(x, y int) *MapOptions {
   295  	options.x = x
   296  	options.y = y
   297  	return options
   298  }
   299  
   300  // SetSize sets the size of the map to draw.
   301  func (options *MapOptions) SetSize(width, height int) *MapOptions {
   302  	options.width = width
   303  	options.height = height
   304  	return options
   305  }
   306  
   307  // SetPosition sets the screen coordinates to draw the map to.
   308  func (options *MapOptions) SetPosition(x, y int) *MapOptions {
   309  	options.screenX = x
   310  	options.screenY = y
   311  	return options
   312  }
   313  
   314  // SetScale sets the scale as a whole-number multiplier.
   315  func (options *MapOptions) SetScale(scale int) *MapOptions {
   316  	options.scale = scale
   317  	return options
   318  }
   319  
   320  // MusicOptions provides additional options to [tic80.Music]
   321  type MusicOptions struct {
   322  	track   int
   323  	frame   int
   324  	row     int
   325  	loop    bool
   326  	sustain bool
   327  	tempo   int
   328  	speed   int
   329  }
   330  
   331  var defaultMusicOptions MusicOptions = MusicOptions{
   332  	track:   -1,
   333  	frame:   -1,
   334  	row:     -1,
   335  	loop:    true,
   336  	sustain: false,
   337  	tempo:   -1,
   338  	speed:   -1,
   339  }
   340  
   341  // NewMusicOptions constructs a [tic80.MusicOptions] object with the defaults.
   342  // See the [API] for more details.
   343  //
   344  // [API]: https://github.com/nesbox/TIC-80/wiki/music
   345  func NewMusicOptions() *MusicOptions {
   346  	options := new(MusicOptions)
   347  	*options = defaultMusicOptions
   348  	return options
   349  }
   350  
   351  // SetTrack sets the track index to start playing.
   352  func (options *MusicOptions) SetTrack(track int) *MusicOptions {
   353  	options.track = track % 8
   354  	return options
   355  }
   356  
   357  // SetFrame sets the frame index to start playing.
   358  func (options *MusicOptions) SetFrame(frame int) *MusicOptions {
   359  	options.frame = frame % 16
   360  	return options
   361  }
   362  
   363  // SetRow sets the row index to start playing.
   364  func (options *MusicOptions) SetRow(row int) *MusicOptions {
   365  	options.row = row % 64
   366  	return options
   367  }
   368  
   369  // SetTempo sets the tempo in beats per minute.
   370  func (options *MusicOptions) SetTempo(tempo int) *MusicOptions {
   371  	options.tempo = tempo%241 + 40
   372  	return options
   373  }
   374  
   375  // SetSpeed sets the speed.
   376  func (options *MusicOptions) SetSpeed(speed int) *MusicOptions {
   377  	options.speed = speed%31 + 1
   378  	return options
   379  }
   380  
   381  // ToggleLooping toggles whether to loop the track.
   382  func (options *MusicOptions) ToggleLooping() *MusicOptions {
   383  	options.loop = !options.loop
   384  	return options
   385  }
   386  
   387  // ToggleSustain toggles whether to sustain notes or not.
   388  func (options *MusicOptions) ToggleSustain() *MusicOptions {
   389  	options.sustain = !options.sustain
   390  	return options
   391  }
   392  
   393  // PrintOptions provides additional options to [tic80.Print]
   394  type PrintOptions struct {
   395  	color         byte
   396  	fixed         bool
   397  	scale         int
   398  	alternateFont bool
   399  }
   400  
   401  var defaultPrintOptions PrintOptions = PrintOptions{
   402  	color:         15,
   403  	fixed:         false,
   404  	scale:         1,
   405  	alternateFont: false,
   406  }
   407  
   408  // NewPrintOptions constructs a [tic80.PrintOptions] object with the defaults.
   409  // See the [API] for more details.
   410  //
   411  // [API]: https://github.com/nesbox/TIC-80/wiki/print
   412  func NewPrintOptions() *PrintOptions {
   413  	options := new(PrintOptions)
   414  	*options = defaultPrintOptions
   415  	return options
   416  }
   417  
   418  // SetColor sets the color of the text to print.
   419  func (options *PrintOptions) SetColor(color int) *PrintOptions {
   420  	options.color = byte(color % 16)
   421  	return options
   422  }
   423  
   424  // SetScale sets the scale as a whole-number multiplier.
   425  func (options *PrintOptions) SetScale(scale int) *PrintOptions {
   426  	options.scale = scale
   427  	return options
   428  }
   429  
   430  // ToggleFixed toggles monospacing.
   431  func (options *PrintOptions) ToggleFixed() *PrintOptions {
   432  	options.fixed = !options.fixed
   433  	return options
   434  }
   435  
   436  // TogglePage toggles which font page to use (usually between large and small font).
   437  func (options *PrintOptions) TogglePage() *PrintOptions {
   438  	options.alternateFont = !options.alternateFont
   439  	return options
   440  }
   441  
   442  // SoundEffectNote is an enumeration of music notes.
   443  type SoundEffectNote int
   444  
   445  const NOTE_NONE SoundEffectNote = -1
   446  
   447  // Notes
   448  const (
   449  	NOTE_C SoundEffectNote = iota
   450  	NOTE_C_SHARP
   451  	NOTE_D
   452  	NOTE_D_SHARP
   453  	NOTE_E
   454  	NOTE_F
   455  	NOTE_F_SHARP
   456  	NOTE_G
   457  	NOTE_G_SHARP
   458  	NOTE_A
   459  	NOTE_A_SHARP
   460  	NOTE_B
   461  )
   462  
   463  // SoundEffectOptions provides additional options for [tic80.Sfx]
   464  type SoundEffectOptions struct {
   465  	id          int
   466  	note        int
   467  	octave      int
   468  	duration    int
   469  	channel     int
   470  	leftVolume  int
   471  	rightVolume int
   472  	speed       int
   473  }
   474  
   475  var defaultSoundEffectOptions SoundEffectOptions = SoundEffectOptions{
   476  	id:          -1,
   477  	note:        -1,
   478  	octave:      -1,
   479  	duration:    -1,
   480  	channel:     0,
   481  	leftVolume:  15,
   482  	rightVolume: 15,
   483  	speed:       0,
   484  }
   485  
   486  // NewSoundEffectOptions constructs a [tic80.SoundEffectOptions] object with the defaults.
   487  // See the [API] for more details.
   488  //
   489  // [API]: https://github.com/nesbox/TIC-80/wiki/sfx
   490  func NewSoundEffectOptions() *SoundEffectOptions {
   491  	options := new(SoundEffectOptions)
   492  	*options = defaultSoundEffectOptions
   493  	return options
   494  }
   495  
   496  // SetId sets the id of the sound effect to play.
   497  func (options *SoundEffectOptions) SetId(id int) *SoundEffectOptions {
   498  	options.id = id % 64
   499  	return options
   500  }
   501  
   502  // SetNote sets the note and octave to play the sound effect.
   503  func (options *SoundEffectOptions) SetNote(note SoundEffectNote, octave int) *SoundEffectOptions {
   504  	options.note = int(note) % 12
   505  	options.octave = octave % 9
   506  	return options
   507  }
   508  
   509  // SetDuration sets the duration in frames to play the sound effect.
   510  func (options *SoundEffectOptions) SetDuration(duration int) *SoundEffectOptions {
   511  	options.duration = duration
   512  	return options
   513  }
   514  
   515  // SetChannel sets the channel index to play the sound effect in.
   516  func (options *SoundEffectOptions) SetChannel(channel int) *SoundEffectOptions {
   517  	options.channel = channel % 4
   518  	return options
   519  }
   520  
   521  // SetSpeed sets the speed of the sound effect.
   522  func (options *SoundEffectOptions) SetSpeed(speed int) *SoundEffectOptions {
   523  	if speed < -4 {
   524  		options.speed = -4
   525  	} else if speed > 3 {
   526  		options.speed = 3
   527  	} else {
   528  		options.speed = speed
   529  	}
   530  	return options
   531  }
   532  
   533  // SetVolume sets the volume of both left and right speakers to the same level.
   534  func (options *SoundEffectOptions) SetVolume(level int) *SoundEffectOptions {
   535  	level %= 16
   536  	options.leftVolume = level
   537  	options.rightVolume = level
   538  	return options
   539  }
   540  
   541  // SetStereoVolume sets the volume of left and right speakers independently.
   542  func (options *SoundEffectOptions) SetStereoVolume(leftLevel, rightLevel int) *SoundEffectOptions {
   543  	options.leftVolume = leftLevel % 16
   544  	options.rightVolume = rightLevel % 16
   545  	return options
   546  }
   547  
   548  // SpriteOptions provides additional options to [tic80.Spr]
   549  type SpriteOptions struct {
   550  	transparentColors paletteSet
   551  	scale             int
   552  	flip              int
   553  	rotate            int
   554  	width             int
   555  	height            int
   556  }
   557  
   558  var defaultSpriteOptions SpriteOptions = SpriteOptions{
   559  	transparentColors: 0,
   560  	scale:             1,
   561  	flip:              0,
   562  	rotate:            0,
   563  	width:             1,
   564  	height:            1,
   565  }
   566  
   567  // NewSpriteOptions constructs a [tic80.SpriteOptions] object with the defaults.
   568  // See the [API] for more details.
   569  //
   570  // [API]: https://github.com/nesbox/TIC-80/wiki/spr
   571  func NewSpriteOptions() *SpriteOptions {
   572  	options := new(SpriteOptions)
   573  	*options = defaultSpriteOptions
   574  	return options
   575  }
   576  
   577  // AddTransparentColor adds an additional color to the list of colors to render as transparent.
   578  func (options *SpriteOptions) AddTransparentColor(color int) *SpriteOptions {
   579  	options.transparentColors.AddColor(color)
   580  	return options
   581  }
   582  
   583  // RemoveTransparentColor removes a color to the list of colors to render as transparent.
   584  func (options *SpriteOptions) RemoveTransparentColor(color int) *SpriteOptions {
   585  	options.transparentColors.RemoveColor(color)
   586  	return options
   587  }
   588  
   589  // SetOpaque removes all colors to render transparent.
   590  func (options *SpriteOptions) SetOpaque() *SpriteOptions {
   591  	options.transparentColors.Clear()
   592  	return options
   593  }
   594  
   595  // SetScale sets the scale as a whole-number multiplier.
   596  func (options *SpriteOptions) SetScale(scale int) *SpriteOptions {
   597  	options.scale = scale
   598  	return options
   599  }
   600  
   601  // FlipHorizontally toggles horizontally flipping.
   602  func (options *SpriteOptions) FlipHorizontally() *SpriteOptions {
   603  	options.flip ^= 1
   604  	return options
   605  }
   606  
   607  // FlipVertically toggles vertical flipping.
   608  func (options *SpriteOptions) FlipVertically() *SpriteOptions {
   609  	options.flip ^= 2
   610  	return options
   611  }
   612  
   613  // Rotate90CW rotates the sprite 90 degrees clockwise.
   614  func (options *SpriteOptions) Rotate90CW() *SpriteOptions {
   615  	options.rotate = (options.rotate + 1) % 4
   616  	return options
   617  }
   618  
   619  // Rotate90CCW rotates the sprite 90 degrees counterclockwise.
   620  func (options *SpriteOptions) Rotate90CCW() *SpriteOptions {
   621  	options.rotate = (options.rotate - 1) % 4
   622  	return options
   623  }
   624  
   625  // Rotate180 rotates the sprite 180 degrees.
   626  func (options *SpriteOptions) Rotate180() *SpriteOptions {
   627  	options.rotate = (options.rotate + 2) % 4
   628  	return options
   629  }
   630  
   631  // SetSize sets the size of the sprite in 8x8 sub-sprites.
   632  func (options *SpriteOptions) SetSize(width, height int) *SpriteOptions {
   633  	options.width = width
   634  	options.height = height
   635  	return options
   636  }
   637  
   638  // SyncMask is an enumeration of data banks.
   639  type SyncMask int
   640  
   641  const SYNC_ALL SyncMask = 0
   642  
   643  // Banks
   644  const (
   645  	SYNC_TILES SyncMask = 1 << iota
   646  	SYNC_SPRITES
   647  	SYNC_MAP
   648  	SYNC_SOUND_EFFECTS
   649  	SYNC_MUSIC
   650  	SYNC_PALETTE
   651  	SYNC_FLAGS
   652  	SYNC_SCREEN
   653  )
   654  
   655  // TexturedTriangleOptions provides additional options for [tic80.Ttri]
   656  type TexturedTriangleOptions struct {
   657  	useTiles             bool
   658  	transparentColors    paletteSet
   659  	useDepthCalculations bool
   660  	z0                   int
   661  	z1                   int
   662  	z2                   int
   663  }
   664  
   665  var defaultTexturedTriangleOptions TexturedTriangleOptions = TexturedTriangleOptions{
   666  	useTiles:             false,
   667  	transparentColors:    0,
   668  	useDepthCalculations: false,
   669  	z0:                   0,
   670  	z1:                   0,
   671  	z2:                   0,
   672  }
   673  
   674  // NewTexturedTriangleOptions constructs a [tic80.TexturedTriangleOptions] object with the defaults.
   675  // See the [API] for more details.
   676  //
   677  // [API]: https://github.com/nesbox/TIC-80/wiki/ttri
   678  func NewTexturedTriangleOptions() *TexturedTriangleOptions {
   679  	options := new(TexturedTriangleOptions)
   680  	*options = defaultTexturedTriangleOptions
   681  	return options
   682  }
   683  
   684  // AddTransparentColor adds an additional color to the list of colors to render as transparent.
   685  func (options *TexturedTriangleOptions) AddTransparentColor(color int) *TexturedTriangleOptions {
   686  	options.transparentColors.AddColor(color)
   687  	return options
   688  }
   689  
   690  // RemoveTransparentColor removes a color to the list of colors to render as transparent.
   691  func (options *TexturedTriangleOptions) RemoveTransparentColor(color int) *TexturedTriangleOptions {
   692  	options.transparentColors.RemoveColor(color)
   693  	return options
   694  }
   695  
   696  // SetOpaque removes all colors to render transparent.
   697  func (options *TexturedTriangleOptions) SetOpaque() *TexturedTriangleOptions {
   698  	options.transparentColors.Clear()
   699  	return options
   700  }
   701  
   702  // SetTextureDepth enables z-depth consideration and sets the z-depth for each vertex of the triangle.
   703  func (options *TexturedTriangleOptions) SetTextureDepth(z0, z1, z2 int) *TexturedTriangleOptions {
   704  	options.useDepthCalculations = true
   705  	options.z0 = z0
   706  	options.z1 = z1
   707  	options.z2 = z2
   708  	return options
   709  }
   710  
   711  // ToggleTextureSource toggles whether to use tiles or sprites for the texture source.
   712  func (options *TexturedTriangleOptions) ToggleTextureSource() *TexturedTriangleOptions {
   713  	options.useTiles = !options.useTiles
   714  	return options
   715  }
   716  
   717  // TraceOptions provides additional options for [tic80.Trace]
   718  type TraceOptions struct {
   719  	color byte
   720  }
   721  
   722  var defaultTraceOptions = TraceOptions{
   723  	color: 15,
   724  }
   725  
   726  // NewTraceOptions constructs a [tic80.TraceOptions] object with the defaults.
   727  // See the [API] for more details.
   728  //
   729  // [API]: https://github.com/nesbox/TIC-80/wiki/trace
   730  func NewTraceOptions() *TraceOptions {
   731  	options := new(TraceOptions)
   732  	*options = defaultTraceOptions
   733  	return options
   734  }
   735  
   736  // SetColor sets the color of the trace output.
   737  func (options *TraceOptions) SetColor(color int) *TraceOptions {
   738  	options.color = byte(color % 16)
   739  	return options
   740  }
   741  
   742  //go:export btn
   743  func rawBtn(id int32) int32
   744  
   745  // Btn returns true if the controller button specified by the given id is pressed; false otherwise.
   746  // See the [API] for more details.
   747  //
   748  // [API]: https://github.com/nesbox/TIC-80/wiki/btn
   749  func Btn(id ButtonCode) bool {
   750  	return rawBtn(int32(id%32)) > 0
   751  }
   752  
   753  //go:export btnp
   754  func rawBtnp(id, hold, period int32) bool
   755  
   756  // Btnp returns true if the controller button specified by the given id was pressed the last frame, or after hold every period frames; false otherwise.
   757  // See the [API] for more details.
   758  //
   759  // [API]: https://github.com/nesbox/TIC-80/wiki/btnp
   760  func Btnp(id ButtonCode, hold, period int) bool {
   761  	return rawBtnp(int32(id%32), int32(hold), int32(period))
   762  }
   763  
   764  //go:export clip
   765  func rawClip(x, y, width, height int32)
   766  
   767  // Clip sets the clipping region for the screen.
   768  // See the [API] for more details.
   769  //
   770  // [API]: https://github.com/nesbox/TIC-80/wiki/clip
   771  func Clip(x, y, width, height int) {
   772  	rawClip(int32(x), int32(y), int32(width), int32(height))
   773  }
   774  
   775  //go:export cls
   776  func rawCls(color int8)
   777  
   778  // Cls fills the screen with the specified color to the screen.
   779  // See the [API] for more details.
   780  //
   781  // [API]: https://github.com/nesbox/TIC-80/wiki/cls
   782  func Cls(color int) {
   783  	rawCls(int8(color))
   784  }
   785  
   786  //go:export circ
   787  func rawCirc(x, y, radius int32, color int8)
   788  
   789  // Circ draws a filled circle with the specified color to the screen.
   790  // See the [API] for more details.
   791  //
   792  // [API]: https://github.com/nesbox/TIC-80/wiki/circ
   793  func Circ(x, y, radius, color int) {
   794  	rawCirc(int32(x), int32(y), int32(radius), int8(color%16))
   795  }
   796  
   797  //go:export circb
   798  func rawCircb(x, y, radius int32, color int8)
   799  
   800  // Circb draws a circle border with the specified color to the screen.
   801  // See the [API] for more details.
   802  //
   803  // [API]: https://github.com/nesbox/TIC-80/wiki/circb
   804  func Circb(x, y, radius, color int) {
   805  	rawCircb(int32(x), int32(y), int32(radius), int8(color%16))
   806  }
   807  
   808  //go:export elli
   809  func rawElli(x, y, radiusX, radiusY int32, color int8)
   810  
   811  // Elli draws a filled ellipse with the specified color to the screen.
   812  func Elli(x, y, radiusX, radiusY, color int) {
   813  	rawElli(int32(x), int32(y), int32(radiusX), int32(radiusY), int8(color%16))
   814  }
   815  
   816  //go:export ellib
   817  func rawEllib(x, y, radiusX, radiusY int32, color int8)
   818  
   819  // Ellib draws an ellipse border with the specified color to the screen.
   820  func Ellib(x, y, radiusX, radiusY, color int) {
   821  	rawEllib(int32(x), int32(y), int32(radiusX), int32(radiusY), int8(color%16))
   822  }
   823  
   824  //go:export exit
   825  func rawExit()
   826  
   827  // Exit closes TIC-80.
   828  // See the [API] for more details.
   829  //
   830  // [API]: https://github.com/nesbox/TIC-80/wiki/exit
   831  func Exit() {
   832  	rawExit()
   833  }
   834  
   835  //go:export fget
   836  func rawFget(sprite int32, flag int8) bool
   837  
   838  // Fget gets the status of the specified flag of the specified sprite.
   839  // See the [API] for more details.
   840  //
   841  // [API]: https://github.com/nesbox/TIC-80/wiki/fget
   842  func Fget(sprite, flag int) bool {
   843  	return rawFget(int32(sprite%512), int8(flag%8))
   844  }
   845  
   846  //go:export fset
   847  func rawFset(sprite int32, flag int8, value bool)
   848  
   849  // Fset sets the status of the specified flag of the specified sprite.
   850  // See the [API] for more details.
   851  //
   852  // [API]: https://github.com/nesbox/TIC-80/wiki/fset
   853  func Fset(sprite, flag int, value bool) {
   854  	rawFset(int32(sprite%512), int8(flag%8), value)
   855  }
   856  
   857  //go:export font
   858  func rawFont(textBuffer unsafe.Pointer, x, y int32, transparentColorBuffer unsafe.Pointer, transparentColorCount int8, characterWidth, characterHeight int8, fixed bool, scale int8, useAlternateFontPage bool) int32
   859  
   860  // Font draws text to the screen using sprite data.
   861  // See the [API] for more details.
   862  //
   863  // [API]: https://github.com/nesbox/TIC-80/wiki/font
   864  func Font(text string, x, y int, options *FontOptions) (textWidth int) {
   865  	if options == nil {
   866  		options = &defaultFontOptions
   867  	}
   868  
   869  	transparentColors := options.transparentColors.Colors()
   870  	transparentColorBuffer, transparentColorCount := toByteData(&transparentColors)
   871  	textBuffer := toTextData(&text)
   872  
   873  	return int(rawFont(textBuffer, int32(x), int32(y), transparentColorBuffer, int8(transparentColorCount), int8(options.characterWidth), int8(options.characterHeight), options.fixed, int8(options.scale), options.alternateFont))
   874  }
   875  
   876  //go:export key
   877  func rawKey(id int32) int32
   878  
   879  // Key returns true if keyboard key specified by the id was pressed; false otherwise.
   880  // See the [API] for more details.
   881  //
   882  // [API]: https://github.com/nesbox/TIC-80/wiki/key
   883  func Key(id KeyCode) bool {
   884  	return rawKey(int32(id)) > 0
   885  }
   886  
   887  //go:export keyp
   888  func rawKeyp(id int8, hold, period int32) int32
   889  
   890  // Keyp returns true if the keyboard key specified by the given id was pressed the last frame, or after hold every period frames; false otherwise.
   891  // See the [API] for more details.
   892  //
   893  // [API]: https://github.com/nesbox/TIC-80/wiki/btnp
   894  func Keyp(id KeyCode, hold, period int) bool {
   895  	return rawKeyp(int8(id), int32(hold), int32(period)) > 0
   896  }
   897  
   898  //go:export line
   899  func rawLine(x0, y0, x1, y1 float32, color int8)
   900  
   901  // Line draws a line with the specified color to the screen.
   902  // See the [API] for more details.
   903  //
   904  // [API]: https://github.com/nesbox/TIC-80/wiki/line
   905  func Line(x0, y0, x1, y1, color int) {
   906  	rawLine(float32(x0), float32(y0), float32(x1), float32(y1), int8(color))
   907  }
   908  
   909  //go:export map
   910  func rawMap(x, y, width, height, screenX, screenY int32, transparentColorBuffer unsafe.Pointer, transparentColorCount int8, unused int32)
   911  
   912  // Map draws a tile map to the screen.
   913  // See the [API] for more details.
   914  //
   915  // [API]: https://github.com/nesbox/TIC-80/wiki/map
   916  func Map(options *MapOptions) {
   917  	if options == nil {
   918  		options = &defaultMapOptions
   919  	}
   920  
   921  	transparentColors := options.transparentColors.Colors()
   922  	transparentColorBuffer, transparentColorCount := toByteData(&transparentColors)
   923  
   924  	rawMap(int32(options.x), int32(options.y), int32(options.width), int32(options.height), int32(options.screenX), int32(options.screenY), transparentColorBuffer, int8(transparentColorCount), 0)
   925  }
   926  
   927  //go:export memcpy
   928  func rawMemcpy(destination, source, length int32)
   929  
   930  // Memcpy copies a buffer of RAM to RAM.
   931  // See the [API] for more details.
   932  //
   933  // [API]: https://github.com/nesbox/TIC-80/wiki/memcpy
   934  func Memcpy(destination, source, length int) {
   935  	rawMemcpy(int32(destination), int32(source), int32(length))
   936  }
   937  
   938  //go:export memset
   939  func rawMemset(address, value, length int32)
   940  
   941  // Memset sets a buffer of RAM to one value.
   942  // See the [API] for more details.
   943  //
   944  // [API]: https://github.com/nesbox/TIC-80/wiki/memset
   945  func Memset(address, value, length int) {
   946  	rawMemset(int32(address), int32(value), int32(length))
   947  }
   948  
   949  //go:export mget
   950  func rawMget(x, y int32) int32
   951  
   952  // Mget gets the id of a tile given by the specified coordinates on the map.
   953  // See the [API] for more details.
   954  //
   955  // [API]: https://github.com/nesbox/TIC-80/wiki/mget
   956  func Mget(x, y int) int {
   957  	return int(rawMget(int32(x), int32(y)))
   958  }
   959  
   960  //go:export mset
   961  func rawMset(x, y, value int32)
   962  
   963  // Mset sets the specified id of a tile given by the specified coordinates on the map.
   964  // See the [API] for more details.
   965  //
   966  // [API]: https://github.com/nesbox/TIC-80/wiki/mset
   967  func Mset(x, y, value int) {
   968  	rawMset(int32(x), int32(y), int32(value))
   969  }
   970  
   971  type mouseData struct {
   972  	x       int16
   973  	y       int16
   974  	scrollX int8
   975  	scrollY int8
   976  	left    bool
   977  	middle  bool
   978  	right   bool
   979  }
   980  
   981  var mouse *mouseData = new(mouseData)
   982  
   983  //go:export mouse
   984  func rawMouse(data *mouseData)
   985  
   986  // Mouse returns the current state of the mouse.
   987  // See the [API] for more details.
   988  //
   989  // [API]: https://github.com/nesbox/TIC-80/wiki/mouse
   990  func Mouse() (x, y int, left, middle, right bool, scrollX, scrollY int) {
   991  	rawMouse(mouse)
   992  
   993  	x = int(mouse.x)
   994  	y = int(mouse.y)
   995  	left = mouse.left
   996  	middle = mouse.middle
   997  	right = mouse.right
   998  	scrollX = int(mouse.scrollX)
   999  	scrollY = int(mouse.scrollY)
  1000  	return
  1001  }
  1002  
  1003  //go:export music
  1004  func rawMusic(track, frame, row int32, loop, sustain bool, tempo, speed int32)
  1005  
  1006  // Music plays a music track.
  1007  // See the [API] for more details.
  1008  //
  1009  // [API]: https://github.com/nesbox/TIC-80/wiki/music
  1010  func Music(options *MusicOptions) {
  1011  	if options == nil {
  1012  		options = &defaultMusicOptions
  1013  	}
  1014  
  1015  	rawMusic(int32(options.track), int32(options.frame), int32(options.row), options.loop, options.sustain, int32(options.tempo), int32(options.speed))
  1016  }
  1017  
  1018  //go:export peek
  1019  func rawPeek(address int32, bits int8) int8
  1020  
  1021  // Peek reads a byte from RAM.
  1022  // See the [API] for more details.
  1023  //
  1024  // [API]: https://github.com/nesbox/TIC-80/wiki/peek
  1025  func Peek(address int) byte {
  1026  	return byte(rawPeek(int32(address), 8))
  1027  }
  1028  
  1029  // Peek4 reads a nybble from RAM.
  1030  // See the [API] for more details.
  1031  //
  1032  // [API]: https://github.com/nesbox/TIC-80/wiki/peek
  1033  func Peek4(address int) byte {
  1034  	return byte(rawPeek(int32(address), 4))
  1035  }
  1036  
  1037  // Peek2 reads a half-nybble from RAM.
  1038  // See the [API] for more details.
  1039  //
  1040  // [API]: https://github.com/nesbox/TIC-80/wiki/peek
  1041  func Peek2(address int) byte {
  1042  	return byte(rawPeek(int32(address), 2))
  1043  }
  1044  
  1045  // Peek reads a bit from RAM.
  1046  // See the [API] for more details.
  1047  //
  1048  // [API]: https://github.com/nesbox/TIC-80/wiki/peek
  1049  func Peek1(address int) byte {
  1050  	return byte(rawPeek(int32(address), 1))
  1051  }
  1052  
  1053  //go:export pix
  1054  func rawPix(x, y int32, color int8) uint8
  1055  
  1056  // Pix draws a pixel to the screen, and returns the original color.
  1057  // See the [API] for more details.
  1058  //
  1059  // [API]: https://github.com/nesbox/TIC-80/wiki/pix
  1060  func Pix(x, y, color int) int {
  1061  	return int(rawPix(int32(x), int32(y), int8(color%16)))
  1062  }
  1063  
  1064  //go:export pmem
  1065  func rawPmem(address int32, value int64) uint32
  1066  
  1067  // Pmem reads and writes values to persistent memory.
  1068  // See the [API] for more details.
  1069  //
  1070  // [API]: https://github.com/nesbox/TIC-80/wiki/pmem
  1071  func Pmem(address int, value int64) uint32 {
  1072  	return rawPmem(int32(address), value)
  1073  }
  1074  
  1075  //go:export poke
  1076  func rawPoke(address int32, value, bits int8)
  1077  
  1078  // Poke writes a byte to RAM.
  1079  // See the [API] for more details.
  1080  //
  1081  // [API]: https://github.com/nesbox/TIC-80/wiki/poke
  1082  func Poke(address int, value byte) {
  1083  	rawPoke(int32(address), int8(value), 8)
  1084  }
  1085  
  1086  // Poke4 writes a nybble to RAM.
  1087  // See the [API] for more details.
  1088  //
  1089  // [API]: https://github.com/nesbox/TIC-80/wiki/poke
  1090  func Poke4(address int, value byte) {
  1091  	rawPoke(int32(address), int8(value), 4)
  1092  }
  1093  
  1094  // Poke2 writes a half-nybble to RAM.
  1095  // See the [API] for more details.
  1096  //
  1097  // [API]: https://github.com/nesbox/TIC-80/wiki/poke
  1098  func Poke2(address int, value byte) {
  1099  	rawPoke(int32(address), int8(value), 2)
  1100  }
  1101  
  1102  // Poke1 writes a bit to RAM.
  1103  // See the [API] for more details.
  1104  //
  1105  // [API]: https://github.com/nesbox/TIC-80/wiki/poke
  1106  func Poke1(address int, value byte) {
  1107  	rawPoke(int32(address), int8(value), 1)
  1108  }
  1109  
  1110  //go:export print
  1111  func rawPrint(textBuffer unsafe.Pointer, x, y int32, color, fixed, scale, useAlternateFontPage int8) int32
  1112  
  1113  // Print prints text to the screen using the system fonts.
  1114  // See the [API] for more details.
  1115  //
  1116  // [API]: https://github.com/nesbox/TIC-80/wiki/print
  1117  func Print(text string, x, y int, options *PrintOptions) int {
  1118  	if options == nil {
  1119  		options = &defaultPrintOptions
  1120  	}
  1121  
  1122  	textBuffer := toTextData(&text)
  1123  
  1124  	var optionFixed int8
  1125  	if options.fixed {
  1126  		optionFixed = 1
  1127  	}
  1128  
  1129  	var optionAlternateFont int8
  1130  	if options.alternateFont {
  1131  		optionAlternateFont = 1
  1132  	}
  1133  
  1134  	return int(rawPrint(textBuffer, int32(x), int32(y), int8(options.color), optionFixed, int8(options.scale), optionAlternateFont))
  1135  }
  1136  
  1137  //go:export rect
  1138  func rawRect(x, y, width, height int32, color int8)
  1139  
  1140  // Rect draws a filled rectangle with the specified color to the screen.
  1141  // See the [API] for more details.
  1142  //
  1143  // [API]: https://github.com/nesbox/TIC-80/wiki/rect
  1144  func Rect(x, y, width, height, color int) {
  1145  	rawRect(int32(x), int32(y), int32(width), int32(height), int8(color%16))
  1146  }
  1147  
  1148  //go:export rectb
  1149  func rawRectb(x, y, width, height int32, color int8)
  1150  
  1151  // Rectb draws a rectangle border with the specified color to the screen.
  1152  // See the [API] for more details.
  1153  //
  1154  // [API]: https://github.com/nesbox/TIC-80/wiki/rectb
  1155  func Rectb(x, y, width, height, color int) {
  1156  	rawRectb(int32(x), int32(y), int32(width), int32(height), int8(color%16))
  1157  }
  1158  
  1159  //go:export sfx
  1160  func rawSfx(id, note, octave, duration, channel, volumeLeft, volumeRight, speed int32)
  1161  
  1162  // Sfx plays a sound effect.
  1163  // See the [API] for more details.
  1164  //
  1165  // [API]: https://github.com/nesbox/TIC-80/wiki/sfx
  1166  func Sfx(options *SoundEffectOptions) {
  1167  	if options == nil {
  1168  		options = &defaultSoundEffectOptions
  1169  	}
  1170  
  1171  	rawSfx(int32(options.id), int32(options.note), int32(options.octave), int32(options.duration), int32(options.channel), int32(options.leftVolume), int32(options.rightVolume), int32(options.speed))
  1172  }
  1173  
  1174  //go:export spr
  1175  func rawSpr(id, x, y int32, transparentColorBuffer unsafe.Pointer, transparentColorCount int8, scale, flip, rotate, width, height int32)
  1176  
  1177  // Spr draws a sprite to the screen.
  1178  // See the [API] for more details.
  1179  //
  1180  // [API]: https://github.com/nesbox/TIC-80/wiki/spr
  1181  func Spr(id, x, y int, options *SpriteOptions) {
  1182  	if options == nil {
  1183  		options = &defaultSpriteOptions
  1184  	}
  1185  
  1186  	transparentColors := options.transparentColors.Colors()
  1187  	transparentColorBuffer, transparentColorCount := toByteData(&transparentColors)
  1188  
  1189  	rawSpr(int32(id), int32(x), int32(y), transparentColorBuffer, int8(transparentColorCount), int32(options.scale), int32(options.flip), int32(options.rotate), int32(options.width), int32(options.height))
  1190  }
  1191  
  1192  //go:export sync
  1193  func rawSync(mask int32, bank, toCart int8)
  1194  
  1195  // Sync exchanges and optionally persists the changes of data banks.
  1196  // See the [API] for more details.
  1197  //
  1198  // [API]: https://github.com/nesbox/TIC-80/wiki/sync
  1199  func Sync(mask SyncMask, bank int, toCart bool) {
  1200  	var toCartValue int8
  1201  	if toCart {
  1202  		toCartValue = 1
  1203  	}
  1204  
  1205  	rawSync(int32(mask), int8(bank), toCartValue)
  1206  }
  1207  
  1208  //go:export ttri
  1209  func rawTtri(x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2 float32, useTiles int32, transparentColorBuffer unsafe.Pointer, transparentColorCount int8, z0, z1, z2 float32, depth bool)
  1210  
  1211  // Ttri draws a textured triangle using sprites or tiles as its texture to the screen.
  1212  // See the [API] for more details.
  1213  //
  1214  // [API]: https://github.com/nesbox/TIC-80/wiki/ttri
  1215  func Ttri(x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2 int, options *TexturedTriangleOptions) {
  1216  	if options == nil {
  1217  		options = &defaultTexturedTriangleOptions
  1218  	}
  1219  
  1220  	transparentColors := options.transparentColors.Colors()
  1221  	transparentColorBuffer, transparentColorCount := toByteData(&transparentColors)
  1222  
  1223  	var useTilesValue int32
  1224  	if options.useTiles {
  1225  		useTilesValue = 1
  1226  	}
  1227  
  1228  	rawTtri(float32(x0), float32(y0), float32(x1), float32(y1), float32(x2), float32(y2), float32(u0), float32(v0), float32(u1), float32(v1), float32(u2), float32(v2), useTilesValue, transparentColorBuffer, int8(transparentColorCount), float32(options.z0), float32(options.z1), float32(options.z2), options.useDepthCalculations)
  1229  }
  1230  
  1231  //go:export time
  1232  func rawTime() float32
  1233  
  1234  // Time returns the number of milliseconds since the game started.
  1235  // See the [API] for more details.
  1236  //
  1237  // [API]: https://github.com/nesbox/TIC-80/wiki/time
  1238  func Time() float32 {
  1239  	return rawTime()
  1240  }
  1241  
  1242  //go:export trace
  1243  func rawTrace(messageBuffer unsafe.Pointer, color int8)
  1244  
  1245  // Trace writes text to the console.
  1246  // See the [API] for more details.
  1247  //
  1248  // [API]: https://github.com/nesbox/TIC-80/wiki/trace
  1249  func Trace(message string, options *TraceOptions) {
  1250  	if options == nil {
  1251  		options = &defaultTraceOptions
  1252  	}
  1253  
  1254  	messageBuffer := toTextData(&message)
  1255  
  1256  	rawTrace(messageBuffer, int8(options.color))
  1257  }
  1258  
  1259  //go:export tri
  1260  func rawTri(x0, y0, x1, y1, x2, y2 float32, color int8)
  1261  
  1262  // Tri draws a filled triangle with the specified color to the screen.
  1263  // See the [API] for more details.
  1264  //
  1265  // [API]: https://github.com/nesbox/TIC-80/wiki/tri
  1266  func Tri(x0, y0, x1, y1, x2, y2, color int) {
  1267  	rawTri(float32(x0), float32(y0), float32(x1), float32(y1), float32(x2), float32(y2), int8(color))
  1268  }
  1269  
  1270  //go:export trib
  1271  func rawTrib(x0, y0, x1, y1, x2, y2 float32, color int8)
  1272  
  1273  // Trib draws a triangle border with the specified color to the screen.
  1274  // See the [API] for more details.
  1275  //
  1276  // [API]: https://github.com/nesbox/TIC-80/wiki/trib
  1277  func Trib(x0, y0, x1, y1, x2, y2, color int) {
  1278  	rawTrib(float32(x0), float32(y0), float32(x1), float32(y1), float32(x2), float32(y2), int8(color))
  1279  }
  1280  
  1281  //go:export tstamp
  1282  func rawTstamp() uint32
  1283  
  1284  // Tstamp returns the current Unix timestamp.
  1285  // See the [API] for more details.
  1286  //
  1287  // [API]: https://github.com/nesbox/TIC-80/wiki/tstamp
  1288  func Tstamp() uint32 {
  1289  	return rawTstamp()
  1290  }
  1291  
  1292  // Start is a workaround to allow TIC-80 to run Go code.
  1293  // This should be the first function run in BOOT.
  1294  //
  1295  //go:linkname Start _start
  1296  func Start()
  1297  
  1298  //go:export main.main
  1299  func main() {}