a summary of y's investigation with Taito's 1998 arcade game Land Maker (ランドメーカー), the last title for the f3 system hardware.
|🎎 \{unless otherwise noted, rom addresses are for version 2.01 (`landmakrj`).
see the \link[#shifts]{2.01J -> 2.02O program shifts} table for translation to 2.02 addresses.}|
- \link[#unused]{unused content, etc.}
- \link[#check-menu]{check menu}
- \link[#alternate-difficulty-menu]{alternate difficulty menu}
- \link[#4-player-switch-test]{4 player switch test}
- \link[#alternate-sound-test]{alternate sound test}
- \link[#running-debug]{running debug}
- \link[#attack-portrait-test]{attack portrait test}
- \link[#p1-autoplay]{p1 autoplay}
- \link[#map-data-edit]{MAP DATA EDIT}
- \link[#location-test-text]{location test text}
- \link[#unused-attack-pattern]{unused attack pattern}
- \link[#music-names]{music names}
- \link[#sample-names]{sample names}
- \link[#sequencer-software]{sequencer software}
- \link[#various-unused-code]{various misc. unused code}
- \link[#unused-prng]{unused 16-bit prng?}
- \link[#counter-test]{counter test?}
- \link[#unused-sprites]{unused sprites}
- \link[#early-items]{early items}
- \link[#tile-designs]{tile designs}
- \link[#color-change]{adjacent piece color change}
- \link[#pusher-wall-extension]{pusher wall extension}
- \link[#select-screen]{select screen}
- \link[#character-sprites]{character sprites}
- \link[#katakana-title]{larger katakana title}
- \link[#backgrounds]{unknown backgrounds}
- \link[#opening]{opening}
- \link[#mechanics]{mechanics}
- \link[#terminology]{terminology}
- \link[#tile-bag-rng]{tile bag and rng}
- \link[#damage-pushback]{damage and pushback}
- \link[#pushback]{pushback}
- \link[#natural-push]{natural push}
- \link[#arrow-item-behavior]{arrow item behavior}
- \link[#rank-calculation]{rank calculation}
- \link[#vs-stage-selection]{2p vs stage selection}
- \link[#artifacts]{artifacts}
- \link[#patents]{patents}
- \link[#flyer]{flyer}
- \link[#magazines]{magazines}
- \link[#instruction-card]{control panel instruction card}
- \link[#taito-universe-trading-card]{taito universe trading card}
- \link[#fanart]{fanart}
- \link[#staff-credits]{staff}
- \link[#maps]{rom maps}
- \link[#shifts]{2.01J -> 2.02O program shifts}
- \link[#emulation-notes]{emulation notes}
#[unused] unused content etc.
##[check-menu]{check menu}
!https://qcs.shsbs.xyz/api/File/raw/biniz[320x232]
the graphic check menu is already covered well by https://sudden-desu.net/entry/unused-menus-in-land-maker under "Check Menu"
by the way, "SCP" is a typo. should be SCR, referring to tilemaps.
interestingly, the format of the graphic tables used by the menu are different from other f3 games:
land maker interleaves the block definition address and filename (array of structs), while e.g. puchi carat, arabian magic, arkanoid returns, recalhorn, puzzle bobble 4, and bubble bobble ii have separate arrays for the addresses and filenames (struct of arrays).
(the array of associated palette pointers is still separate in land maker.)
##[alternate-difficulty-menu]{alternate difficulty menu}
see https://sudden-desu.net/entry/unused-menus-in-land-maker under "Alternate Difficulty Menu"
##[4-player-switch-test]{4 player switch test}
!https://pbs.twimg.com/media/EjePAEGVcAA2a0f?format=png&name=orig[320x232]
https://pbs.twimg.com/media/EjePAEHUcAAfu5H?format=png&name=orig[normal menu, for comparison]
unused code for a 4 player version of the switch test menu exists along with the normal switch test, likely retained due to the service menu being common code.
##[alternate-sound-test]{alternate sound test}
not necessarily unused, but... hold **SERVICE 1** while selecting the sound test from the test mode main menu to enter an alternate sound test with per-track volume controls for the sequenced music.
!https://qcs.shsbs.xyz/api/File/raw/qficw[320x232]
it seems a little buggy, though.
##[running-debug] running debug
!https://qcs.shsbs.xyz/api/File/raw/lgevk[320x232]
pop-up debug/test menu like in many other f3 games.
TILT: toggle [PAUSE]
hold **SERVICE 1** + press **TILT**: bring up popup [EDIT] menu
#### [PAUSE]
**P1 BUTTON 3**: (press) advance one frame
**P2 BUTTON 3**: (while held) advance frames
#### [EDIT]
**UP/DOWN**: navigation
**LEFT/RIGHT**: navigation in submenus
**BUTTON 1**: select/set
**BUTTON 2:** back/cancel
EXIT: exit the menu
SLOW LEVEL: left/right to set delay between frames
COLOR EDIT: edit color ram
DISPLAY: flip the vertical display orientation
TEST MODE: enter service menu
RESET: reset
#### [SLOW]
mode indicator displayed during delay
### mame cheat
the entry point, `$8CD70` which handles printing the mode, should be called by `$8DF32` right before the call to display credit count.
you'll also need to prevent the tilt error behavior.
(2.01)
```xml
<cheat desc="Running Debug">
<comment>note: this replaces service switch handling</comment>
<script state="run">
<action>maincpu.mw@8DF34=0xEE3C</action>
</script>
<script state="off">
<action>maincpu.mw@8DF34=0x0104</action>
</script>
</cheat>```
```xml
<cheat desc="disable tilt error">
<script state="run">
<action>maincpu.mw@008FA=0x00BE</action>
</script>
<script state="off">
<action>maincpu.mw@008FA=0x014A</action>
</script>
</cheat>```
##[attack-portrait-test] attack portrait test
`$94EE6` is a disabled function that cycles through attack portrait animations when the respective player's **B2** is pressed.
we can re-enable it in its former calling task at `$94EBC` easily:
2.01
```xml
<cheat desc="Attack Portrait Test Routine">
<comment>during a match, p1 B2 and p2 B2 will cycle through attack portrait wipes</comment>
<script state="run">
<action>maincpu.mw@94EC6=0x611E</action>
<action>maincpu.mw@94EC8=0x617C</action>
</script>
<script state="off">
<action>maincpu.mw@94EC6=0x6100</action>
<action>maincpu.mw@94EC6=0x007E</action>
</script>
</cheat>```
##[p1-autoplay] p1 autoplay
near `$9C108` is (still active! task at `$9BEE0`) code that, when **P1 UP+P2 UP** are pressed, sets a demo autoplay mode flag.
**SERVICECOIN + TILT** clears the flag.
the code that handles the flag exists (`$9C132`) but is unused. the correct caller is a fairly high priority task, /not/ the function nearby: when called correctly it should constantly insert credits and continue on a loss, but the nearby code is only active during the game round.
possibly for a demonstration mode while in development? the autoplay ai properties are hardcoded: 'thinking' delay is 0 and the level is 4.
### mame cheat: (incorrect) autoplay demo
|⚠ this cheat is an /easy/ patch for demonstration, and **not the correct way to call this code**. in particular, it only runs during a round and cannot auto-continue from loss.|
2.01
```xml
<cheat desc="P1 side computer play">
<comment>hold p1 UP+p2 UP during a match to activate, TILT to deactivate. on deactivation, computer control remains in effect until end of round.</comment>
<script state="run">
<action>maincpu.mw@9C130=0x4E71</action>
</script>
<script state="off">
<action>maincpu.mw@9C130=0x4E75</action>
</script>
</cheat>```
##[map-data-edit] MAP DATA EDIT
!https://qcs.shsbs.xyz/api/File/raw/31950[320x232]
there is task code for a (partially functional) stage pattern editor from `$9F218` to at least `$9F72E`, possibly through `$9F9C3`.
however, the routine is unconnected, and has several strange patterns.
possibly missing tables, more unreferenced task loops interspersed, empty functions...
the task is called along with some other functions in debug-related code:
`$6986` to play the opening
`$698E` to map edit
`$6996` to (unknown, possibly map edit-related or for testing map)
`$699E` to run the teach demo (? uses `jsr` instead of `trap` to create task and yield)
so it's possible that these would be accessible from some kind of debug menu, but the code to create them as tasks is missing(?)
#### controls
**P1 B3**: cycle color
**P1 JOY**: grid position
**P1 B1**: place tile
**P1 B2**: recalculate coordinates?
---
**P2 B3**: clear board
**P2 UP/DOWN**: change some kind of address
**P2 START**: toggle SCROLL/START edit mode ?
**P2 B2**: `$9F560()` ?
##[location-test-text] location test text
at `$9113A`, a function to print a location test message, similar to other taito games.
!https://qcs.shsbs.xyz/api/File/raw/uxman[320x232]
```none
THANK YOU FOR PLAYING UP TO THIS STAGE.
YOU ARE A VERY GOOD PLAYER, AREN'T YOU?
BECAUSE THIS GAME IS NOW UNDER LOCATION
TEST, WE ARE VERY SORRY NOT TO SHOW YOU
THE NEXT STAGE OF THE GAME.
WE ARE TERRIBLY SORRY FOR THIS AND
HOPE TO SEE YOU AGAIN,
SOMETIME AND SOMEPLACE. ```
### mame cheat: use location test message after practice stage 3
2.01
```xml
<cheat desc="Practice Use LocTest Text">
<script state="run">
<action>temp0=maincpu.md@91026</action>
<action>maincpu.md@91026=0x60000112</action>
</script>
<script state="off">
<action>maincpu.md@91026=temp0</action>
</script>
</cheat>```
##[unused-attack-pattern] unused attack pattern
there is an unused piece damage attack pattern at `$AC2F2`
!https://qcs.shsbs.xyz/api/File/raw/hwvlq[large]
it shows some similarities to ranju's final pattern:
!https://qcs.shsbs.xyz/api/File/raw/32173
there is no respective data for the select screen attack pattern preview, which uses a different format.
#### mame cheat: aifa use unused attack pattern
(in practice mode, the opponents use an entirely different set of attack patterns)
2.01
```
<cheat desc="(non-practice) aifa use unused nuisance pattern">
<script state="on">
<action>maincpu.mw@AB14C=C2F2</action>
</script>
<script state="off">
<action>maincpu.mw@AB14C=B3C2</action>
</script>
</cheat>
```
2.02
```
<cheat desc="(non-practice) aifa use unused nuisance pattern">
<script state="on">
<action>maincpu.mw@AB5AC=C752</action>
</script>
<script state="off">
<action>maincpu.mw@AB5AC=B822</action>
</script>
</cheat>
```
##[music-names] music names
https://forums.insertcredit.com/d/9-lets-share-some-game-music/236
>[FlutterSprite] I don’t think there’s any official track order or track names
the arcade rom gives the following names for sequence data:
\spoiler[internal sequence name list]{
found at `$C3886C`, some kind of sequence header data. each entry is 168 bytes, which includes 4 bytes (sequence length?) followed by 16 chars sequence name. after some more header information is a series of 14 byte sequence track events(?).
n.b.: much of the text on the audio cpu has a dirty 8th bit (possibly formatting control for a display?) that needs to be masked off to read properly in ascii
```
Sequence-00
Sequence-01
Sequence-02
SELECT_R
BOSS_RI
BOSS_RL
MAP_R
Sequence-07
PUSH
SOUMEI2
Opening
Ending
HIRYU_I
HIRYU_L
Sequence-14
AIFA
SOUMEI_I
SOUMEI_L
Sequence-18
RENKI
YOUEN_R
ROHKO
RINRE_I
RINRE_L
Sequence-24
ROUCHI
LAST
```
(suffixes `_I` and `_L` indicate intro and loop sections for the same song)
placeholder sequence names (Sequence-##) most likely do not have leftover sequence data associated.}
"reZonance world〜ZUNTATA 30th ANNIVERSARY〜 L'ab-normal Limited 3" included the tracks
>{19.ランドメーカー (アーケード) SELECT BGM
20.ランドメーカー (アーケード) R1 BGM
21.ランドメーカー (アーケード) R2 BGM
22.ランドメーカー (アーケード) R3 BGM
23.ランドメーカー (アーケード) R4 BGM
24.ランドメーカー (アーケード) R5 BGM
25.ランドメーカー (アーケード) R6 BGM}
"R1" being 'round 1' i.e. hiryu's stage theme.
rinrei and roushinshi's stages (as well as other music) weren't present. it's not clear why.
the audio cpu, sound test, and what exists on reZonance world agree on sequence order.
|snd #|internal (adapted)|reZonance world|y's description|[#]
| 4E| SELECT | SELECT BGM | |
| 4F| BOSS | | final round(s) |
| 50| MAP | | map screen intermission |
| 51| PUSH | | instruction explanation |
| 52| SOUMEI2 | | high score table |
| 53| Opening | | |
| 54| Ending | | credits |
| 55| HIRYU | R1 BGM | hiryu stage theme |
| 56| AIFA | R2 BGM | aifa stage theme |
| 57| SOUMEI | R3 BGM | soumei stage theme |
| 58| RENKI | R4 BGM | renki stage theme |
| 59| YOUEN | R5 BGM | youen stage theme |
| 5A| ROHKO | R6 BGM | kouko stage theme |
| 5B| RINRE | | rinrei stage theme |
| 5C| ROUCHI | | roushinshi stage theme |
| 5D| LAST | | map intermission before last stage |
in 2p vs, music is determined by player character selection.
it would be appropriate to consider them respective character themes.
###[furukawa-credit] norihiro furukawa composition credit
https://twitter.com/nakayamaraiden/status/100012318167015424
>{ランドメーカーってタイトルデモ曲だけ自分が書いてたようなw}
https://twitter.com/nakayamaraiden/status/700640597476913153
>{そういえばタイトーのアドバタイズデモというと業務用の「ランドメーカー」のアドバタイズデモ曲はアテクシ担当でした(この一曲だけ)。}
norihiro furukawa (@nakayamaraiden) has claimed to have only composed the opening attract demo theme,
~~but y wonders, because of the similar name formatting, if he composed "Ending" as well~~ (pure speculation)
(2023-06-16 update:)
https://twitter.com/nakayamaraiden/status/1669648174544461824
>{アトラクトのみです。エンディングは書いた記憶ないですね…。}
"Attract only. I don't remember writing the ending...."
sorry for the misunderstanding!
##[sample-names] sample names
at the beginning of each bank is a table of instrument/sample names and the offset to the parameters for the first split.
\spoiler[on extracting samples from ensoniq sample rom]{\b{(the following examples ignore padding(?) bytes in the ensoniq rom)}
`80 [oo oo NN NN NN NN NN NN NN NN NN NN NN NN] ...`
the sample offset/name table is followed by `00 00 00 00` sentinel, then the split parameters
```c
SampleParameters {
?int16 base_freq; // in multiples of semitones, sign affects interpretation?
uint24 start_ofs; // where the sample starts in the bank
uint8 key_range_end; // highest appropriate midi key to play split at
uint24 loop_start;
uint8 loop_type; // 0=nonlooping. for es5505, 1,2,4=unidirectional, 3=bidirectional
uint24 loop_end; // loop end point (integer part)
uint8 loop_end_frac; // (?) possibly fractional part of loop end position
}```
if key_range_end < 127, additional instrument splits follow.
8 bit mono pcm.
mame uses fixed point 20.9 for sample positions.
https://github.com/mamedev/mame/blob/ae373baa246e69a52e6e8249e6e8c7897ba1e1fe/src/devices/sound/es5506.h#L236
problems: how do we convert to something preserving fractional loop points...
after determining a midi note to play at, `$C1946C` - `C194D6` determines freqcount to send to es5505 for playback.
something like this...
```asm
00c1946c 1038d834 move.b (PLAY_NOTE).w,D0b
;; at this point PLAY_NOTE is a midi note << 8, e.g. 0x3C00
;; A6 is the first split's SampleParams for the instrument
loop_find_split_for_note:
00c19470 b02e0005 cmp.b (pSampleParams->key_range_end,A6),D0b
00c19474 6306 bls.b found_split
00c19476 dcfc000e adda.w #0xe ,pSampleParams
00c1947a 60f4 bra.b loop_find_split_for_note
found_split:
00c1947c 294e001a move.l pSampleParams ,(#0x1a ,A4 )
00c19480 302c009a move.w (unk_A4->note ,A4 ),D0w ; same as PLAY_NOTE
00c19484 d056 add.w (pSampleParams->base_freq ),D0w
00c19486 6a28 bpl.b frequency_positive
00c19488 b07cb800 cmp.w #0xB800 ,D0w ; D0 = max(0xB800, D0)
00c1948c 6c04 bge.b no_clamp
00c1948e 303cb800 move.w #0xB800 ,D0w ; -0x4800, 6 octave range per split?
no_clamp:
00c19492 4241 clr.w octave
count_octaves_n:
00c19494 5241 addq.w #0x1 ,octave
00c19496 d07c0c00 add.w #0xC00 ,D0w
00c1949a 6bf8 bmi.b count_octaves_n
00c1949c e248 lsr.w #0x1 ,D0w
00c1949e c07cfffe and.w #0xFFFE ,D0w
00c194a2 207c00c0 movea.l #NEG_NOTE2FREQ_LUT ,A0 ; pow(pow(2,1/12),D0w/64)*1024
9e6c
00c194a8 30300000 move.w (0x0 ,A0 ,D0w *0x1 ),D0w
00c194ac e268 lsr.w octave ,D0w ; multiply by octaves
00c194ae 6026 bra.b freqcount_end
;; land maker's samples don't use this route
frequency_positive:
00c194b0 b07c5400 cmp.w #0x5400 ,D0w
00c194b4 6f04 ble.b no_clamp_p
00c194b6 303c5400 move.w #0x5400 ,D0w
no_clamp_p:
00c194ba 72ff moveq #-0x1 ,octave
count_octaves_p:
00c194bc 5241 addq.w #0x1 ,octave
00c194be 907c0c00 sub.w #0xc00 ,D0w
00c194c2 6af8 bpl.b count_octaves_p
00c194c4 e240 asr.w #0x1 ,D0w
00c194c6 c07cfffe and.w #0xFFFE ,D0w
00c194ca 207c00c0 movea.l #POS_LUT ,A0 ; this table is different
a46c
00c194d0 30300000 move.w (0x0 ,A0 ,D0w *0x1 ),D0w
00c194d4 e360 asl.w octave ,D0w
freqcount_end:
00c194d6 3940007a move.w D0w,(#0x7a ,A4) ; write to FC reg later```
https://github.com/y-ack/landmaker-color-mod/blob/main/scripts/samples.rb#L40
}
by bank:
#### 0x400000
\spoiler{|`SE01 `|
|`SE02 `|
|`SE03 `|
|`SE04 `|
|`SE05 `|
|`SE06 `|
|`SE07 `|
|`SE08 `|
|`SE09 `|
|`SE10 `|
|`SE11 `|
|`SE12 `|
|`SE13 `|
|`SE14 `|
|`SE15 `|
|`SE16 `|
|`SE17 `|
|`SE18 `|
|`SE19 `|
|`SE20 `|
|`SE21 `|
|`SE22 `|
|`SE23 `|
|`SE24 `|}
#### 0x500000
\spoiler{|`KETTEI `|
|`CRAR `|
|`DANSA `|
|`GAGE `|
|`KOGEKI `|
|`SHOU1 `|
|`SHOU2 `|
|`SHOU3 `|
|`WARN `|
|`52SE-1 `|
|`52SE-3 `|
|`52SE-4 `|
|`52SE-5 `|
|`EFF1 `|
|`SINE `|}
#### 0x600000
\spoiler{|`F-BRONZE `|
|`F-SILVER `|
|`F-GOLD `|
|`F-PLATINA `|
|`F-NO `|
|`F-READY `|
|`F-GO `|
|`F-MAP1 `|
|`F-MAP2 `|
|`F-MAP3 `|
|`F-MAP4 `|
|`F-DANGER `|
|`RASOLOOT `|
|`SCI FI `|
|`SOUBEAT `|
|`ROHBEAT2 `|}
#### 0x700000
\spoiler{|`M-BRONZE `|
|`M-SILVER `|
|`M-GOLD `|
|`M-PLATINA `|
|`M-NO `|
|`M-READY `|
|`M-GO `|
|`M-MAP1 `|
|`M-MAP2 `|
|`M-MAP3 `|
|`M-MAP4 `|
|`M-DANGER `|
|`SOUVOICE1 `|
|`SOUVOICE2 `|
|`SOUVOICE3 `|
|`SOUVOICE4 `|
|`SOUVOICE5 `|
|`SOUVOICE6 `|}
#### 0x800000
\spoiler{|`54-1 `|
|`19 `|
|`28-1 `|
|`38-1R `|
|`SYNC LEAD2 `|
|`SHARPY `|
|`FIZZY `|
|`MOVIN HIT `|}
#### 0x900000
\spoiler{|`ANA ERA `|
|`CHORAL `|
|`CLUB HIT `|
|`EURO STAB `|
|`FAT STACK `|
|`FLY CHORD `|
|`MAJOR RAVE `|
|`MINOR RAVE `|
|`MOD TRAN `|
|`MONSTO `|
|`OLD STR `|
|`RAVE HIT `|}
#### 0xA00000
\spoiler{|`UNI `|
|`JUPI SYNTH1 `|
|`ZITER2 `|
|`ZITER3 `|
|`TAIKO1 `|
|`TAIKO2 `|
|`TAIKO3 `|
|`SYAKUJYO `|
|`TIMBARS `|
|`PONDR2 `|
|`KON1 `|
|`KON2 `|
|`BATA-D `|
|`HIRYU1 `|
|`HIRYU2 `|
|`HIRYU3 `|
|`HIRYU4 `|
|`HIRYU5 `|
|`HIRYU6 `|
|`HIRYU7 `|
|`HIRYU8 `|
|`HIRYU9 `|
|`HIRYU10 `|}
#### 0xB00000
\spoiler{|`ROHBEAT1 `|
|`ROHVOICE1 `|
|`ROHVOICE2 `|
|`ROHVOICE3 `|
|`ROHVOICE4 `|
|`ROHVOICE5 `|
|`ROHVOICE6 `|}
#### 0xC00000
\spoiler{|`CYN 1 `|
|`DANCE KICK `|
|`ENSO SN4 `|
|`EX SNARE `|
|`GONG CYN `|
|`RAP KICK `|
|`TAMB `|
|`909 KICK `|
|`909 SNARE `|
|`SIMMONS `|
|`BAKICK `|
|`T-HATO `|
|`PI `|
|`HIHATC `|
|`HIHATO `|
|`+EX HI TOM `|
|`+EX LOW TOM `|
|`808 KICK `|
|`808 SNARE `|
|`808 HATC `|
|`808 HATO `|
|`+CHA `|
|`+GILO `|
|`+RIM SHOT `|
|`+RIDE `|
|`CRAP2 `|
|`PONDR1 `|
|`SNARE PP `|
|`FX1 `|
|`FX2 `|
|`FX5 `|}
#### 0xD00000
\spoiler{|`ANAPAD `|
|`L212-9 `|
|`LBUZZ 5TH `|
|`LFM6+7 `|
|`MEM BASS2 `|
|`MG BASS PL `|
|`+RHODES 2B `|
|`+FM BASS 1 `|
|`+E BASS 28 `|
|`29 SLAP BASS`|
|`5THGT `|
|`+MINI VIOLIN`|
|`38 OBOE `|
|`25 ACOU BASS`|
|`30 FRETLESS `|
|`+NOISE 1 `|
|`+NOISE 2 `|
|`STRAT GUIT2 `|
|`BELL V `|
|`ALASKA `|
|`J-8 HARP `|
|`D-STR `|
|`MIAMI BRASS `|}
#### 0xE00000
\spoiler{|`PAMERA `|
|`ELIP `|
|`SAW LEAD EX `|
|`BRNS `|
|`SYNB-V `|
|`CLR `|
|`HARP `|
|`+MARIMBA `|
|`TAKAGT4 `|
|`ACOGT `|
|`ZITER1 `|
|`EDR0320 `|
|`+BRASS DOWN `|
|`66 PADSAWS `|
|`+PAN FLOOT `|
|`+CLAV1 `|}
#### 0xF00000
\spoiler{|`AMB PAD2 `|
|`+FULLSTRINGS`|
|`+MOOG BASS1 `|
|`+ROCK PIANO `|
|`+ORGAN 2 `|
|`+ORGAN 3 `|
|`+SIRENS `|
|`+CLAV2 `|
|`BARAPHO `|
|`MUTE GTR `|
|`TIMP B1 `|
|`52BASS1 `|
|`52BASS5 `|
|`52BASS6 `|
|`SQUARE TONE `|
|`FIESTA `|}
## unused samples
the MAP4 voice lines can be heard in the sound test (no. 034 and 03F) but are not used ingame.
|52SE-1|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/52SE-1_127.wav||
|52SE-3|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/52SE-3_127.wav||
|52SE-5|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/52SE-5_127.wav||
|F-MAP4|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/F-MAP4_127.wav|intended playback at C#3|
|SCI FI|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/SCI%20FI_127.wav||
|ROHBEAT2|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/ROHBEAT2_127.wav||
|M-MAP4|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/M-MAP4_127.wav||
|FIZZY|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/FIZZY_127.wav||
|MOVIN HIT|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/MOVIN%20HIT_127.wav||
|ANA ERA|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/ANA%20ERA_127.wav||
|EURO STAB|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/EURO%20STAB_127.wav||
|FAT STACK|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/FAT%20STACK_127.wav||
|FLY CHORD|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/FLY%20CHORD_127.wav||
|MAJOR RAVE|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/MAJOR%20RAVE_127.wav||
|MINOR RAVE|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/MINOR%20RAVE_127.wav||
|ZITER3|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/ZITER3_127.wav||
|TIMBARS|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/TIMBARS_127.wav||
|PONDR2|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/PONDR2_127.wav||
|RAP KICK|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/RAP%20KICK_127.wav||
|+CHA|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/+CHA_127.wav||
|+GILO|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/+GILO_127.wav||
|+RIM SHOT|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/+RIM%20SHOT_127.wav||
|FX1|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/FX1_127.wav||
|FX2|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/FX2_127.wav||
|FX5|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/FX5_127.wav||
|ANAPAD|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/ANAPAD_127.wav||
|LBUZZ 5TH|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/LBUZZ%205TH_127.wav||
|MG BASS PL|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/MG%20BASS%20PL_127.wav||
|+E BASS 28|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/+E%20BASS%2028_127.wav||
|5THGT|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/5THGT_127.wav||
|+MINI VIOLIN|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/+MINI%20VIOLIN_127.wav||
|38 OBOE|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/38%20OBOE_68.wav|3 splits|
|+NOISE 1|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/+NOISE%201_127.wav||
|+NOISE 2|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/+NOISE%202_127.wav||
|STRAT GUIT2|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/STRAT%20GUIT2_63.wav|2 splits|
|MIAMI BRASS|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/MIAMI%20BRASS_127.wav||
|ELIP|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/ELIP_127.wav||
|SAW LEAD EX|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/SAW%20LEAD%20EX_127.wav||
|CLR|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/CLR_127.wav||
|+BRASS DOWN|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/+BRASS%20DOWN_127.wav||
|52BASS1|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/52BASS1_127.wav||
|52BASS5|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/52BASS5_127.wav||
|TIMP B1|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/TIMP%20B1_127.wav||
|FIESTA|!https://qcs.shsbs.xyz/resources/audio/landmaker/samples/FIESTA_127.wav||
##[sequencer-software] sequencer software
|🎎 to do: this needs a /lot/ more research|
(in addition to sequence playback) the audio cpu contains a lot of code and strings for what looks like a full sequencer.
#### `$C058C8`
offsets for string interpolation(function `$C0C4BA`) commands, e.g. "MIDI," "Channel," "Rename"
#### `$C05CD7`
strings constructed from interpolation:
` ENSONIQ EGOS OS Version 0.42`
`Personal Studio`
#### duart
the audio cpu writes various information out over UART as well.
`$C111D0`: duart_putchar?
`$C11276`: ensoniq_putchar? over duart
`$C11284`: ensoniq_print? over duart
\spoiler[early mame debugger duart sniffing attempt]{`wpset 280017,1,w,temp0 == 0,{temp0 = temp1; temp1 = temp2; temp2 = temp3; temp3 = temp4; temp4 = temp5; temp5 = temp6; temp6 = temp7; temp7 = temp8; temp8 = temp9; temp9 = wpdata; g}`
`wpset 280017,1,w,temp0 != 0,{printf "%c%c%c%c%c%c%c%c%c%c",temp0,temp1,temp2,temp3,temp4,temp5,temp6,temp7,temp8,temp9; temp0=0; temp1=0; temp2=0; temp3=0; temp4=0; temp5=0; temp6=0; temp7=0; temp8=0; temp9=0; g}`
!https://qcs.shsbs.xyz/api/File/raw/tqtsj
!https://qcs.shsbs.xyz/api/File/raw/slrgf}
string ` Land SE 00` @ `$D600` seems to be referenced during "Unexpected Event ID"(function $C10FEE)
##[various-unused-code] various miscellaneous unused code
|🎎 this is not a complete list!|
###[unused-prng] unused 16-bit prng?
`$00147E` (used lcg is at `$001468`)
```asm
LCG_SEED = -$77da
;; if (LCG_SEED == 0) LCG_SEED = 1
00147e move.w (LCG_SEED,A5),D0w
001482 bne.b .no_reseed
001484 moveq #1,D0
.no_reseed:
;; LCG_SEED = (LCG_SEED * 176) % 32749
001486 muls.w #176,D0
00148a divs.w #32749,D0
00148e swap D0
001490 move.w D0w,(LCG_SEED,A5)
001494 rts
```
###[counter-test] counter test?
`$9C034` counts to... various values... displaying a hexadecimal counter on the screen...
```asm
09c034 moveq #0x0,D2
09c036 ori #0x700,SR
.loop:
09c03a move.w #0xffff,D6w
09c03e bsr.w debug_count_to
09c042 move.w #0xff,D6w
09c046 bsr.w debug_count_to
09c04a move.w #0xff00,D6w
09c04e bsr.w debug_count_to
09c052 move.w #0xf,D6w
09c056 bsr.w debug_count_to
09c05a move.w #0xf0,D6w
09c05e bsr.w debug_count_to
09c062 move.w #0xf00,D6w
09c066 bsr.w debug_count_to
09c06a move.w #0xf000,D6w
09c06e bsr.w debug_count_to
09c072 bra.b .loop
09c074 rts```
after the first call of `debug_count_to(0xFFFF)`, which takes around 74 minutes, it doesn't actually stop at 0xFF. y didn't test after that.
`debug_count_to()` @`$9C076` isn't called by any other code (it's blocking, anyway).
##[unused-sprites] unused sprites
|🎎 note: `_BL_` graphic definition filename prefix is omitted for brevity in this section.|
###[early-items] early items
|!https://qcs.shsbs.xyz/api/File/raw/ivbrc|!https://qcs.shsbs.xyz/api/File/raw/rkvov|!https://qcs.shsbs.xyz/api/File/raw/jsuno|!https://qcs.shsbs.xyz/api/File/raw/jjcpn|
|ITMC_A01|ITMC_A02|ITMC_A03|ITMC_A04|
static versions of the arrow, star, moon, and flare items attached to an unused item base design.
the arrow looks very different from its final appearance.
moon and flare are closer to their final appearances, though the moon has no outline in this iteration.
another unused set of items (sans arrow) with no animation sequence exists
|!https://qcs.shsbs.xyz/api/File/raw/sepqj|!https://qcs.shsbs.xyz/api/File/raw/wgyhr|!https://qcs.shsbs.xyz/api/File/raw/mszrl|
|ITME_B02|ITME_C03|ITME_D04|
likely as placeholders for attaching a separate item top (as the final sprites are) to the item base, ITME01:
!https://qcs.shsbs.xyz/api/File/raw/osntq
(first frame of) final item designs:
|!https://qcs.shsbs.xyz/api/File/raw/ffioo|!https://qcs.shsbs.xyz/api/File/raw/pgsdz|!https://qcs.shsbs.xyz/api/File/raw/esdor|!https://qcs.shsbs.xyz/api/File/raw/jsdlb|
|ITMA01|ITMB01|ITMC01|ITMD01|
definitions `ITMD07` and `ITMD08` of the flare item are identical (i.e. reference the same 16x16 chips), and the `ITMD08` definition is unused.
###[tile-designs] tile designs
unused static tile graphics, possibly early designs? PIEAA01 is used in \link[#map-data-edit]{MAP DATA EDIT}:
|!https://qcs.shsbs.xyz/api/File/raw/mbssp|!https://qcs.shsbs.xyz/api/File/raw/yrczq|!https://qcs.shsbs.xyz/api/File/raw/bjabm|!https://qcs.shsbs.xyz/api/File/raw/skzfx|!https://qcs.shsbs.xyz/api/File/raw/aflyw|
|PIEAA01|PIEAA01A|PIEAA01C|PIEAA01G|PIEAF01|
(there is no PIEAA01[B|D|E|F] or PIEA[B-E]01)
there are 6 different tile graphics which have full animation definitions, but only 2 are used:
PITA_A (normal tile) and PITA_E (another world)
|!https://qcs.shsbs.xyz/api/File/raw/qzoxy|!https://qcs.shsbs.xyz/api/File/raw/vezmw|!https://qcs.shsbs.xyz/api/File/raw/ohlys|!https://qcs.shsbs.xyz/api/File/raw/nwret|!https://qcs.shsbs.xyz/api/File/raw/dghep|!https://qcs.shsbs.xyz/api/File/raw/mimus|
|PITA_A01|PITA_B01|PITA_C01|PITA_D01|PITA_E01|PITA_F01|
type F is present in tables used for switching between type A and E on another world state, even though that value is binary.
#### mame cheat: select tile graphic
2.01
```
<cheat desc="select tile graphic">
<comment>change the tile graphics used in non-another world play</comment>
<parameter min="0" max="5" step="1"/>
<script state="change">
<action>maincpu.mw@955E4=(6878+param*64)</action>
<action>maincpu.mw@95A54=(6E9C+param*30)</action>
</script>
</cheat>```
###[color-change] adjacent piece color change
there are two unused animation labels for the effect when a shot tile settles (conveying converting adjacent colors).
|EFXCHA@A22A4|!https://qcs.shsbs.xyz/api/File/raw/yjrzf[32x16]
|EFXCH*@A228E|!https://qcs.shsbs.xyz/api/File/raw/kizbs[64x48]
|IROTES*@A22BA|!https://qcs.shsbs.xyz/api/File/raw/wmxay[48x64]|
#### mame cheat: select tile placement effect
2.01
```xml
<cheat desc="select tile placement effect">
<comment>change the effect sprite when placing tiles</comment>
<parameter>
<item value="0x2242">IROTES (final)</item>
<item value="0x2236">EFXCH (early?)</item>
<item value="0x223C">EFXCHA (placeholder?)</item>
</parameter>
<script state="change">
<action>maincpu.mw@A21DE=param</action>
</script>
</cheat>```
###[pusher-wall-extension] pusher wall extension
when the pusher extends, the parts upboard are colored in more and more (usually very subtly, palette depends on the stage).
PUSA_C[11-13] are not referenced by game logic (the pusher cannot extend 13 levels).
`PUSA_C13`
!https://qcs.shsbs.xyz/api/File/raw/ygfjy
!https://qcs.shsbs.xyz/api/File/raw/lutrf
!https://qcs.shsbs.xyz/api/File/raw/idclh
---
!https://qcs.shsbs.xyz/api/File/raw/ejgdv
!https://qcs.shsbs.xyz/api/File/raw/mzjhn
!https://qcs.shsbs.xyz/api/File/raw/omrmz
!https://qcs.shsbs.xyz/api/File/raw/mbasp
!https://qcs.shsbs.xyz/api/File/raw/kleuq
!https://qcs.shsbs.xyz/api/File/raw/pfsto
!https://qcs.shsbs.xyz/api/File/raw/ogvmk
!https://qcs.shsbs.xyz/api/File/raw/tvora
!https://qcs.shsbs.xyz/api/File/raw/gdzvi
!https://qcs.shsbs.xyz/api/File/raw/ixraz
`PUSA_C01`
###[game-select] game mode select
|!https://qcs.shsbs.xyz/api/File/raw/hsaad|
|GSELBG02|
sprite definition of a single solid color chip from GSELBG01, the wavy space game mode select screen background (i.e., the chip itself is used, the sprite obj definition is not).
###[select-screen] select screen
|!https://qcs.shsbs.xyz/api/File/raw/byexv|
|SELSPL14|
this placeholder select icon is actually used... during frames after selecting a character where the respective icon flashes white (that is, it's rendered with an all-white palette over the original icon).
this is the palette used in the object viewer.
(also: gaira's icon is SELSPL10. there is no 11-13.)
\{|!https://qcs.shsbs.xyz/api/File/raw/cfxiy[128x128]|!https://qcs.shsbs.xyz/api/File/raw/anmef[128x128]|
|SEBGA01A|SEBGA01B|}
\{|!https://qcs.shsbs.xyz/api/File/raw/bqkcd[128x128]|!https://qcs.shsbs.xyz/api/File/raw/gvrol[128x128]|
|SEBGB01A|SEBGB01B|}
unused character select background elements.
final:
|!https://qcs.shsbs.xyz/api/File/raw/tffal[128x128]|!https://qcs.shsbs.xyz/api/File/raw/urxeu[128x128]|
|SELBGA01|SELBGB01|
near the rest of the select graphics are these:
\{|!https://qcs.shsbs.xyz/api/File/raw/nmypt|!https://qcs.shsbs.xyz/api/File/raw/lwkem|!https://qcs.shsbs.xyz/api/File/raw/kaznp|
|SELST01A|SELST01B|SELST01C|}
\{|!https://qcs.shsbs.xyz/api/File/raw/dvjvf|!https://qcs.shsbs.xyz/api/File/raw/xomzt|
|SELST02A|SELST03A|}
\{|!https://qcs.shsbs.xyz/api/File/raw/pdoro|!https://qcs.shsbs.xyz/api/File/raw/ireoi|!https://qcs.shsbs.xyz/api/File/raw/qpkmw|
|SELSTG02|SELSTG03|SELSTG04|
|!https://qcs.shsbs.xyz/api/File/raw/fpgyz|!https://qcs.shsbs.xyz/api/File/raw/noklp|!https://qcs.shsbs.xyz/api/File/raw/qlcwt|
|SELSTG05|SELSTG06|SELSTG08|
`SELSTO1A`, `SELSTO1B`, and `SELSTO1C` (not shown) are duplicate definitions to
`SELST01A`, `SELST01B`, and `SELST01C`, respectively.
it seems that at some point a stage select feature may have been planned (though it's also possible that the graphics would have just been associated with characters during character selection).
interestingly, the numbering doesn't seem to match up with the final character order.
1, 2, and 3 would be associated with hiryu, soumei, and aifa, but SELSTG04 is inappropriate for renki.
possibly:
|SELSTG04|rinrei or youen|
|SELSTG05|kouko|
|SELSTG06|rinrei or roushinshi|
|SELSTG08|renki|
there is no animation data for the SELST01 sequence,
but y shows some possible animation fanfiction for it here:
!https://qcs.shsbs.xyz/api/File/raw/gngoh
###[character-sprites] chibi character sprites
|🎎 incomplete! come back to this when animation data can be handled better. |
soumei has this rabbit-like creature encased in ice (animdata at `$E8492`):
|!https://qcs.shsbs.xyz/api/File/raw/vgyum|
|P3H1A[01-16]|
it shares the common 'frozen in ice' attack palette.
is it an easter egg? a placeholder for other frozen character sprites?
###[katakana-title] larger katakana title
|!https://qcs.shsbs.xyz/api/File/raw/gxelh|
|TLAND02|
unused in favor of the smaller TLAND03, which appears beneath TLAND01 ("LAND MAKER") on the title screen.
###[tutorial-text] tutorial/introduction text
for the after-credit mechanics introduction text, the unused TEAE_A[01-08] are the same text as TEAF_A[01-08] but with a smaller font.
four of the TEAF messages, which describe items, are unused
|TEAF_A02|!https://qcs.shsbs.xyz/api/File/raw/natwo|\{大きい建物からは
アイテム出現}|
|TEAF_A06|!https://qcs.shsbs.xyz/api/File/raw/anise|\{アイテムをうまく使おう}|
|TEAF_A07|!https://qcs.shsbs.xyz/api/File/raw/sjmgf|\{大きい建物ほど
強力なアイテム出現}|
|TEAF_A08|!https://qcs.shsbs.xyz/api/File/raw/mzvzu|\{一気に勝負をつけろ}|
(item appearance is instead explained in the attract mode teach demo.)
###[backgrounds] unknown backgrounds
\{|!https://qcs.shsbs.xyz/api/File/raw/rammv[320x240]|
|DEMS_A01|}
\{|!https://qcs.shsbs.xyz/api/File/raw/slijs[320x240]|
|DEMS_A02|}two backgrounds, similar to those used for win screen 'character land' (`KARI[01-09]`) backgrounds, unused. ranju and gaira share `KARI09`. it's not clear if these are placeholders or unused backgrounds for another character, or something else entirely(???).
###[opening] opening
|!https://qcs.shsbs.xyz/api/File/raw/klaqw[320x160]|
|O3_02D|
ice shards for soumei's sequence in the opening.
instead, individual kouko rock chunk sprites(!) (`P6H3A[01-07]`) with an ice palette are used, for random placement and independent movement.
\{|!https://qcs.shsbs.xyz/api/File/raw/pttwl[320x160]|
|OBGC_A01|}
\{|!https://qcs.shsbs.xyz/api/File/raw/xwswf[320x160]|
|OBGC_B01|}unused backgrounds for soumei's opening sequence.
instead he always appears on black or OBGE_A01 (which, by naming convention, would seem to indicate youen... nonetheless, it's used for soumei).
|!https://qcs.shsbs.xyz/api/File/raw/vxkrg[240x160]|
|OBGG_B02|
unused parallax layer for rinrei.
|!https://qcs.shsbs.xyz/api/File/raw/ddcgx[320x160]|
|OBGJ_A01|
unused opening background for gaira(!!).
kinda looks like his face... maybe intended as a teaser?
#[mechanics] mechanics
###[terminology] terminology
|pusher|this. !https://qcs.shsbs.xyz/api/File/raw/muurl|
|push damage|it goes in here and then the pusher extends. !https://qcs.shsbs.xyz/api/File/raw/pusherdamagemetersmall[56x83]|
|piece damage|it goes in here and then falls on the board as tiles. !https://qcs.shsbs.xyz/api/File/raw/mxwrl|
|natural push|when board pieces are pushed forward not as a result of push damage.|
|breaking|clearing/"popping" groups of pieces by hitting the corner.|
|color change|\{when pieces adjacent to a shot tile's settled position change to match color.
(also "color conversion," "color spread," etc.)}|
|||
|bronze structure|a 2x2 structure piece. produces an **arrow item** when broken.|
|silver structure|a 3x3 structure piece. produces a **star item** when broken.|
|gold structure|a 4x4 structure piece. produces a **moon item** when broken.|
|platinum structure|a 5x5 structure piece. produces a **flare item** when broken. sometimes abbreviated 'plat'|
|arrow item|normally, retracts the pusher wall. see \link[#arrow-item-behavior]{**arrow item behavior**} for more detail.|
|star item|eradicates from the board all pieces of whichever color breaks it.|
|moon item|changes the color of all pieces on the board to the color it is broken with.|
|flare item|\{resets the pusher and all push damage, then adds a predetermined
building pattern to the board of the same color as it was broken with.}|
##[tile-bag-rng] tile bag and rng
|⚠ tile bag and rng behavior is /known to be different/ in the arcade mode of the playstation version. |
the prng source(`$001468`) is a linear congruential generator with (m=2\sup 32, a=7, c=5).
low bits with these parameters are not suitable, so the return value has its words swapped.
```c
uint p_rand(void) {
LCG_SEED = 7 * LCG_SEED + 5;
return LCG_SEED<<16 | LCG_SEED>>16;
}```
when a round starts, both players take their own copies of the global rng state, used only when drawing tiles. this means both players can get the same sequence of tiles at the start of the round (until becoming out of phase by rerolling, when tile color pools diverge), and do not affect each others' draws.
#### get_next_tile_color() @ $93A1C
when a tile is drawn during teach demo 1 (`stage==-1`) a special sequence of tiles @ `$939B0` is used
when a tile is drawn during teach demo 2 (`stage==-2`) a special sequence of tiles @ `$939F6` is used
otherwise:
- 1) the global rng state is saved, and the current player's rng state is loaded.
- 2) whether this is an even(3a) or odd(3b) draw is checked.
- 3a) \{the draw is even: loop over the board and construct a bitset of colors present.
store this in ram (p1: `0x40715C`, p2: `0x40715E`).}
- 3b) the draw is odd: load the previously determined valid color set.
- 4) if the valid color set is empty, the color is RED, otherwise (4b)
- 4b) call p_rand until the value passes. specifically:\{
```asm
;; if a negative random word is generated
;; the lookup takes index -2=4e75 (rts)
;; and has to go around again
select_random_from_set_loop:
; do {
; color = p_rand()
jsr p_rand.l
; color = tile_ids_map[color % 7]
ext.l color
divu.w #7,color
swap color
move.w (tile_ids_map,PC,color*0x2),color
nop
nop
; return_color = color
move.w color,return_color
; } while((legal_color_bitset & 1<<color) == 0)
asr.w #1,color
btst.l color,legal_color_bitset
beq.b select_random_from_set_loop
```
```
;; 0xC is grey invalid tile color,
;; so we map to skip to 0xE (purple)
tile_ids_map:
; RED,BLUE,ORANGE,GREEN,CYAN,YELLOW,PURPLE
dc.w 0,2,4,6,8,10,14
```}
- 5) the global rng state is restored.
##[damage-pushback] damage and pushback
###[raw-damage] raw damage
raw damage for each piece is calculated at break time by `$96680`,
which runs once for each piece cleared, including the shot tile. (larger structures count as a single 'piece')
non-building tiles (including items) are worth 0.5 damage, but they are counted separately from building damage, so that leftover half-damage carries over between breaks.
single buildings are worth 1 damage,
structures are worth
`min(pusher_position, 7) * structure_level + structure_value`
where pusher position 0 is **fully retracted**, and position 1 looks like
!https://cdn.discordapp.com/attachments/455404849626873869/957277010512728104/32080.png
| |[*]STRUCTURE |[*]VALUE |[*] HEX |
|0| bronze | 8 | 8h |
|1| silver | 22 | 16h |
|2| gold | 38 | 26h |
|3| platinum | 54 | 36h |
table: damage values by structure level [1]
e.g. breaking 2 silvers (structure level=1), at pusher position 2
adds
` 2*1 + 22
` + 2*1 + 22
for **48** raw damage from structures
note that 7 push is almost all the way down the board;
large structures will not be able to take advantage of it.
assuming one did break a gold structure at 5 push, 5*2 == 10 extra raw damage.
-------------------------------------------------------------------------------
[1] internal tile level assigns nonstructure `0` and bronze starting at 2,
but level used in structure damage is `(internal level - 2)` (`$96696`)
[2] pusher row is stored as index into board, div 16 for position here.
###[damage-conversion] damage conversion
`$AB03E` applies received damage
raw damage is converted into two types of damage when it is sent to the opponent (represented by glowing orbs), 'piece damage' and 'push damage,'
but the conversion is affected by margin time.
the push damage conversion threshold starts at 9, meaning 9 raw damage is needed for 1 push damage.
when the round elapsed time reaches 60 seconds, the push damage threshold decreases by 1, and further decreases every 30 seconds after that, until a minimum push damage threshold of 4 (at 180 seconds) [1]
the remainder goes into piece damage, i.e.:
`push damage += raw damage / push threshold`
`piece damage += raw damage % push threshold`
in other words, <60s into a match, it takes 9 rawdmg for 1 push;
between 60 and 90s, 8 rawdmg is 1 push; and 180s+ is 4 dmg/push
note the modulo operator for nuisance tile damage:
remainder damage that doesn't go towards push goes into piece.
the push threshold influences nuisance tile accumulation!
if incoming push damage >= 3, the "DANGER" voice line plays.
-------------------------------------------------------------------------------
[1] (strictly speaking, this is a modifier that counts up and is subtracted from 9 at damage conversion time, but a view of `(9 - modifier)` as `push threshold` is simpler)
###[pushback] pushback
pushback(`$953A4`) is evaluated /whenever damage is sent/.
damage is sent on every frame that raw damage is >= 1.
(note that **all** breaks will send at least 1 damage; breaking an item (0.5(shot tile)+0.5(item)) or single tile (0.5+0.5) will both evaluate pushback.)
internally, pushback accumulates raw damage sent.
it can be thought of like an invisible meter.
"pusher [position]" refers to the amount of board covered/topmost line
- when pusher is at 0, the meter resets.
- when pusher is NOT at 0,
- the requirement for pushback is `REQ[pusher] + 2`
- the total raw damage this frame is added to the total accumulated pushback
- if accumulated pushback meter exceeds the requirement:
- the threshold is subtracted for the meter
- the push state is set to PUSHBACK
| |[*]REQ|[*]+2 |
|0| 15 | 17 |
|1| 15 | 17 |
|2| 13 | 15 |
|3| 9 | 11 |
|4| 6 | 8 |
|5| 4 | 6 |
|6| 2 | 4 |
|7| 1 | 3 |
|8| 1 | 3 |
|9| 1 | 3 |
table: pushback meter threshold lookup.
note that pusher 0 (and 9?) cannot actually be encountered.
- pusher 0 is fully retracted, and the threshold is not considered if damage is sent at this position
- pusher 9 is off of the board.
for help visualizing pushback meter accumulation and requirements, see scripts for mame and fbneo:
https://gist.github.com/y-ack/b17cd4a25b673dcfc7303ad8f5c60770
#### example
given a pusher position of 2 and initial accumulated pushback value of 0, a player makes two breaks: 1B+4, then 1S
at pusher 2, **15** raw damage is required to achieve pushback.
the first break, 1 bronze and 4 house pieces:
`(2*0 + 8) + (4) = 12`
12/15 is insufficient to trigger pushback
the second break, 1 silver:
`(2*1 + 22) = 24`
12 previously accumulated + 24 = 36
36/15 is sufficient to trigger pushback,
so pushback will occur this turn, and
(given that we have no incoming damage)
pusher position will be **1** for the next turn.
the pushback value vs requirement is now
21/17,
meaning the next shot that sends damage (any break) will also trigger pushback.
\spoiler[esoterics]{
fundamentally, the behavior of pushback is "sending enough damage will retreat the pusher." however, there are other subtle behaviors hidden in the undocumented mechanic:
firstly, while every breaking shot will evaluate damage, it is possible for damage to be counted over multiple frames. the most obvious case is with **star items**, where the shot tile and item are counted 40 frames before the tiles eliminated are counted.
additionally, it seems that there is some limit to the number of pieces that can be counted while sweeping over the board each frame, such that masses of single tiles send damage over multiple frames. damage being evaluated on multiple frames means pushback can be evaluated multiple times per break, and because there is no check for whether pushback state has already occurred, the pushback accumulator can drain multiple times with no benefit to the player.
this bug could be prevented by checking whether the push state is already PUSHBACK before checking the pushback requirement.
similarly, because **arrow items** 1) activate on break 2) set the same PUSHBACK state, breaking an arrow will drain pushback if possible, and unless there are tiles in the danger zone, this is essentially 'wasted' pushback.
the second behavior has to do with pushback evaluation being triggered by sending damage.
this is another separation of the actions of shooting a tile without sending damage (placing) and shooting a tile and sending damage (breaking).
no matter how much pushback 'meter' is stored up, the pusher cannot be repelled without making a breaking shot.
the other side of this is that pushback cannot be /drained/ without breaking tiles. this includes the behavior of resetting when the pusher is fully retracted.}
##[natural-push] natural push
after every shot, around the same time as acquiring the next tile,
the board is analyzed by `$98126`, calculating:
- **total visible piece count**
- counts of each color
- number of unique colors
- a bitset of colors present (redundantly, also generated by `get_next_tile_color()`?)
(the latter three seem to only be used for ai decision-making)
when a new natural push time needs to be determined (i.e. at the start of the round or **if natural push just occurred**), `$93740` is called to determine the number of shots before the next natural push.
this is based solely on the number of pieces visible on the board at the time.
|pieces on board|natural push in:|[*]
|0-9|1|
|10-14|2|
|15-19|4|
|20-24|6|
|25-29|9|
|30-34|12|
|35-39|15|
|40-44|18|
|45-49|21|
|50+|24|
##[arrow-item-behavior] arrow item behavior
arrow item and pushback (by damage accumulation) both set push state to PUSHBACK, which:
1) (if possible) reduces incoming push damage by 1
2) (if possible) moves the pusher wall back 1 row, revealing tiles
at some point **later, incoming push damage gets evaluated** and (if necessary) the pusher pushes forward once and decrements one incoming push damage.
when breaking an arrow item specifically, if there are any tiles in the red danger zone on the board, a special behavior is triggered that will skip push forward that turn, 'stalling' the pusher.
!https://qcs.shsbs.xyz/api/File/raw/mnssb[large]
figure: arrow item pusher stall conditions flow diagram
##[rank-calculation] rank calculation
a value separate from normal score, an internal 'rank score' is calculated on loss (by `$996DA`), determining the rank displayed on the end screen and, if conditions are met, the ending sequence shown.
`rank score = ((bronze*3 + silver*9 + gold*25 + platinum*60)^2) / ((15 - stages_cleared) * (continues+1))`
where structures are counted when broken/sent, and 'stages_cleared' is a stage counter that starts at 0. losing on hiryu's stage is 0, losing on aifa is 1, and so on, up to 10 for clearing gaira and 11 for clearing bonus.
\{|rank score | rank | ending |[*]
| 0 |初級(E) | D |
| 1 | 9級(E) |[x9] C|
| 2-3 | 8級(E+) |
| 4-7 | 7級(E+) |
| 8-15 | 6級(D) |
| 16-31 | 5級(D) |
| 32-63 | 4級(D+) |
| 64-127 | 3級(D+) |
| 128-255 | 2級(C) |
| 256-499 | 1級(C) |
| 500-799 | 初段(C+) |[x6] B|
| 800-1199 | 2段(C+)
| 1200-2499 | 3段(B)
| 2500-3999 | 4段(B)
| 4000-7999 | 5段(B+)
| 8000-15999 | 6段(B+)
| 16000-31999 | 7段(A) |[x4] A |
| 32000-63999 | 8段(A)
| 64000-99999 | 9段(A+)|
| 100000+ | 名人(A+)|
\spoiler[rank tables (horizontal)]{\{|[*] rank score | 0 | 1 | 2-3 | 4-7 | 8-15 | 16-31 | 32-63 | 64-127 | 128-255 | 256-499 |
|[*] rank | 初級(E)| 9級(E)| 8級(E+)| 7級(E+)| 6級(D)| 5級(D)| 4級(D+)| 3級(D+) | 2級(C)| 1級(C)|
|[*] ending | D |[10x] C |}
\{| 500- 799 | 800- 1199 | 1200- 2499 | 2500- 3999 | 4000- 7999 | 8000- 15999 | 16000- 31999 | 32000- 63999 | 64000- 99999 | 100000+ |
| 初段(C+)| 2段(C+)| 3段(B)| 4段(B)| 5段(B+)| 6段(B+)| 7段(A)| 8段(A)| 9段(A+)| 名人(A+)|
|[6x] B |[4x] A |}}
`((BRZ*3 + SLV*9 + GLD*25 + PLT*60)^2) / ((15-STAGE) * (CONTINUES+1))`
note: `cmp2` was bugged in mame prior to 0.227, causing rank and ending selection to be incorrect.
##[vs-stage-selection] 2p vs stage selection
($8E46A)
in vs mode, the stage set is selected by:
- taking the current stage number
- adding 1
- adding a random number 0-3 (inclusive)
- quantity modulo 8
```asm
;; $8E470:
jsr p_rand.l
andi.w #0x3,D0w
addq.w #0x1,D0w
add.w (stage_num,A5),D0w
andi.w #0x7,D0w ; hiryu-roushinshi
move.w D0w,(stage_num,A5)
```
that is to say that:
a) only stages in aifa, soumei, renki, and youen pools are possible in round 1,
b) given a known round 1 stage, there are only 4 stages (16 layouts) possible in the following round 2,
c) boss/bonus stage layouts will not show up in 2p vs,
d) as an independent event, hiryu stage layouts only have a 1.5625% chance of appearing without going into the tiebreaker round.
round distributions when considered independently:
!https://qcs.shsbs.xyz/api/File/raw/vrkfn[666x433;large]
!https://qcs.shsbs.xyz/api/File/raw/mdmic[666x433;large]
!https://qcs.shsbs.xyz/api/File/raw/mlecy[600x390;large]
one of **four** /layouts/ ("openers," piece sequences) in the stage's pool is later selected randomly.
#[artifacts] artifacts
##[patents] patents
- 1998-02-16 JPH11226254 (A) - BLOCK GAME MACHINE, \ruby[Tsumori]{津森} \ruby[Yasuo]{康男}, \ruby[Nakakuki]{中久木} \ruby[Seiichi]成一 (https://worldwide.espacenet.com/publicationDetails/biblio?FT=D&date=19990824&DB=&locale=&CC=JP&NR=H11226254A&KC=A&ND=1[Espacenet]) (https://patents.google.com/patent/JPH11226254A/en[Google])
- shooting/structure mechanics
- 1998-02-16 JPH11226259 (A) - BLOCK GAME MACHINE, \ruby[Tsumori]{津森} \ruby[Yasuo]{康男}, \ruby[Nakakuki]{中久木} \ruby[Seiichi]成一 (https://worldwide.espacenet.com/publicationDetails/biblio?FT=D&date=19990824&DB=&locale=&CC=JP&NR=H11226259A&KC=A&ND=1[Espacenet]) (https://patents.google.com/patent/JPH11226259A/en[Google])
- block deflection, settling
- 1998-02-17 JPH11226255 (A) - BLOCK GAME MACHINE, \ruby[Tsumori]{津森} \ruby[Yasuo]{康男}, \ruby[Nakakuki]{中久木} \ruby[Seiichi]成一 (https://worldwide.espacenet.com/publicationDetails/biblio?FT=D&date=19990824&DB=&locale=&CC=JP&NR=H11226255A&KC=A&ND=1[Espacenet]) (https://patents.google.com/patent/JPH11226255A/en[Google])
- large structure composition
##[flyer] flyer
https://flyers.arcade-museum.com/flyers_video/taito/28000501.jpg
https://flyers.arcade-museum.com/flyers_video/taito/28000502.jpg
- error: the moon and star item graphics are misplaced.
##[pamphlet] pamphlet
(various photos)
https://twitter.com/spread_bomb/status/727817185612075009
https://twitter.com/z7Ze3mGJQNGQurt/status/1346343293320249344
https://twitter.com/hatimituxiaoyu/status/1409132070132015104
https://twitter.com/hPa_ll/status/1498917163712716800
Protokami scans
- https://cdn.discordapp.com/attachments/933903225889902652/964345237717778482/scan3.pdf[side 1]
- https://cdn.discordapp.com/attachments/933903225889902652/964345237323526174/scan2.pdf[side 2]
##[instruction-card] control panel instruction card
- https://qcs.shsbs.xyz/api/File/raw/gqjza[side 1]
- https://qcs.shsbs.xyz/api/File/raw/fgekh[side 2]
https://www.mameworld.info/mrdo/mame_artwork_ingame.php
##[magazines] magazines
|❗ need scans!!!|
- [1998-07-15] Gamest vol.227 p.184, release 1998-06-15 (http://www.netlaputa.ne.jp/~dummy/gamest/magazine/gamest/v227.html[src])
- [1998-08-15] Gamest vol.230 p.180-181, release 1998-07-15 (http://www.netlaputa.ne.jp/~dummy/gamest/magazine/gamest/v230.html#KOURYAKU[src])
photo: https://twitter.com/suoh_takamura/status/1515503956843438080
!https://qcs.shsbs.xyz/api/File/raw/jhhbz[large]
##[taito-universe-trading-card] taito universe trading card
|!https://qcs.shsbs.xyz/api/File/raw/oexsc[large]|!https://qcs.shsbs.xyz/api/File/raw/ekybr[large]|
(more information (japanese): https://gmdisc.com/archives/679)
##[fanart] fanart
(1999-03-02) rinrei by ろさ (久保田千寿) http://orange.zero.jp/senju.rose/rosa/gallery/04game02.html
(2000-10-01) rinrei, aifa, youen, shaoren by QQQ https://qcs.shsbs.xyz/api/File/raw/tytsw[Arcadia 0005 p.170]
(200?-??-??) youen by QQQ https://twitter.com/qqq99999_qqq/status/1491399059458117635
(2002-08-23) aifa by HAL44 http://www.ocn1.net/takebo/itadakimono9.htm
(2012-11-21) soumei by KaiSuki https://www.deviantart.com/kaisuki/art/LandMaker-Soumei-339008288
(2013-08-24) aifa by いのり https://twitter.com/q_od/status/371489553036505088
(2017-04-22) aifa by randomouscrap https://www.deviantart.com/randomouscrap/art/Aifa-Land-Maker-request-676564777
(2018-12-25) renki and soumei by 藤堂与吉 https://twitter.com/shiromochi_flag/status/1077505874598322176
(2022-06-26) aifa by カービィ (miitopia) https://twitter.com/G0OvffOExpv2cLc/status/1540979593821028352
(2022-07-23) ranju by カービィ (miitopia) https://twitter.com/G0OvffOExpv2cLc/status/1550987519344271360
(2022-10-22) rinrei by kyatt7 https://qcs.shsbs.xyz/api/File/raw/kyatt7-10-22-rinrei https://web.archive.org/web/20221030183100/https://twitter.com/kyatt7/status/1583844978966814721[(archive)]
(2022-10-24) aifa by haloopdy https://qcs.shsbs.xyz/api/File/raw/dlvxs
(2022-12-11) hiryu by kyatt7 https://cdn.discordapp.com/attachments/849101921000095754/1051615897028153445/image.png
(2023-01-18) roushinshi, shaoren by chen https://twitter.com/kinoglossia/status/1615625364889378816 https://qcs.shsbs.xyz/api/File/raw/chen-2023-01-18-roushinshi[(img)]
(2023-01-21) hiryu, renki, gaira, aifa, ranju, rinrei, soumei by kyatt7 https://twitter.com/kyatt7/status/1616928671046197248 https://qcs.shsbs.xyz/api/File/raw/bfuqz[(img)] https://cdn.discordapp.com/attachments/849101921000095754/1051633829330296832/image.png[(2022-12-11 lines)]
(2023-01-25) youen, aifa by Retinacyst https://retinacyst.tumblr.com/post/707493955606020096
(2023-01-25) aifa by chen https://twitter.com/kinoglossia/status/1618505766528483328
(2023-01-26) aifa, youen by Retinacyst https://twitter.com/retinacyst/status/1618872946038284290
(2023-01-28) roushinshi, shaoren by chen https://twitter.com/kinoglossia/status/1619604518546849792
(2023-09-01) aifa by squidkeki https://twitter.com/squidkeki/status/1697834018744549519
(is it fanart if it's by the original art director...?)
(2020-08-10) aifa by 加藤久和 https://twitter.com/arotak/status/1314903377457807361
#[staff-credits] STAFF
\spoiler[credits]{
### ART DIRECTOR & CHARACTER DESIGN
加藤 久和 (https://twitter.com/arotak[@arotak])
### GAME DIRECTOR & GAME DESIGN
中久木 成一 (http://www.nakakuki.net/)
### PROGRAM
https://w.atwiki.jp/game_staff/pages/802.html[TMR] (津森 康男 YASUO TSUMORI)
https://w.atwiki.jp/game_staff/pages/709.html[谷口 晃] (HIKARU TANIGUCHI)
ジラプマX (林康高 YASUTAKA HAYASHI)
### CHARACTER DESIGN
https://www.mobygames.com/developer/sheet/view/developerId,483907/[高田 明義] (AKI) (AKIYOSHI TAKADA)
GREAT FUJIMOTO (藤本一弘 KAZUHIRO FUJIMOTO)
https://www.mobygames.com/developer/sheet/view/developerId,448591/[ディスティーノブ] (細見 晋敬 NOBUHIRO HOSOMI)
https://w.atwiki.jp/game_staff/pages/340.html[川石 徹] (TOHRU KAWAISHI)
### GAME DESIGN
野村 昌弘 (MASAHIRO NOMURA)
### SOUND
渡部 恭久 (Yack. https://twitter.com/Feldherrn[@Feldherrn])
石川 勝久 (https://twitter.com/babi_ztt[@babi_ztt])
瓜田 幸治 (https://twitter.com/Yukiharu_Urita[@Yukiharu_Urita])
NORIHIRO FURUKAWA (https://twitter.com/nakayamaraiden[@nakayamaraiden])
### DESIGN
https://www.mobygames.com/developer/sheet/view/developerId,522421/[竹浪 利行] (TOSHIYUKI TAKENAMI)
### VOICE
LISLE "WEAPON" WILKERSON (https://twitter.com/lisleweapon[@lisleweapon])
BRIAN MATT-UHL (https://twitter.com/brianmatt_tokyo[@brianmatt_tokyo)]
### "LAND MAKERS"
SEIJI KAWAKAMI (河上 聖冶)
https://w.atwiki.jp/game_staff/pages/804.html[KEPPEL MAEKAWA] (前川 浩之 https://twitter.com/keppelclub[@keppelclub])
NOBUAKI KUROKI (黒木 伸章)
https://w.atwiki.jp/game_staff/pages/746.html[NAOMITSU ABE] (阿部 直光)
https://w.atwiki.jp/game_staff/pages/807.html[YOUSUKE TSUDA] (津田 洋介)
YOUICHIRO KUGIMIYA (釘宮 陽一郎)
TAKAYUKI TSUCHIYA (土屋 貴之)
NAOTO OMURA (大村 直人)
### SPECIAL THANKS
https://w.atwiki.jp/game_staff/pages/805.html[MASAKI OGATA] (緒方 正樹)
YOSHIHIRO SUZUKI (鈴木 善博)
https://w.atwiki.jp/game_staff/pages/808.html[YOSHIHISA NAGATA] (永田 喜久)
TOSHIAKI KATO
SON KEN
SHIGENOBU SHIMIZU (清水 重信)
ゴリゴ ダイラ
ハイパー ヨシハラ
コバヤシ ダイスケ
KURI
CP ALL STAFF
CP MARKETING STAFF
http://www.studio-peacock.co.jp/index.html[PEACOCK] (likely TOMOKI ODA (小田 智樹))
}
(some information taken from https://w.atwiki.jp/game_staff/pages/771.html)
GameStaff@wiki credits 鈴木善博 / YOSHIHIRO SUZUKI twice. the first occurrence is the correct placement.
#[maps] maps
|🎎 to do: x.x|
## audio cpu
|🎎 to do: everything.|
|c0c4ba|string interpolation with control sequences for display|
|c192ee|writes es5505 registers for play sound|
bank 1: sequencer code
bank 2: sequence data
https://qcs.shsbs.xyz/api/File/raw/chxul[main sequence playback code locations]
old notes
| `$C11A0A` | "maybe find sequence" |
| `$C14CB8` | playback control? beat+measure counting |
https://twitter.com/babi_ztt/status/1250245632142397441
>[石川勝久] グリッドはF3初期だからシーケンス再生ソフトがまだ不完全だったんだよねぇ
https://blog.goo.ne.jp/nakayamaraiden/e/02fa8ff92769b1388c8bf09a84e3b4b6
>[古川 典裕] SQ-1とEPSはF3ボードの開発用として散々使い倒した
### resources
https://www.4gamer.net/games/040/G004098/20070927044/
>{なお,スライドではES5505に「8bitリニアPCM」とキャプションが付けられているが,ES5505自体は16bit PCMに対応する音源チップである。8bitと書かれているのは,「当時のROM容量の制限からデータサイズを抑える必要があったため」(石川氏)だそうだ。}
https://mamelife.blogspot.com/2005/02/f3-sound.html[Nicola's MAME Ramblings - F3 sound] - discusses sample rom banks
https://drive.google.com/file/d/1qk29pd83UtjdI9_YuXQZeABgiW0zWn0j/edit[ENSONIQ EPS/ASR SEQUENCE STRUCTURE] - maybe hints for decoding sequence headers
https://github.com/jedpossum/Mame-Music-Scripts/blob/master/taitof3.lua - interesting ram addresses for currently playing sequence
\spoiler[summary]{|[*] address |[*] notes |
| `$5766` | https://github.com/jedpossum/Mame-Music-Scripts/blob/master/taitof3.lua#L11[note channel 11?] |
| `$579E` | chan 10? |
| `$57D6` | chan 9? |
| `$580E` | chan 8? |
| `$5846` | chan 7? |
| `$587E` | chan 6? |
| `$58EE` | chan 5? |
| `$5926` | chan 4? |
| `$595E` | chan 3? |
| `$5996` | chan 2? |
| `$59CE` | chan 1? |
| `$5D4E` | chan 12? |
| `$FFD06C` | song name |
| `$FFD0B0` | measure |
| `$FFD0B2` | beat |
| `$FFD0BA` | measure count |
| `$FFD0E6` | tempo |}
https://blog.goo.ne.jp/nakayamaraiden/e/506852dfb7f5512c11202b3d8d4760c7[nakayamaraiden - タイトーメモリーズ] - on f3 sound reproduction issues. it's suggested reading.
>{When changing the tempo in the middle of a song, F3 requires tempo data to be sent from the outside (main). Therefore, tempo changes are not included in the sound data itself. In test mode (as a common specification with other platforms), tempo change processing is not performed, so the default tempo of the song is played from beginning to end.}
#[shifts] 2.01J -> 2.02O Program ROM shifts
|[*] shift |[*] 2.01J |[*] 2.02O |[*] 2.02O end |[*] content |
| 0x4C | `$01154C` | `$01154C` | `$011598` | \spoiler[76 bytes]{`0003000c36a036a136a136a136a136a136a136a136a236a136a136a136a336a436a536a636a736a836a936aa36ab36ac36ad36ae36af36b036b136b236b336b436b536b636b736b836b936ba`} |
| 0x3AE | `$013954` | `$0139A0` | `$013D02` | unknown (for text ram?)\spoiler[866 bytes]{`000000000000000000000000000000000000000000000000e000eeeee000eeee000000000000000000000000000000000000000000000000eeeeeeeeeeeeeeee000000000000000000000000000000000000000000000000eeeeeeeeeeee8888e000eeeee000eeeee000eeeee000eeeee0008eeee00088eee000f8eee000f8eeeeeeeeeeeeeeeeeeeeeeeeee888888e8fff8f888888f8f8f8e888f88eee88f8eeeeeeeeeeeeeeeeeeeeeeeee888888888fff8ff8f888ff88f8ee8f88f8ee8f88eeeeeeeeeeeeeeeeeeeeeeee888888ee8ffff888f8888f88f8e8ff88f8ee8888eeeeeeeeeeeee888eeeee8f8888888f88fffffff8f8888f88888e8f888ffe8f8eeeeeeeeeeeeeeeeeeeeeeee888888888ff8f8ffff8888f88f8e88888f8e8eeeeeeeeeeeeeeeeeeeeeeeeeee8e88e8888e8fe8ff8e8f88f8ee8f88f8ee8f88f8eeeeeeeeeeee8eeeeeee8eee888e8888ff88f88f88f888f8e88f8888ee8f8eeeeeee8ff8ee888ff8ee8f8888888f88888fff8ff8888f8f88ee8f8f8eee8f8f8eeeeeeeeeeeeeeeeeeeeeeeee8888e888f8ff88ff8ff88f8888f88f8ee8f88f8eeeeeeeeeeeeeeeeeeeeeeeee888e8888ff888fff88f888f888f8e8f8ff88e88feeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000f8eee00088eee0008eeee000eeeee000eeeee000eeeee000eeee000000008e888f88888f8f8ffff8f888888888e8eeeeeeeeeeeeeeeeeeeeeeee00000000f8ee8f88f8888f888ffffff888888888eeeeeeeeeeeeeeeeeeeeeeee00000000f8ee8888f8888f88ff88ff8f88888888eeeeeeeeeeeeeeeeeeeeeeee000000008f88e8f88f8888f888ffff88e888888eeeeeeeeeeeeeeeeeeeeeeeee000000008f8e8eee8f888ee8fff88ee88888eee8eeeeeeeeeeeeeeeeeeeeeeee000000008e8f88f8888f88fffff88ff888888888eeeeeeeeeeeeeeeeeeeeeeee00000000e88f888888f888f8ff88888f888eee88eeeeeeeeeeeeeeeeeeeeeeee00000000ee8f8f8e888f8f888ff8fff888888888eeeeeeeeeeeeeeeeeeeeeeee00000000e8f88f8e88f88f888ffffff888888888eeeeeeeeeeeeeeeeeeeeeeee0000000088f8e888ff8888ff88f88f8888f88f88ff8888ff888ee888eeeeeeee00000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000d8`} |
| 0x3B4 | `$015BFC` | `$015FAA` | `$015FB0` | \{unknown palette init-related resource
`001003C006C0`} |
| 0x3F4 | `$015FBC` | `$016370` | `$0163B0` | new palette (for?) \spoiler[64 bytes]{`00F8009000885840009868500098705000784848000080F800E8480800A038100000000000F8780000F8880000F8980000F8A80000F8B8000028188800F8F8F8`}|
| 0x400 | `$091470` | `$091864` | `$091870` | \{region check
```cmpi.w #1,(0x1ffffe)
bne.w 0x91958```
\spoiler[12 bytes]{`0C790001001FFFFE660000EA`}}|
| 0x404 | `$0A06C8` | `$0A0AC8` | `$0A0ACC` | function table entry `000A0BEC` |
| 0x406 | `$0A06D4` | `$0A0AD8` | `$0A0ADA` | word table entry `0002` |
| 0x40A | `$0A06F0` | `$0A0AF6` | `$0A0AFA` | function table entry `000A0B00` |
| 0x41C | `$0A07E2` | `$0A0BEC` | `$0A0BFE` | \{new function
```cmpi.w #1,(0x1ffffe)
beq.b 0x0a0bfc ;(rts)
jsr 0x0059ee
rts```
\spoiler[18 bytes]{`0C790001001FFFFE67064EB9000059EE4E75`}}|
| 0x450 | `$0A1114` | `$0A1530` | `$0A1564` | \{new function
```
movem.l { A0 D1 D0 }, -( SP )
move.w #0xd8, D0w
movea.l #0x0139a0, A0 ; ❗
jsr 0x005bce
move.w #0x36, -(SP )
move.l #0x61c222, -(SP )
move.l #0x01154c, -(SP ) ; ❗
jsr 0x0056e6
adda.w #0xa, SP
movem.l (SP)+, { D0 D1 A0 }
rts
```
\spoiler[52 bytes]{`48E7C080303C00D8207C000139A04EB900005BCE3F3C00362F3C0061C2222F3C0001154C4EB9000056E6DEFC000A4CDF01034E75`}}|
| 0x45E | `$0A112C` | `$0A157C` | `$0A158A` | \{new region code
```
cmpi.w #0x2 ,D1w
bne.b 0x0a158a
cmp.w (-0x5f0, A5), D1w
beq.b 0x0a158a
bsr.b 0x0a1530 ; ❗
```\spoiler[14 bytes]{`0C4100026608B26DFA10670261A6`}}|
| 0x460 | `$0A1416` | `$0A1874` | `$0A1876` | unknown `0006` |
#[emulation-notes] emulation notes
>{ - audio improperly emulated
- possibly incorrect clock timings
- effect chip not emulated(?)}
m68k `cmp2` was bugged in mame prior to 0.227, causing rank and ending selection to be incorrect.
as of mame 0.253, win messages and endings are visible thanks to this research!
the taito f3 has 4 total clip planes, and up to 2 can be assigned to each playfield.
the low bits are in 625x00 and the high bits are in the upper nybble of 624400 (1, 2) and 624600 (3, 4)
\h[previous notes on ending slides]{
>{known emulation issues (MAME 0.227)
- line ram 5600 mode is unemulated
- win messages don't display
- possibly cause of first ending slide not appearing}
ending slides have maybe a table of clip plane and playfield column scroll addresses at `$FF102`
|slide|clip 1 lo | clip 1 hi | clip 2 lo | clip 2 hi|[#]
|1|null | null | 625600(unemu) | 624600 |
|2|625600(unemu)|624600 |625400(unemu)|624600 |
|3|625400(unemu)|624600|625200 |624400 |
|4|625200 |624400 |625000|624400 |
|5|625600|624600 |625000 |624400 |
table: line ram base addresses
finalburn neo has a https://github.com/finalburnneo/FBNeo/blob/b60f14c9964a52810fb795bd176cadf9a6e27653/src/burn/drv/taito/taitof3_video.cpp#L1955[kludge to make win messages(playfield 4?) show up],
it also allows the first ending message to show up, but it will overlap the second message/tilemap.
}
playstation version: not emulated. cut down spritesheets: how much of the originals were unused? some color, graphics changes. what is going on with the sound (w. this is not a psx resource. XEBRA can emulate pocketstation 'https://youtu.be/0yOQkyPKaiY?t=74[POCKET LAND MAKER]' (japan only)
#[y-scripts] scripts and tools for y's reference
\spoiler[mame spaces:list]{
```lua
rom = manager.machine.system.name
for d in pairs(manager.machine.devices) do
for spacename, space in pairs(manager.machine.devices[d].spaces) do
for e = 1,space.map.entries:size(),1 do
mapentry = space.map.entries[e]
print((d.." "..spacename.." "..e))
print(string.format("echo 0x%x 0x%x 0x%x %s",mapentry.address_start,mapentry.address_end,mapentry.region_offset, mapentry.read.name))
for i=mapentry.address_start,mapentry.address_end,1 do
end
end
end
end```}
\spoiler[mame spaces:save]{
```lua
rom = manager.machine.system.name
for d in pairs(manager.machine.devices) do
for spacename, space in pairs(manager.machine.devices[d].spaces) do
for e = 1,space.map.entries:size(),1 do
mapentry = space.map.entries[e]
print((rom.."_"..d.."_"..spacename.."_"..e..".bin"):gsub(":",""):gsub(" ","-"))
print(string.format("\tregion %d: %x, %x (%s)",e,mapentry.address_start,mapentry.address_end,mapentry.read.name))
out = io.open((rom.."_"..d.."_"..spacename.."_"..e..".bin"):gsub(":",""):gsub(" ","-"),"wb")
for i=mapentry.address_start,mapentry.address_end,1 do
out:write(string.char(space:read_u8(i)))
end
out:close()
end
end
end```}
### ensoniq sample data
interleaved 0s. remove them for processing.
```sh
cat ensoniq.bin | ruby -e 'print ARGF.read.b.scan(/.(.)/m).join' > ensoniq_unpadded.bin```
\spoiler[patterns and extraction in imhex]{
(cannot do anything useful with sample params structure because it will not handle the 24-bit pointers...)
```cpp
#include <std/io.pat>
#include <std/mem.pat>
#pragma endian big
fn bank_relative(u16 offset) {
return addressof(parent) & 0xF80000;
};
struct SampleParams {
u8 uk1[2];
u8 start_ofs[3]; // 24-bit pointers
u8 uk2;
u8 loop_ofs[3]; // maybe
u8 uk3;
u8 end_ofs[3];
u8 uk4;
};
struct SampleName {
SampleParams* params : u16 [[pointer_base("bank_relative")]];
char name[12];
};
SampleName bank1names[24] @ 0x200001;
SampleName bank2names[15] @ 0x280001;
SampleName bank3names[16] @ 0x300001;
SampleName bank4names[18] @ 0x380001;
SampleName bank5names[8] @ 0x400001;
SampleName bank6names[12] @ 0x480001;
SampleName bank7names[23] @ 0x500001;
SampleName bank8names[7] @ 0x580001;
SampleName bank9names[31] @ 0x600001;
SampleName bank10names[23] @ 0x680001;
SampleName bank11names[16] @ 0x700001;
SampleName bank12names[16] @ 0x780001;
fn main() {
str output;
for (u8 i = 0, i < 24, i = i + 1) {
output = output + std::format("|`{}`|\n",bank1names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 15, i = i + 1) {
output = output + std::format("|`{}`|\n",bank2names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 16, i = i + 1) {
output = output + std::format("|`{}`|\n",bank3names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 18, i = i + 1) {
output = output + std::format("|`{}`|\n",bank4names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 8, i = i + 1) {
output = output + std::format("|`{}`|\n",bank5names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 12, i = i + 1) {
output = output + std::format("|`{}`|\n",bank6names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 23, i = i + 1) {
output = output + std::format("|`{}`|\n",bank7names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 7, i = i + 1) {
output = output + std::format("|`{}`|\n",bank8names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 31, i = i + 1) {
output = output + std::format("|`{}`|\n",bank9names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 23, i = i + 1) {
output = output + std::format("|`{}`|\n",bank10names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 16, i = i + 1) {
output = output + std::format("|`{}`|\n",bank11names[i].name);
}
output = output +"\n";
for (u8 i = 0, i < 16, i = i + 1) {
output = output + std::format("|`{}`|\n",bank12names[i].name);
}
std::print(output);
};```
}
#### playing instrument log
`bp c17cd0,1,{temp0=(a6+d0+$4); logerror "%c%c%c%c%c%c%c%c%c%c%c%c\n",b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0; g}`
`bp c19454,1,{temp0=(a6+d0+$4); logerror "%c%c%c%c%c%c%c%c%c%c%c%c\n",b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0++,b@temp0; g}`
`diff -yb ensoniq-sample-names.txt land-maker-sample-log-uniq.txt --suppress-common-lines`
### dumping graphics
https://github.com/mamedev/mame/blob/ca79d71af4bca7c1b8acc1df9e5dbb5b987d1542/src/mame/drivers/taito_f3.cpp#L394[mame gfx layout defs]
https://github.com/y-ack/landmaker-color-mod/blob/main/scripts/landmakrsavexpm.lua
https://github.com/y-ack/landmaker-color-mod/blob/main/scripts/landmakrsaveraw.lua[for palmod raws]
### array-ize block def
```python
from ghidra.program.model.data import ArrayDataType, UnsignedIntegerDataType
if getSymbolAt(currentAddress) is None:
raise Exception("refusing to overwrite listing; no data label at current position")
dataSize = 4
height = getByte(currentAddress.add(1))
width = getByte(currentAddress.add(3))
listStart = currentAddress.add(4)
length = (height+1) * (width+1)
uint = UnsignedIntegerDataType()
clearListing(listStart, listStart.add((length - 1) * dataSize))
createData(listStart, ArrayDataType(uint, (height+1) * (width+1), dataSize))```
### animations
flow format
| word | subsequent|[#]
|0x00|`code pointer`|
|0x01|`code pointer`|
|0x04|`code pointer`|
|0x05|`list node pointer`|
|0x09|`animation data pointer`|
|0x0C|?? can be followed by 0x09 and data pointer|
animlist
|0x00|`code pointer`|
|0x0B|w`time? often 6 or 60`, w`??? usually 0`, p`bl graphic`|
|0x0A| end anim list|
### mame cheats
```xml
<cheat desc="Region Select">
<comment>region for region checks</comment>
<parameter>
<item value="0x0000">(0) Undefined (behaves like World?)</item>
<item value="0x0001">(1) Japan</item>
<item value="0x0002">(2) Americas</item>
<item value="0x0003">(3) World</item>
</parameter>
<script state="change">
<action>maincpu.mw@1FFFFE=param</action>
</script>
</cheat>```
```xml
<cheat desc="Stage layout always...">
<comment>Force stage layout for both players. CANNOT BE REVERTED WITHOUT HARD RESET!</comment>
<parameter min="0" max="120" step="1"/>
<script state="change">
<action>maincpu.mw@98550=303C</action>
<action>maincpu.mw@98552=param</action>
<action>maincpu.mw@98602=303C</action>
<action>maincpu.mw@98604=param</action>
<action>maincpu.mw@9865A=303C</action>
<action>maincpu.mw@9865C=param</action>
<action>maincpu.mw@98708=303C</action>
<action>maincpu.mw@9870A=param</action>
</script>
</cheat>```
P2A2A curtsy
P2A3A ... dance kick?
P2C1A pull out fan hold up
P2C3 fan dance
P2G1 victory celebration jump
P2G2 defeat fall
P2H1 release doves
P2H2A little dance with gold(?) flower trim
P2H4A fan spin
### input checks
|119e| process raw input |active|
|11dc| == |active|
|12cc| process input edge differences|active|
|12d6|write edge difference|/rising/|
|||
|667a|object check|active|
|6668|object check main menu|/rising/|
|6728|==|/rising/|
|673c|==|/rising/|
|6754|==|/rising/|
|696e|object check menu, START|active|
|||
|8ce68|debug popup P2 B3+P1 rB3->pop up|/rising/|
|8d214|debug popup menu UP|/rising/|
|8d22a|debug popup menu DOWN|/rising/|
|d82be|debug popup menu B1->select|/rising/|
|8d310|YES/NO prompt (left/right)|active|
|8d398|YES/NO prompt B2->cancel|/rising/|
|8d3aa|YES/NO prompt B1->select|/rising/|
|8d41e|OFF/ON prompts (left/right?)|active|
|8d4a6|OFF/ON prompts B2->cancel|/rising/|
|8d4b8|OFF/ON prompts B1->select|/rising/|
|8d56c|debug popup slow level (left/right)|active|
|8d604|debug slow level B1->set|/rising/|
|8d60e|debug slow level B2->cancel|/rising/|
|8d7fa|debug color edit LEFT|/rising/|
|8d808|debug color edit RIGHT|/rising/|
|8d85a|debug color edit (up/down?)|active|
|8d93c|debug color edit B2->back|/rising/|
|8d946|debug color edit B1->color submenu|/rising/|
|8dae8|debug color edit RGB submenu (LEFT/RIGHT)|active|
|8da50|debug color edit RGB submenu UP|/rising/|
|8da5e|debug color edit RGB submenu DOWN|/rising/|
|8dc28|debug color edit RGB submenu B2->set(?)|/rising/|
|8dc28|debug color edit RGB submenu B1->set|/rising/|
|||
|8dea6|main loop.....? START|/rising/|
|8e27a|credit inserted...? START|/rising/|
|8e380|"PUSH ANY BUTTON TO CANCEL" START|/rising/|
|8e388|"PUSH ANY BUTTON TO CANCEL" B1|/rising/|
|8e79c|main loop.....? **need bp**|active|
|8ef7e|continue timer B1->dec timer|
|8f2fa|START-> for player jump in?|active|
|8f764|unref'd? rSTART+B1->set MATCH_OVER||
|||
|908a6|title screen into d3, redundant/unuse?|/rising/|
|90a74|title screen secret code input|/rising/|
|90a7a|==|/rising/|
|90f86|match setup reset inputs|active|
|90f92|match setup reset inputs|/rising/|
|91006|??? write... something? probably p2 input or prev input hack, **need bp** |active|
|910a8|practice TRY NEXT LEVEL text B1->shorten->skip|/rising/
|912f8|location test text B1/B2/B3->skip|/rising/|
|919d8|win screen B1->skip|active|
|92782|map screen B1->skip|active|
|||
|93b22|in-match p1 controls->state|active|
|93b28|in-match p1 controls->state|/rising/|
|94ee6|debug cycle B2 cycle through attack portraits|/rising/|
|||
|9c10e|early auto p1 demo play p1+p2 UP->on, TILT->OFF|active|
|9c15c|early p1 auto-play write inputs|/rising/|
|9c162|==|/rising/|
|9c186|==|/rising/|
|||
|9dcda|character select interface|active|
|9dd1a|character select grid interface|/rising/|
|9ef6e|game mode select interface|active|
|9ef72|game mode select interface|/rising/|
|||
|9f2e6|map data edit controls|/rising/|
|9f76a|alt map data edit controls ???|/rising/|
|9f890|alt map data edit controls ???|/rising/|
|9f950|alt map data edit controls ???|/rising/|
|||
|a0710|\{called by a0682 jsr table tutorial actions
reset input, pusher++}||
|a0728| ==; reset input, pusher--||
|a0762| ==; take inputs from 407a0c/d, 407a0a--||
|a0784| ==; reset input; 407a0e = *(a4+2)||
|a07a6| ==; reset input; nextTile = *(a4+2)||
|a07be| ==; reset input; incomingPushTotal=1, something||
|a0934|detect B1 for teach button press graphic|active|
|a094a|detect left/right for teach joy graphic|active|
|a0a48|reset inputs for demo stage -1||
|a0ac2|reset inputs for? demo stage -1||
|a0db4|more reset inputs while loading demo assets||
|a0e52|==||
|a0e9c|==||
|a11b8|==||
|a1298|==||
|a135a|reset inputs for demo stage -2||
|a15aa|reset inputs for demo||
|fed52|ending sequence B1/START->skip|/rising/|
**(omitted: service menu)**
|8f2|TILT->tilt error|active|
|90a|SERVICE1->service coin|/falling/|
|||
|559e|SERVICEMODE/SERVICE_UNUSED->backup data failure prompt escape|/rising/|
|||
|8cde6|TILT->debug [PAUSE]|/rising/|
|8cde6|SERVICE1+rTILT->debug popup activate|active|
|||
|8e038|SERVICEMODE/SERVICE_UNUSED->enter service menu|/rising/|
|||
|8eefc|SERVICE1/COIN1/COIN2->reset continue timer|/rising/|
|||
|9c124|TILT->p1 side autoplay disable|active|
|||
|100056|SERVICEMODE/SERVICE_UNUSED->escape monitor test|/rising/|
|1001dc|SERVICE1->switch test ???|/rising/|
|1009ac|SERVICEMODE/SERVICE_UNUSED->exit switch test|/active/|
|101562|SERVICE1->alternate sound test|active|
### task slots
|0|$14c8:main loop(wait a moment)|
|1|\{$8d67e:service menu
$8de38:copyright notice
$8de88:attract loop
$8df06:credit inserted
$8e066:service menu}|
|2|$8e31c:teach demo|
|3|$8ed22:round control|
|4|$8ed62:"start round?"|
|5|$8ed3c:"per frame code with damage?"|
|6|$8e300,$8ed32:3988|
|7|$8ed42,907ba:3d5e|
|8|$8ed72:94a50|
|9|\{$8ed82:p1 autoplay input check
$8f8a0:map screen
$8f8da,$8f978:win screen
$90894,$90d54:'insert coin' blink}|
|10|\{$8e3c0,$8e972,$8ea0a,$8f810:8e096
$8e658,$8e6de,$8e99c,$8e9e6:charram black transition}|
|12|\{$8edea:game mode select
$8ee12,$8f878:character select}|
|14|$8de22:4498|
|15|$8de0c:10170|
### player states
|-1|shot tile traveling|
|0|full control, can fire|
|2|?|
|3|wall pushing back?|
|4|shot tile converting adjacent colors|
|5|breaking|
|6|sending damage (damage orbs)|
|8|initial + ?|
|9|pushing forward?|
|10|push done|
|11|?|
!https://qcs.shsbs.xyz/api/File/raw/ndqrl
# unrelated
https://twitter.com/TSUKAPPI/status/704254180328808450
1996 graph paper,
https://twitter.com/TheMogMiner/status/1032984277925945345
>{The audio hardware on the Taito F3 board, for example, is almost identical, right down to the memory map, with the Ensoniq SD-1.}
https://twitter.com/TSUKAPPI/status/1250237806284165121
> I remember that when ENSONIQ was introduced, programmers were having a hard time with Galactic Storm and early F3 motherboards.
https://twitter.com/babi_ztt/status/1250245632142397441
> Since Grid Seeker was in the early stages of the F3, the sequence playback software was still incomplete
https://twitter.com/blapa_3rd/status/1388473208576241668
>{パズルボブル2Xとクレオパトラフォーチュン位ですね。F3末期はサターンも衰退していたので、ぽっぷんぽっぷやランドメーカーもPSに移植されちゃいましたw}
>{Puzzle Bobble 2X and Cleopatra Fortune. At the end of F3, Saturn was also declining, so Pop'n Pop and Landmaker were also transplanted to PS.}
https://twitter.com/arotak/status/443787079919472640
> 僕が入った頃のタイトーはバリバリ硬派なアメコミなグラフィックがメインの会社だったんです。アニメっぽい絵を描く方が異端の存在で、その手のものをちょこちょこ引き受けて描いてました。
> When I first joined Taito, the main company was crunchy and hard-core American comic graphics. Drawing an anime-like picture is a heretic, and I took on and drew things of that kind.
https://twitter.com/kenji_kaido/status/1223808603108196352
>{There are two types of specifications at Taito: the pre-development specifications and the post-development final specifications. The final specifications are written after completion, so they're pretty standard, but I get the impression that the pre-development specifications are often a bit too much.}
https://togetter.com/li/664375
(kaido on x-55 cleo)
https://twitter.com/suddendesu/status/1312535651917590529
>{Big thanks to whoever liked this 2+ year old tweet which reminded I need to update the Land maker article}
https://twitter.com/arotak/status/443424335668060160
> 偉そうなことを色々書いてますが、当時自分が企画を立てたもので開発中止になったものだってあるんです。プリルラも一度は開発中止になったのでした。救ったのは僕ではなく直談判した当時の担当プログラマーです。プリルラが陽の目をみたのは彼の手柄です
> I've written a lot of things that look great, but at that time I had a plan and the development was discontinued. The development of Pu-Li-Ru was also once discontinued. It wasn't me who saved me, but the programmer in charge at the time who spoke directly. It is his credit that Pu-Li-Ru saw the sun
## palette mods
tools, raws, list of known palette mods:
https://github.com/y-ack/landmaker-color-mod
https://github.com/y-ack/PalMod