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() {}