Crash-tan Crash-tan

Last minute fixes...

Crash BASIC 1.57.3 Release Notes

written by Crash-tan

Turn off the palette, give a bound polygon a colour, and you got white. A
different colour: still white. Every shape on screen the same shade of nothing,
and the immediate-mode POLYGON right beside it drawing your colour perfectly.

Pulling on that thread found the rest of this release, all of it in the same
corner. A GHOST sprite could cross a wall, a trigger zone or another sprite
without any of it counting as a collision — so ONCOLLISION never fired and
AFTERCOLLISION had nothing to end. And a bound polygon could not reliably be
hidden: HIDE reached the engine and left the picture alone, and half a dozen
unrelated modifiers turned a hidden shape back on behind your back.

A BOUND POLYGON'S COLOUR SURVIVES SET PALETTE OFF

FILL and COLOR on SET POLYGON now carry a direct colour intact:

SET PALETTE OFF

DIM shield AS MUTATION
shield = MUTATION((0, 0), (40, 0), (40, 12), (0, 12))

SET POLYGON 0 BIND shield FILL &HFFFFFF00 COLOR &HFF804000

Before today that shape came out white — and so did the next one, whatever
colour you asked for. The colours were being flattened on the way to the
renderer: a value above &H7FFFFFFF was clipped down to &H7FFFFFFF, which
happens to be half-transparent white. Every opaque colour is above that
line, because opacity is the top byte, so every shape landed on the same
value. Two polygons in two different colours came out identical, which is the
part that makes it look like the colour was never read at all.

The same fix covers a polygon particle — EMITPARTICLE given a MUTATION
instead of an image name takes the same COLOR and FILL and had the same
problem.

Palette mode never had this. If you have been writing FILL 4, nothing about
your program changes.

AND COLOR IS NO LONGER DROPPED IN DIRECT-COLOUR MODE

An outline had a second problem hiding behind the first. SET PALETTE ON uses
-1 to mean "no outline", and the renderer was applying that rule in both
modes — but with the palette off, a colour is a literal &HAARRGGBB and every
opaque one looks like a negative number to the machinery underneath. So the
outline was quietly thrown away for every solid colour a program named.

SET PALETTE OFF means you are stating transparency yourself, in the alpha
byte, so there is nothing left for a sentinel to do. Colour values now pass
straight through, and alpha 0 is what says "don't draw this":

SET PALETTE OFF
SET POLYGON 0 BIND ship COLOR &HFFFFFFFF   ' a white outline
SET POLYGON 1 BIND hull  FILL &HFF202060   ' filled, no outline — COLOR unsaid
SET POLYGON 2 BIND glow  FILL &HFF80C0FF COLOR &H00000000   ' the same, said out loud

Leaving COLOR out still means no outline, in either mode — the statement now
picks the spelling that mode understands.

One thing to check in your code. If you wrote a literal COLOR -1 while the
palette was off, it used to mean "no outline" and now means opaque white, which
is what &HFFFFFFFF is. Drop the modifier, or write COLOR &H00000000. In
palette mode COLOR -1 is unchanged and still means no outline.

This is what SET PALETTE has described all along, and what the immediate
POLYGON statement has always done — a bound polygon was the one shape reading
the rules differently.

SOLID DECIDES WHAT GETS PUSHED, NOT WHAT GETS NOTICED

A GHOST sprite now collides in every sense except the physical one. It fires
ONCOLLISION when it reaches something and AFTERCOLLISION when it leaves, and
it passes straight through in between:

BEHAVIOR "wanderer"
  BVELOCITY 1, 0
  ONCOLLISION
    PRINT "entered "; tag_b$
  END ONCOLLISION
  AFTERCOLLISION
    PRINT "left "; tag_b$
  END AFTERCOLLISION
END BEHAVIOR

SET SPRITE 0, 40, 100, "ghost" GHOST BEHAVIOR "wanderer"

