Castlevania II (Simon's Quest) - Multilingual enhancement

Started by Bisqwit, December 19, 2012, 01:38:36 PM

Previous topic - Next topic

Bisqwit

Quote from: Turambar on April 28, 2015, 09:05:46 AMIs the game noticeably laggier with this extra code?
Not that I can see. Mind you, the original game is made of highly inefficient code. Any code rewrite by an experienced hacker is bound to make existing code more efficient, mitigating the cost of added code.

QuoteI wonder if you could substitute metatiles instead of individual tiles and if that would be any faster.
I was thinking of the same thing. And it even might be. Because it does appear that the game does not dereference the metatile table on every 8x8 tile, which would make substituting metatile numbers moot.

A problem is that I don't understand the format of the metatile table:
LevelData_32x32squares_0_Towns
        $841D               .byte $44,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        $842D               .byte $00,$06,$09,$66,$99,$55,$55,$62,$98,$AA,$55,$15,$45,$11,$50,$50
        $843D               .byte $55,$55,$55,$AA,$AA,$FF,$05,$45,$15,$55,$55,$51,$55,$55,$55,$55
        $844D               .byte $AA,$55,$55,$55,$55,$55,$5A,$44,$50,$55,$05,$05,$55,$65,$55,$95
        $845D               .byte $54,$88,$22,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
        $846D               .byte $00,$00,$00,$00,$F6,$F8,$F6,$F8,$F7,$F9,$F7,$F9,$00,$00,$00,$00
        $847D               .byte $00,$00,$00,$00,$F3,$F4,$F5,$FA,$00,$74,$75,$00,$00,$00,$74,$75
        $848D               .byte $00,$00,$00,$74,$F5,$FA,$F1,$F2,$00,$72,$73,$00,$72,$73,$00,$00
        $849D               .byte $73,$00,$00,$00,$74,$75,$00,$00,$00,$74,$75,$00,$00,$00,$74,$75
        $84AD               .byte $00,$00,$00,$74,$00,$00,$72,$73,$00,$72,$73,$00,$72,$73,$00,$00
        $84BD               .byte $73,$00,$00,$00,$F6,$F8,$00,$00,$F7,$F9,$00,$00,$F6,$F8,$00,$00
        $84CD               .byte $F7,$F9,$00,$00,$00,$00,$F6,$F8,$00,$00,$F7,$F9,$00,$00,$F6,$F8
        $84DD               .byte $00,$00,$F7,$F9,$FB,$FD,$00,$00,$FC,$FE,$00,$00,$FB,$FD,$00,$00
        $84ED               .byte $FC,$FE,$00,$00,$00,$00,$FB,$FD,$00,$00,$FC,$FE,$00,$00,$FB,$FD
        $84FD               .byte $00,$00,$FC,$FE,$F6,$F8,$F6,$F8,$F7,$F9,$F7,$F9,$00,$00,$00,$00
        $850D               .byte $75,$00,$00,$00,$F6,$F8,$F6,$F8,$F7,$F9,$F7,$F9,$00,$00,$00,$00
        $851D               .byte $00,$00,$00,$72,$FB,$FD,$FB,$FD,$FC,$FE,$FC,$FE,$00,$00,$00,$00
        $852D               .byte $00,$00,$00,$00,$65,$66,$66,$67,$65,$66,$66,$67,$00,$68,$00,$00
        $853D               .byte $00,$68,$00,$00,$FB,$FD,$F6,$F8,$FC,$FE,$F7,$F9,$FB,$FD,$F6,$F8
        $854D               .byte $FC,$FE,$F7,$F9,$F6,$F8,$FB,$FD,$F7,$F9,$FC,$FE,$F6,$F8,$FB,$FD
        $855D               .byte $F7,$F9,$FC,$FE,$00,$B0,$E2,$7F,$00,$B2,$E2,$9C,$00,$C9,$C9,$91
        $856D               .byte $00,$96,$96,$96,$7E,$E3,$B0,$00,$AE,$E3,$B3,$00,$CF,$C9,$C9,$00
        $857D               .byte $96,$96,$96,$00,$00,$B0,$E2,$7F,$00,$B0,$E4,$A2,$00,$B1,$E2,$7F
        $858D               .byte $00,$B0,$E2,$7F,$7E,$E3,$B0,$00,$C6,$E5,$B0,$00,$7E,$E3,$B1,$00
        $859D               .byte $7E,$E3,$B0,$00,$7E,$7F,$7E,$7F,$DE,$DF,$E0,$E1,$AD,$00,$00,$9D
        $85AD               .byte $94,$00,$00,$97,$7E,$7F,$81,$7F,$7E,$D6,$D6,$C6,$7E,$D7,$D7,$7F
        $85BD               .byte $81,$93,$92,$7F,$00,$B0,$C8,$C8,$00,$B0,$00,$00,$00,$B1,$00,$93
        $85CD               .byte $00,$B0,$E2,$7F,$C8,$C8,$B0,$00,$00,$00,$B0,$00,$92,$00,$B1,$00
        $85DD               .byte $7E,$E3,$B0,$00,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0
        $85ED               .byte $A0,$A0,$A0,$A0,$81,$BA,$BB,$96,$BC,$BD,$BE,$BF,$81,$C0,$C1,$C6
        $85FD               .byte $7E,$C2,$C3,$A2,$00,$00,$00,$93,$00,$00,$92,$9C,$00,$00,$CF,$C9
        $860D               .byte $00,$00,$96,$96,$92,$00,$00,$00,$AE,$92,$00,$00,$C9,$91,$00,$00
        $861D               .byte $96,$96,$00,$00,$7E,$7F,$9E,$9F,$81,$7F,$98,$99,$A3,$81,$98,$99
        $862D               .byte $7E,$82,$98,$99,$C8,$C8,$C8,$C8,$00,$00,$00,$00,$D0,$D1,$D2,$D3
        $863D               .byte $A4,$A5,$A6,$A7,$C8,$C8,$C8,$C8,$00,$00,$00,$00,$92,$93,$92,$93
        $864D               .byte $96,$7F,$7E,$7F,$81,$7F,$7E,$7F,$7E,$AA,$81,$7F,$7E,$82,$A3,$81
        $865D               .byte $96,$7F,$7E,$82,$7E,$7F,$7E,$7F,$DE,$DF,$E0,$E1,$AD,$77,$AF,$9D
        $866D               .byte $94,$78,$7C,$97,$CA,$CB,$DC,$DD,$83,$84,$85,$86,$87,$88,$89,$8A
        $867D               .byte $83,$84,$85,$86,$90,$A1,$C4,$00,$90,$A1,$C4,$00,$90,$A1,$C4,$00
        $868D               .byte $90,$A1,$C4,$00,$90,$A1,$C4,$00,$90,$A1,$C4,$00,$90,$A1,$C4,$00
        $869D               .byte $C5,$CC,$CD,$00,$00,$00,$00,$00,$DA,$DA,$DA,$DA,$DB,$DB,$DB,$DB
        $86AD               .byte $DB,$DB,$DB,$DB,$7E,$7F,$7E,$81,$AE,$95,$AE,$82,$CF,$C9,$C9,$C9
        $86BD               .byte $96,$96,$96,$96,$AC,$7F,$7E,$7F,$00,$AC,$A3,$7F,$00,$00,$AC,$A2
        $86CD               .byte $75,$00,$00,$AC,$7E,$7F,$7E,$AC,$7E,$A3,$AC,$00,$C6,$AC,$00,$00
        $86DD               .byte $AC,$00,$00,$72,$94,$00,$00,$97,$94,$00,$00,$97,$94,$F0,$F0,$97
        $86ED               .byte $AA,$8E,$8F,$AB,$92,$00,$00,$00,$7E,$93,$00,$00,$81,$7F,$92,$00
        $86FD               .byte $7E,$7F,$7E,$93,$7E,$7F,$98,$99,$A2,$7F,$A8,$A9,$7E,$7F,$92,$93
        $870D               .byte $81,$7F,$7E,$7F,$94,$79,$7D,$97,$94,$78,$7C,$97,$94,$7B,$EF,$97
        $871D               .byte $AA,$8E,$8F,$AB,$87,$88,$89,$8A,$8B,$8C,$8D,$80,$D5,$D5,$D5,$D5
        $872D               .byte $92,$93,$92,$93,$94,$9A,$C7,$97,$94,$9A,$C7,$97,$94,$9A,$C7,$97
        $873D               .byte $94,$9A,$C7,$97,$94,$9A,$C7,$97,$D8,$D9,$D9,$CE,$92,$93,$92,$93
        $874D               .byte $7E,$7F,$C6,$81,$CA,$CB,$DC,$DD,$83,$84,$85,$86,$87,$88,$89,$8A
        $875D               .byte $83,$84,$85,$86,$B4,$B6,$B6,$B5,$B8,$B9,$B9,$B7,$92,$93,$92,$93
        $876D               .byte $81,$7F,$82,$7F,$B4,$B6,$B6,$B5,$B4,$B6,$B6,$B5,$B4,$B6,$B6,$B5
        $877D               .byte $B4,$B6,$B6,$B5,$C6,$A2,$7E,$7F,$95,$7F,$81,$7F,$AE,$9C,$AE,$9C
        $878D               .byte $00,$00,$00,$00,$7E,$7F,$7E,$7F,$DE,$DF,$E0,$E1,$AD,$D4,$9B,$9D
        $879D               .byte $94,$9A,$C7,$97,$7E,$7F,$7E,$7F,$82,$7F,$7E,$82,$D0,$D1,$D2,$D3
        $87AD               .byte $A4,$B6,$B6,$A7,$87,$88,$89,$8A,$8B,$8C,$8D,$80,$D5,$D5,$D5,$D5
        $87BD               .byte $92,$93,$92,$93,$9E,$9F,$81,$7F,$98,$99,$7E,$7F,$98,$99,$7E,$82
        $87CD               .byte $98,$99,$96,$7F,$E6,$E7,$E7,$E8,$E9,$EA,$EA,$EB,$7E,$82,$A3,$81
        $87DD               .byte $96,$7F,$7E,$82,$7E,$7F,$C6,$A2,$7E,$C6,$A2,$C6,$C6,$A2,$C6,$7F
        $87ED               .byte $7E,$7F,$7E,$7F,$7E,$7F,$7E,$AC,$7E,$A3,$AC,$00,$C9,$AA,$00,$00
        $87FD               .byte $96,$00,$00,$72,$AC,$7F,$7E,$7F,$00,$AC,$A3,$7F,$00,$00,$AB,$C9
        $880D               .byte $75,$00,$00,$96,$00,$00,$00,$93,$00,$00,$92,$7F,$00,$93,$7E,$81
        $881D               .byte $92,$7F,$7E,$7F,$EC,$ED,$EC,$ED,$EC,$EE,$ED,$EC,$00,$00,$00,$00
        $882D               .byte $00,$B0,$00,$93,$EC,$ED,$EC,$ED,$ED,$EC,$ED,$EC,$00,$00,$00,$00
        $883D               .byte $92,$93,$92,$93,$EC,$ED,$EC,$ED,$ED,$EC,$EE,$ED,$00,$00,$00,$00
        $884D               .byte $92,$00,$B0,$00,$98,$99,$7E,$7F,$A8,$A9,$7E,$C6,$92,$93,$81,$7F
        $885D               .byte $7E,$7F,$7E,$82,$F6,$F8,$A0,$A0,$F7,$F9,$A0,$A0,$F6,$F8,$A0,$A0
        $886D               .byte $F7,$F9,$A0,$A0,$A0,$A0,$F6,$F8,$A0,$A0,$F7,$F9,$A0,$A0,$F6,$F8
        $887D               .byte $A0,$A0,$F7,$F9,$F6,$F8,$F6,$F8,$F7,$F9,$F7,$F9,$F6,$F8,$F6,$F8
        $888D               .byte $F7,$F9,$F7,$F9

You said that the open door is 0x14 and 0x28 and closed door is 0x20 and 0x2B.
The open door graphics is found at $85A5 for top and $86E1 for bottom. These addresses correspond to offsets 0x188 and 0x2C0 respectively from the beginning of that data. Not only is 0x188 not a multiple of 0x14, and 0x2C0 not a multiple of 0x28, their distance (312) is not an integer multiple of the distance between their indexes. This suggests that adding new metatiles to the table might not be trivial (assuming we want the closed-for-night door to have a different appearance than a closed-for-ever door). I know the beginning of that table looks like nametable attributes.

The metatile number locations you quoted belong, unsurprisingly, to a table defining that particular screen (56 bytes):
Screen_Map0_0_and_0_1_and_0_3_and_0_4
        $8577               .byte $18,$12,$34,$31,$34,$13,$18,$18,$3D,$12,$31,$30,$31,$13,$3D,$3E
        $8587               .byte $15,$12,$31,$19,$31,$13,$15,$13,$21,$12,$30,$15,$30,$13,$21,$13
        $8597               .byte $2C,$12,$15,$14,$15,$13,$2C,$13,$25,$10,$25,$28,$25,$11,$25,$11
        $85A7               .byte $01,$01,$01,$01,$01,$01,$01,$01

The format of this table is simple enough, it's just metatile numbers, and there's about 222 of these screens in total in various locations in the ROM.

Turambar

I don't know how to add more metatiles to the game, I don't have the game code in front of me to make changes and compile, but I color coded this data to make it easier to read.
There are 0x43 (67) nametable attributes that correspond with 0x43 (67) metatiles and there is one byte at the beginning that I don't know about.

Spoiler

Not sure what this is
Nametable attributes
Metatiles


$841D  $44,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
$842D  $00,$06,$09,$66,$99,$55,$55,$62,$98,$AA,$55,$15,$45,$11,$50,$50
$843D  $55,$55,$55,$AA,$AA,$FF,$05,$45,$15,$55,$55,$51,$55,$55,$55,$55
$844D  $AA,$55,$55,$55,$55,$55,$5A,$44,$50,$55,$05,$05,$55,$65,$55,$95
$845D  $54,$88,$22,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
$846D  $00,$00,$00,$00,$F6,$F8,$F6,$F8,$F7,$F9,$F7,$F9,$00,$00,$00,$00
$847D  $00,$00,$00,$00,$F3,$F4,$F5,$FA,$00,$74,$75,$00,$00,$00,$74,$75
$848D  $00,$00,$00,$74,$F5,$FA,$F1,$F2,$00,$72,$73,$00,$72,$73,$00,$00
$849D  $73,$00,$00,$00,$74,$75,$00,$00,$00,$74,$75,$00,$00,$00,$74,$75
$84AD  $00,$00,$00,$74,$00,$00,$72,$73,$00,$72,$73,$00,$72,$73,$00,$00
$84BD  $73,$00,$00,$00,$F6,$F8,$00,$00,$F7,$F9,$00,$00,$F6,$F8,$00,$00
$84CD  $F7,$F9,$00,$00,$00,$00,$F6,$F8,$00,$00,$F7,$F9,$00,$00,$F6,$F8
$84DD  $00,$00,$F7,$F9,$FB,$FD,$00,$00,$FC,$FE,$00,$00,$FB,$FD,$00,$00
$84ED  $FC,$FE,$00,$00,$00,$00,$FB,$FD,$00,$00,$FC,$FE,$00,$00,$FB,$FD
$84FD  $00,$00,$FC,$FE,$F6,$F8,$F6,$F8,$F7,$F9,$F7,$F9,$00,$00,$00,$00
$850D  $75,$00,$00,$00,$F6,$F8,$F6,$F8,$F7,$F9,$F7,$F9,$00,$00,$00,$00
$851D  $00,$00,$00,$72,$FB,$FD,$FB,$FD,$FC,$FE,$FC,$FE,$00,$00,$00,$00
$852D  $00,$00,$00,$00,$65,$66,$66,$67,$65,$66,$66,$67,$00,$68,$00,$00
$853D  $00,$68,$00,$00,$FB,$FD,$F6,$F8,$FC,$FE,$F7,$F9,$FB,$FD,$F6,$F8
$854D  $FC,$FE,$F7,$F9,$F6,$F8,$FB,$FD,$F7,$F9,$FC,$FE,$F6,$F8,$FB,$FD
$855D  $F7,$F9,$FC,$FE,$00,$B0,$E2,$7F,$00,$B2,$E2,$9C,$00,$C9,$C9,$91
$856D  $00,$96,$96,$96,$7E,$E3,$B0,$00,$AE,$E3,$B3,$00,$CF,$C9,$C9,$00
$857D  $96,$96,$96,$00,$00,$B0,$E2,$7F,$00,$B0,$E4,$A2,$00,$B1,$E2,$7F
$858D  $00,$B0,$E2,$7F,$7E,$E3,$B0,$00,$C6,$E5,$B0,$00,$7E,$E3,$B1,$00
$859D  $7E,$E3,$B0,$00,$7E,$7F,$7E,$7F,$DE,$DF,$E0,$E1,$AD,$00,$00,$9D
$85AD  $94,$00,$00,$97,$7E,$7F,$81,$7F,$7E,$D6,$D6,$C6,$7E,$D7,$D7,$7F
$85BD  $81,$93,$92,$7F,$00,$B0,$C8,$C8,$00,$B0,$00,$00,$00,$B1,$00,$93
$85CD  $00,$B0,$E2,$7F,$C8,$C8,$B0,$00,$00,$00,$B0,$00,$92,$00,$B1,$00
$85DD  $7E,$E3,$B0,$00,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0,$A0
$85ED  $A0,$A0,$A0,$A0,$81,$BA,$BB,$96,$BC,$BD,$BE,$BF,$81,$C0,$C1,$C6
$85FD  $7E,$C2,$C3,$A2,$00,$00,$00,$93,$00,$00,$92,$9C,$00,$00,$CF,$C9
$860D  $00,$00,$96,$96,$92,$00,$00,$00,$AE,$92,$00,$00,$C9,$91,$00,$00
$861D  $96,$96,$00,$00,$7E,$7F,$9E,$9F,$81,$7F,$98,$99,$A3,$81,$98,$99
$862D  $7E,$82,$98,$99,$C8,$C8,$C8,$C8,$00,$00,$00,$00,$D0,$D1,$D2,$D3
$863D  $A4,$A5,$A6,$A7,$C8,$C8,$C8,$C8,$00,$00,$00,$00,$92,$93,$92,$93
$864D  $96,$7F,$7E,$7F,$81,$7F,$7E,$7F,$7E,$AA,$81,$7F,$7E,$82,$A3,$81
$865D  $96,$7F,$7E,$82,$7E,$7F,$7E,$7F,$DE,$DF,$E0,$E1,$AD,$77,$AF,$9D
$866D  $94,$78,$7C,$97,$CA,$CB,$DC,$DD,$83,$84,$85,$86,$87,$88,$89,$8A
$867D  $83,$84,$85,$86,$90,$A1,$C4,$00,$90,$A1,$C4,$00,$90,$A1,$C4,$00
$868D  $90,$A1,$C4,$00,$90,$A1,$C4,$00,$90,$A1,$C4,$00,$90,$A1,$C4,$00
$869D  $C5,$CC,$CD,$00,$00,$00,$00,$00,$DA,$DA,$DA,$DA,$DB,$DB,$DB,$DB
$86AD  $DB,$DB,$DB,$DB,$7E,$7F,$7E,$81,$AE,$95,$AE,$82,$CF,$C9,$C9,$C9
$86BD  $96,$96,$96,$96,$AC,$7F,$7E,$7F,$00,$AC,$A3,$7F,$00,$00,$AC,$A2
$86CD  $75,$00,$00,$AC,$7E,$7F,$7E,$AC,$7E,$A3,$AC,$00,$C6,$AC,$00,$00
$86DD  $AC,$00,$00,$72,$94,$00,$00,$97,$94,$00,$00,$97,$94,$F0,$F0,$97
$86ED  $AA,$8E,$8F,$AB,$92,$00,$00,$00,$7E,$93,$00,$00,$81,$7F,$92,$00
$86FD  $7E,$7F,$7E,$93,$7E,$7F,$98,$99,$A2,$7F,$A8,$A9,$7E,$7F,$92,$93
$870D  $81,$7F,$7E,$7F,$94,$79,$7D,$97,$94,$78,$7C,$97,$94,$7B,$EF,$97
$871D  $AA,$8E,$8F,$AB,$87,$88,$89,$8A,$8B,$8C,$8D,$80,$D5,$D5,$D5,$D5
$872D  $92,$93,$92,$93,$94,$9A,$C7,$97,$94,$9A,$C7,$97,$94,$9A,$C7,$97
$873D  $94,$9A,$C7,$97,$94,$9A,$C7,$97,$D8,$D9,$D9,$CE,$92,$93,$92,$93
$874D  $7E,$7F,$C6,$81,$CA,$CB,$DC,$DD,$83,$84,$85,$86,$87,$88,$89,$8A
$875D  $83,$84,$85,$86,$B4,$B6,$B6,$B5,$B8,$B9,$B9,$B7,$92,$93,$92,$93
$876D  $81,$7F,$82,$7F,$B4,$B6,$B6,$B5,$B4,$B6,$B6,$B5,$B4,$B6,$B6,$B5
$877D  $B4,$B6,$B6,$B5,$C6,$A2,$7E,$7F,$95,$7F,$81,$7F,$AE,$9C,$AE,$9C
$878D  $00,$00,$00,$00,$7E,$7F,$7E,$7F,$DE,$DF,$E0,$E1,$AD,$D4,$9B,$9D
$879D  $94,$9A,$C7,$97,$7E,$7F,$7E,$7F,$82,$7F,$7E,$82,$D0,$D1,$D2,$D3
$87AD  $A4,$B6,$B6,$A7,$87,$88,$89,$8A,$8B,$8C,$8D,$80,$D5,$D5,$D5,$D5
$87BD  $92,$93,$92,$93,$9E,$9F,$81,$7F,$98,$99,$7E,$7F,$98,$99,$7E,$82
$87CD  $98,$99,$96,$7F,$E6,$E7,$E7,$E8,$E9,$EA,$EA,$EB,$7E,$82,$A3,$81
$87DD  $96,$7F,$7E,$82,$7E,$7F,$C6,$A2,$7E,$C6,$A2,$C6,$C6,$A2,$C6,$7F
$87ED  $7E,$7F,$7E,$7F,$7E,$7F,$7E,$AC,$7E,$A3,$AC,$00,$C9,$AA,$00,$00
$87FD  $96,$00,$00,$72,$AC,$7F,$7E,$7F,$00,$AC,$A3,$7F,$00,$00,$AB,$C9
$880D  $75,$00,$00,$96,$00,$00,$00,$93,$00,$00,$92,$7F,$00,$93,$7E,$81
$881D  $92,$7F,$7E,$7F,$EC,$ED,$EC,$ED,$EC,$EE,$ED,$EC,$00,$00,$00,$00
$882D  $00,$B0,$00,$93,$EC,$ED,$EC,$ED,$ED,$EC,$ED,$EC,$00,$00,$00,$00
$883D  $92,$93,$92,$93,$EC,$ED,$EC,$ED,$ED,$EC,$EE,$ED,$00,$00,$00,$00
$884D  $92,$00,$B0,$00,$98,$99,$7E,$7F,$A8,$A9,$7E,$C6,$92,$93,$81,$7F
$885D  $7E,$7F,$7E,$82,$F6,$F8,$A0,$A0,$F7,$F9,$A0,$A0,$F6,$F8,$A0,$A0
$886D  $F7,$F9,$A0,$A0,$A0,$A0,$F6,$F8,$A0,$A0,$F7,$F9,$A0,$A0,$F6,$F8
$887D  $A0,$A0,$F7,$F9,$F6,$F8,$F6,$F8,$F7,$F9,$F7,$F9,$F6,$F8,$F6,$F8
$888D  $F7,$F9,$F7,$F9

[close]

Bisqwit

Quote from: Turambar on April 29, 2015, 07:51:17 AM
I don't know how to add more metatiles to the game, I don't have the game code in front of me to make changes and compile, but I color coded this data to make it easier to read.
There are 0x43 (67) nametable attributes that correspond with 0x43 (67) metatiles and there is one byte at the beginning that I don't know about.
The problem with there being 0x43 metatiles, each 16 bytes long, is that the offset between tile 0x14 ($85A5) and tile 0x28 ($86E1) should be 16*(0x28-0x14) = 320 bytes, but it is 316っ

*beat*

Yeah, tile 0x14 begins at $85A1. Then it matches. Byte: Offset to the first metatile. Metatile number 0 is unused.
The attribute corresponding to a metatile number is table[metatilenumber], and the metatile itself begins at table[table[0] + metatilenumber*16]. This is accomplished by the routine at $EA57. The routine sets the pointer at $16 to point to the beginning of this room's metatile table (one of town,mansions,forests&bridges,wilderness,wastelands and ruins), and the pointer at $0F:$08 to point to the beginning of a particular metatile. The routine at $E7F4 sets the pointer at $16 to point to the beginning of a particular row in the metatile pointed by $0F:$08.
$EA4B seems to be the routine that reads the 56-byte table and retrieves the particular metatile number, so this would be the only routine I would need to change.

Changes required, in order to use the more efficient metatile patching than single-tile patching:
-- Change all town screens to refer to a magic metatile (say, $94 and $A8) when they are referring to $14 and $28 respectively. This will rather increase the patch size, as it requires a number of scattered changes throughout the ROM. It will also make the patch slightly incompatible with ROM hacks that change the level data.
-- Add night-closed-door metatiles in the town metatile table.
-- Relocate the town metatile table, because when it's grown, it can't fit in its old spot. Obviously I need to capture the entire town metatile table in the insertor so it can be placed elsewhere. This rather increases the patch size, too. It will also make the patch seriously more incompatible with ROM hacks that change the level data.
-- Change the $EA4B routine to check if the metatile number is the magic one (a negative number, such as $80; adds only two cycles to the normal case processing). If it's not, proceed as normal. Otherwise, if it's day, give metatile number N & $7F, and if it's night, give the newly added metatile number, one of the two, depending on N.
-- Of course, the $EA4B routine must be relocated because it no longer fits in its old spot. This necessitates patching all the spots where the function is called. (Because adding a JMP instruction at the original location of the function is not how I roll.) Again, a number of scattered changes throughout the ROM.

Turambar

Now that there is no more confusion or mysteries and there is a clear goal, I lick my lips and rub my hands together waiting for the next patch.
:laugh: :beer:

Bisqwit

Quote from: Turambar on April 29, 2015, 09:16:00 AMNow that there is no more confusion or mysteries
Well, there is a mystery: How to efficiently refresh the entire background graphics without pausing the game...
It must be done over several frames of course. And it must work also when the screen is scrolling at the same time, and when it might be interrupted by a dialog popping up (such as the status screen).

helaku

Bisqwit do you think you can repair this bug: when is night and you stand in the front of a door you can shoot holy water on it like it's something solid.
Here is a screenshot:
http://gifmaker.cc/PlayGIFAnimation.php?folder=2015042906r6wxHKs5qCmzpyI0OJt2ee&file=output_D2dOdp.gif

P.S. I'm very happy to see that you work on a fix with the opened doors ;D
Have at you!

Turambar

Quote from: Bisqwit on April 29, 2015, 02:56:50 PM
Well, there is a mystery: How to efficiently refresh the entire background graphics without pausing the game...
It must be done over several frames of course. And it must work also when the screen is scrolling at the same time, and when it might be interrupted by a dialog popping up (such as the status screen).
I wouldn't really call that a mystery. Seems like a programming task, like most others, where you just have to think about it for a while, write some code, and then see how it could be written better. A mystery is more like when you're staring at data and not understanding what it means or staring at compressed data and trying to figure out what compression method was used, the kind of programming task where you have trouble even starting.

I was thinking about these doors. Is it true that there is only ever one open door on screen at a time? Knowing that might help.
Maybe if you could scan across each horizontal line looking for an open door and when you encounter it, update just that part of the screen and then stop.
The towns are set up in such a way that there are places on screen that are more likely to have doors than other parts.
Maybe you could scan across certain lines first? Like scan the first line, scan across the middle, then scan across the bottom third?
If there is a door on screen they are likely to be there first.
But I have no idea if this is feasible to program, I'm just talking out of my butt here, and throwing ideas out there.
I don't know if any of this is useful. Here is an ugly image.
Spoiler
[close]

Bisqwit

#867
It is a clever observation that there's only one open door per screen. However, there can be multiple open doors in the background graphics buffer simultaneously.
Observe this video that I made. It shows how Simon's Quest scrolls. A white rectangle shows which area of the nametables the game is updating at any given time.

http://www.youtube.com/watch?v=z7Z5fltXDmU

The game always uses horizontal nametable layout.
At any given time when the screen is scrolling horizontally, the game updates a single metatile per frame, approximately half a screenful ahead of where the camera is. This method is highly redudant. Each metatile is drawn four times. Additionally, if the screen is scrolling vertically, the game updates a single 512x8 pixel stripe at once (64 tiles) per frame.

This is off-topic, but for comparison, here's how various other games do it. I've been meaning to do a YouTube video series about this topic that I find highly fascinating.

Super Mario Bros. 2: http://youtu.be/swuI_KpommQ
The game uses horizontal layout for horizontal scenes, and switches to vertical layout for vertical scenes.
When scrolling horizontally, it updates a 16-pixel wide column of tiles pretty close to the screen edges at once, and it does not do redundant updates. It is a pretty optimal way to do it, and there's never a column with incorrect color attributes, even if the camera could see that.
Scrolling vertically is done in dedicated time by pausing the game while the screen scrolls.

Super Mario Bros. 3: http://youtu.be/N-Duurd0ZFk
The game always uses vertical layout. Each level is always two screens tall.* When scrolling horizontally, the game updates a single tile (8x8 pixel) wide two-screen column at the appropriate edge of the screen. The game attempts to hide this using the left-edge blanking bit of the PPU, but it can't avoid discoloration because the attribute data is only supplied for 16x16 units. Vertical scrolling does not involve any nametable updates; it just updates the PPU scrolling offset.
EDIT: *) Except some stages in world 7 with vertical scrolling and horizontal wrapping. They are implemented differently.

