Skool macros — SkoolKit 9.6 documentation (original) (raw)

Skool files and ref files may contain skool macros that are ‘expanded’ to an appropriate piece of HTML markup (when rendering in HTML mode), or to an appropriate piece of plain text (when rendering in ASM mode).

Syntax

Skool macros have the following general form:

#MACROri1,ri2,...,oi1,oi2,...

where:

If an optional parameter is left blank or omitted entirely, it assumes its default value. So, for example:

is equivalent to:

and:

is equivalent to:

Numeric parameters

Numeric parameters may be written in decimal notation:

or in hexadecimal notation (prefixed by $):

Wherever a sequence of numeric parameters appears in a macro, that sequence may optionally be enclosed in parentheses: ( and ). Parentheses are generally recommended - especially when there are two or more parameters - in order to unambiguously separate the numeric parameters from any content that follows them. Parentheses are required if any numeric parameter is written as an expression containing arithmetic operations, skool macros or replacement fields:

#UDG(51672+{offset},#PEEK51672)

The following operators are permitted in an arithmetic expression:

Parentheses and spaces are also permitted in an arithmetic expression:

#IF(1 == 2 || (1 <= 2 && 2 < 3))(Yes,No)

String parameters

Where a macro requires a single string parameter consisting of arbitrary text, it must be enclosed in parentheses, square brackets or braces:

If text contains unbalanced brackets, a non-whitespace character that is not present in text may be used as an alternative delimiter. For example:

Where a macro requires multiple string parameters consisting of arbitrary text, they must be enclosed in parentheses, square brackets or braces and be separated by commas:

(string1,string2) [string1,string2] {string1,string2}

When a comma-separated sequence of string parameters is split, any commas that appear between parentheses are retained. For example, the string parameters of the outer #FOR macro in:

#FOR0,1(n,#FOR(0,1)(m,(n,m),;),;)

are split into n, #FOR(0,1)(m,(n,m),;) and ;, and the string parameters of the inner #FOR macro are split into m, (n,m), and;.

Alternatively, an arbitrary delimiter - d, which cannot be whitespace - and separator - s, which can be whitespace - may be used. (They can be the same character.) The string parameters must open with ds, be separated by s, and close with sd. For example:

//same/delimiter/and/separator// | different delimiter and separator |

Note that if an alternative delimiter or separator is used, it must not be ‘&’, ‘<’ or ‘>’.

Changed in version 6.4: When a comma-separated sequence of string parameters is split, any commas that appear between parentheses are retained.

Replacement fields

