417 lines
24 KiB
Markdown
417 lines
24 KiB
Markdown
# Arcade 85
|
||
|
||
A 5-in-1 iOS collection of faithful **HD remakes** of five classic TI-85
|
||
calculator games. Native **SwiftUI + SpriteKit**.
|
||
|
||
The games (from the original sources in this repo's sibling folders):
|
||
|
||
| Game | Original | Status |
|
||
|------|----------|--------|
|
||
| **Lunar Lander** | Tiger/Istar, 1997 (`lander/LANDER.C`) | ✅ Playable |
|
||
| **ZTetris** | J. Mårdell, 1998 (`zetris/ZTETRIS.ASM`) | ✅ Playable |
|
||
| **Phoenix** | P. Davidson, 2008 (`phx4.0ti85/`) | ✅ Playable |
|
||
| **Dope Wars** | J.E. Dell, 1984 · engine via J. Gannon's NerdWars, 2000 | ✅ Playable |
|
||
| **ZMercury** | P. Davidson, 2004 (`zmercury-ti85/`) | ✅ Playable |
|
||
| **Galaxian** | P. Davidson, 1998 (`galaxian-ti85/`) | 💤 Ported, dormant |
|
||
|
||
All five collection slots are playable. Galaxian was fully ported, then swapped
|
||
out of the line-up for a trading game (too much overlap with Phoenix); its code
|
||
stays in the project and swapping one `GameCatalog.swift` entry restores it.
|
||
The trading slot first shipped as NerdWars (the TI-85's Drugwars clone), then
|
||
was restored to the classic **Dope Wars** setup it secretly was all along —
|
||
see the Dope Wars section.
|
||
|
||
## Running it
|
||
|
||
Requires Xcode 16+ (developed against Xcode 26).
|
||
|
||
```sh
|
||
open Arcade85/Arcade85.xcodeproj
|
||
# pick an iPhone simulator, then Cmd-R
|
||
```
|
||
|
||
Or from the command line:
|
||
|
||
```sh
|
||
cd Arcade85
|
||
xcodebuild -scheme Arcade85 -sdk iphonesimulator \
|
||
-destination 'platform=iOS Simulator,name=iPhone 17' build
|
||
```
|
||
|
||
There is no third-party dependency and no code-signing needed for the simulator.
|
||
The project uses Xcode "synchronized file groups", so **new files added under
|
||
`Arcade85/Arcade85/` are picked up automatically** — no `.pbxproj` editing.
|
||
|
||
## Project layout
|
||
|
||
```
|
||
Arcade85/Arcade85/
|
||
Arcade85App.swift @main entry point
|
||
Shell/ the collection UI, shared across every game
|
||
Theme.swift palette + fonts (SwiftUI + SpriteKit mirrors)
|
||
Haptics.swift feedback helpers
|
||
HighScoreStore.swift per-game best scores (UserDefaults)
|
||
GameCatalog.swift game metadata + SKScene factory
|
||
RootView.swift home screen (starfield + game cards)
|
||
GameHostView.swift full-screen SpriteView host + back button
|
||
Games/
|
||
SceneArt.swift procedural gradients, starfields, symbol + sprite textures
|
||
ComingSoonScene.swift placeholder scene for the four unbuilt games
|
||
Lander/
|
||
LanderSim.swift faithful port of LANDER.C (pure logic)
|
||
LanderScene.swift HD rendering, multi-touch thrusters, game flow
|
||
ZTetris/
|
||
TetrisSim.swift faithful port of ZTETRIS.ASM (pure logic)
|
||
TetrisScene.swift HD rendering, DAS touch controls, game flow
|
||
Phoenix/
|
||
PhoenixData.swift sprites (images.asm) + campaign (levels.asm), verbatim
|
||
PhoenixSim.swift faithful port of the Z80 game logic
|
||
PhoenixScene.swift HD rendering, drag-to-fly control, shop, flow
|
||
Galaxian/ (dormant — swapped out of the catalog for Dope Wars)
|
||
GalaxianData.swift sprites, formation patterns + 20-level table, verbatim
|
||
GalaxianSim.swift faithful port of GALAXIAN.ASM
|
||
GalaxianScene.swift HD rendering, drag-to-fly + laser button, flow
|
||
DopeWars/
|
||
DopeWarsSim.swift the NerdWars engine restored to Dell's classic setup
|
||
DopeWarsScene.swift night-city trading board, event cards, cop chase, flow
|
||
ZMercury/
|
||
MercuryData.swift terrain tiles, map, sine table + sprites, verbatim
|
||
MercurySim.swift faithful port of the multi-file Z80 sources
|
||
MercuryScene.swift HD terrain scroller, parallax, drag-to-fly, flow
|
||
Assets.xcassets/ app icon (procedurally generated) + accent color
|
||
```
|
||
|
||
## Design approach
|
||
|
||
Each game is split into a **pure simulation** and a **SpriteKit scene** that
|
||
renders and drives it. The simulation reproduces the original's mechanics
|
||
exactly; the scene is where the HD glass goes (neon vector art, particles,
|
||
haptics, touch controls). This keeps the remakes honest — the feel comes from
|
||
the original numbers, not an approximation.
|
||
|
||
### Lunar Lander (the reference implementation)
|
||
|
||
`LanderSim` ports `LANDER.C` line-for-line in the original integer space:
|
||
|
||
- the Dape/Istar landscape generator (random walk + erosion smoothing passes),
|
||
- the 10-wide landing pad carved 4 below the surrounding terrain,
|
||
- gravity, the ±2 thruster impulses, horizontal friction, velocity clamping,
|
||
- the 8-pixel-footprint landing/crash test (must be flat under all 8 columns
|
||
with descent speed ≥ −3), and
|
||
- the original scoring: `((90 − maxFuel) × fuel / maxFuel) × maxVel`.
|
||
|
||
The sim ticks at the original's real pace — LANDER.C ends every loop pass with
|
||
`delay(20)` ≈ 200 ms (the same `delay()` whose 200-unit calls are the ~2 s
|
||
message pauses), i.e. **~5 loops/sec** — with rendering interpolated between
|
||
ticks so motion stays smooth. Taps shorter than one tick are latched so they
|
||
still burn for exactly one loop, like one keypress in the original.
|
||
|
||
Deliberate HD liberties (everything else is the original's integer rules,
|
||
which hold verbatim on the Moon setting):
|
||
|
||
- The field is **128×96** instead of 128×64 — extra sky above the same 0…32
|
||
terrain for a phone-shaped playfield and a longer descent. Every rule is
|
||
height-relative, so nothing else changes.
|
||
- **Soft walls.** In the original the screen edge was fatal; on touch that
|
||
turned a mistimed start tap into an instant "lost in space". Now the top and
|
||
sides stop the lander (velocity zeroed) instead of ending the run, the
|
||
lander spawns with 7 px of ceiling headroom, and a tap that starts a run is
|
||
consumed by the transition — it can never double as a first-tick burn.
|
||
Crashing into terrain is the only way to die.
|
||
- A **GRAVITY** setting — the remake's third difficulty knob, added because
|
||
the original's self-braking lateral friction leaves little to fight:
|
||
- **MOON** — the original: pull 1/tick, drift damped every tick;
|
||
- **MARS** — pull 1,1,1,2 (avg 1.25), damping every *other* tick;
|
||
- **EARTH** — pull 1,2 alternating (avg 1.5), **no damping** — Newtonian
|
||
drift you must counter-burn, landing scores **×3** (Mars ×2).
|
||
The patterns are phase tables over the tick counter, so the sim stays
|
||
integer-exact.
|
||
|
||
The scene renders the actual TI-85 8×8 lander bitmap as crisp merged neon
|
||
pixels and adds on-screen thruster pads (with true multi-touch so you can fire
|
||
lateral + main thrust together), a live V-SPEED / FUEL / SCORE HUD, and
|
||
ready / landed / game-over flow. The original's adjustable **FUEL (30–80)**
|
||
lives on the ready screen next to **MAX SPEED (4–7)** — the original allowed
|
||
speed 3, but there terminal velocity *equals* the safe-touchdown limit and the
|
||
game cannot be lost, so the floor is 4. The classic's own defaults (40/7) are
|
||
its hardest speed setting, so the remake defaults to a gentler **60 fuel /
|
||
speed 4 / Moon**, remembers the player's last choice, and teaches the rule on
|
||
screen (`V-SPEED · SAFE ≤3` plus stepper hints). The score formula already
|
||
pays more for harder settings; the gravity multiplier extends that to the new
|
||
worlds. A 20-assertion standalone harness pins the spawn headroom, wall
|
||
clamps, all three pull/damping patterns, the score multipliers, and that
|
||
speed 4 remains losable.
|
||
|
||
### ZTetris
|
||
|
||
`TetrisSim` ports `ZTETRIS.ASM` mechanically — several of its tables are
|
||
embedded **verbatim**:
|
||
|
||
- the 28-word `BitData` piece table (7 pieces × 4 rotations, four (dy,dx)
|
||
offsets packed 2 bits each), decoded exactly like the ASM's `Uncrunch`;
|
||
- the well geometry: 10 columns, 16 visible rows + 2 rows of hidden headroom,
|
||
spawn at the original (6,16), no wall kicks, moves fail silently;
|
||
- `levelcnts` gravity (level 0–20), converted at the TI-85's real interrupt
|
||
timing: one main-loop iteration = 4 HALTs ≈ 20 ms, so level 0 = 0.8 s/row;
|
||
- scoring: line clears `4/10/30/120 × (level+1)`, plus the hidden units
|
||
counter (`scoreU`) — +1 per Down/Drop step *including the blocked one* —
|
||
carried into the displayed score ÷10 on each new piece, exactly as `NewB`
|
||
does it;
|
||
- level = lines ÷ 10 (only increasing, capped at 20), start level 0–9;
|
||
- "start high" trash (0–5 → ×2 rows), each row punched with 5 random gaps;
|
||
- the 16 per-level background patterns, tiled on the rails beside the well.
|
||
|
||
The scene adds the HD glass: colored beveled blocks, a ghost landing outline,
|
||
next-piece preview, DAS auto-repeat on held ◄ ► (0.167 s delay, 50 ms repeat),
|
||
held soft drop, tap hard drop, both rotation directions, pause, and line-clear
|
||
flash/score-pop feedback. The sim has a standalone test harness (68 assertions)
|
||
covering piece decode, drop scoring, clears, leveling, trash rows and top-out.
|
||
|
||
### Phoenix
|
||
|
||
The deepest port: the entire Phoenix 4.0 campaign and economy, extracted from
|
||
the Z80 sources file by file:
|
||
|
||
- **Campaign** (`levels.asm`): all 31 combat waves + 9 shop stops, with every
|
||
power/movement/weapon/fire-rate value and the four pattern paths (circle,
|
||
oval, figure-eight, huge oval) transcribed literally; `L_GOTO` chains inlined.
|
||
- **Enemy AI** (`emove.asm`): the synchronized rectangle formation wobble
|
||
(byte-timer, odd-tick moves, 17-tick phases, −60 entry descent), bosses
|
||
(descend then 83/90-px sweeps), bouncers, pattern followers driven by the
|
||
original's bit-reversed-timer fractional velocities (`Div_A_16`), rampagers
|
||
with the exact trigger columns, and the 4-path swoop system.
|
||
- **Weapons**: player F1–F5 with the original damage/speed/offsets (including
|
||
F4's alternating sides and F5's arcing swing shots), enemy weapons from
|
||
straight drops to the 7-angle-bucket aimed big/huge shots.
|
||
- **Economy**: money as dmg-0 "bonus bullets" dropped every 4–11 kills, $ value
|
||
by difficulty (100/50/25), cash cap 9900, and the shop's 7 items with the
|
||
original prices and purchase rules (shield cap 16, one-time weapons that
|
||
auto-select, companion refill).
|
||
- **Companion** (`helper.asm`): position-queue follower, 10-damage shots every
|
||
8 frames, its own 16-point shield and explosion.
|
||
- **Scoring** (`score16.asm`): shields×1000 + time bonus (19000 counting down
|
||
every other frame) + difficulty/speed bonus + cash, awarded on finishing.
|
||
- **Sprites** (`images.asm`): all 44 bitmaps rendered as neon pixel art,
|
||
including the 16-wide bosses and the 8-frame explosion.
|
||
|
||
Touch layer: drag anywhere to fly (original ±2/±1-px-per-frame speed limits
|
||
still govern the ship), always-on autofire at the original 10/4-frame cadence,
|
||
tap weapon selector, pause, and full title → shop → victory/game-over flow at
|
||
the original 25/29/35 fps speed options. Sim verified by a 172-assertion
|
||
standalone harness (progress additions covered by a follow-up suite).
|
||
|
||
**Progress scoring (remake addition).** The original only scored a *finished*
|
||
campaign (`score16.asm`), which on the phone meant the high score sat at 0
|
||
until you beat all 31 waves. The sim now tracks `wavesCleared` and
|
||
`totalEarned` (lifetime $, unspent or not), and every run posts
|
||
`waves × 400 + earnings` — a death shows `WAVE n/31 · SCORE`, and a victory
|
||
adds the untouched score16 tally (shields/time/bonus/cash) on top, itemised
|
||
as a PROGRESS line in the classic victory breakdown.
|
||
|
||
The 2:1 TI-85 window is drawn **full-bleed** with a **2× vertical stretch on
|
||
entity positions** while the sprites themselves keep a mild 1.25× arcade-monitor
|
||
stretch — the battle fills the phone instead of sitting in a letterboxed strip,
|
||
and the pixel art stays crisp. Sim geometry and collisions are untouched — the
|
||
visible window itself can't widen, because the original parks and spawns
|
||
entities just outside the y 32…96 band.
|
||
|
||
### Galaxian
|
||
|
||
`GalaxianSim` ports `GALAXIAN.ASM` (v3.0) at its ~35 fps frame rate:
|
||
|
||
- **Formation choreography**: each slot's pattern byte is *both* entry time
|
||
and formation depth — an enemy triggers when `timer & 127 == 128 - depth`,
|
||
descends 1 px/frame, and the 128-frame timer wrap locks it into formation
|
||
exactly at its row. The whole formation then sways ±32 px on timer bit 6.
|
||
- **Swoops**: the original's 8-stage dive state machine (types 5–12: up/out,
|
||
arc over, dive at double speed), started by the R-register roll
|
||
(`R < 19/128` on every 4th frame), aimed away from the screen edge, and
|
||
rejoining the entry queue at the bottom for −1 point.
|
||
- **20 levels** from `levels_jump_table`: plain waves, the ring formation,
|
||
mixed weak/strong waves (13 power-1 + 7 of the level type), bouncing cross
|
||
trainers (exactly half of which can flee, −50), aim-shooting "operator"
|
||
ships, patrolling 10-hit bosses, and two 98-hit superbosses that deploy
|
||
drones mid-fight (−200 each).
|
||
- **Weapons**: one cannon bullet per press from a 10-slot pool (+10 per hit,
|
||
+100 per kill), and 9 lasers that wipe an entire column but never hurt a
|
||
boss. Enemy bullets come in 5 drift types picked by your position.
|
||
- **Scoring** exactly as documented: +200 per level, +25 per boss hit, +1000
|
||
per boss kill, −16×16 per death, +5000 victory.
|
||
|
||
The scene adds drag-to-fly (4-way, original 1 px/frame speed), always-on
|
||
autofire, a big LASER button with the remaining count, wave banners, and the
|
||
9-lives / 9-lasers HUD. Sim verified by a 129-assertion standalone harness.
|
||
|
||
### ZMercury
|
||
|
||
`MercurySim` ports the multi-file 2004 sources — a fully deterministic
|
||
horizontal cave-shooter (the original contains *no* randomness at all):
|
||
|
||
- **Terrain scroller**: 1 px/frame leftward; every 8 frames a new 8-px tile
|
||
column enters from a 64-column looping map (9th map row = wave triggers).
|
||
The buffer's polarity quirk (bits set = open sky) and the one-byte offset
|
||
between sprite space and terrain space are both preserved.
|
||
- **Waves**: straight flyers, aimed-fire phoenixes, sine-bobbing spinners,
|
||
turret bases mounted on their map pad tiles (ceiling *and* floor), spin-T
|
||
sine crossers, an open-space gate that halts the map until the field is
|
||
clear, and a 50-hit boss that holds the right edge firing bullet pairs.
|
||
- **Damage model**: 100 shield points; every ship corner touching rock costs
|
||
1 per frame, enemy bullets cost 5, rams cost 1 (and hurt the enemy back).
|
||
Kills pay +1 immediately and +20 when the explosion finishes — the
|
||
original's BCD scoring, faithfully odd.
|
||
- **Aimed fire**: the shallow-cone rule — bullets angle up/down only when
|
||
the vertical offset beats deltaX/4 — plus per-slot fire stagger.
|
||
|
||
The scene renders the terrain from prebuilt map-column textures that slide
|
||
with the sim's scroll counter — full-bleed, positions/terrain stretched 1.9×
|
||
vertically (sprites 1.35×), every rock pixel facing open air lit as a glowing
|
||
rim over a dark rock mass — plus drifting star layers, a slower stalactite
|
||
silhouette band for cave depth, and the original ~28.6 fps (`timer ≥ 7`
|
||
against the ~200 Hz interrupt). Sim verified by an 81-assertion standalone
|
||
harness.
|
||
|
||
### Dope Wars
|
||
|
||
The genre swap for the fifth slot — and a restoration story. The engine is the
|
||
verbatim port of **NerdWars** (J. Gannon, 2000), the TI-85's only
|
||
Drugwars-style game, decoded from its `.85p`. Reading the BASIC revealed that
|
||
Gannon had kept John E. Dell's original **Drug Wars (1984)** item variables
|
||
`C,H,A,W,S,L` — Cocaine, Heroin, Acid, Weed, Speed, Ludes — and merely
|
||
rescaled the price bands and renamed the nouns. `DopeWarsSim` reverses the
|
||
re-skin: Dell's classic setup on Gannon's proven engine.
|
||
|
||
- **The month**: $2,000 cash, the classic **$5,500** debt to the loan shark
|
||
growing 10%/day, a 6%/day bank (shark and bank live in the Bronx), a
|
||
100-pocket trench coat, and 30 subway rides between six boroughs (Bronx,
|
||
Ghetto, Central Park, Manhattan, Coney Island, Brooklyn); each ride rerolls
|
||
the six prices plus one 0…20 event roll.
|
||
- **Market** (Dell's iconic bands): Cocaine 15000–30000 · Heroin 5000–14000 ·
|
||
Acid 1000–4500 · Weed 300–900 · Speed 90–250 · Ludes 10–60, bent by events:
|
||
cheap heroin at 850–1999, "Cops made a big bust!" heroin at 18000–42999,
|
||
$80,000+ cocaine manias, $2 pharmacy-raid ludes, weed and acid floods, a
|
||
subway mugging (keep 2/3), $200-coat and $400-gun offers (Baretta /
|
||
.38 Special / Saturday Night Special), free drugs on a dead dude — and the
|
||
weed on the sidewalk that always ends in one last wild trip.
|
||
- **Officer Hardass**: carrying 50+ units can trigger a chase — run (50/50;
|
||
escaping rerolls the day, possibly straight into another event) or fight
|
||
with a gun; every fight round draws return fire (+3 wounds, 50 = death),
|
||
and dropping the whole squad loots Hardass's body ($750–1999) with a
|
||
$1,000 doctor offer if you can afford it.
|
||
- **Scoring**: your **final net worth in dollars** (cash + bank − debt) is
|
||
the high score — "$13.4M" beats "$2.1M", the way a trading game should
|
||
brag. (Dell's `√(net ÷ 31.5)` 0–100 rating is still computed in the sim
|
||
for the curious; the old 0–100 stored best migrates to $0 once.)
|
||
- **The market grows with you (remake extension).** Below $100k net worth
|
||
the game is exactly the classic. Cross **$100k** and the ludes slot
|
||
retires — any stock is bought out at yesterday's price — and **METH**
|
||
moves in at $2,000–16,000, the widest swing on the board. Cross **$1M**
|
||
and speed retires for **CHINA WHITE** at $40,000–160,000, the whale
|
||
product that dwarfs even a cocaine mania. Shifts are one-way, announced
|
||
as street-word cards on arrival, and bring their own events on formerly
|
||
idle rolls of the 0…20 table: a Jersey meth-lab explosion spikes local
|
||
product to $30–48k (the tier-2 face of the old $2-ludes roll), a superlab
|
||
dump floors meth at $400–999, and the cartel flooding the docks drops
|
||
China White to $8–20k. The dead-dude loot names the tier's product —
|
||
yes, you can find china white on a dead dude in the subway.
|
||
- **The streets got real (round-5 extensions).** Each borough now prices its
|
||
own way — multipliers on the daily band rolls (Bronx neutral; event prices
|
||
are absolute news and ignore the bias): heroin and speed run cheap in the
|
||
Ghetto, acid and weed in the Park, everything's sleepy-cheap on Coney,
|
||
Manhattan's rich buyers pay up to +30%, Brooklyn's fences pay a little
|
||
over — so routing (buy in the Park, sell in Manhattan) is a real strategy,
|
||
and the subway sheet captions each borough's economy. Some days **word on
|
||
the street** names a product and a borough for tomorrow — ride there to
|
||
find out if the tip was good (×3 spike or ÷3 glut) or street garbage
|
||
(about 1 in 4). And the debt finally has teeth: run a **$15,000+ tab past
|
||
day 10** and you get one warning before the shark's two leg-breakers start
|
||
jumping you — the classic chase engine with his collection money as loot,
|
||
amber sodium strobe, and a nastier ending ("THE SHARK COLLECTED") if they
|
||
put you down. Rumors and shark muscle roll on a separate RNG stream, so
|
||
classic price/event sequences per seed stay byte-identical.
|
||
- **Month lengths**: 30 / 60 / 90 days or **endless** on the ready screen —
|
||
endless has no clock and posts no score (interest caps keep marathon runs
|
||
from overflowing). Amount sheets have a MAX chip, and tapping the number
|
||
opens an in-game keypad to type any amount directly (DONE trims to the
|
||
limit).
|
||
- **Engine quirks kept**: the dead-dude loot roll can never grant cocaine
|
||
(`int(rand*5)` is 0…4 over the cheap-to-dear order); the shark fronts at
|
||
most $5,000 *per visit* but unlimited visits; the final ride ends the month
|
||
with no fresh roll. One NerdWars quirk was *dropped* with the re-theme:
|
||
trading matched items **by price** (`If F==C …`), which could fill/empty
|
||
several pockets at once — no longer authentic to the classic fiction, so
|
||
trading is by item, the way Dell's original worked (the harness pins the
|
||
new behaviour with a regression test).
|
||
|
||
The scene wraps it in a night-city board — skyline silhouettes with lit
|
||
windows, sodium-lamp glow, gradient market rows with day-over-day ▲▼ movement
|
||
arrows and reroll flashes (arrows sit out a tier-shift day, since yesterday's
|
||
prices belong to retired products) — plus quantity-chip trade sheets,
|
||
SUBWAY / SHARK / BANK / END actions, the original's Pause screens as
|
||
tap-through event cards, and a RUN / FIGHT chase overlay under red/blue
|
||
strobe light. The ready screen states the rules as a plain bulleted list and
|
||
carries the 30/60/90/∞ month picker. Sim verified by a 133-assertion
|
||
standalone harness covering the classic engine end-to-end plus every
|
||
extension: tier mechanics (bands, liquidation, one-way + double promotion,
|
||
tier events and their tier-1 no-ops, tier-aware loot naming), borough bias
|
||
math and event-absolute pricing, rumor spawn/payout/garbage/missed/final-day
|
||
gating, the shark warning → chase → loot/death paths, and month-length /
|
||
endless / interest-cap behaviour.
|
||
|
||
## The HD art pass
|
||
|
||
A collection-wide visual up-level (round 3 of feedback: "still a little too
|
||
simple… as if they are straight ports"). Shared toolkit in `SceneArt.swift`:
|
||
radial glow textures, gradient panel textures, programmatic particle emitters
|
||
(spark bursts, thrust/trail flames, ambient dust), vignettes, screen-shake and
|
||
flash actions. Per game, all render-layer only — every sim stays verbatim:
|
||
|
||
- **Lander**: full-bleed field; terrain rebuilt as gradient rock with speckle
|
||
grain and a lit crust hugging the skyline, over a distant ridge silhouette;
|
||
particle exhaust jets + engine glow instead of triangle flames; pulsing pad
|
||
light-cone and sequenced approach beacons; touchdown dust ring; crash
|
||
flash + spark burst + tumbling debris + screen shake; nebula blooms,
|
||
two-depth starfield, drifting dust, vignette.
|
||
- **Phoenix**: full-bleed field (2× position / 1.25× sprite stretch); sprites
|
||
shaded top-lit so they read as bodies, not flat clusters; engine trail and
|
||
banking tilt on the ship; particle explosions; screen shake + red flash on
|
||
hits; WAVE / BOSS banners; two scrolling star layers over static far stars.
|
||
- **ZMercury**: full-bleed canyon (1.9× / 1.35×); terrain columns re-rendered
|
||
with glowing rim pixels on every air-facing edge over dark rock; a slow
|
||
stalactite/stalagmite silhouette band behind the real walls; engine trail,
|
||
scrape sparks + shake, kill sparks synced to the original explosion frames,
|
||
and a proper going-out blast.
|
||
- **Dope Wars**: built HD from the start (see its section).
|
||
- **ZTetris**: untouched — it set the bar.
|
||
|
||
## Porting notes
|
||
|
||
Tip from the ZTetris port: the 1990s sources use extended-ASCII + CRLF, which
|
||
makes `grep` treat them as binary — strip with
|
||
`tr -d '\r' < FILE | tr -c '[:print:]\n\t' '?'` first, then the ASM tables
|
||
(pieces, speeds, scoring) can be read and ported directly.
|
||
|
||
NerdWars (the Dope Wars engine) arrived as a `.85p` Graph Link file rather
|
||
than source — but that format's ASCII mode stores TI-85 BASIC nearly as plain
|
||
text, so a ~20-line decoder mapping the few special bytes (0xD6 newline,
|
||
0x1C the STO→ arrow, 0x19 ≥, 0x1A negate, 0x10 √) recovers the entire
|
||
listing.
|
||
|
||
## Notes
|
||
|
||
- Portrait-only, status bar hidden, targets iOS 17+.
|
||
- The app icon is generated by `scripts`-free CoreGraphics (see the git history
|
||
/ the 1024px asset in `Assets.xcassets`).
|
||
- `#if DEBUG` launch hooks exist for screenshots/tests and are stripped from
|
||
Release builds:
|
||
- `ARCADE_DIRECT_GAME=<id>` — open straight into a game.
|
||
- `ARCADE_AUTOPLAY=1` — start the run immediately (any game).
|
||
- `ARCADE_DEMO=1` — freeze a staged mid-game pose (any game).
|
||
- `ARCADE_DEMO_VIEW=buy|chase|tier3|over|ride|keypad|sharkchase|endless` —
|
||
with Dope Wars' demo, pose the buy sheet, cop chase, tier-3 board
|
||
(Meth + China White), net-worth game-over, borough-captioned subway
|
||
sheet, amount keypad, leg-breaker chase, or an endless-mode board.
|
||
- `ARCADE_SHOP=1` — open Phoenix's shop stocked with cash.
|
||
- `ARCADE_GAMEOVER=1` — pose Phoenix's death card mid-campaign (progress score).
|
||
|
||
e.g. `SIMCTL_CHILD_ARCADE_DIRECT_GAME=lander xcrun simctl launch booted com.albanese.arcade85`
|