Как добавить Spin Dash в Sonic 1 — различия между версиями
NeKit (обсуждение | вклад) |
NeKit (обсуждение | вклад) |
||
Строка 335: | Строка 335: | ||
Постройте [[ROM]], все должно заработать. | Постройте [[ROM]], все должно заработать. | ||
+ | |||
+ | [[Категория:Как сделать...]] |
Версия 21:58, 13 февраля 2010
Движок Sonic the Hedgehog 2 во многом схож с движком Sonic 1, так что можно портировать Спин Дэш из Sonic 2, немного адаптировав его код для работы на другом движке. Все эти адаптации уже сделаны для Вас в этом гиде, вы даже можете проверить сходства предоставленых кодов, откопав суброутину Спин Дэша в коде Второго Соника.
Вставка основы Спин Дэша
Найдите в исходном коде лейбл Obj01_MdNormal и добавьте прямо после него строчку:
<asm> bsr.w Sonic_SpinDash ; ++ branch to Spin Dash </asm>
Теперь каждый раз, когда ежик стоит, будет запукаться суброутина Спин Дэша, которая в свою очередь будет проверять, можно ли выполнять Спин Дэш.
Настало время вставлять саму суброутину Sonic_SpinDash. Вставьте ее после суброутины Sonic_JumpHeight. Найдите конец суброутины,
<asm>
- End of function Sonic_JumpHeight
</asm>
и вставьте после него код:
<asm>
- ---------------------------------------------------------------------------
- Subroutine allowing Sonic to do Spin Dash
- ---------------------------------------------------------------------------
- ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
Sonic_SpinDash: tst.b $39(a0) bne.s loc_1AC8E cmpi.b #8,$1C(a0) bne.s locret_1AC8C move.b ($FFFFF603).w,d0 andi.b #$70,d0 beq.w locret_1AC8C move.b #2,$1C(a0) move.w #$BE,d0 jsr (PlaySound_Special).l addq.l #4,sp move.b #1,$39(a0) move.w #0,$3A(a0) cmpi.b #$C,$28(a0) bcs.s loc_1AC84 move.b #2,($FFFFD11C).w
loc_1AC84: bsr.w Sonic_LevelBound bsr.w Sonic_AnglePos
locret_1AC8C: rts
- ---------------------------------------------------------------------------
loc_1AC8E: move.b ($FFFFF602).w,d0 btst #1,d0 bne.w loc_1AD30 move.b #$E,$16(a0) move.b #7,$17(a0) move.b #2,$1C(a0) addq.w #5,$C(a0) move.b #0,$39(a0) moveq #0,d0 move.b $3A(a0),d0 add.w d0,d0 move.w word_1AD0C(pc,d0.w),$14(a0) tst.b ($FFFFFE19).w beq.s loc_1ACD0 move.w word_1AD1E(pc,d0.w),$14(a0)
loc_1ACD0: move.w $14(a0),d0 subi.w #$800,d0 add.w d0,d0 andi.w #$1F00,d0 neg.w d0 addi.w #$2000,d0 move.w d0,($FFFFEED0).w btst #0,$22(a0) beq.s loc_1ACF4 neg.w $14(a0)
loc_1ACF4: bset #2,$22(a0) move.b #0,($FFFFD11C).w move.w #$BC,d0 jsr (PlaySound_Special).l bra.s loc_1AD78
- ---------------------------------------------------------------------------
word_1AD0C: dc.w $800 ; 0 dc.w $880 ; 1 dc.w $900 ; 2 dc.w $980 ; 3 dc.w $A00 ; 4 dc.w $A80 ; 5 dc.w $B00 ; 6 dc.w $B80 ; 7 dc.w $C00 ; 8
word_1AD1E: dc.w $B00 ; 0 dc.w $B80 ; 1 dc.w $C00 ; 2 dc.w $C80 ; 3 dc.w $D00 ; 4 dc.w $D80 ; 5 dc.w $E00 ; 6 dc.w $E80 ; 7 dc.w $F00 ; 8
- ---------------------------------------------------------------------------
loc_1AD30: ; If still charging the dash... tst.w $3A(a0) beq.s loc_1AD48 move.w $3A(a0),d0 lsr.w #5,d0 sub.w d0,$3A(a0) bcc.s loc_1AD48 move.w #0,$3A(a0)
loc_1AD48: move.b ($FFFFF603).w,d0 andi.b #$70,d0 beq.w loc_1AD78 ;move.w #$900,$1C(a0) move.w #$BE,d0 jsr (PlaySound_Special).l addi.w #$200,$3A(a0) cmpi.w #$800,$3A(a0) bcs.s loc_1AD78 move.w #$800,$3A(a0)
loc_1AD78: addq.l #4,sp cmpi.w #$60,($FFFFEED8).w beq.s loc_1AD8C bcc.s loc_1AD88 addq.w #4,($FFFFEED8).w
loc_1AD88: subq.w #2,($FFFFEED8).w
loc_1AD8C: bsr.w Sonic_LevelBound bsr.w Sonic_AnglePos move.w #$60,($FFFFF73E).w ; reset looking up/down rts
- End of subroutine Sonic_SpinDash
</asm>
Отлично! Теперь у нас есть подобие Спин Дэша, с виду похожее на Спин Дэш из Sonic CD. Файл:S g3 scr.gif
Исправление багов
Камера не всегда может успевать прокручиваться вниз за Соником, особенно при прохождении двойных S-образных труб в Green Hill Zone. К тому же у камеры в первом Сонике есть врожденный баг. Он заключается в том, что если Соник зайдет ниже своей высоты за нижнюю границу камеры, игра посчитает что он свалился в пропасть и убьет его. Чтобы исправить этот баг, идите к суброутине Boundary_Bottom и замените ее на это:
<asm> Boundary_Bottom: move.w ($FFFFF726).w,d0 move.w ($FFFFF72E).w,d1 cmp.w d0,d1 ; screen still scrolling down? blt.s Boundary_Bottom_locret ; if so, don't kill Sonic cmpi.w #$501,($FFFFFE10).w ; is level SBZ2 ? bne.w KillSonic ; if not, kill Sonic cmpi.w #$2000,($FFFFD008).w bcs.w KillSonic clr.b ($FFFFFE30).w ; clear lamppost counter move.w #1,($FFFFFE02).w ; restart the level move.w #$103,($FFFFFE10).w ; set level to SBZ3 (LZ4)
Boundary_Bottom_locret: rts </asm>
Еще один заметный баг, который вскроется после исправления Spike Bug (смотрите [[Как изменить поведение шипов в Sonic 1) — отказ Соника прекращать Спин Дэш, после того как он накололся на иголках (Spikes). Для исправления бага, идите к лейбелу Hurt_ChkSpikes и вставьте прямо за ним строчку:
<asm> move.b #0,$39(a0) ; clear Spin Dash flag </asm>
Следующий баг, который предстоит исправить, заключается в том, что враг может спокойно поранить Соника, когда он совершает разгон на месте. Чтобы его исправить, идите к суброутине Touch_Enemy и перед строчкой
<asm> cmpi.b #2,$1C(a0) ; is Sonic rolling? </asm>
вставьте проверку на Спин Дэш:
<asm> cmpi.b #$1F,$1C(a0) ; is Sonic Spin Dashing? beq.w loc_1AF40 ; if yes, branch </asm>
Скомпилируйте ROM и убедитесь, что эти баги исправлены.
Вставка анимации Спин Дэша
Чтобы Спин Дэш смотрелся как надо, сделать ему нормальную анимацию, чем мы сейчас и займемся.
Для начала, нужно портировать арт Спин Дэша из Sonic 2. Это уже сделано за Вас, скачайте Файл:Spindash S1 Art.7z. Достаньте из него spindash.bin и поместите этот файл в папку artunc.
Теперь в исходном коде игры найдите лейбл Art_Sonic и после строчки
<asm> incbin artunc\sonic.bin </asm>
вставьте:
<asm> incbin artunc\spindash.bin ; Spin Dash art </asm>
Арт Соника, особенный, так как каждый раз динамически подгружается нужный спрайту набор тайлов. Новый арт требуется вписать в список динамически загружаемых тайлов для дайльнешей работы с ним.
Откройте файл _inc/Sonic dynamic pattern load cues.asm и вставьте эти строки перед лейбелом SonPLC_Blank:
<asm> dc.w SonPLC_SpinDash1-SonicDynPLC ;58 dc.w SonPLC_SpinDash2-SonicDynPLC ;59 dc.w SonPLC_SpinDash3-SonicDynPLC ;5A dc.w SonPLC_SpinDash4-SonicDynPLC ;5B dc.w SonPLC_SpinDash5-SonicDynPLC ;5C dc.w SonPLC_SpinDash6-SonicDynPLC ;5D </asm>
Эти номерки справа от строк стоят для удобства. Они обозначают номер кадра, который полезно знать для создания покадровой анимации. Мы только что сделали ссылки на лейбелы, в которых содержится информация о подгружаемых тайлах, теперь нужно вставить сами лейбелы.
Почти в самом конце файла, перед строкой
<asm> even </asm>
вставьте нужные лейбелы:
<asm> SonPLC_SpinDash1: dc.b 1, $F5, $10 ; 01 F 510 SonPLC_SpinDash2: dc.b 1, $F5, $20 ; 01 F 520 SonPLC_SpinDash3: dc.b 1, $F5, $30 ; 01 F 530 SonPLC_SpinDash4: dc.b 1, $F5, $40 ; 01 F 540 SonPLC_SpinDash5: dc.b 1, $F5, $50 ; 01 F 550 SonPLC_SpinDash6: dc.b 1, $F5, $60 ; 01 F 560 </asm>
В комментариях справа от строк дано более удобное представление информации. Данные о подгружаемых тайлах имеют формат NN(STTT), где N - количество следуемых за ним данных о тайлах STTT, S - количество погружаемых тайлов (от 1 до 16), T - номер тайла, с которого начинается подгрузка.
Вся эта динамическая подгрузка нужна для экономии VRAM. Ее всего 64 Кб, если загрузить туда весь сониковский арт, а он весит 40 Кб, то не хватит места на остальное.
Но вернемся к делу. Теперь нам нужно слепить спрайты из блоков 8х8, предоставленных в арте.
Откройте файл _maps/Sonic.asm и над строчкой
<asm> byte_21292: dc.b 0 </asm>
вставьте:
<asm> dc.w byte_spdh1-Map_Sonic, byte_spdh2-Map_Sonic dc.w byte_spdh3-Map_Sonic, byte_spdh4-Map_Sonic dc.w byte_spdh5-Map_Sonic, byte_spdh6-Map_Sonic </asm>
Теперь надо прописать вышеперечисленные лейбелы. Опять, прописывать будем почти в конце файла, перед строкой
<asm> even </asm>
пропишите:
<asm> byte_spdh1: dc.b 1 ; Spin Dash 1 dc.b $F8, $F, 0, 0, $F0 byte_spdh2: dc.b 1 ; Spin Dash 2 dc.b $F8, $F, 0, 0, $F0 byte_spdh3: dc.b 1 ; Spin Dash 3 dc.b $F8, $F, 0, 0, $F0 byte_spdh4: dc.b 1 ; Spin Dash 4 dc.b $F8, $F, 0, 0, $F0 byte_spdh5: dc.b 1 ; Spin Dash 5 dc.b $F8, $F, 0, 0, $F0 byte_spdh6: dc.b 1 ; Spin Dash 6 dc.b $F8, $F, 0, 0, $F0 </asm> Спрайты готовы. То, что мы добавили, называется спрайтовыми маппингами, об их устройстве вы можете посмотреть в справочниках.
Последнее, что осталось сделать — скрепить все спрайты анимацией, которая будет воспроизводится. Откройте _anim/Sonic.asm и перед строкой
<asm> SonAni_Walk: dc.b $FF, 8, 9, $A, $B, 6, 7, $FF </asm>
вставьте:
<asm> dc.w SonAni_SpinDash-SonicAniData ;1F </asm>
Справа записан порядковый номер анимации для справки. Теперь перед строкой
<asm> even </asm>
в конце файла вставьте:
<asm> SonAni_SpinDash: dc.b 0, $58, $59, $58, $5A, $58, $5B, $58, $5C, $58, $5D, $FF </asm>
В этой строке перечислены по порядку номера кадров, включенные в анимацию.
И нам осталось почти ничего, всего лишь отредактировать код Спин Дэша, чтобы он использовал новую анимацию. Идите к суброутине Sonic_SpinDash и замените
<asm> move.b #2,$1C(a0) </asm>
на:
<asm> move.b #$1F,$1C(a0) ; changed from #2 </asm>
Теперь идите к лейбелу loc_1AD48 и раскомментируйте строчку
<asm> move.w #$900,$1C(a0) </asm>
Постройте ROM, все должно заработать.