# Crash BASIC 1.33.0 Release Notes

*~written by Crash-tan~*

## THE BIT-TWIDDLER'S RELEASE

Crash BASIC can now reach all the way down to the individual bits of an
integer. Nine new functions — `BITAND`, `BITOR`, `BITXOR`, `BITNOT`,
`SHL`, `SHR`, `BITTEST`, `BITSET`, `BITCLEAR` — give you packed flags,
bitmasks, color channels, and bitboards without ever leaving BASIC.

If you've never needed bitwise math, nothing changes for you. If you
*have* been waiting for it: it's here, it's loud about mistakes, and it
behaves the same on every platform.

```basic
state = 0
state = BITSET(state, 2)          ' raise bit 2
IF BITTEST(state, 2) THEN PRINT "bit 2 is up"
PRINT BITAND(12, 10)              ' 8   (1100 & 1010 = 1000)
PRINT SHL(1, 4)                   ' 16  (1 shifted left 4)
```

---

## Why functions, not operators?

A fair question if you're coming from QBasic, where `AND` / `OR` / `NOT`
secretly do double duty as bitwise operators (it only *works* there
because QBasic's `TRUE` is `-1`, so all-bits-set and "true" happen to
coincide).

Crash BASIC doesn't play that game. Here **`TRUE` is `1`**, `AND` / `OR`
/ `NOT` are strictly **boolean** — they short-circuit and return `0`/`1`
by truthiness — and they are staying that way. Overloading them to
*sometimes* mean bitwise would make `a AND b` ambiguous depending on
context, which is exactly the kind of footgun this language tries not to
hand you.

So bitwise math gets its own clearly-named functions. No guessing.

```basic
PRINT (12 AND 10)        ' 1   — both operands are truthy → boolean true
PRINT BITAND(12, 10)     ' 8   — the actual bitwise AND
```

---

## The toolkit

Everything operates on Crash BASIC's 64-bit signed integers. Float
arguments are truncated to integer first, so `SHL(2.9, 1)` is `SHL(2, 1)`.

### The combiners — `BITAND`, `BITOR`, `BITXOR`, `BITNOT`

```basic
BITAND(a, b)    ' bits set in BOTH        — masking
BITOR(a, b)     ' bits set in EITHER      — combining flags
BITXOR(a, b)    ' bits set in EXACTLY one — toggling
BITNOT(a)       ' flip every bit
```

`BITNOT` flips all 64 bits, so on a signed integer `BITNOT(0)` is `-1`
(every bit set). That's not a bug — that's what "all bits on" *is* in
two's complement. Mask it down to the width you care about:

```basic
low_byte = BITAND(BITNOT(0), 255)   ' 255 — bottom 8 bits only
```

### The shifters — `SHL`, `SHR`

```basic
SHL(a, n)   ' shift left by n bits  (a * 2^n)
SHR(a, n)   ' shift right by n bits — LOGICAL, zero-filled
```

Two things worth knowing:

- **`SHR` is a *logical* (zero-fill) shift, not arithmetic.** It treats
  your integer as an unsigned 64-bit pattern, so the sign bit does **not**
  smear downward. This is the right behavior for masks and bitboards —
  bit 63 shifts cleanly down to bit 0 instead of dragging a wall of 1s
  behind it.
- **Shift amounts must be `>= 0`.** A negative shift is a bug, so it
  **halts loud** instead of guessing a direction. Shifting by `>= 64`
  pushes every bit out the end and yields `0`.

### The single-bit trio — `BITTEST`, `BITSET`, `BITCLEAR`

For when you don't want to hand-roll `1 << n` masks every time. **Bit 0
is the least-significant bit.**

```basic
BITTEST(a, bit)    ' 1 if that bit is set, else 0
BITSET(a, bit)     ' return a with that bit turned ON
BITCLEAR(a, bit)   ' return a with that bit turned OFF
```

`BITSET` / `BITCLEAR` return a *new* value — they don't mutate in place,
so assign the result back:

```basic
flags = BITSET(flags, 3)
```

A negative bit index is a bug and **halts**. A bit index `>= 64` has no
representable bit, so it's handled gracefully rather than crashing:
`BITTEST` reads `0`, and `BITSET` / `BITCLEAR` return the value unchanged.

---

## What you'll actually use it for

**Packed flags** — stuff a dozen booleans into one integer:

```basic
HAS_KEY    = 0      ' bit positions
HAS_SWORD  = 1
IS_POISONED = 2

inv = 0
inv = BITSET(inv, HAS_KEY)
inv = BITSET(inv, HAS_SWORD)

IF BITTEST(inv, HAS_KEY) THEN PRINT "the door clicks open"
inv = BITCLEAR(inv, HAS_KEY)        ' key consumed
```

**Color channels** — pack and unpack RGB in a single number:

```basic
rgb = BITOR(BITOR(SHL(red, 16), SHL(green, 8)), blue)

red   = BITAND(SHR(rgb, 16), 255)
green = BITAND(SHR(rgb, 8), 255)
blue  = BITAND(rgb, 255)
```

**Bitboards** — represent an 8x8 board as a single 64-bit integer, one
bit per square, and test/flip squares with `BITTEST` / `BITSET`. This is
the fast foundation for board-game AI, and it's exactly why these landed
now.

---

## Also fixed

- **`PLAYMUSIC` in the browser could play silently.** A song whose name
  wasn't all-uppercase (e.g. `"Moon"`) would load fine but make no sound
  on the web build, while playing correctly on desktop. Song names now
  match case-insensitively in the browser, the same way every other audio
  handle already does. Desktop was never affected.

---

## Compatibility notes

- **Purely additive.** Nine new built-in functions; nothing existing
  changed. `AND` / `OR` / `NOT` are still boolean, exactly as before.
- **No protocol / multiplayer changes.** Wire-compatible with 1.32.x.
- **Same answers everywhere.** The bitwise functions are pure integer
  math — identical results on Mac, Windows, Linux, iOS, Android, and the
  browser.

---

*Go forth and twiddle. One bit at a time.*

*— Crash-tan*
