Useful
Inventions
Favorite
Quotes
Game
Design
Atari
Memories
Personal
Pages

7800basic Guide

By Mike “RevEng” Saarna (adapted by Duane Alan Hahn, a.k.a. Random Terrain)

As an Amazon Associate I earn from qualifying purchases.

 

Table of Contents

About This HTML Page

Introduction

7800 Hardware Overview

Controls

Graphics

Sprites and Characters

Palettes

Graphics Modes

Zones

Sound

Formatting and Layout Features

Indenting and White Space

Numeric Representation

Line Numbers and Labels

Combining Multiple Commands

Variables

Regular Variables

Dimensioning Variable Names

Assignment

Other Variable Types

Variable Arrays

Bitwise Variables

Constant Variables

Indirect Variable Arrays

8.8 Fixed Point Variables

Special Variables

Score Variables and BCD Variables

Random Numbers

Temporary Variables

CARRY Variable

pokeydetected Variable

paldetected Variable

Automatically Dimensioned Variables

autodim statement

Conditional Logic

Code Organization and Flow Control

bank

dmahole

noflow

goto

gosub and return

on…goto and on…gosub

loadrombank

loadrambank

reboot

for…next

altgamestart label

User Functions

Data

Regular Data

Sequential Data

Using Character Data

Tiled Character-Map Data Import

speechdata

Program Configuration

set romsize [value]

set bankset on

set doublewide on

set zoneheight [value]

set tallsprite [on|off|spritesheet]

set screenheight

set extradlmemory on

set dlmemory

set plotvalueonscreen