Rockman 2: http://youtu.be/qJBLXP40xvU
The game always uses horizontal layout, except for select cutscenes. Like Castlevania II, the game updates 16x16 pixel regions at once, that are about half a screen away from the camera. However, they are updated with minimal redundancy, and the pattern changes from up-to-down to down-to-up depending on whether Mega Man is walking right or left. Like Castlevania II, the scrolling may pull garbage graphics into the nametables at the beginning or end of the level data.
Like Super Mario Bros. 2, this game does vertical scrolling only in dedicated paused moments. However, vertical scrolling in this game is very redundant. Suppose we are currently in screen 3, and we're scrolling up towards screen 4, and our current screen is in the left nametable. First, the neighboring nametable (on the right) is refreshed completely with the screen 4, while the game is paused, because chances are it contains half of the screen 2 and half of the screen 4, or some other unpredictable combination. Then, the scrolling starts. The game draws 64x16 pixel regions on the current nametable (left) as the screen scrolls, gradually changing the current screen into the next screen. Once the scrolling is completed, both nametables contain screen 4. Then, camera is changed to the right-side nametable. Next, the left-side nametable is transformed into screen 5 by rendering 32x64 pixel blocks (two metatiles), while the game is still paused.

Castlevania: http://youtu.be/o-9T4fDppnI
The game, too, always uses horizontal layout, except for select cutscenes.
Unsurprisingly, this uses a similar technique as Simon's Quest. However, there is half the redundancy of Simon's Quest: The refreshing happens at half the rate as in Simon's Quest, even though the screen scrolls at the same rate. I wonder why.
There's also screen-split. Like Mega Man, this game also happily renders garbage level data when the next/previous screen is out of level data bounds. Hooray for systems without memory protection.

