Full Changer Technical Documentation 0.4 August 10th, 2017 Shonumi aka D.S. Baxter *************************************************** 1. Introduction *************************************************** Zok Zok Heroes was a GBC JRPG released on August 4, 2000, made by Media Factory when they still produced video games. It used a special accessory called the "Full Changer", a device that looks like a toy, but acts as an IR transmitter. It sent signals to the GBC once players moved it through the air to "draw" certain patterns. Once the GBC gets the IR light pulses, it allows players to transform into different "Bright Heroes" to do battle against evil bad guys. It never sold outside of Japan. After a specific point early in the game, it becomes impossible to progress further in emulators without cheat codes/hacks or by properly emulating the Full Changer. Below are brief technical notes about the Full Changer. *************************************************** 2. General Cart+Hardware Information *************************************************** Zok Zok Heroes (CGB-BZHJ-JPN) MBC5 + Battery Saves GBC Only Comes with 1 Full Changer accessory Full Changer uses one CR2032 Full Changer contains 4 Hall effect sensors to detect movement Full Changer has a series of status lights and blinks/beeps when swung correctly *************************************************** 3. Full Changer Operation *************************************************** 1. Grab the Full Changer firmly, holding it by the strap 2. Press and release the top button. It should beep and the 3 lights should flash for approximately 5 seconds. 3. During those 5 seconds, move the Full Changer to draw the pattern of a "Cosmic Character" e.g. for "Z" start left, move right, stop, move downward and leftward, stop, move right, stop. 4. Make sure the Full Changer is always held upright while drawing. 5. For each successful movement, the Full Changer will activate another light and beep. Once all three at lit, it beeps a little tune and the data is ready to be sent to the GBC. 6. Put the bottom of the Full Changer on top of the GBC, making sure to cover the IR port. The Full Changer has a little plastic guide to make sure everything fits and faces the right direction. *************************************************** 4. Full Changer-GBC Communication *************************************************** The Full Changer sends a total of 18 IR pulses (on then off periods) when transmitting data. The length of these pulses varies and determines what values the Full Changer is trying to send. Zok Zok Heroes runs in a couple of loops while the pulse takes place. Each iteration, it increments a counter to get an idea of the overall "delay" it takes for the IR light to turn on then turn off. That counter is then placed in WRAM as a single byte (anything greater than 0xFF causes a timeout) and verified later. In this way, Zok Zok Heroes can view data from the Full Changer as a series of bytes rather than light pulses. These 18 bytes do not have especially strict values, rather they are expected to fall within a certain range to indicate long or short pulses. *************************************************** 5. Capturing IR Data From Full Changer *************************************************** Below is psuedo-code representing how Zok Zok Heroes grabs the 18 bytes: ================================== LABEL CHECK_ON_LOOP: ================================== //Use an 8-bit CPU register as a Time-Out Counter, initially set to 0xFF, exit if it hits zero TIMEOUT_COUNTER-- IF(TIMEOUT_COUNTER == 0) { RETURN } //Load A from 16-bit immediate address for RP register A = [0xFF56] //Wait for IR light to come on (Bit 1 of 0xFF56 goes to zero) IF(A AND 0x1) { GOTO CHECK_ON_LOOP } //Use another 8-bit CPU register to act as a counter for total number of bytes processed from Full Changer TOTAL_BYTES = 0x12 //Set a 16-bit CPU register pair as the destination address (0xD005+) to write IR data DEST_ADDR = 0xD005 ================================== LABEL GRAB_IR_BYTES: ================================== //Wait for IR light to go off (Bit 1 of 0xFF56 goes to one) //Set an 8-bit CPU register to act as an IR pulse length counter, initialized to 0x00 PULSE_LENGTH = 0x00 CALL WAIT_FOR_OFF CALL WAIT_FOR_ON //Save pulse length results to 0xD005 - 0xD017 [DEST_ADDR] = PULSE_LENGTH DEST_ADDR++ TOTAL_BYTES-- IF(TOTAL_BYTES != 0) { GOTO GRAB_IR_BYTES } ... //IR handling code ends here ================================== FUNCTION WAIT_FOR_OFF: ================================== PULSE_LENGTH++ IF(PULSE_LENGTH == 0) { RETURN } LOAD_RP_ON: //Load A from 16-bit immediate address for RP register A = [0xFF56] //Wait for IR light to come on (Bit 1 of 0xFF56 goes to one) IF((A AND 0x1) == 0x00) { GOTO WAIT_FOR_OFF } RETURN ================================== FUNCTION WAIT_FOR_ON: ================================== PULSE_LENGTH++ IF(PULSE_LENGTH == 0) { RETURN } LOAD_RP_OFF: //Load A from 16-bit immediate address for RP register A = [0xFF56] //Wait for IR light to come on (Bit 1 of 0xFF56 goes to zero) IF(A AND 0x1) { GOTO WAIT_FOR_ON } RETURN Once all 18 bytes have been stored in WRAM, it's possible to read them and save them using a ROM hack. Alternatively, homebrew software can use code with the same timing to accurately capture IR data from the Full Changer. *************************************************** 6. Emulating The Full Changer *************************************************** The Full Changer can be successfully emulated by setting Bit 1 of RP register (located at 0xFF56) to 0 or 1 at the appropiate times. To do so requires accurate timing and knowing the amount of cycles it takes to generate the delays represented by those 18 bytes in WRAM. When activating the Full Changer, GBE+ always fires the 1st "ON" IR signal at a specific time to get consistent timings: TIMEOUT_COUNTER-- IF(TIMEOUT_COUNTER == 0) { RETURN } A = [0xFF56] <---- After the CPU reads 0xFF56 and the user activates the Full Changer, IR light is turned on here <---- This happens after the actual read instruction is executed, so the loop runs once more IF(A AND 0x1) { GOTO CHECK_ON_LOOP } Afterwards, the timings for ON and OFF pulses can be calculated as such (ALL TIMING IS IN DOUBLE SPEED): 1st ON pulse length 74 + (20 * (LENGTH-2)) Every other ON pulse length 78 + (20 * (LENGTH-2)) OFF pulse length 38 + (20 * (LENGTH-2)) The LENGTH is number of times the 8-bit CPU register is incremented in the WAIT_FOR_OFF or WAIT_FOR_ON functions. The sum of two LENGTHs from one ON pulse and one OFF pulse must be equal to the delay data in WRAM. For example, say the delay data contains 0x20. This means that the TOTAL amount of times the 8-bit register was incremented is 0x20. In a perfect world, the Full Changer would probably turn on the IR light so that this 8-bit register is incremented 0x10 times, then turn off the IR light so that D is incremented again 0x10 times. In reality, however, the length of the ON/OFF pulses could run a bit longer or shorter. As far as Zok Zok Heroes is concerned, the total amount of time the IR light is ON then OFF is what matters, so the ON/OFF pulse timings ultimately have to add up. The current database GBE+ uses recreates ON/OFF pulses that generally run for the same amount of cycles. However, based on hardware tests, the ON pulses have variable lengths, while the OFF pulses are typically constant. Again, Zok Zok Heroes won't care, as long as the total time of the ON/OFF pulses meets whatever value it expects. *************************************************** 7. Cosmic Characters *************************************************** There are a total of 70 "Cosmic Characters" available in Zok Zok Heroes, and by extension, there are 70 unique transformations. This Cosmic Character is simply an 8-bit ID generated from the ON and OFF pulses from the Full Changer. Using the delays stored in the 18 WRAM bytes, the game software uses the following logic to determine an ID. The first pulse is checked to ensure that it has a delay greater than 0x20, signaling a long pulse, otherwise processing for the Cosmic Character does not continue. Afterwards, the next 16 pulses are examined to build two separate 8-bit values. These values are constructed LSB. A short pulse (any value from 0x00 to 0x13) translates into a "0", and a long pulse (any value from 0x14 to 0x20) translates into a "1". The 1st 8-bit value built from these pulses is used for a checksum of a sort, and the 2nd 8-bit value is complemented to form an ID. IDs range from 0x01 to 0x46 and correspond to the 70 Cosmic Characters. Note that while the 18th IR pulse is required by the software, it isn't used for the ID or checksum. Checksum Calculation: Pulse Byte 1 + Pulse Byte 2 = 0xFF Cosmic Character ID Calculation: ~Pulse Byte 2 = Cosmic Character ID Pulse Byte 1 Calculation (using an arbitrary ID of one's choosing): Pulse Byte 1 = 0xFF - (~Cosmic Character ID) Pulse Byte 2 Calculation (using an arbitrary ID of one's choosing): Pulse Byte 2 = ~Cosmic Character ID ------------------------------------------------------------------------------------------------------------ ID | Cosmic Character Movements (S* = Short Move) | Translated Name | (Character) Japanese Name ------------------------------------------------------------------------------------------------------------ 01 | Up, Down, Up | Alkaline Powered | (あ) アルカリパワード 02 | Right, Left, Right | In Water | (い) イン ウォーター 03 | Down, Up, Down | Ultra Runner | (う) ウルトランナー 04 | Left, Right, Left | Aero Power | (え) エアロ パワー 05 | Down+Left, Right, Left | Ochaapa | (お) オチャッパ 06 | Up, Right, Down | Kaizer Edge | (か) カイザーエッジ 07 | Right, Down, Left | King Batter | (き) キングバッター 08 | Down, Left, Up | Crash Car | (く) クラッシッカー 09 | Left, Up, Right | Cellphone Tiger | (け) ケイタイがー 10 | Down+Left, Up, Right | Cup Ace | (こ) コップエース 11 | Up, Left, Down | Sakanard | (さ) サカナード 12 | Right, Up, Left | Thin Delta | (し) シンデルター 13 | Down, Right, Up | Skateboard Rider | (す) スケボーライダー 14 | Left, Down, Right | Celery Star | (せ) セロリスター 15 | Down+Left, S* Down, Right | Cleaning Killer | (そ) ソウジキラー 16 | S* Up, Right, S* Up | Takoyaki Kid | (た) タコアキッド 17 | S* Right, Down, S* Right | Chinkoman | (ち) チンコーマン 18 | S* Down, Left, S* Down | Tsukai Stater | (つ) ツカイステイター 19 | S* Left, Up, S* Left | Teppangar | (て) テッパンガー 20 | S* Down+Left, Up, S* Left | Tongararin | (と) トンガラリン 21 | S* Up, Right, Left | Nagashiman | (な) ナガシマン 22 | S* Right, Down, Up | Ninja | (に) ニンジャーノン 23 | S* Down, Left, Right | Plushy-chan | (ぬ) ぬいぬいちゃん 24 | S* Left, Up, Down | Screw Razor | (ね) ネジレイザー 25 | S* Down+Left, Up, Down | Nobel Brain | (の) ノーベルブレイン 26 | S* Up, Left, S* Up | Hard Hammer | (は) ハードハンマー 27 | S* Right, Up, S* Right | Heat Man | (ひ) ヒートマン 28 | S* Down, Right, S* Down | Flame Gourmet | (ふ) フレイムグルメ 29 | S* Left, Down, S* Left | Hercules Army | (へ) ヘラクレスアーミー 30 | S* Down+Left, S* Down, S* Left | Hot Card | (ほ) ホットカード 31 | S* Up, Left, Right | Mr. Muscle | (ま) マッスルさん 32 | S* Right, Up, Down | Mist Water | (み) ミストウォーター 33 | S* Down, Right, Left | Mushimushi Man | (む) ムシムシマン 34 | S* Left, Down, Up | Megaaten | (め) メガーテン 35 | Down+Left, Down, Up | Mobile Robot X | (も) モビルロボX 36 | Up, Down, Left | Yaki Bird | (や) ヤキバード 37 | Down, Up, Right | Utron | (ゆ) ユートロン 38 | Down+Left, Right, Down | Yo-Yo Mask | (よ) ヨーヨーマスク 39 | Up, Down, Right | Radial Road | (ら) ラジアルロード 40 | Right, Left, Down | Remote-Control Man | (り) リモコンマン 41 | Down, Up, Left | Ruby Hook | (る) ルビーフック 42 | Left, Right, Up | Retro Sounder | (れ) レトロサウンダー 43 | Down+Left, Right, S* Up | Rocket Bastard | (ろ) ロケットやろう 44 | Up, Down, Up+Left | Wild Sword | (わ) ワイルドソード 45 | Up, Down+Right, S* Left | Guts Lago | (が) ガッツラゴー 46 | Right, Down+Left, S* Up | Giniun | (ぎ) ギーニウン 47 | Down, Up+Left, S* Right | Great Fire | (ぐ) グレートファイヤー 48 | Left, Up+Right, S* Down | Gamemark | (げ) ゲーマルク 49 | Down+Left, Up+Right, S* Down | Gorilla Killa | (ご) ゴウリキラー 50 | Up, Down+Right, S* Right | The Climber | (ざ) ザ・クライマー 51 | Right, Up+Left, S* Down | G Shark | (じ) Gシャーク 52 | Down, Up+Right, S* Left | Zoom Laser | (ず) ズームレーザー 53 | Left, Down+right, S* Up | Zenmai | (ぜ) ゼンマイン 54 | S* Down+Left, S* Down+Right, S* Up | Elephant Shower | (ぞ) ゾウシャワー 55 | Up, Down+Right, Up | Diamond Mall | (だ) ダイヤモール 56 | Right, Down+Left, Right | Digronyan | (ぢ) ヂグロニャン 57 | Down, Up+Left, Down | Ziza One | (づ) ヅィザーワン 58 | Left, Up+Right, Left | Danger Red | (で) デンジャレッド 59 | Down+Left, Up+Right, Left | Dohatsuten | (ど) ドハツテン 60 | Up, Down+Left, Up | Balloon | (ば) バルバルーン 61 | Right, Up+Left, Right | Videoja | (び) ビデオージャ 62 | Down, Up+Right, Down | Boo Boo | (ぶ) ブーブーウー 63 | Left, Down+Right, Left | Belt Jain | (べ) ベルトジャイン 64 | S* Down+Left, Down+Right, Left | Boat Ron | (ぼ) ボートロン 65 | Up, Down+Left, Up+Left | Perfect Sun | (ぱ) パーフェクトサン 66 | Right, Up+Left, Up+Right | Pinspawn | (ぴ) ピンスポーン 67 | Down, Up+Right, Down+Right | Press Arm | (ぷ) プレスアーム 68 | Left, Down+Right, Down+Left | Pegasus Boy | (ぺ) ペガサスボーイ 69 | S* Down+Left, S* Down+Right, S* Down+Left | Pop Thunder | (ぽ) ポップサンダー 70 | Right, Down+Left, Down+Right | Ndjamenas | (ん) ンジャメナス