The following replacement fields are available for use in the integer parameters of the @if directive and every skool macro (including macros defined by #DEF), and also in the string parameters of some macros:

Replacement fields for the variables defined by the #LET macro are also available. Note that the #LET macro can change the values of the asm,base, case, fix and html fields, but their original values are always available in the mode dictionary.

For example:

#IF({mode[case]}==1)(hl,HL)

expands to hl if in lower case mode, or HL otherwise.

Note that if a replacement field is used, the parameter string must be enclosed in parentheses.

Changed in version 9.4: Added the cfg dictionary.

Changed in version 8.7: Added the sim dictionary.

Changed in version 8.2: Added the mode dictionary.

Changed in version 6.4: The asm replacement field indicates the exact ASM mode; added thefix and vars replacement fields.

Configuration parameters

The cfg dictionary contains skool macro configuration parameters. Recognised parameter names are:

To set the value of a configuration parameter, use the #LET macro with the following special syntax:

For example, to set the poke parameter to use hexadecimal values:

#LET(cfg[poke]=POKE addr:04X,{addr:04X},addr:04X,{byte:02X})

Parameter values may also contain skool macros:

#LET(cfg[pokes]=#FOR({start},{end})//a/POKE a,{byte}/: //)

This would make the POKEname special variable emit a sequence of POKE statements separated by colons instead of a FOR loop.

SMPL macros

The macros described in this section constitute the Skool Macro Programming Language (SMPL). They can be used to programmatically specify values in the parameter string of any macro.

#()

The #() macro expands the skool macros in its sole string parameter.

It takes effect only when it immediately follows the opening token of another skool macro, and is expanded before that macro. For example:

#UDGARRAY#(2(#FOR37159,37168,9||n|(n+1),#PEEKn|;||))(item)

This instance of the #() macro expands the #FOR macro first, giving:

2((37159+1),#PEEK37159;(37168+1),#PEEK37168)

It then expands the #PEEK macros, ultimately forming the parameters of the#UDGARRAY macro.

See String parameters for details on alternative ways to supply thetext parameter. Note that if an alternative delimiter is used, it must not be an alphanumeric character (A-Z, a-z, 0-9).

#DEF

The #DEF macro defines a new skool macro.

#DEFflags]] body)

flags is the sum of the following values, chosen according to the desired outcome:

For example:

#DEF(#MIN(a,b) #IF($a<$b)($a,$b))

This defines a #MIN macro that accepts two integer arguments and expands to the value of the smaller argument.

Default values for the defined macro’s optional integer parameters can be specified in the macro’s signature. For example:

#DEF(#PROD(a,b=1,c=1) #EVAL($a*$b*$c))

This defines a #PROD macro that accepts one, two or three integer arguments, the second and third of which default to 1, and expands to the product of all three arguments.

Default values for the defined macro’s optional string parameters can also be specified in the macro’s signature, and their default values may refer to the integer argument values. For example:

This defines a #NUM macro that accepts one integer argument and an optional string argument. It expands either to the integer argument, or to the string argument if provided. So #NUM15 expands to ‘15’, and #NUM15($0F)expands to ‘$0F’.

If flags is odd (bit 0 set), replacement fields are used instead of $-placeholders to represent the defined macro’s argument values. The main advantage of using replacement fields is that Python string formatting options can be used on the argument values. For example:

This defines a #HEX macro that formats its sole integer argument as a 4-digit upper case hexadecimal number.

However, when using replacement fields, care must be taken to escape any field that doesn’t represent an argument value. For example:

#LET(count=0) #DEF1(#ADD(amount) #LET(count={{count}}+{amount}))

This defines a variable named count, and an #ADD macro that increases its value by a given amount. Note how the replacement field for the countvariable in the body of the macro definition is escaped: {{count}}.

If bit 1 of flags is set, the defined macro will be expanded, in isolation from any surrounding content, as soon as it is encountered. For that to work, the macro definition must be entirely self-contained, i.e. it must not depend on any surrounding content in order to be syntactically correct. For example, if the #IFZERO macro is defined thus:

#DEF2(#IFZERO(n) #IF($n==0))

then any attempt to expand an #IFZERO macro will lead to an error message about the #IF macro having no output strings. To fix this, either reset bit 1 of flags, or redefine #IFZERO with the output strings included in the definition:

#DEF2(#IFZERO(n)(a,b) #IF($n==0)($a,$b))

For more examples, see Defining macros with #DEF.

Note that if a string parameter of a defined macro is optional, that argument will take its default value only if it is omitted; if instead it is left blank, it takes the value of the empty string.

In general, the string arguments of a defined macro may be supplied between alternative delimiters (see String parameters) if desired. However, if every string parameter of the defined macro is optional, the string arguments must be either omitted entirely or provided between parentheses (and therefore separated by commas). This allows a macro with all of its optional string arguments omitted to be immediately followed by some character other than an opening parenthesis without that character being interpreted as an alternative delimiter.

To define a macro that will be available for use immediately anywhere in the skool file or ref files, consider using the @expand directive, or theExpand parameter in the [Config] section.

The flags parameter of the #DEF macro may containreplacement fields.

The integer parameters of a macro defined by #DEF may containreplacement fields, and may also be supplied via keyword arguments.

Version Changes
8.6 Added the flags parameter, the ability to use replacement fields to represent the defined macro’s argument values, and the ability to strip whitespace from the defined macro’s output
8.5 New

#EVAL

The #EVAL macro expands to the value of an arithmetic expression.

For example:

; The following mask byte is #EVAL(#PEEK29435,2,8). 29435 DEFB 62

This instance of the #EVAL macro expands to ‘00111110’ (62 in binary).

The parameter string of the #EVAL macro may containreplacement fields.

Version Changes
8.0 Added support for replacement fields in the parameter string
6.0 Hexadecimal values are rendered in lower case when the--lower option is used
5.1 New

#FOR

The #FOR macro expands to a sequence of strings based on a range of integers.

#FORstart,stop,step,flags

flags is the sum of the following values, chosen according to the desired outcome:

For example:

; The next three bytes (#FOR31734,31736,,1(n,#PEEKn, , and )) define the ; item locations. 31734 DEFB 24,17,156

This instance of the #FOR macro expands to ‘24, 17 and 156’.

The integer parameters of the #FOR macro (start, stop, step,flags) may contain replacement fields.

See String parameters for details on alternative ways to supply thevar, string, sep and fsep parameters.

Version Changes
8.7 Added the flags parameter
8.2 Added support for replacement fields in the integer parameters
5.1 New

#FOREACH

The #FOREACH macro expands to a sequence of output strings based on a sequence of input strings.

#FOREACH([s1,s2,...])(var,string[,sep,fsep])

or:

#FOREACH(svar)(var,string[,sep,fsep])

For example:

; The next three bytes (#FOREACH(31734,31735,31736)||n|#PEEKn|, | and ||) ; define the item locations. 31734 DEFB 24,17,156

This instance of the #FOREACH macro expands to ‘24, 17 and 156’.

The #FOREACH macro recognises certain special variables, each one of which expands to a specific sequence of strings. The special variables are:

For example:

; The messages can be found at #FOREACH(ENTRYt)||n|n|, | and ||.

This instance of the #FOREACH macro expands to a list of the addresses of the entries of type t (text).

The format of an item produced by POKEname depends on the values of thelength and step parameters of the corresponding #POKES macro. For example:

The format of these items can be changed by setting the poke, pokesand pokes-step configuration parameters.

To specify a subset of the POKEs in a list, use either an index parameter, or start and stop parameters separated by a colon, enclosed in square brackets and appended to name. As with Python sequences, these parameters are 0-based, and the start and stop parameters are optional, so:

See String parameters for details on alternative ways to supply thes1,s2,... and var,string[,sep,fsep] parameter strings.

Version Changes
9.4 Added support for the POKEname special variable
5.1 New

#FORMAT

The #FORMAT macro performs a Python-style string formatting operation on its string argument.

For example:

This instance of the #FORMAT macro formats the value of the countvariable (assuming it has already been defined by the #LET macro) as a 4-digit upper case hexadecimal number prefixed by ‘0x’.

Note that if text could be read as an integer parameter, case should be explicitly specified in order to prevent text from being interpreted as thecase parameter. For example:

Alternatively, the #EVAL macro may be a better option for formatting a pure numeric value.

The parameters of the #FORMAT macro may containreplacement fields.

See String parameters for details on alternative ways to supply thetext parameter.

Version Changes
8.5 Added the case parameter
8.2 New

#IF

The #IF macro expands to an arbitrary string based on the truth value of an arithmetic expression.

For example:

; #FOR0,7(n,#IF(#PEEK47134 & 2**(7-n))(X,O)) 47134 DEFB 170

This instance of the #IF macro is used (in combination with a #FORmacro and a #PEEK macro) to display the contents of the address 47134 in the memory snapshot in binary format with ‘X’ for one and ‘O’ for zero: XOXOXOXO.

See String parameters for details on alternative ways to supply thetrue and false output strings.

Version Changes
6.0 Added support for replacement fields in the expr parameter
5.1 New

#LET

The #LET macro defines an integer, string or dictionary variable.

The syntax for defining an integer or string variable is:

If name ends with a dollar sign ($), value is interpreted as a string. Otherwise value is evaluated as an arithmetic expression.

For example:

#LET(count=22) #LET(count$=22)

These #LET macros assign the integer value ‘4’ to the variable count and the string value ‘2*2’ to the variable count$. The variables are then accessible to other macros via the replacement fields {count} and{count$}.

The syntax for defining a dictionary variable is:

#LET(name[]=(default[,k1[:v1],k2[:v2]...]))

The keys in a dictionary are integers, and the associated values are strings ifname ends with a dollar sign, or integers otherwise. If the value part of a key-value pair is omitted, it defaults to the key.

For example:

#LET(n[]=(0,1:10,2:20)) #LET(d$[]=(?,1:a,2:b))

The first #LET macro defines the dictionary variable n with default integer value 0, and keys ‘1’ and ‘2’ mapping to the integer values 10 and 20. The values in this dictionary are accessible to other macros via the replacement fields {n[1]} and {n[2]}.

The second #LET macro defines the dictionary variable d$ with default string value ‘?’, and keys ‘1’ and ‘2’ mapping to the string values ‘a’ and ‘b’. The values in this dictionary are accessible to other macros via the replacement fields {d$[1]} and {d$[2]}.

An individual key-value pair in a dictionary can be set by using the following syntax:

Here key is the integer key, which may be expressed using skool macros and replacement fields.

The #LET macro may also be used to set skool macroconfiguration parameter values.

To define a variable that will be available for use immediately anywhere in the skool file or ref files, consider using the @expand directive.

See String parameters for details on alternative ways to supply the entire name=value parameter string, or the part after the equals sign when defining a dictionary variable.

Version Changes
9.4 Added the ability to set individual key-value pairs in dictionary variables
8.6 Added the ability to define dictionary variables
8.2 New

#MAP

The #MAP macro expands to a value from a map of key-value pairs whose keys are integers.

#MAPkey(default[,k1:v1,k2:v2...])

For example:

; The next three bytes specify the directions that are available from here: ; #FOR56112,56114,,1(q,#MAP(#PEEKq)(?,0:left,1:right,2:up,3:down), , and ). 56112 DEFB 0,1,3

This instance of the #MAP macro is used (in combination with a #FORmacro and a #PEEK macro) to display a list of directions available based on the contents of addresses 56112-56114: ‘left, right and down’.

Note that the keys (k1, k2 etc.) may be expressed using arithmetic operations. They may also be expressed using skool macros, but in that case the_entire_ parameter string of the #MAP macro must be enclosed by a#() macro.

See String parameters for details on alternative ways to supply the default output string and the key-value pairs.

Version Changes
6.0 Added support for replacement fields in the key parameter
5.1 New

#PC

The #PC macro expands to the address of the closest instruction in the current entry.

For example:

c32768 XOR A ; This instruction is at #PC.

This instance of the #PC macro expands to ‘32768’.

In an entry header (i.e. title, description, register description or start comment), the #PC macro expands to the address of the first instruction in the entry. In a mid-block comment, the #PC macro expands to the address of the following instruction. In an instruction-level comment, the #PC macro expands to the address of the instruction. In a block end comment, the #PCmacro expands to the address of the last instruction in the entry.

Version Changes
8.0 New

#PEEK

The #PEEK macro expands to the contents of an address in the internal memory snapshot constructed from the contents of the skool file.

For example:

; At the start of the game, the number of lives remaining is #PEEK33879.

This instance of the #PEEK macro expands to the contents of the address 33879 in the internal memory snapshot.

See also #POKES.

Version Changes
8.2 Added support for replacement fields in the addr parameter
5.1 New

#STR

The #STR macro expands to the text string at a given address in the memory snapshot.

#STRaddr[,flags,length][(end)]

flags is the sum of the following values, chosen according to the desired outcome:

When bit 3 of flags is set, end is evaluated for each byte encountered, and if the result is true, the string is terminated. end may contain the placeholder $b for the current byte value.

For example:

; The messages here are '#STR47154', '#STR47158' and '#STR47161,8($b==255)'. 47154 DEFM "One",0 47158 DEFM "Tw","o"+128 47161 DEFM "Three",255

These instances of the #STR macro expand to ‘One’, ‘Two’ and ‘Three’.

The parameters of the #STR macro may containreplacement fields.

Version Changes
8.6 New

#WHILE

The #WHILE macro repeatedly expands macros while a conditional expression is true.

For example:

#LET(a=3) #WHILE({a}>0)( #EVAL({a}) #LET(a={a}-1) )

This instance of the #WHILE macro expands to ‘321’.

The expr parameter of the #WHILE macro may containreplacement fields.

See String parameters for details on alternative ways to supply thebody parameter.

Version Changes
8.6 New

General macros

#AUDIO

In HTML mode, the #AUDIO macro expands to an HTML5 <audio> element.

#AUDIOflags,offset[(delays)]

Or, when executing code in a simulator (bit 2 of flags set):

#AUDIOflags,offset(start,stop[,execint,cmio])

flags is the sum of the following values, chosen according to the desired outcome:

If execint is set to 1, make sure that bit 1 of flags is 0, otherwise interrupt delays may be applied twice: once during execution of the code, and again in post-processing. Similarly, if cmio is set to 1, make sure that bit 0 of flags is 0, otherwise memory and I/O contention delays may be applied twice.

If fname starts with a ‘/’, the filename is taken to be relative to the root of the HTML disassembly. Otherwise the filename is taken to be relative to the audio directory (as defined by the AudioPath parameter in the[Paths] section).

If delays is specified and fname ends with ‘.wav’, a corresponding audio file in WAV format is created. Each element in delays can be an integer, a list or tuple of integers, or a list/tuple of lists/tuples of integers etc. nested to arbitrary depth, expressed as Python literals. For example:

1000, [1500]*100, [(800, 1200)*2, 900]*200

This would be flattened into a list of integers, as follows:

The sum of this list of integers being 1131000, this would result in an audio file of duration 1131000 / 3500000 = 0.323s (assuming that no memory contention is simulated and interrupts are disabled, i.e. bits 0 and 1 of flags are reset).

The characters allowed in the delays parameter are ‘ ‘ (space), newline, the digits 0-9, and any of ,*+-%()[].

An alternative to supplying the delay values manually is to execute the code that produces the sound effect in a simulator, and let the simulator compute the delays. This can be done by setting bit 2 of flags and specifying the code to execute via the start and stop address parameters. For example:

; #AUDIO4(beep.wav)(32768,32782) c32768 LD L,0 *32771 OUT (254),A 32773 XOR 16 32775 LD B,200 32777 DJNZ 32777 32779 DEC L 32780 JR NZ,32771 32782 RET

Before executing code in a simulator, the #AUDIO macro copies the simulator state as it was left by the most recent invocation of either the #AUDIO or the #SIM macro (if any).

Note that code executed by the #AUDIO macro operates directly on the internal memory snapshot, and therefore can modify it. To avoid that, use the#PUSHS and #POPS macros to operate on a copy of the snapshot.

If delays or start and stop parameters are specified, but fnamedoes not end with ‘.wav’, no audio file is written. This enables the parameters to be kept in place as a reminder of how an original WAV file was created by the #AUDIO macro before it was converted to another format.

If neither delays nor start and stop parameters are specified, orfname does not end with ‘.wav’, the named audio file must already exist in the specified location, otherwise the <audio> element controls will not work. To make sure that a pre-built audio file is copied into the desired location when skool2html.py is run, it can be declared in the[Resources] section.

By default, if fname ends with ‘.wav’, but a ‘.flac’, ‘.mp3’ or ‘.ogg’ file with the same basename already exists, that file is used and no WAV file is written. This enables an original WAV file to be replaced by an alternative (compressed) version without having to modify the fname parameter of the#AUDIO macro. The alternative audio file types that the #AUDIO macro looks for before writing a WAV file are specified by the AudioFormatsparameter in the [Game] section.

The integer parameters (i.e. all except fname and delays) of the#AUDIO macro may contain replacement fields.

The audio template is used to format the <audio> element.

Audio file creation can be configured via the [AudioWriter] section.

Version Changes
9.1 Added the cmio and execint parameters; added support for executing code in a 128K memory snapshot
9.0 Added support for passing delays through a moving average filter
8.7 New

#BANK

The #BANK macro switches the RAM bank that is mapped to 49152-65535 (0xC000-0xFFFF) in the memory snapshot:

For example:

; This is the UDG at 50000 in RAM bank 6: #BANK6 #UDG50000(udg)

This instance of the #BANK macro maps RAM bank 6 to 49152-65535 in preparation for creating an image of the UDG at 50000 in that RAM bank.

If the memory snapshot hasn’t already been converted from 48K to 128K by a@bank directive, it will be converted when the first #BANK macro in the skool file is expanded.

Version Changes
9.1 New

#CALL

The #CALL macro expands to the return value of either a method on theHtmlWriter or AsmWriter object currently in use, or an arbitrary function.

#CALL(method(args)) #CALL([/path/to/moduledir:]module.func(args))

In each form of the macro, args is a comma-separated list of arguments to pass to the method or function. The list may containreplacement fields. Each argument can be expressed either as a plain value (e.g. 32768) or as a keyword argument (e.g.address=32768).

For example:

; The word at address 32768 is #CALL(word(32768)).

This instance of the #CALL macro expands to the return value of the wordmethod (on the HtmlWriter or AsmWriter subclass being used) when called with the argument 32768.

For information on writing methods or functions that may be called by a#CALL macro, see the documentation onextending SkoolKit.

Note

The #CALL:method(args) syntax is deprecated since version 9.5.

Version Changes
9.5 Added support for calling an arbitrary function
8.3 Added support for replacement fields in the args parameter
8.1 Added support for keyword arguments
5.1 Added support for arithmetic expressions and skool macros in theargs parameter
3.1 Added support for ASM mode
2.1 New

#CHR

In HTML mode, the #CHR macro expands either to a numeric character reference, or to a unicode character in the UTF-8 encoding. In ASM mode, it always expands to a unicode character in the UTF-8 encoding.

flags is the sum of the following values, chosen according to the desired outcome:

For example:

26751 DEFB 127 ; This is the copyright symbol: #CHR169 26572 DEFB 127 ; This is also the copyright symbol: #CHR127,2

In HTML mode, these instances of the #CHR macro expand to ‘©’. In ASM mode, they both expand to ‘©’.

The parameter string of the #CHR macro may containreplacement fields.

Version Changes
8.6 Added the flags parameter, the ability to use UTF-8 encoding in HTML mode, and support for mapping character codes 94, 96 and 127 to ‘↑’, ‘£’ and ‘©’
8.3 Added support for replacement fields in the parameter string
5.1 Added support for arithmetic expressions and skool macros in the parameter string
3.1 New

#D

The #D macro expands to the title of an entry (a routine or data block) in the memory map.

For example:

; Now we make an indirect jump to one of the following routines: ; . ; #TABLE(default,centre) ; { =h Address | =h Description } ; { #R27126 | #D27126 }

This instance of the #D macro expands to the title of the routine at 27126.

Version Changes
8.3 Added support for replacement fields in the addr parameter
5.1 Added support for arithmetic expressions and skool macros in theaddr parameter

#HTML

The #HTML macro expands to arbitrary text (in HTML mode) or to an empty string (in ASM mode).

The #HTML macro may be used to render HTML (which would otherwise be escaped) from a skool file. For example:

; #HTML(For more information, go here.)

text may contain other skool macros, which will be expanded before rendering. For example:

; #HTML[The UDG defined here (32768) looks like this: #UDG32768,4,1]

See String parameters for details on alternative ways to supply thetext parameter. Note that if an alternative delimiter is used, it must not be an upper case letter.

See also #UDGTABLE.

Version Changes
3.1.2 New

#INCLUDE

In HTML mode, the #INCLUDE macro expands to the contents of one or more ref file sections. In ASM mode, it expands to an empty string.

#INCLUDEparagraphs

The #INCLUDE macro can be used to insert the contents of one ref file section into another. For example:

[MemoryMap:RoutinesMap] Intro=#INCLUDE(RoutinesMapIntro)

[RoutinesMapIntro] This is the intro to the 'Routines' map page.

If pattern identifies multiple ref file sections, they are concatenated in the order in which they appear in the ref file.

The paragraphs parameter of the #INCLUDE macro may containreplacement fields.

See String parameters for details on alternative ways to supply thepattern parameter.

Version Changes
8.6 Added the ability to combine multiple ref file sections
8.3 Added support for replacement fields in the paragraphsparameter
5.3 New

#LINK

In HTML mode, the #LINK macro expands to a hyperlink (<a> element) to another page.

#LINK(PageId[#name])(link text)

In HTML mode, if the link text is blank, it defaults either to the title of the entry being linked to (if the page is a box page and contains an entry with the specified anchor), or to the page’s link text.

In ASM mode, the #LINK macro expands to the link text.

The page IDs that may be used are the same as the file IDs that may be used in the [Paths] section of a ref file, or the page IDs defined by [Page:*]sections.

For example:

; See the #LINK(Glossary)(glossary) for a definition of 'chuntey'.

In HTML mode, this instance of the #LINK macro expands to a hyperlink to the ‘Glossary’ page, with link text ‘glossary’.

In ASM mode, this instance of the #LINK macro expands to ‘glossary’.

To create a hyperlink to an entry on a memory map page, use the address of the entry as the anchor. For example:

; Now we update the #LINK(GameStatusBuffer#40000)(number of lives).

In HTML mode, the anchor of this #LINK macro (40000) is converted to the format specified by the AddressAnchor parameter in the [Game]section.

Note

The #LINK:PageId[#name](link text) syntax is deprecated since version 9.5.

Version Changes
9.5 Added support for the #LINK(PageId[#name])(link text) syntax
5.4 When linking to an entry on a box page, the link text, if left blank, defaults to the title of the entry (in HTML mode)
5.2 An entry address anchor in a link to a memory map page is converted to the format specified by the AddressAnchorparameter
3.1.3 If left blank, the link text defaults to the page’s link text in HTML mode
2.1 New

#LIST

The #LIST macro marks the beginning of a list of bulleted items; LIST#is used to mark the end. Between these markers, the list items are defined.

#LIST[(class[,bullet])][][items]LIST#

Each item in a list must start with { followed by a space, and end with} preceded by a space.

For example:

; #LIST(data) ; { Item 1 } ; { Item 2 } ; LIST#

This list has two items, and will have the CSS class ‘data’.

In ASM mode, lists are rendered as plain text, with each item on its own line, and an asterisk as the bullet character. The bullet character can be changed for all lists by using a @set directive to set the bullet property, or it can be changed for a specific list by setting the bullet parameter.

The wrap flag (flag), if present, determines how sna2skool.py will write list items when reading from a control file. Supported values are:

By default, each list item is wrapped over multiple lines with no indent.

Version Changes
7.2 #LIST can be used in register descriptions in ASM mode
7.0 Added the nowrap and wrapalign flags
6.4 In ASM mode: #LIST can be used in an instruction-level comment and as a parameter of another macro; if the bullet character is an empty string, list items are no longer indented by one space; added the bullet parameter
3.2 New

#N

The #N macro renders a numeric value in either decimal or hexadecimal format depending on the options used with skool2asm.py orskool2html.py. A hexadecimal number is rendered in lower case when the--lower option is used, or in upper case otherwise.

#Nvalue[,hwidth,dwidth,affix,hex][(prefix[,suffix])]

For example:

This instance of the #N macro expands to one of the following:

The integer parameters of the #N macro may containreplacement fields.

See String parameters for details on alternative ways to supply theprefix and suffix parameters.

Version Changes
8.3 Added support for replacement fields in the integer parameters
6.2 Added the hex parameter
5.2 New

#R

In HTML mode, the #R macro expands to a hyperlink (<a> element) to the disassembly page for a routine or data block, or to a line at a given address within that page.

#Raddr[@code][#name][(link text)]

The disassembly ID (code) and anchor name (name) must be limited to the characters ‘$’, ‘#’, 0-9, A-Z and a-z.

If link_text is not provided, it defaults to the label for addr if one is defined, or to the address formatted according to the Address parameter in the [Game] section.

In ASM mode, the #R macro expands to the link text if it is specified, or to the label for addr, or to addr (converted to decimal or hexadecimal as appropriate) if no label is found.

For example:

; Prepare for a new game ; ; Used by the routine at #R25820.

In HTML mode, this instance of the #R macro expands to a hyperlink to the disassembly page for the routine at 25820.

In ASM mode, this instance of the #R macro expands to the label for the routine at 25820 (or simply 25820 if that routine has no label).

To create a hyperlink to the first instruction in a routine or data block, use an anchor that evaluates to the address of that instruction. For example:

; See the #R40000#40000(first item) in the data table at 40000.

In HTML mode, the anchor of this #R macro (40000) is converted to the format specified by the AddressAnchor parameter in the [Game]section.

Version Changes
8.4 In HTML mode, the link text defaults to the address formatted according to the Address parameter
8.3 Added support for replacement fields in the addr parameter
6.1 In ASM mode, addr is converted to decimal or hexadecimal as appropriate even when it refers to an unavailable instruction
5.1 An anchor that matches the entry address is converted to the format specified by the AddressAnchor parameter; added support for arithmetic expressions and skool macros in theaddr parameter
3.5 Added the ability to resolve (in HTML mode) the address of an entry point in another disassembly when an appropriateremote entry is defined
2.0 Added support for the @code notation

#RAW

The #RAW macro expands to the exact value of its sole string argument, leaving any other macros (or macro-like tokens) it contains unexpanded.

For example:

; See the routine at #RAW(#BEEF).

This instance of the #RAW macro expands to ‘#BEEF’.

See String parameters for details on alternative ways to supply thetext parameter. Note that if an alternative delimiter is used, it must not be an upper case letter.

Version Changes
6.4 New

#REG

In HTML mode, the #REG macro expands to a styled <span> element containing a register name or arbitrary text (with case adjusted as appropriate).

where reg is the name of the register, or:

where text is arbitrary text (e.g. hlh'l').

See String parameters for details on alternative ways to supply thetext parameter. Note that if an alternative delimiter is used, it must not be a letter.

In ASM mode, the #REG macro expands to either reg or text (with case adjusted as appropriate).

The register name (reg) must be one of the following:

a b c d e f h l a' b' c' d' e' f' h' l' af bc de hl af' bc' de' hl' ix iy ixh iyh ixl iyl i r sp pc

For example:

24623 LD C,31 ; #REGbc'=31

Version Changes
9.5 IXh, IXl, IYh and IYl are always rendered with a lower case ‘h’ or ‘l’
5.4 Added support for an arbitrary text parameter
5.3 Added support for the F and F’ registers
5.1 The reg parameter must be a valid register name

#SIM

The #SIM macro simulates the execution of machine code in the internal memory snapshot constructed from the contents of the skool file.

#SIM[stop,start,clear,a,f,bc,de,hl,xa,xf,xbc,xde,xhl,ix,iy,i,r,sp,execint,tstates,iff,im,cmio]

The parameters of the #SIM macro may containreplacement fields and may also be given as keyword arguments.

When execution stops, the simulator’s register values are copied to the simdictionary, where they are accessible via replacement fields with the following names:

In addition, the simulator’s hardware state is copied to the simdictionary, where it is accessible via replacement fields with the following names:

For example:

; #SIM(start=32768,stop=32772,bc=13256,de=672) 32768 LD HL,443 32771 ADD HL,BC ; At this point HL=#EVAL({sim[HL]}). ; #SIM(32773) 32772 ADD HL,DE ; And now HL=#EVAL({sim[HL]}). 32773 RET

The first #SIM macro initialises the BC and DE register pairs to 13256 and 672 respectively, starts executing code at 32768, and stops when it reaches the ‘ADD HL,DE’ instruction at 32772. The second #SIM macro picks up execution where the first left off, and stops when it reaches the ‘RET’ instruction at 32773.

After the #EVAL macros have been expanded, the second mid-block comment here is rendered as ‘At this point HL=13699’, and the third is rendered as ‘And now HL=14371’.

Note that, by default, the simulator does not simulate memory contention or I/O contention. This means that sim[tstates] may not be accurate if the code being simulated runs in or accesses contended memory, or performs I/O operations. To simulate memory and I/O contention, set the cmio parameter to 1.

If the stop parameter is not given, no code is executed, but the simulator’s registers and hardware state may be updated by providing other parameters. This technique can be used to initialise the simulator for use by the #AUDIO or #TSTATES macro.

Before executing code, the #SIM macro copies the simulator state as it was left by the most recent invocation of either the #AUDIO or the #SIMmacro (if any).

Note that code executed by the #SIM macro operates directly on the internal memory snapshot, and therefore can modify it. To avoid that, use the#PUSHS and #POPS macros to operate on a copy of the snapshot.

Version Changes
9.1 Added the cmio, execint, iff, im and tstatesparameters; added support for executing code in a 128K memory snapshot; added the 7ffd, ay, fffd, halted,iff and im fields to the sim dictionary; made thestop parameter optional
8.7 New

#SPACE

The #SPACE macro expands to one or more &#160; expressions (in HTML mode) or spaces (in ASM mode).

For example:

; '#SPACE8' (8 spaces) t56832 DEFM " "

In HTML mode, this instance of the #SPACE macro expands to:

        

In ASM mode, this instance of the #SPACE macro expands to a string containing 8 spaces.

The form SPACE([num]) may be used to distinguish the macro from adjacent text where necessary. For example:

; 'Score:#SPACE(5)0' t49152 DEFM "Score: 0"

Version Changes
8.3 Added support for replacement fields in the num parameter
5.1 Added support for arithmetic expressions and skool macros in thenum parameter
2.4.1 Added support for the #SPACE([num]) syntax

#TABLE

The #TABLE macro marks the beginning of a table; TABLE# is used to mark the end. Between these markers, the rows of the table are defined.

#TABLE[([class[,class1[:w][,class2[:w]...]]])][][rows]TABLE#

Each row in a table must start with { followed by a space, and end with} preceded by a space. The cells in a row must be separated by | with a space on each side.

For example:

; #TABLE(default,centre) ; { 0 | Off } ; { 1 | On } ; TABLE#

This table has two rows and two columns, and will have the CSS class ‘default’. The cells in the first column will have the CSS class ‘centre’.

By default, cells will be rendered as <td> elements. To render a cell as a<th> element, use the =h indicator before the cell contents:

; #TABLE ; { =h Header 1 | =h Header 2 } ; { Regular cell | Another one } ; TABLE#

It is also possible to specify colspan and rowspan attributes using the=c and =r indicators:

; #TABLE ; { =r2 2 rows | X | Y } ; { =c2 2 columns } ; TABLE#

Finally, the =t indicator makes a cell transparent (i.e. gives it the same background colour as the page body).

If a cell requires more than one indicator, separate the indicators by commas:

; #TABLE ; { =h,c2 Wide header } ; { Column 1 | Column 2 } ; TABLE#

The CSS files included in SkoolKit provide two classes that may be used when defining tables:

In ASM mode, tables are rendered as plain text, using dashes (-) and pipes (|) for the borders, and plus signs (+) where a horizontal border meets a vertical border.

ASM mode also supports the :w indicator in the #TABLE macro’s parameters. The :w indicator marks a column as a candidate for having its width reduced (by wrapping the text it contains) so that the table will be no more than 79 characters wide when rendered. For example:

; #TABLE(default,centre,:w) ; { =h X | =h Description } ; { 0 | Text in this column will be wrapped in ASM mode to make the table less than 80 characters wide } ; TABLE#

The wrap flag (flag), if present, determines how sna2skool.py will write table rows when reading from a control file. Supported values are:

By default, each table row is wrapped over multiple lines with no indent.

See also #UDGTABLE.

Version Changes
7.2 #TABLE can be used in register descriptions in ASM mode
7.0 Added the nowrap and wrapalign flags
6.4 In ASM mode, #TABLE can be used in an instruction-level comment and as a parameter of another macro

#TSTATES

The #TSTATES macro expands to the time taken, in T-states, to execute one or more instructions.

#TSTATESstart[,stop,flags,execint,cmio(text)]

flags is the sum of the following values, chosen according to the desired outcome:

For example:

c30000 LD A,1 ; This instruction takes #TSTATES30000 T-states

This instance of the #TSTATES macros expands to ‘7’.

For any instruction in the range start to stop whose timing is variable (e.g. a conditional call, return or relative jump), the smaller timing value is used by default:

c40000 RET Z ; This instruction takes at least #TSTATES40000 T-states

This instance of the #TSTATES macros expands to ‘5’.

To use the larger timing values, set bit 0 of flags. If both smaller and larger timing values are required, set bit 1 of flags and use the textparameter:

c50000 LD B,100 ; Set the delay parameter 50002 DJNZ 50002 ; Delay for #TSTATES50002,,2(#EVAL(99*$max+$min)) T-states

This instance of the #TSTATES macro expands to #EVAL(99*13+8), which in turn expands to ‘1295’.

Note that unless bit 2 of flags is set, only true assembly language instructions (i.e. not DEFB, DEFM, DEFS and DEFW statements) can be timed.

If bit 2 of flags is set, the stop address must be specified, and the instructions are executed in a simulator to determine their actual timing. This is useful for computing the time taken by conditional operations and operations that are repeated in a loop. For example:

c32768 LD DE,0 ; {This creates a delay of #TSTATES(32768,32776,4) *32771 DEC DE ; T-states 32772 LD A,D ; 32773 OR E ; 32774 JR NZ,32771 ; } 32776 RET

This instance of the #TSTATES macro expands to ‘1703941’.

Note that, by default, the simulator does not simulate memory contention or I/O contention. This means that the time reported by #TSTATES may not be accurate if the code being simulated runs in or accesses contended memory, or performs I/O operations. To obtain precise timing in such cases, set thecmio parameter to 1.

Before executing code in a simulator, the #TSTATES macro copies the simulator state as it was left by the most recent invocation of the#AUDIO or #SIM macro (if any).

However, unlike the #AUDIO and #SIM macros, code executed by the#TSTATES macro operates on a copy of the internal memory snapshot, and therefore does not modify it.

The integer parameters of the #TSTATES macro may containreplacement fields.

See String parameters for details on alternative ways to supply thetext parameter.

See also the #SIM macro, which can not only time instructions, but also track changes to register values as code is executed.

See also the Timings configuration parameter forsna2skool.py, which can be used to show instruction timings in comment fields when disassembling a snapshot.

Version Changes
9.1 Added the cmio and execint parameters; added support for executing code in a 128K memory snapshot
8.7 New

#UDGTABLE

The #UDGTABLE macro behaves in exactly the same way as the #TABLEmacro, except that the resulting table will not be rendered in ASM mode. Its intended use is to contain images that will be rendered in HTML mode only.

See #TABLE, and also #HTML.

#VERSION

The #VERSION macro expands to the version of SkoolKit.

Version Changes
6.0 New

Image macros

The #COPY, #FONT, #OVER, #PLOT, #SCR, #UDG,#UDGARRAY and #UDGS macros (described in the following sections) may be used to create images based on graphic data in the memory snapshot. They are not supported in ASM mode.

Some of these macros have several numeric parameters, most of which are optional. This can give rise to a long sequence of commas in a macro parameter string, making it hard to read (and write); for example:

To alleviate this problem, the image macros accept keyword arguments at any position in the parameter string; the #UDG macro above could be rewritten as follows:

#COPY

In HTML mode, the #COPY macro copies all or part of an existing frame into a new frame.

#COPY[x,y,width,height,scale,mask,tindex,alpha]{CROP}

For example:

; #UDGARRAY4(30000-30120-8)(*original) ; #COPY1,1,2,2(original,centre) ; #FRAMES(centre)(img)

This instance of the #COPY macro creates a new frame from a copy of the central 2x2 portion of the 4x4 frame created by the #UDGARRAY macro. The#FRAMES macro then creates an image of the new frame.

The integer parameters and the cropping specification of the #COPY macro may contain replacement fields.

See String parameters for details on alternative ways to supply theold and new parameters.

Version Changes
8.6 Added the tindex and alpha parameters
8.5 New

#FONT

In HTML mode, the #FONT macro expands to an <img> element for an image of text rendered in the game font.

#FONTaddr[,chars,attr,scale,tindex,alpha][(text)][{CROP}][(fname)]

For example:

; Font graphic data ; ; #HTML[#FONT49152,0(0123456789)]

In HTML mode, this instance of the #FONT macro expands to an <img>element for the image of the digits 0-9 in the 8x8 font whose graphic data starts at 49152.

The integer parameters and the cropping specification of the #FONT macro may contain replacement fields.

See String parameters for details on alternative ways to supply thetext parameter.

Note

The #FONT:(text)params[{CROP}][(fname)] syntax is deprecated since version 9.5.

Version Changes
9.5 Added support for the #FONTparams[(text)][{CROP}][(fname)]syntax
8.3 Added support for replacement fields in the integer parameters and the cropping specification
8.2 Added the tindex and alpha parameters
6.3 Added support for image path ID replacement fields in thefname parameter
5.1 Added support for arithmetic expressions and skool macros in the numeric parameters
4.3 Added the ability to create frames
4.2 Added the ability to specify alt text for the element
4.0 Added support for keyword arguments
3.6 Added the text parameter, and made the chars parameter optional
3.0 Added image-cropping capabilities
2.0.5 Added the fname parameter and support for regular 8x8 fonts

#FRAMES

In HTML mode, the #FRAMES macro expands to an <img> element for an image built from one or more frames already created by other image macros.

#FRAMES(FRAME1[;FRAME2;...])(fname)

Each frame specification has the form:

To create a frame, use a #FONT, #SCR, #UDG, #UDGARRAYor #UDGS macro with the fname parameter in one of the following forms:

For example:

; #UDGTABLE { ; #FONT$3D00,0(hello)(hello*) | ; #FONT$3D00,0(there)(there*) | ; #FONT$3D00,0(peeps)(peeps*) | ; #FRAMES(hello,50;there;peeps)(hello_there_peeps) ; } TABLE#

The #FONT macros create the required frames (and write images of them); the#FRAMES macro combines the three frames into a single animated image, with a delay of 0.5s between each frame.

The integer parameters of a frame specification may containreplacement fields.

Note that the first frame of an animated image determines the size of the image as a whole. Therefore, the region defined by the width, height and coordinates of any subsequent frame must fall entirely inside the first frame.

Note

The #FRAMES macro has the same syntax and function as the older#UDGARRAY* macro, which is deprecated since version 9.5.

Version Changes
9.5 New

#OVER

In HTML mode, the #OVER macro superimposes one frame (the foreground frame) on another (the background frame).

#OVERx,y[,xoffset,yoffset,rmode][(attr)](byte)

rmode specifies whether and how to replace the attribute and graphic bytes of each background UDG over which a foreground UDG is superimposed:

attr is an expression that is evaluated once for each background UDG over which a foreground UDG is superimposed. attr may contain skool macros, and recognises the following placeholders:

byte is an expression that is evaluated once for each of the 8 graphic bytes in a background UDG over which a foreground UDG is superimposed. bytemay contain skool macros, and recognises the following placeholders:

If the foreground frame has no mask, its contents are combined with those of the background frame by OR operations.

For example:

; #UDGARRAY2(30000-30024-8)(*background) ; #UDG30032:30040(*object) ; #OVER0,1(background,object) ; #FRAMES(background)(image)

This instance of the #OVER macro superimposes the frame created by the#UDG macro at tile coordinates (0, 1) on the background frame created by the #UDGARRAY macro. The #FRAMES macro then creates an image of the modified background frame.

The integer parameters of the #OVER macro may containreplacement fields.

See String parameters for details on alternative ways to supply thebg and fg parameters.

Version Changes
8.5 New

#PLOT

In HTML mode, the #PLOT macro sets, resets or flips a pixel in a frame already created by one of the other image macros.

For example:

; #UDG30000(*tile) ; #PLOT1,2(tile) ; #FRAMES(tile)(tile)

This instance of the #PLOT macro sets the second pixel from the left in the third row from the top in the frame created by the #UDG macro. The#FRAMES macro then creates an image of the modified frame.

The integer parameters of the #PLOT macro may containreplacement fields.

Version Changes
8.3 New

#SCR

In HTML mode, the #SCR macro expands to an <img> element for an image constructed from the display file and attribute file (or suitably arranged graphic data and attribute bytes elsewhere in memory) of the current memory snapshot (in turn constructed from the contents of the skool file).

#SCR[scale,x,y,w,h,df,af,tindex,alpha][{CROP}][(fname)]

For example:

; #UDGTABLE ; { #SCR(loading) | This is the loading screen. } ; TABLE#

The integer parameters and the cropping specification of the #SCR macro may contain replacement fields.

Version Changes
8.3 Added support for replacement fields in the integer parameters and the cropping specification
8.2 Added the tindex and alpha parameters
6.3 Added support for image path ID replacement fields in thefname parameter
5.1 Added support for arithmetic expressions and skool macros in the numeric parameters
4.3 Added the ability to create frames
4.2 Added the ability to specify alt text for the element
4.0 Added support for keyword arguments
3.0 Added image-cropping capabilities and the df and afparameters
2.0.5 Added the scale, x, y, w, h and fnameparameters

#UDG

In HTML mode, the #UDG macro expands to an <img> element for the image of a UDG (an 8x8 block of pixels).

#UDGaddr[,attr,scale,step,inc,flip,rotate,mask,tindex,alpha][:MASK][{CROP}][(fname)]

The mask specification (MASK) takes the form:

Note that if any of the parameters in the mask specification is expressed using arithmetic operations or skool macros, then the entire specification must be enclosed in parentheses.

For example:

; Safe key UDG ; ; #HTML[#UDG39144,6(safe_key)]

In HTML mode, this instance of the #UDG macro expands to an <img>element for the image of the UDG at 39144 (which will be named safe_key.png), with attribute byte 6 (INK 6: PAPER 0).

The integer parameters, mask specification and cropping specification of the#UDG macro may contain replacement fields.

Version Changes
8.3 Added support for replacement fields in the integer parameters, mask specification and cropping specification
8.2 Added the tindex and alpha parameters
6.3 Added support for image path ID replacement fields in thefname parameter
5.1 Added support for arithmetic expressions and skool macros in the numeric parameters
4.3 Added the ability to create frames
4.2 Added the ability to specify alt text for the element
4.0 Added the mask parameter and support for AND-OR masking; added support for keyword arguments
3.1.2 Made the attr parameter optional
3.0 Added image-cropping capabilities
2.4 Added the rotate parameter
2.3.1 Added the flip parameter
2.1 Added support for masks
2.0.5 Added the fname parameter

#UDGARRAY

In HTML mode, the #UDGARRAY macro expands to an <img> element for the image of an array of UDGs (8x8 blocks of pixels).

#UDGARRAYwidth,attr,scale,step,inc,flip,rotate,mask,tindex,alpha[[ATTRS1;ATTRS2;...]]{CROP}

SPEC1, SPEC2 etc. are UDG specifications for the sets of UDGs that make up the array. Each UDG specification has the form:

addr[,attr,step,inc][:MASK]

The mask specification (MASK) takes the form:

ATTRS1, ATTRS2 etc. are attribute address range specifications (see below). If supplied, attribute values are taken from the specified addresses instead of the attr parameter values.

Address range specifications (for both UDGs and attributes) may be given in one of the following forms:

Any of these forms of address ranges can be repeated by appending xN, whereN is the desired number of repetitions. For example:

As many UDG specifications as required may be supplied, separated by semicolons; the UDGs will be arranged in a rectangular array with the given width.

Note that, like the main parameters of a #UDGARRAY macro (up to but not including the first semicolon), if any of the following parts of the parameter string is expressed using arithmetic operations or skool macros, then that part must be enclosed in parentheses:

For example:

; Base sprite ; ; #HTML[#UDGARRAY4(32768-32888-8)(base_sprite.png)]

In HTML mode, this instance of the #UDGARRAY macro expands to an <img>element for the image of the 4x4 sprite formed by the 16 UDGs with base addresses 32768, 32776, 32784 and so on up to 32888; the image file will be named base_sprite.png.

The integer parameters, UDG specifications, attribute address range specification and cropping specification of the #UDGARRAY macro may containreplacement fields.

See also #UDGS.

Note

Omitting the parentheses around the UDG specifications, and using the @notation instead of square brackets around the attribute address range specifications are both deprecated since version 9.5.

Version Changes
9.5 The attribute address range specifications may be enclosed in square brackets
8.6 The UDG specifications may be enclosed in parentheses
8.3 Added support for replacement fields in the integer parameters and the UDG, attribute address range and cropping specifications
8.2 Added the tindex and alpha parameters
7.1 Added the ability to specify attribute addresses
6.3 Added support for image path ID replacement fields in thefname parameter
5.1 Added support for arithmetic expressions and skool macros in the numeric parameters
4.2 Added the ability to specify alt text for the element
4.0 Added the mask parameter and support for AND-OR masking; added support for keyword arguments
3.6 Added support for creating an animated image from an arbitrary sequence of frames
3.1.1 Added support for UDG address ranges with horizontal and vertical steps
3.0 Added image-cropping capabilities
2.4 Added the rotate parameter
2.3.1 Added the flip parameter
2.2.5 Added support for masks
2.0.5 New

#UDGS

In HTML mode, the #UDGS macro expands to an <img> element for the image of a rectangular array of UDGs (8x8 blocks of pixels).

#UDGSwidth,height[,scale,flip,rotate,mask,tindex,alpha]{CROP}(uframe)

For example:

#UDGS2,2(sprite)( #LET(a=30000+9*(2*$y+$x)) #UDG({a}+1,#PEEK({a}))(*udg) udg )

This instance of the #UDGS macro expands to an <img> element for the image of the 2x2 sprite formed by the four 9-byte UDG definitions (where the first byte is the attribute value, and the next eight bytes are the graphic data) with base addresses 30000, 30009, 30018 and 30027. The image file is named sprite.png.

Unless specified by macro arguments, the scale, mask type, transparency index and alpha value of the image created by the #UDGS macro are copied from the last frame used to populate the array (corresponding to the bottom-right UDG).

The integer parameters and the uframe parameter of the #UDGS macro may contain replacement fields.

See String parameters for details on alternative ways to supply theuframe parameter.

See also #UDGARRAY.

Version Changes
8.6 New

Filenames

The fname parameter of the #FONT, #SCR, #UDG,#UDGARRAY and #UDGS macros can be used to specify not only an image filename, but also its exact location, the alt attribute of the <img>element, and a frame name (see #FRAMES).

If fname contains an image path ID replacement field (e.g.{ScreenshotImagePath}/udgs), the corresponding parameter value from the[Paths] section will be substituted.

If fname starts with a ‘/’, the filename is taken to be relative to the root of the HTML disassembly.

If fname contains no image path ID replacement fields and does not start with a ‘/’, the filename is taken to be relative to the directory defined by one of the following parameters in the [Paths] section, depending on the macro being used:

If fname does not end with ‘.png’, that suffix will be appended.

If an image with the given filename doesn’t already exist, it will be created.

The value of the alt attribute in the <img> element can be specified by appending a | character and the required text to the filename. For example:

#SCR(screenshot1|Screenshot 1)

This #SCR macro creates an image named screenshot1.png with alt text ‘Screenshot 1’.

Cropping

The #COPY, #FONT, #SCR, #UDG, #UDGARRAY and#UDGS macros accept a cropping specification (CROP) which takes the form:

For example:

#UDG40000,scale=2{2,2,12,12}

This #UDG macro creates an image of the UDG at 40000, at scale 2, with the top two rows and bottom two rows of pixels removed, and the leftmost two columns and rightmost two columns of pixels removed.

The parameters of the cropping specification may containreplacement fields.

Masks

The #COPY, #UDG, #UDGARRAY and #UDGS macros accept amask parameter that determines what kind of mask to apply to each UDG. The supported values are:

Given a ‘background’ bit (B), a UDG bit (U), and a mask bit (M), the OR-AND mask works as follows:

U M Result
0 0 0 (paper)
0 1 B (transparent)
1 0 0 (paper)
1 1 1 (ink)

The AND-OR mask works as follows:

U M Result
0 0 0 (paper)
0 1 B (transparent)
1 0 1 (ink)
1 1 1 (ink)

By default, transparent bits in masked images are rendered in bright green (#00fe00); this colour can be changed by modifying the TRANSPARENTparameter in the [Colours] section. To make the transparent bits in masked images actually transparent, set PNGAlpha=0 in the[ImageWriter] section.

Palette

Images created by the image macros use colours drawn from a palette of 16 entries:

The RGB values for these colours are defined in the [Colours] section.

The index values (0-15) may be used by an image macro’s tindex parameter to specify a transparent colour to use other than the default (0). The palette entry specified by tindex, if not 0, will be used as the transparent colour only if the image does not already contain any transparent bits produced by amask. In an animated image, the tindex and alpha values on the first frame take effect; any tindex and alpha values on the second or subsequent frames are ignored.

For example:

#UDG30000,attr=2,tindex=1,alpha=0

This #UDG macro creates an image of the UDG at 30000 with red INK and black PAPER (attr=2), black as the transparent colour (tindex=1), and full transparency (alpha=0).

Snapshot macros

The #POKES, #POPS and #PUSHS macros (described in the following sections) may be used to manipulate the memory snapshot that is built from the skool file. Each macro expands to an empty string.

#POKES

The #POKES macro POKEs values into the current memory snapshot.

#POKESaddr,byte[,length,step][;addr,byte[,length,step];...]

For example:

The UDG looks like this:

#UDG32768(udg_orig)

But it's supposed to look like this:

#PUSHS #POKES32772,254;32775,136 #UDG32768(udg_fixed) #POPS

This instance of the #POKES macro does POKE 32772,254 andPOKE 32775,136, which fixes a graphic glitch in the UDG at 32768.

The parameter string of the #POKES macro may containreplacement fields.

See also #PEEK.

Version Changes
8.3 Added support for replacement fields in the parameter string
5.1 Added support for arithmetic expressions and skool macros in the parameter string
3.1 Added support for ASM mode
2.3.1 Added support for multiple addresses

#POPS

The #POPS macro removes the current internal memory snapshot and replaces it with the one that was previously saved by a #PUSHS macro.

Version Changes
3.1 Added support for ASM mode

#PUSHS

The #PUSHS macro saves the current internal memory snapshot, and replaces it with an identical copy with a given name.

The snapshot name must be limited to the characters ‘$’, ‘#’, 0-9, A-Z and a-z; it must not start with a capital letter. The name can be retrieved by using theget_snapshot_name() method on HtmlWriter.

Version Changes
3.1 Added support for ASM mode

Defining macros with #DEF

By using the #DEF macro, it is possible to define new macros based on existing ones without writing any Python code. Some examples are given below.

#ASM

There is the #HTML macro for inserting content in HTML mode only, but there is no corresponding macro for inserting content in ASM mode only. The following #DEF macro defines an #ASM macro to fill that gap:

#DEF(#ASM #IF({mode[asm]}))

For example:

#ASM(This text appears only in ASM mode.)

#ASMUDG

The #UDG macro is not supported in ASM mode, but #DEF can define an#ASMUDG macro (based on the #ASM macro defined above) that is:

#DEF(#ASMUDG(a) #ASM(#LIST(,) #FOR($a,$a+7)(u,{ |#FOR(7,0,-1)(n,#IF(#PEEKu&2*n)(, ))| }) LIST#))

For example:

; #ASMUDG30000 30000 DEFB 48,72,136,144,104,4,10,4

This #ASMUDG macro produces the following output:

; | ** | ; | * * | ; |* * | ; |* * | ; | ** * | ; | * | ; | * * | ; | * |

#TILE, #TILES

Suppose the game you’re disassembling arranges tiles in groups of nine bytes: the attribute byte first, followed by the eight graphic bytes. If there is a tile at 32768, then:

will create an image of it. If you want to create several tile images, this syntax can get cumbersome; it would be easier if you could supply just the address of the attribute byte. The following #DEF macro defines a #TILEmacro that creates a tile image given an attribute byte address:

#DEF(#TILE(a) #UDG($a+1,#PEEK$a))

Now you can create an image of the tile at 32768 like this:

If you have several nine-byte tiles arranged one after the other, you might want to create images of all of them in a single row of a #UDGTABLE. The following #DEF macro defines a #TILES macro (based on the #TILEmacro already defined) for this purpose:

#DEF(#TILES(a,m) #FOR($a,$a+9*($m-1),9)(n,#TILEn, | ))

Now you can create a #UDGTABLE of images of a series of 10 tiles starting at 32768 like this:

#UDGTABLE { #TILES32768,10 } TABLE#