Batman: http://youtu.be/qQ1J8lPzDww
This game uses horizontal layout and only updates 8-pixel wide columns at time near the camera edge. It also scrolls vertically, updating single-screen wide 8-pixel tall rows at once (most games update two screens width). It really does nothing more than what is absolutely necessary, and does it beautifully, even if not the fastest way possible.

Duck Tales: http://youtu.be/bTGGFwnKOpo
Being a Capcom game, it bears some similarity to Rockman 2 in terms of scrolling. However, there are two crucial differences: One is that there's a split screen, and the other is that the levels are nonlinear.
Horizontal scrolling works just like it does in Rockman 2, except that the game does great care to avoid overwriting the status bar which always resides at the top of nametable 0.
When scrolling vertically, the current nametable updated in 256x16 pixel wide increments as the screen scrolls, but at the same time, the other nametable is updated too: It puts a 128x16 wide blob on the left side of the screen corresponding to the previous screen from the new location's perspective, and a 128x16 wide blob on the right side of the screen corresponding to the next screen from the new location's perspective.

Ghosts 'n Goblins: http://youtu.be/nrKNw_NZ21k
Like Batman, it updates 8x240 pixel stripes at the horizontal edges of the screen. No vertical scrolling. Despite writing right next to the visible screen, there are no visible artifacts.