set plotvaluepage [$##]

set zoneprotection

set pauseroutine

set pausesilence

set paddlerange

set paddlescalex2

set paddlepair

set mousexonly

set mousetime

set trakxonly

set traktime

set drivingboost

set pokeysupport

set pokeysfxsupport

set trackersupport [basic|rmt]

set rmtspeed [ntsc|pal]

set tiasfx mono

set tiavolume on

set avoxvoice on

set debug color

set canary

set breakprotect

set crashdump

set mcpdevcart

set basepath

set hssupport

set hsseconds

set hsscoresize

set hscolorbase

set hsdifficultytext off

set hsdifficultytext

set hsgameranks

set deprecated

set dumpgraphics

set snes0pause

set snes1pause

set snes#pause

set 7800GDmenuoff

set multibutton

set multibuttonpause

set 7800header

Bankset ROMs

Working With Banksets

Banksets and Bankswitching

Banksets and In-Cart RAM

Valid Bankset Hardware

Graphics Commands

displaymode

clearscreen

savescreen and restorescreen

drawscreen

drawwait

Working With the Screen Commands

doublebuffer

topscreenroutine, bottomscreenroutine, and userinterrupt subroutines

Setting Palettes

setfade, getfade (Color Fading)

zoneheight

screenheight

adjustvisible

incgraphic

incbanner

newblock

plotsprite

plotbanner

Notes on Use of Characters

characterset

plotchars

plotmap

plotmapfile

plotvalue

peekchar

pokechar

lockzone

unlockzone

shakescreen

memcpy

strcpy

memset

Sprite Collisions with boxcollision

Joystick Controls

joyxany

Driving Controls

Paddle Controls

Mouse Controls

Trakball Controls

Keypad Controls

SNES Controls

Mega7800 Controls

Console Switches

Reset, Select, & Difficulty Switches

pausing

Direct TIA Sound

tsound

TIA Sound Registers

Direct POKEY Sound

psound

POKEY Sound Registers

TIA and POKEY Sound Effect Driver

TIA Music Tracker

Enabling the TIA Music Tracker

Instrument Data

songdata

Labels

Track and Song Modifiers

TIA Key Mapping

Note Data

Drum Note Data

playsong

stopsong

RMT Music Tracker

Enabling the RMT Music Tracker

RMTA and RMT Files

7800rmt2asm

7800rmtfix

incrmtfile

playrmt

stoprmt

startmt

Miscellaneous RMT Notes

AtariVox Voice Support

High Score Support

hiscoreclear

hiscoreload

High Score Callback Functions

Saving Game Memory

Data Compression

Feature Modules

Conditional Compilation and Compiling Message Output

sizeof

Advanced Spritework

plotsprite4

PLOTSPRITE and PLOTSPRITE4

Assembly Language

inline assembly

Including External Assembly

Inlining External Assembly

Including Binary Data

Installing 7800basic

Compiling Your 7800basic Code

On Windows

On OS X or Linux

Files Produced by Compilation

Backing Up Your 7800basic Game

set backupstyle

set backupfile

Troubleshooting Issues With Your 7800basic Code

Page last updated on: 2024y_02m_09d_1426t

This document is meant as an introduction to the 7800basic language command structure and syntax. It's not meant as a general programming primer.

 

 

 

About This HTML Page

This page is based on the 7800basic PDF file created by RevEng. You can download the latest version of 7800basic and the 7800basic Developers Guide (PDF) through a link at AtariAge.

 

 

Table of Contents and Index

There is a table of contents and an index on this page to help you find what you are looking for as quickly as possible.

 

 

Link Colors

Links that jump to other places on this page are blue. Links that lead to other pages online are red.

 

 

 

 

 

Introduction

7800basic is a programming language that can be used to create games for the Atari 7800 game console. It differs from the majority of BASIC languages in that it compiles your source code into fast 6502 machine language code.

 

7800basic is based on the Atari 2600 programming language batari BASIC, so if you're familiar with bB, you'll be right at home with 7800basic.

 

7800basic is designed to put as much control as you want in your hands, so if you're familiar with 6502 assembly code you can easily customize the modular framework, or mix your high level BASIC source code with your own low level assembly code.

 

If you don't want to learn assembly language, don't worry, you don't need to know assembly language to produce games. Everything you need is accessible using pure BASIC, and many impressive games have been produced using no assembly language.

Back to Top

 

 

 

 

 

7800 Hardware Overview

Although 7800basic handles many of the hardware details for you, it will help to have a general understanding of the hardware you'll be developing for.

 

 

 

Controls

The 7800 comes with 2 dual-button joysticks, though the console is often used with Atari single button joysticks as well. The console can also be used with other legacy Atari controls, such as paddle controls, driving controls, and keyboard controls.

 

The 7800 console itself has a number of switches on the console: Power, Pause, Reset, Player 1 Difficulty A/B, and Player 2 Difficulty A/B.

 

The Power button is a hardware switch that can't be detected or otherwise interacted with through software.

 

The Pause button is a momentary switch. If you wish to support in-game pausing, your game code needs to check this switch every frame. If it's pressed and released, your game code should stop the action. If pressed and released again, the game code should resume the action.

 

The Difficulty Switches can either be in A or B position. If you wish to support these switches in your game, you should check these switches during gameplay, and adjust difficulty as selected (A=pro, B=amateur).

 

See Joystick Controls, Driving Controls, Paddle Controls, Mouse Controls, Keypad Controls, SNES Controls, Mega7800 Controls, and Console Switches for more information.

 

 

 

 

Graphics

The graphics chip in the 7800 is called MARIA. MARIA was designed with an architecture similar to many arcade games of its era, and is unlike any other console graphics chip.

 

 

 

 

Sprites and Characters

MARIA takes a series of instructions to draw sprites and characters, and runs though them to create the screen bitmap display. In a sense, MARIA is hardware assistance for soft-sprites.

 

If MARIA runs out of time to create the screen bitmap, sprites and characters it didn't reach aren't displayed. The number of graphical objects you can successfully put on the screen depends on the width and color depth of the graphics you specify.

 

Another consequence of the screen being a bitmap is that MARIA provides no hardware collision detection. Your game code will need to do its own check of overlapping rectangles to see if sprites have collided.

 

See Sprite Collisions with boxcollision for more information.

 

 

 

 

Palettes

MARIA is equipped with 8 adjustable 3-color palettes. A sprite or character can be drawn using any one of these palettes, allowing for fairly colorful screens.

 

See Setting Palettes for more information.

 

 

 

 

Graphics Modes

MARIA is capable of 3 graphic display modes, 160A, 320A, and 320B. Each of these graphic modes is capable of display sprites or characters in its regular format, or an alternate format.

 

Here's a quick summary table with the mode details…

 

Mode

Resolution

Number of Colors
(in addition to
transparent)

Width of
One
Character

Alt. Format

Alt. Number
of Colors
(in addition to
transparent)

Alt. Width
of One
Character

Restrictions

160A

160x192

3 colors

4 pixels

160B

12 colors

2 pixels

None

320A

320x192

1 color

8 pixels

320C

3 colors

4 pixels

In 320C mode, even pixel pairs use the first two colors in the palette, and odd pixel pairs use the last two colors in the palette.

320B

320x192

3 colors

4 pixels

320D

3 colors

8 pixels

320B mode requires pairs of pixels to use the same palette. 320D requires pixels in odd columns to use the first two palette colors, and pixels in even columns to use the last two palette colors.

 

As you can see from the table, the 160A/B mode has no restrictions, and is generally the most popular. 320A and 320B are also particularly useful and allow for higher resolution images.

 

The alternate formats 320C and 320D put odd limits where certain colors can be used, and as a consequence they're used less often than the other modes.

 

 

 

 

Zones

MARIA, splits the screen up into a series of horizontal bands called zones. A 7800 game typically spends a good deal of its time setting up memory structures for MARIA, called display lists. Display lists tell MARIA which characters and sprites it should be displaying in any one zone.

 

7800basic will deal with zones and create and manipulate display lists on your behalf, so there won't be further mention of them in this guide.

 

 

 

 

Sound

The 7800 uses the TIA chip for audio, just as the Atari 2600 does. This chip is capable of unique sounds, though it has coarse frequency control, which makes it difficult to play musical notes that sound in tune.

 

It's possible for the 7800 to play sound through an in-cartridge sound chip. The POKEY sound chip from Atari is the typical choice for this, and was used in some commercial games, such as Ballblazer and Commando.

 

See Direct TIA Sound, Direct POKEY Sound and TIA and POKEY Sound Effect Driver for more information.

Back to Top

 

 

 

 

 

Formatting and Layout Features

 

Indenting and White Space

Each command in 7800basic should be indented, that is, there should be one or more spaces or tabs between the command and the left-margin. If you forget to do this, your BASIC program will compile incorrectly and fail miserably.

 

In fact, the only things that aren't indented in 7800basic are labels (we'll talk about them in a second) and multi-line command “end” markers (we'll get into those with specific command documentation).

 

 

 

 

Numeric Representation

7800basic programs can use numbers in decimal, hexadecimal, and binary formats. Numbers with a $ prefix are assumed to be in hexadecimal format, numbers with a % prefix are assumed to be in binary format, and numbers without a prefix are assumed to be in decimal format.

 

Here's an example of decimal, hexadecimal, and binary numbers:

   13
   $2A
   %00110011

 

 

 

 

Line Numbers and Labels

7800basic doesn't require the old-fashioned BASIC style of numbering each linein fact we don't recommend itbut it does support line numbers if you prefer to use them.

 

Instead of using line numbers, your 7800basic program can use labels for important sections of code. A label is a name you give a section of code, and is easily identified because it has no indentation.

 

If you wish to jump to a certain section of code, you can use goto with the label name. This is much easier to read and understand than using line numbers. Which of these examples do you prefer to read, amongst hundreds of similar commands?

   goto BlowUpEnemy
   goto 12428

We'll touch more on goto and related commands when we discuss program flow control.

 

 

 

 

Combining Multiple Commands

In 7800basic you may use the “:” character to chain several commands together on a single line. This is most useful in if…then commands, when you'd like to do many things conditionally.

   If PlayerY>150 then PlayerDying=1:PlayerDeathSound=1:goto GameOver

Back to Top

 

 

 

 

 

Variables

 

Regular Variables

Regular variables in 7800basic are byte sized, and limited to values from 0-255. If math on a regular variable causes it to exceed 255, it will overflow and become a small number near 0. Similarly, if math on a regular variable causes it to decrease below 0, it will underflow and become a large number near 255.

 

 

 

 

Dimensioning Variable Names

You have 126 pre-named variables in 7800basic, ready and available exclusively to your game code. These have been given the names a-z and var0-var99, but you're not stuck with those names. Defining a new name is as simple as using the dim command.

   dim MyPlayerDied=q

If 126 variables isn't enough memory for your game, there's also a 1.5K block of unnamed RAM locations that's ready for use in your game. This block ranges from memory address $2200 to $27FF, and you can assign any bit of it a name using the dim command.

   dim UfoState=$2200

So every time “UfoState” is used in code, the 7800 will really operate on memory location $2200.

 

In case you missed it, 7800basic programmers have the usual 26 variables (a to z), 100 more variables (var0 to var99), and another 1,535 variables in the form of unnamed RAM locations ($2200 to $27FF).

 

 

 

 

Assignment

Assigning a value to a variable is just a matter of using the form: “myvariable=myvalue” where myvalue can be a number, another variable, or a complex expression.

   UfoState = 0
   Laserx = PlayerX
   frame = (frame+1)&63

Expressions can contain operators for addition, subtraction division, multiplication, and/or bitwise operators.

 

The order of operations for expressions is:

   ( ) brackets
   * / // multiplication, division, and modulus
   + - addition, and subtraction
   & | ^ bitwise AND, bitwise OR, and bitwise XOR

Back to Top

 

 

 

 

 

Other Variable Types

 

Variable Arrays

Regular variables can be accessed as arrays in 7800basic. Doing so will access memory locations next to the variable in question.

 

The following sets variables “a”, “b”, and “c” to 0.

   a[0]=0
   a[1]=0
   a[2]=0

Using array notation will allow you to loop through elements without a lot of duplicated code, providing you've used dim to place the elements side by side in memory.

 

Note: Many advanced statements in 7800basic don't work directly with arrays. To use arrays with those statements, you will need to assign any array lookups to a variable, and use the variable with those statements.

 

 

 

 

Bitwise Variables

7800basic also has the ability to work directly with bits in regular variables. We call this working with bitwise variables, because we can treat each bit as if it were its own variable.

 

To set or unset a bit in a variable, simply access the bit position with the {} braces like this…

   playerflags{0}=1
   enemyflags{3}=0

Bitwise access can also be used as a true or false condition if…then statements as well.

   if playerflags{0} then goto playerdeath

Notice that we didn't test if playerflags{0}=1. Since the bit can already only be 1 or 0true or falsewe don't check its value like we would with a regular variable.

 

We'll cover other aspects of if…then statements a bit later.

 

Note: Many advanced statements in 7800basic don't work directly with bitwise-arrays. To use bitwise-arrays with those statements, you will need to assign any bitwise-array lookups to a variable, and use the variable with those statements.

 

 

 

 

Constant Variables

A constant is a special type of variable that cannot be changed while a program is running. To declare a constant in 7800basic, use the const command. const declares a constant value for use within a program. This improves readability in a program in the case where a value is used several times but will not change, or you want to try different values in a program but don't want to change your code in several places first.

 

For example, you might have the following near the beginning of your program:

   const MyConst = 200
   const Monster_Height = $12

After that, any time MyConst or Monster_Height is used, the compiler will substitute 200 or $12 respectively.

 

 

 

 

Indirect Variable Arrays

Indirect variable arrays are similar to regular variable arrays, but instead of accessing memory from a certain ROM or RAM location, they reference memory pointed to by a two-byte memory variable. (The two bytes of memory must be dim'ed to consecutive a-z memory locations.) This is typically used to access the advance POKEY sound registers, but you may also use indirect variable arrays if you wish to use the same code with different bits of data.

 

An indirect variable array is signified by using double square braces around the array index. To initialize the pointer to point to some data, you must use const to reference the data values…

   dim mempointer=a
   dim mempointerhi=b
   dim memindex=c
   
   rem ** Each data statement you wish to point at should
   rem ** have a similar const statement.
   rem **
   const mydataplo=#<mydata
   const mydataphi=#>mydata

   rem ** Set the memory pointer to point to "mydata".
   rem **
   mempointer=mydataplo
   mempointerhi=mydataphi

   rem ** An example of indirect variable array access.
   rem **
   if mempointer[[memindex]]=0 then goto drawelephant

   data mydata
   0,3,5,8
end

Indirect variable arrays work with variable assignments and if…then statements.

 

If your indirect array is accessing a data statement, you can forgo the constant definitions in the example above, and just add “_hi” and “_lo” to the data label name.

   dim mempointer=a
   dim mempointerhi=b
   dim memindex=c

   rem ** Set the memory pointer to point to "mydata".
   rem **
   mempointer=mydata_lo
   mempointerhi=mydata_hi

   rem ** An example of indirect variable array access.
   rem **
   if mempointer[[memindex]]=0 then goto drawelephant

   data mydata
   0,3,5,8
end

Note: Many advanced statements in 7800basic don't work directly with indirect arrays. To use indirect arrays with those statements, you will need to assign any indirect array lookups to a variable, and use the variable with those statements.

 

 

 

 

8.8 Fixed Point Variables

Fixed point variables can be assigned fractional values, similar to floating point variables in other languages. 7800basic stores the integer part of the value in one byte (sometimes referred to as the “hi” or “large” part of the value), and the decimal part of the value in another (sometimes referred to as the “lo” or “small” part of the value).

 

To use fixed point variables you need to name them with dim, but this time we tell 7800basic that we'll be representing the variable with 2 parts.

   dim playerx = j.k

After that, using fixed point variables is pretty much as easy as using regular variables, except you can add or subtract values with a decimal point. This comes in handy, for example, when you want to move an object at slower speed than the frame rate.

   playerx = playerx + 0.2

The decimal point aspect of fixed point numbers is limited to addition and subtraction. When it comes to other operations in 7800basic, like if…then statements, the language works with the variable by just referencing the large/hi whole number byte.

 

Note: You must use decimal values when adding to fixed point variables. Assuming playerx is a fixed point variable, the following example would silently generate incorrect code.

   playerx = playerx + 1

Back to Top

 

 

 

 

 

Special Variables

 

The Score Variables and BCD Variables

7800basic provides you with two 24-bit score variables that you can use to track points for two player games, score0 and score1.

 

If you need more score variables than the two provided, you can dimension additional score2 to score9 variables, ensuring each dimension location has two free bytes of memory directly following it.

   dim score2=g : rem ** h and i are also used for score2

Usage of the score variables is straightforward. You can set the score variables with a regular assignment.

   score0 = 1000

And any time you wish to change the score, just do so with a regular addition or subtraction operation.

   score0 = score0 + 10

Please be aware that 7800basic cannot reliably add a variable to the score unless the variable is in Binary Coded Decimal format, or BCD for short. BCD is an alternate way for computers to represent decimal numbers in binary.

 

To assign numbers in BCD, you just take your decimal number you wish to assign, and add the hexadecimal $ specifier in front. For example, if we wanted a BCD variable to be 13, we'd assign $13 to it.

   z = $13
 

When performing operations on non-score BCD format numbers, you need to use the “dec” command to let 7800basic know it should do its work in BCD format.

   dec z = z + 1

It should be noted that multiplication and division don't work on numbers in BCD format in 7800basic, due to lack of support in the underlying hardware.

 

 

If you wish to display a regular variable, 7800basic also includes a “converttobcd” utility function that returns the BCD value of a non-BCD variable. The non-BCD variable should be in the range between 0-99, or else it will start to display incorrect values.

   BCDVar=converttobcd(NonBCDVar)

 

 

 

 

Random Numbers

rand is a special variable that will implicitly call a random number generator when used.

 

The rand function returns a pseudo-random number between 1 and 255 every time it is called. You typically call this function by something like this:

   a = rand

However, you can also use it in an if…then statement:

   if rand < 32 then r = r + 1

You can also set the rand variable to a specific value, at least until it is accessed again. The only reason you would ever want to do this is to seed the randomizer. If you do this, pay careful attention to the value you store there, since storing a zero in rand will “break” the randomizer, and all subsequent reads will also be zero!

 

 

 

 

Temporary Variables

There are 9 temporary variables, named temp1 through temp9, that are used by various 7800basic commands. You may reuse these variables so long as your code doesn't call one of the commands that overwrites it (typically the plot functions, some cases of multiplication and division, and function calls).

 

 

 

 

CARRY Variable

The 6502 CPU sets something called “the carry flag” every time an addition results in a value that exceeds 255, and every time a subtraction results in a value that isn't less than 0.

 

7800basic allows you to check the status of this flag with if…then. This is particularly useful if you wish to perform events every N frames…

   enemytick = enemytick + 33
   if CARRY then gosub enemymove

 

 

 

 

pokeydetected Variable

When your program has POKEY support enabled with “set pokeysupport on” (or “set pokeysupport ####”), you can check to see if 7800basic detected a POKEY chip through the pokeydetected variable.

   if pokeydetected then gosub playpokeymusic

 

 

 

 

paldetected Variable

You can check to see if 7800basic detected a PAL console through the paldetected variable.

   if !paldetected then frameskip=frameskip+213: if !CARRY then goto skipmoveplayer

 

 

 

 

Automatically Dimensioned Variables

 

autodim statement

The dim statement in 7800basic allows a fair bit of flexibility, as you can precisely choose where variables are situated in memory. This gives you the capability to create two or more variables that use the same memory. The downside to the specificity of the dim statement, is you need to manage the specific details when removing variables, relocating memory used by variables, etc.

 

To alleviate this management work, 7800basic's autodim statement allows you to specify a start and end location to automatically pull new variables from.

   autodim init var0 var99

The start and end locations can either be existing variable names (as in the previous example) or it can also just be direct memory locations.

   autodim init $2600 $26FF

To start creating variables in this area, you just specify the variable type and its name.

   autodim byte shipspeed

Available variable types are “byte” for regular 7800basic variables, and “8.8” for 16-bit fixed point variables.

 

If you want to allocate several variables at once, say for an array, you can just add the number of variables you want to allocate next to the variable name.

   autodim byte enemyhealth 8

You can also mix autodim usage with dim, if you need to give a variable multiple names, or uniquely access bytes in an allocation.

   autodim byte treasurestate 3
   dim red_treasure = treasurestate
   dim blue_treasure = treasurestate + 1
   dim green_treasure = treasurestate + 2

If you autodim a number of 8.8 variables, the hi/large parts of the 8.8 variables are grouped together, followed by the lo/small parts of the 8.8 variables, to allow easy access from an array. The compiler will also auto-create labels that allow you to directly access the hi and lo parts of the variable, by appending “_hi” and “_lo” to the variable name you used.

   autodim 8.8 tempxposition
   autodim 8.8 enemyxposition 4
   for index = 0 to 3
      rem ** stick this enemy’s current info into the temp variables...
      tempxposition_hi = enemyxposition_hi[index]
      tempxposition_lo = enemyxposition_lo[index]
      rem ** do calculations and update the temp variables...
      gosub UpdateEnemyX
      rem ** stick the temp variables back into the enemy info...
      enemyxposition_hi[index] = tempxposition_hi
      enemyxposition_lo[index] = tempxposition_lo
   next

Back to Top

 

 

 

 

 

Conditional Logic

Perhaps the most important statement is the if…then statement. These can divert the flow of your program based on a condition. The basic syntax is:

 

if condition then action

 

action can be a statement, label or line number if you prefer. If the condition is true, then the statement will be executed. Specifying a line number or label will jump there if the condition is true. Put into numerical terms, the result of any comparison that equals a zero is false, with all other numbers being true.

 

There are three types of if…then statements.

 

1. Simple True/False Evaluation

The first type is a simple check where the condition is a single statement.

 

The following example diverts program flow to line 20 if a is anything except zero:

   if a then 20

This type of if…then statement is more often used for checking the state of various read registers. For example, the joysticks, console switches, single bits and hardware collisions are all checked this way.

   if joy0up then x = x + 1

That will add 1 to x if the left joystick is pushed up.

   if switchreset then 200

Jumps to line 200 if the reset switch on the console is set.

   if collision(player1,playfield) then t = 1

Sets t to 1 if player1 collides with the playfield.

   if !a{3} then a{4} = 1

Sets bit 4 of a if bit 3 of a is zero. See Bitwise Variables for more information about using single bits.

 

 

2. Simple Comparison

A second type of statement includes a simple comparison. Valid comparisons are = , < , >, <=, >=, and <>.

   if a < 2 then 50
   if f = g then f = f + 1
   if r <> e then r = e

 

3. Compound Statement

The third type of if…then is a complex or compound statement, that is, one containing a boolean AND (&&) operator or a boolean OR (||) operator. You are allowed only one OR (||) for each if…then statement. You can use more than one AND (&&) in a line, but you cannot mix AND (&&) and OR (||).

   if x < 10 && x > 2 then b = b - 1
   if !joy0up && gameover = 0 then 200
   if x = 5 || x = 6 then x = x - 4

Warning: Using multiple if…thens in a single line might not work correctly if you are using boolean operators.

Back to Top

 

 

 

 

 

Code Organization and Flow Control

 

bank #

If you've chosen to use one of the bankswitch formats (see the set romsize command) you need to break up your game into banks. To signify any code that follows belongs to a particular bank number, you use the bank command…

[code belonging to bank 1]

   bank 2

[code belonging to bank 2]

You don't need to use the bank command to specify bank 1, as 7800basic assumes that a bankswitched game begins in bank 1.

 

 

 

 

dmahole #

The 7800 requires its graphics to be padded with zeroes. To avoid wasting ROM space with zeroes, 7800basic uses a 7800 feature called holey DMA. This allows you to stick program code in these areas between the graphics blocks that would otherwise be wasted with zeroes.

 

To direct 7800basic to store any code that follows in these areas, just use the dmahole command…

   dmahole 0

If you have multiple dmahole areas you can use multiple dmahole commands.

 

7800basic will stop directing code into the current dmahole when another dmahole command is encountered, or if a new bank is declared.

 

 

7800basic will automatically add assembly code to allow your BASIC program to flow across a DMA hole. If you're creating a bankswitched ROM and intend to fill the last bank entirely with graphics, you'll need to disable that extra generated assembly code. You can do that by adding the noflow keyword to the dmahole command…

   dmahole 0 noflow

 

 

 

 

goto

To leave one section of code and go to another, you create a label above the destination code, and use the goto command. The destination code can be anywhere in the program, as can the goto.

   If enemyy>150 then goto __Blow_Up_Enemy

   [more program code here]

__Blow_Up_Enemy

   [more program code here]

If your game is bankswitched, you can add a bank destination to your goto command.

   goto __Nuke_Them_All bank4

 

 

 

 

gosub and return

To leave one section of code for another, but eventually return back, you use the gosub command. gosub works almost the same as goto, except your destination area must eventually use the return command.

   If UFO=1 then gosub __Move_UFO

   [more program code here]

__Move_UFO

   [more program code here]

   return

If your game is bankswitched, you can add a destination bank number to your gosub command.

   gosub __Alien_Snot bank4

To return from a bankswitched gosub, use “return otherbank”.

 

If you have a routine that is called both locally and from other banks, you can end your routine with a “return” instead of “return otherbank”, and the bankswitch routines will sort out what to do.

 

If your game is bankswitched, you may want to use “return thisbank” instead of “return” for local returns, so 7800basic can use a bit less ROM space, and save a little bit of time too.

 

 

 

 

on…goto and on…gosub

To goto or gosub to different destinations depending on the value of a variable, you can use on…goto or on…gosub.

   on _Mokey_Size gosub __Small_Monkey __Medium_Monkey

   [more program code here]

__Small_Monkey

   rem we're here if _Mokey_Size was equal to 0

   [more program code here]

   return

__Medium_Monkey

   rem we're here if _Mokey_Size was equal to 1

   [more program code here]

   return

Please note that 7800basic won't make sure that your variable isn't larger than the number of labels used in on…goto or on…gosub. If there aren't enough labels in on…goto to handle the variable, your code will likely do unexpected things, up to and including crashing the console.

 

 

 

 

loadrombank

When using bankswitching, there may be times you wish to switch the active bank for using its data without actually calling goto or gosub. You may do this from the last always-present bank.

   loadrombank bank2

 

 

 

 

loadrambank

When using bankswitching with the BANKRAM formats, you can switch the active RAM bank with the loadrambank command.

   loadrambank bank1

 

 

 

 

reboot

The reboot command will restart your game as if the console had just been turned on. It uses no arguments...

   reboot

 

 

 

 

for…next

For-next loops work similar to the way they work in other BASICs.

 

The syntax is:

for variable = value1 to value2 [step value3]

 

variable is any variable, and value1, 2, and 3 can be variables or numbers. You may also specify a negative step for value3.

 

The step keyword is optional. Omitting it will default the step to 1.

   for x = 1 to 10
   for a = b to c step d
   for l = player0y to 0 step -1

Normally, you would place a variable after the next keyword, but 7800basic ignores the keyword and instead finds the nearest for and jumps back there. Therefore, the usual way to call next is without a variable. If any variable is specified after a next, it will be ignored.

   for x = 1 to 10 : a[x] = x : next

It is also important to note that the next doesn't care about the program flowit will instead find the nearest preceding for based on distance.

   for x = 1 to 20
   goto skipout
   for g = 2 to 49
skipout
   next

The next above WILL NOT jump back to the first for; instead it will jump to the nearest one, even if this statement has never been executed. Therefore, you should be very careful when using next.

 

 

 

 

altgamestart label

If for some reason you don't wish for 7800basic to begin running your game code from the beginning, you can define an “altgamestart” label elsewhere in your code. When the game is started, 7800basic will begin to execute code from your altgamestart location instead.

 

The main use for this functionality would be when you're using bankswitching, and you've stuffed the first bank completely full of graphics, and wish to start your game inside a dmahole.

   dmahole 0 noflow
altgamestart
   rem our game code will start running here

 

 

 

 

User Functions

A simple interface is provided for you to define your own functions in 7800basic. These functions can be defined within your program itself or compiled to their own separate .asm file then included with the include command. Functions can be written in BASIC or assembly language.

 

To call a function, you assign it to a variable. This is currently the only way to call a function. Functions can have up to six input arguments, but they only have one explicit return value (that which is passed to the variable you assigned to the function.) You can have multiple return values, but they will be implicit, meaning that the function will modify a variable and then you can access that variable after you call the function.

 

A function should have input arguments. In 7800basic, a function can be called with no input arguments if you want, but you might as well use a subroutine instead, as it will save space.

 

To declare a function, use the function command, and specify a name for the function. To return a value, use the return keyword. Using return without a value will return an unpredictable value.

 

Note that in 7800basic, all variables are global, and arguments are passed to the function by use of the temporary variables, temp1-temp6. Therefore it is recommended that you use the same temp variables for calculations within your function wherever possible so that the normal variables are not affected.

 

Example of declaring a function in 7800basic:

   function sgn
   rem this function returns the sign of a number
   rem if 0 to 127, it returns 1
   rem if -128 to 1 (or 128 to 255), it returns -1 (or 255)
   rem if 0, it returns 0
   if temp1=0 then return 0
   if temp1 <128 then return 1 else return 255
end

To call the above function, assign it to a variable, as follows:

   a = sgn(f)

Note that there is no checking to see if the number of arguments is correct. If you specify too many, the additional arguments will be ignored. If you specify too few, you will likely get incorrect results.

 

 

 

 

Data

For convenience, you may specify a list of values that will essentially create a read-only array in ROM. We'll go over the different commands in 7800basic to accomplish this.

 

 

 

 

Regular Data

You create these lists of values as data tables using the data statement. Although the data statement is similar in its method of operation as in other BASIC languages, there are some important differences. Most notably, access to the data does not need to be linear as with the read function in other BASICs, and the size is limited to 256 bytes.

 

If you prefer to use a data statement similar to that in other BASICs and don't want to be limited to 256 bytes, see Sequential Data below.

 

In a regular data statement, any element of the data statement can be accessed at any time. In this vein, it operates like an array. To declare a set of data, use data at the beginning of a line, then include an identifier after the statement. The actual data is included after a linefeed and can continue for a number of lines before being terminated by end. Suppose you declare a data statement as follows, with array name _My_Data:

   data _My_Data
   200, 43, 33, 93, 255, 54, 22
end

To access the elements of the data table, simply index it like you would an array in RAM. For example, _My_Data[0] is 200, _My_Data[1] is 43, … and _My_Data[6] is 22. You can only use this method to retrieve up to 256 elements, since the index is byte sized.

 

 

To help prevent the reading of values beyond data tables, a constant is defined with every data statementthis constant contains the length, or the number of elements, in the data. The constant will have the same name as the name of the data statement, but it will have _length appended to it.

 

For example, if you declare:

   data _My_Data
   1,2,3,4,5,6,7,8,9 
end

you can then access the length of the data with _My_Data_length. You can assign this to variables or use anywhere else you would use a number.

   a = _My_Data_length

These data _length constants will not work correctly if they are used before you declare the corresponding data statement. If you need to use a data _length constant before its data statement, declare the data _length constant near the beginning of your program (using the name of the constant as the value).

   const _My_Data_length=_My_Data_length

Note again that these data tables are in ROM. Attempting to write values to data tables with commands like _My_Data[1]=200 will compile but will perform no function.

 

 

 

 

Sequential Data

The sdata statement will define a set of data that is accessed more like the data in other BASICs. The 256-byte limitation is also removed. SequentialIn a row or in order without gaps. data is useful for things like music or a large set of scrolled playfield data. There is also no need to specify a pointer into the data.

 

Sequential data statement requires two adjacent variables to be set aside.

 

To define the set of data, use:

 

sdata <name>=<variable>

 

<name> is the name you wish to call it when it is read, and <variable> is the first variable name you are setting aside. Although you just specify one variable, the next variable in sequence will also be used.

   sdata _My_Music=a
   1,2,3,4,5,6,7,255
end

The above will set up a sequential data table called _My_Music that uses variables a and b to remember the element at which it is currently pointing.

 

Unlike regular data statements, the program must actually run over the sdata statement for it to be properly initialized to the beginning of the data table. Also, it must typically be defined outside the game loop because each time the program runs over the statement, it will be reinitialized to the beginning of the table.

 

To read the data, use the sread function. It works somewhat similar to a regular 7800basic function.

   t = sread(_My_Music)

This will get the next value in the data table _My_Music and place it in t.

 

Note that unlike other BASICs, there is no error or other indication when reaching the end of data. Since there is no data length variable defined with sequential data, it's usually necessary to place a terminal value at the end of your data. In the above example, 255 was used. In the above example you would then check t for 255.

 

There is no restore function like other BASICs. However, if you allow your program to run over the sdata statement again, it will be initialized to the beginning of data just like the restore function.

 

 

 

 

Using Character Data With alphachars and alphadata

To help with creation of tile maps and text strings, 7800basic has special data functions to reference each graphical character.

 

If you wanted to create text data that would be used to draw characters from a graphic file called “tileset_chars.png” that looks like this…

 

text data

 

…you would first give 7800basic a heads-up as to which letters you wish to use to represent these graphics with the alphachars command.

   alphachars ' abcd'

7800basic doesn't “know” the letters A, B, C. Instead, your alphachars statement tells 7800basic that any alphadata commands that follow should represent the space, A, B, C, and D, as the 0th, 1st, 2nd, and 3rd characters in the image file.

 

Once you've defined the characters in the image file with alphachars, you may go ahead and use them in one or more alphadata commands.

   alphadata mytext tileset_chars
   'bad dad'
   'abacab '
end

Plotting the characters on the screen would be just a matter of calling plotchars with the “mytext” data.

 

You can also embed non-character values in your alphadata by including comma separated numbers in the statement. Note that these numbers must be on a line by themselves, separate from your quoted text lines.

   alphadata mytext tileset_chars
   'bad dad'
   0,0,0
  'abacab '
end

Recall from the chart in the Graphics Modes section that most 7800modes represent a character with less than 8 pixels of width. If you would prefer to use wider character graphics than your mode allows, you have 2 choices.

 

1. You can set MARIA to doublewidth mode with the command…

   set doublewide on

This will make every character use two bytes instead of one, doubling the pixel width of each character.

 

2. If you only want to display some tiles with extra width and others with the normal character width, you can use the “extrawide” parameter with alphadata.

   alphadata testtext alphabet_8_wide extrawide
   'copyright'
end

Alphadata can also be used to help entry of non-alphabet data.

 

If we had a tile graphic that looks like this…

 

text data

 

…you could use the following alphachars to give a letter to each tile.

   alphachars ' abcdefg'

Which would tell 7800basic to reference tiles in the graphic with the following letters…

 

text data

 

After which we can define a screen with alphadata…

   alphadata screen1map tileset_blanks
   'fgdede        dedefg'
   'fg                fg'
   'fg                fg'
   'de                de'
   '                    '
   '                    '
   '                    '
   '                    '
   'fg                fg'
   'fg                fg'
   'fg              bcfg'
   'dedede        dedede'
end

With the screen data defined, we can call plotmap to display the screen.

 

text data

 

There are few more details we need to cover on using the alphachars command.

 

The default alphachars definition is ' abcdefghijklmnopqrstuvwxyz.!?,"$():'. This matches the graphical content of the sample alphabet_4_wide.png and alphabet_8_wide.png files that were provided with 7800basic.

 

If you wish to work with a full ASCII characterset, like the ATASCII set provided with 7800basic, you can quickly setup alphachars with “alphachars ASCII”.

 

If you have changed alphachars in one part of your code and wish to go back to the default set later, you can use the command “alphachars default”.

 

 

 

 

Tiled Character-Map Data Import

In the previous section we took a look at using alphadata to represent character maps. There is another, more flexible, way to represent character maps in 7800basic, and that's using the incmapfile command.

 

incmapfile allows you to import tile layouts that you have created in the Tiled graphical editor. The Tiled TMX files should be in XML format (under Edit->Preferences), and in Tiled you should use the same png image files you are using with incgraphic in your 7800basic program.

 

Once you've created the screen, import is just a matter of issuing the incmapfile command with the filename.

   incmapfile screen1map.tmx

You may then use the map name with the plotmap command, using the filename without the extension as the “mapdata” parameter.

 

It should be noted that you may only use characters in the filename that would be valid for 7800basic labels, so stick to alphanumeric characters, and avoid spaces and characters that have other meanings.

 

 

 

 

speechdata

Speechdata is a command used to generate voice data for use with the speak command, which sends data to the AtariVox speech module. Like other data commands, speechdata must be terminated by the end keyword.

  speechdata downspeech
  reset
  phonetic   'may the force be with yoo.'
end

The data itself contains several keywords, each of which represent the different types of data that AtariVox will accept. In the example above, you see reset data, followed by phonetic speech data.

 

Here's the list of valid data types for use in the speechdata command.

 

reset

Causes AtariVox to reset current speech and parameters.

pitch #

Any future speech data will use the provided pitch.

speed #

Any future speech data will use the provided speed.

raw #,#,#,...

The raw data provided is sent to the AtariVox. This is useful if you wish to send more complex commands to the AtariVox. See the SpeakJet manual for more information.

dictionary 'word phrase'

Each word is converted to AtariVox data via 7800basic's dictionary. Any words that aren't in the dictionary are run through phonetic translation.

phonetic 'word phrase'

Each word is converted to AtariVox data via 7800basic's phonetic translation. You will likely need to misspell complex words to get the pronounciation you desire, though first give the correct spelling a try before you try tweaking it.

 

For both dictionary and phonetic data, if you use a period at the end of a word, it will drop the pitch partway through the word and invoke a pause. Similarly, a question mark will cause a rise in pitch and similar pause. Spaces and commas will provide moments of silence.

 

See the speak command and set avoxvoice on for more information.

Back to Top

 

 

 

 

 

Program Configuration

7800basic has a series of “set” commands you may use to customize the 7800basic environment configuration. These should be at the top of your program, prior to other commands.

 

 

 

set romsize [value]

This sets the ROM size and format of your game. The default is 32k, and valid values for the romsize are 16k, 32k, 32kRAM, 48k, 128k, 128kRAM, 128kBANKRAM, 144k, 256k, 256kRAM, 256kBANKRAM, 272k, 512k, 512kRAM, 512BANKRAM, and 528k.

   set romsize 128k

Formats larger than 48k are bankswitching formats, with many 16k banks. While you need to bankswitch to access all banks except the last, which is always present. If you use bankswitching format, you'll need to use the bankswitching goto/gosub commands to move between different banks.

 

 

The formats with RAM on the end of the name provide an extra 16k of RAM from $4000-$7fff. You can access this extra RAM by naming it with dim, and using the memory through regular variable access.

   dim treasuremap = $4000

The formats with BANKRAM on the end of the name provide 2 banks of 16k RAM from $4000-$7fff. You may switch the active RAM bank with the loadrambank command.

 

The formats 144k, 272k, and 528k, all have bank 1 permanently available at the $4000 address space. This means you don't have to bankswitch to reach bank 1 with these formats. Similarly, you don't need to bankswitch to ensure graphics in bank 1 are displayed.

 

 

 

 

set bankset on

This instructs 7800basic to create a bankset format rom. Banksets doubles the amount of ROM your game can access. For more information, see the Bankset ROMs section of this guide.

 

 

 

 

set doublewide on

This tells MARIA to fetch 2 bytes of character data for each character you plot, effectively making the characters twice as wide.

 

 

 

 

set zoneheight [value]

The default zone height is 16, but can be defined just once in your program with the zone height setting.

   set zoneheight 8

There are more details on zone heights in the zoneheight entry in the Graphics Commands section of this guide.

 

 

 

 

set tallsprite [on|off|spritesheet]

If the tallsprite is set to “on” (the default) then when the 7800basic incgraphic command sees a graphic that is 2 zone-heights or more, it will import all of the graphics and link them together as a “tallsprite”. If you use the plotsprite command on a tallsprite graphic, the plotsprite command will loop to ensure all parts will be drawn.

 

If you wish to force incgraphic to only import 1 zone-height's worth of graphic data, you can issue the “set tallsprite off” command.

 

If you wish to import a png with a series of zone-sized vertical sprites, you can “set tallsprite spritesheet”. This has the benefit of ensuring all of the index colors are consistent between frames. The one drawback is the resulting sprites aren't uniquely named, and need to be drawn with plotsprite command [frame] parameter.

 

 

 

 

set screenheight

The default screen height is 192, but it can be defined once in your program with the screen height setting. Valid height values are 192, 208, and 224.

   set screenheight 208

There are more details on screen heights in the screenheight entry in the Graphics Commands section of this guide.

 

 

 

 

set extradlmemory on

This setting tells 7800basic that you want to use the memory at $2200 for the purpose of expanding your display list, to allow more objects. When you compile your program with this option, the compile output will tell you what memory values it used.

   $2250 to $27ff was claimed as extra DL memory.

In this example, you're still able to use the memory from $2200 to $224F for your program.

 

This option is incompatible with set dlmemory.

 

 

 

 

set dlmemory [first byte location] [end byte location]

By default, 7800basic allocates its object display list from $1880 to $1fff. If you have another source of available memory (like on-cart memory) and you need to increase the number of objects that the display can hold, you may wish to relocate the display list.

   set dlmemory $4000 $4fff

You can see the number of possible display objects during the game compilation.

   7800basic compilation complete.
   User-defined 7800.asm found in current directory
      7505 bytes of ROM space left in the main area of bank 1.
               4096 bytes of ROM space left in DMA hole 0.
      $18c0 to $1fff used as zone memory, allowing 14 display objects per zone.
      2314 bytes left in the 7800basic reserved area.

Note: Even though you can increase the number of bytes of display storage, this still isn't a guarantee you will have time to actually plot or display all those objects. Check out the doublebuffer command if you need more than one frame to build your display.

 

Warning: “set dlmemory” is incompatible with banksets.

 

 

 

 

set plotvalueonscreen [on|off]

This tells 7800basic that when the plotvalue command is used, it should update the screen immediately, instead of waiting for the screen to complete drawing. This will save precious off-screen cycles for plotting other objects, like sprites.

 

When using this configuration option, a program should issue its plotvalue commands in the same order, immediately after the restorescreen or clearscreen commands. This will ensure they go into the display list in the same order as previous frames, which prevents glitching.

 

 

 

 

set plotvaluepage [$##]

The plotvalue function converts the variable you pass to it into character-set codes. These character codes take up room in a buffer, which limits the total number of plotvalue characters to 64. This should be enough for most game types, but if your game has a screen full of values, the 64 character limit won't be enough. You can provide your own 256-byte storage page with the set plotvaluepage command. This will allow for 256 characters of value display.

   set plotvaluepage $27

 

 

 

 

set zoneprotection [on|off]

If too many objects are plotted to the same horizontal zone, there's a chance objects will overflow the storage for that zone, and corrupt display of the next zone. Using this command will prevent that from happening, at the expense of available CPU time.

 

It's unlikely this protection is needed when the zoneheight is 16. It may be needed if the zoneheight is 8 and the game has many free roaming objects.

 

 

 

 

set pauseroutine [on|off]

Turning pauseroutine off tells 7800basic to not use its built-in pause routine in the game.

 

See pausing for more information.

 

 

 

 

set pausesilence [on|off]

Turning pausesilence on tells 7800basic to not play sfx or tracker music when the game is paused.

 

 

 

 

set paddlerange [#]

This sets the value range the paddle controllers will return. Larger ranges use more CPU time.

 

 

 

 

set paddlescalex2 [on|off]

Doubles the values returned by the paddles, increasing the range without additional CPU time.

 

 

 

 

set paddlepair [on|off]

Tells 7800basic to read both paddles in a set of 2.

 

 

 

 

set mousexonly [on|off]

Tells 7800basic to only read the X axis of mice, to conserve CPU time.

 

 

 

 

set mousetime [value]

Tells 7800basic to change the amount of time reading the mouse driver. The default amount of time is 180, or 100 if you've enabled mousexonly. Spending less time reading the driver will also limit the maximum movement speed of the device.

 

 

 

 

set trakxonly [on|off]

Tells 7800basic to only read the X axis of trakballs, to conserve CPU time.

 

 

 

 

set traktime [value]

Tells 7800basic to change the amount of time reading the trakball driver. The default amount of time is 180, or 100 if you've enabled trakxonly. Spending less time reading the driver will also limit the maximum movement speed of the device.

 

 

 

 

set drivingboost [on|off]

Tells 7800basic to apply a boost to values, when the driving wheel controller is turned quickly.

 

 

 

 

set pokeysupport [on|off|$450|$800|$4000]

This tells 7800basic to enable or disable pokey soundchip support. If “on” is selected, the pokey location will be probed by 7800basic. If you instead specify one of the supported pokey addresses, no autoprobe will be done, and the pokey will be assumed to be presentthis is the recommended method of pokey support. There are more details in the Direct POKEY Sound section of this guide.

 

 

 

 

set pokeysfxsupport [on|off]

This tells 7800basic to enable or disable pokey sound within the 7800basic sound effect driver. If you want to use pokey-based sound effects with the 7800basic playsfx command, you'll want to use “set pokeysfxsupport on”

 

 

 

 

set trackersupport [basic|rmt]

This tells 7800basic to include music tracker support in your game. If “basic” is selected, the native MML TIA tracker will be included, If “rmt” is selected, the pokey RMT tracker will be included. You can only include one tracker type in your rom.

 

For more details see the TIA Music Tracker and RMT Music Tracker sections of this guide.

 

 

 

 

set rmtspeed [ntsc|pal]

This tells 7800basic what speed your rmt music was composed for. If you use this command, 7800basic will adjust the music speed so the music plays as composed, on both ntsc and pal consoles.

 

 

 

 

set tiasfx mono

This tells 7800basic to only use one channel for TIA sound effects. For more details see the TIA and POKEY Sound Effect Driver section.

 

 

 

 

set tiavolume on

This tells 7800basic to scale any TIA sounds by the variable “tiavolume”. The tiavolume value can range from 0 (silent) to 15 (full scale). This only applies to the 7800basic playsfx command and tia music trackerif you set tia registers directly in your program, they'll be unaffected by tiavolume.

 

Note that TIA sound volume itself ranges from 0 to 15, so using tiavolume at lower levels will cause some quieter sounds to be completely dropped. If you're using tiavolume to provide a volume control to your game, it's recommended that you encode sound effects and tia music at maximum volume levels, and provide descriptive volume levels (e.g. “off”, “low”, “medium”, “high”) to avoid setting tiavolume to very quiet.

 

Using this configuration setting will enable the “fourbitfade” assembly module in 7800basic's reserved area.

 

 

 

 

set avoxvoice on

This tells 7800basic to turn on AtariVox voice support. For more details see the speak and speechdata command documentation.

 

 

 

 

set debug color

This tells 7800basic to change the color of the screen to red, until all of the screen plotting functions are called. This allows you to judge how much of the program calculations are happening during the visible screen, and allows you to see the relative efficiency of your program.

 

 

 

 

set canary [on|off]

7800basic checks a memory location called “the canary” to see if its stack memory is being overwritten by your game. If this location changes, the screen will turn red and the game will stop. The canary protection is on by default, but you can use this statement to disable the protection.

 

 

 

 

set breakprotect [on|off]

If 7800basic detects the 6502 break opcode has been encountered, it will turn the screen yellow and stop the game. This is meant to highlight that data has been executed, instead of code, since the break opcode isn't normally part of your 7800basic game code. By default this break protection is on, but you can use this statement to disable the protection.

 

 

 

 

set crashdump [on|off]

If your game has the hiscorefont imported and you use “set crashdump on”, then any canary crash (red screen of death) or break protect crash (yellow screen of death) crash will dump the top of the stack contents to the screen. This may help someone with strong assembly skills track down which game routine led to the crash.

 

 

 

 

set mcpdevcart [on|off]

This tells 7800basic to use hotspots compatible with the 7800 MCP DevCart. This only needs to be used when working with bankswitched formats.

 

 

 

 

set basepath [directory path]

This tells 7800basic to add the provided directory path to any relative paths used with the incgraphic, incmapfile, and plotmapfile commands.

 

 

 

 

set hssupport $####

This tells 7800basic to include support for saving to the Atari High Score Cart, AtariVox, and Savekey. The #### is a unique hex number that identifies your game. You can reserve by announcing it in this AtariAge thread: https://atariage.com/forums/topic/128432-high-score-cart-values/

 

This should come before all other high score related set commands.

 

 

 

 

set hsseconds #

This allows you to control how many seconds the “drawhiscores attract” command will display for, before continuing to the basic command.

 

 

 

 

set hsscoresize #

This determines how many digits will be displayed for scores displayed by the “drawhiscores” command.

 

 

 

 

set hscolorbase #

This determines which color value the color cycling in the high score table will begin with.

 

 

 

 

set hsdifficultytext off

This turns off the difficulty level names in the high score display, which is useful for games with only one difficulty level.

 

 

 

 

set hsdifficultytext 'diff string 1' 'diff string 2' 'diffstring 3' 'diff string 4'

This allows you to provide custom names for the difficulty levels, instead accepting the default of easy, intermediate, advanced, and expert. The single quotes are only necessary if your names include spaces.

 

 

 

 

set hsgameranks # 'rank string 1' # 'rank name 2' # 'rank name 3' [...]

If you use this parameter, the high score tables will display a descriptive ranking of player's score. The scores+descriptions should be listed in descending order, with the last score listed being 0. The single quotes are only necessary if your descriptions include spaces.

   set hsgameranks 30000 commander 10000 lieutenant 0 ensign

 

 

 

 

set deprecated [frameheight|160bindexes|boxcollision|onepass]

Set deprecated is used to enable legacy behavior in some 7800basic routines. You should only use “set deprecated” for old code that you don't wish to update.

 

When using plotsprite with tallsprites and a frame index, incrementing the frame index by 1 will advance to the next tallsprite. The old behavior (advancing to the next sprite row) can be enabled by adding “set deprecated frameheight” to your source code.

 

Historically the incgraphic import used to import some 160B color indexes into 7800 transparent color indexes. Since this isn't likely to be what the user intended, 7800basic was updated so the 7800 transparent indexes were skipped. If you wish to use the old behavior you can add “set deprecated 160bindexes” to your source code.

 

The boxcollision function was updated to improve performance. If you need the older version for compatibility reasons, you can use “set deprecated boxcollision” to your source code.

 

7800basic was updated to a two-pass compile process, to allow resources to be imported after the code that references them. You can use “set deprecated onepass” to revert to the historic single-pass behavior.

 

 

 

 

set dumpgraphics [address]

Set dumpgraphics instructs 7800basic to dump all create graphics blocks to a “dump_gfx_##.bin” file, and to dump any needed assembly code to access those graphics within 7800basic to a “dump_gfx_##.asm” file.

 

This is useful for a few different scenarios:

  • You might want to use cart ram for character or sprite graphics, so it can be modified on-the-fly, or stored in an ephemeral rom bank that you don't need.
  • If your game uses banksets, you might want to increase graphics storage by including the graphics block bin into Sally rom, and copy it to Maria cart ram when it's needed.
  • You might want to use the previous scenarios with compression and decompression, to additionally save on rom.

 

The address parameter indicates where the cart ram storage that will eventually hold the graphics is located.

   set dumpgraphics $4000

The idea behind “set dumpgraphics” is you would use the command in a sacrificial game project, to generate the bin and asm files you need for your main game project. To include the bin in your main game project, you'd use the incbin command.

   bank 2
   include dump_gfx_00.asm ; ** allow plot* commands to work
   gosub copymycharset bank4
   [...the rest of the game logic in bank 2 follows...]

   bank 4
copymycharset
   memcpy $4000 .mycharset 2048 ; ** notice the dot before the label name
   return otherbank
mycharset
   incbin dump_gfx_00.bin

 

 

 

 

set snes0pause [on|off]

This set command tells 7800basic to pause or unpause the game via the “start” button on the SNES controller plugged into the left controller port, in addition to the regular console pause switch.

 

 

 

 

set snes1pause [on|off]

This set command tells 7800basic to pause or unpause the game via the “start” button on the SNES controller plugged into the right controller port, in addition to the regular console pause switch.

 

 

 

 

set snes#pause [on|off]

This set command tells 7800basic to pause or unpause the game via the “start” button on an autodetected SNES controller, in addition to the regular console pause switch.

 

 

 

 

set 7800GDmenuoff [0|1|all]

The 7800GD flash cart monitors for start/menu button presses on a megadrive controller (via mega7800) while your game runs, to allow the flash cart to interrupt the game and display a menu. The 7800GDmenuoff set command tells 7800basic to turn off the 7800GD monitoring for a given joystick port, or all of them. This is useful if your game uses the start or menu buttons on the controller.

 

 

 

 

set multibutton [on|off]

This set command tells 7800basic to enable support for SNES and Mega Drive gamepads (via the snes2atari and mega7800 controller adapters, respectively).

 

 

 

 

set multibuttonpause [on|off]

This set command tells 7800basic to use the controller's start button with the 7800basic pause routine. If you enable multibuttonpause, you can also use the “pausedisable” variable to disable pausing, and then detect and process the controller's start button normally. This can be used to allow the controller's start button to also start the game from a title screen, in addition to in-game pausing.

 

 

 

 

set 7800header ‘[command]’

This set command tells 7800basic to pass on your command to 7800header, when it's generating your a78 file. Normally 7800basic manages all of the required header information, but you may wish to add commands or override produced commands with this set command.

   set 7800header 'name Bird Blaster'

Back to Top

 

 

 

 

 

Bankset ROMs

By using the “set bankset on” configuration setting, you can double the amount of ROM available to your game. Half of that ROM spacethe first banksetonly visible to the 6502 CPU, a.k.a. Sally. Your program code, and any data that your program code needs to directly access, goes here. The other half of that ROM spacethe second banksetis only visible to Maria. Graphics, character strings, and map data, go here.

 

In addition to doubling the ROM, banksets have the added benefit that you don't need to squeeze program code into DMA holes.

 

 

 

 

Working With Banksets

Once you've enabled banksets, certain commands will automatically put data into Maria's bankset.

  • incgraphic
  • plotchars (with a quoted character string)
  • hi score related commands

 

Other commands will default to putting data into Sally's bankset, but you can direct them to put data into Maria's bankset by starting the data name with “bset_”

  • data
  • alphadata
  • incmapfile

 

Since Sally can't access Maria's ROM with banksets, if you use a ROM-based mapfile for graphics, you won't be able to use the same mapfile with peekchar. To use peekchar or any other sort of tile lookup, you'll either need a separate import of the mapfile to Sally's bankset, or you'll need to use RAM based maps, since both Sally and Maria can see the console RAM.

 

It should be noted that the dmahole command doesn't do anything with banksets activated, since there are no graphics in the Sally ROM.

 

 

 

 

Banksets and Bankswitching

When you use banksets with a bankswitched ROM type, you need to keep in mind that any change in the active bank is a change for both Sally's view of the bank and Maria's view of the bank. It's best practice to group code and graphics that will be needed at the same time together in the same bank.

 

 

 

 

Banksets and In-Cart RAM

The in-cart RAM with banksets is also doubled, with Sally-only RAM being 16K and Maria-only RAM being 16K. The in-cart RAM is located at $4000 to $7FFF, as usual.

 

To write to the Maria RAM, you write to a location from $C000 to $FFFF; just bear in mind that Maria will still read this RAM from its usual $4000-$7FFF location. There isn't a way for your code to read from Maria RAM.

 

Note that you can't use “set dlmemory” with banksets, due to hardware limitations.

 

 

 

 

Valid Bankset Hardware

While 7800basic will allow you to enable banksets with various other bits of hardwarelike pokey at various locationsthe available bankset cartridge hardware is more constraining. Before you rely on a particular hardware configuration with banksets, you should ensure it's listed as a variation at the bankset wiki entry.

Back to Top

 

 

 

 

 

Graphics Commands

 

displaymode

This command sets the current graphics display mode. You may choose between 160A, 320A, 320B. It should be noted that these modes are also capable of displaying 160B, 320C, and 320D formatted graphics, respectively.

   displaymode 320A

 

 

 

 

clearscreen

This command erases all sprites and characters that you've previously drawn on the screen, so you can draw the next screen.

 

 

 

 

savescreen and restorescreen

The savescreen command saves any sprites and characters that you've drawn on the screen since the last clearscreen. The restorescreen erases any sprites and characters that you've drawn on the screen since the last savescreen.

 

These commands are meant to reduce the CPU requirements of your game, by avoiding re-plotting background elements that don't change from frame to frame.

 

There are a couple of restrictions worth noting.

  1. You must use restorescreen with savescreen. If the clearscreen command is issued, the last saved screen is lost.
  2. Only one screen is ever saved. In other words, if you save the screen many times, you can't keep restoring many times to get back to the first screen.

 

 

 

 

drawscreen

The drawscreen command ensures that all plotted graphics are ready to display, and waits for MARIA to start the display. Including drawscreen in any display loop ensures that the loop will run every 1/60th of a second for NTSC consoles, or 1/50th of a second for PAL consoles.

 

 

 

 

drawwait

The drawscreen command completes near the beginning of the visible display. This is done intentionally, to allow your program to have the maximum amount of CPU time possible.

 

You may occasionally have code that you don't want to execute during the visible screen. For these occasions you can call the drawwait command. This command will only return after the visible screen has been completely displayed.

 

It should be noted that the plot* commands do the equivalent of calling drawwait for you, since modifying the screen display while it is being drawn would cause display glitches.

 

 

 

 

Working With the Screen Commands

Here's one example of putting the previous screen commands to work…

__Load_Level
   clearscreen
   gosub DrawBackgroundMap
   gosub DrawScoreBackdrop
   savescreen
__Main_Loop
   restorescreen
   [game logic and sprite plotting]
   drawscreen
   goto __Main_Loop

Though games with ever-changing backgrounds or non-character single-color backgrounds may choose to simply draw everything single thing every single frame, since they don't benefit from saving the background…

__Main_Loop
   clearscreen
   [game logic, character and sprite plotting, score display]
   drawscreen
   goto __Main_Loop

 

 

 

 

doublebuffer

If your game takes a very long time to build the display, you may wish to use the double buffering system in 7800basic, which frees you from the requirement of completing a display within a single frame. The double buffering system is controlled through the doublebuffer command.

   doublebuffer [on|off|flip] [minimum framerate]

When using double buffering, you don't need to use drawscreen anymore. The program flow will look something like this.

   doublebuffer on
   clearscreen
   [plot* commands to draw background]
   savescreen
__Main_Loop
   restorescreen
   [game logic, character and sprite plotting, etc.]
   doublebuffer flip
   goto __Main_Loop

You can optionally set a minimum framerate with the doublebuffer command, to ensure there's a uniform framerate when your game logic and object count differs.

   doublebuffer on 2

When you execute a savescreen command with double-buffering on, 7800basic will copy the current screen (typically the screen's background) from active buffer into the inactive one. This avoids you having to populate both buffers with the same background information.

 

Note: Double buffering requires two object buffers, so it will reduce the number of objects any given zone can display. To learn how to increase the number of objects, see the set dlmemory command.

 

 

 

 

topscreenroutine, bottomscreenroutine, and userinterrupt subroutines

If your game has a subroutine named “topscreenroutine”, this routine will be called at the beginning of each visible frame. This is useful if you wish to change the screen display as it's being drawn, changing the background color, changing the display mode, etc.

 

Similarly, you can create a “bottomscreenroutine” that corresponds to the bottom of the visible screen, and a “userinterrupt” routine, which runs when the off-screen area has been reached.

 

If you use the adjustvisible command, you can adjust the position on screen where the topscreenroutine or bottomscrenroutine routines are run.

 

You shouldn't modify the 7800basic temp1-temp9 variables, or any other key game variables in any of these routines. If you need temporary variables, you may use the inttemp1-inttemp6 variables.

 

See the two splitmode demos in the 7800basic samples directory for more information.

 

 

 

 

Setting Palettes

MARIA has 8x 3-color palettes to choose from when drawing sprites and characters. Setting the actual color these palettes use is just a matter of setting some special variables.

   rem  **  set palette 0 colors to green, light green, and salmon
   P0C1 = $d2
   P0C2 = $d8
   P0C3 = $3b
   rem  **  set palette 1 colors to grey, white, and yellow
   P1C1 = $04
   P1C2 = $0f
   P1C3 = $18

 

 

 

 

setfade, getfade (Color Fading)

7800basic has a “four-bit fade” module which allows you to fade-in or fade-out color values.

 

You set the current fade value by calling setfade with a current value, ranging from 0-15.

   setfade myfadevalue

After setting the fade value, you set get the values that your various color should be (with the current fade level) via the getfade command.

   P0C1 = getfade ($26)
   P0C2 = getfade ($44)

Since TIA shows non-black colors, even when a color's luminosity is 0, you can tell getfade to return 0 when the luminosity is zero, with the “black” argument. That way every color will fade to black, when the fade value is zero.

   P0C1 = getfade ($26, black)
   P0C2 = getfade ($44, black)

For more information on color fading, see the colorfade example in the 7800basic samples directory.

 

 

 

 

zoneheight

Graphics in 7800basic are limited to either 8 or 16 pixels tall. This is a result of MARIA's zone based architecture. To use taller sprites in your game, simple define more sprites and position one above the other. Other 7800 games with sprites taller than a zone are doing the same, one way or another.

 

The default zone height is 16, but can be defined just once in your program with the zone height setting.

   set zoneheight 8

Using a zone height of 8 means that 7800basic needs to present more memory to MARIA for screen building. As a consequence, when you use a zone height of 8, you may only display up to 16 objects within any zone. When you use a zone height of 16, you may display up to 20 objects on any zone.

 

 

 

 

screenheight

The vertical resolution of your screen in 7800basic defaults to 192 pixels, but you may set it to 208 or 224 pixels with set screenheight.

   set screenheight 208

The drawback of setting the screen height taller than 192 is it reduces the number of off-screen cycles your game may use. This may impact the number of objects you can plot on the screen, if your game has a large number of moving objects.

 

 

 

 

adjustvisible

If the very top or bottom part of your game screen doesn't have moving objects in it, you can use the adjustvisible command to tell 7800basic where the area that receives object updates is. This will make more CPU cycles available to your game.

 

The adjustvisible command takes the top visible zone and bottom visible zone as an argument. For example, if you wanted to exclude the top 2 zones in a game with zoneheight set to 8, the following command would do so.

   adjustvisible 2 23

The default values for a game with a zoneheight of 8 and screenheight of 192 would be 0 and 23. The default values for a game with a zoneheight of 16 and a screenheight of 192 would be 0 and 11.

 

Be warned that if you use adjustvisible and continually plot objects into the “non-visible” area, there will likely be some display glitching for those objects.

 

It should also be noted that 7800basic runs its own housekeeping code from interrupts at the top and bottom of the screen. If you create a very short visible area with adjustvisible, the housekeeping code won't have time to complete, which will cause issues with your game.

 

 

 

 

incgraphic

Being a command line program, 7800basic has no built-in image editor. Instead it has the ability to import standard .png format graphics.

 

When you create graphics, its important that you create them to adhere to the 7800 mode you want to import them in. If you have too many colors in your image, or if it the image has a width that isn't a multiple of the mode's character width, the import will fail with a compile error.

 

Images should also be in “indexed” format, rather than “rgb” format.

 

Whether you're importing a tileset or sprite image, the same incgraphic command is used.

   graphic filename.png [graphics mode] [color #0] [#1] ... [palette #]

The graphics mode is the name of the various MARIA display modes, 160A, 160B, 320A, 320B, 320C, or 320D. If you don't enter a mode, your image will default to being imported for 160A mode.

 

Since your image editor probably doesn't provide control over which color uses which index, 7800basic provides the ability to change which png color index goes to which MARIA color index. Here's an example of swapping the second and third colors.

   incgraphic foobar1.png 160A 0 2 1 3

The palette parameter needs to be defined if you plan to use your image as part of a map to be displayed with the plotmapfile command. It tells plotmapfile which palette number it should use when drawing any tile from the image.

 

The graphic plotting commands will access your image by its filename, without the .png extension. Because of this, it has certain restrictions on the file naming to avoid confusing the 7800basic compiler…

  • Each name should be unique.
  • Each name should contain only letters and digits.
  • Each name should begin with a letter character.

 

The png images should reside in the same directory as your source files, or in a subdirectory in the same directory as your source files. It's recommended that you use the subdirectory approach, since the number of graphic files used in a typical game can get overwhelming. Here's an example of using a subdirectory…

   incgraphic gfx/foobar2.png

You may use Windows style directory separator slashes (“\”) or Unix style directory separator slashes (“/”). Either style will work with 7800basic running on any platform.

 

When importing a graphic, incgraphic also creates “color constants” that you can use to set the palette entries for the sprite. Here's an example for setting palette 0 for the graphic “foobar3.png”.

   P0C1 = foobar3_color1
   P0C2 = foobar3_color2
   P0C3 = foobar3_color3

Since 7800basic only learns of these values during the incgraphic command, you may only use these constants in your source code lines after the incgraphic command for the sprite you wish to set the color for.

 

If you wish to fine-tune the color that 7800basic has provided, you may add or subtract a constant value from it.

   P0C2 = foobar3_color2 + $10

Note: For smooth glitch-free vertical movement with sprites, sprite graphics need to be placed into memory between $9000 and $EFFF. This is due to Maria not implementing the DMA hole feature at memory locations below $8000.

 

You can check where your graphics are presently imported by looking at the messages that 7800basic puts out when it compiles your game.

 

If you desperately need to use the areas below $9000 for sprite graphics, you'll need to ensure adjacent areas to your sprite graphics there have no code or data in them. At a high level, you can do this by using the “dmahole #” command to ensure your code doesn't spill into those areas. Exact details here are very specific to your game layout and zoneheight choices, and are beyond the scope of this document.

 

 

 

 

incbanner

Incbanner is identical to the incgraphic command, but is used to import png graphics that are taller than a single zone's height.

   incbanner filename.png [graphics mode] [color #0] [#1]  ...

 

 

 

 

newblock

You can use the newblock command to tell 7800basic to close off the current graphics block and begin a new one. This can be useful if you want to group certain graphics together in the same block. e.g. for sprite animations.

 

The command is used without arguments...

   newblock

 

 

 

 

plotsprite

To display a sprite on the screen you use the plotsprite command.

   plotsprite sprite_graphic palette_# x y [frame] [tallheight]

Where…

 

sprite_graphic is the the name of the imported graphic image you wish to display.

 

palette_# is the palette color set you wish the sprite to be drawn with.

 

x is the x screen coordinate of the new sprite.

 

y is the y screen coordinate of the new sprite.

 

[frame] is an optional parameter. If you have a series of sprites you wish to display (a walk cycle for example) you can do so by using a variable here. The first sprite will be displayed if the value is 0, the second sprite will be displayed if the value is 1, and so on. This feature requires all of the sprites to be the same width.

 

[tallheight] is the number of zones each tallsprite occupies, if you're using tallsprites. This parameter normally isn't needed, as 7800basic will detect the tallsprite height, provided your sprite's incgraphic statement happens before the plotsprite statement. The parameter can be used to ensure correct behavior if the incgraphic statement is after the plotsprite statement, as it may be with bankswitched games.

 

The display order of sprites and characters depends on the order they were drawn in. The very last sprite will be the one that appears to pass over top of other sprites.

 

 

 

 

plotbanner

To display a banner that was imported with incbanner on the screen, you use the plotbanner command.

   plotbanner banner_graphic palette_# x y

Where…

 

banner_graphic is the the name of the imported banner graphic image you wish to display.

 

palette_# is the palette color set you wish the sprite to be drawn with.

 

x is the x screen coordinate of the new sprite.

 

y is the y screen coordinate of the new sprite.

 

It should be mentioned that in the 7800 architecture, to accomplish plotting a banner “N” zones tall, 7800basic actually plots “N” sprites. This should be taken into consideration for games that are already pushing the sprite limits.

 

 

 

 

Notes on Use of Characters

Character graphics in 7800basic have a few wrinkles you should keep in mind.

  • Characters being used for any one frame of graphics must come from the same graphics area. The area will be 2k or 4k, depending on if you used 8 or 16 for your zone height setting.
  • Characters can only be plotted on distinct lines. The Y coordinates in character functions refers to a coarse/line position, not the screen Y coordinate.
  • MARIA can only plot 32 characters across with a single command. If you need more than 32 characters across, you'll either need to draw all the characters in 2 commands, or you can set doublewide on to double the amount of graphics one character displays.

 

 

 

 

characterset

MARIA is only capable of accessing characters from one graphics block at a time. To choose the active graphics block containing your characters, you use the characterset command. As an argument you just provide the name of one of the character graphics in the block you wish to activate.

   characterset playfield_tiles

If you have multiple graphics blocks and wish to maximize the number of characters you can display in any one frame, group the incgraphic commands for all character graphics together so they wind up in the same block.

 

 

 

 

plotchars

To display a character or line of characters on the screen you use the plotchars command.

   plotchars textdata palette_# x y [number_of_chars | extrawide]

Where…

 

textdata is the RAM, ROM, or literal text string you're trying to plot on the screen.

 

palette_# is the palette color set you wish the charters to be drawn with.

 

x is the x screen coordinate of the new characters.

 

y is the y line coordinate of the new characters.

 

number_of_chars is the number of characters you wish to draw. This isn't used if you've used a literal string for the textdata parameter.

 

extrawide can be specified if the graphics are twice the width of the character size. This optional parameter is only available if you've used a literal string for the textdata parameter. If you wish to make RAM or ROM character based data extrawide, the alphadata statement has a parameter for that.

   plotchars 'Hello World!' 0 0 8

Note 1: If you are using a literal text string with plotchars, you must specify the graphic with your font, using the characterset command.

   characterset alphabet_8_wide

Note 2: plotchars is normally limited to a maximum of 32 characters, due to the Maria chip's maximum object width limitation. If you're using 160A, 320A, or 320D modes for characters, you can exceed 32 characters and plotchars will split your text up into two text objects.

 

 

 

 

plotmap

To display two or more rows of characters on the screen you may use the plotmap command.

   plotmap mapdata palette_# x y width height [map_x_off map_y_off map_width]

Where…

 

mapdata is the RAM or ROM location of the data you're trying to plot.

 

palette_# is the palette color set you wish the charters to be drawn with.

 

x is the x screen coordinate of the new characters.

 

y is the y line coordinate of the new characters.

 

width is the number of columns of characters you wish to plot.

 

height is the number of lines of rows of characters you wish to plot.

 

The parameters that follow are optional, providing the ability to plot a small area of a larger data map definition.

 

map_off_x is the x coordinate of the area within the larger map.

 

map_off_y is the y coordinate of the area within the larger map.

 

map_width is the actual row width of the larger map.

 

 

 

 

plotmapfile

If you've drawn a screen map using Tiled (see incmapfile) you may wish to use plotmapfile to display it instead of plotmap. Plotmap displays its data in a single palette, while using plotmapfile will allow your display to use different palettes in different parts of the screen. Also, plotmap is limited to displaying a maximum width of 32 characters, but plotmapfile will allow you to fill the display with characters.

   plotmapfile mapfile.tmx mapdata x y width height

Where…

 

mapfile.tmx is the mapfile you wish to use as the screen map definition.

 

mapdata is the RAM or ROM location of the data you're trying to plot. In the case of ROM, this parameter will be the name of your mapfile without the extension.

 

x is the x screen coordinate of the new characters.

 

y is the y line coordinate of the new characters.

 

width is the number of columns of characters you wish to plot.

 

height is the number of lines of rows of characters you wish to plot.

 

It's important to note that when you import images for use with plotmapfile, you need to define their “palette” parameter, so plotmapfile will know which palette to use for areas of the screen that use that image. See the incgraphic entry for more information.

 

 

 

 

plotvalue

To display the value of a score or other BCD variable on the screen you use the plotvalue command.

   plotvalue digit_gfx palette_# variable #_of_digits x y [extrawide]

Where…

 

digit_gfx is the png graphic containing the numeric characters.

 

palette_# is the palette color set you wish the charters to be drawn with.

 

variable is the variable containing the BCD value you wish to display on the screen.

 

#_of_digits is the number of digits you wish to display. If you specify more digits than 2, which is the maximum a BCD value can hold, the next memory location will be used for the next 2 digits, and so on.

 

x is the x screen coordinate of the new characters.

 

y is the y line coordinate of the new characters.

 

extrawide is an optional parameter. If used, plotvalue will display digits at 2x the normal character width. The png graphic containing the numeric characters will need to be designed at 2x the normal character width for this feature to work.

 

Note: Because plotvalue uses an internal buffer to convert numbers to character strings, you can only plot up to 32 double-width or 64 single-width digits on the screen with plotvalue. If you need a larger number of values, please see the section for set plotvaluepage.

 

 

 

 

peekchar

The peekchar command is used to look up what value character is at a particular character position, in a character map. You may need to do this to, for example, to check if there's an item for the game's hero to eat, or to see if the game's hero is standing on solid ground.

 

peekchar may be used for RAM or ROM based maps.

   charvalue=peekchar( mapdata, x, y, width, height )

Where…

 

mapdata is either a ROM data statement that you defined with alphadata, or a RAM memory area that you defined with dim.

 

x and y are the column and row where the you wish to check is.

 

width and height are the total width and height of the map. These should be actual values, rather than variables.

 

Note: The character index returned by peekchar is the byte-position of the character within the current characterset. If you've turned on double-wide characters, the 7800 still uses byte-position for these indexes, so your first character will be at index 0, then second will at index 2, the third at index 4, and so on.

 

 

 

 

pokechar

The pokechar command is used to set a character value within a RAM based character map. You may need to use this, for example, if the game's hero has touched a “food” character and you wish to make it vanish.

   pokechar mapdata x y width height value

Where…

 

mapdata is a RAM memory area that you defined with dim.

 

x and y are the column and row where the you wish to check is.

 

width and height are the total width and height of the map. These should be actual values, rather than variables.

 

value is the character number you wish to store at the position.

 

Note: The character index used by pokechar is the byte-position of the character within the current characterset. If you've turned on double-wide characters, the 7800 still uses byte-position for these indexes, so your first character will be at index 0, then second will at index 2, the third at index 4, and so on.

 

 

 

 

lockzone

The lockzone command tells 7800basic to ignore any attempts to add any new sprites or tiles to a particular zone.

   lockzone zonenumber

Where zonenumber is the zone you wish to lock. The first zone at the top of the screen is number 0.

 

Note: The lock/unlock state of zones is saved with the savescreen command, restored with the restorescreen command, and cleared with the clearscreen command.

 

 

 

 

unlockzone

The unlockzone command tells 7800basic to remove a zone lock that was added previously with the lockzone command.

   unlockzone zonenumber

Where zonenumber is the zone you wish to lock. The first zone at the top of the screen is number 0.

 

Note: The lock/unlock state of zones is saved with the savescreen command, restored with the restorescreen command, and cleared with the clearscreen command.

 

 

 

 

shakescreen

The shakescreen command tells 7800basic to move the screen randomly, for visual effect.

   shakescreen amount

Where amount is one of the following words: hi, med, lo, or off.

 

The shakescreen command needs to be called once per frame, to continuously move the screen. When you're done with the shaking effect, you should call “shakescreen off” to restore the correct screen position.

 

 

 

 

memcpy

While it's not strictly a graphical command, the memcpy command is useful for copying ROM based character map data to RAM.

   memcpy destination source number_of_bytes

Where…

 

destination is a RAM based memory area that you defined with dim.

 

source is a ROM data statement that you defined with alphadata or data.

 

number_of_bytes is the number of bytes you wish to copy. This can range from 1 to 65535, but must be an actual value, rather than a variable.

 

 

 

 

strcpy

The strcpy command is useful for copying character strings directly into a memory location, without having to create the string data with an alphadata command first.

   strcpy destination 'Character String'

Where…

 

destination is a RAM based memory area that you defined with dim.

 

‘Character String’ is the sequence of characters you want copied to RAM.

 

The string needs to fit in 7800basic statement and line length limitations. If you need more data than this allows, you should use alphadata and memcpy instead.

 

Note: A characterset statement needs to precede strcpy, so that strcpy will know how to represent the encoded string.

 

 

 

 

 

 

 

memset

Also not strictly a graphical command, but memset is often usefull for initializing RAM based map data.

   memset destination value number_of_bytes

Where…

 

destination is a RAM based memory area that you defined with dim.

 

value is the value you wish to initialize each byte with. You can also use an alphanumeric character here, bounded by single quotes.

 

number_of_bytes is the number of bytes you wish to initialize with the value. This can range from 1 to 65535, but must be an actual value, rather than a variable.

 

 

 

 

Sprite Collisions with boxcollision

The Atari 7800 doesn't have hardware collision registers, so any collision detection needs to happen through software.

 

7800basic provides a boxcollision check that you can use to see if two of your sprites overlap. You must specify the sprites coordinates, and their width and height information…

   if boxcollision(sprite1x, sprite1y, sprite1w, sprite1h, sprite2x, sprite2y,
   sprite2w, sprite2h) then ...

The width and height information can either be numerical values or variables.

 

Normally 7800basic adds a bit of extra code to collision checking that allows it to check for sprites that are partially off screen. If you need a performance boost, you can turn collision wrapping off…

   set collisionwrap off

Be advised that turning collision-wrapping off may cause collision checks near the X=0 coordinate to also fail, so it's advised not to turn off collision wrapping if you need collision detection in the leftmost coordinates.

 

Boxcollision may fail if your width values are much larger than typical sprite widths, due to 6502 math overflow.

 

Checking the overlap of too many sprites with boxcollision() may cause your game to use too many cycles, which will result in slowdown and graphic artifacts. Checking if main character collided with 10 enemies shouldn't be an issue, but checking if those enemies have collided with each other will likely be a problem.

 

One solution for having too many objects to detect collisions between is to limit the sprite locations to certain areas of the screen, and only collision detect for sprites in the same area.

 

There are faster alternatives to boxcollision as well. If you just want to see if a bullet or small object has hit an enemy, you can do a quick coordinate check…

   if bulletx>enemyx && bulletx<(enemyx+16) && bullety>enemyy &&
   bullety<(enemyy+16) then ...

Another thing to keep is mind is that boxcollision() isn't reliable with off-screen objects, or objects wider than 48, or taller than 32. This is due to the limitations of 8-bit calculations.

Back to Top

 

 

 

 

 

Joystick Controls

Two-button joystick controls are the default in 7800basic. If you've switched from joysticks to another controller, you may switch back with the changecontrol statement, specifying controller port 0 or controller port 1.

   changecontrol 0 2buttonjoy

The 2buttonjoy mode will work with one button sticks, but if you prefer to force a single-button mode, you can do so with changecontrol.

   changecontrol 0 1buttonjoy

Joysticks are read by using an if…then statement. There are four directional functions and two fire button functions for each joystick.

   if joy0up then y = y - 1
   if joy0down then y = y + 1
   if joy0left then x = x - 1
   if joy0right then x = x + 1
   if joy0fire0 then goto __Purple_Monkey
   if joy0fire1 then goto __Aqua_Monkey

These can also be inverted using the ! token. For example:

   if !joy0up then goto __Tasty_Pilgrim

If a 2600 style single-button joystick is plugged in, the joystick button is read through joy0fire1.

 

 

If you wish to see if a joystick was used at all, you can check joy0any or joy1any:

   if joy0any then goto __Player_Moved

Back to Top

 

 

 

 

 

Driving Controls

Atari 2600 style driving controls can be used with 7800basic. To enable them for your game, use the changecontrol command in your program code, specifying controller port 0 or port 1.

   changecontrol 0 driving

7800basic will then read the driving controller every frame and adjust either the drivingposition0 (controller port 0) or drivingposition1 (controller port 1) variables.

 

If you wish to use the driving control like a quick-turn paddle controller, instead of slower drivingwheel control, you may wish to change the device step-per-resolution and/or use the “drivingboost” acceleration curve for the device.

   set drivingboost on
   port0resolution = 3

The driving wheel is an extremely low-resolution device, with 16 positions per 360 degree rotation. The above settings would make the controller useful for a paddle game.

 

Take note that driving controls, paddles, trakball x-axis, and the mouse x-axis all use the same variables for position, and the buttons can all be read using the regular joystick joy0fire method. This makes is easy to support multiple devices in your game code.

Back to Top

 

 

 

 

 

Paddle Controls

Atari 2600 style paddle controls can be used with 7800basic. To enable them for your game, use the changecontrol command in your program code, specifying controller port 0 or port 1.

   changecontrol 0 paddle

7800basic will then read selected paddle controllers every frame, and adjust the paddleposition0 (paddle 0, controller port 0), paddleposition1 (paddle 1, controller port 0), paddleposition2 (paddle 0, controller port 1) or paddleposition3 (paddle 1, controller port 1) variables.

 

By default, only the first paddle in the controller port is read. If your game requires two paddles, you can enable both controllers in the port.

   set paddlepair on

For reading the fire button of the first paddle in a pair, you can use joy0fire (or joy1fire). To read the second paddle fire button, you'd need to check joy0right (or joy1right).

 

You can also set the paddle range, which will adjust the amount of time required to read the paddle.

   set paddlerange 160

To save CPU time, you may wish to reduce the paddle range and scale up returned values x2.

   set paddlerange 80
   set paddlescalex2 on

Take note that driving controls, paddles, trakball x-axis, and the mouse x-axis all use the same variables for position, and the buttons can all be read using the regular joystick joy0fire method. This makes is easy to support multiple devices in your game code.

Back to Top

 

 

 

 

 

Mouse Controls

Either Atari ST or Amiga mice can be used with 7800basic. To enable them for your game, use the changecontrol command in your program code, specifying controller port 0 or port 1.

   changecontrol 0 stmouse

   changecontrol 0 amigamouse

7800basic will then read the selected mouse every frame, and adjust the mousex0 and mousey0 variables (controller port 0) or mousex1 and mousey1 variables (controller port 1).

 

If your game only incorporates mice for side to side movement, you may wish to save CPU time by only reading the mouse x axis.

   set mousexonly on

You can also set the amount of CPU time that 7800basic will spend polling the mouse.

   set mousetime 100

The easiest and least expensive source of compatible mice are PS2 mouse -> Amiga/Atari mouse adapters, used in conjunction with PS2 mice. These adapters tend to have fewer issues, while providing the superior resolution of a modern mouse. Legacy ST and Amiga mice may not work with all consoles, and even when they do, these are lower resolution devices.

 

If you wish to support legacy mice in your game, you may wish to warn your users that old mice may not be reliable on all consoles. You can also change the resolution of the device.

   port0resolution = 2

Take note that driving controls, paddles, trakball x-axis, and the mouse x-axis all use the same variables for position, and the buttons can all be read using the regular joystick joy0fire method. This makes is easy to support multiple devices in your game code.

Back to Top

 

 

 

 

 

Trakball Controls

CX-22 Trakballs can be used with 7800basic. In theory the 7800basic trakball driver should also work with CX-80 Trakballs, but some small portion of these devices actually use the Atari ST mouse protocol.

To enable trakballs for your game, use the changecontrol command in your program code, specifying controller port 0 or port 1.

   changecontrol 0 trakball

7800basic will then read the selected trakball every frame, and adjust the trakballx0 and trakbally0 variables (controller port 0) or trakballx1 and trakbally1 variables (controller port 1). If your game also allows for mice, you may instead reference the mousex# and mousey# variables.

 

If your game only incorporates trakball for side to side movement, you may wish to save CPU time by only reading the trakball x axis.

   set trakxonly on

You can also set the amount of CPU time that 7800basic will spend polling the trakball.

   set traktime 100

You can also change the resolution of the device to suit your game requirements better.

   port0resolution = 2

Take note that driving controls, paddles, trakball x-axis, and the mouse x-axis all use the same variables for position, and the buttons can all be read using the regular joystick joy0fire method. This makes is easy to support multiple devices in your game code.

Back to Top

 

 

 

 

 

Keypad Controls

Atari 2600 keypad controls can be used with 7800basic. To enable them for your game, use the changecontrol command in your program code, specifying controller port 0 or port 1.

   changecontrol 0 keypad

Keypad controllers are read by using an if…then statement to test for key presses. Here's an example of testing if button “3” is being pressed.

   if keypad0key3 then goto __Handle_Key_Press_3

The keypad 0 buttons can be read with keypad0key0 through keypad0key9, keypad0keys (star), and keypad0keyh (hash).

 

The keypad 1 buttons can be read with keypad1key0 through keypad1key9, keypad1keys (star), and keypad1keyh (hash).

 

The keypad data is also encoded as bits in the variables keypadmatrix0a-keypadmatrix0d and keypadmatrix1a – keypadmatrix1d.

Back to Top

 

 

 

 

 

Multibutton Controls

7800basic allows for a variety of controllers to be used by your game, including some with more than 2 buttons, such as the SNES gamepad (via snes2atari) and the Sega Mega Drive/Sega Genesis gamepad (via mega7800). To add support for these controllers in your game, turn on multibutton support near the top of your source code.

   set multibutton on

For any game port that's set to “twobuttonjoy” (the default controller) 7800basic will probe the port for a supported controller. On finding the controller, the “multibuttoncount0” or “multibuttoncount1” variables will be updated with the number of regular buttons found on the controller.

 

You can detect movement and buttons from the controller in your game code by using the following conditions in if…then statements: joy0up, joy0down, joy0left, joy0right, joy0fire0, joy0fire1, joy0fire2,joy0fire3, joy0fire4, joy0fire5, joy0select, joy0start.

 

Some controllers don't physically have every possible button. You can still test for buttons that aren't present on the controller in your game code without running into errors, but you should give the player an alternate way of accessing that functionality, or inform the players up-front which controllers are supported with the game.

   Pro-Line: joy0fire0, joy0fire1
   3-button Mega Drive: joy0fire0, joy0fire1, joy0fire2, joy0start
   6-button Mega Drive and SNES: joy0fire0, joy0fire1, joy0fire2, joy0fire3,
                                 joy0fire4, joy0fire5, joy0select, joy0start

If your game doesn't use the controller's start button, you can tell 7800basic to allow the controller button to control pausing, in addition to the console pause switch.

   set multibuttonpause on

Even if your game doesn't use more than two buttons, you may want to consider enabling support for multibutton controllers and multibutton pausing, to make the game experience nicer for those with supported controllers.

Back to Top

 

 

 

 

 

SNES Controls

Note: It's recommended to use the Multibutton Controls support in 7800basic, rather than using this older snes2atari functionality. The multibutton support allows for a wider range of controllers, and is easier to write code for.

 

SNES controls can be connected to the 7800 console via the SNES2ATARI adapter, and then used with 7800basic. To enable them for your game, use the changecontrol command in your program code, specifying controller port 0 or port 1.

   changecontrol 0 snes

SNES controls are read by using an if…then statement to test for button presses or direction pad pushing. Here's an example of testing if button “Y” is being pressed.

   if snes0Y then goto handlesnesY

The complete list of if…then testable conditions are: snes0up, snes0down, snes0left, snes0right, snes0A, snes0B, snes0X, snes0Y, snes0lsh (left shoulder), snes0rsh (right shoulder), snes0select, and snes0start. If you configure an SNES controller for port 1, there are corresponding snes1up, snes1down, etc. testable conditions.

 

SNES controls also support autodetection with the snesdetect command

   snesdetect

If an SNES controller was found during autodetection, you can detect which port it was found in by checking if either the port0control or port1control variables is equal to 11. You can also check if the controller is responding at any given moment with the snesdetected0 and snesdetected1 variables. If the player unplugs an SNES controller, the port will remain setup, but the snesdetected0/snesdetected1 variable will be equal to zero.

   if port0control = 11 && snesdetected0 then skipsnesdetect

Alternatively, you don't need to pay attention to the port the detection happened on, and just test for any autodetected SNES controller state with: snes#up, snes#down, etc.

   if snes#Y then goto handlesnesY

It should be noted that after the snesdetect command, any ports without an SNES controller found will be left in a 2-button joystick configuration.

 

If you wish to control game pausing via the SNES pad “start” button, in addition to the console pause button, you can use one or more of the following “set” commands. Choose the one appropriate to your control scheme.

   set snes0pause on
   set snes1pause on
   set snes#pause on

Back to Top

 

 

 

 

 

Mega7800 Controls

Note: It's recommended to use the Multibutton Controls support in 7800basic, rather than using this older Mega7800 functionality. The multibutton support allows for a wider range of controllers, and is easier to write code for.

 

Sega Mega Drive/Sega Genesis controls can be connected to the 7800 console via the Mega7800 adapter, and then used with 7800basic. To enable them for your game, use the changecontrol command in your program code, specifying controller port 0 or port 1.

   changecontrol 0 mega7800

The controls are read by using an if…then statement to test for button presses or direction pad pushing. Here's an example of testing if button “Y” is being pressed.

   if mega0Y then goto handlemegaY

The complete list of if…then testable conditions are: joy0up, joy0down, joy0left, joy0right, mega0A, mega0B, mega0C, mega0X, mega0Y, mega0Z, mega0mode, and mega0start. If you configure a mega7800 controller for port 1, there are corresponding mega1A, mega1B, etc. testable conditions.

Back to Top

 

 

 

 

 

Console Switches

 

The Reset, Select, and Difficulty Switches

Reading the console switches is done by using an if…then statement.

 

if switchreset

True if Reset is pressed. See reboot if you would like to use switchreset to warm boot your game.

 

if switchselect

True if Select is pressed.

 

if switchleftb

True if left difficulty is set to B (amateur), false if A (pro).

 

if switchrightb

True if right difficulty is set to B (amateur), false if A (pro).

 

For example, these are accessed by:

   if switchreset then goto __My_Reset

These can all be inverted by the NOT (!) token:

   if !switchreset then goto __Skip_Reset

 

 

 

 

pausing

7800basic has a built-in handler for the pause switch, and will automatically pause your game and silence any TIA audio if the pause switch is pressed. If you're satisfied with this behavior, there's nothing else required from your BASIC code.

 

If you would like to run a special routine during this time, create a subroutine called pause. This is where you can play a song, gray out colors, or display a “paused” message while the console is paused.

 

If you wish to draw moving sprites or changing characters during your pause subroutine, you'll need to restorescreen or clearscreen at the top of your pause routine. You don't need to include a drawscreen command though, as this is done for you when you return from the pause subroutine.

pause
   restorescreen
   gosub DrawPlayerTappingFoot
   return
 

7800basic provides a “pausestate” variable you can use to detect the first time through the pause routine. This variable will equal 1 on the first time running the subroutine, and it will equal 2 on subsequent runs.

 

This is useful if you want to display a simple “paused” message, but don't want to bother with restorescreen or clearscreen.

pause
   if pausestate = 1 then plotchars pausedtext 2 64 5 5
   return

If you wish to roll your own pause handler, you can do that as well. To stop 7800basic from including the built-in handler, use the “set pauseroutine off” command.

   set pauseroutine off

You can then read the pause switch state with if switchpause.

   if switchpause then goto myownpauseroutine

Remember that the switch is a momentary switch, so you'll need to track one press and release for pausing, and another press and release for un-pausing.

 

If you only wish to momentarily disable the pause feature, you can set the variable “pausedisable=1”. To reenable the pause feature, use “pausedisable=0”.

Back to Top

 

 

 

 

 

Direct TIA Sound

TIA is the sound chip in the 7800. If you're creating a game that has no extra soundchip on the circuit board, you'll be making all of your sounds by manipulating TIA. You can do so by playing TIA data with the playsfx command, or by manipulating the TIA registers directly.

 

 

 

tsound

7800basic provides the tsound command for conveniently setting the TIA audio registers. It's similar in function to the sound command found in Atari BASIC.

   tsound channel, [frequency], [waveform],[volume]

The channel value must be 0 or 1. You may omit any of the frequency, waveform, or volume values, if you wish to keep a previously set value for the current channel (though you must still include the commas).

 

Here's an example of using tsound to set the frequency and volume for channel 0, and omitting the waveform information.

   tsound 0,12,,8

 

 

 

 

TIA Sound Registers

If you wish, you may drive the TIA audio by changing its registers directly, instead of using tsound.

 

TIA has two independent audio channels that work identically (channel 0 and channel 1). Each channel has three registers that determine the sound that will be produced (AUDV0, AUDC0, AUDF0, AUDV1, AUDC1, AUDF1).

 

AUDVx stands for AUDio Volume. The volume register determines the volume or amplitude of the sound that will be produced. Valid values are 0 through 15.

 

AUDCx stands for AUDio Control. The control register determines the waveform or tonal quality that will be produced. Valid values are 0 through 15.

 

AUDFx stands for AUDio Frequency. The frequency register determines the frequency or note that will be produced. Valid values are 0 through 31.

 

Set AUDV0 or AUDV1 to pick the volume or amplitude of the sound you want to play0 is “off” or “mute” and 15 is the loudest.

 

Set AUDC0 or AUDC1 to pick the waveform you want to use. With one exception, each waveform is just a stream of 0s and 1s that are repeated endlessly in a specific pattern, causing the speaker to vibrate in that pattern and create a sound. The length of the pattern determines the primary frequency of the sound, and the complexity of the pattern determines how “pure” or “noisy” the sound is. One waveform is just a stream of 1s (or “always on”), so it sounds “silent” (because the speaker doesn't vibrate back and forth the way it does with the other waveforms)but you can use the volume register with this “always on” waveform to create your own waveforms.

 

Set AUDF0 or AUDF1 to pick the frequency or note you want to play. The TIA doesn't use the standard set of musical notes (C, D, F#, G, etc.)instead, it uses harmonics (or really “subharmonics”) of the primary frequency that's been selected with the AUDC0 or AUDC1 register. To determine what the resulting frequency will be, add 1 to the AUDF0 or AUDF1 setting and divide the primary frequency by that numberfor example, AUDF0 = 3 divides the primary frequency by 4 (3 plus 1), whereas AUDF0 = 7 divides it by 8.

 

Unless you're using the “always on” waveform, making music with the TIA is a “set it and forget it” thing, meaning you can set AUDC0, AUDV0, and AUDF0 (or AUDC1, AUDV1, and AUDF1) and they'll keep their values, playing the same sound continuously until you change their settings to pick a different sound. In practical terms, this means you don't need to keep setting them over and over again within a loop to keep playing the same sound; you just set them once and then you don't have to worry about them again until you're ready to play a different sound.

Back to Top

 

 

 

 

 

Direct POKEY Sound

7800basic is able to access the POKEY sound chip, if the chip is provided either on the cartridge or through add-on hardware. To enable pokey support and auto-detection, use the following line near the top of your basic program.

   set pokeysupport on

You can check to see if a POKEY chip was detected in the following manner.

   if pokeydetected then gosub playmypokeysong else gosub playmytiasong

If you wish to skip pokey autodetection and assume a location at one of the supported locations ($450, $800, or $4000) you can specify the location in your pokeysupport statement.

   set pokeysupport $450

 

 

 

 

psound

7800basic provides the psound command for conveniently setting the POKEY audio registers. It's similar in function to the sound command found in Atari BASIC.

   psound channel, [frequency], [waveform , volume]

The channel value may range from 0 to 3. You may omit the frequency parameter. You may also omit the waveform and volume parameters, so long as you omit or include them both.

 

The frequency parameter may range from 0 to 255. Both the waveform and volume parameters range from 0 to 15.

 

Here's an example of using psound to set the frequency and volume for channel 0.

   psound 0,200,10,15

It's recommended that you stick to even waveform values, as odd ones only move the speaker to a certain position, and won't play a frequency. Here are some descriptions of waveform values you may find useful as a starting point…

 

0 pink noise, rough whooshing
2 triangle wave, bell tones
4 noise tone mix, rumbling at lower end
6 triangle wave, bell tones (repeat of 2)
8 white noise, whooshing
10 square wave, pure tones
12 sawtooth wave, buzzy if using AUDF that's non-divisible by 3
14 square wave, pure tones (repeat of 10)

 

 

 

 

POKEY Sound Registers

7800basic handles all initialization when it runs through its POKEY detection routines at start up, so you don't need to do any initialization of your own.

 

Because POKEY is detected and may be in different locations in memory, you'll need to access the POKEY registers using indirect array access.

 

The details of driving POKEY through its registers is beyond the scope of this document, but here's an example of how to set the PAUDF0 register to 100, within 7800basic's auto-detection scheme.

   pokeybase[[PAUDF0]]=100

Back to Top

 

 

 

 

 

TIA and POKEY Sound Effect Driver

7800basic has an advanced sound driver that greatly simplifies adding both TIA and POKEY sound effects in your game.

   playsfx soundata [offset]

The optional offset parameter allows you to raise or lower the pitch of the played sound. If you have a sound which is often repeated, it's recommended that you vary its pitch a bit randomly.

   temp7=rand&3 : rem set temp7 to a random number from 0-3
   playsfx sfx_lasershot temp7

When you play a sound, the sound driver will automatically choose between the two available sound channels based on which channels are already being used by the driver, and if both channels are being used it will interrupt one of the playing sounds based on a priority system.

 

Before playing a sound with playsfx, you'll need to define the sound effect data in the expected format. The data format 7800basic works with is composed of three parts, a header, the sound data itself, and an end-of-sound marker.

 

The header consists of 3 bytes:

 

The sound data then consists of 3 byte chunks, each of which represents the Sound Frequency, Control/Waveform, and Volume to play. The sound driver will continue to play the sound data until it reaches an end of sound marker, which consists of 3 zero bytes.

 

Here's an example TIA sound, which simulates the sound effect when jumpman jumps a barrel in Donkey Kong. There are 5 chunks of sound data, and each chunk plays for 5 frames.

   data sfx_jumpman
   16, 5, 4 ; version, priority, frames per chunk
   $1E,$04,$08 ; 1st chunk of freq,channel,volume data
   $1B,$04,$08 ; 2nd chunk
   $18,$04,$08 ; 3rd chunk
   $11,$04,$08 ; 4th chunk
   $16,$04,$08 ; 5th chunk
   $00,$00,$00 ; End Of Sound marker
end

If you want to change the frames-per-chunk mid-sound, you can do so by adding in a chunk with values $00, $10, followed by a value for the new frames-per-chunk, as seen in the example below.

   data sfx_extendobump
   $10,$10,$01 ; version, priority, frames per chunk
   $08,$08,$0a
   $08,$0c,$0a
   $08,$06,$0a
   $08,$0e,$0a
   $08,$06,$08
   $08,$06,$08
   $00,$10,$08 ; slow down to 8 frames per chunk
   $08,$0e,$06
   $08,$06,$04
   $08,$06,$02
   0,0,0
end

If you wish to constrain the sound driver to only using the first sound channel when playing TIA sounds, you can use the “set tiasfx mono” statement.

 

 

If you wish to silence all in-progress sounds, you can use the “mutesfx” command, and specify which sound chip you wish to mute.

   mutesfx tia
   mutesfx pokey

Back to Top

 

 

 

 

 

TIA Music Tracker

7800basic has a music tracker you can use to automatically play song data, with options to select tempo and number of repetitions.

 

The music tracker requires that you provide instrument data and song data.

 

 

 

Enabling the TIA Music Tracker

Since not every game design features music, 7800basic doesn't automatically incorporate the tracker code into your game. To enable music tracker support, add the following line near the start of your basic program:

   set trackersupport basic

 

 

 

 

Instrument Data

Instruments are defined in data statements that are similar in structure to sound effects. Here's the syntax breakdown.

 

byte 0:

Instrument type+version. ($10 for TIA is all that's supported right now).

byte 1:

Instrument priority. Instruments work with the 7800basic sound-effect priority system.

byte 2:

Frames per chunk. Larger values here plays back the instrument data slower.

bytes 3+4:

Offset+volume for the first chunk of instrument sound data. The offset is semitone offset from the note currently being played, so you can simulate tremolo.

bytes 5+6:

Offset+volume for the second chunk of instrument sound data.

bytes “0”,“0”:

The End Of Instrument flag.

 

 

Here's an example instrument.

   data tiashort
   $10,$00,$03 ; version, priority, frames per chunk
   $00,$06 ; note offset, volume
   $00,$04 ; note offset, volume
   $00,$00 ; End Of Instrument
end

You may have noticed that there isn't a place to select which TIA channel/distortion is being played. Because TIA doesn't have much useful overlap between the frequencies it produces, the TIA channel is automatically selected for you based on the note position being played.

 

 

 

 

songdata

Song data is stored with your basic source code with a songdata command, which follows the same basic syntax as other 7800basic data statements.

   songdata mysong
   [song data here]
end

The actual song data has its own special syntax, which will be covered in following sections in-detail. It should be noted that addional white space within songdata is ignored, so you are free to data together using spaces, tabs, and newlines.

 

 

 

 

Labels

Any word in the song data that isn't indented from the left-margin is considered a label.

 

There are 4 special labels that identify the data the song should begin with – main1, main2, main3, and main4. The 4 labels are played in parallel, as 4 independant tracks.

 

Even though there are 4 tracks available, you still need to keep in mind there are only 2 TIA voices available. Having 4 tracks will become more useful in the future when other instrument types, like POKEY, are integrated into the tracker.

 

The song data that follows a label may contain notes, note modifiers, or other labels. Here's an example of a songdata statement with 2 tracks, and labels that call other labels.

   songdata funeralmarch
main1
   k=a4
   i=tiashort
   c2 c8 r4 c8 c2 d#8 r4 d8 d8 r4 c8 c8 r8 < b4 > c2
main2
   i=tiashort
   k=a2 bassline ; transpose the key, and call the baseline label
   k=b2 bassline ; again, with another transpose
   k=a2 altbassline ; and again
   c2 ; final note
bassline
   c4 c4 c4 r4
altbassline
   c4 c4 < b4 > r4
end

If you want a called label to play a number of times, by adding a period and number after the label name. This method uses less ROM space than repeating the same label call over and over, but is limited to playing the label up to 8 times.

 

Here's an example of a labels called multiple times.

   songdata herecomesthesun
main1
   k=a3
   i=tiashort
   intro.4
   chorus.8
intro
   [note data]
chorus
   [more note data]
end

It should be noted that labels can only call other labels to a depth of 3; any one of the main tracks (depth 1) can call another label (depth 2), which in turn can call another label (depth 3). If you go beyond a depth of 3, the song and your program itself will likely crash.

 

 

 

 

Track and Song Modifiers

At any time in the song, you may set/change the instrument being played on the track, transpose the key a track is in, or modify the overall song tempo.

 

To change the instrument being played, set “i” equal to the name of the data containing the instrument definition.

   i = tiashort

To transpose the absolute key the track is being played in, set “k” equal to the note position on the TIA scale.

   k = a3

There are a few ways to change the relative key of the track. Here are examples of shifting the key up 2 semitones, down 3 semitones, shifting the key down an octave, and shifting the key up an octave.

   k+2
   k-3
   <
   >

To transpose the absolute tempo the track is being played in, set “t” equal to the BPM value you desire.

   t = 120

You can also change the relative tempo of a track. Bear in mind the numbers in a relative tempo adjustment don't represent BPM, but rather just internal tempo counter amounts.

   t+5
   t-10

 

 

 

 

TIA Key Mapping

TIA isn't capable of playing pure tones across the whole musical spectrum. Some musical frequencies aren't able to be played at all, while others must be played in a TIA channel with distortion or buzzing. The following is a breakdown of the notes the 7800basic tracker can play, and their tonal quality.

Octave 0 – Electronic
note is very out of tune:      . .  . .  . * .  . .  * .  .
                               c c# d d# e f f# g g# a a# b
Octave 1 – Somewhat Buzzy
note is very out of tune:      . .  . .  . . .  . .  . .  .
                               c c# d d# e f f# g g# a a# b
Octave 2 – Buzzy
note is very out of tune:      . .  . .  . . .  . .  . .  .
                               c c# d d# e f f# g g# a a# b
Octave 3 – Buzzy from c3 to d#3, Pure from e3 to b3
note is very out of tune:      . .  . *  . . .  . .  . .  .
                               c c# d d# e f f# g g# a a# b
Octave 4 – Pure
note is very out of tune:      . .  . .  . . .  * .  . .  .
                               c c# d d# e f f# g g# a a# b
Octave 5 – Pure
note is very out of tune:      . .  . .  . . .  . .  . .  .
                               c c# d d# e f f# g g# a a# b
Octave 6 – Tuned Wind
note is very out of tune:      . .  . .  . . .  . .  . .  .
                               c c# d d# e f f# g g# a a# b
Octave 11 – Drum Kit
note drum pattern number:      0 1  2 3  4 5 6  7
                               c c# d d# e f f# g


      0=Bass/Kick, 1=Low Tom, 2=High Tom, 3=Snare, 
      4=Closed Hat, 5=Open Hat, 6=Bass/Kick+ClosedHat, 
      7=Snare+Closed Hat

 

 

 

 

Note Data

Notes are represented with regular music lettering and using the # sign to indicate sharps. The number following the note indicates the length, where 1=whole note, 2=half note, 4=quarter note, 8=eighth note, and 16=sixteenth note. At preset time, other fractional notesthird, fifth, etc.aren't supported.

 

Here's an example of how to play an octave scale with quarter notes.

   c4 c#4 d4 d#4 e4 f4 f#4 g4 g#4 a4 a#4 b4

To play the notes below c, you need to temporarily shift down an octave.

   c4 < e4 g4 > c4

To play rests, just use the letter r as you would a note.

   c4 r4 e4 g4

 

 

 

 

Drum Note Data

An alternate note representation can be used for drum beats. Periods indicate rests, and numbers indicate the drum instruments. The default drum instruments are provided at the key of c11.

  songdata drums
main1
  k=c11
  '6.4.6.4.3.4.6.6.6.6.6'
end

 

 

 

 

playsong

Once you've put together the song and instrument data, you can play the music using the playsong command. When doing so you must supply the initial tempo in BPM.

   playsong songname 120

You can also tell the command to repeat the song indefinitely.

   playsong songname 120 repeat

Or you may tell it to repeat a limited number of times.

   playsong songname 120 4

 

 

 

 

stopsong

If you wish to halt a playing song, you can do so by using the stopsong command.

   stopsong

Back to Top

 

 

 

 

 

RMT Music Tracker

7800basic has a music tracker you can use to automatically play song data, with options to select tempo and number of repetitions.

 

The music tracker requires that you provide instrument data and song data.

 

 

 

Enabling the RMT Music Tracker

To enable RMT support in your game, add the following line near the start of your basic program:

   set trackersupport rmt

You also need to allocate 173 bytes of RAM within your game for the tracker to use.

   dim RMTRAM=$2200 ; to $22AC

 

 

 

 

RMTA and RMT Files

RMT files expect to be loaded into a particular area of memory, and reference addresses in that location directly. Typically that location is $4000, but this can vary depending on the settings the rmt file was exported with. To help you deal with this aspect of rmt files, 7800basic includes two programs7800rmt2asm and 7800rmtfix.

 

 

 

 

7800rmt2asm

The command-line based 7800rmt2asm program will convert an existing rmt file into a relocatable assembly file, which has a file extension of “.rmta” The rmta format is what you want when you wish to store your rmt music any place in rom.

   7800rmt2asm mysong.rmt

 

 

 

 

7800rmtfix

The command-line based 7800rmtfix program will relocate an existing rmt file to a new address. Working with rmt files, instead of rmta files, is only useful if you wish to play the music out of cart ram.

   7800rmtfix mysong.rmt 0x4000

If you wish to use assembly language to “incbin” your rmt data, you should use the “-s” option with 7800rmtfix, to produce a stripped rmt file. (7800Basic normally does this stripping on your behalf, with the incrmtfile command.)

 

 

 

 

incrmtfile

Whether you're using rmta or rmt files, you can use the incrmtfile command to include the song in your game rom.

   incrmtfile mysong.rmt

incrmtfile will create a label from your filename, so you should only use filenames that use characters that are valid for 7800basic labels.

 

If you're dealing with an rmt file, instead of rmta, you'll want to copy it to your cart ram prior to playing it, with the memcpy command.

   memcpy $5000 mysong 3544

 

 

 

 

playrmt

To begin playing your rmta file-based song, you can just call the playrmt command with the name of the rmta file.

   playrmt mysong

To begin playing your rmt file-based song, you can call the playrmt command with the memory location the rmt data has been stored at.

   playrmt $5000

 

 

 

 

stoprmt

You can stop a playing rmt song with the stoprmt command.

   stoprmt

You can use this command even when no song is playing, if you're not sure about the current state of playback.

 

 

 

 

startmt

You can resume previously stopped song with the startrmt command.

   startrmt

 

 

 

 

Miscellaneous RMT Notes

  • The tracker runs once a frame, so you can't play an rmta based song that is stored in an inactive bank.
  • rmt songs can be composed for NTSC or PAL framerates. You can tell 7800basic what the native framerate of your songs are with the “set rmtspeed” command, and it will auto-adjust the playback speed as needed to play at the correct speed.
  • The rmt driver used by 7800basic is version 1.20. It's best to stick to the 1.20 version of the rmt authoring program, to avoid incompatibilities.
  • rmt instruments can be designed to update multiple times per frame. This isn't supported under 7800basic.
  • At this point in time dual-pokey rmt music isn't supported.
  • There are code examples for rmt playback in the 7800basic samples directory.

 

Back to Top

 

 

 

 

 

AtariVox Voice Support

You can send speech data to the AtariVox via the speak command.

   speak speechdataname

See the speechdata command and set avoxvoice on for more information.

Back to Top

 

 

 

 

 

High Score Support

7800basic supports high score tables for up to 4 different difficulty levels in your game. The actual device used to store the tables can be an Atari 7800 High Score Cart, AtariVox, or SaveKey device.

 

To incorporate high score support in your game, you first need to enable high score support. Pick a unique 4 digit hex value to identify your game...

   set hssupport $1234

When your game is nearing completion, you can reserve your chosen number by announcing it in this AtariAge thread: https://atariage.com/forums/topic/128432-high-score-cart-values/

 

You also need to include the high score font graphic in your game. It can go in any graphics block, but must be the first graphic imported in its block. Note that you need to use 320A mode for the high score graphic, even if your game uses a different mode.

   incgraphic hiscorefont.png 320A

Before trying to display a high score table, you need to set the game difficulty level variable from 0 to 3, which represents easy, intermediate, advanced, and expert levels.

   gamedifficulty=2

If your game has no difficulty levels, you can leave gamedifficulty at the default of 0. You can then display the current high score table, without allowing high score entry with the command...

   drawhiscores attract

When a single player game is over, and you them to have the chance to enter their initials, you can use the command...

   drawhiscores single

Or with a two player game, you can use the following command to allow the first player to enter initials...

   drawhiscores player1

And as you might expect, the second player has a similar command...

   drawhiscores player2

The drawhiscores command will erase the currently drawn screen, savescreen buffer, and the color palettes, so you'll need to draw a new screen after issuing this command.

 

It's also noteworthy that drawhiscores command allows the high score display to be interrpted by pressing the joystick fire button. The command may exit with the user holding the fire button down, so you may need to account for that in your basic code.

 

Please be aware that the drawhiscores statement doesn't work with double-buffering turned on. If you're using double-buffering in your game, you'll need to temporarily disable it with “doublebuffer off” prior to calling drawhiscores.

 

If you want the players' scores to be provided a descriptive ranking, you can use the “set hsgameranks” command. Scores should be ordered from biggest to 0...

   set hsgameranks 30000 commander 10000 lieutenant 0 ensign

If the player's score variable didn't beat any recorded scores, the high score routines will just display the table, and the ranking description if you've enabled that functionality in your game.

 

 

If you wish to access the currently saved high scores, you can use the “hiscoreload” command to populate the HSRAMScores array with the stored scores, in high score order. Each score entry is 3 bytes, in 7800basic score variable format.

 

 

If you wish to clear out any saved high scores, you can use the “hiscoreclear” command.

 

If you have AtariVox speechdata named “vox_highscore”, the AtariVox will say the speech once while the player enters a high score.

 

If you have sound effect data named “sfx_highscore”, the sound effect will play once while the player enters a high score.

 

If you have a tracker song named “song_highscore”, the song will play once while the player enters a high score.

 

There are various “set” commands that change the behavior of the high score tables. See the Program Configuration section for more details.

 

Lastly, if you wish to detect which device is being used, you may check the hsdevice variable:

   0=no device, 1=High Score Cart, and 2=AtariVox/SaveKey

Back to Top

 

 

 

 

 

High Score Callback Functions

The default high score table functionality in 7800basic is coded to work only with joystick controls. If you wish to use another controller to enter scores in your game, you can use the high score callbacks to achieve that. These callbacksHSup, HSdown, and HSSelectallow you to map the controller inputs that correspond to moving up or down through the available letters, or to selecting the current letter.

 

Here are some example callbacks that allow high score entry using a SNES pad plugged into the first controller port.

HSup
  hsreturn=0
  if snes0up then hsreturn=1
  return thisbank
  
HSdown
  hsreturn=0
  if snes0down then hsreturn=1
  return thisbank
  
HSselect
  hsreturn=0
  if snes0X || snes0Y then hsreturn=1
  if snes0A || snes0B then hsreturn=1
  return thisbank

Please note that the variable hsreturn must always be set to 0 (no action was detected) or 1 (the action was detected) before returning from a callback. It should also be pointed out that there's no need to debounce controller input in your callback routines.

 

If you wish to allow different players to use different devices for high score input, the value in the temp1 variable indicates which player # (0 or 1) is currently entering the score.

 

In the case of a bank-switched game, the callbacks must reside either in the same bank as the hiscore code, or in the last bank.

Back to Top

 

 

 

 

 

Saving Game Memory

7800basic supports saving and loading up to 25 variables to any detected High Score device. You will need to include high score support in your game, as demonstrated in the previous High Score Support section. If you only wish to save game memory and not display high score tables, you may omit importing the high score font.

 

The data will be saved in an unused difficulty level's area. To inform 7800basic of this, we set the gamedifficulty variable.

   gamedifficulty=3

From there we call the savememory command to save your variables.

   savememory playerx playery playerroom playerworld

If the variables are dim'ed consecutively in memory, you may list them as a range.

   savememory playerx-playerworld

Loading previously saved variables is done with the loadmemory command, which also accepts both forms of variable listing that the savememory command uses.

   loadmemory playerx playery playerroom playerworld

   loadmemory playerx-playerworld

If your game is also displaying high score tables, be sure to restore the gamedifficulty variable to its original value after loading/saving data.

Back to Top

 

 

 

 

 

Data Compression

7800basic allows you to import and compress files containing game data, with the inccompress command.

   inccompress mydatafile.dat

7800basic will automatically create a label from the filename (excluding the file extension) so be sure to use filenames that don't contain characters that are illegal for labels, and to make sure the new label will be unique.

 

To later use the compressed data, you'll need to decompress it into into RAM. For the RAM destination, you can either use an address directly, or a dim'ed variable.

   decompress mydatafile $4000

7800basic uses LZSA1 (m3) compression, which has relatively good speed and compression capabilities. You can see the compressed size and compression ratio for each of your files in the 7800basic compile messages.

 

You can use inccompress directly with RMT files and SAP files containing RMT music tracks. 7800basic will automatically scan for the RMT identifier in the data, and if it's present all data prior to the RMT identifier will be skipped. (See the rmtramcompressiondemo demo in the 7800basic samples directory for an example.)

 

Note 1: Decompression can take some time (sometimes several frames) which means you can't use it during your regular game loop. You should use decompression during some natural break in the action, like between game levels.

 

Note 2: Due to the console having relatively small amounts of ram, it's highly recommended that you only use this feature with a bankswitch format that includes extra ram.

Back to Top

 

 

 

 

 

Feature Modules

7800basic has a lot of options to interface with external hardware, and there isn't enough space in the 7800basic's reserved 4k area to hold all of the feature modules required. If you get a message about this area having negative space during compiling, it means you need to store the modules elsewhere in your game.

 

You can do so with the “inline” keyword at the location where the module can go. At present time you can do this for the atarivox, pokey support, hiscore support, sound tracker, rmt tracker, mega7800 controller, snes2atari controller, plotsprite4, four-bit fade, and LZSA-compression modules.

   inline 7800vox.asm
   inline pokeysound.asm
   inline hiscore.asm
   inline tracker.asm
   inline rmtplayer.asm
   inline mega7800.asm
   inline snes2atari.asm
   inline plotsprite4.asm
   inline fourbitfade.asm
   inline lzsa1compression.asm

Avoid putting these statements directly in the path of your own code flow, since they're not meant to be executed directly.

 

If your game is bankswitched, any inline feature modules need to go in a non-bankswitched bank (a good place for them would be in dmaholes, in the last bank). The one exception to this rule is the hiscore.asm moduleyou may inline this module into a bankswitched bank, as long as you only use the hiscore functionality from the same bank.

Back to Top

 

 

 

 

 

Conditional Compilation and Compiling Message Output

7800basic has a few commands that let you easily enable or disable code blocks. This allows you to build a few different custom ROM images from just a minor change to a constant value in your source code.

 

These commands are #ifconst, #else, and #endif, and can be used in the following fashion.

   const officialrelease = 1
   
   [a bunch of common game code would go here]
   
   #ifconst officialrelease
     plotbanner officialbanner 0 0 0
   #else
     plotbanner demobanner 0 0 0
   #endif

There's also an echo command which you can use to display messages, or the values of constants, when the ROM is compiled.

   echo " "
   const airblockstart = <chars_air
   const airblockend = airblockstart+chars_air_width-1
   echo "TILES: airblockstart:",airblockstart," airblockend:",airblockend
   echo " "

The #ifconst, #else, #endif, and echo commands are all passed directly from your 7800basic source code to the dasm assembler, which is responsible for their function. If you wish to learn more about them, you can reference the documentation for dasm.

 

 

If you wish to know how much rom was used by a routine, you can use the sizeof command at the end of the routine. When you compile your game, the output will contain a message with the size of the routine.

mysubroutine
   dogbark = dogbark + 1
   if dogbark > 10 then gosub chasecat
   return
   sizeof mysubroutine

You can also use sizeof to output the size of some data, by placing sizeof at the end of the data.

   data mydata
     1,2,3,4
     5,6,7,8
end
   sizeof mydata

Back to Top

 

 

 

 

 

Advanced Spritework

 

plotsprite4

The 7800 console displays sprite objects and character objects by adding them to in-RAM structures called Display Lists. (DLs for short). Those sprite objects can either be 4 or 5 bytes long each. With 5 byte sprites, the extra byte is used to set the sprite's graphics mode. Since 4 byte sprites lack a graphics mode value, the graphics mode used for the sprite is inherited from the last seen 5 byte sprite.

 

Due to most games featuring sprites that can move around dynamically, 7800basic normally uses 5 byte sprites and explicitly sets the mode each time. If you wish to use 4 byte sprites, you can just substitute the plotsprite4 command for the normal plotsprite command.

   plotsprite4 gorillabot 0 x y

There are three benefits to using plotsprite4 over plotsprite. First, the plotsprite4 command uses somewhat fewer CPU cycles than plotsprite. Second, Maria will be able to display more 4 byte sprites than equivalent 5 byte sprites, before it runs out of screen rendering time. Third, 4 byte sprites use less display list memory, which is another factor that can limit how many sprites are on-screen.

 

There are two drawbacks to using plotsprite4 over plotsprite. First, you need to be careful about sprites in the wrong graphics mode changing the mode for your plotsprite4 sprites. Second, plotsprite4 is limited to a maximum sprite width of 31 bytes.

 

 

 

 

PLOTSPRITE and PLOTSPRITE4

The plotsprite and plotsprite4 commands in 7800basic work by preparing some arguments and then calling a subroutine to do the real work. If you're trying to put a lot of sprites on the screen in a loop (e.g. to draw a bunch of enemies) you can skip that overhead by using the alternative PLOTSPRITE and PLOTSPRITE4 commands. These commands will embed a plotsprite routine directly where you call them, hard-coded to the sprite in question.

   for t = 0 to 12
     x = enemyx[t]
     y = enemyy[t]
     PLOTSPRITE4 gorillabot 0 x y
   next

It should be noted that the PLOTSPRITE and PLOTSPRITE4 commands have some implementation quirks that differ from the regular plotsprite and plotsprite4 commands.

  • The PLOTSPRITE and PLOTSPRITE4 commands don't work with tallsprites.
  • If you use a variable for the palette argument, the variable value must be 32 times the actual palette index you want.
  • The width of each sprite cannot exceed 16 bytes.

Back to Top

 

 

 

 

 

Assembly Language

7800basic allows you to incorporate your own assembly language routines into your BASIC code in a few different ways.

 

 

 

inline assembly

The first is to just use the asm command, followed by assembly language, finally ending with the end keyword.

   drawscreen
   asm
   lda PlayerX
   lsr
   lsr
   lsr
   sta PlayerCharX
end

 

 

 

 

Including External Assembly

The second method, the include command, allows you to keep the assembly language in a separate file. The assembly code will be imported to an area outside your BASIC code, and you'll be expected to call a label in the assembly with either a function or gosub call.

   include killallhumans.asm

The include command must typically precede all other commands (at the beginning of your program, before anything else). At this time there is no checking to ensure that you do this. Particularly, if you use an includes file or a different kernel, you need to specify all of your include commands first or they will be ignored.

 

 

 

 

Inlining External Assembly

The inline command is like the include command, except 7800 import the assembly code directly into the program where the inline command is.

   inline savehumanity.asm

 

 

 

 

Including Binary Data

You can use the incbin command to include a binary data file into your game.

mybin
   incbin killallhumans.asm

It's important that you don't allow your program code to flow into the location with the incbin statement. Unlike the 7800basic data statement, there isn't built-in code to skip over incbin data.

 

To access the binary data with memcpy, you need to add a “.” dot to the beginning of the label before your data.

   memcpy $4000 .mybin 2048

Back to Top

 

 

 

 

 

Installing 7800basic

7800basic is distributed as a single zip file. Download the latest zip file and unzip to whichever location you desire to use. Make sure your unzip utility creates the expected subdirectories (/docs, /includes, …) rather than sticking all of the files into one directory.

 

Windows users should double-click and the provided install_win.bat file. OS X and Linux users should run the install_ux.sh script.

 

In both cases, just follow any instructions presented by the installer.

Back to Top

 

 

 

 

 

Compiling Your 7800basic Code

7800basic is a command-line program, so these instructions will cover how to compile your BASIC programs using the command-line. If you're uncomfortable with BASIC command-line usage for your OS, you may wish to read up on it a bit first.

 

 

 

On Windows

Assuming you've completed the 7800basic installations in the previous section, you can compile your program under Windows with the following steps…

  1. Click on Start->Search or Start->Run and type: CMD, followed by [ENTER].
  2. Type: cd \my\project\directory (substitute the directory that contains your BASIC source).
  3. Type: 7800bas.bat myprogram.bas (substitute the filename containing your BASIC source code).

 

Information about the compiling process will be displayed in your CMD window. With some luck, you should have some new compiled files.

 

 

 

 

On OS X or Linux

Assuming you've completed the 7800basic installations in the previous section, you can compile your program under OS X or Linux with the following steps…

  1. Open a terminal or console window.
  2. Type: cd /my/project/directory (substitute the directory that contains your BASIC source code).
  3. Type: 7800basic.sh myprogram.bas (substitute the filename containing your BASIC source code).

 

Information about the compiling process will be displayed in your terminal window. With some luck, you should have some new compiled files.

 

 

 

 

Files Produced by Compilation

myprogram.bas.bin

This is a ROM file for your game, typically used for creating cartridges.

 

myprogram.bas.a78

This is another ROM file for your game, typically used for emulation. This format file has a special header, to let emulators know which features are needed for the ROM, like controllers, bankswitching format, etc.

 

myprogram.bas.list.txt

This holds the detailed assembly listing of your game. This file can be potentially useful in hunting down syntax errors and similar bugs.

 

other temporary files

There are other temporary files are created by the compilation process, but these aren't particularly useful to the 7800basic coder.

Back to Top

 

 

 

 

 

Backing Up Your 7800basic Game

7800basic has built-in commands to make it convenient to backup your game's source code and resource files each time you compile it.

 

The backup files that 7800basic produces are in “tar” archive format, which can be opened/extracted by many different programs on Windows (7-zip, WinZip, …), MacOS (Finder, tar, etc), and Linux. (tar, various).

 

 

 

set backupstyle [single|running]

This set command determines if 7800basic will overwrite the same backup file always (single) or produce new backup files each time (running). The default mode is “running.”

   set backupstyle single

You need to use the “set backupstyle” setting prior to using “set backupfile,” since it affects the file name of the backup file.

 

 

 

 

set backupfile ‘/location/of/backup’

This set command determines where 7800basic will store the backup file. If your file path has spaces or non-alphanumeric characters, you need to use single quotes around the path.

 

When using 7800basic on Windows, you can use regular Windows paths with drive letters…

   set backupfile ‘E:\backups\spaceman’

Or If you're on MacOS or Linux, you can use Unix style paths…

   set backupfile ‘/Volumes/MyThumbdrive/backups/spaceman’

If you've set the backupfile location, and the backupfile itself can't be written to, or one of you referenced files can't be backed up, the 7800basic build process will fail with an error. This is to bring the backup failure to your full attention, and in a pinch it can be overridden by commenting out your “set backupfile” command. Just don't forget to fix the underlying issue when possible and re-enable your backups.

 

It's important that backupfile is referencing a location that isn't your main OS disk, like a USB drive, network storage, or cloud storage. If you put the backups on the same disk that your game project is located on, your backups will be unreachable if that disk fails.

 

The further away the backup device is from your computer the bettera USB drive will save your project from an OS disk failure, but it may not help in the case of natural disaster or theft. But if your choice is using a USB drive or nothing, then choose to use a USB drive. The most common cause of data loss, by far, is disk failure. Small profile USB drives are inexpensive and inobtrusive, and will save you some heartache if your disk does fail.

 

 

 

 

backup ‘asm/myassembly.asm’

For various technical reasons, 7800basic can't automatically backup assembly files you've included into your basic source code. If you wish to back assembly files, documentation files, or anything else critical to your work, just add the backup command to your source code, with the name of the file you want to backup.

   backup ‘docs/README.TXT’

If your file path has spaces or non-alphanumeric characters, you need to use single quotes around the path.

Back to Top

 

 

 

 

 

Troubleshooting Issues With Your 7800basic Code

Here are some issues that you may encounter while using 7800basic, and what their underlying cause may be.

 

 

 

 

 

 

 

 

 

 

 

 

Index

Back to Top

 

 

In Case You Didn't Know

 

Trump's Jab = Bad

Did you know that Trump's rushed Operation Warp Speed rona jab has less than one percent overall benefit? Some people call it the depopulation jab and it has many possible horrible side effects (depending on the lot number, concentration, and if it was kept cold). Remember when many Democrats were against Trump's Operation Warp Speed depopulation jab, then they quickly changed their minds when Biden flip-flopped and started pushing it?

 

Some brainwashed rona jab cultists claim that there are no victims of the jab, but person after person will post what the jab did to them, a friend, or a family member on web sites such as Facebook and they'll be lucky if they don't get banned soon after. Posting the truth is “misinformation” don't you know. Awakened sheep might turn into lions, so powerful people will do just about anything to keep the sheep from waking up.

 

Check out these videos:

If You Got the COVID Shot and Aren't Injured, This May Be Why

Thought Experiment: What Happens After the Jab?

The Truth About Polio and Vaccines

What Is Causing the Mysterious Self-Assembling Non-Organic Clots and Sudden Deaths?

Full Video of Tennessee House of Representatives Health Subcommittee Hearing Room 2 (The Doctors Start Talking at 33:28)

 

 

H Word and I Word = Good

Take a look at my page about the famous demonized medicines called The H Word and Beyond. You might also want to look at my page called Zinc and Quercetin. My sister and I have been taking zinc and quercetin since the summer of 2020 in the hopes that they would scare away the flu and other viruses (or at least make them less severe). Here's one more page to check out: My Sister's Experiences With COVID-19.

 

 

B Vitamins = Good

Some people appear to have a mental illness because they have a vitamin B deficiency. For example, the wife of a guy I used to chat with online had severe mood swings which seemed to be caused by food allergies or intolerances. She would became irrational, obnoxious, throw tantrums, and generally act like she had a mental illness. The horrid behavior stopped after she started taking a vitamin B complex. I've been taking Jarrow B-Right (#ad) for many years. It makes me much easier to live with. I wonder how many people with schizophrenia and other mental mental illnesses could be helped by taking a B complex once or twice a day with meals (depending on their weight)?

 

 

Soy = Bad

Unfermented soy is bad!When she stopped eating soy, the mental problems went away.” Fermented soy doesn't bother me, but the various versions of unfermented soy (soy flour, soybean oil, and so on) that are used in all kinds of products these days causes a negative mental health reaction in me that a vitamin B complex can't tame. The sinister encroachment of soy has made the careful reading of ingredients a necessity.

 

I started taking AyaLife (99% Pure CBD oil) as needed in April of 2020. So far it's the only thing that helps my mood when I've mistakenly eaten something that contains soy. AyaLife is THC-free (non-psychoactive) and is made in the USA. I also put a couple dropper fulls under my tongue before leaving the house or if I just need to calm down.

 

It's supposedly common knowledge that constantly angry Antifa-types basically live on soy products. What would happen if they stopped eating and drinking soy sludge and also took a B complex every day? Would a significant number of them become less angry? Would AyaLife CBD oil also help?

 

 

Wheat = Bad

If you are overweight, have type II diabetes, or are worried about the condition of your heart, check out the videos by Ken D Berry, William Davis, and Ivor Cummins. It seems that most people should avoid wheat, not just those who have a wheat allergy or celiac disease. Check out these books: Undoctored (#ad), Wheat Belly (#ad), and Eat Rich, Live Long (#ad).

 

 

Negative Ions = Good

Negative ions are good for us. You might want to avoid positive ion generators and ozone generators. A plain old air cleaner is better than nothing, but one that produces negative ions makes the air in a room fresher and easier for me to breathe. It also helps to brighten my mood.

 

 

Litterbugs = Bad

Never litter. Toss it in the trash or take it home. Do not throw it on the ground. Also remember that good people clean up after themselves at home, out in public, at a campsite and so on. Leave it better than you found it.

 

 

Climate Change Cash Grab = Bad

Seems like more people than ever finally care about water, land, and air pollution, but the climate change cash grab scam is designed to put more of your money into the bank accounts of greedy politicians. Those power-hungry schemers try to trick us with bad data and lies about overpopulation while pretending to be caring do-gooders. Trying to eliminate pollution is a good thing, but the carbon footprint of the average law-abiding human right now is actually making the planet greener instead of killing it.

 

Eliminating farms and ranches, eating bugs, getting locked down in 15-minute cities, owning nothing, using digital currency (with expiration dates) that is tied to your social credit score, and paying higher taxes will not make things better and “save the Earth.” All that stuff is part of an agenda that has nothing to do with making the world a better place for the average person. It's all about control, depopulation, and making things better for the ultra-rich. They just want enough peasants left alive to keep things running smoothly.

 

Watch these two videos for more information:

CO2 is Greening The Earth

The Climate Agenda

 

 

How to Wake Up Normies

Charlie Robinson had some good advice about waking up normies (see the link to the video below). He said instead of verbally unloading or being nasty or acting like a bully, ask the person a question. Being nice and asking a question will help the person actually think about the subject.

 

Interesting videos:

Charlie Robinson Talks About the Best Way to Wake Up Normies

Georgia Guidestones Explained

The Men Who Own Everything

Disclaimer

View this page and any external web sites at your own risk. I am not responsible for any possible spiritual, emotional, physical, financial or any other damage to you, your friends, family, ancestors, or descendants in the past, present, or future, living or dead, in this dimension or any other.

 

Use any example programs at your own risk. I am not responsible if they blow up your computer or melt your Atari 7800.

 

Home Inventions Quotations Game Design Atari Memories Personal Pages About Site Map Contact Privacy Policy Tip Jar