A passenger needs the platform’s movement, not its absolute position. If a platform moves five pixels right, add five to the passenger. If it moves left, preserve that negative displacement before applying it.

Include and initialise
Reserve public P/C/O/X/A/B/S/L/H, private T and lines 3000–3230. There are no arrays. Combine routines.bas with your caller through build.py, keeping END, STOP or a jump before the helper. C64/BBC use GOSUB; Spectrum uses GO SUB. Call 3000 to clear public fields at an intended reset boundary, then supply the actual limits and positions.
X is the passenger position, A the platform’s old position and B its new position, all in the same nonwrapping coordinate space. S is support: zero false, any nonzero byte true. L/H are inclusive passenger limits. Every input must be an integral byte, with L no greater than H and X already within them.
Apply the delta
Call 3100. O=1 reports valid inputs. An unsupported passenger returns P=X and C=0. A supported passenger receives the signed displacement B-A, clamped to L/H. P is the proposed position; C=1 means that clamping changed the mathematical result. Landing exactly on a limit is not clipping.
Reusable numbered routines
3000 LET P=0: LET C=0: LET O=0: LET X=0: LET A=0: LET B=0: LET S=0: LET L=0: LET H=0: RETURN
3100 LET P=X: LET C=0: LET O=0
3110 IF X<0 OR X>255 OR X<>INT (X) THEN RETURN
3120 IF A<0 OR A>255 OR A<>INT (A) THEN RETURN
3130 IF B<0 OR B>255 OR B<>INT (B) THEN RETURN
3140 IF S<0 OR S>255 OR S<>INT (S) THEN RETURN
3150 IF L<0 OR L>255 OR L<>INT (L) THEN RETURN
3160 IF H<0 OR H>255 OR H<>INT (H) THEN RETURN
3170 IF L>H OR X<L OR X>H THEN RETURN
3180 LET O=1
3190 IF S=0 THEN RETURN
3200 LET T=X+B-A
3210 IF T<L THEN LET T=L: LET C=1
3220 IF T>H THEN LET T=H: LET C=1
3230 LET P=T: RETURNInvalid input returns P=X, C/O=0 and preserves every input. The helper never commits X itself. This lets the caller decide whether to accept the proposal after consulting other game rules. Do not use P as a newly valid position when O=0.
Preserve the old position until it has been used
The normal caller carries X=100 from platform 40 to 45, producing P=105. The custom platform moves from 40 to 30: passenger 15 would become five, so it stops at L=10 and returns C=1. The caller then commits X=P only when O=1.
Example calls from the maintained caller
70 GOSUB 3000: LET AA=0: LET BB=0
80 LET X=100: LET A=40: LET B=45: LET S=1: LET L=10: LET H=200
90 GOSUB 3100: GOSUB 2000
100 IF P=105 THEN LET AA=1
110 IF A=40 THEN LET BB=1
120 IF O=1 THEN LET X=P
130 LET S=0: LET B=255
140 GOSUB 3100: GOSUB 2000
150 LET X=198: LET A=250: LET B=255: LET S=1
160 GOSUB 3100: GOSUB 2000
170 LET L=201: LET H=200
180 GOSUB 3100: GOSUB 2000
190 PRINT "CARY RESULTS";AA;BB
200 POKE MB+995,AA: POKE MB+996,BB: POKE MB+997,GD: POKE MB+998,WC-256*INT (WC/256): POKE MB+999,INT (WC/256): POKE MB+1000,239: STOPSubsequent calls exercise an unsupported passenger, an upper-limit clamp and invalid reversed limits. AA/BB/JJ (Z on Spectrum), line 2000 and the mailbox are observations. In a game, determine support separately, retain old platform position until all passengers have been served, and commit both platform and passenger states at a deliberate stage.
Choose a clipping response
C=1 is feedback, not a crush policy. A game might stop the platform, detach the passenger, test a ceiling, apply damage or reject the whole move. This one-dimensional helper does none of those automatically. It also cannot discover a passenger on a platform or perform swept collision detection.
For two axes, supply separate contexts or renamed fields and apply the game’s collision rules to each proposed displacement. A wrapping world or a platform that teleports needs an explicit displacement convention: subtracting two wrapped positions cannot reliably recover the intended movement. Wider world coordinates need wider validation and intermediate bounds together.
Mistake and repair
The wrong caller sets old A equal to new B before asking for the displacement. The delta becomes zero, so the passenger stays behind; both saved position and old-position/clipping checks fail. Keep old and new positions distinct through the query. Repaired source and loaded program match normal exactly.

Cost and Maths for Games
The helper validates six inputs, performs one signed subtraction and addition, then at most two clamps. The intermediate can lie outside the byte range and must stay wide until bounded. BASIC numeric arithmetic handles that here; assembly must explicitly preserve the carry/borrow and signed meaning. Neither version proves a whole game’s platform collision behaviour.
Maths for Games connects relative displacement, signed arithmetic and projection onto an interval. The Craft connects support ownership, movement order and deliberate clipping feedback.
Global names and line numbers
BASIC numeric names, arrays and numbered lines are global. To combine helpers, rename public and private fields and renumber the helper together with every GO SUB/GO TO reference. Keep each state block under one owner. The maintained build.py rejects duplicate line numbers; it does not automatically namespace or renumber routines.
Machine and measured size
C64 BASIC V2 recognises only the first two significant characters of numeric variable names. Short names make the ownership visible; check for collisions before including another component. This helper uses scalar numeric fields and allocates no arrays. The diagnostic uses a mailbox at $C000, outside the normal BASIC heap.
The numbered helper occupies 418 tokenised program bytes on this interpreter, including line headers. This excludes the caller, test tables, numeric scalar/array storage, interpreter stacks and ROM. Tokenised size is not machine-code size or a hardware-cycle count. No real-time or whole-game performance budget is inferred from the diagnostic. The caller’s AA/BB, JJ and RAM mailbox are observation machinery, not required game state.
Execution evidence
Working, custom, deliberately wrong and exact repaired callers executed through C64’s stock BASIC interpreter under Emu198x 0.44.2. Build198x 0.2.9 tokenises C64 PRG and Spectrum TAP programs. C64 enters stock RUN, Spectrum uses ROM tape loading, and BBC enters every numbered source line through MOS/BASIC. Actual loaded program bytes, complete state packets, positive completion/count/guards and visible result pixels are checked. After the positive completion marker, the observer advances two complete display frames before capturing, so a partially scanned final character cannot masquerade as a finished picture. Firmware is not distributed.
An independent mathematical/order model checks the trace and rejects altered source, configuration, loaded program, state, completion and image evidence. Host exhaustive checks complement the native boundary/sequential examples; those host ranges are not claimed as natively exhaustive. The supplied diagnostic callers deliberately end with STOP; the interpreter report is expected. The wrong caller prints 0,0 and the normal/custom/repaired callers print 1,1.
Public CI checks retained evidence; it does not execute restricted firmware. Refresh with python3 scripts/verify-basic-contacts.py moving-platform-carry commodore-64 --tools /path/to/extracted/releases and inspect with python3 scripts/check-basic-contacts.py moving-platform-carry.
Explore further
Compare the assembly technique. The BASIC game-flow routine makes session boundaries explicit. Complete source and native evidence.