Teenage Mutant Ninja Turtles: http://youtu.be/qK46RTdzVII
On technical merits, a horrible, horrible laggy game. This game uses vertical layout.
The overworld has 4-way scrolling. However, it can either scroll horizontally or vertically, but not both at the same time. When it does, it updates the minimal number of 8x8 tiles right next to the visible screen.  In the dungeons, the game acts like Super Mario Bros. 3, except that vertical scrolling is implemented nowhere as sophisticated. (Not seen in the video, because I ran out of disk space.) When the game scrolls vertically, it draws the new content in the nametables quite in a normal manner using 256x8 pixel updates, but when it hits the location of the status bar, the status bar is instantly relocated in another spot in the nametables.
Additionally, the status bar is constantly updated while the game runs. Every odd frame, a different portion of the status bar is updated, so that each element is updated about four times in a second.

I can't wait to make a similar video about Big Foot. It's my favourite. The mountain climbing scenarios got two independent four-way scrolling regions and several screen splits. I've seen how it does it, including studying it at the disassemble level, and it's incredible.

EDIT: Here's how Big Foot does it.
https://www.youtube.com/watch?v=eiMMvQNBZ9U

Bregalad

Quote[...] about this topic that I find highly fascinating.
I agree, this is absolutely fascinating :)
I don't know how you can see if there is redundancy in updates, since you cannot see this in a name table viewer. However, I don't think it hurts to have redundant updates, as long as they are correct. Why add extra resources to add logic that skip the update if it was already done, when the result is the same?