Before today that sprite crossed the whole screen in silence. Detection was only
ever a by-product of resolution — the engine noticed a collision by
correcting one — so anything it was never going to push was also something it
never saw. SOLID was acting as a detection switch, which is not what it is and
not what the reference says it is.

Three situations get their events back, and each of them is a thing the manual
already told you to build:

  • A GHOST sprite against anything. Including one that starts life already
    overlapping — spawn a sprite outside an ENCLOSURE and walk it in, and it
    fires on its first tick (it is in contact from the moment it exists) and
    closes the contact as it crosses in. Making it SOLID was never an
    alternative: an enclosure snaps a solid sprite to the wall on its first tick,
    which is the whole reason to spawn one as a ghost.
  • A non-solid boundary. BOUNDARY ADD without SOLID is documented as a
    trigger zone, and now behaves as one: entry and exit, with the sprite walking
    through. An ENCLOSURE without SOLID reports a sprite leaving without
    holding it in.
  • Two sprites with no barrier tag between them. SOLID SPRITES("wall") says
    what this sprite is stopped by. It never claimed to say what it can see.

Both sides of a pair get their own event, so "player walks into enemy, enemy's
handler fires" needs no code on the player.

FOR COLLISIONS follows the same rule and reports GHOST sprites too. This
is the one thing here that may change a program that was working:
a loop that
relied on ghosts being invisible to it will start finding them. Nothing that was
already reported has stopped being reported, and physics is untouched — a ghost
still passes through everything, a solid sprite is still stopped by exactly what
it was stopped by before.

HIDE POLYGON AND SHOW POLYGON

SET POLYGON 0 BIND shield FILL 4 SOLID BOX
HIDE POLYGON 0
REM ...the shield is off, but still exactly where it was...
SHOW POLYGON 0

HIDE SPRITE cannot do this. A polygon's sprite half lives in its own range of
ids, so HIDE SPRITE 3 hides sprite 3 and leaves polygon 3 alone — quietly,
with no error to tell you so. These two statements address the shape.

Hiding is not GHOST: a hidden polygon still collides, still runs its behavior,
and comes back exactly as it was. Use GHOST to drop the collider and
DESTROY POLYGON to remove the shape.

AND HIDING A POLYGON NOW STAYS HIDDEN

SET POLYGON n HIDE has always set the shape's own state correctly — every
query agreed it was hidden. What it did not do was tell the renderer directly,
and six other modifiers turned the picture back on without meaning to.

The bad one was silent and permanent. Re-sending the polygon — which is what
COLOR, FILL, LAYER, ZORDER, TEXTURE and UV each do — marked it
visible on screen while the shape itself still said hidden. Nothing disagreed
loudly enough to be corrected, so it stayed on, and no amount of re-issuing
HIDE brought it back down; the only way out was to show it and hide it again.
A shield that recoloured itself as it came up could never be put away.

HIDE POLYGON 0
SET POLYGON 0 COLOR 2      ' recolour it while it is away — it STAYS away

SOLID did the same thing on the other side of the fence: attaching a collider
to a hidden shape un-hid it. Attaching a collider is not a statement about
visibility, and it no longer behaves like one.

Visibility is now applied after everything else in the statement, so the
modifiers commute — SET POLYGON 0 SOLID BOX HIDE and
SET POLYGON 0 HIDE SOLID BOX mean the same thing, and both end up hidden.

The one place a shape still comes back visible is a re-BIND, and that is
deliberate: BIND rebuilds the polygon, so anything the statement does not
mention returns to its default — visibility along with everything else. If you
re-bind a shape that should stay hidden, say so in the same breath:
SET POLYGON 0 BIND shield HIDE.

A REMINDER WHILE YOU ARE IN THERE

Direct colours are &HAARRGGBB — alpha first, then red, green, blue. So
&HFFFF00FF is opaque magenta, and the yellow you may have meant by it is
&HFFFFFF00. Worth a glance now that your colours actually arrive.