QuoteSuper Mario Bros. 3 [...] The game always uses vertical layout. Each level is always two screens tall.
Just to point out, this is not true. There is a couple of cylindrical levels, that scrolls only vertically and where mario can warp from left to right or right to left on the screen. Those use horizontal layout (or vertical mirroring).

Turambar

Those videos are neato. Now I have a better idea why Mega Man 2 pauses so long when scrolling up and down.

Bisqwit

Quote from: Bregalad on April 30, 2015, 11:15:13 AMI don't know how you can see if there is redundancy in updates, since you cannot see this in a name table viewer.
Did you watch my videos? Because–
Quote from: Bisqwit on April 30, 2015, 10:47:18 AMa white rectangle shows which area of the nametables the game is updating at any given time.
When the same area is refreshed several times without the content changing, that's when you know it's redundantly, needlessly, updating it.
EDIT: You may need to watch it in HD to see it.

helaku

Quote from: helaku on April 29, 2015, 04:20:18 PM
Bisqwit do you think you can repair this bug: when is night and you stand in the front of a door you can shoot holy water on it like it's something solid.
Here is a screenshot:
http://gifmaker.cc/PlayGIFAnimation.php?folder=2015042906r6wxHKs5qCmzpyI0OJt2ee&file=output_D2dOdp.gif

P.S. I'm very happy to see that you work on a fix with the opened doors ;D
Have at you!

Bisqwit

I for one do not appreciate reposting for attention. It is as obnoxious as soliciting in YouTube like "upvote so he can see!".
If I am not replying, it doesn't mean I didn't see your post. It means I'll reply when I think of a good answer, and in the meantime, pay attention to other things.

helaku

I don't want attention I was thinking that you pass my question.
No problem then ;D


P.S. about paying attention to your thread; I check every day your thread for news ;D
Sadly I don't know how to help you with improvements because I know nothing about rom hacking :(
I wish that I know.
Anyway good luck with your findings :)
Have at you!

Bisqwit

Quote from: helaku on April 29, 2015, 04:20:18 PMBisqwit do you think you can repair this bug: when is night and you stand in the front of a door you can shoot holy water on it like it's something solid.
You can also do it on day. The 0xF0 tile that is the bottom of the door acts as a trigger required by the game for door entry, and coincidentally it also appears to be solid for weapons...

EDIT:

Free space report after patching, without any town doors related work:
. Bank 0 space changed from 1931 to 1893 bytes in 2 fragments
. Bank 1 space changed from 1219 to 1054 bytes in 5 fragments
. Bank 3 space changed from 7286 to 1041 bytes in 3 fragments
. Bank 4 space changed from 5544 to 1330 bytes in 5 fragments
. Bank 7 space changed from 1357 to 37 bytes in 20 fragments
. Total before: 24337  after: 12355  use: 11982

Free space report after patching, with town doors using 8x8 tile patching (before whole-screen refreshing is implemented):
. Bank 0 space changed from 1931 to 1893 bytes in 2 fragments
. Bank 1 space changed from 1219 to 1054 bytes in 5 fragments
. Bank 3 space changed from 7286 to 1207 bytes in 2 fragments
. Bank 4 space changed from 5544 to 1212 bytes in 5 fragments
. Bank 7 space changed from 1524 to 38 bytes in 21 fragments
. Total before: 24504  after: 12404  use: 12100

Free space report after patching, with town doors using 32x32 metatile patching suggested by Turambar (before whole-screen refreshing is implemented):
. Bank 0 space changed from 1931 to 1893 bytes in 2 fragments
. Bank 1 space changed from 1219 to 1054 bytes in 5 fragments
. Bank 2 space changed from 238 to 211 bytes in 1 fragments
. Bank 3 space changed from 7286 to 1219 bytes in 2 fragments
. Bank 4 space changed from 6684 to 1208 bytes in 4 fragments
. Bank 7 space changed from 1536 to 38 bytes in 21 fragments
. Total before: 25656  after: 12385  use: 13271

Free space report after patching, without town doors, but with optimizations from both 8x8 and 32x32 code:
. Bank 0 space changed from 1931 to 1893 bytes in 2 fragments
. Bank 1 space changed from 1219 to 1054 bytes in 5 fragments
. Bank 2 space changed from 238 to 227 bytes in 1 fragments
. Bank 3 space changed from 7286 to 1219 bytes in 2 fragments
. Bank 4 space changed from 5544 to 1242 bytes in 3 fragments
. Bank 7 space changed from 1536 to 38 bytes in 21 fragments
. Total before: 24516  after: 12435  use: 12081

Gained 80 bytes of free space in the ROM from optimizations alone! It also gained 179 bytes of additional storage in the common bank. Both of these improvements will help a great deal in fitting less compressible translations like Dutch into the ROM, even if the night-door support is ultimately never finished and/or enabled, and in adding new program features. Nothing is more frustrating than getting an error message "Could not fit blob ___ anywhere in the ROM" from the linker, because that means the ROM will be broken, and this helps avoid that.


May 04, 2015, 02:06:37 PM - (Auto Merged - Double Posts are not allowed before 7 days.)


Quote from: elbobelo on January 07, 2013, 08:38:07 AMI wouldn't waste time adding achievements, here is what should be added instead.

There is one scene where Simon waits by the cliff-side and a whirlwind carries him off to a mansion.  In this mansion, Simon should "prossess" a special item that, when used, can summon the Whirl Wind at any time.  Now that you have the Map, you should be brought to the map screen in which you can choose your destination.  Then the Whirlwind drops you off there.

That would be my next priority if I were working on this hack.
The whirlwind is not a living creature or a spirit, despite what the USA translation suggests. As such, it is also hardly a taxi that you can order around.
It is a natural phenomenon that takes you up the cliff's edge. It does not even move you very far from where you were, if you look at the map.
So what does the crystal have to do with it? Beats me. Considering the crystal also does causes water to withdraw into earth in select places, maybe it has inherent physical powers in the game's world. After all, it's a world in which all of these magical beasts can be animated, so why should we assume the same laws of physics hold there as here?

EDIT: Oops, I just realized that I did reply to that comment earlier. I just couldn't find it at first, and I thought I had left someone's question/post unanswered for two years. Sorry about the duplicate answer.

Bisqwit

Just a progress report.

I've been working hard on that town-doors feature this month, putting dozens of hours into it.

So far, it's quite broken. I'm having a lot of trouble correlating the current scrolling position into map data coordinates and then map data coordinates into nametable coordinates.
What you see in this example screenshot below is that the automatic whole-screen refresher miscalculated the location for the church door, and placed it slightly too high. It also miscalculated the location for the holywater vendor's door, and placed it not only too high, but also in the wrong nametable (256 pixels too far left). Additionally, the latter door is broken and missing its top arch, and there are unexplained bits of yet another door found in the between of two buildings.



This is what I have been tearing out my hair for the last few weekends. For who is curious, you can find the current source code of that particular feature at: http://bisqwit.iki.fi/kala/towndoors_snap.html and http://bisqwit.iki.fi/kala/towndoors_snap2.html (the latter shows also how any patch is composed in my insertor in general).

EDIT: To recap, other things that are still on the TODO list are, in order of priority:
-- Adding custom music to the cinematic prologue
-- More languages support!
-- Adding a credits screen behind the title screen, activated by pressing some particular key
-- Adding achievements (contingent on SRAM support)
Other things that are not on TODO list, but which I have promised to keep in mind:
-- Possibility that a death warps you back into first town
-- Placeholder music into the cinematic prologue while proper music is still being developed
-- What have I forgotten?

NES Boy

Quote from: Bisqwit on May 09, 2015, 07:05:35 PM
To recap, other things that are still on the TODO list are, in order of priority:
-- Adding custom music to the cinematic prologue
-- More languages support!
-- Adding a credits screen behind the title screen, activated by pressing some particular key
-- Adding achievements (contingent on SRAM support)
Other things that are not on TODO list, but which I have promised to keep in mind:
-- Possibility that a death warps you back into first town
-- Placeholder music into the cinematic prologue while proper music is still being developed
-- What have I forgotten?

That fourth point reminds me of Retro Achievements, a site and community that offers special editions of emulators such as FCEUX, SNES9X, Gens, and VBA (there's one of PC Engine as well, but I don't know which emulator it's based on) that supports custom achievements that the on the site. Yes, Simon's Quest is one of the games on there.

Turambar

That's a pretty neat site. I just got all the achievements for Castlevania 2. I've noticed that when you have the leather whip it seems like your subweapons don't do any damage. What's with that? The achievement for getting the silk bag should be called "What a Fabulous Night to Wear a Purse!" :laugh:

Bisqwit

Quote from: Turambar on May 11, 2015, 06:42:22 PMThe achievement for getting the silk bag should be called "What a Fabulous Night to Wear a Purse!" :laugh:
That's a great idea. I was planning on calling that achievement Duck Hunt though.

ShadowOne333

Bisquit, one question just out of curiosity, not trying to be nitpicky:

Why replace the "What a horrible night to have a curse" and "The morning sun has vanquished the horrible night" iconic text from the prompt windows? :P