aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-11-05 11:22:55 +0000
committerJuan J. Martinez <jjm@usebox.net>2023-11-05 11:31:28 +0000
commit2fbdf974338bde8576efdae40a819a76b2391033 (patch)
tree64d41a37470143f142344f9a439d96de3e7918c2 /lib
downloadkitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.tar.gz
kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.zip
Initial import of the open source release
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile21
-rw-r--r--lib/aplib.h4
-rw-r--r--lib/aplib.z80162
-rw-r--r--lib/cpcrslib/GphStrStd.s412
-rw-r--r--lib/cpcrslib/LICENSE20
-rw-r--r--lib/cpcrslib/Makefile19
-rw-r--r--lib/cpcrslib/Sprites.s37
-rw-r--r--lib/cpcrslib/TileMap.h304
-rw-r--r--lib/cpcrslib/Wyz.s1414
-rw-r--r--lib/cpcrslib/cpc_ClrScr.s11
-rw-r--r--lib/cpcrslib/cpc_CollSp.s126
-rw-r--r--lib/cpcrslib/cpc_DisableEnableFirmware.s28
-rw-r--r--lib/cpcrslib/cpc_GetScrAddress.s65
-rw-r--r--lib/cpcrslib/cpc_GetSp.s49
-rw-r--r--lib/cpcrslib/cpc_GphStr.s700
-rw-r--r--lib/cpcrslib/cpc_Keyboard.s344
-rw-r--r--lib/cpcrslib/cpc_PrintStr.s27
-rw-r--r--lib/cpcrslib/cpc_PutMaskSp.s79
-rw-r--r--lib/cpcrslib/cpc_PutMaskSp2x8.s45
-rw-r--r--lib/cpcrslib/cpc_PutMaskSp4x16.s56
-rw-r--r--lib/cpcrslib/cpc_PutSp.s54
-rw-r--r--lib/cpcrslib/cpc_PutSp2x14.s50
-rw-r--r--lib/cpcrslib/cpc_PutSpTr.s75
-rw-r--r--lib/cpcrslib/cpc_PutSpXOR.s79
-rw-r--r--lib/cpcrslib/cpc_PutSprite.s108
-rw-r--r--lib/cpcrslib/cpc_RLI.s39
-rw-r--r--lib/cpcrslib/cpc_RRI.s39
-rw-r--r--lib/cpcrslib/cpc_Random.s34
-rw-r--r--lib/cpcrslib/cpc_SetBorder.s10
-rw-r--r--lib/cpcrslib/cpc_SetColour.s16
-rw-r--r--lib/cpcrslib/cpc_SetInk.s12
-rw-r--r--lib/cpcrslib/cpc_SetMode.s13
-rw-r--r--lib/cpcrslib/cpc_SetModo.s9
-rw-r--r--lib/cpcrslib/cpc_TileMap.s1332
-rw-r--r--lib/cpcrslib/cpc_UnExoOpt.s183
-rw-r--r--lib/cpcrslib/cpc_Uncrunch.s308
-rw-r--r--lib/cpcrslib/cpcrslib.h116
-rw-r--r--lib/cpcrslib/cpcwyzlib.h18
-rw-r--r--lib/cpcrslib/make.bat19
-rw-r--r--lib/plw.h19
-rw-r--r--lib/plw/Makefile34
-rw-r--r--lib/plw/README.md16
-rw-r--r--lib/plw/player/Makefile11
-rw-r--r--lib/plw/player/PlayerLightWeight.asm1694
-rw-r--r--lib/plw/player/PlayerLightWeight_SoundEffects.asm458
-rw-r--r--lib/plw/player/player.asm43
-rw-r--r--lib/plw/plw_init.z8014
-rw-r--r--lib/plw/plw_init_sound_effects.z809
-rw-r--r--lib/plw/plw_is_sound_effect_on.z807
-rw-r--r--lib/plw/plw_play.z806
-rw-r--r--lib/plw/plw_play_sound_effect.z8048
-rw-r--r--lib/plw/plw_player.asm1193
-rw-r--r--lib/plw/plw_player.c3
-rw-r--r--lib/plw/plw_stop.z806
54 files changed, 9998 insertions, 0 deletions
diff --git a/lib/Makefile b/lib/Makefile
new file mode 100644
index 0000000..a8bf391
--- /dev/null
+++ b/lib/Makefile
@@ -0,0 +1,21 @@
+all: aplib.lib cpcrslib.lib plw.lib
+
+AS=sdasz80
+AR=sdar
+
+aplib.lib: aplib.z80
+ $(AS) -o $<
+ $(AR) -rcD $@ aplib.rel
+
+cpcrslib.lib: $(wildcard cpcrslib/*.s)
+ make -C cpcrslib
+
+plw.lib: $(wildcard plw/*.z80)
+ make -C plw
+
+.PHONY: clean
+clean:
+ rm -f *.rel *.lib
+ make -C cpcrslib clean
+ make -C plw clean
+
diff --git a/lib/aplib.h b/lib/aplib.h
new file mode 100644
index 0000000..79de9c6
--- /dev/null
+++ b/lib/aplib.h
@@ -0,0 +1,4 @@
+#ifndef _APLIB_H
+#define _APLIB_H
+extern void aplib_uncompress(const unsigned char *dst, unsigned char *src);
+#endif
diff --git a/lib/aplib.z80 b/lib/aplib.z80
new file mode 100644
index 0000000..6a5d8d4
--- /dev/null
+++ b/lib/aplib.z80
@@ -0,0 +1,162 @@
+; See apultra for licence.
+;
+; Z80 Version by Dan Weiss
+; Call depack.
+;
+; hl = source
+; de = dest
+
+; C convention
+.globl _aplib_uncompress
+; register call
+.globl aplib_depack
+
+; aPPack decompressor
+; original source by dwedit
+; very slightly adapted by utopian
+; optimized by Metalbrain
+
+;hl = source
+;de = dest
+
+; this is to enable undocumented Z80 opcodes in SDCC assembler
+.ez80
+
+_aplib_uncompress::
+ ld hl, #2
+ add hl, sp
+ ld e, (hl)
+ inc hl
+ ld d, (hl)
+ inc hl
+ ld a, (hl)
+ inc hl
+ ld h, (hl)
+ ld l, a
+
+aplib_depack::
+ ld ixl, #128
+
+apbranch1:
+ ldi
+aploop0:
+ ld ixh, #1 ;LWM = 0
+aploop:
+ call ap_getbit
+ jr nc, apbranch1
+ call ap_getbit
+ jr nc, apbranch2
+ ld b, #0
+ call ap_getbit
+ jr nc, apbranch3
+ ld c, #16 ;get an offset
+apget4bits:
+ call ap_getbit
+ rl c
+ jr nc, apget4bits
+ jr nz, apbranch4
+ ld a, b
+apwritebyte:
+ ld (de), a ;write a 0
+ inc de
+ jr aploop0
+apbranch4:
+ and a
+ ex de, hl ;write a previous byte (1-15 away from dest)
+ sbc hl, bc
+ ld a, (hl)
+ add hl, bc
+ ex de, hl
+ jr apwritebyte
+apbranch3:
+ ld c, (hl) ;use 7 bit offset, length = 2 or 3
+ inc hl
+ rr c
+ ret z ;if a zero is encountered here, it is EOF
+ ld a, #2
+ adc a,b
+ push hl
+ ld iyh, b
+ ld iyl, c
+ ld h, d
+ ld l, e
+ sbc hl, bc
+ ld c, a
+ jr ap_finishup2
+apbranch2:
+ call ap_getgamma ;use a gamma code * 256 for offset, another gamma code for length
+ dec c
+ ld a, c
+ sub ixh
+ jr z, ap_r0_gamma ;if gamma code is 2, use old r0 offset,
+ dec a
+ ;do I even need this code?
+ ;bc=bc*256+(hl), lazy 16bit way
+ ld b, a
+ ld c, (hl)
+ inc hl
+ ld iyh, b
+ ld iyl, c
+
+ push bc
+
+ call ap_getgamma
+
+ ex (sp), hl ;bc = len, hl=offs
+ push de
+ ex de, hl
+
+ ld a, #4
+ cp d
+ jr nc, apskip2
+ inc bc
+ or a
+apskip2:
+ ld hl, #127
+ sbc hl, de
+ jr c, apskip3
+ inc bc
+ inc bc
+apskip3:
+ pop hl ;bc = len, de = offs, hl=junk
+ push hl
+ or a
+ap_finishup:
+ sbc hl, de
+ pop de ;hl=dest-offs, bc=len, de = dest
+ap_finishup2:
+ ldir
+ pop hl
+ ld ixh, b
+ jr aploop
+
+ap_r0_gamma:
+ call ap_getgamma ;and a new gamma code for length
+ push hl
+ push de
+ ex de, hl
+ ld d, iyh
+ ld e, iyl
+ jr ap_finishup
+
+ap_getbit:
+ ld a, ixl
+ add a, a
+ ld ixl, a
+ ret nz
+ ld a, (hl)
+ inc hl
+ rla
+ ld ixl, a
+ ret
+
+ap_getgamma:
+ ld bc, #1
+ap_getgammaloop:
+ call ap_getbit
+ rl c
+ rl b
+ call ap_getbit
+ jr c, ap_getgammaloop
+ ret
+
diff --git a/lib/cpcrslib/GphStrStd.s b/lib/cpcrslib/GphStrStd.s
new file mode 100644
index 0000000..08c19ec
--- /dev/null
+++ b/lib/cpcrslib/GphStrStd.s
@@ -0,0 +1,412 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl Simarro (Artaburu) - 2009, 2012 **
+; ******************************************************
+
+cpc_GetScrAddress0: ;en HL están las coordenadas
+
+ ;LD A,H
+ LD (#inc_ancho+1),A
+ LD A,L
+ SRL A
+ SRL A
+ SRL A
+ ; A indica el bloque a multiplicar x &50
+ LD D,A ;D
+ SLA A
+ SLA A
+ SLA A
+ SUB L
+ NEG
+ ; A indica el desplazamiento a multiplicar x &800
+ LD E,A ;E
+ LD L,D
+ LD H,#0
+ ADD HL,HL
+ LD BC,#bloques
+ ADD HL,BC
+ ;HL APUNTA AL BLOQUE BUSCADO
+ LD C,(HL)
+ INC HL
+ LD H,(HL)
+ LD L,C
+ ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO
+ PUSH HL
+ LD D,#0
+ LD HL,#sub_bloques
+ ADD HL,DE
+ LD A,(HL)
+ POP HL
+ ADD H
+ LD H,A
+inc_ancho:
+ LD E,#0
+ ADD HL,DE
+ RET
+
+bloques:
+.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780
+sub_bloques:
+.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38
+
+
+
+
+.globl _cpc_PrintGphStrStd
+
+_cpc_PrintGphStrStd::
+ ld ix,#2
+ add ix,sp
+ ld l,3 (ix)
+ ld h,4 (ix) ;destino
+ ld e,1 (ix)
+ ld d,2 (ix) ;texto origen
+ ld a,0 (ix) ;color
+ ld (#color_uso+1),a
+ JP cpc_PrintGphStrStd0
+
+
+.globl _cpc_PrintGphStrStdXY
+
+_cpc_PrintGphStrStdXY::
+;preparación datos impresión. El ancho y alto son fijos!
+ ld ix,#2
+ add ix,sp
+ ld L,4 (ix)
+ ld A,3 (ix) ;pantalla
+ call cpc_GetScrAddress0
+ ld e,1 (ix)
+ ld d,2 (ix) ;texto origen
+ ld a,0 (ix) ;color
+ ld (#color_uso+1),a
+ JP cpc_PrintGphStrStd0
+
+color0:
+ XOR A
+ CALL metecolor
+ JP sigue
+color1:
+ LD A,#0B00001000
+ CALL metecolor
+ JP sigue
+color2:
+ LD A,#0B10000000
+ CALL metecolor
+ JP sigue
+color3:
+ LD A,#0b10001000
+ CALL metecolor
+ JP sigue
+metecolor:
+ LD (#cc0_gpstd-1),A
+ LD (#cc4_gpstd-1),A
+ SRL A
+ LD (#cc1_gpstd-1),A
+ LD (#cc5_gpstd-1),A
+ SRL A
+ LD (#cc2_gpstd-1),A
+ LD (#cc6_gpstd-1),A
+ SRL A
+ LD (#cc3_gpstd-1),A
+ LD (#cc7_gpstd-1),A
+ RET
+
+cpc_PrintGphStrStd0:
+;; marcará el color con que se imprime
+color_uso:
+ LD A,#1
+ OR A
+ JP Z,color0
+ CP #1
+ JP Z,color1
+ CP #2
+ JP Z,color2
+ CP #3
+ JP Z,color3
+sigue:
+
+ ;trabajo previo: Para tener una lista de trabajos de impresión. No se interrumpe
+ ;la impresión en curso.
+ LD A,(#imprimiendo)
+ CP #1
+ JP Z,add_elemento
+ LD (#direcc_destino),HL
+ EX DE,HL
+ CALL bucle_texto0
+
+;antes de terminar, se mira si hay algo en cola.
+bucle_cola_impresion:
+ LD A,(#elementos_cola)
+ OR A
+ JP Z,terminar_impresion
+ CALL leer_elemento
+ JP bucle_cola_impresion
+
+terminar_impresion:
+ XOR A
+ LD (#imprimiendo),A
+ RET
+entrar_cola_impresion:
+ ;si se está imprimiendo se mete el valor en la cola
+ RET
+add_elemento:
+ DI
+ LD IX,(#pos_cola)
+ LD 0 (IX),L
+ LD 1 (IX),H
+ LD 2 (IX),E
+ LD 3 (IX),D
+ INC IX
+ INC IX
+ INC IX
+ INC IX
+ Ld (#pos_cola),IX
+ LD HL,#elementos_cola
+ INC (HL)
+ EI
+ RET
+leer_elemento:
+ DI
+ LD IX,(#pos_cola)
+ LD L,0 (IX)
+ LD H,1 (IX)
+ LD E,2 (IX)
+ LD D,3 (IX)
+ DEC IX
+ DEC IX
+ DEC IX
+ DEC IX
+ LD (#pos_cola),IX
+ LD HL,#elementos_cola
+ DEC (HL)
+ EI
+ RET
+
+elementos_cola:
+ .DW #0
+pos_cola:
+ .DW cola_impresion
+cola_impresion:
+ .DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; defs 12
+bucle_texto0:
+ LD A,#1
+ LD (#imprimiendo),A
+ LD A,(#first_char8)
+ LD B,A ;resto 48 para saber el número del caracter (En ASCII 0=48)
+ LD A,(HL)
+ OR A ;CP 0
+ RET Z
+ SUB B
+ LD BC,#cpc_Chars8 ;apunto a la primera letra
+ PUSH HL
+ LD L,A
+ LD H,#0
+ ADD HL,HL
+ ADD HL,HL
+ ADD HL,HL
+ ADD HL,BC
+ CALL escribe_letra_gpstd
+ LD HL,(#direcc_destino)
+
+ LD DE,#letra_decodificada
+ CALL cpc_PutSp0_gpstd
+ LD HL,(#direcc_destino)
+ INC HL
+ INC HL
+ LD (#direcc_destino),HL
+ POP HL
+ INC HL
+ JP bucle_texto0
+
+imprimiendo:
+ .db #0
+direcc_destino:
+ .dw #0
+
+
+cpc_PutSp0_gpstd:
+ .DB #0XFD
+ LD H,#8
+ LD B,#7
+ LD C,B
+loop_alto_2_gpstd:
+loop_ancho_2_gpstd:
+ EX DE,HL
+ LDI
+ LDI
+ .DB #0XFD
+ DEC H
+ RET Z
+ EX DE,HL
+salto_linea_gpstd:
+ LD C,#0XFE
+ ADD HL,BC
+ JP NC,loop_alto_2_gpstd
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7
+ JP loop_alto_2_gpstd
+
+
+
+escribe_letra_gpstd: ;; lee el byte y lo interpreta
+ LD IY,#letra_decodificada
+ LD B,#8
+bucle_alto_gpstd:
+ PUSH BC ;leo el byte... ahora se miran sus bits y se rellena el caracter a imprimir
+ XOR A
+ LD B,(HL)
+ BIT 7,B
+ JP Z,cc0_gpstd
+ OR #0b10001000
+cc0_gpstd:
+ BIT 6,B
+ JP Z,cc1_gpstd
+ OR #0b01000100
+cc1_gpstd:
+ BIT 5,B
+ JP Z,cc2_gpstd
+ OR #0b00100010
+cc2_gpstd:
+ BIT 4,B
+ JP Z,cc3_gpstd
+ OR #0b00010001
+cc3_gpstd:
+ ;primer byte
+ LD 0 (IY),A
+ INC IY
+ XOR A
+ BIT 3,B
+ JP Z,cc4_gpstd
+ OR #0b10001000
+cc4_gpstd:
+ BIT 2,B
+ JP Z,cc5_gpstd
+ OR #0b01000100
+cc5_gpstd:
+ BIT 1,B
+ JP Z,cc6_gpstd
+ OR #0b00100010
+cc6_gpstd:
+ BIT 0,B
+ JP Z,cc7_gpstd
+ OR #0b00010001
+cc7_gpstd:
+ ;segundo byte
+ LD 0 (IY),A
+ INC IY
+ INC HL
+ POP BC
+ DJNZ bucle_alto_gpstd
+ RET
+
+
+
+byte_tmp: ;DEFS 2
+ .DB #0,#0
+letra_decodificada:
+ .DB #0,#0,#0,#0,#0,#0,#0,#0 ;DEFS 16
+ .DB #0,#0,#0,#0,#0,#0,#0,#0 ;USO ESTE ESPACIO PARA GUARDAR LA LETRA QUE SE DECODIFICA
+
+;DEFC direcc_destino0s_m1 = direcc_destino
+
+first_char8:
+ .DB #32 ;first defined char number (ASCII)
+cpc_Chars8: ;each bit of each byte is a pixel,#same way as SYMBOL function of Locomotive BASIC.
+ ;; KEY SET BY ANJUEL & NA_TH_AN FROM NANAKO CPC GAME.
+ .DB #0,#0,#0,#0,#0,#0,#0,#0
+ .DB #28,#8,#8,#8,#28,#0,#8,#0
+ .DB #10,#10,#0,#0,#0,#0,#0,#0
+ .DB #36,#126,#36,#36,#36,#126,#36,#0
+ .DB #16,#62,#32,#60,#4,#124,#8,#0
+ .DB #0,#50,#52,#8,#22,#38,#0,#0
+ .DB #0,#16,#40,#58,#68,#58,#0,#0
+ .DB #16,#16,#0,#0,#0,#0,#0,#0
+ .DB #16,#112,#80,#64,#80,#112,#16,#0
+ .DB #8,#14,#10,#2,#10,#14,#8,#0
+ .DB #0,#42,#28,#28,#42,#0,#0,#0
+ .DB #0,#8,#8,#62,#8,#8,#0,#0
+ .DB #0,#0,#0,#0,#12,#12,#0,#0
+ .DB #0,#0,#0,#62,#0,#0,#0,#0
+ .DB #0,#0,#0,#0,#12,#12,#16,#0
+ .DB #0,#4,#8,#16,#32,#64,#0,#0
+ .DB #62,#34,#34,#34,#34,#34,#62,#0
+ .DB #12,#4,#4,#4,#4,#4,#4,#0
+ .DB #62,#34,#2,#62,#32,#34,#62,#0
+ .DB #62,#36,#4,#28,#4,#36,#62,#0
+ .DB #32,#32,#36,#62,#4,#4,#14,#0
+ .DB #62,#32,#32,#62,#2,#34,#62,#0
+ .DB #62,#32,#32,#62,#34,#34,#62,#0
+ .DB #62,#36,#4,#4,#4,#4,#14,#0
+ .DB #62,#34,#34,#62,#34,#34,#62,#0
+ .DB #62,#34,#34,#62,#2,#34,#62,#0
+ .DB #0,#24,#24,#0,#0,#24,#24,#0
+ .DB #0,#24,#24,#0,#0,#24,#24,#32
+ .DB #4,#8,#16,#32,#16,#8,#4,#0
+ .DB #0,#0,#126,#0,#0,#126,#0,#0
+ .DB #32,#16,#8,#4,#8,#16,#32,#0
+ .DB #64,#124,#68,#4,#28,#16,#0,#16
+ .DB #0,#56,#84,#92,#64,#60,#0,#0
+ .DB #126,#36,#36,#36,#60,#36,#102,#0
+ .DB #124,#36,#36,#62,#34,#34,#126,#0
+ .DB #2,#126,#66,#64,#66,#126,#2,#0
+ .DB #126,#34,#34,#34,#34,#34,#126,#0
+ .DB #2,#126,#66,#120,#66,#126,#2,#0
+ .DB #2,#126,#34,#48,#32,#32,#112,#0
+ .DB #2,#126,#34,#32,#46,#36,#124,#0
+ .DB #102,#36,#36,#60,#36,#36,#102,#0
+ .DB #56,#16,#16,#16,#16,#16,#56,#0
+ .DB #28,#8,#8,#8,#8,#40,#56,#0
+ .DB #108,#40,#40,#124,#36,#36,#102,#0
+ .DB #112,#32,#32,#32,#34,#126,#2,#0
+ .DB #127,#42,#42,#42,#42,#107,#8,#0
+ .DB #126,#36,#36,#36,#36,#36,#102,#0
+ .DB #126,#66,#66,#66,#66,#66,#126,#0
+ .DB #126,#34,#34,#126,#32,#32,#112,#0
+ .DB #126,#66,#66,#74,#126,#8,#28,#0
+ .DB #126,#34,#34,#126,#36,#36,#114,#0
+ .DB #126,#66,#64,#126,#2,#66,#126,#0
+ .DB #34,#62,#42,#8,#8,#8,#28,#0
+ .DB #102,#36,#36,#36,#36,#36,#126,#0
+ .DB #102,#36,#36,#36,#36,#24,#0,#0
+ .DB #107,#42,#42,#42,#42,#42,#62,#0
+ .DB #102,#36,#36,#24,#36,#36,#102,#0
+ .DB #102,#36,#36,#60,#8,#8,#28,#0
+ .DB #126,#66,#4,#8,#16,#34,#126,#0
+ .DB #4,#60,#36,#32,#36,#60,#4,#0
+ .DB #0,#64,#32,#16,#8,#4,#0,#0
+ .DB #32,#60,#36,#4,#36,#60,#32,#0
+ .DB #0,#16,#40,#68,#0,#0,#0,#0
+ .DB #0,#0,#0,#0,#0,#0,#0,#0
+ .DB #0,#100,#104,#16,#44,#76,#0,#0
+ .DB #126,#36,#36,#36,#60,#36,#102,#0
+ .DB #124,#36,#36,#62,#34,#34,#126,#0
+ .DB #2,#126,#66,#64,#66,#126,#2,#0
+ .DB #126,#34,#34,#34,#34,#34,#126,#0
+ .DB #2,#126,#66,#120,#66,#126,#2,#0
+ .DB #2,#126,#34,#48,#32,#32,#112,#0
+ .DB #2,#126,#34,#32,#46,#36,#124,#0
+ .DB #102,#36,#36,#60,#36,#36,#102,#0
+ .DB #56,#16,#16,#16,#16,#16,#56,#0
+ .DB #28,#8,#8,#8,#8,#40,#56,#0
+ .DB #108,#40,#40,#124,#36,#36,#102,#0
+ .DB #112,#32,#32,#32,#34,#126,#2,#0
+ .DB #127,#42,#42,#42,#42,#107,#8,#0
+ .DB #126,#36,#36,#36,#36,#36,#102,#0
+ .DB #126,#66,#66,#66,#66,#66,#126,#0
+ .DB #126,#34,#34,#126,#32,#32,#112,#0
+ .DB #126,#66,#66,#74,#126,#8,#28,#0
+ .DB #126,#34,#34,#126,#36,#36,#114,#0
+ .DB #126,#66,#64,#126,#2,#66,#126,#0
+ .DB #34,#62,#42,#8,#8,#8,#28,#0
+ .DB #102,#36,#36,#36,#36,#36,#126,#0
+ .DB #102,#36,#36,#36,#36,#24,#0,#0
+ .DB #107,#42,#42,#42,#42,#42,#62,#0
+ .DB #102,#36,#36,#24,#36,#36,#102,#0
+ .DB #102,#36,#36,#60,#8,#8,#28,#0
+ .DB #126,#66,#4,#8,#16,#34,#126,#0
+ .DB #4,#60,#36,#96,#96,#36,#60,#4
+ .DB #0,#16,#16,#16,#16,#16,#16,#0
+ .DB #32,#60,#36,#6,#6,#36,#60,#32
+ .DB #0,#0,#16,#40,#68,#0,#0,#0
+ .DB #126,#66,#90,#82,#90,#66,#126,#0 \ No newline at end of file
diff --git a/lib/cpcrslib/LICENSE b/lib/cpcrslib/LICENSE
new file mode 100644
index 0000000..04424c0
--- /dev/null
+++ b/lib/cpcrslib/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2008-2015 Raúl Simarro <artaburu@hotmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/lib/cpcrslib/Makefile b/lib/cpcrslib/Makefile
new file mode 100644
index 0000000..c440a28
--- /dev/null
+++ b/lib/cpcrslib/Makefile
@@ -0,0 +1,19 @@
+all: cpcrslib.lib
+
+AS=sdasz80
+AR=sdar
+
+cpcrslib_SRCS=$(wildcard cpc_*.s)
+cpcrslib_OBJS=$(patsubst %.s,%.rel,$(cpcrslib_SRCS))
+
+cpcrslib.lib: $(cpcrslib_OBJS)
+ $(AR) -rcD cpcrslib.lib $(cpcrslib_OBJS)
+ cp cpcrslib.lib ..
+
+%.rel: %.s
+ $(AS) -o $<
+
+.PHONY: clean
+clean:
+ rm -f *.rel *.lib
+
diff --git a/lib/cpcrslib/Sprites.s b/lib/cpcrslib/Sprites.s
new file mode 100644
index 0000000..20ed720
--- /dev/null
+++ b/lib/cpcrslib/Sprites.s
@@ -0,0 +1,37 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl Simarro (Artaburu) - 2009, 2012 **
+; ******************************************************
+
+
+;*************************************
+; SPRITES
+;*************************************
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/cpcrslib/TileMap.h b/lib/cpcrslib/TileMap.h
new file mode 100644
index 0000000..6240bad
--- /dev/null
+++ b/lib/cpcrslib/TileMap.h
@@ -0,0 +1,304 @@
+
+.globl _tiles
+.globl _pantalla_juego
+.globl _tiles_tocados
+.globl _posiciones_pantalla
+.globl _posiciones_super_buffer
+.globl _tabla_y_ancho_pantalla
+
+
+;.globl _posicion_inicial_area_visible
+;.globl _posicion_inicial_superbuffer
+;.globl _ancho_pantalla_bytes
+;.globl _alto_pantalla_bytes
+;.globl _ancho_pantalla_bytes_visible
+
+
+; ***************************************************
+; Transparent colour for cpc_PutTrSpTileMap2b routine
+;.globl _mascara1
+;.globl _mascara2
+; ***************************************************
+
+;.globl _tiles_ocultos_ancho0
+;.globl _tiles_ocultos_alto0
+;.globl _tiles_ocultos_ancho1
+;.globl _tiles_ocultos_alto1
+
+
+;.globl _posicion_inicio_pantalla_visible
+;.globl _posicion_inicio_pantalla_visible_sb
+
+
+
+;.globl _tile
+; ***************************************************
+; Scroll Left Addresses column
+; not requiered if scroll not used
+.globl _ColumnScr
+; ***************************************************
+
+
+; ***************************************************
+; Transparent colour for cpc_PutTrSpTileMap2b routine
+; For printing sprites using transparent color (mode 0) transparent color selection is requiered.
+; Selección color transparente. Escribir las 2 máscaras que correspondan al color elegido.
+;Example colour number 7:
+mascara1 = #0
+mascara2 = #0
+
+
+;0: #0x00, #0x00
+;1: #0x80, #0x40
+;2: #0x04, #0x08
+;3: #0x44, #0x88
+;4: #0x10, #0x20
+;5: #0x50, #0xA0
+;6: #0x14, #0x28
+;7: #0x54, #0xA8
+;8: #0x01, #0x02
+;9: #0x41, #0x82
+;10: #0x05, #0x0A
+;11: #0x45, #0x8A
+;12: #0x11, #0x22
+;13: #0x51, #0xA2
+;14: #0x15, #0x2A
+;15: #0x55, #0xAA
+; ***************************************************
+
+
+
+
+;------------------------------------------------------------------------------------
+; SCREEN AND BUFFER ADDRESSES
+; VALORES QUE DEFINEN EL BUFFER Y LA PANTALLA
+;------------------------------------------------------------------------------------
+
+posicion_inicial_area_visible = #0xc0A4
+posicion_inicial_superbuffer = #0x100
+
+
+;------------------------------------------------------------------------------------
+
+;------------------------------------------------------------------------------------
+; TILE MAP DIMENSIONS
+;------------------------------------------------------------------------------------
+
+T_WIDTH = 32 ;max=40 ;dimensiones de la pantalla en tiles
+T_HEIGHT = 16 ;max=20
+
+
+;Invisible tile margins:
+T_WH = 2
+T_HH = 0
+;------------------------------------------------------------------------------------
+
+
+tiles_ocultos_ancho0 = T_WH
+tiles_ocultos_alto0 = T_HH
+tiles_ocultos_ancho1 = T_WIDTH - T_WH - 1
+tiles_ocultos_alto1 = T_HEIGHT - T_HH - 1
+
+;------------------------------------------------------------------------------------
+; Other parameters (internal use)
+;------------------------------------------------------------------------------------
+;------------------------------------------------------------------------------------
+
+ancho_pantalla_bytes = 2*T_WIDTH ; 2*T_WIDTH; ; El ancho de pantalla influye determinantemente en numerosas rutinas que hay que actualizar si se cambia
+ ; OJO con el modo
+alto_pantalla_bytes = 8*T_HEIGHT;
+ancho_pantalla_bytes_visible = 2*T_WIDTH ;32 ; 64; ;dentro del area definida, cuanto se debe mostrar. 2*T_WIDTH
+
+;El tamaño del buffer es ancho_pantalla_bytes*alto_pantalla_bytes
+
+_TileMapConf:
+;------------------------------------------------------------------------------------
+;Con la definición del mapeado hay que tener en cuenta que las coordenadas son:
+;ANCHO=64 bytes (128 pixels en modo 0)
+;ALTO=128 pixels
+;el máximo que entra en el CPC es 20 líneas
+;SI NO SE VAN A USAR TODAS LAS LINEAS, PARA AHORRA MEMORIA ES INTERESANTE COMENTARLAS
+_posiciones_pantalla: ;Posiciones en las que se dibujan los tiles
+.DW #posicion_inicial_area_visible+#0x50*0
+.DW #posicion_inicial_area_visible+#0x50*1
+.DW #posicion_inicial_area_visible+#0x50*2
+.DW #posicion_inicial_area_visible+#0x50*3
+.DW #posicion_inicial_area_visible+#0x50*4
+.DW #posicion_inicial_area_visible+#0x50*5
+.DW #posicion_inicial_area_visible+#0x50*6
+.DW #posicion_inicial_area_visible+#0x50*7
+.DW #posicion_inicial_area_visible+#0x50*8
+.DW #posicion_inicial_area_visible+#0x50*9
+.DW #posicion_inicial_area_visible+#0x50*10
+.DW #posicion_inicial_area_visible+#0x50*11
+.DW #posicion_inicial_area_visible+#0x50*12
+.DW #posicion_inicial_area_visible+#0x50*13
+.DW #posicion_inicial_area_visible+#0x50*14
+.DW #posicion_inicial_area_visible+#0x50*15
+.DW #posicion_inicial_area_visible+#0x50*16
+.DW #posicion_inicial_area_visible+#0x50*17
+.DW #posicion_inicial_area_visible+#0x50*18
+.DW #posicion_inicial_area_visible+#0x50*19
+
+_posiciones_super_buffer: ;muestra el inicio de cada línea (son 10 tiles de 8x16 de alto)
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*0
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*1
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*2
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*3
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*4
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*5
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*6
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*7
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*8
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*9
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*10
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*11
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*12
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*13
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*14
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*15
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*16
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*17
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*18
+.DW #posicion_inicial_superbuffer+8*ancho_pantalla_bytes*19
+
+
+
+
+; ***************************************************
+; Scroll Left Addresses column. DECRAPTED
+; not requiered if scroll not used comment it ;)
+_ColumnScr:
+; ***************************************************
+
+
+_pantalla_actual: .DW #0
+_pantalla_juego: ;en tiles
+;defs T_WIDTH*T_HEIGHT
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.DB #0xFF ;Este byte es importante, marca el fin de la pantalla.
+
+
+_fondo_pantalla_juego: ;en tiles
+;defs T_WIDTH*T_HEIGHT
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#13,#14,#17,#13,#14,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#15,#16,#17,#15,#16,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+.DB #17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17,#17
+
+
+_tiles_tocados:
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+.DB #0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF,#0xFF
+ ;defs 150 ;150 ;cuando un tile es tocado, se marca en esta tabla para luego restaurarlo. Es una tabla sin duplicados.
+
+
+_tabla_y_ancho_pantalla:
+.dw #_pantalla_juego + #0
+.dw #_pantalla_juego + #1*T_WIDTH
+.dw #_pantalla_juego + #2*T_WIDTH
+.dw #_pantalla_juego + #3*T_WIDTH
+.dw #_pantalla_juego + #4*T_WIDTH
+.dw #_pantalla_juego + #5*T_WIDTH
+.dw #_pantalla_juego + #6*T_WIDTH
+.dw #_pantalla_juego + #7*T_WIDTH
+.dw #_pantalla_juego + #8*T_WIDTH
+.dw #_pantalla_juego + #9*T_WIDTH
+.dw #_pantalla_juego + #10*T_WIDTH
+.dw #_pantalla_juego + #11*T_WIDTH
+.dw #_pantalla_juego + #12*T_WIDTH
+.dw #_pantalla_juego + #13*T_WIDTH
+.dw #_pantalla_juego + #14*T_WIDTH
+.dw #_pantalla_juego + #15*T_WIDTH
+.dw #_pantalla_juego + #16*T_WIDTH
+.dw #_pantalla_juego + #17*T_WIDTH
+.dw #_pantalla_juego + #18*T_WIDTH
+.dw #_pantalla_juego + #19*T_WIDTH
+
+;_tabla_y_x_ancho2:
+;.dw #ancho_pantalla_bytes * 0 /2
+;.dw #ancho_pantalla_bytes * 1 /2
+;.dw #ancho_pantalla_bytes * 2 /2
+;.dw #ancho_pantalla_bytes * 3 /2
+;.dw #ancho_pantalla_bytes * 4 /2
+;.dw #ancho_pantalla_bytes * 5 /2
+;.dw #ancho_pantalla_bytes * 6 /2
+;.dw #ancho_pantalla_bytes * 7 /2
+;.dw #ancho_pantalla_bytes * 8 /2
+;.dw #ancho_pantalla_bytes * 9 /2
+;.dw #ancho_pantalla_bytes * 10 /2
+;.dw #ancho_pantalla_bytes * 11 /2
+;.dw #ancho_pantalla_bytes * 12 /2
+;.dw #ancho_pantalla_bytes * 13 /2
+;.dw #ancho_pantalla_bytes * 14 /2
+;.dw #ancho_pantalla_bytes * 15 /2
+;.dw #ancho_pantalla_bytes * 16 /2
+;.dw #ancho_pantalla_bytes * 17 /2
+;.dw #ancho_pantalla_bytes * 18 /2
+;.dw #ancho_pantalla_bytes * 19 /2
+
+
+;------------------------------------------------------------------------------------
+; TILE DATA. TILES MUST BE DEFINED HERE
+;------------------------------------------------------------------------------------
+
+
+_tiles: ;Son de 2x8 bytes
+;tile 0
+.db #0x00,#0x00
+.db #0x40,#0x00
+.db #0x40,#0x00
+.db #0x40,#0x00
+.db #0x40,#0x00
+.db #0x40,#0x00
+.db #0x40,#0xC0
+.db #0x00,#0x00
+;tile 1
+.db #0x3C,#0x00
+.db #0x3C,#0x00
+.db #0x00,#0x3C
+.db #0x00,#0x3C
+.db #0x3C,#0x00
+.db #0x3C,#0x00
+.db #0x00,#0x3C
+.db #0x00,#0x3C
+;tile 2
+.db #0x00,#0x00
+.db #0x15,#0x00
+.db #0x00,#0x2A
+.db #0x15,#0x00
+.db #0x00,#0x2A
+.db #0x15,#0x00
+.db #0x00,#0x00
+.db #0x00,#0x00
diff --git a/lib/cpcrslib/Wyz.s b/lib/cpcrslib/Wyz.s
new file mode 100644
index 0000000..4724c3e
--- /dev/null
+++ b/lib/cpcrslib/Wyz.s
@@ -0,0 +1,1414 @@
+; ******************************************************
+; ** Librería de rutinas para Amstrad CPC **
+; ** Raúl Simarro, Artaburu 2010 **
+; ** PLAYER programado por WYZ **
+; ******************************************************
+
+;XLIB cpc_WyzPlayer
+
+
+
+;XDEF CARGA_CANCION_WYZ
+;XDEF INICIA_EFECTO_WYZ
+;XDEF cpc_WyzSetPlayerOn0
+;XDEF cpc_WyzSetPlayerOff0
+
+;XDEF TABLA_SONG
+;XDEF TABLA_EFECTOS
+;XDEF TABLA_PAUTAS
+;;XDEF TABLA_SONIDOS
+;XDEF INTERRUPCION
+
+;XDEF BUFFER_MUSICA
+;XDEF direcc_tempo
+
+
+
+
+;DEFINE BUFFER_DEC = #0x100
+
+
+
+
+
+; CPC PSG proPLAYER - WYZ 2010
+;XREF INTERRUPCION
+
+
+.globl _cpc_WyzConfigurePlayer
+
+_cpc_WyzConfigurePlayer::
+
+ LD HL,#2
+ ADD HL,SP
+ LD a,(HL)
+
+ LD (#INTERR),A
+ RET
+
+
+.globl _cpc_WyzInitPlayer
+
+_cpc_WyzInitPlayer::
+
+; la entrada indica las tablas de canciones, pautas, efectos,... sólo hay que inicializar esos datos
+; en la librería
+ PUSH IX
+ LD IX,#4
+ ADD IX,SP
+
+ LD L,6 (IX)
+ LD H,7 (IX)
+ LD (#TABLA_SONG0),HL
+ LD L,4 (IX)
+ LD H,5 (IX)
+ LD (#TABLA_EFECTOS0),HL
+ LD L,2 (IX)
+ LD H,3 (IX)
+ LD (#TABLA_PAUTAS0),HL
+ LD L,0 (IX)
+ LD H,1 (IX)
+ LD (#TABLA_SONIDOS0),HL
+ POP IX
+ RET
+
+.globl _cpc_WyzLoadSong
+
+_cpc_WyzLoadSong::
+ LD HL,#2
+ ADD HL,SP
+ LD A,(HL)
+ JP CARGA_CANCION_WYZ0
+
+
+.globl _cpc_WyzSetTempo
+
+_cpc_WyzSetTempo::
+ LD HL,#2
+ ADD HL,SP
+ LD A,(HL)
+ ld (#dir_tempo+1),a
+ ret
+
+
+.globl _cpc_WyzStartEffect
+
+_cpc_WyzStartEffect::
+ LD HL,#2
+ ADD HL,SP
+ LD c,(HL)
+ INC HL
+ LD b,(HL)
+ ;AHORA TIENE 2 parámetros: C:canal, B:numero efecto
+ JP INICIA_EFECTO_WYZ0
+
+;.globl _cpc_WyzStartSound
+
+;_cpc_WyzStartSound::
+; LD HL,#2
+; ADD HL,SP
+; LD A,(HL)
+; JP INICIA_SONIDO_WYZ
+
+.globl _cpc_WyzTestPlayer
+
+_cpc_WyzTestPlayer::
+ LD HL,#INTERR
+ LD A,(HL)
+ LD L,A
+ LD H,#0
+ RET
+
+_cpc_WyzPlayer::
+
+;.globl _cpc_WyzSetPlayerOn
+;.globl _cpc_WyzSetPlayerOn1
+
+;_cpc_WyzSetPlayerOn::
+;_cpc_WyzSetPlayerOn1::
+ ;El player funcionará por interrupciones.
+; DI
+; ld a,(#0x0038)
+; ld (#datos_int),a
+; ld (#salto_int),a
+; ld a,(#0x0039)
+; ld (#datos_int+1),a
+; ld (#salto_int+1),a
+; ld a,(#0x003a)
+; ld (#datos_int+2),a
+; ld (#salto_int+2),a
+;
+; ld a,#0xC3
+; ld (#0x0038),a
+; ld HL,#INICIO
+; ld (#0x0039),HL
+; EI
+; ret
+
+.globl _cpc_WyzSetPlayerOff
+;.globl _cpc_WyzSetPlayerOff1
+_cpc_WyzSetPlayerOff::
+;_cpc_WyzSetPlayerOff1::
+
+ ;apago todos los sonidos poniendo los registros a 0
+ call PLAYER_OFF
+ ret
+
+ ;DI
+ ;Restaura salto original
+ ;ld a,(#datos_int) ;guardo el salto original
+ ;ld (#0x0038),A
+ ;ld a,(#datos_int+1) ;guardo el salto original
+ ;ld (#0x0039),A
+ ;ld a,(#datos_int+2) ;guardo el salto original
+ ;ld (#0x003a),A
+
+ ;EI
+ ;ret
+
+
+
+
+
+;___________________________________________________________
+
+ ; .db "PSG PROPLAYER BY WYZ'10"
+
+;___________________________________________________________
+
+
+;___________________________________________________________
+
+.globl _cpc_WyzPlayerISR
+
+_cpc_WyzPlayerISR::
+
+INICIO:
+
+
+ ;primero mira si toca tocar :P
+ ;push af
+ LD A,(#contador)
+ DEC A
+ LD (#contador),A
+ OR #0
+ JP NZ,termina_int
+dir_tempo:
+ LD A,#6
+ LD (#contador),A
+
+ ;EXX -> by int6
+ PUSH IX
+ PUSH IY
+
+
+
+ CALL ROUT
+ LD HL,#PSG_REG
+ LD DE,#PSG_REG_SEC
+ LD BC,#14
+ LDIR
+
+
+
+ CALL PLAY
+ CALL REPRODUCE_SONIDO
+
+ LD HL,#PSG_REG_SEC
+ LD DE,#PSG_REG_EF
+ LD BC,#14
+ LDIR
+
+ ;De este modo, prevalece el efecto
+ CALL REPRODUCE_EFECTO_A
+ CALL REPRODUCE_EFECTO_B
+ CALL REPRODUCE_EFECTO_C
+ CALL ROUT_EF
+
+
+exit_no_loop:
+ POP IY
+ POP IX
+ ;EXX -> by int 6
+
+termina_int:
+ ;pop af
+ ex af,af
+ ei
+ ret
+;salto_int:
+;.db #0,#0,#0
+
+
+
+contador: .db #0
+;datos_int: .db #0,#0,#0 ; Se guardan 3 BYTES!!!! (Dedicado a Na_th_an, por los desvelos)
+
+
+
+;INICIA EL SONIDO Nº (A)
+
+;INICIA EL SONIDO Nº (A)
+
+INICIA_EFECTO_WYZ0:
+
+;INICIA EL SONIDO Nº (B) EN EL CANAL (C)
+ LD A,C
+ CP #0
+ JP Z,INICIA_EFECTO_A
+ CP #1
+ JP Z,INICIA_EFECTO_B
+ CP #2
+ JP Z,INICIA_EFECTO_C
+ ;JP INICIA_EFECTO_A
+ RET
+
+
+;REPRODUCE EFECTOS
+
+
+
+
+;REPRODUCE EFECTOS CANAL A
+
+
+REPRODUCE_EFECTO_A:
+ LD HL,#INTERR
+ BIT 3,(HL) ;ESTA ACTIVADO EL EFECTO?
+ RET Z
+ LD HL,(#PUNTERO_EFECTO_A)
+ LD A,(HL)
+ CP #0xFF
+ JR Z,FIN_EFECTO_A
+ CALL BLOQUE_COMUN
+ LD (#PUNTERO_EFECTO_A),HL
+ LD 0 (IX),B
+ LD 1 (IX),C
+ LD 8 (IX),A
+ RET
+FIN_EFECTO_A:
+ LD HL,#INTERR
+ RES 3,(HL)
+ XOR A
+ LD (#PSG_REG_EF+0),A
+ LD (#PSG_REG_EF+1),A
+ LD (#PSG_REG_EF+8),A
+ RET
+
+REPRODUCE_EFECTO_B:
+ LD HL,#INTERR
+ BIT 5,(HL) ;ESTA ACTIVADO EL EFECTO?
+ RET Z
+ LD HL,(#PUNTERO_EFECTO_B)
+ LD A,(HL)
+ CP #0xFF
+ JR Z,FIN_EFECTO_B
+ CALL BLOQUE_COMUN
+ LD (#PUNTERO_EFECTO_B),HL
+ LD 2 (IX),B
+ LD 3 (IX),C
+ LD 9 (IX),A
+ RET
+FIN_EFECTO_B:
+ LD HL,#INTERR
+ RES 5,(HL)
+ XOR A
+ LD (#PSG_REG_EF+2),A
+ LD (#PSG_REG_EF+3),A
+ LD (#PSG_REG_EF+9),A
+ RET
+
+REPRODUCE_EFECTO_C:
+ LD HL,#INTERR
+ BIT 6,(HL) ;ESTA ACTIVADO EL EFECTO?
+ RET Z
+ LD HL,(#PUNTERO_EFECTO_C)
+ LD A,(HL)
+ CP #0xFF
+ JR Z,FIN_EFECTO_C
+ CALL BLOQUE_COMUN
+ LD (#PUNTERO_EFECTO_C),HL
+ LD 4 (IX),B
+ LD 5 (IX),C
+ LD 10 (IX),A
+ RET
+FIN_EFECTO_C:
+ LD HL,#INTERR
+ RES 6,(HL)
+ XOR A
+ LD (#PSG_REG_EF+4),A
+ LD (#PSG_REG_EF+5),A
+ LD (#PSG_REG_EF+10),A
+ RET
+
+BLOQUE_COMUN:
+ LD IX,#PSG_REG_EF
+ LD B,A
+ INC HL
+ LD A,(HL)
+ RRCA
+ RRCA
+ RRCA
+ RRCA
+ AND #0b00001111
+ LD C,A
+ LD A,(HL)
+ AND #0b00001111
+ INC HL
+ RET
+
+INICIA_EFECTO_A:
+ LD A,B
+ LD HL,(#TABLA_EFECTOS0)
+ CALL EXT_WORD
+ LD (#PUNTERO_EFECTO_A),HL
+ LD HL,#INTERR
+ SET 3,(HL)
+ RET
+
+INICIA_EFECTO_B:
+ LD A,B
+ LD HL,(#TABLA_EFECTOS0)
+ CALL EXT_WORD
+ LD (#PUNTERO_EFECTO_B),HL
+ LD HL,#INTERR
+ SET 5,(HL)
+ RET
+
+INICIA_EFECTO_C:
+ LD A,B
+ LD HL,(#TABLA_EFECTOS0)
+ CALL EXT_WORD
+ LD (#PUNTERO_EFECTO_C),HL
+ LD HL,#INTERR
+ SET 6,(HL)
+ RET
+
+
+
+INICIA_SONIDO:
+ LD HL,(#TABLA_SONIDOS0)
+ CALL EXT_WORD
+ LD (#PUNTERO_SONIDO),HL
+ LD HL,#INTERR
+ SET 2,(HL)
+ RET
+;PLAYER OFF
+
+PLAYER_OFF:
+ LD HL,#INTERR
+
+ XOR A
+
+ LD (HL), A
+
+ LD HL,#PSG_REG
+ LD DE,#PSG_REG+1
+ LD BC,#14
+ LD (HL),A
+ LDIR
+
+ LD HL,#PSG_REG_SEC
+ LD DE,#PSG_REG_SEC+1
+ LD BC,#14
+ LD (HL),A
+ LDIR
+
+ LD HL,#PSG_REG_EF
+ LD DE,#PSG_REG_EF+1
+ LD BC,#14
+ LD (HL),A
+ LDIR
+
+ CALL ROUT
+ CALL ROUT_EF
+ CALL FIN_SONIDO
+ RET
+
+
+
+
+CARGA_CANCION_WYZ0:
+ DI
+ push af
+ CALL PLAYER_OFF
+ pop af
+; MUSICA DATOS INICIALES
+
+
+
+
+ LD DE,#0x0010 ; Nº BYTES RESERVADOS POR CANAL
+ LD HL,#BUFFER_DEC ;* RESERVAR MEMORIA PARA BUFFER DE SONIDO!!!!!
+ LD (#CANAL_A),HL
+
+ ADD HL,DE
+ LD (#CANAL_B),HL
+
+ ADD HL,DE
+ LD (#CANAL_C),HL
+
+ ADD HL,DE
+ LD (#CANAL_P),HL
+
+ ;LD A,#0 ;* CANCION Nº 0
+ CALL CARGA_CANCION
+
+ LD A,#6
+ LD (#contador),A
+
+;PANTALLA
+ EI
+ ret
+
+
+
+;CARGA UNA CANCION
+;IN:(A)=Nº DE CANCION
+
+CARGA_CANCION:
+ LD HL,#INTERR ;CARGA CANCION
+
+ LD (HL), #0 ;RESETEA TODO
+ SET 1,(HL) ;REPRODUCE CANCION
+ LD HL,#SONG
+ LD (HL),A ;Nº A
+
+
+
+;DECODIFICAR
+;IN-> INTERR 0 ON
+; SONG
+
+;CARGA CANCION SI/NO
+
+DECODE_SONG:
+ LD A,(#SONG)
+
+;LEE CABECERA DE LA CANCION
+;BYTE 0=TEMPO
+
+ ;LD HL,TABLA_SONG
+ LD HL,(#TABLA_SONG0)
+ CALL EXT_WORD
+ LD A,(HL)
+ LD (#TEMPO),A
+ XOR A
+ LD (#TTEMPO),A
+
+;HEADER BYTE 1
+;(-|-|-|-|-|-|-|LOOP)
+
+ INC HL ;LOOP 1=ON/0=OFF?
+ LD A,(HL)
+ BIT 0,A
+ JR Z,NPTJP0
+ PUSH HL
+ LD HL,#INTERR
+ SET 4,(HL)
+ POP HL
+
+
+NPTJP0:
+ INC HL ;2 BYTES RESERVADOS
+ INC HL
+ INC HL
+
+;BUSCA Y GUARDA INICIO DE LOS CANALES EN EL MODULO MUS
+
+
+ LD (#PUNTERO_P_DECA),HL
+ LD E,#0x3F ;CODIGO INTRUMENTO 0
+ LD B,#0xFF ;EL MODULO DEBE TENER UNA LONGITUD MENOR DE #0xFF00 ... o_O!
+BGICMODBC1:
+ XOR A ;BUSCA EL BYTE 0
+ CPIR
+ DEC HL
+ DEC HL
+ LD A,E ;ES EL INSTRUMENTO 0??
+ CP (HL)
+ INC HL
+ INC HL
+ JR Z,BGICMODBC1
+
+ LD (#PUNTERO_P_DECB),HL
+
+BGICMODBC2:
+ XOR A ;BUSCA EL BYTE 0
+ CPIR
+ DEC HL
+ DEC HL
+ LD A,E
+ CP (HL) ;ES EL INSTRUMENTO 0??
+ INC HL
+ INC HL
+ JR Z,BGICMODBC2
+
+ LD (#PUNTERO_P_DECC),HL
+
+BGICMODBC3:
+ XOR A ;BUSCA EL BYTE 0
+ CPIR
+ DEC HL
+ DEC HL
+ LD A,E
+ CP (HL) ;ES EL INSTRUMENTO 0??
+ INC HL
+ INC HL
+ JR Z,BGICMODBC3
+ LD (#PUNTERO_P_DECP),HL
+
+
+;LEE DATOS DE LAS NOTAS
+;(|)(|||||) LONGITUD\NOTA
+
+INIT_DECODER:
+ LD DE,(#CANAL_A)
+ LD (#PUNTERO_A),DE
+ LD HL,(#PUNTERO_P_DECA)
+ CALL DECODE_CANAL ;CANAL A
+ LD (#PUNTERO_DECA),HL
+
+ LD DE,(#CANAL_B)
+ LD (#PUNTERO_B),DE
+ LD HL,(#PUNTERO_P_DECB)
+ CALL DECODE_CANAL ;CANAL B
+ LD (#PUNTERO_DECB),HL
+
+ LD DE,(#CANAL_C)
+ LD (#PUNTERO_C),DE
+ LD HL,(#PUNTERO_P_DECC)
+ CALL DECODE_CANAL ;CANAL C
+ LD (#PUNTERO_DECC),HL
+
+ LD DE,(#CANAL_P)
+ LD (#PUNTERO_P),DE
+ LD HL,(#PUNTERO_P_DECP)
+ CALL DECODE_CANAL ;CANAL P
+ LD (#PUNTERO_DECP),HL
+
+ RET
+
+
+;DECODIFICA NOTAS DE UN CANAL
+;IN (DE)=DIRECCION DESTINO
+;NOTA=0 FIN CANAL
+;NOTA=1 SILENCIO
+;NOTA=2 PUNTILLO
+;NOTA=3 COMANDO I
+
+DECODE_CANAL:
+ LD A,(HL)
+ AND A ;FIN DEL CANAL?
+ JR Z,FIN_DEC_CANAL
+ CALL GETLEN
+
+ CP #0b00000001 ;ES SILENCIO?
+ JR NZ,NO_SILENCIO
+ SET 6,A
+ JR NO_MODIFICA
+
+NO_SILENCIO:
+ CP #0b00111110 ;ES PUNTILLO?
+ JR NZ,NO_PUNTILLO
+ OR A
+ RRC B
+ XOR A
+ JR NO_MODIFICA
+
+NO_PUNTILLO:
+ CP #0b00111111 ;ES COMANDO?
+ JR NZ,NO_MODIFICA
+ BIT 0,B ;COMADO=INSTRUMENTO?
+ JR Z,NO_INSTRUMENTO
+ LD A,#0b11000001 ;CODIGO DE INSTRUMENTO
+ LD (DE),A
+ INC HL
+ INC DE
+ LD A,(HL) ;Nº DE INSTRUMENTO
+ LD (DE),A
+ INC DE
+ INC HL
+ JR DECODE_CANAL
+
+NO_INSTRUMENTO:
+ BIT 2,B
+ JR Z,NO_ENVOLVENTE
+ LD A,#0b11000100 ;CODIGO ENVOLVENTE
+ LD (DE),A
+ INC DE
+ INC HL
+ JR DECODE_CANAL
+
+NO_ENVOLVENTE:
+ BIT 1,B
+ JR Z,NO_MODIFICA
+ LD A,#0b11000010 ;CODIGO EFECTO
+ LD (DE),A
+ INC HL
+ INC DE
+ LD A,(HL)
+ CALL GETLEN
+
+NO_MODIFICA:
+ LD (DE),A
+ INC DE
+ XOR A
+ DJNZ NO_MODIFICA
+ SET 7,A
+ SET 0,A
+ LD (DE),A
+ INC DE
+ INC HL
+ RET ;** JR DECODE_CANAL
+
+FIN_DEC_CANAL:
+ SET 7,A
+ LD (DE),A
+ INC DE
+ RET
+
+GETLEN:
+ LD B,A
+ AND #0b00111111
+ PUSH AF
+ LD A,B
+ AND #0b11000000
+ RLCA
+ RLCA
+ INC A
+ LD B,A
+ LD A,#0b10000000
+DCBC0:
+ RLCA
+ DJNZ DCBC0
+ LD B,A
+ POP AF
+ RET
+
+
+
+
+
+
+;PLAY __________________________________________________
+
+
+PLAY:
+ LD HL,#INTERR ;PLAY BIT 1 ON?
+ BIT 1,(HL)
+ RET Z
+;TEMPO
+ LD HL,#TTEMPO ;CONTADOR TEMPO
+ INC (HL)
+ LD A,(#TEMPO)
+ CP (HL)
+ JR NZ,PAUTAS
+ LD (HL),#0
+
+;INTERPRETA
+ LD IY,#PSG_REG
+ LD IX,#PUNTERO_A
+ LD BC,#PSG_REG+8
+ CALL LOCALIZA_NOTA
+ LD IY,#PSG_REG+2
+ LD IX,#PUNTERO_B
+ LD BC,#PSG_REG+9
+ CALL LOCALIZA_NOTA
+ LD IY,#PSG_REG+4
+ LD IX,#PUNTERO_C
+ LD BC,#PSG_REG+10
+ CALL LOCALIZA_NOTA
+ LD IX,#PUNTERO_P ;EL CANAL DE EFECTOS ENMASCARA OTRO CANAL
+ CALL LOCALIZA_EFECTO
+
+;PAUTAS
+
+PAUTAS:
+ LD IY,#PSG_REG+0
+ LD IX,#PUNTERO_P_A
+ LD HL,#PSG_REG+8
+ CALL PAUTA ;PAUTA CANAL A
+ LD IY,#PSG_REG+2
+ LD IX,#PUNTERO_P_B
+ LD HL,#PSG_REG+9
+ CALL PAUTA ;PAUTA CANAL B
+ LD IY,#PSG_REG+4
+ LD IX,#PUNTERO_P_C
+ LD HL,#PSG_REG+10
+ CALL PAUTA ;PAUTA CANAL C
+
+ RET
+
+
+
+;REPRODUCE EFECTOS DE SONIDO
+
+REPRODUCE_SONIDO:
+
+ LD HL,#INTERR
+ BIT 2,(HL) ;ESTA ACTIVADO EL EFECTO?
+ RET Z
+ LD HL,(#PUNTERO_SONIDO)
+ LD A,(HL)
+ CP #0xFF
+ JR Z,FIN_SONIDO
+ LD (#PSG_REG_SEC+4),A
+ INC HL
+ LD A,(HL)
+ RRCA
+ RRCA
+ RRCA
+ RRCA
+ AND #0b00001111
+ LD (#PSG_REG_SEC+5),A
+ LD A,(HL)
+ AND #0b00001111
+ LD (#PSG_REG_SEC+10),A
+ INC HL
+ LD A,(HL)
+ AND A
+ JR Z,NO_RUIDO
+ LD (#PSG_REG_SEC+6),A
+ LD A,#0b10011000
+ JR SI_RUIDO
+NO_RUIDO:
+ LD A,#0b10111000
+SI_RUIDO:
+ LD (#PSG_REG_SEC+7),A
+
+ INC HL
+ LD (#PUNTERO_SONIDO),HL
+ RET
+FIN_SONIDO:
+ LD HL,#INTERR
+ RES 2,(HL)
+
+FIN_NOPLAYER:
+ LD A,#0b10111000 ;2 BITS ALTOS PARA MSX / AFECTA AL CPC???
+ LD (#PSG_REG+7),A
+ RET
+
+;VUELCA BUFFER DE SONIDO AL PSG
+
+;VUELCA BUFFER DE SONIDO AL PSG
+
+ROUT:
+ XOR A
+ LD HL,#PSG_REG_SEC
+LOUT:
+ CALL WRITEPSGHL
+ INC A
+ CP #13
+ JR NZ,LOUT
+ LD A,(HL)
+ AND A
+ RET Z
+ LD A,#13
+ CALL WRITEPSGHL
+ XOR A
+ LD (#PSG_REG+13),A
+ LD (#PSG_REG_SEC+13),A
+ RET
+
+
+ROUT_EF:
+ XOR A
+ LD HL,#PSG_REG_EF
+LOUT_EF:
+ CALL WRITEPSGHL
+ INC A
+ CP #13
+ JR NZ,LOUT_EF
+ LD A,(HL)
+ AND A
+ RET Z
+ LD A,#13
+ CALL WRITEPSGHL
+ XOR A
+ LD (#PSG_REG_EF+13),A
+ RET
+;; A = REGISTER
+;; (HL) = VALUE
+WRITEPSGHL:
+ LD B,#0xF4
+ OUT (C),A
+ LD BC,#0xF6C0
+ OUT (C),C
+ .db #0xED
+ .db #0x71
+ LD B,#0xF5
+ OUTI
+ LD BC,#0xF680
+ OUT (C),C
+ .db #0xED
+ .db #0x71
+ RET
+
+;LOCALIZA NOTA CANAL A
+;IN (PUNTERO_A)
+
+LOCALIZA_NOTA:
+ LD L,0 (IX) ;HL=(PUNTERO_A_C_B)
+ LD H,1 (IX)
+ LD A,(HL)
+ AND #0b11000000 ;COMANDO?
+ CP #0b11000000
+ JR NZ,LNJP0
+
+;BIT(0)=INSTRUMENTO
+
+COMANDOS:
+ LD A,(HL)
+ BIT 0,A ;INSTRUMENTO
+ JR Z,COM_EFECTO
+
+ INC HL
+ LD A,(HL) ;Nº DE PAUTA
+ INC HL
+ LD 0 (IX),L
+ LD 1 (IX),H
+ ;LD HL,TABLA_PAUTAS
+ LD HL,(#TABLA_PAUTAS0)
+ CALL EXT_WORD
+ LD 18 (IX),L
+ LD 19 (IX),H
+ LD 12 (IX),L
+ LD 13 (IX),H
+ LD L,C
+ LD H,B
+ RES 4,(HL) ;APAGA EFECTO ENVOLVENTE
+ XOR A
+ LD (#PSG_REG_SEC+13),A
+ LD (#PSG_REG+13),A
+ JR LOCALIZA_NOTA
+
+COM_EFECTO:
+ BIT 1,A ;EFECTO DE SONIDO
+ JR Z,COM_ENVOLVENTE
+
+ INC HL
+ LD A,(HL)
+ INC HL
+ LD 0 (IX),L
+ LD 1 (IX),H
+ CALL INICIA_SONIDO
+ RET
+
+COM_ENVOLVENTE:
+ BIT 2,A
+ RET Z ;IGNORA - ERROR
+
+ INC HL
+ LD 0 (IX),L
+ LD 1 (IX),H
+ LD L,C
+ LD H,B
+ LD (HL),#0b00010000 ;ENCIENDE EFECTO ENVOLVENTE
+ JR LOCALIZA_NOTA
+
+
+LNJP0:
+ LD A,(HL)
+ INC HL
+ BIT 7,A
+ JR Z,NO_FIN_CANAL_A ;
+ BIT 0,A
+ JR Z,FIN_CANAL_A
+
+FIN_NOTA_A:
+ LD E,6 (IX)
+ LD D,7 (IX) ;PUNTERO BUFFER AL INICIO
+ LD 0 (IX),E
+ LD 1 (IX),D
+ LD L,30 (IX) ;CARGA PUNTERO DECODER
+ LD H,31 (IX)
+ PUSH BC
+ CALL DECODE_CANAL ;DECODIFICA CANAL
+ POP BC
+ LD 30 (IX),L ;GUARDA PUNTERO DECODER
+ LD 31 (IX),H
+ JP LOCALIZA_NOTA
+
+FIN_CANAL_A:
+ LD HL,#INTERR ;LOOP?
+ BIT 4,(HL)
+ JR NZ,FCA_CONT
+ CALL PLAYER_OFF
+ POP AF
+ POP AF
+ JP exit_no_loop
+
+FCA_CONT:
+ LD L,24 (IX) ;CARGA PUNTERO INICIAL DECODER
+ LD H,25 (IX)
+ LD 30 (IX),L
+ LD 31 (IX),H
+ JR FIN_NOTA_A
+
+NO_FIN_CANAL_A:
+ LD 0 (IX),L ;(PUNTERO_A_B_C)=HL GUARDA PUNTERO
+ LD 1 (IX),H
+ AND A ;NO REPRODUCE NOTA SI NOTA=0
+ JR Z,FIN_RUTINA
+ BIT 6,A ;SILENCIO?
+ JR Z,NO_SILENCIO_A
+ LD A,(BC)
+ AND #0b00010000
+ JR NZ,SILENCIO_ENVOLVENTE
+ XOR A
+ LD (BC),A ;RESET VOLUMEN
+ LD 0 (IY),A
+ LD 1 (IY),A
+ RET
+
+SILENCIO_ENVOLVENTE:
+ LD A,#0xFF
+ LD (#PSG_REG+11),A
+ LD (#PSG_REG+12),A
+ XOR A
+ LD (#PSG_REG+13),A
+ LD 0 (IY),A
+ LD 1 (IY),A
+ RET
+
+NO_SILENCIO_A:
+ CALL NOTA ;REPRODUCE NOTA
+ LD L,18 (IX) ;HL=(PUNTERO_P_A0) RESETEA PAUTA
+ LD H,19 (IX)
+ LD 12 (IX),L ;(PUNTERO_P_A)=HL
+ LD 13 (IX),H
+FIN_RUTINA:
+ RET
+
+
+;LOCALIZA EFECTO
+;IN HL=(PUNTERO_P)
+
+LOCALIZA_EFECTO:
+ LD L,0 (IX) ;HL=(PUNTERO_P)
+ LD H,1 (IX)
+ LD A,(HL)
+ CP #0b11000010
+ JR NZ,LEJP0
+
+ INC HL
+ LD A,(HL)
+ INC HL
+ LD 0 (IX),L
+ LD 1 (IX),H
+ CALL INICIA_SONIDO
+ RET
+
+
+LEJP0:
+ INC HL
+ BIT 7,A
+ JR Z,NO_FIN_CANAL_P ;
+ BIT 0,A
+ JR Z,FIN_CANAL_P
+FIN_NOTA_P:
+ LD DE,(#CANAL_P)
+ LD 0 (IX),E
+ LD 1 (IX),D
+ LD HL,(#PUNTERO_DECP) ;CARGA PUNTERO DECODER
+ PUSH BC
+ CALL DECODE_CANAL ;DECODIFICA CANAL
+ POP BC
+ LD (#PUNTERO_DECP),HL ;GUARDA PUNTERO DECODER
+ JP LOCALIZA_EFECTO
+
+FIN_CANAL_P:
+ LD HL,(#PUNTERO_P_DECP) ;CARGA PUNTERO INICIAL DECODER
+ LD (#PUNTERO_DECP),HL
+ JR FIN_NOTA_P
+
+NO_FIN_CANAL_P:
+ LD 0 (IX),L ;(PUNTERO_A_B_C)=HL GUARDA PUNTERO
+ LD 1 (IX),H
+ RET
+
+; PAUTA DE LOS 3 CANALES
+; IN:(IX):PUNTERO DE LA PAUTA
+; (HL):REGISTRO DE VOLUMEN
+; (IY):REGISTROS DE FRECUENCIA
+
+; FORMATO PAUTA
+; 7 6 5 4 3-0 3-0
+; BYTE 1 (LOOP|OCT-1|OCT+1|SLIDE|VOL) - BYTE 2 ( | | | |PITCH)
+
+PAUTA:
+ BIT 4,(HL) ;SI LA ENVOLVENTE ESTA ACTIVADA NO ACTUA PAUTA
+ RET NZ
+
+ LD A,0 (IY)
+ LD B,1 (IY)
+ OR B
+ RET Z
+
+
+ PUSH HL
+ ;LD L,(IX+0)
+ ;LD H,(IX+1)
+
+ ;LD A,(HL) ;COMPRUEBA SLIDE BIT 4
+ ;BIT 4,A
+ ;JR Z,PCAJP4
+ ;LD L,(IY+0) ;FRECUENCIA FINAL
+ ;LD H,(IY+1)
+ ;SBC HL,DE
+ ;JR Z,PCAJP4
+ ;JR C,SLIDE_POS
+ ;EX DE,HL
+ ;RRC D ;/4
+ ;RR E
+ ;RRC D
+ ;RR E
+
+
+ ;ADC HL,DE
+ ;LD (IY+0),L
+ ;LD (IY+1),H
+SLIDE_POS:
+ ;POP HL
+ ;RET
+
+PCAJP4:
+ LD L,0 (IX)
+ LD H,1 (IX)
+ LD A,(HL)
+
+ BIT 7,A ;LOOP / EL RESTO DE BITS NO AFECTAN
+ JR Z,PCAJP0
+ AND #0b00011111 ;LOOP PAUTA (0,32)X2!!!-> PARA ORNAMENTOS
+ RLCA ;X2
+ LD D,#0
+ LD E,A
+ SBC HL,DE
+ LD A,(HL)
+
+PCAJP0:
+ BIT 6,A ;OCTAVA -1
+ JR Z,PCAJP1
+ LD E,0 (IY)
+ LD D,1 (IY)
+
+ AND A
+ RRC D
+ RR E
+ LD 0 (IY),E
+ LD 1 (IY),D
+ JR PCAJP2
+
+PCAJP1:
+ BIT 5,A ;OCTAVA +1
+ JR Z,PCAJP2
+ LD E,0 (IY)
+ LD D,1 (IY)
+
+ AND A
+ RLC E
+ RL D
+ LD 0 (IY),E
+ LD 1 (IY),D
+
+
+PCAJP2:
+ INC HL
+ PUSH HL
+ LD E,A
+ LD A,(HL) ;PITCH DE FRECUENCIA
+ LD L,A
+ AND A
+ LD A,E
+ JR Z,ORNMJP1
+
+ LD A,0 (IY) ;SI LA FRECUENCIA ES 0 NO HAY PITCH
+ ADD A,1 (IY)
+ AND A
+ LD A,E
+ JR Z,ORNMJP1
+
+
+ BIT 7,L
+ JR Z,ORNNEG
+ LD H,#0xFF
+ JR PCAJP3
+ORNNEG:
+ LD H,#0
+
+PCAJP3:
+ LD E,0 (IY)
+ LD D,1 (IY)
+ ADC HL,DE
+ LD 0 (IY),L
+ LD 1 (IY),H
+ORNMJP1:
+ POP HL
+
+ INC HL
+ LD 0 (IX),L
+ LD 1 (IX),H
+PCAJP5:
+ POP HL
+ AND #0b00001111 ;VOLUMEN FINAL
+ LD (HL),A
+ RET
+
+
+
+;NOTA : REPRODUCE UNA NOTA
+;IN (A)=CODIGO DE LA NOTA
+; (IY)=REGISTROS DE FRECUENCIA
+
+
+NOTA:
+ ;ADD 6 ;*************************
+ LD L,C
+ LD H,B
+ BIT 4,(HL)
+ LD B,A
+ JR NZ,EVOLVENTES
+ LD A,B
+ LD HL,#DATOS_NOTAS
+ RLCA ;X2
+ LD D,#0
+ LD E,A
+ ADD HL,DE
+ LD A,(HL)
+ LD 0 (IY),A
+ INC HL
+ LD A,(HL)
+ LD 1 (IY),A
+ RET
+
+;IN (A)=CODIGO DE LA ENVOLVENTE
+; (IY)=REGISTRO DE FRECUENCIA
+
+EVOLVENTES:
+ PUSH AF
+ CALL ENV_RUT1
+ LD DE,#0x0000
+ LD 0 (IY),E
+ LD 1 (IY),D
+
+ POP AF
+ ADD A,#48
+ CALL ENV_RUT1
+
+
+ LD A,E
+ LD (#PSG_REG+11),A
+ LD A,D
+ LD (#PSG_REG+12),A
+ LD A,#0x0E
+ LD (#PSG_REG+13),A
+ RET
+
+;IN(A) NOTA
+ENV_RUT1:
+ LD HL,#DATOS_NOTAS
+ RLCA ;X2
+ LD D,#0
+ LD E,A
+ ADD HL,DE
+ LD E,(HL)
+ INC HL
+ LD D,(HL)
+ RET
+
+
+
+EXT_WORD:
+ LD D,#0
+ SLA A ;*2
+ LD E,A
+ ADD HL,DE
+ LD E,(HL)
+ INC HL
+ LD D,(HL)
+ EX DE,HL
+ RET
+
+;BANCO DE INSTRUMENTOS 2 BYTES POR INT.
+
+;(0)(RET 2 OFFSET)
+;(1)(+-PITCH)
+
+
+;BANCO DE INSTRUMENTOS 2 BYTES POR INT.
+
+;(0)(RET 2 OFFSET)
+;(1)(+-PITCH)
+
+;.TABLA_PAUTAS .dw PAUTA_1,PAUTA_2,PAUTA_3,PAUTA_4,PAUTA_5,PAUTA_6,PAUTA_7;,PAUTA_8,PAUTA_9,PAUTA_10,PAUTA_11,PAUTA_12,PAUTA_13,PAUTA_14,PAUTA_15,PAUTA_16,PAUTA_17,PAUTA_18
+
+
+
+
+
+
+
+
+
+
+
+;DATOS DE LOS EFECTOS DE SONIDO
+
+;EFECTOS DE SONIDO
+
+
+
+;.TABLA_SONIDOS .dw SONIDO1,SONIDO2,SONIDO3,SONIDO4,SONIDO5;,SONIDO6,SONIDO7;,SONIDO8
+
+TABLA_PAUTAS0: .dw 0
+
+TABLA_SONIDOS0: .dw 0
+
+
+;DATOS MUSICA
+
+
+
+;TABLA_SONG: .dw SONG_0;,SONG_1,SONG_2;,SONG_3 ;******** TABLA DE DIRECCIONES DE ARCHIVOS MUS
+
+;DATOS_NOTAS: .INCBIN "C:/EM/BRMSX/PLAYER/NOTAS.DAT" ;DATOS DE LAS NOTAS
+
+
+DATOS_NOTAS:
+ .dw #0x0000,#0x0000
+
+; .dw #0x41D,#0x3E2,#0x3AA,#0x376,#0x344,#0x315,#0x2E9,#0x2BF,#0x297,#0x272,#0x24F,#0x22E,#0x20E,#0x1F1,#0x1D5,#0x1BB
+; .dw #0x1A2,#0x18A,#0x174,#0x15F,#0x14B,#0x139,#0x127,#0x117,#0x107,#0xF8,#0xEA,#0xDD
+; .dw #0xD1,#0xC5,#0xBA,#0xAF,#0xA5,#0x9C,#0x93,#0x8B,#0x83,#0x7C,#0x75,#0x6E
+; .dw #0x68,#0x62,#0x5D,#0x57,#0x52,#0x4E,#0x49,#0x45,#0x41,#0x3E,#0x3A,#0x37
+; .dw #0x34,#0x31,#0x2E,#0x2B,#0x29,#0x27,#0x24,#0x22,#0x20,#0x1F,#0x1D,#0x1B
+; .dw #0x1A,#0x18,#0x17,#0x15,#0x14,#0x13,#0x12,#0x11,#0x10,#0xF,#0xE,#0xD
+
+
+.DW #1711,#1614,#1524,#1438,#1358,#1281,#1210,#1142,#1078,#1017
+.DW #960,#906,#855,#807,#762,#719,#679,#641,#605,#571
+.DW #539,#509,#480,#453,#428,#404,#381,#360,#339,#320
+.DW #302,#285,#269,#254,#240,#227,#214,#202,#190,#180
+.DW #170,#160,#151,#143,#135,#127,#120,#113,#107,#101
+.DW #95,#90,#85,#80,#76,#71,#67,#64,#60,#57
+
+
+;SONG_0:
+ ;INCBIN "WYAZOW.MUS"
+
+
+
+; VARIABLES__________________________
+
+
+INTERR:
+ .db #0 ;INTERRUPTORES 1=ON 0=OFF
+ ;BIT 0=CARGA CANCION ON/OFF
+ ;BIT 1=PLAYER ON/OFF
+ ;BIT 2=SONIDOS ON/OFF
+ ;BIT 3=EFECTOS ON/OFF
+
+;MUSICA **** EL ORDEN DE LAS VARIABLES ES FIJO ******
+
+TABLA_SONG0: .dw #0
+TABLA_EFECTOS0: .dw #0
+
+;.db 'P','S','G',' ','P','R','O','P','L','A','Y','E','R',' ','B','Y',' ','W','Y','Z','-','1','0'
+
+
+SONG: .db #00 ;DBNº DE CANCION
+TEMPO: .db #00 ;.dbTEMPO
+TTEMPO: .db #00 ;.dbCONTADOR TEMPO
+PUNTERO_A: .dw #00 ;DW PUNTERO DEL CANAL A
+PUNTERO_B: .dw #00 ;DW PUNTERO DEL CANAL B
+PUNTERO_C: .dw #00 ;DW PUNTERO DEL CANAL C
+
+BUFFER_MUSICA:
+CANAL_A: .dw #00 ;DW DIRECION DE INICIO DE LA MUSICA A
+CANAL_B: .dw #00 ;DW DIRECION DE INICIO DE LA MUSICA B
+CANAL_C: .dw #00 ;DW DIRECION DE INICIO DE LA MUSICA C
+
+PUNTERO_P_A: .dw #00 ;DW PUNTERO PAUTA CANAL A
+PUNTERO_P_B: .dw #00 ;DW PUNTERO PAUTA CANAL B
+PUNTERO_P_C: .dw #00 ;DW PUNTERO PAUTA CANAL C
+
+PUNTERO_P_A0: .dw #00 ;DW INI PUNTERO PAUTA CANAL A
+PUNTERO_P_B0: .dw #00 ;DW INI PUNTERO PAUTA CANAL B
+PUNTERO_P_C0: .dw #00 ;DW INI PUNTERO PAUTA CANAL C
+
+
+PUNTERO_P_DECA: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL A
+PUNTERO_P_DECB: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL B
+PUNTERO_P_DECC: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL C
+
+PUNTERO_DECA: .dw #00 ;DW PUNTERO DECODER CANAL A
+PUNTERO_DECB: .dw #00 ;DW PUNTERO DECODER CANAL B
+PUNTERO_DECC: .dw #00 ;DW PUNTERO DECODER CANAL C
+
+
+;CANAL DE EFECTOS - ENMASCARA OTRO CANAL
+
+PUNTERO_P: .dw #00 ;DW PUNTERO DEL CANAL EFECTOS
+CANAL_P: .dw #00 ;DW DIRECION DE INICIO DE LOS EFECTOS
+PUNTERO_P_DECP: .dw #00 ;DW PUNTERO DE INICIO DEL DECODER CANAL P
+PUNTERO_DECP: .dw #00 ;DW PUNTERO DECODER CANAL P
+
+PSG_REG: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER DE REGISTROS DEL PSG
+PSG_REG_SEC: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER SECUNDARIO DE REGISTROS DEL PSG
+
+PSG_REG_EF: .db #00,#00,#00,#00,#00,#00,#00,#0b10111000 ,#00,#00,#00,#00,#00,#00,#00 ;.db(11) BUFFER DE REGISTROS DEL PSG
+
+;ENVOLVENTE_A EQU #0xD033 ;DB
+;ENVOLVENTE_B EQU #0xD034 ;DB
+;ENVOLVENTE_C EQU #0xD035 ;DB
+
+
+
+
+;EFECTOS DE SONIDO
+
+N_SONIDO: .db #0 ;.db NUMERO DE SONIDO
+PUNTERO_SONIDO: .dw #0 ;.dw PUNTERO DEL SONIDO QUE SE REPRODUCE
+
+;EFECTOS
+
+N_EFECTO: .db #0 ;.db NUMERO DE SONIDO
+;PUNTERO_EFECTO .dw 0 ;.dw PUNTERO DEL SONIDO QUE SE REPRODUCE
+
+PUNTERO_EFECTO_A: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE
+PUNTERO_EFECTO_B: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE
+PUNTERO_EFECTO_C: .dw #0 ;DW : PUNTERO DEL SONIDO QUE SE REPRODUCE
+
+
+
+
+
+
+
+
+
+
+
+BUFFER_DEC: ; defs #0x40
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 16 bytes
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 32 bytes
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 48 bytes
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 ; 64 bytes
+
+
+; .db #0x00 ;************************* mucha atencion!!!!
+;.BUFFER_DEC defs 2048 ;space dinamically asigned in source code compilation!!
+ ; aqui se decodifica la cancion hay que dejar suficiente espacio libre.
+ ;*************************
+
+;DEFC CARGA_CANCION_WYZ = CARGA_CANCION_WYZ0
+;DEFC INICIA_EFECTO_WYZ = INICIA_EFECTO_WYZ0
+;DEFC cpc_WyzSetPlayerOn0 = cpc_WyzSetPlayerOn1
+;DEFC cpc_WyzSetPlayerOff0 = cpc_WyzSetPlayerOff1
+;DEFC TABLA_SONG = TABLA_SONG0
+;DEFC TABLA_EFECTOS = TABLA_EFECTOS0
+;DEFC TABLA_PAUTAS = TABLA_PAUTAS0
+;DEFC TABLA_SONIDOS = TABLA_SONIDOS0
+;DEFC INTERRUPCION = INTERR
+;DEFC direcc_tempo = dir_tempo
diff --git a/lib/cpcrslib/cpc_ClrScr.s b/lib/cpcrslib/cpc_ClrScr.s
new file mode 100644
index 0000000..49f1d2d
--- /dev/null
+++ b/lib/cpcrslib/cpc_ClrScr.s
@@ -0,0 +1,11 @@
+.globl _cpc_ClrScr
+
+_cpc_ClrScr::
+ XOR A
+ LD HL,#0xC000
+ LD DE,#0xC001
+ LD BC,#16383
+ LD (HL),A
+ LDIR
+ RET
+
diff --git a/lib/cpcrslib/cpc_CollSp.s b/lib/cpcrslib/cpc_CollSp.s
new file mode 100644
index 0000000..08bd02a
--- /dev/null
+++ b/lib/cpcrslib/cpc_CollSp.s
@@ -0,0 +1,126 @@
+.globl _cpc_CollSp
+
+_cpc_CollSp::
+;first parameter sprite
+;second parameter value
+ ld hl,#2
+ add hl,sp
+
+ ;ld ix,#2
+ ;add ix,sp
+; ld e,2 (ix)
+; ld d,3 (ix)
+ ;A=x value
+; ld l,0 (ix)
+; ld h,1 (ix)
+
+ ld e,(hl)
+ inc hl
+ ld d,(hl)
+ push de
+ inc hl
+ ld e,(hl)
+ inc hl
+ ld d,(hl)
+ push de
+
+ pop iy ;ix sprite2 data
+
+ pop ix ;iy sprite1 data
+
+ ;Sprite coords & sprite dims
+
+;COLISION_sprites
+
+
+
+;entran sprite1 y sprite 2 y se actualizan los datos
+;ix apunta a sprite1
+;iy apunta a sprite2
+
+;coordenadas
+ ld l,8 (ix)
+ ld h,9 (ix)
+ LD (#SPR2X),HL
+
+ ld l,8 (iy)
+ ld h,9 (iy)
+ LD (#SPR1X),HL
+
+;dimensiones sprite 1
+ ld l,0 (ix)
+ ld h,1 (ix)
+ ld b,(hl)
+ inc hl
+ ld c,(hl)
+;dimensiones sprite 12
+ ld l,0 (iy)
+ ld h,1 (iy)
+ ld d,(hl)
+ inc hl
+ ld e,(hl)
+
+
+ ;ld e,(ix+6)
+ ;ld d,(ix+7)
+
+
+
+;ld de,DIMENSIONES_SP_PPAL ;dimensiones sprite 2
+;ld bc,DIMENSIONES_SP_PPAL ;dimensiones sprite 1
+CALL TOCADO
+;RET NC ;vuelve si no hay colision
+ld h,#0
+JP nc,no_colision
+;Aquí hay colisión
+ld l,#1
+RET
+
+no_colision:
+ld l,h
+ret
+
+TOCADO:
+ LD HL,#SPR2X
+ LD A,(#SPR1X)
+ CP (HL)
+ jp C,C1
+ LD A,(HL)
+ ADD A,B ;alto del sprite1
+ LD B,A
+ LD A,(#SPR1X)
+ SUB B
+ RET NC
+ jp COMPROBAR
+C1:
+ ADD A,D ;alto sprite2
+ LD D,A
+ LD A,(HL)
+ SUB D
+ RET NC
+COMPROBAR:
+ INC HL
+ LD A,(#SPR1Y)
+ CP (HL)
+ jp C,C2
+ LD A,(HL)
+ ADD A,C
+ LD C,A
+ LD A,(#SPR1Y)
+ SUB C
+ RET
+C2:
+ ADD A,E
+ LD E,A
+ LD A,(HL)
+ SUB E
+ RET
+
+SPR1X:
+.db 0
+SPR1Y:
+.db 0
+SPR2X:
+.db 0
+SPR2Y:
+.db 0
diff --git a/lib/cpcrslib/cpc_DisableEnableFirmware.s b/lib/cpcrslib/cpc_DisableEnableFirmware.s
new file mode 100644
index 0000000..00a8710
--- /dev/null
+++ b/lib/cpcrslib/cpc_DisableEnableFirmware.s
@@ -0,0 +1,28 @@
+.globl _cpc_DisableFirmware
+
+_cpc_DisableFirmware::
+ DI
+ LD HL,(#0X0038)
+ LD (backup_fw),HL
+ LD HL,#0X0038
+ LD (HL),#0XFB ;EI
+ INC HL
+ LD (HL),#0XC9 ;RET
+ EI
+ RET
+
+backup_fw:
+ .DW #0
+
+.globl _cpc_EnableFirmware
+
+_cpc_EnableFirmware::
+ DI
+ LD DE,(backup_fw)
+ LD HL,#0X0038
+ LD (HL),E ;EI
+ INC HL
+ LD (HL),D ;RET
+ EI
+ RET
+
diff --git a/lib/cpcrslib/cpc_GetScrAddress.s b/lib/cpcrslib/cpc_GetScrAddress.s
new file mode 100644
index 0000000..42b17f7
--- /dev/null
+++ b/lib/cpcrslib/cpc_GetScrAddress.s
@@ -0,0 +1,65 @@
+.globl _cpc_GetScrAddress
+
+_cpc_GetScrAddress::
+
+; LD IX,#2
+; ADD IX,SP
+; LD A,0 (IX)
+; LD L,1 (IX) ;pantalla
+
+
+ LD HL,#2
+ ADD HL,SP
+ LD A,(HL)
+ INC HL
+ LD L,(HL)
+ ;LD L,E
+ ;JP cpc_GetScrAddress0
+
+
+cpc_GetScrAddress0: ;en HL están las coordenadas
+
+ ;LD A,H
+ LD (#inc_ancho+1),A
+ LD A,L
+ SRL A
+ SRL A
+ SRL A
+ ; A indica el bloque a multiplicar x &50
+ LD D,A ;D
+ SLA A
+ SLA A
+ SLA A
+ SUB L
+ NEG
+ ; A indica el desplazamiento a multiplicar x &800
+ LD E,A ;E
+ LD L,D
+ LD H,#0
+ ADD HL,HL
+ LD BC,#bloques
+ ADD HL,BC
+ ;HL APUNTA AL BLOQUE BUSCADO
+ LD C,(HL)
+ INC HL
+ LD H,(HL)
+ LD L,C
+ ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO
+ PUSH HL
+ LD D,#0
+ LD HL,#sub_bloques
+ ADD HL,DE
+ LD A,(HL)
+ POP HL
+ ADD H
+ LD H,A
+inc_ancho:
+ LD E,#0
+ ADD HL,DE
+ RET
+
+bloques:
+.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780
+sub_bloques:
+.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38
+
diff --git a/lib/cpcrslib/cpc_GetSp.s b/lib/cpcrslib/cpc_GetSp.s
new file mode 100644
index 0000000..cb19efc
--- /dev/null
+++ b/lib/cpcrslib/cpc_GetSp.s
@@ -0,0 +1,49 @@
+.globl _cpc_GetSp
+
+_cpc_GetSp::
+
+ LD IX,#2
+ ADD IX,SP
+ LD E,0 (IX)
+ LD D,1 (IX)
+ LD A,3 (IX)
+ LD L,4 (IX)
+ LD H,5 (IX)
+
+
+
+ LD (#loop_alto_2x_GetSp0+1),A
+
+
+ SUB #1
+ CPL
+ LD (#salto_lineax_GetSp0+1),A ;comparten los 2 los mismos valores.
+
+ LD A,2 (IX)
+ ;JP cpc_GetSp0
+
+cpc_GetSp0::
+ .DB #0XFD
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ LD B,#7
+loop_alto_2x_GetSp0:
+ LD C,#0
+loop_ancho_2x_GetSp0:
+ LD A,(HL)
+ LD (DE),A
+ INC DE
+ INC HL
+ DEC C
+ JP NZ,loop_ancho_2x_GetSp0
+ .DB #0XFD
+ DEC H
+ RET Z
+salto_lineax_GetSp0:
+ LD C,#0XFF ;salto linea menos ancho
+ ADD HL,BC
+ JP NC,loop_alto_2x_GetSp0 ;sig_linea_2zz ;si no desborda va a la siguiente linea
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7 ;sólo se daría una de cada 8 veces en un sprite
+ JP loop_alto_2x_GetSp0
+
diff --git a/lib/cpcrslib/cpc_GphStr.s b/lib/cpcrslib/cpc_GphStr.s
new file mode 100644
index 0000000..3f656fa
--- /dev/null
+++ b/lib/cpcrslib/cpc_GphStr.s
@@ -0,0 +1,700 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl Simarro (Artaburu) - 2009, 2012 **
+; ******************************************************
+
+
+
+cpc_GetScrAddress0: ;en HL están las coordenadas
+
+ ;LD A,H
+ LD (#inc_ancho+1),A
+ LD A,L
+ SRL A
+ SRL A
+ SRL A
+ ; A indica el bloque a multiplicar x &50
+ LD D,A ;D
+ SLA A
+ SLA A
+ SLA A
+ SUB L
+ NEG
+ ; A indica el desplazamiento a multiplicar x &800
+ LD E,A ;E
+ LD L,D
+ LD H,#0
+ ADD HL,HL
+ LD BC,#bloques
+ ADD HL,BC
+ ;HL APUNTA AL BLOQUE BUSCADO
+ LD C,(HL)
+ INC HL
+ LD H,(HL)
+ LD L,C
+ ;HL TIENE EL VALOR DEL BLOQUE DE 8 BUSCADO
+ PUSH HL
+ LD D,#0
+ LD HL,#sub_bloques
+ ADD HL,DE
+ LD A,(HL)
+ POP HL
+ ADD H
+ LD H,A
+inc_ancho:
+ LD E,#0
+ ADD HL,DE
+ RET
+
+bloques:
+.DW #0XC000,#0XC050,#0XC0A0,#0XC0F0,#0XC140,#0XC190,#0XC1E0,#0XC230,#0XC280,#0XC2D0,#0XC320,#0XC370,#0XC3C0,#0XC410,#0XC460,#0XC4B0,#0XC500,#0XC550,#0XC5A0,#0XC5F0,#0XC640,#0XC690,#0XC6E0,#0XC730,#0XC780
+sub_bloques:
+.DB #0X00,#0X08,#0X10,#0X18,#0X20,#0X28,#0X30,#0X38
+
+
+
+
+;*************************************
+; GRAPHIC TEXT
+;*************************************
+
+.globl _cpc_PrintGphStr2X
+
+_cpc_PrintGphStr2X::
+;preparación datos impresión. El ancho y alto son fijos!
+ LD IX,#2
+ ADD IX,SP
+ LD L,2 (IX)
+ LD H,3 (IX) ;DESTINO
+ LD E,0 (IX)
+ LD D,1 (IX) ;TEXTO ORIGEN
+ LD A,#1
+ JP cpc_PrintGphStr0
+
+
+
+.globl _cpc_PrintGphStrXY2X
+
+_cpc_PrintGphStrXY2X::
+;preparación datos impresión. El ancho y alto son fijos!
+ LD IX,#2
+ ADD IX,SP
+ LD L,3 (IX)
+ LD A,2 (IX) ;pantalla
+ CALL cpc_GetScrAddress0
+ LD E,0 (IX)
+ LD D,1 (IX) ;texto origen
+ LD A,#1
+ JP cpc_PrintGphStr0
+
+.globl _cpc_PrintGphStrXY
+
+_cpc_PrintGphStrXY::
+;preparación datos impresión. El ancho y alto son fijos!
+ LD IX,#2
+ ADD IX,SP
+ LD L,3 (IX)
+ LD A,2 (IX) ;pantalla
+ CALL cpc_GetScrAddress0
+ LD E,0 (IX)
+ LD D,1 (IX) ;texto origen
+ JP cpc_PrintGphStr0
+
+
+.globl _cpc_PrintGphStr
+
+_cpc_PrintGphStr::
+;preparación datos impresión. El ancho y alto son fijos!
+ LD IX,#2
+ ADD IX,SP
+ LD L,2 (IX)
+ LD H,3 (IX) ;DESTINO
+ ;LD (CPC_PRINTGPHSTR0+DIRECC_DESTINO0),HL
+ LD E,0 (IX)
+ LD D,1 (IX) ;TEXTO ORIGEN
+ ;JP cpc_PrintGphStr0
+
+cpc_PrintGphStr0:
+
+ ;DE destino
+ ;HL origen
+ ;ex de,hl
+ LD (#doble),A
+ ;trabajo previo: Para tener una lista de trabajos de impresión. No se interrumpe
+ ;la impresión en curso.
+ LD A,(#imprimiendo)
+ CP #1
+ JP Z,add_elemento
+ LD (#direcc_destino),HL
+ EX DE,HL
+ CALL bucle_texto0
+
+;antes de terminar, se mira si hay algo en cola.
+bucle_cola_impresion:
+ LD A,(#elementos_cola)
+ OR A
+ JP Z,terminar_impresion
+ CALL leer_elemento
+ JP bucle_cola_impresion
+
+
+terminar_impresion:
+ XOR A
+ LD (#imprimiendo),A
+ RET
+entrar_cola_impresion:
+;si se está imprimiendo se mete el valor en la cola
+ RET
+add_elemento:
+ DI
+ LD IX,(#pos_cola)
+ LD 0 (IX),L
+ LD 1 (IX),H
+ LD 2 (IX),E
+ LD 3 (IX),D
+ INC IX
+ INC IX
+ INC IX
+ INC IX
+ LD (#pos_cola),IX
+
+ LD HL,#elementos_cola
+ INC (HL)
+ ;Se añaden los valores hl y de
+ EI
+ RET
+leer_elemento:
+ DI
+ LD IX,(#pos_cola)
+ LD L,0 (IX)
+ LD H,1 (IX)
+ LD E,2 (IX)
+ LD D,4 (IX)
+ DEC IX
+ DEC IX
+ DEC IX
+ DEC IX
+ LD (#pos_cola),IX
+ LD HL,#elementos_cola
+ DEC (HL)
+ EI
+ RET
+
+elementos_cola:
+ .DW #0 ; defw 0
+pos_cola:
+ .DW #cola_impresion ;defw cola_impresion
+ ;pos_escritura_cola defw cola_impresion
+cola_impresion: ; defs 12
+ .DB #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+bucle_texto0:
+ LD A,#1
+ LD (imprimiendo),A
+
+ LD A,(first_char)
+ LD B,A ;resto 48 para saber el número del caracter (En ASCII 0=48)
+
+ LD A,(HL)
+ OR A ;CP 0
+ RET Z
+ SUB B
+ LD BC,(#cpc_Chars) ;apunto a la primera letra
+ PUSH HL
+
+ LD L,A ;en A tengo la letra que sería
+ LD H,#0
+ ADD HL,HL
+ ADD HL,HL
+ ADD HL,HL ;x8 porque cada letra son 8 bytes
+ ADD HL,BC ;ahora HL apunta a los datos de la letra correspondiente
+ CALL escribe_letra
+ LD A,(doble)
+ CP #1
+; ANTES DE IMPRIMIR SE CHEQUEA SI ES DE ALTURA EL DOBLE Y SE ACTÚA EN CONSECUENCIA
+ CALL Z, doblar_letra
+ LD HL,(#direcc_destino)
+ LD A,(doble)
+ CP #1
+ ;alto
+ JR Z,cont_doble
+ LD DE,#letra_decodificada
+ .DB #0xfD
+ LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ JR cont_tot
+
+
+cont_doble:
+ LD DE,#letra_decodificada_tmp
+ .DB #0xfD
+ LD H,#16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+
+cont_tot:
+ CALL cpc_PutSp0
+ LD HL,(#direcc_destino)
+ INC HL
+ INC HL
+ LD (#direcc_destino),HL
+ POP HL
+ INC HL
+ JP bucle_texto0
+
+
+doble:
+ .DB #0
+imprimiendo:
+ .DB #0
+direcc_destino:
+ .DW #0
+
+
+cpc_PutSp0:
+; .DB #0xfD
+; LD H,16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ LD B,#7
+ LD C,B
+loop_alto_2:
+
+loop_ancho_2:
+ EX DE,HL
+ LDI
+ LDI
+ .DB #0XFD
+ DEC H
+ RET Z
+ EX DE,HL
+salto_linea:
+ LD C,#0XFE ;&07F6 ;SALTO LINEA MENOS ANCHO
+ ADD HL,BC
+ JP NC,loop_alto_2 ;SIG_LINEA_2ZZ ;SI NO DESBORDA VA A LA SIGUIENTE LINEA
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7 ;SÓLO SE DARÍA UNA DE CADA 8 VECES EN UN SPRITE
+ JP loop_alto_2
+
+
+
+
+doblar_letra:
+ LD HL,#letra_decodificada
+ LD DE,#letra_decodificada_tmp
+ LD B,#8
+buc_doblar_letra:
+ LD A,(HL)
+ INC HL
+ LD (DE),A
+ INC DE
+ INC DE
+ LD (DE),A
+ DEC DE
+ LD A,(HL)
+ INC HL
+ LD (DE),A
+ INC DE
+ INC DE
+ LD (DE),A
+ INC DE
+ DJNZ buc_doblar_letra
+ RET
+
+
+escribe_letra: ; Code by Kevin Thacker
+ PUSH DE
+ LD IY,#letra_decodificada
+ LD B,#8
+bucle_alto_letra:
+ PUSH BC
+ PUSH HL
+ LD E,(HL)
+ CALL op_colores
+ LD (IY),D
+ INC IY
+ CALL op_colores
+ LD (IY),D
+ INC IY
+ POP HL
+ INC HL
+ POP BC
+ DJNZ bucle_alto_letra
+ POP DE
+ RET
+
+op_colores:
+ ld d,#0 ;; initial byte at end will be result of 2 pixels combined
+ CALL op_colores_pixel ;; do pixel 0
+ RLC D
+ CALL op_colores_pixel
+ RRC D
+ RET
+
+;; follow through to do pixel 1
+
+op_colores_pixel:
+ ;; shift out pixel into bits 0 and 1 (source)
+ RLC E
+ RLC E
+ ;; isolate
+ LD A,E
+ AND #0X3
+ LD HL,#colores_b0
+ ADD A,L
+ LD L,A
+ LD A,H
+ ADC A,#0
+ LD H,A
+ ;; READ IT AND COMBINE WITH PIXEL SO FAR
+ LD A,D
+ OR (HL)
+ LD D,A
+ RET
+
+
+.globl _cpc_SetInkGphStr
+
+_cpc_SetInkGphStr::
+;preparación datos impresión. El ancho y alto son fijos!
+ LD IX,#2
+ ADD IX,SP
+
+ ;LD A,H
+ ;LD C,L
+ LD A,1 (IX) ;VALOR
+ LD C,0 (IX) ;COLOR
+
+ LD HL,#colores_b0
+ LD B,#0
+ ADD HL,BC
+ LD (HL),A
+ RET
+
+
+
+
+
+.globl _cpc_PrintGphStrXYM1
+
+_cpc_PrintGphStrXYM1::
+;preparación datos impresión. El ancho y alto son fijos!
+ LD IX,#2
+ ADD IX,SP
+ LD L,3 (IX)
+ LD A,2 (IX) ;pantalla
+ CALL cpc_GetScrAddress0
+ LD E,0 (IX)
+ LD D,1 (IX) ;texto origen
+ XOR A
+ JP cpc_PrintGphStr0M1
+
+
+.globl _cpc_PrintGphStrXYM12X
+
+_cpc_PrintGphStrXYM12X::
+;preparación datos impresión. El ancho y alto son fijos!
+ LD IX,#2
+ ADD IX,SP
+ LD L,3 (IX)
+ LD A,2 (IX) ;pantalla
+ CALL cpc_GetScrAddress0
+ LD E,0 (IX)
+ LD D,1 (IX) ;texto origen
+ LD A,#1
+ JP cpc_PrintGphStr0M1
+
+
+
+
+.globl _cpc_PrintGphStrM12X
+
+_cpc_PrintGphStrM12X::
+ LD IX,#2
+ ADD IX,SP
+ LD L,2 (IX)
+ LD H,3 (IX) ;DESTINO
+ LD E,0 (IX)
+ LD D,1 (IX) ;TEXTO ORIGEN
+ LD A,#1
+
+ JP cpc_PrintGphStr0M1
+
+
+
+.globl _cpc_PrintGphStrM1
+
+_cpc_PrintGphStrM1::
+;preparación datos impresión. El ancho y alto son fijos!
+
+ LD IX,#2
+ ADD IX,SP
+ LD L,2 (IX)
+ LD H,3 (IX) ;DESTINO
+ LD E,0 (IX)
+ LD D,1 (IX) ;TEXTO ORIGEN
+ XOR A
+
+ ;JP cpc_PrintGphStr0M1
+
+cpc_PrintGphStr0M1:
+ ;DE destino
+ ;HL origen
+ ;ex de,hl
+ LD (#dobleM1),A
+ ;trabajo previo: Para tener una lista de trabajos de impresión. No se interrumpe
+ ;la impresión en curso.
+ LD A,(#imprimiendo)
+ CP #1
+ JP Z,add_elemento
+ LD (#direcc_destino),HL
+ EX DE,HL
+ CALL bucle_texto0M1
+;antes de terminar, se mira si hay algo en cola.
+bucle_cola_impresionM1:
+ LD A,(#elementos_cola)
+ OR A
+ JP Z,terminar_impresion
+ CALL leer_elemento
+ JP bucle_cola_impresionM1
+
+
+
+
+
+bucle_texto0M1:
+ LD A,#1
+ LD (#imprimiendo),A
+
+ LD A,(#first_char)
+ LD B,A ;resto 48 para saber el número del caracter (En ASCII 0=48)
+ LD A,(HL)
+ OR A ;CP 0
+ RET Z
+ SUB B
+ LD BC,(#cpc_Chars) ;apunto a la primera letra
+ PUSH HL
+ LD L,A ;en A tengo la letra que sería
+ LD H,#0
+ ADD HL,HL
+ ADD HL,HL
+ ADD HL,HL ;x8 porque cada letra son 8 bytes
+ ADD HL,BC ;ahora HL apunta a los datos de la letra correspondiente
+ CALL escribe_letraM1
+ LD A,(dobleM1)
+ CP #1
+ ; ANTES DE IMPRIMIR SE CHEQUEA SI ES DE ALTURA EL DOBLE Y SE ACTÚA EN CONSECUENCIA
+ CALL Z, doblar_letraM1
+ LD HL,(direcc_destino)
+ LD A,(dobleM1)
+ CP #1
+ ;alto
+ JR Z,cont_dobleM1
+ LD DE,#letra_decodificada
+ .DB #0xfD
+ LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ JR cont_totM1
+
+
+cont_dobleM1:
+ LD DE,#letra_decodificada_tmp
+ .DB #0XFD
+ LD H,#16 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+cont_totM1:
+ CALL cpc_PutSp0M1
+ LD HL,(#direcc_destino)
+ INC HL
+ LD (#direcc_destino),HL
+ POP HL
+ INC HL
+ JP bucle_texto0M1
+
+dobleM1:
+ .DB #0
+;.imprimiendo defb 0
+;.direcc_destino defw 0
+
+doblar_letraM1:
+ LD HL,#letra_decodificada
+ LD DE,#letra_decodificada_tmp
+ LD B,#8
+buc_doblar_letraM1:
+ LD A,(HL)
+ INC HL
+ LD (DE),A
+ INC DE
+ LD (DE),A
+ INC DE
+ DJNZ buc_doblar_letraM1
+ RET
+
+
+cpc_PutSp0M1:
+ ; defb #0xfD
+ ; LD H,8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ LD B,#7
+ LD C,B
+loop_alto_2M1:
+loop_ancho_2M1:
+ EX DE,HL
+ LDI
+ .DB #0XFD
+ DEC H
+ RET Z
+ EX DE,HL
+salto_lineaM1:
+ LD C,#0XFF ;#0x07f6 ;salto linea menos ancho
+ ADD HL,BC
+ JP NC,loop_alto_2M1 ;sig_linea_2zz ;si no desborda va a la siguiente linea
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7 ;sólo se daría una de cada 8 veces en un sprite
+ JP loop_alto_2M1
+
+
+
+escribe_letraM1:
+ LD IY,#letra_decodificada
+ LD B,#8
+ LD IX,#byte_tmp
+bucle_altoM1:
+ PUSH BC
+ PUSH HL
+
+ LD A,(HL)
+ LD HL,#dato
+ LD (HL),A
+ ;me deja en ix los valores convertidos
+ ;HL tiene la dirección origen de los datos de la letra
+ ;LD DE,letra ;el destino es la posición de decodificación de la letra
+ ;Se analiza el byte por parejas de bits para saber el color de cada pixel.
+ LD (IX),#0 ;reset el byte
+ LD B,#4 ;son 4 pixels por byte. Los recorro en un bucle y miro qué color tiene cada byte.
+bucle_coloresM1:
+ ;roto el byte en (HL)
+ PUSH HL
+ CALL op_colores_m1 ;voy a ver qué color es el byte. tengo un máximo de 4 colores posibles en modo 0.
+ POP HL
+ SRL (HL)
+ SRL (HL) ;voy rotando el byte para mirar los bits por pares.
+ DJNZ bucle_coloresM1
+ LD A,(IX)
+ LD (IY),A
+ INC IY
+ POP HL
+ INC HL
+ POP BC
+ DJNZ bucle_altoM1
+ RET
+
+
+;.rutina
+;HL tiene la dirección origen de los datos de la letra
+
+;Se analiza el byte por parejas de bits para saber el color de cada pixel.
+;ld ix,byte_tmp
+;ld (ix+0),0
+
+;LD B,4 ;son 4 pixels por byte. Los recorro en un bucle y miro qué color tiene cada byte.
+;.bucle_colores
+;roto el byte en (HL)
+;push hl
+;call op_colores_m1 ;voy a ver qué color es el byte. tengo un máximo de 4 colores posibles en modo 0.
+;pop hl
+;sla (HL)
+;sla (HL) ;voy rotando el byte para mirar los bits por pares.
+
+;djnz bucle_colores
+
+;ret
+op_colores_m1: ;rutina en modo 1
+ ;mira el color del bit a pintar
+ LD A,#3 ;hay 4 colores posibles. Me quedo con los 2 primeros bits
+ AND (HL)
+ ; EN A tengo el número de bytes a sumar!!
+ LD HL,#colores_m1
+ LD E,A
+ LD D,#0
+ ADD HL,DE
+ LD C,(HL)
+ ;EN C ESTÁ EL BYTE DEL COLOR
+ ;LD A,4
+ ;SUB B
+ LD A,B
+ DEC A
+ OR A ;CP 0
+ JP Z,_sin_rotar
+rotando:
+ SRL C
+ DEC A
+ JP NZ, rotando
+_sin_rotar:
+ LD A,C
+ OR (IX)
+ LD (IX),A
+ ;INC IX
+ RET
+
+
+.globl _cpc_SetInkGphStrM1
+
+_cpc_SetInkGphStrM1::
+ LD IX,#2
+ ADD IX,SP
+ LD A,1 (IX) ;VALOR
+ LD C,0 (IX) ;COLOR
+ LD HL,#colores_cambM1
+ LD B,#0
+ ADD HL,BC
+ LD (HL),A
+ RET
+
+
+
+colores_cambM1:
+colores_m1:
+ .DB #0b00000000,#0b10001000,#0b10000000,#0b00001000
+
+;defb @00000000, @01010100, @00010000, @00000101 ;@00000001, @00000101, @00010101, @00000000
+
+
+
+;DEFC direcc_destino0_m1 = direcc_destino
+;DEFC colores_cambM1 = colores_m1
+
+
+.globl _cpc_SetFont
+
+_cpc_SetFont::
+ ld ix, #2
+ add ix, sp
+ ld a, 0(ix)
+ ld (#first_char), a
+ ld l, 1(ix)
+ ld h, 2(ix)
+ ld (#cpc_Chars), hl
+ ret
+
+dato:
+ .DB #0b00011011 ;aquí dejo temporalmente el byte a tratar
+
+byte_tmp:
+ .DB #0
+ .DB #0
+ .DB #0 ;defs 3
+colores_b0: ;defino los 4 colores posibles para el byte. Los colores pueden ser cualesquiera.
+ ;Pero se tienen que poner bien, en la posición que le corresponda.
+ .DB #0b00001010,#0b00100000,#0b10100000,#0b00101000
+ ;.DB #0b00000000, #0b01010100, #0b00010000, #0b00000101 ;#0b00000001, #0b00000101, #0b00010101, #0b00000000
+
+letra_decodificada: ;. defs 16 ;16 ;uso este espacio para guardar la letra que se decodifica
+ .DB #0,#0,#0,#0,#0,#0,#0,#0
+ .DB #0,#0,#0,#0,#0,#0,#0,#0
+letra_decodificada_tmp: ;defs 32 ;16 ;uso este espacio para guardar la letra que se decodifica para tamaño doble altura
+ .DB #0,#0,#0,#0,#0,#0,#0,#0
+ .DB #0,#0,#0,#0,#0,#0,#0,#0
+ .DB #0,#0,#0,#0,#0,#0,#0,#0
+ .DB #0,#0,#0,#0,#0,#0,#0,#0
+
+
+first_char:
+ .DB #0 ;first defined char number (ASCII)
+
+cpc_Chars: ;cpc_Chars codificadas... cada pixel se define con 2 bits que definen el color.
+ .DW #0
+
diff --git a/lib/cpcrslib/cpc_Keyboard.s b/lib/cpcrslib/cpc_Keyboard.s
new file mode 100644
index 0000000..6008a50
--- /dev/null
+++ b/lib/cpcrslib/cpc_Keyboard.s
@@ -0,0 +1,344 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl Simarro (Artaburu) - 2009, 2012 **
+; ******************************************************
+
+;*************************************
+; KEYBOARD
+;*************************************
+
+
+.globl _cpc_AnyKeyPressed
+
+MAX_KEYS = 12
+
+_cpc_AnyKeyPressed::
+ call hacer_tiempo
+ call hacer_tiempo
+ call hacer_tiempo
+
+
+
+ LD A,#0x40
+bucle_deteccion_tecla:
+ PUSH AF
+ CALL cpc_TestKeyboard ;en A vuelve los valores de la linea
+ OR A
+ JP NZ, tecla_pulsada ; retorna si no se ha pulsado ninguna tecla
+ POP AF
+ INC A
+ CP #0x4a
+ JP NZ, bucle_deteccion_tecla
+ LD HL,#0
+
+ RET
+
+tecla_pulsada:
+ POP AF
+ LD HL,#1
+ RET
+
+hacer_tiempo:
+ LD A,#254
+bucle_previo_deteccion_tecla:
+ PUSH AF
+ POP AF
+ dec A
+ Jr nZ, bucle_previo_deteccion_tecla
+ ret
+
+
+
+.globl _cpc_AssignKey
+
+_cpc_AssignKey::
+
+ LD HL,#2
+ ADD HL,SP
+ LD E,(HL) ;E-> numero tecla
+ INC HL
+ ;INC HL
+ LD A,(HL) ;linea, byte
+ INC HL
+ LD B,(HL) ;DE tiene el valor de la tecla a escribir en la tabla
+ ; En A se tiene el valor de la tecla seleccionada a comprobar [0..11]
+ ;___________________________________________________________________
+ ; ;En A viene la tecla a redefinir (0..11)
+ SLA E
+ LD D,#0
+ LD HL, #tabla_teclas
+ ADD HL,DE ;Nos colocamos en la tecla a redefinir y la borramos
+ LD (HL),#0XFF
+ INC HL
+ LD (HL),#0XFF
+ DEC HL
+ PUSH HL
+ ;call ejecutar_deteccion_teclado ;A tiene el valor del teclado
+ ; A tiene el byte (<>0)
+ ; B tiene la linea
+ ;guardo linea y byte
+ POP HL
+ LD (HL),A ;byte
+ INC HL
+ LD (HL),B
+ RET
+
+
+.globl _cpc_TestKey
+
+_cpc_TestKey::
+
+ LD HL,#2
+ ADD HL,SP
+ LD L,(HL) ; En A se tiene el valor de la tecla seleccionada a comprobar [0..11]
+ SLA L
+ INC L
+ LD H,#0
+ LD DE,#tabla_teclas
+ ADD HL,DE
+ LD A,(HL)
+ CALL cpc_TestKeyboard ; esta rutina lee la línea del teclado correspondiente
+ DEC HL ; pero sólo nos interesa una de las teclas.
+ and (HL) ;para filtrar por el bit de la tecla (puede haber varias pulsadas)
+ CP (HL) ;comprueba si el byte coincide
+ LD H,#0
+ JP Z,pulsado
+ LD L,H
+ RET
+pulsado:
+ LD L,#1
+ RET
+
+
+
+
+
+.globl _cpc_RedefineKey
+
+_cpc_RedefineKey::
+
+ LD HL,#2
+ ADD HL,SP
+ LD L,(HL)
+ SLA L
+ LD H,#0
+ LD DE,#tabla_teclas
+ ADD HL,DE ;Nos colocamos en la tecla a redefinir
+ LD (HL),#0XFF ; y la borramos
+ INC HL
+ LD (HL),#0XFF
+ DEC HL
+ PUSH HL
+ CALL ejecutar_deteccion_teclado ;A tiene el valor del teclado
+ LD A,D
+ ; A tiene el byte (<>0)
+ ; B tiene la linea
+ ;guardo linea y byte
+ POP HL ;recupera posición leída
+ LD A,(linea)
+ LD (HL),A ;byte
+ INC HL
+ LD A,(bte)
+ LD (HL),A
+ RET
+
+
+ejecutar_deteccion_teclado:
+ LD A,#0x40
+bucle_deteccion_tecla1:
+ PUSH AF
+ LD (bte),A
+ CALL cpc_TestKeyboard ;en A vuelve los valores de la linea
+ OR A
+ JR NZ, tecla_pulsada1 ; retorna si no se ha pulsado ninguna tecla
+ POP AF
+ INC A
+ CP #0x4A
+ JR NZ, bucle_deteccion_tecla1
+ JR ejecutar_deteccion_teclado
+
+tecla_pulsada1:
+ LD (linea),A
+ POP AF
+ CALL comprobar_si_tecla_usada
+ RET NC
+ JR bucle_deteccion_tecla1
+
+comprobar_si_tecla_usada: ; A tiene byte, B linea
+ LD B,#MAX_KEYS ;numero máximo de tecla redefinibles
+ LD IX,#tabla_teclas
+ LD C,(IX)
+bucle_bd_teclas: ;comprobar byte
+ LD A,(linea)
+ LD C,(IX)
+ CP (IX)
+ JR Z, comprobar_linea
+ INC IX
+ INC IX
+ DJNZ bucle_bd_teclas
+ SCF
+ CCF
+ RET ; si vuelve después de comprobar, que sea NZ
+comprobar_linea: ;si el byte es el mismo, mira la linea
+ LD A,(bte)
+ CP 1 (IX) ; esto es (ix+1)
+ JR Z, tecla_detectada ; Vuelve con Z si coincide el byte y la linea
+ INC IX
+ INC IX
+ DJNZ bucle_bd_teclas
+ SCF
+ CCF
+ RET ; si vuelve después de comprobar, que sea NZ
+tecla_detectada:
+ SCF
+ RET
+
+
+.globl _cpc_DeleteKeys
+
+_cpc_DeleteKeys:: ;borra la tabla de las teclas para poder redefinirlas todas
+ LD HL,#tabla_teclas
+ LD DE,#tabla_teclas+#1
+ LD BC, #MAX_KEYS
+ LD (HL),#0xFF
+ LDIR
+ RET
+
+
+.globl _cpc_TestKeyF
+
+_cpc_TestKeyF::
+ LD HL,#2
+ ADD HL,SP
+ LD L,(HL)
+ SLA L
+ INC L
+ LD H,#0
+ LD DE,#tabla_teclas
+ ADD HL,DE
+ LD A,(HL)
+ SUB #0X40
+ EX DE,HL
+ LD HL,#keymap ;; LEE LA LÍNEA BUSCADA DEL KEYMAP
+ LD C,A
+ LD B,#0
+ ADD HL,BC
+ LD A,(HL)
+ EX DE,HL
+ DEC HL ; PERO SÓLO NOS INTERESA UNA DE LAS TECLAS.
+ AND (HL) ;PARA FILTRAR POR EL BIT DE LA TECLA (PUEDE HABER VARIAS PULSADAS)
+ CP (HL) ;COMPRUEBA SI EL BYTE COINCIDE
+ LD H,#0
+ JP NZ,#pulsado_cpc_TestKeyF
+ LD L,H
+ RET
+pulsado_cpc_TestKeyF:
+ LD L,#1
+ RET
+
+
+.globl _cpc_ScanKeyboard
+
+_cpc_ScanKeyboard::
+
+ DI ;1 #0X#0X%%#0X#0X C P C VERSION #0X#0X%%#0X#0X FROM CPCWIKI
+ LD HL,#keymap ;3
+ LD BC,#0XF782 ;3
+ OUT (C),C ;4
+ LD BC,#0XF40E ;3
+ LD E,B ;1
+ OUT (C),C ;4
+ LD BC,#0XF6C0 ;3
+ LD D,B ;1
+ OUT (C),C ;4
+ .DB #0XED,#0X71 ; 4 OUT (C),0
+ LD BC,#0XF792 ;3
+ OUT (C),C ;4
+ LD A,#0X40 ;2
+ LD C,#10 ;2 44
+loop_cpc_scankeyboard:
+ LD B,D ;1
+ OUT (C),A ;4 SELECT LINE
+ LD B,E ;1
+ INI ;5 READ BITS AND WRITE INTO KEYMAP
+ INC A ;1
+ DEC C ;1
+ JR NZ,loop_cpc_scankeyboard ;2/3 9*16+1*15=159
+ LD BC,#0XF782 ;3
+ OUT (C),C ;4
+ EI ;1 8 =209 MICROSECONDS
+ RET
+
+
+
+cpc_TestKeyboard:: ;Tomado de las rutinas básicas que aparecen
+ ;en los documentos de Kevin Thacker
+
+ DI
+ LD BC,#0XF782
+ OUT (C),C
+ LD BC, #0XF40E
+ OUT (C), C
+ LD BC, #0XF6C0
+ OUT (C), C
+ .DB #0XED,#0X71 ; OUT (C),0
+ LD BC, #0XF792
+ OUT (C), C
+ DEC B
+ OUT (C), A
+ LD B, #0XF4
+ IN A, (C)
+ LD BC, #0XF782
+ OUT (C), C
+ DEC B
+ .DB #0XED,#0X71 ; OUT (C),0
+ CPL
+ EI
+ RET
+
+linea:
+ .DB #0
+bte:
+ .DB #0
+
+keymap:
+ .DB #0
+ .DB #0
+ .DB #0
+ .DB #0
+ .DB #0
+ .DB #0
+ .DB #0
+ .DB #0
+ .DB #0
+ .DB #0
+
+;teclado_usable ; teclas del cursor, cada tecla está definida por su bit y su línea.
+.globl _cpc_keys_table
+_cpc_keys_table:
+tabla_teclas:
+tecla_0_x: .DW #0xffff ; bit 0, línea 2
+tecla_1_x: .DW #0xffff ; bit 1, línea 1
+tecla_2_x: .DW #0xffff ; bit 0, línea 1
+tecla_3_x: .DW #0xffff ; bit 0, línea 4
+tecla_4_x: .DW #0xffff ; bit 0, línea 2
+tecla_5_x: .DW #0xffff ; bit 1, línea 1
+tecla_6_x: .DW #0xffff ; bit 0, línea 1
+tecla_7_x: .DW #0xffff ; bit 0, línea 4
+tecla_8_x: .DW #0xffff ; bit 0, línea 4
+tecla_9_x: .DW #0xffff ; bit 0, línea 4
+tecla_10_x: .DW #0xffff ; bit 0, línea 4
+tecla_11_x: .DW #0xffff ; bit 0, línea 4
+; For increasing keys available just increase this word table
+.DB #0
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/cpcrslib/cpc_PrintStr.s b/lib/cpcrslib/cpc_PrintStr.s
new file mode 100644
index 0000000..28e713a
--- /dev/null
+++ b/lib/cpcrslib/cpc_PrintStr.s
@@ -0,0 +1,27 @@
+.globl _cpc_PrintStr
+
+_cpc_PrintStr::
+ LD IX,#2
+ ADD IX,SP
+ LD l,0 (IX)
+ LD h,1 (IX) ;TEXTO ORIGEN
+
+; LD HL,#2
+ ; ADD HL,SP
+; LD E,(HL)
+; INC HL
+; LD D,(HL)
+; EX DE,HL
+bucle_imp_cadena:
+ LD A,(HL)
+ OR A
+ JR Z,salir_bucle_imp_cadena
+ CALL #0XBB5A
+ INC HL
+ JR bucle_imp_cadena
+salir_bucle_imp_cadena:
+ LD A,#0X0D ; PARA TERMINAR HACE UN SALTO DE LÃNEA
+ CALL #0XBB5A
+ LD A,#0X0A
+ JP 0XBB5A
+
diff --git a/lib/cpcrslib/cpc_PutMaskSp.s b/lib/cpcrslib/cpc_PutMaskSp.s
new file mode 100644
index 0000000..e9683e4
--- /dev/null
+++ b/lib/cpcrslib/cpc_PutMaskSp.s
@@ -0,0 +1,79 @@
+;void cpc_PutMaskSprite(int *sprite, int *posicion);
+;void cpc_PutMaskSp(int *sprite, char alto, char ancho, int *posicion);
+.globl _cpc_PutMaskSp
+
+_cpc_PutMaskSp:: ; dibujar en pantalla el sprite
+ ; Entradas bc-> Alto Ancho
+ ; de-> origen
+ ; hl-> destino
+ ; Se alteran hl, bc, de, af
+
+ LD IX,#2
+ ADD IX,SP
+ LD L,4 (IX)
+ LD H,5 (IX)
+ LD A,3 (IX)
+ LD E,0 (IX)
+ LD D,1 (IX)
+ ld (#loop_alto_2m_PutMaskSp0+#1),a ;actualizo rutina de captura
+ SUB #1
+ CPL
+ LD (#salto_lineam_PutMaskSp0+#1),A ;comparten los 2 los mismos valores.
+ ld A,2(IX)
+ ;JP cpc_PutMaskSp0
+
+cpc_PutMaskSp0:
+ .DB #0XFD
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ LD B,#7
+loop_alto_2m_PutMaskSp0:
+ LD C,#4
+ EX DE,HL
+loop_ancho_2m_PutMaskSp0:
+ LD A,(DE) ;LEO EL BYTE DEL FONDO
+ AND (HL) ;LO ENMASCARO
+ INC HL
+ OR (HL) ;LO ENMASCARO
+ LD (DE),A ;ACTUALIZO EL FONDO
+ INC DE
+ INC HL
+ DEC C
+ JP NZ,loop_ancho_2m_PutMaskSp0
+ .DB #0XFD
+ DEC H
+ RET Z
+ EX DE,HL
+salto_lineam_PutMaskSp0:
+ LD C,#0XFF
+ ADD HL,BC
+ JP nc,loop_alto_2m_PutMaskSp0
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7
+ JP loop_alto_2m_PutMaskSp0
+
+.globl _cpc_PutMaskSprite
+
+_cpc_PutMaskSprite:: ; dibujar en pantalla el sprite
+ ; Entradas bc-> Alto Ancho
+ ; de-> origen
+ ; hl-> destino
+ ; Se alteran hl, bc, de, af
+
+ POP AF
+ POP HL
+ POP DE
+ PUSH AF
+ LD A,(HL) ;ANCHO
+ INC HL
+ ld (#loop_alto_2m_PutMaskSp0+#1),a ;ACTUALIZO RUTINA DE CAPTURA
+ ;LD (ANCHOT+1),A ;ACTUALIZO RUTINA DE DIBUJO
+ SUB #1
+ CPL
+ LD (#salto_lineam_PutMaskSp0+#1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES.
+ LD A,(HL) ;ALTO
+ INC HL
+ EX DE,HL
+ jp cpc_PutMaskSp0
+
+
diff --git a/lib/cpcrslib/cpc_PutMaskSp2x8.s b/lib/cpcrslib/cpc_PutMaskSp2x8.s
new file mode 100644
index 0000000..ac85f0e
--- /dev/null
+++ b/lib/cpcrslib/cpc_PutMaskSp2x8.s
@@ -0,0 +1,45 @@
+.globl _cpc_PutMaskSp2x8
+; imprime un sprite de 8x8 en modo 1
+; El formato del sprite es el siguiente por cada línea:
+; defb byte1,byte2,byte3,byte4
+; siendo byte1 y byte3 son las máscaras de los bytes 2 y 4
+; se recibe de entrada el sprite y la posición.
+_cpc_PutMaskSp2x8::
+ LD IX,#2
+ ADD IX,SP
+ LD L,2 (IX)
+ LD H,3 (IX)
+ LD E,0 (IX)
+ LD D,1 (IX)
+ .DB #0XFD
+ LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ LD B,#7
+loop_alto_mask_2x8:
+ EX DE,HL
+ LD A,(DE) ;leo el byte del fondo
+ AND (HL) ;lo enmascaro
+ INC HL
+ OR (HL) ;lo enmascaro
+ LD (DE),A ;actualizo el fondo
+ INC DE
+ INC HL
+ ;COMO SOLO SON 2 BYTES, es más rápido y económico desplegar la rutina
+ LD A,(DE)
+ AND (HL)
+ INC HL
+ OR (HL)
+ LD (DE),A
+ INC DE
+ INC HL
+ .DB #0XFD
+ DEC H
+ RET Z
+ EX DE,HL
+ LD C,#0XFE
+ ADD HL,BC
+ JP NC,loop_alto_mask_2x8
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7
+ JP loop_alto_mask_2x8
+
diff --git a/lib/cpcrslib/cpc_PutMaskSp4x16.s b/lib/cpcrslib/cpc_PutMaskSp4x16.s
new file mode 100644
index 0000000..4fbbd61
--- /dev/null
+++ b/lib/cpcrslib/cpc_PutMaskSp4x16.s
@@ -0,0 +1,56 @@
+.globl _cpc_PutMaskSp4x16
+
+_cpc_PutMaskSp4x16::
+
+ LD IX,#2
+ ADD IX,SP
+ LD L,2 (IX)
+ LD H,3 (IX)
+ LD E,0 (IX)
+ LD D,1 (IX)
+ .DB #0XFD
+ LD H,#16
+ LD B,#7
+loop_alto_mask_4x16:
+ EX DE,HL
+ LD A,(DE) ;leo el byte del fondo
+ AND (HL) ;lo enmascaro
+ INC HL
+ OR (HL) ;lo enmascaro
+ LD (DE),A ;actualizo el fondo
+ INC DE
+ INC HL
+ ;COMO SOLO SON 4 BYTES, es más rápido y económico desplegar la rutina
+ LD A,(DE) ;leo el byte del fondo
+ AND (HL) ;lo enmascaro
+ INC HL
+ OR (HL) ;lo enmascaro
+ LD (DE),A ;actualizo el fondo
+ INC DE
+ INC HL
+ LD A,(DE) ;leo el byte del fondo
+ AND (HL) ;lo enmascaro
+ INC HL
+ OR (HL) ;lo enmascaro
+ LD (DE),A ;actualizo el fondo
+ INC DE
+ INC HL
+ LD A,(DE) ;leo el byte del fondo
+ AND (HL) ;lo enmascaro
+ INC HL
+ OR (HL) ;lo enmascaro
+ LD (DE),A ;actualizo el fondo
+ INC DE
+ INC HL
+ .DB #0XFD
+ DEC H
+ RET Z
+ EX DE,HL
+ LD C,#0XFC
+ ADD HL,BC
+ JP NC,loop_alto_mask_4x16
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7
+ JP loop_alto_mask_4x16
+
diff --git a/lib/cpcrslib/cpc_PutSp.s b/lib/cpcrslib/cpc_PutSp.s
new file mode 100644
index 0000000..0ddbf10
--- /dev/null
+++ b/lib/cpcrslib/cpc_PutSp.s
@@ -0,0 +1,54 @@
+.globl _cpc_PutSp
+
+_cpc_PutSp:: ; dibujar en pantalla el sprite
+ ; Entradas bc-> Alto Ancho
+ ; de-> origen
+ ; hl-> destino
+ ; Se alteran hl, bc, de, af
+
+ LD IX,#2
+ ADD IX,SP
+ LD E,0 (IX)
+ LD D,1 (IX)
+ LD A,3 (IX)
+ LD L,4 (IX)
+ LD H,5 (IX)
+
+ LD (#ancho0+1),A ;actualizo rutina de captura
+ ;ld (anchot+1),a ;actualizo rutina de dibujo
+ SUB #1
+ CPL
+ LD (#suma_siguiente_linea0+1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES.
+
+ LD A,2 (IX)
+ ;JP cpc_putsp0
+
+pc_PutSp0:
+ .DB #0XFD
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ LD B,#7
+ancho0:
+loop_alto_2_pc_PutSp0:
+ LD C,#4
+loop_ancho_2_pc_PutSp0:
+ LD A,(DE)
+ LD (HL),A
+ INC DE
+ INC HL
+ DEC C
+ JP NZ,loop_ancho_2_pc_PutSp0
+ .DB #0XFD
+ DEC H
+ RET Z
+
+suma_siguiente_linea0:
+salto_linea_pc_PutSp0:
+ LD C,#0XFF ;&07F6 ;SALTO LINEA MENOS ANCHO
+ ADD HL,BC
+ JP nc,loop_alto_2_pc_PutSp0 ;sig_linea_2zz ;si no desborda va a la siguiente linea
+ LD BC,#0XC050
+
+ ADD HL,BC
+ LD B,#7 ;SÓLO SE DARÃA UNA DE CADA 8 VECES EN UN SPRITE
+ JP loop_alto_2_pc_PutSp0
+
diff --git a/lib/cpcrslib/cpc_PutSp2x14.s b/lib/cpcrslib/cpc_PutSp2x14.s
new file mode 100644
index 0000000..241d66b
--- /dev/null
+++ b/lib/cpcrslib/cpc_PutSp2x14.s
@@ -0,0 +1,50 @@
+.globl _cpc_PutSp4x14
+
+_cpc_PutSp4x14:: ; dibujar en pantalla el sprite
+ ; Entradas bc-> Alto Ancho
+ ; de-> origen
+ ; hl-> destino
+ ; Se alteran hl, bc, de, af
+
+ LD IX,#2
+ ADD IX,SP
+ LD e,0 (IX)
+ LD d,1 (IX) ;sprite
+ LD l,2 (IX)
+ LD h,3 (IX) ;address
+ ld A,#14
+
+pc_PutSp0X:
+ .DB #0XFD
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ LD B,#7
+ancho0X:
+loop_alto_2_pc_PutSp0X:
+ LD C,#4
+loop_ancho_2_pc_PutSp0X:
+ EX DE,HL
+ LDI
+ LDI
+ LDI
+ LDI
+ EX DE,HL
+ ;LD A,(DE)
+ ;LD (HL),A
+ ;INC DE
+ ;INC HL
+ ;DEC C
+ ;JP NZ,loop_ancho_2_pc_PutSp0X
+ .DB #0XFD
+ DEC H
+ RET Z
+
+suma_siguiente_linea0X:
+salto_linea_pc_PutSp0X:
+ LD C,#0XFC ;&07F6 ;SALTO LINEA MENOS ANCHO
+ ADD HL,BC
+ JP nc,loop_alto_2_pc_PutSp0X ;sig_linea_2zz ;si no desborda va a la siguiente linea
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7 ;SÓLO SE DARÃA UNA DE CADA 8 VECES EN UN SPRITE
+ JP loop_alto_2_pc_PutSp0X
+
diff --git a/lib/cpcrslib/cpc_PutSpTr.s b/lib/cpcrslib/cpc_PutSpTr.s
new file mode 100644
index 0000000..e1d24fa
--- /dev/null
+++ b/lib/cpcrslib/cpc_PutSpTr.s
@@ -0,0 +1,75 @@
+.globl _cpc_PutSpTr
+
+_cpc_PutSpTr:: ; dibujar en pantalla el sprite
+ ; Entradas bc-> Alto Ancho
+ ; de-> origen
+ ; hl-> destino
+ ; Se alteran hl, bc, de, af
+ LD IX,#2
+ ADD IX,SP
+ LD E,0 (IX)
+ LD D,1 (IX)
+ LD A,4 (IX)
+ LD L,6 (IX)
+ LD H,7 (IX)
+
+
+ LD (#anchot+1),A ;actualizo rutina de dibujo
+ SUB #1
+ CPL
+ LD (#suma_siguiente_lineat+1),A ;comparten los 2 los mismos valores.
+
+ LD A,2 (IX)
+ ;JP cpc_PutSpTr0
+
+cpc_PutSpTr0:
+ .DB #0XFD
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+anchot:
+loop_alto_2t:
+ LD B,#0
+loop_ancho_2t:
+ LD A,(DE)
+ AND #0XAA
+ JP Z,sig_pixn_der_2
+ LD C,A ;B es el único registro libre
+ LD A,(HL) ;pixel actual donde pinto
+ AND #0X55
+ OR C
+ LD (HL),A ;y lo pone en pantalla
+sig_pixn_der_2:
+ LD A,(DE) ;pixel del sprite
+ AND #0X55
+ JP Z,pon_buffer_der_2
+ LD C,A ;B es el único registro libre
+ LD A,(HL) ;PIXEL ACTUAL DONDE PINTO
+ AND #0XAA
+ OR C
+ LD (HL),A
+pon_buffer_der_2:
+ INC DE
+ INC HL
+ DEC B
+ JP NZ,loop_ancho_2t
+ .DB #0XFD
+ DEC H
+ RET Z
+suma_siguiente_lineat:
+salto_lineat:
+ LD BC,#0X07FF ;&07f6 ;salto linea menos ancho
+ ADD HL,BC
+ JP NC,loop_alto_2t ;sig_linea_2zz ;si no desborda va a la siguiente linea
+ LD BC,#0XC050
+ ADD HL,BC
+ ;ld b,7 ;sólo se daría una de cada 8 veces en un sprite
+ JP loop_alto_2t
+
+ LD A,H
+ ADD #0X08
+ LD H,A
+ SUB #0XC0
+ JP NC,loop_alto_2t ;sig_linea_2
+ LD BC,#0XC050
+ ADD HL,BC
+ JP loop_alto_2t
+
diff --git a/lib/cpcrslib/cpc_PutSpXOR.s b/lib/cpcrslib/cpc_PutSpXOR.s
new file mode 100644
index 0000000..f4e58f0
--- /dev/null
+++ b/lib/cpcrslib/cpc_PutSpXOR.s
@@ -0,0 +1,79 @@
+.globl _cpc_PutSpXOR
+
+_cpc_PutSpXOR:: ; dibujar en pantalla el sprite
+ ; Entradas bc-> Alto Ancho
+ ; de-> origen
+ ; hl-> destino
+ ; Se alteran hl, bc, de, af
+
+ LD IX,#2
+ ADD IX,SP
+ LD E,0 (IX)
+ LD D,1 (IX)
+ LD A,3 (IX)
+ LD L,4 (IX)
+ LD H,5 (IX)
+
+ LD (#anchox0+#1),A ;actualizo rutina de captura
+ SUB #1
+ CPL
+ LD (#suma_siguiente_lineax0+#1),A ;comparten los 2 los mismos valores.
+
+ LD A,2 (IX)
+ JP cpc_PutSpXOR0
+
+
+.globl _cpc_PutSpriteXOR
+
+_cpc_PutSpriteXOR:: ; dibujar en pantalla el sprite
+ ; Entradas bc-> Alto Ancho
+ ; de-> origen
+ ; hl-> destino
+ ; Se alteran hl, bc, de, af
+ POP AF
+ POP HL
+ POP DE
+ PUSH AF
+ LD A,(HL) ;ANCHO
+ INC HL
+ LD (#anchox0+#1),A ;ACTUALIZO RUTINA DE CAPTURA
+ ;LD (ANCHOT+1),A ;ACTUALIZO RUTINA DE DIBUJO
+ SUB #1
+ CPL
+ LD (#suma_siguiente_lineax0+1),A ;COMPARTEN LOS 2 LOS MISMOS VALORES.
+ LD A,(HL) ;ALTO
+ INC HL
+ EX DE,HL
+ ;LD A,(IX+4)
+ JP cpc_PutSpXOR0
+
+
+cpc_PutSpXOR0:
+ .DB #0XFD
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ LD B,#7
+anchox0:
+loop_alto_2x:
+ LD C,#4
+loop_ancho_2x:
+ LD A,(DE)
+ XOR (HL)
+ LD (HL),A
+ INC DE
+ INC HL
+ DEC C
+ JP NZ,loop_ancho_2x
+ .DB #0XFD
+ DEC H
+ RET Z
+
+suma_siguiente_lineax0:
+salto_lineax:
+ LD C,#0XFF ;&07F6 ;SALTO LINEA MENOS ANCHO
+ ADD HL,BC
+ JP NC,loop_alto_2x ;SIG_LINEA_2ZZ ;SI NO DESBORDA VA A LA SIGUIENTE LINEA
+ LD BC,#0XC050
+ ADD HL,BC
+ LD B,#7 ;SÓLO SE DARÃA UNA DE CADA 8 VECES EN UN SPRITE
+ JP loop_alto_2x
+
diff --git a/lib/cpcrslib/cpc_PutSprite.s b/lib/cpcrslib/cpc_PutSprite.s
new file mode 100644
index 0000000..a6d6dec
--- /dev/null
+++ b/lib/cpcrslib/cpc_PutSprite.s
@@ -0,0 +1,108 @@
+.globl _cpc_PutSprite
+
+_cpc_PutSprite::
+;*************************************
+; SPRITE ROUTINE WITHOUT TRANSPARENCY
+; Supplied by Tim Riemann
+; from a German forum
+; DE = source address of the sprite
+; (includes header with 1B width [64byte maximum!], 1B height)
+; HL = destination address
+;*************************************
+
+ POP AF
+ POP HL ;DESTINATION ADDRESS
+ POP DE ;SPRITE DATA
+ PUSH AF
+ ;EX DE,HL
+ LD A,#64
+ SUB (HL)
+ ADD A
+ LD (width1+1),A
+ XOR A
+ SUB (HL)
+ LD (width2+1),A
+ INC HL
+ LD A,(HL)
+ INC HL
+width0:
+ ;ex de,hl
+width1:
+ JR width1 ;cada LDI es un byte
+ LDI ;se hace el salto al byte correspondiente (64-ancho)
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+ LDI
+width2:
+ LD BC,#0X700
+ EX DE,HL
+ ADD HL,BC
+ JP NC,width3
+ LD BC,#0XC050
+ ADD HL,BC
+width3:
+ EX DE,HL
+ DEC A
+ JP NZ, width1
+ RET
+
diff --git a/lib/cpcrslib/cpc_RLI.s b/lib/cpcrslib/cpc_RLI.s
new file mode 100644
index 0000000..92a9385
--- /dev/null
+++ b/lib/cpcrslib/cpc_RLI.s
@@ -0,0 +1,39 @@
+.globl _cpc_RLI ;rota las líneas que se le digan hacia la izq y mete lo rotado por la derecha.
+
+_cpc_RLI::
+ LD IX,#2
+ ADD IX,SP
+ LD L,0 (IX)
+ LD H,1 (IX) ;posición inicial
+ LD A,2 (IX) ;lineas
+ LD (alto_cpc_RLI+1),A
+ LD A,3 (IX) ;ancho
+ LD (ancho_cpc_RLI+1),A
+ DEC HL
+alto_cpc_RLI:
+ LD A,#8 ;; parametro
+ciclo0_cpc_RLI:
+ PUSH AF
+ PUSH HL
+ INC HL
+ LD A,(HL)
+ LD D,H
+ LD E,L
+ DEC HL
+ LD B, #0
+ancho_cpc_RLI:
+ LD C,#50 ; parametro
+ LDDR
+ INC HL
+ LD (HL),A
+ POP HL
+ POP AF
+ DEC A
+ RET Z
+ LD BC,#0X800 ;salto de línea, ojo salto caracter.
+ ADD HL,BC
+ JP NC,ciclo0_cpc_RLI ;sig_linea_2zz ;si no desborda va a la siguiente linea
+ LD BC,#0XC050
+ ADD HL,BC
+ JP ciclo0_cpc_RLI
+
diff --git a/lib/cpcrslib/cpc_RRI.s b/lib/cpcrslib/cpc_RRI.s
new file mode 100644
index 0000000..d2f5b5d
--- /dev/null
+++ b/lib/cpcrslib/cpc_RRI.s
@@ -0,0 +1,39 @@
+.globl _cpc_RRI
+;cpc_RRI(unsigned int pos, unsigned char w, unsigned char h);
+_cpc_RRI::
+ LD IX,#2
+ ADD IX,SP
+ LD L,0 (IX)
+ LD H,1 (IX) ;posición inicial
+ LD A,2 (IX) ;lineas
+ LD (alto_cpc_RRI+1),A
+ LD A,3 (IX) ;ancho
+ LD (ancho_cpc_RRI+1),A
+ INC HL
+alto_cpc_RRI:
+ LD A,#8 ;; parametro
+ciclo0_cpc_RRI:
+ PUSH AF
+ PUSH HL
+ DEC HL
+ LD A,(HL)
+ LD D,H
+ LD E,L
+ INC HL ; SOLO MUEVE 1 BYTE
+ LD B, #0
+ancho_cpc_RRI:
+ LD C,#50 ; PARAMETRO
+ LDIR
+ DEC HL
+ LD (HL),A
+ POP HL
+ POP AF
+ DEC A
+ RET Z
+ LD BC,#0X800 ;salto de línea, ojo salto caracter
+ ADD HL,BC
+ JP NC,ciclo0_cpc_RRI ;sig_linea_2zz ;si no desborda va a la siguiente linea
+ LD BC,#0XC050
+ ADD HL,BC
+ JP ciclo0_cpc_RRI
+
diff --git a/lib/cpcrslib/cpc_Random.s b/lib/cpcrslib/cpc_Random.s
new file mode 100644
index 0000000..2f2916e
--- /dev/null
+++ b/lib/cpcrslib/cpc_Random.s
@@ -0,0 +1,34 @@
+.globl _cpc_Random
+
+_cpc_Random::
+
+
+ ; LD A,(#valor_previo)
+ ; LD C,A
+; LD L,A
+; LD A,R;
+; ADD L
+; AND #0xB8
+; SCF
+; JP PO,NO_CLR
+; CCF
+;NO_CLR: LD A,C
+ ; RLA
+ ; LD C,A
+ ; LD A,R
+ ; ADD C
+ ; LD (#valor_previo),A
+ ; LD L,A
+; RET
+
+ LD A,(#valor_previo)
+ LD L,A
+ LD A,R
+ ADD L ;LOS 2 ÚLTIMOS BITS DE A DIRÃN SI ES 0,1,2,3
+ LD (#valor_previo),A
+ LD L,A ;SE DEVUELVE L (CHAR)
+ LD H,#0
+ RET
+valor_previo:
+ .db #0xFF
+
diff --git a/lib/cpcrslib/cpc_SetBorder.s b/lib/cpcrslib/cpc_SetBorder.s
new file mode 100644
index 0000000..b1939df
--- /dev/null
+++ b/lib/cpcrslib/cpc_SetBorder.s
@@ -0,0 +1,10 @@
+.globl _cpc_SetBorder
+
+_cpc_SetBorder::
+ LD HL,#2
+ ADD HL,SP
+ LD B,(HL)
+ ;LD B,A
+ LD C,B
+ JP 0XBC38
+
diff --git a/lib/cpcrslib/cpc_SetColour.s b/lib/cpcrslib/cpc_SetColour.s
new file mode 100644
index 0000000..7fd6dc3
--- /dev/null
+++ b/lib/cpcrslib/cpc_SetColour.s
@@ -0,0 +1,16 @@
+.globl _cpc_SetColour
+
+_cpc_SetColour:: ;El número de tinta 17 es el borde
+ LD HL,#2
+ ADD HL,SP
+ LD A,(HL)
+ INC HL
+ ;INC HL
+ LD E,(HL)
+ LD BC,#0x7F00 ;Gate Array
+ OUT (C),A ;Número de tinta
+ LD A,#64 ;@01000000 ;Color (y Gate Array)
+ ADD E
+ OUT (C),A
+ RET
+
diff --git a/lib/cpcrslib/cpc_SetInk.s b/lib/cpcrslib/cpc_SetInk.s
new file mode 100644
index 0000000..2c29464
--- /dev/null
+++ b/lib/cpcrslib/cpc_SetInk.s
@@ -0,0 +1,12 @@
+.globl _cpc_SetInk
+
+_cpc_SetInk::
+ LD HL,#2
+ ADD HL,SP
+ LD A,(HL)
+ INC HL
+
+ LD B,(HL)
+ LD C,B
+ JP 0XBC32
+
diff --git a/lib/cpcrslib/cpc_SetMode.s b/lib/cpcrslib/cpc_SetMode.s
new file mode 100644
index 0000000..f6877b4
--- /dev/null
+++ b/lib/cpcrslib/cpc_SetMode.s
@@ -0,0 +1,13 @@
+.globl _cpc_SetMode
+
+_cpc_SetMode::
+ ;ld a,l
+ LD HL,#2
+ ADD HL,SP
+ LD L,(HL) ; Comprobar que el valor vaya a L!!
+ LD BC,#0x7F00 ;Gate array port
+ LD D,#140 ;@10001100 ;Mode and rom selection (and Gate Array function)
+ ADD D
+ OUT (C),A
+ RET
+
diff --git a/lib/cpcrslib/cpc_SetModo.s b/lib/cpcrslib/cpc_SetModo.s
new file mode 100644
index 0000000..8e96c3b
--- /dev/null
+++ b/lib/cpcrslib/cpc_SetModo.s
@@ -0,0 +1,9 @@
+.globl _cpc_SetModo
+
+_cpc_SetModo::
+ ;LD A,L
+ LD HL,#2
+ ADD HL,SP
+ LD a,(HL) ; COMPROBAR QUE EL VALOR VAYA A L!!
+ JP 0XBC0E
+
diff --git a/lib/cpcrslib/cpc_TileMap.s b/lib/cpcrslib/cpc_TileMap.s
new file mode 100644
index 0000000..501115b
--- /dev/null
+++ b/lib/cpcrslib/cpc_TileMap.s
@@ -0,0 +1,1332 @@
+PEEPHOLE = 0
+
+.include "TileMap.h"
+
+
+
+.globl _cpc_ResetTouchedTiles
+
+_cpc_ResetTouchedTiles::
+ LD HL,#_tiles_tocados
+ LD (HL),#0xFF
+ RET
+
+
+.globl _cpc_InitTileMap
+
+_cpc_InitTileMap::
+ LD HL,#0
+ LD (_tiles),HL
+ RET
+
+
+.globl _cpc_SetTile
+
+_cpc_SetTile::
+
+; ld ix,#2
+; add ix,sp
+
+; ld e,1 (ix)
+; ld a,0 (ix)
+
+ ld hl,#2
+ add hl,sp
+ ld a,(hl)
+ inc hl
+ ld e,(hl)
+ inc hl
+ ld c,(hl)
+
+ ;.include "multiplication2.asm"
+ ;LD H, #ancho_pantalla_bytes/2
+ ;LD L, #0
+ LD HL,#ancho_pantalla_bytes * 256 / 2
+ LD D, L
+ LD B, #8
+
+MULT: ADD HL, HL
+ JR NC, NOADD
+ ADD HL, DE
+NOADD: DJNZ MULT
+
+ ld e,a
+ ;ld d,#0 ; D ya es 0
+ add hl,de
+
+ ld de,#_pantalla_juego
+ add hl,de
+ ld (hl),c
+
+ ret
+
+
+
+
+; ******************************************************
+; ** Librería de rutinas para Amstrad CPC **
+; ** Raúl Simarro, Artaburu 2007 **
+; ******************************************************
+
+.globl _cpc_ShowTileMap ; para una pantalla de 64x160 bytes. Superbuffer 8192bytes
+
+
+
+_cpc_ShowTileMap::
+
+cont_normal:
+ xor a
+ ld (#contador_tiles),a
+;Se busca el número de tiles en pantalla
+ ld hl,(#ntiles)
+ ld (#contador_tiles2),hl
+ ld hl,#_pantalla_juego
+ call transferir_pantalla_a_superbuffer
+
+;parte donde se transfiere el superbuffer completo a la pantalla
+
+ ld de,#posicion_inicial_superbuffer
+ ld hl,#tiles_ocultos_ancho0*2
+ add hl,de ;primero posiciona en ancho
+
+ ; Posición inicial lectura datos superbuffer
+ ld de,#ancho_pantalla_bytes
+ ld b,#tiles_ocultos_alto0*8
+ XOR A
+ CP B
+ JR Z, NO_SUMA
+bucle_alto_visible:
+ add hl,de
+ djnz bucle_alto_visible
+NO_SUMA:
+ push hl
+ ld (#posicion_inicio_pantalla_visible_sb+1),HL
+
+
+;;.otro_ancho
+ ld b,#ancho_pantalla_bytes-4*(tiles_ocultos_ancho0) ;;nuevo ancho
+ ld c,#alto_pantalla_bytes-16*(tiles_ocultos_alto0) ;;nuevo alto
+
+
+;; a HL tb se le suma una cantidad
+ ld de, #tiles_ocultos_alto0*2
+ ld hl,#_posiciones_pantalla
+ add hl,de
+ ld e,(hl)
+ inc hl
+ ld d,(hl)
+ ld hl, #2*tiles_ocultos_ancho0
+ add hl,de
+ ld (#posicion_inicio_pantalla_visible+1),HL
+ ld (#posicion_inicio_pantalla_visible2+1),HL
+ pop de ;origen
+ ;HL destino
+ ;DE origen
+ ;call cpc_PutSpTM ;cambiar la rutina por una que dibuje desde superbuffer
+ ;ret
+ jp creascanes
+; A partir de la dirección del vector de bloques se dibuja el mapeado en pantalla
+
+
+transferir_pantalla_a_superbuffer:
+
+
+ PUSH HL
+ POP IX ;IX lleva los datos de la pantalla
+ LD DE,(#_posiciones_super_buffer)
+bucle_dibujado_fondo:
+ ;Leo en HL el tile a meter en el superbuffer
+ LD L,0 (IX)
+ LD H,#0
+ ADD HL,HL ;x2
+ ADD HL,HL ;x4
+ ADD HL,HL ;x8
+ ADD HL,HL ;x16
+ LD BC,#_tiles
+ ADD HL,BC ;hl apunta al tile a transferir
+ ;me falta conocer el destino. IY apunta al destino
+ EX DE,HL
+ PUSH HL
+ call transferir_map_sbuffer ;DE origen HL destino
+
+ ; Inicio Mod. 29.06.2009
+; Se cambia la forma de controlar el final de datos de tiles. El #0xFF ahora sí que se podrá utilizar.
+ ld HL,(#contador_tiles2)
+ dec HL
+ LD (#contador_tiles2),HL
+ LD A,H
+ OR L
+ ;ret z
+ jp z, ret2
+; Fin Mod. 29.06.2009
+ POP HL
+ INC IX ;Siguiente byte
+
+
+
+; LD A,(IX+0)
+; CP #0xFF ;El fin de los datos se marca con #0xFF, no hay un tile que sea #0xFF
+ ;RET Z
+ EX DE,HL
+ LD A,(#contador_tiles)
+ CP #ancho_pantalla_bytes/2-1 ;31 ;son 32 tiles de ancho
+ JP Z,incremento2
+ INC A
+ LD (#contador_tiles),A
+ INC DE
+ INC DE ;para pasar a la siguiente posición
+ ;si ya se va por el 18 el salto es mayor, es
+ JP bucle_dibujado_fondo
+
+incremento2:
+ XOR A
+ LD (#contador_tiles),A
+ LD BC, #7*ancho_pantalla_bytes+2 ;450 ; 64x7+2 48x7+2 1084 ;72x15+4
+ EX DE,HL
+ ADD HL,BC
+ EX DE,HL
+ JP bucle_dibujado_fondo
+
+contador_tiles: .DB 0
+contador_tiles2: .DW 0
+; Ahora se puede usar el tile 255
+ntiles: .DW ( alto_pantalla_bytes / 8 ) * ( ancho_pantalla_bytes / 2 )
+
+ret2:
+;Se busca el número de tiles en pantalla
+ ;ld hl,(ntiles)
+ ;ld (contador_tiles2),hl
+ pop hl
+ret
+
+
+transferir_map_sbuffer:
+
+ ld bc,#ancho_pantalla_bytes-1
+
+ .DB #0xfD
+ LD H,#8 ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+
+loop_alto_map_sbuffer:
+loop_ancho_map_sbuffer:
+ ld A,(DE)
+ ld (HL),A
+ inc de
+ inc hl
+ ld A,(DE)
+ ld (HL),A
+ inc de
+
+ .DB #0xfD
+ dec h
+ ret z
+;hay que sumar el ancho de la pantalla en bytes para pasar a la siguiente línea
+
+ add HL,BC
+ jp loop_alto_map_sbuffer
+
+
+.globl _cpc_PutSpTM
+
+_cpc_PutSpTM:: ; dibujar en pantalla el sprite
+
+;di
+ld a,b
+ld b,c
+ld c,a
+loop_alto_2_cpc_PutSpTM:
+ push bc
+ ld b,c
+ push hl
+loop_ancho_2_cpc_PutSpTM:
+ ld A,(DE)
+ ld (hl),a
+ inc de
+ inc hl
+ djnz loop_ancho_2_cpc_PutSpTM
+
+ ;incremento DE con el ancho de la pantalla-el del sprite
+ ex de,hl
+ancho_mostrable:
+ ld bc,#4*(tiles_ocultos_ancho0)
+ add hl,bc
+ ex de,hl
+ pop hl
+ ld A,H
+ add #0x08
+ ld H,A
+ sub #0xC0
+ jp nc,sig_linea_2_cpc_PutSpTM
+ ld bc,#0xc050
+ add HL,BC
+sig_linea_2_cpc_PutSpTM:
+ pop BC
+ djnz loop_alto_2_cpc_PutSpTM
+;ei
+ret
+
+
+
+
+
+.globl _cpc_ShowTileMap2
+
+_cpc_ShowTileMap2::
+ ld bc, #256*(ancho_pantalla_bytes-4*(tiles_ocultos_ancho0))+#alto_pantalla_bytes-16*(tiles_ocultos_alto0)
+
+posicion_inicio_pantalla_visible:
+ ld hl,#0000
+
+
+posicion_inicio_pantalla_visible_sb:
+ ld hl,#0000
+papa: ; código de Xilen Wars
+ di
+ ld (#auxsp),sp
+ ld sp,#tablascan
+ ld a,#alto_pantalla_bytes-16*(tiles_ocultos_alto0) ;16 alto
+ppv0:
+ pop de ; va recogiendo de la pila!!
+inicio_salto_ldi:
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+
+ ldi
+ ldi
+
+ ldi
+ ldi
+ ldi
+ ldi
+
+
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+ ldi
+CONT_salto_ldi:
+ ld de,#4*tiles_ocultos_ancho0
+ add hl,de
+
+CONT_salto_ldi1:
+ dec a
+ jp nz, ppv0
+ ld sp,(#auxsp)
+ ei
+ ret
+
+auxsp: .DW 0
+
+
+
+
+
+creascanes:
+ ld ix,#tablascan
+posicion_inicio_pantalla_visible2:
+ ld hl,#0000
+ ld b, #alto_pantalla_bytes/8-2*tiles_ocultos_alto0 ; 20 ; num de filas.
+cts0:
+ push bc
+ push hl
+ ld b,#8
+ ld de,#2048
+cts1:
+ ld 0 (ix),l
+ inc ix
+ ld 0 (ix),h
+ inc ix
+ add hl,de
+ djnz cts1
+ pop hl
+ ld bc,#80
+ add hl,bc
+ pop bc
+ djnz cts0
+; jp prepara_salto_ldi
+prepara_salto_ldi: ; para el ancho visible de la pantalla:
+ ld hl,#ancho_pantalla_bytes-4*tiles_ocultos_ancho0
+ ld de,#inicio_salto_ldi
+ add hl,hl
+ add hl,de
+ ld (hl),#0xc3
+ inc hl
+ ld de,#CONT_salto_ldi
+ ld (hl),e
+ inc hl
+ ld (hl),d
+ ret
+
+
+
+
+
+; MIRAR SUMA DE COORDENADAS PARA HACER SOLO UNA BUSQUEDA DE TILES
+.globl _cpc_PutSpTileMap
+
+_cpc_PutSpTileMap::
+
+.if PEEPHOLE-0
+ ex de,hl
+.else
+ ld hl,#2 ;3
+ add hl,sp ;3
+
+ ld e,(hl) ;2
+ inc hl ;1
+ ld d,(hl) ;2
+.endif
+
+
+
+;según las coordenadas x,y que tenga el sprite, se dibuja en el buffer
+
+; ld hl,#2 ;3
+; add hl,sp ;3
+; ld e,(hl) ;2
+; inc hl ;1
+; ld d,(hl) ;2
+
+ .db #0xdd
+ ld l,e ;2
+ .db #0xdd
+ ld h,d ;2
+ ; --> 15 NOPS
+
+ ;Obtencion de
+;dimensiones, solo usadas para calcular iteraciones -> BC
+ld l,0 (ix)
+ld h,1 (ix) ;dimensiones del sprite
+ld C,(hl) ;; ANCHO
+inc hl
+ld B,(hl) ;; ANCHO
+Dec b
+Dec c
+;->BC coord -1
+
+ ld l,10 (ix)
+ ld h,11 (ix) ;recoje coordenadas anteriores
+
+ ld e,8 (ix)
+ ld d,9 (ix)
+ ld 10 (ix),e
+ ld 11 (ix),d
+
+
+;Obtencion x0y0 -> HL
+PUSH HL
+Srl l ; x0/2
+Srl h
+Srl h
+Srl h ; y0/8
+Ex de,hl ;-> Guarda de con origen de loops
+
+POP hl ;(recuperar coord xoyo)
+Add hl,bc ;(Suma de dimensiones)
+Srl l ; (x0+ancho)/2
+Srl h
+Srl h
+Srl h; (y0+alto)/2
+
+xor a
+SBC hl,de ;diferencia entre bloque inicial y bloque con dimensiones
+
+;Hl tiene iteraciones en i,j partiendo de origen loops
+Ld a,h
+Inc a
+Ld (pasos_alto_xW+1),a
+Ld a,l
+Inc a
+;Ld (pasos_ancho_x+1),a
+
+;Loop from d, i veces
+;Loop from e, j veces
+jp macario
+.db 'r','a','u','l'
+macario:
+pasos_ancho_xW: ; *parametro
+ ld b,a
+bucle_pasos_anchoW:
+ push de
+pasos_alto_xW: ; *parametro
+ ld c,#0
+bucle_pasos_altoW:
+ ; Mete E y D
+ call _cpc_UpdTileTable
+ inc d
+ dec c
+ jp nz,bucle_pasos_altoW
+
+ pop de
+ inc e
+ dec b
+ jp nz,bucle_pasos_anchoW
+
+ ret
+
+
+
+
+.globl _cpc_UpdTileTable
+
+_cpc_UpdTileTable::
+; En DE word a comprobar (fila/columna o al revés)
+ LD HL,#_tiles_tocados
+ ;incorporo el tile en su sitio, guardo x e y
+bucle_recorrido_tiles_tocados:
+ LD A,(HL)
+ CP #0xFF
+ JP Z,incorporar_tile ;Solo se incorpora al llegar a un hueco
+; INC HL
+; PUSH HL
+; LD H,(HL)
+; LD L,A
+; SBC HL,DE
+; POP HL
+; RET Z
+; INC HL
+; JP bucle_recorrido_tiles_tocados
+ CP E
+ JP Z, comprobar_segundo_byte
+ INC HL
+ INC HL
+ JP bucle_recorrido_tiles_tocados
+comprobar_segundo_byte:
+ INC HL
+ LD A,(HL)
+ CP D
+ RET Z ;los dos bytes son iguales, es el mismo tile. No se añade
+ INC HL
+ JP bucle_recorrido_tiles_tocados
+
+
+
+incorporar_tile:
+ LD (HL),E
+ INC HL
+ LD (HL),D
+ INC HL
+ LD (HL),#0xFF ;End of data
+contkaka:
+ RET
+
+
+;_solo_tile0:
+;LD HL,#_tiles
+;jp _saltate
+
+.globl _cpc_UpdScr
+
+_cpc_UpdScr::
+;lee la tabla de tiles tocados y va restaurando cada uno en su sitio.
+ LD IX,#_tiles_tocados ;4
+bucle_cpc_UpdScr:
+ LD E, 0 (IX) ;5
+ LD A,#0xFF ;2
+ CP E ;1
+ RET Z ;RETORNA SI NO HAY MÁS DATOS EN LA LISTA ;2/4
+ LD D,1 (IX) ;5
+ INC IX ;3
+ INC IX ;3
+
+posicionar_superbuffer:
+;con la coordenada y nos situamos en la posición vertical y con x nos movemos a su sitio definitivo
+ LD C,D
+ SLA C ;x2
+ LD B,#0
+
+ ; puedo usar BC para el siguiente cálculo
+ push bc
+
+ LD HL,#_posiciones_super_buffer
+ ADD HL,BC
+ LD C,(HL)
+ INC HL
+ LD B,(HL)
+
+ LD L,E
+ SLA L
+ LD H,#0
+
+ ADD HL,BC
+
+ pop bc
+ ;HL apunta a la posición correspondiente en superbuffer
+ push hl
+
+posicionar_tile:
+
+ LD HL,#_tabla_y_ancho_pantalla
+ ADD HL,BC
+ LD C,(HL)
+ INC HL
+ LD B,(HL)
+ LD L,E
+ LD H,#0
+ ADD HL,BC
+; LD DE,#_pantalla_juego
+; ADD HL,DE
+ LD L,(HL)
+; xor a
+; cp l
+; jp z, _solo_tile0
+
+ LD H,#0
+
+ ADD HL,HL
+ ADD HL,HL
+ ADD HL,HL
+ ADD HL,HL ;X16
+ LD DE,#_tiles
+ ADD HL,DE
+ ;HL apunta a los datos del tile
+;_saltate:
+ ;ex de,hl
+ pop de ;hl
+ ;RET
+
+
+
+; de: Posición buffer
+; hl: datos tile
+
+
+transferir_map_sbuffer1: ;; ENVIA EL TILE AL SUPERBUFFER
+ ;ld bc,ancho_pantalla_bytes-2 ;63
+ ldi ;5
+ ldi ;de<-hl ;5
+ ex de,hl ;1
+ ld bc,#ancho_pantalla_bytes-2 ;3
+ ld a,c
+ add HL,BC ;3
+ ex de,hl ;1
+ ldi ;5
+ ldi ;5
+ ex de,hl ;1
+ ld c,a ;ld c,#ancho_pantalla_bytes-2 ;2
+ add HL,BC ;3
+ ex de,hl ;1
+ ldi
+ ldi
+ ex de,hl
+ ld c,a ;ld c,#ancho_pantalla_bytes-2
+ add HL,BC
+ ex de,hl
+ ldi
+ ldi
+ ex de,hl
+ ld c,a ;ld c,#ancho_pantalla_bytes-2
+ add HL,BC
+ ex de,hl
+ ldi
+ ldi
+ ex de,hl
+ ld c,a ;ld c,#ancho_pantalla_bytes-2
+ add HL,BC
+ ex de,hl
+ ldi
+ ldi
+ ex de,hl
+ ld c,a ;ld c,#ancho_pantalla_bytes-2
+ add HL,BC
+ ex de,hl
+ ldi
+ ldi
+ ex de,hl
+ ld c,a ;ld c,#ancho_pantalla_bytes-2
+ add HL,BC
+ ex de,hl
+ ldi
+ ldi
+jp bucle_cpc_UpdScr
+
+
+
+.globl _cpc_PutSpTileMap2b
+
+_cpc_PutSpTileMap2b::
+
+;según las coordenadas x,y que tenga el sprite, se dibuja en el buffer
+
+ ; ld ix,#2
+ ; add ix,sp
+
+
+ ; ld l,0 (ix)
+ ; ld h,1 (ix) ;HL apunta al sprite
+
+ ; push hl
+ ; pop ix
+
+
+ ld hl,#2 ;3
+ add hl,sp ;3
+ ld e,(hl) ;2
+ inc hl ;1
+ ld d,(hl) ;2
+
+ .db #0xdd
+ ld l,e ;2
+ .db #0xdd
+ ld h,d ;2
+ ; --> 15 NOPS
+
+
+
+ ;lo cambio para la rutina de multiplicar
+ ld a,8 (ix)
+ ld e,9 (ix)
+
+
+;include "multiplication1.asm"
+
+
+ ;ld h, #ancho_pantalla_bytes
+ ;LD L, #0
+ LD HL,#ancho_pantalla_bytes * 256
+ LD D, L
+ LD B, #8
+
+MULT2: ADD HL, HL
+ JR NC, NOADD2
+ ADD HL, DE
+NOADD2: DJNZ MULT2
+
+
+
+
+
+ ;ld b,#0
+ ld e,a
+ add hl,de
+ ld de,#posicion_inicial_superbuffer
+ add hl,de
+ ;hl apunta a la posición en buffer (destino)
+
+
+ ld 4 (ix),l ;update superbuffer address
+ ld 5 (ix),h
+
+
+ ld e,0 (ix)
+ ld d,1 (ix) ;HL apunta al sprite
+
+ ;con el alto del sprite hago las actualizaciones necesarias a la rutina
+ ld a,(de)
+ ld (#loop_alto_map_sbuffer2+2),a
+ ld b,a
+ ld a,#ancho_pantalla_bytes
+ sub b
+ ;ld (#ancho_22+1),a
+ ld c,a
+ inc de
+ ld a,(de)
+ inc de
+
+ ;ld a,16 ;necesito el alto del sprite
+
+
+
+sp_buffer_mask2:
+ ld b,#0
+ancho_22:
+ ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO
+
+ .db #0xDD
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ ;ld ixh,a
+loop_alto_map_sbuffer2:
+ .db #0xDD
+ LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ ;ld ixl,#4
+ ex de,hl
+loop_ancho_map_sbuffer2:
+
+
+ LD A,(hl) ;leo el byte del fondo
+ ;AND (HL) ;lo enmascaro
+ ;INC HL
+ ;OR (HL) ;lo enmascaro
+ LD (de),A ;actualizo el fondo
+ INC DE
+ INC HL
+
+
+ .db #0xDD
+ DEC L ;resta ancho
+ ;dec ixl
+ JP NZ,loop_ancho_map_sbuffer2
+
+ .db #0xDD
+ dec H
+ ;dec ixh
+ ret z
+ EX DE,HL
+;hay que sumar 72 bytes para pasar a la siguiente línea
+ add HL,BC
+ jp loop_alto_map_sbuffer2
+
+
+.globl _cpc_PutMaskSpTileMap2b
+
+_cpc_PutMaskSpTileMap2b::
+;según las coordenadas x,y que tenga el sprite, se dibuja en el buffer
+ .if PEEPHOLE-0
+ ex de,hl
+.else
+
+ ld hl,#2 ;3
+ add hl,sp ;3
+ ld e,(hl) ;2
+ inc hl ;1
+ ld d,(hl) ;2
+.endif
+
+
+; ld hl,#2 ;3
+; add hl,sp ;3
+; ld e,(hl) ;2
+; inc hl ;1
+; ld d,(hl) ;2
+
+ .db #0xdd
+ ld l,e ;2
+ .db #0xdd
+ ld h,d ;2
+ ; --> 15 NOPS
+
+
+ ld a,8 (ix)
+ ld e,9 (ix)
+
+;include "multiplication1.asm"
+ ;ld h, #ancho_pantalla_bytes
+ ;LD L, #0
+ LD HL,#ancho_pantalla_bytes * 256
+ LD D, L
+ LD B, #8
+
+MULT3: ADD HL, HL
+ JR NC, NOADD3
+ ADD HL, DE
+NOADD3: DJNZ MULT3
+
+
+
+ ;ld b,#0
+ ld e,a
+ add hl,de
+ ;HL=E*H+D
+
+
+
+
+
+ ld de,#posicion_inicial_superbuffer
+ add hl,de
+ ;hl apunta a la posición en buffer (destino)
+
+ ld 4 (ix),l ;update superbuffer address
+ ld 5 (ix),h
+
+ ld e,0 (ix)
+ ld d,1 (ix) ;HL apunta al sprite
+
+ ;con el alto del sprite hago las actualizaciones necesarias a la rutina
+ ld a,(de)
+ ld (#loop_alto_map_sbuffer3+2),a
+ ld b,a
+ ld a,#ancho_pantalla_bytes
+ sub b
+ ;ld (#ancho_23+1),a
+ ld c,a
+ inc de
+ ld a,(de)
+ inc de
+
+ ;ld a,16 ;necesito el alto del sprite
+
+
+
+sp_buffer_mask3:
+ ld b,#0
+ancho_23:
+ ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO
+
+ .db #0xdd
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ ;ld ixh,a
+loop_alto_map_sbuffer3:
+ .db #0xdd
+ LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ ;ld ixl,4
+ ex de,hl
+loop_ancho_map_sbuffer3:
+
+
+ LD A,(DE) ;leo el byte del fondo
+ AND (HL) ;lo enmascaro
+ INC HL
+ OR (HL) ;lo enmascaro
+ LD (DE),A ;actualizo el fondo
+ INC DE
+ INC HL
+
+ .db #0xdD
+ DEC L ;resta ancho
+ ;dec ixl
+ JP NZ,loop_ancho_map_sbuffer3
+
+ .db #0xdd
+ dec H
+ ;dec ixh
+ ret z
+ EX DE,HL
+;hay que sumar 72 bytes para pasar a la siguiente línea
+ add HL,BC
+ jp loop_alto_map_sbuffer3
+
+
+
+
+
+
+
+
+.globl _cpc_PutMaskInkSpTileMap2b
+
+_cpc_PutMaskInkSpTileMap2b::
+;según las coordenadas x,y que tenga el sprite, se dibuja en el buffer
+
+ ld hl,#2 ;3
+ add hl,sp ;3
+ ld e,(hl) ;2
+ inc hl ;1
+ ld d,(hl) ;2
+
+ .db #0xdd
+ ld l,e ;2
+ .db #0xdd
+ ld h,d ;2
+ ; --> 15 NOPS
+
+
+ ld a,8 (ix)
+ ld e,9 (ix)
+
+;include "multiplication1.asm"
+ ;ld h, #ancho_pantalla_bytes
+ ;LD L, #0
+ LD HL,#ancho_pantalla_bytes * 256
+ LD D, L
+ LD B, #8
+
+MULT7: ADD HL, HL
+ JR NC, NOADD7
+ ADD HL, DE
+NOADD7: DJNZ MULT7
+
+ ld e,a
+ add hl,de
+ ;HL=E*H+D
+
+ ld de,#posicion_inicial_superbuffer
+ add hl,de
+ ;hl apunta a la posición en buffer (destino)
+
+ ld 4 (ix),l ;update superbuffer address
+ ld 5 (ix),h
+
+ ld e,0 (ix)
+ ld d,1 (ix) ;HL apunta al sprite
+
+ ;con el ancho del sprite hago las actualizaciones necesarias a la rutina
+ ld a,(de)
+ ld (#loop_alto_map_sbuffer7+2),a
+ ld b,a
+ ld a,#ancho_pantalla_bytes
+ sub b
+ ;ld (#ancho_27+1),a
+ ld c,a
+ inc de
+ ld a,(de)
+ inc de
+
+
+sp_buffer_mask7:
+ ld b,#0
+ancho_27:
+ ;ld c,#ancho_pantalla_bytes-4 ;60 ;;DEPENDE DEL ANCHO
+
+ .db #0xdd
+ LD H,A ;ALTO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ ;ld ixh,a
+loop_alto_map_sbuffer7:
+ .db #0xdd
+ LD L,#4 ;ANCHO, SE PUEDE TRABAJAR CON HX DIRECTAMENTE
+ ;ld ixl,4
+ ex de,hl
+
+loop_ancho_map_sbuffer7:
+
+
+ LD A,(hl) ;leo el byte del fondo
+ or a
+ jp z, cont7
+
+ LD (DE),A ;actualizo el fondo
+cont7:
+ INC DE
+ INC HL
+
+ .db #0xdD
+ DEC L ;resta ancho
+ ;dec ixl
+ JP NZ,loop_ancho_map_sbuffer7
+
+ .db #0xdd
+ dec H
+ ;dec ixh
+ ret z
+ EX DE,HL
+;hay que sumar 72 bytes para pasar a la siguiente línea
+ add HL,BC
+ jp loop_alto_map_sbuffer7
+
+
+
+.globl _cpc_ScrollLeft00
+
+_cpc_ScrollLeft00::
+
+ ;se decrementa cada posiciones_pantalla
+ LD HL,#_posiciones_pantalla
+ ld b,#20
+ buc_suma1:
+ DEC (HL)
+ INC HL
+ INC HL
+ djnz buc_suma1
+
+ ld hl,(#posicion_inicio_pantalla_visible_sb+1)
+ inc HL
+ ld (#posicion_inicio_pantalla_visible_sb+1),HL
+
+ RET
+
+.globl _cpc_ScrollLeft01
+
+_cpc_ScrollLeft01::
+
+ ;se incrementa cada posiciones_pantalla
+ LD HL,#_posiciones_pantalla
+ ld b,#20
+ buc_suma14:
+ INC (HL)
+ INC HL
+ INC HL
+ djnz buc_suma14
+
+
+ ld hl,(#posicion_inicio_pantalla_visible_sb+1)
+ dec HL
+ ld (#posicion_inicio_pantalla_visible_sb+1),HL
+
+
+ ld hl,#_pantalla_juego+1
+ ld de,#_pantalla_juego
+ ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes/16 -1
+ LDIR
+
+ ld hl,#posicion_inicial_superbuffer+2
+ ld de,#posicion_inicial_superbuffer
+ ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes -1
+ LDIR
+
+ RET
+
+
+
+
+.globl _cpc_ScrollRight00
+
+_cpc_ScrollRight00:: ;;scrollea el area de pantalla de tiles
+
+ ;se decrementa cada posiciones_pantalla
+ LD HL,#_posiciones_pantalla
+ ld b,#20
+ buc_suma12:
+ INC (HL)
+ INC HL
+ INC HL
+ djnz buc_suma12
+
+
+ ld hl,(#posicion_inicio_pantalla_visible_sb+1)
+ dec HL
+ ld (#posicion_inicio_pantalla_visible_sb+1),HL
+
+ RET
+
+
+.globl _cpc_ScrollRight01
+
+_cpc_ScrollRight01:: ;;scrollea el area de pantalla de tiles
+
+ ;se incrementa cada posiciones_pantalla
+ LD HL,#_posiciones_pantalla
+ ld b,#20
+ buc_suma15:
+ DEC (HL)
+ INC HL
+ INC HL
+ djnz buc_suma15
+
+
+ ld hl,(#posicion_inicio_pantalla_visible_sb+1)
+ inc HL
+ ld (#posicion_inicio_pantalla_visible_sb+1),HL
+
+ ld hl,#_pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16-1
+ ld de,#_pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16
+ ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes/16 -1 ;-1
+ LDDR
+
+ ;;scrollea el superbuffer
+ ld hl,#posicion_inicial_superbuffer+alto_pantalla_bytes*ancho_pantalla_bytes-2 ; pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16-1
+ ld de,#posicion_inicial_superbuffer+alto_pantalla_bytes*ancho_pantalla_bytes ;pantalla_juego+alto_pantalla_bytes*ancho_pantalla_bytes/16
+ ld bc,#alto_pantalla_bytes*ancho_pantalla_bytes-1 ;-1
+ LDDR
+ RET
+
+.globl _cpc_SetTouchTileXY
+
+_cpc_SetTouchTileXY::
+
+ ;ld ix,#2
+ ;add ix,sp
+
+ ;ld d,1 (ix)
+ ;ld e,0 (ix)
+
+
+ ld hl,#2
+ add hl,sp
+ ld e,(hl)
+ inc hl
+ ld d,(hl)
+ inc hl
+ ld c,(hl)
+
+
+ ;ld d,e
+ ;ld e,c
+ call _cpc_UpdTileTable
+
+ ;ld e,1 (ix)
+ ;ld a,0 (ix)
+ ld a,e
+ ld e,d
+;include "multiplication2.asm"
+ ;ld h, #ancho_pantalla_bytes/2
+ ;LD L, #0
+ LD HL,#ancho_pantalla_bytes * 256 / 2
+ LD D, L
+ LD B, #8
+
+MULT4: ADD HL, HL
+ JR NC, NOADD4
+ ADD HL, DE
+NOADD4: DJNZ MULT4
+
+
+ ld e,a
+ ;ld d,#0
+ add hl,de
+ ld de,#_pantalla_juego
+ add hl,de
+ ;ld a,2 (ix)
+ ld (hl),c
+ ret
+
+
+.globl _cpc_ReadTile
+
+_cpc_ReadTile::
+
+
+; ld ix,#2
+; add ix,sp
+; ld e,1 (ix)
+; ld a,0 (ix)
+
+ ld hl,#2
+ add hl,sp
+ ld a,(hl)
+ inc hl
+ ld e,(hl)
+
+
+
+; ld hl,2
+; add hl,sp ; ¿Es la forma de pasar parámetros? ¿Se pasan en SP+2? ¿en la pila?
+; ld E,(hl) ;Y
+; inc hl
+; inc hl
+; ld a,(hl) ;X
+
+; include "multiplication2.asm"
+ ;ld h, #ancho_pantalla_bytes/2
+ ;LD L, #0
+ LD HL,#ancho_pantalla_bytes * 256 / 2
+ LD D, L
+ LD B, #8
+
+MULT5: ADD HL, HL
+ JR NC, NOADD5
+ ADD HL, DE
+NOADD5: DJNZ MULT5
+
+
+
+ ld e,a
+ ;ld d,#0
+ add hl,de ;SUMA X A LA DISTANCIA Y*ANCHO
+ ld de,#_pantalla_juego
+ add hl,de
+ ld l,(hl)
+ ld h,#0
+ ret
+
+
+.globl _cpc_SuperbufferAddress
+
+_cpc_SuperbufferAddress::
+; ld ix,#2
+; add ix,sp
+
+; ld l,0 (ix)
+; ld h,1 (ix) ;HL apunta al sprite
+
+; push hl
+; pop ix
+
+ ld hl,#2 ;3
+ add hl,sp ;3
+ ld e,(hl) ;2
+ inc hl ;1
+ ld d,(hl) ;2
+
+ .db #0xdd
+ ld l,e ;2
+ .db #0xdd
+ ld h,d ;2
+ ; --> 15 NOPS
+
+
+ ;lo cambio para la rutina de multiplicar
+ ld a,8 (ix)
+ ld e,9 (ix)
+; include "multiplication1.asm"
+ ;ld h, #ancho_pantalla_bytes
+ ;LD L, #0
+ LD HL,#ancho_pantalla_bytes * 256
+ LD D, L
+ LD B, #8
+
+MULT6: ADD HL, HL
+ JR NC, NOADD6
+ ADD HL, DE
+NOADD6: DJNZ MULT6
+
+
+ ;ld b,#0
+ ld e,a
+ add hl,de
+ ld de,#posicion_inicial_superbuffer
+ add hl,de
+ ;hl apunta a la posición en buffer (destino)
+ ld 4 (ix),l
+ ld 5 (ix),h
+ ret
+
+
+
+tablascan: ;defs 20*16
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+.db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+
diff --git a/lib/cpcrslib/cpc_UnExoOpt.s b/lib/cpcrslib/cpc_UnExoOpt.s
new file mode 100644
index 0000000..14197cc
--- /dev/null
+++ b/lib/cpcrslib/cpc_UnExoOpt.s
@@ -0,0 +1,183 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl Simarro (Artaburu) - 2009, 2012 **
+; ******************************************************
+
+
+;*************************************
+; UNEXO
+;*************************************
+
+
+; Exomizer 2 Z80 decoder
+; by Metalbrain
+;
+; optimized by Antonio Villena
+;
+; compression algorithm by Magnus Lind
+
+;input: hl=compressed data start
+; de=uncompressed destination start
+;
+; you may change exo_mapbasebits to point to any free buffer
+
+
+.globl _cpc_UnExo
+
+_cpc_UnExo::
+
+; POP AF
+; POP HL ;DESTINATION ADDRESS
+; POP DE ;SPRITE DATA
+; PUSH AF
+
+ LD IX,#2
+ ADD IX,SP
+ LD e,2 (IX)
+ LD d,3 (IX) ;DESTINO
+ LD l,0 (IX)
+ LD h,1 (IX) ;TEXTO ORIGEN
+
+ di
+ call deexo
+ ei
+ ret
+
+deexo:
+ ld iy, #exo_mapbasebits
+ ld a,#128
+ ld b,#52
+ push de
+exo_initbits:
+ ex af,af'
+ ld a,b
+ sub #4
+ and #15
+ jr nz,exo_node1
+ ld de,#1 ;DE=b2
+exo_node1:
+ ld c,#16
+ ex af, af'
+exo_get4bits:
+ call exo_getbit
+ rl c
+ jr nc,exo_get4bits
+ ld (iy),c ;bits[i]=b1
+ push hl
+ ld hl,#1
+ .db #210 ;3 bytes nop (JP NC)
+exo_setbit:
+ add hl,hl
+ dec c
+ jr nz,exo_setbit
+ ld 52 (iy),e
+ ld 104 (iy),d ;base[i]=b2
+ add hl,de
+ ex de,hl
+ inc iy
+ pop hl
+ djnz exo_initbits
+ inc c
+exo_literalseq:
+ pop de
+exo_literalcopy:
+ ldir ;copy literal(s)
+exo_mainloop:
+ ld c,#1
+ call exo_getbit ;literal?
+ jr c,exo_literalcopy
+ ld c,#255
+exo_getindex:
+ inc c
+ call exo_getbit
+ jr nc,exo_getindex
+ bit 4,c
+ jr z,exo_continue
+ bit 0, c
+ ret z
+ push de
+ ld d,#16
+ call exo_getbits
+ jr exo_literalseq
+exo_continue:
+ push de
+ call exo_getpair
+ push bc
+ pop ix
+ ld de,#560 ;512+48 ;1?
+ inc b
+ djnz exo_dontgo
+ dec c
+ jr z, exo_goforit
+ dec c ;2?
+exo_dontgo:
+ ld de,#1056 ;1024+32
+ jr z,exo_goforit
+ ld e,#16
+exo_goforit:
+ call exo_getbits
+ ex af, af'
+ ld a,e
+ add a,c
+ ld c,a
+ ex af, af'
+ call exo_getpair ;bc=offset
+ pop de ;de=destination
+ push hl
+ ld h,d
+ ld l,e
+ sbc hl,bc ;hl=origin
+ push ix
+ pop bc ;bc=lenght
+ ldir
+ pop hl ;Keep HL, DE is updated
+ jr exo_mainloop ;Next!
+
+exo_getpair:
+ ld iy,#exo_mapbasebits
+ ld b,#0
+ add iy,bc
+ ld d,(iy)
+ call exo_getbits
+ push hl
+ ld l, 52 (iy)
+ ld h, 104 (iy)
+ add hl, bc ;Always clear C flag
+ ld b, h
+ ld c, l
+ pop hl
+ ret
+
+exo_getbits:
+ ld bc,#0 ;get D bits in BC
+exo_gettingbits:
+ dec d
+ ret m
+ call exo_getbit
+ rl c
+ rl b
+ jr exo_gettingbits
+
+exo_getbit:
+ add a, a ;get one bit
+ ret nz
+ ld a, (hl)
+ inc hl
+ adc a, a
+ ret
+
+exo_mapbasebits:
+ ;defs 156 ;tables for bits, baseL, baseH
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0
+ .db #0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0,#0 \ No newline at end of file
diff --git a/lib/cpcrslib/cpc_Uncrunch.s b/lib/cpcrslib/cpc_Uncrunch.s
new file mode 100644
index 0000000..7eba8c3
--- /dev/null
+++ b/lib/cpcrslib/cpc_Uncrunch.s
@@ -0,0 +1,308 @@
+; ******************************************************
+; ** Librería de rutinas SDCC para Amstrad CPC **
+; ** Raúl Simarro (Artaburu) - 2009, 2012 **
+; ******************************************************
+
+
+;*************************************
+; UNCRUNCH
+;*************************************
+
+
+.globl _cpc_Uncrunch
+
+_cpc_Uncrunch::
+; datos necesarios que vienen en la pila:
+; ORIGEN HL
+; DESTINO DE
+
+ ;Ojo, para que el pucrunch funcione hay que coger y quitar el salto de las interrupciones.
+ DI
+ LD HL,(#0X0038)
+ LD (#datos_int),HL
+
+ LD HL,#0X00C9
+ LD (#0x0038),HL
+ EI
+
+;POP AF
+;POP HL
+;POP DE
+;PUSH AF
+ LD IX,#2
+ ADD IX,SP
+ LD e,2 (IX)
+ LD d,3 (IX) ;DESTINO
+ LD l,0 (IX)
+ LD h,1 (IX) ;TEXTO ORIGEN
+
+
+pucrunch:
+ PUSH DE ; destination pointer to 2nd register
+ EXX ; set
+ POP DE
+
+
+ PUSH HL
+ PUSH DE
+ PUSH BC
+ PUSH AF
+
+ EXX
+
+ ; read the header self-modifying the
+ ; parameters straight into the code
+ ; skip useless data
+
+
+ LD BC,#6
+ ADD HL,BC
+
+ LD A, (HL) ; starting escape
+ INC HL
+ LD (#esc+1), A
+
+ INC HL ; skip useless data
+ INC HL
+
+ LD A, (HL) ; number of escape bits
+ INC HL
+ LD (#escb0+1), A
+ LD (#escb1+1), A
+
+ LD B, A ; 8 - escape bits
+ LD A, #8
+ SUB B
+ LD (#noesc+1), A
+
+ LD A, (HL) ; maxGamma + 1
+ INC HL
+ LD (#mg+1), A
+
+ LD B, A ; 8 - maxGamma
+ LD A, #9
+ SUB B
+ LD (#longrle+1), A
+
+ LD A, (HL) ; (1 << maxGamma)
+ INC HL
+ LD (#mg1+1), A
+
+ ADD A, A ; (2 << maxGamma) - 1
+ DEC A
+ LD (#mg21+1), A
+
+ LD A, (HL) ; extra lz77_0 position bits
+ INC HL
+ LD (#elzpb+1), A
+
+ INC HL ; skip useless data
+ INC HL
+
+ LD E, (HL) ; RLE table length
+ LD (#rlet+1), HL ; RLE table pointer
+ INC HL
+ LD D, #0
+ ADD HL, DE
+
+ LD C, #0X80 ; start decompression
+ JP loop_u
+
+newesc:
+ ld a, (#esc+1) ; save old escape code
+ ld d, a
+
+escb0:
+ LD B, #2 ; ** parameter
+ XOR A ; get new escape code
+ CALL get_bits
+ LD (#esc+1), A
+
+ LD A, D
+
+noesc:
+ LD B, #6 ; ** parameter
+ CALL get_bits ; get more bits to complete a byte
+
+ EXX ; output the byte
+ LD (DE), A
+ INC DE
+ EXX
+
+loop_u:
+ XOR A
+escb1:
+ LD B, #2 ; ** parameter
+ CALL get_bits ; get escape code
+esc:
+ CP #0 ; ** PARAMETER
+ JP NZ, noesc
+
+ CALL get_gamma ; get length
+ EXX
+ LD B, #0
+ LD C, A
+ EXX
+
+ CP #1
+ JP NZ, lz77_0 ; lz77_0
+
+ XOR A
+ CALL get_bit
+ JP NC, lz77_0_2 ; 2-byte lz77_0
+
+ CALL get_bit
+ JP NC, newesc ; escaped literal byte
+
+ CALL get_gamma ; get length
+ EXX
+ LD B, #1
+ LD C, A
+ EXX
+
+mg1:
+ CP #64 ; ** parameter
+ JP C, chrcode ; short RLE, get bytecode
+
+longrle:
+ LD B, #2 ; ** parameter
+ CALL get_bits ; complete length LSB
+ EX AF, AF'
+
+ CALL get_gamma ; length MSB
+ EXX
+ LD B, A
+ EX AF, AF'
+ LD C, A
+ EXX
+
+chrcode:
+ CALL get_gamma ; get byte to repeat
+
+ PUSH HL
+rlet:
+ LD HL, #0X0000 ; ** parameter
+ LD D, #0
+ LD E, A
+ ADD HL, DE
+
+ CP #32
+ LD A, (HL)
+ POP HL
+ JP C, dorle
+
+ LD A, E ; get 3 more bits to complete the
+ LD B, #3 ; byte
+ CALL get_bits
+
+dorle:
+ EXX ; output the byte n times
+ INC C
+dorlei:
+ LD (DE), A
+ INC DE
+ DEC C
+ JP NZ, dorlei
+ DEC B
+ JP NZ, dorlei
+ EXX
+ JP loop_u
+
+lz77_0:
+ CALL get_gamma ; offset MSB
+mg21:
+ CP #127 ; ** parameter
+
+ ; ret z
+
+ JP Z, fin ; EOF, return
+
+ DEC A ; (1...126 -> 0...125)
+elzpb:
+ LD B, #0 ; ** parameter
+ CALL get_bits ; complete offset MSB
+
+lz77_0_2:
+ EX AF, AF'
+ LD B, #8 ; offset LSB
+ CALL get_bits
+ CPL ; xor'ed by the compressor
+
+ EXX ; combine them into offset
+ LD L, A
+ EX AF, AF'
+ LD H, A
+ INC HL
+
+ XOR A ; CF = 0
+
+ PUSH DE ; (current output position) - (offset)
+ EX DE, HL
+ SBC HL, DE
+ POP DE
+
+ INC BC
+
+ LDIR ; copy
+ EXX
+ JP loop_u
+
+;## Get a bit from the source stream.
+;## Return CF = result
+get_bit:
+ SLA C ; shift next bit into CF
+ RET NZ
+ LD C, (HL) ; get next byte
+ INC HL ; increase source stream pointer
+ RL C ; shift next bit into CF, bit0 = 1
+ RET
+
+;## Get multiple bits from the source stream.
+;## In B = number of bits to get
+;## Return A = result
+get_bits:
+ DEC B
+ RET M
+ SLA C ; shift next bit into CF
+ JP NZ, gb1
+ LD C, (HL) ; get next byte
+ INC HL ; increase source stream pointer
+ RL C ; shift next bit into CF, bit0 = 1
+gb1:
+ RLA ; rotate next bit into A
+ JP get_bits
+
+;## Get an Elias Gamma coded value from the source stream.
+;## Return A = result
+get_gamma:
+ LD B, #1
+mg:
+ LD A, #7 ; ** parameter
+gg1:
+ CALL get_bit ; get bits until 0-bit or max
+ JR NC, gg2
+ INC B
+ CP B
+ JP NZ, gg1
+gg2:
+ LD A, #1 ; GET THE ACTUAL VALUE
+ DEC B
+ JP get_bits
+
+fin:
+ ; Restauramos los registros dobles y vuelta limpia
+ EXX
+ POP AF
+ POP BC
+ POP DE
+ POP HL
+ EXX
+
+ ;RET
+ DI
+ LD HL,(#datos_int)
+ LD (#0X0038),HL ;RESTAURO LA INTERRUPCIÓN ORIGINAL
+ EI
+ RET
+datos_int:
+ .DW #0 \ No newline at end of file
diff --git a/lib/cpcrslib/cpcrslib.h b/lib/cpcrslib/cpcrslib.h
new file mode 100644
index 0000000..91bee0d
--- /dev/null
+++ b/lib/cpcrslib/cpcrslib.h
@@ -0,0 +1,116 @@
+
+#ifndef __cpcrslib_h__
+#define __cpcrslib_h__
+
+
+
+
+
+
+
+void cpc_UnExo(char *origen, int destino);
+void cpc_Uncrunch(char *origen, int destino);
+
+
+void cpc_SetMode( char color);
+void cpc_SetModo( char x);
+void cpc_SetColour(unsigned char num, char color);
+void cpc_SetInk(unsigned char num, unsigned char color);
+void cpc_SetBorder( char color);
+unsigned char cpc_Random(void);
+
+void cpc_ClrScr(void);
+
+void cpc_PutSprite(char *sprite, int posicion);
+void cpc_PutSp(char *sprite, char height, char width, int address);
+void cpc_PutSp4x14(char *sprite, int address);
+void cpc_PutSpriteXOR(char *sprite, int posicion);
+void cpc_PutSpXOR(char *sprite, char height, char width, int address);
+void cpc_PutSpriteTr(char *sprite, int *posicion);
+void cpc_PutSpTr(char *sprite, char height, char width, int address);
+void cpc_GetSp(char *sprite, char alto, char ancho, int posicion);
+void cpc_PutMaskSprite(char *sprite,unsigned int addr);
+//void cpc_PutMaskSprite(struct sprite *spr,unsigned int *addr);
+void cpc_PutMaskSp(char *sprite, char alto, char ancho, int posicion);
+void cpc_PutMaskSp4x16(char *sprite,unsigned int addr);
+void cpc_PutMaskSp2x8(char *sprite,unsigned int addr);
+
+
+unsigned char cpc_CollSp(char *sprite, char *sprite2);
+
+
+// TILE MAP:
+void cpc_InitTileMap(void);
+void cpc_SetTile(unsigned char x, unsigned char y, unsigned char b);
+void cpc_ShowTileMap();
+void cpc_ShowTileMap2(void);
+void cpc_ResetTouchedTiles(void);
+
+void cpc_PutSpTileMap(char *sprite);
+void cpc_PutSpTileMapF(char *sprite);
+void cpc_UpdScr(void);
+void cpc_PutSpTileMap2b(char *sprite);
+void cpc_PutMaskSpTileMap2b(char *sprite);
+void cpc_PutMaskInkSpTileMap2b(char *sprite);
+void cpc_PutTrSpTileMap2b(char *sprite);
+void cpc_PutTrSpriteTileMap2b(char *sprite);
+
+
+void cpc_SpUpdY(char *sprite, char valor);
+void cpc_SpUpdX(char *sprite, char valor);
+
+void cpc_ScrollRight00(void);
+void cpc_ScrollRight01(void);
+void cpc_ScrollLeft00(void);
+void cpc_ScrollLeft01(void);
+void cpc_ScrollRight(void);
+void cpc_ScrollLeft(void);
+
+void cpc_SetTouchTileXY(unsigned char x, unsigned char y, unsigned char t);
+unsigned char cpc_ReadTile(unsigned char x, unsigned char y);
+void cpc_SuperbufferAddress(char *sprite);
+
+// ****************
+
+
+
+
+
+
+void cpc_RRI(unsigned int pos, unsigned char w, unsigned char h);
+void cpc_RLI(unsigned int pos, unsigned char w, unsigned char h);
+
+
+int cpc_AnyKeyPressed(void);
+void cpc_ScanKeyboard(void);
+char cpc_TestKeyF(char number);
+void cpc_DeleteKeys(void);
+void cpc_AssignKey(unsigned char tecla, int valor);
+unsigned char cpc_TestKey(unsigned char tecla);
+void cpc_RedefineKey(unsigned char tecla);
+
+int cpc_GetScrAddress(char x, char y);
+
+void cpc_PrintStr(char *text);
+
+void cpc_EnableFirmware(void);
+void cpc_DisableFirmware(void);
+
+void cpc_SetFont(unsigned char first_char, unsigned char *font_def);
+
+void cpc_PrintGphStr(char *text, int destino);
+void cpc_PrintGphStrM1(char *text, int destino);
+void cpc_PrintGphStr2X(char *text, int destino);
+void cpc_PrintGphStrM12X(char *text, int destino);
+
+void cpc_PrintGphStrXY(char *text, unsigned char a, unsigned char b);
+void cpc_PrintGphStrXYM1(char *text, unsigned char a, unsigned char b);
+void cpc_PrintGphStrXY2X(char *text, unsigned char a, unsigned char b);
+void cpc_PrintGphStrXYM12X(char *text, unsigned char a, unsigned char b);
+void cpc_SetInkGphStr(unsigned char a, unsigned char b);
+void cpc_SetInkGphStrM1(unsigned char a, unsigned char b);
+
+void cpc_PrintGphStrStd(char color, char *cadena, int destino);
+void cpc_PrintGphStrStdXY(char color, char *cadena, char x, char y);
+
+#endif /* __cpcrslib_h__ */
diff --git a/lib/cpcrslib/cpcwyzlib.h b/lib/cpcrslib/cpcwyzlib.h
new file mode 100644
index 0000000..b0c04c4
--- /dev/null
+++ b/lib/cpcrslib/cpcwyzlib.h
@@ -0,0 +1,18 @@
+
+#ifndef __cpcwyzlib_h__
+#define __cpcwyzlib_h__
+
+
+
+extern void cpc_WyzLoadSong(unsigned char numero);
+extern void cpc_WyzStartEffect(unsigned char canal, unsigned char efecto);
+//extern void cpc_WyzSetPlayerOn(void);
+// use WyzPlayerOn instead!
+extern void cpc_WyzSetPlayerOff(void);
+// WARNING: use WyzPlayerOff instead!
+extern void cpc_WyzConfigurePlayer(unsigned char valor);
+extern unsigned char cpc_WyzTestPlayer(void);
+extern void cpc_WyzInitPlayer(unsigned char *sonidos[], unsigned char *pautas[], unsigned char *efectos[], unsigned char *canciones[]);
+extern void cpc_WyzSetTempo(unsigned char tempo);
+
+#endif
diff --git a/lib/cpcrslib/make.bat b/lib/cpcrslib/make.bat
new file mode 100644
index 0000000..77a7e8c
--- /dev/null
+++ b/lib/cpcrslib/make.bat
@@ -0,0 +1,19 @@
+del *.rel
+del *.lib
+sdasz80 -o cpcrslib.s
+sdasz80 -o GphStr.s
+sdasz80 -o Sprites.s
+sdasz80 -o Keyboard.s
+sdasz80 -o UnExoOpt.s
+sdasz80 -o Uncrunch.s
+sdasz80 -o GphStrStd.s
+sdasz80 -o TileMap.s
+sdasz80 -o Wyz.s
+
+
+
+sdar rc cpcrslib.lib cpcrslib.rel GphStr.rel Sprites.rel Keyboard.rel UnExoOpt.rel Uncrunch.rel GphStrStd.rel TileMap.rel
+
+sdar rc cpcwyzlib.lib Wyz.rel
+copy cpcrslib.lib C:\sdcc\lib\z80
+copy cpcwyzlib.lib C:\sdcc\lib\z80
diff --git a/lib/plw.h b/lib/plw.h
new file mode 100644
index 0000000..5d01172
--- /dev/null
+++ b/lib/plw.h
@@ -0,0 +1,19 @@
+#ifndef __PLW_H
+#define __PLW_H
+
+#include <stdint.h>
+
+void PLW_Init(uint8_t *song, uint8_t sub_song);
+void PLW_Play();
+void PLW_Stop();
+
+void PLW_InitSoundEffects(uint8_t *effects) __z88dk_fastcall;
+void PLW_PlaySoundEffect(uint8_t effect_no, uint8_t chan, uint8_t inv_vol);
+uint8_t PLW_IsSoundEffectOn(uint8_t chan) __z88dk_fastcall;
+
+// play sound effect with priority
+void PLW_PlaySoundEffectP(uint8_t efx_no) __z88dk_fastcall;
+
+#define EFX_CHANNEL 2
+
+#endif // __PLW_H
diff --git a/lib/plw/Makefile b/lib/plw/Makefile
new file mode 100644
index 0000000..ff6e632
--- /dev/null
+++ b/lib/plw/Makefile
@@ -0,0 +1,34 @@
+LIB=plw.lib
+
+all: $(LIB)
+
+CC=sdcc
+AS=sdasz80
+AR=sdar
+CFLAGS=-mz80 --Werror --fsigned-char --std-sdcc99 --opt-code-speed
+LDFLAGS=--no-std-crt0 --fomit-frame-pointer
+
+lib_SRCS=$(wildcard *.z80)
+lib_OBJS=$(patsubst %.z80,%.rel,$(lib_SRCS))
+
+$(LIB): $(lib_OBJS) plw_player.rel
+ $(AR) -rcD $(LIB) $(lib_OBJS)
+ cp $(LIB) ..
+ cp plw_player.rel ../
+
+plw_player.rel: plw_player.c player/plw_player.h
+
+player/plw_player.h:
+ make -C player
+
+%.rel: %.z80
+ $(AS) -o $<
+
+%.rel: %.c
+ $(CC) $(CFLAGS) $(LDFLAGS) -c $<
+
+.PHONY: clean
+clean:
+ make -C player clean
+ rm -f *.bin *.rel *.lk *.noi *.map *.ihx *.sym *.lst *.zx7 player.asm $(LIB)
+
diff --git a/lib/plw/README.md b/lib/plw/README.md
new file mode 100644
index 0000000..174ae56
--- /dev/null
+++ b/lib/plw/README.md
@@ -0,0 +1,16 @@
+This is Arkos 2 lightweight player.
+
+It comes with two components:
+
+ - A .rel module to load in 0x0b06 (just after the CRT0)
+ - A library with the functions to call the module
+
+This is so the player can be assembled by rasm and still use SDCC linker.
+
+IMPORTANT: if your CRT0 changes its size, you'll have to change the loading
+address and the entry point for all the functions.
+
+For licensing information, PLW is just a wrapper that can be distributed
+under the same license as Arkos Player 2 AKW player.
+
+Code by Juan J. Martinez <jjm@usebox.net>
diff --git a/lib/plw/player/Makefile b/lib/plw/player/Makefile
new file mode 100644
index 0000000..53e0b23
--- /dev/null
+++ b/lib/plw/player/Makefile
@@ -0,0 +1,11 @@
+SOURCES=$(wildcard *.asm)
+
+all: plw_player.h
+
+plw_player.h: $(SOURCES)
+ rasm player.asm -ob plw_player.bin
+ bin2h.py plw_player.bin plw_player > plw_player.h
+
+.PHONY: clean all
+clean:
+ rm -f *.bin plw_player.h
diff --git a/lib/plw/player/PlayerLightWeight.asm b/lib/plw/player/PlayerLightWeight.asm
new file mode 100644
index 0000000..5da830c
--- /dev/null
+++ b/lib/plw/player/PlayerLightWeight.asm
@@ -0,0 +1,1694 @@
+; Arkos Tracker 2 Lightweight player (format V1 (used by AT2 since alpha4)).
+
+; ** This player has been superseded by the AKM format, more compact but also more powerful. Please use it instead. **
+
+; This compiles with RASM. Check the compatibility page on the Arkos Tracker 2 website, it contains a source converter to any Z80 assembler!
+
+; This is a generic player, but much simpler and using only the most used features, so that the music and players are both
+; lightweight. The player supports sound effects.
+
+; Though the player is optimized in speed, it is much slower than the generic one or the AKY player.
+; With effects used at the same time, it may reach 35 scanlines on a CPC, plus some few more if you are using sound effects.
+
+; The player uses the stack for optimizations. Make sure the interruptions are disabled before it is called.
+; The stack pointer is saved at the beginning and restored at the end.
+
+; Target harware:
+; ---------------
+; This code can target Amstrad CPC, MSX, Spectrum and Pentagon. By default, it targets Amstrad CPC.
+; Simply use one of the follow line (BEFORE this player):
+; PLY_LW_HARDWARE_CPC = 1
+; PLY_LW_HARDWARE_MSX = 1
+; PLY_LW_HARDWARE_SPECTRUM = 1
+; PLY_LW_HARDWARE_PENTAGON = 1
+; Note that the PRESENCE of this variable is tested, NOT its value.
+;
+; Some severe optimizations of CPU/memory can be performed:
+; ---------------------------------------------------------
+; - Use the Player Configuration of Arkos Tracker 2 to generate a configuration file to be included at the beginning of this player.
+; It will disable useless features according to your songs! Check the manual for more details, or more simply the testers.
+;
+; Sound effects:
+; --------------
+; Sound effects are disabled by default. Declare PLY_LW_MANAGE_SOUND_EFFECTS to enable it:
+; PLY_LW_MANAGE_SOUND_EFFECTS = 1
+; Check the sound effect tester to see how it enables it.
+; Note that the PRESENCE of this variable is tested, NOT its value.
+;
+; ROM
+; ----------------------
+; No ROM player is available for this player. I suggest you try the AKM player, which is more powerful and more compact (albeit a bit slower).
+;
+; -------------------------------------------------------
+
+PLY_LW_Start:
+
+ ;Checks the hardware. Only one must be selected.
+PLY_LW_HardwareCounter = 0
+ IFDEF PLY_LW_HARDWARE_CPC
+ PLY_LW_HardwareCounter = PLY_LW_HardwareCounter + 1
+ ENDIF
+ IFDEF PLY_LW_HARDWARE_MSX
+ PLY_LW_HardwareCounter = PLY_LW_HardwareCounter + 1
+ PLY_LW_HARDWARE_SPECTRUM_OR_MSX = 1
+ ENDIF
+ IFDEF PLY_LW_HARDWARE_SPECTRUM
+ PLY_LW_HardwareCounter = PLY_LW_HardwareCounter + 1
+ PLY_LW_HARDWARE_SPECTRUM_OR_PENTAGON = 1
+ PLY_LW_HARDWARE_SPECTRUM_OR_MSX = 1
+ ENDIF
+ IFDEF PLY_LW_HARDWARE_PENTAGON
+ PLY_LW_HardwareCounter = PLY_LW_HardwareCounter + 1
+ PLY_LW_HARDWARE_SPECTRUM_OR_PENTAGON = 1
+ ENDIF
+ IF PLY_LW_HARDWARECounter > 1
+ FAIL 'Only one hardware must be selected!'
+ ENDIF
+ ;By default, selects the Amstrad CPC.
+ IF PLY_LW_HARDWARECounter == 0
+ PLY_LW_HARDWARE_CPC = 1
+ ENDIF
+
+;PLY_LW_USE_HOOKS: equ 1 ;Use hooks for external calls? 0 if the Init/Play methods are directly called, will save a few bytes.
+;PLY_LW_STOP_SOUNDS: equ 1 ;1 to have the "stop sounds" code. Set it to 0 if you never plan on stopping your music.
+
+ ;Is there a loaded Player Configuration source? If no, use a default configuration.
+ IFNDEF PLY_CFG_ConfigurationIsPresent
+ PLY_CFG_UseTranspositions = 1
+ PLY_CFG_UseSpeedTracks = 1
+ PLY_CFG_UseEffects = 1
+ PLY_CFG_UseHardwareSounds = 1
+ PLY_CFG_NoSoftNoHard_Noise = 1
+ PLY_CFG_SoftOnly_Noise = 1
+ PLY_CFG_SoftOnly_SoftwareArpeggio = 1
+ PLY_CFG_SoftOnly_SoftwarePitch = 1
+ PLY_CFG_SoftToHard_SoftwarePitch = 1
+ PLY_CFG_SoftToHard_SoftwareArpeggio = 1
+ PLY_CFG_SoftAndHard_SoftwarePitch = 1
+ PLY_CFG_SoftAndHard_SoftwareArpeggio = 1
+ PLY_CFG_UseEffect_ArpeggioTable = 1
+ PLY_CFG_UseEffect_PitchTable = 1
+ PLY_CFG_UseEffect_PitchUp = 1
+ PLY_CFG_UseEffect_PitchDown = 1
+ PLY_CFG_UseEffect_SetVolume = 1
+ PLY_CFG_UseEffect_Reset = 1
+ ENDIF
+
+ ;Agglomerates some flags, because they are treated the same way by this player.
+ ;--------------------------------------------------
+ ;Creates a flag for pitch in instrument, and also pitch in hardware.
+ IFDEF PLY_CFG_SoftOnly_SoftwarePitch
+ PLY_LW_PitchInInstrument = 1
+ ENDIF
+ IFDEF PLY_CFG_SoftToHard_SoftwarePitch
+ PLY_LW_PitchInInstrument = 1
+ PLY_LW_PitchInHardwareInstrument = 1
+ ENDIF
+ IFDEF PLY_CFG_SoftAndHard_SoftwarePitch
+ PLY_LW_PitchInInstrument = 1
+ PLY_LW_PitchInHardwareInstrument = 1
+ ENDIF
+ ;A flag for Arpeggios in Instrument, both in software and hardware.
+ IFDEF PLY_CFG_SoftOnly_SoftwareArpeggio
+ PLY_LW_ArpeggioInSoftwareOrHardwareInstrument = 1
+ ENDIF
+ IFDEF PLY_CFG_SoftToHard_SoftwareArpeggio
+ PLY_LW_ArpeggioInSoftwareOrHardwareInstrument = 1
+ PLY_LW_ArpeggioInHardwareInstrument = 1
+ ENDIF
+ IFDEF PLY_CFG_SoftAndHard_SoftwareArpeggio
+ PLY_LW_ArpeggioInSoftwareOrHardwareInstrument = 1
+ PLY_LW_ArpeggioInHardwareInstrument = 1
+ ENDIF
+
+ ;A flag if noise is used (noise in hardware not tested, not present in this format).
+ IFDEF PLY_CFG_NoSoftNoHard_Noise
+ PLY_LW_USE_Noise = 1
+ ENDIF
+ IFDEF PLY_CFG_SoftOnly_Noise
+ PLY_LW_USE_Noise = 1
+ ENDIF
+ ;The noise is managed? Then the noise register access must be compiled.
+ IFDEF PLY_LW_USE_Noise
+ PLY_LW_USE_NoiseRegister = 1
+ ENDIF
+
+ ;Mixing Pitch up/down effects.
+ IFDEF PLY_CFG_UseEffect_PitchUp
+ PLY_LW_USE_EffectPitchUpDown = 1
+ ENDIF
+ IFDEF PLY_CFG_UseEffect_PitchDown
+ PLY_LW_USE_EffectPitchUpDown = 1
+ ENDIF
+ ;Volume and Pitch up/down dual effects (if one exists, the other one too).
+ IFDEF PLY_CFG_UseEffect_SetVolume
+ PLY_LW_USE_Volume_And_PitchUpDown_Effects = 1
+ PLY_LW_USE_EffectPitchUpDown = 1
+ ENDIF
+ IFDEF PLY_LW_USE_EffectPitchUpDown
+ PLY_LW_USE_Volume_And_PitchUpDown_Effects = 1
+ PLY_CFG_UseEffect_SetVolume = 1
+ ENDIF
+ ;Volume and Arpeggio Table dual effect (if one exists, the other one too).
+ IFDEF PLY_CFG_UseEffect_SetVolume
+ PLY_LW_USE_Volume_And_ArpeggioTable_Effects = 1
+ PLY_CFG_UseEffect_ArpeggioTable = 1
+ ENDIF
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable
+ PLY_LW_USE_Volume_And_ArpeggioTable_Effects = 1
+ PLY_CFG_UseEffect_SetVolume = 1
+ ENDIF
+ ;Reset and Arpeggio Table dual effect (if one exists, the other one too).
+ IFDEF PLY_CFG_UseEffect_Reset
+ PLY_LW_USE_Reset_And_ArpeggioTable_Effects = 1
+ PLY_CFG_UseEffect_ArpeggioTable = 1
+ ENDIF
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable
+ PLY_LW_USE_Reset_And_ArpeggioTable_Effects = 1
+ PLY_CFG_UseEffect_Reset = 1
+ ENDIF
+
+
+ ;Disark macro: Word region Start.
+ disarkCounter = 0
+ IFNDEF dkws
+ MACRO dkws
+PLY_LW_DisarkWordRegionStart_{disarkCounter}
+ ENDM
+ ENDIF
+ ;Disark macro: Word region End.
+ IFNDEF dkwe
+ MACRO dkwe
+PLY_LW_DisarkWordRegionEnd_{disarkCounter}:
+ disarkCounter = disarkCounter + 1
+ ENDM
+ ENDIF
+
+ ;Disark macro: Pointer region Start.
+ disarkCounter = 0
+ IFNDEF dkps
+ MACRO dkps
+PLY_LW_DisarkPointerRegionStart_{disarkCounter}
+ ENDM
+ ENDIF
+ ;Disark macro: Pointer region End.
+ IFNDEF dkpe
+ MACRO dkpe
+PLY_LW_DisarkPointerRegionEnd_{disarkCounter}:
+ disarkCounter = disarkCounter + 1
+ ENDM
+ ENDIF
+
+ ;Disark macro: Byte region Start.
+ disarkCounter = 0
+ IFNDEF dkbs
+ MACRO dkbs
+PLY_LW_DisarkByteRegionStart_{disarkCounter}
+ ENDM
+ ENDIF
+ ;Disark macro: Byte region End.
+ IFNDEF dkbe
+ MACRO dkbe
+PLY_LW_DisarkByteRegionEnd_{disarkCounter}:
+ disarkCounter = disarkCounter + 1
+ ENDM
+ ENDIF
+
+ ;Disark macro: Force "No Reference Area" for 3 bytes (ld hl,xxxx).
+ IFNDEF dknr3
+ MACRO dknr3
+PLY_LW_DisarkForceNonReferenceDuring3_{disarkCounter}:
+ disarkCounter = disarkCounter + 1
+ ENDM
+ ENDIF
+
+
+
+ ;Hooks for external calls. Can be removed if not needed.
+ if PLY_LW_USE_HOOKS
+ assert PLY_LW_Start == $ ;Makes sure no extra byte were inserted before the hooks.
+ jp PLY_LW_Init ;Player + 0.
+ jp PLY_LW_Play ;Player + 3.
+ if PLY_LW_STOP_SOUNDS
+ jp PLY_LW_Stop ;Player + 6.
+ endif
+ endif
+
+ ;Includes the sound effects player, if wanted. Important to do it as soon as possible, so that
+ ;its code can react to the Player Configuration and possibly alter it.
+ IFDEF PLY_LW_MANAGE_SOUND_EFFECTS
+ include "PlayerLightWeight_SoundEffects.asm"
+ ENDIF
+ ;[[INSERT_SOUND_EFFECT_SOURCE]] ;A tag for test units. Don't touch or you're dead.
+
+
+;Initializes the song. MUST be called before actually playing the song.
+;IN: HL = Address of the song.
+; A = Index of the subsong to play (>=0).
+PLY_LW_InitDisarkGenerateExternalLabel:
+PLY_LW_Init:
+ ;Reads the Song data.
+ ;Skips the tag and format number.
+dknr3: ld de,5
+ add hl,de
+
+ ;Reads the pointers to the various index tables.
+ ld de,PLY_LW_PtInstruments + 1
+ ldi
+ ldi
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC
+ ld de,PLY_LW_PtArpeggios + 1
+ ldi
+ ldi
+ ELSE
+ inc hl
+ inc hl
+ ENDIF ;PLY_CFG_UseEffect_ArpeggioTable
+ IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC
+ ld de,PLY_LW_PtPitches + 1
+ ldi
+ ldi
+ ELSE
+ inc hl
+ inc hl
+ ENDIF ;PLY_CFG_UseEffect_PitchTable
+ ELSE
+dknr3: ld de,4
+ add hl,de
+ ENDIF ;PLY_CFG_UseEffects
+
+ ;Finds the address of the Subsong.
+ ;HL points on the table, adds A * 2.
+ ;Possible optimization: possible to set the Subsong directly.
+ ld e,a
+ ld d,0
+ add hl,de
+ add hl,de
+ ld e,(hl)
+ inc hl
+ ld d,(hl)
+
+ ;Reads the header of the Subsong.
+ ld a,(de) ;Gets the speed.
+ inc de
+ ld (PLY_LW_Linker + 1),de
+ ld (PLY_LW_Speed + 1),a
+ ;Forces a new line.
+ dec a
+ ld (PLY_LW_TickCounter + 1),a
+
+ ;Can be removed if there is no need to reset the song.
+ xor a
+ ld (PLY_LW_PatternRemainingHeight + 1),a
+
+ ;A big LDIR to erase all the data blocks. Optimization: can be removed if there is no need to reset the song.
+ ld hl,PLY_LW_Track1_Data
+ ld de,PLY_LW_Track1_Data + 1
+dknr3: ld bc,PLY_LW_Track3_Data_End - PLY_LW_Track3_Data - 1
+ ld (hl),0
+ ldir
+
+ ;Reads the first instrument, the empty one, and set-ups the pointers to the instrument to read.
+ ;Optimization: needed if the song doesn't start with an instrument on all the channels. Else, it can be removed.
+ ld hl,(PLY_LW_PtInstruments + 1)
+ ld e,(hl)
+ inc hl
+ ld d,(hl)
+ inc de ;Skips the header.
+ ld (PLY_LW_Track1_PtInstrument),de
+ ld (PLY_LW_Track2_PtInstrument),de
+ ld (PLY_LW_Track3_PtInstrument),de
+ ret
+
+
+;Cuts the channels, stopping all sounds.
+ if PLY_LW_STOP_SOUNDS
+PLY_LW_StopDisarkGenerateExternalLabel:
+PLY_LW_Stop:
+ ld (PLY_LW_SaveSP + 1),sp
+
+ xor a
+ ld (PLY_LW_Track1_Volume),a
+ ld (PLY_LW_Track2_Volume),a
+ ld (PLY_LW_Track3_Volume),a
+ IFDEF PLY_LW_HARDWARE_MSX
+ ld a,%10111111 ;Bit 7/6 must be 10 on MSX!
+ ELSE
+ ld a,%00111111 ;On CPC, bit 6 must be 0! Other platforms don't care.
+ ENDIF
+ ld (PLY_LW_MixerRegister),a
+ jp PLY_LW_SendPsg
+ endif ;PLY_LW_STOP_SOUNDS
+
+;Plays one frame of the song. It MUST have been initialized before.
+;The stack is saved and restored, but is diverted, so watch out for the interruptions.
+PLY_LW_PlayDisarkGenerateExternalLabel:
+PLY_LW_Play:
+ ld (PLY_LW_SaveSP + 1),sp
+
+ ;Reads a new line?
+PLY_LW_TickCounter: ld a,0
+ inc a
+PLY_LW_Speed: cp 1 ;Speed (>0).
+ jp nz,PLY_LW_TickCounterManaged
+
+ ;A new line must be read. But have we reached the end of the Pattern?
+PLY_LW_PatternRemainingHeight: ld a,0 ;Height. If 0, end of the pattern.
+ sub 1
+ jr c,PLY_LW_Linker
+ ;Pattern not ended. No need to read the Linker.
+ ld (PLY_LW_PatternRemainingHeight + 1),a
+ jr PLY_LW_ReadLine
+
+ ;New pattern. Reads the Linker.
+dknr3:
+PLY_LW_Linker: ld hl,0
+PLY_LW_LinkerPostPt:
+ ;Resets the possible empty cell counter of each Track.
+ xor a
+ ld (PLY_LW_Track1_WaitEmptyCell),a
+ ld (PLY_LW_Track2_WaitEmptyCell),a
+ ld (PLY_LW_Track3_WaitEmptyCell),a
+
+ ;Reads the state byte of the pattern.
+ ld a,(hl)
+ inc hl
+ rra
+ jr c,PLY_LW_LinkerNotEndOfSongOk
+ ;End of song.
+ ld a,(hl) ;Reads where to loop in the Linker.
+ inc hl
+ ld h,(hl)
+ ld l,a
+ jr PLY_LW_LinkerPostPt
+
+PLY_LW_LinkerNotEndOfSongOk:
+ rra
+ ld b,a
+ IFDEF PLY_CFG_UseSpeedTracks ;CONFIG SPECIFIC
+ ;New speed?
+ jr nc,PLY_LW_LinkerAfterSpeed
+ ld a,(hl)
+ inc hl
+ ld (PLY_LW_Speed + 1),a
+PLY_LW_LinkerAfterSpeed:
+ ENDIF ;PLY_CFG_UseSpeedTracks
+
+ ;New height?
+ rr b
+ jr nc,PLY_LW_LinkerUsePreviousHeight
+ ld a,(hl)
+ inc hl
+ ld (PLY_LW_LinkerPreviousRemainingHeight + 1),a
+ jr PLY_LW_LinkerSetRemainingHeight
+ ;The same height is used. It was stored before.
+PLY_LW_LinkerUsePreviousHeight:
+PLY_LW_LinkerPreviousRemainingHeight: ld a,0
+PLY_LW_LinkerSetRemainingHeight:
+ ld (PLY_LW_PatternRemainingHeight + 1),a
+
+ ;New transpositions?
+ rr b
+ IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC
+ jr nc,PLY_LW_LinkerAfterNewTranspositions
+ ;New transpositions.
+ ld de,PLY_LW_Track1_Transposition
+ ldi
+ ld de,PLY_LW_Track2_Transposition
+ ldi
+ ld de,PLY_LW_Track3_Transposition
+ ldi
+PLY_LW_LinkerAfterNewTranspositions:
+ ENDIF ;PLY_CFG_UseTranspositions
+
+ ;Reads the 3 track pointers.
+ ld de,PLY_LW_Track1_PtTrack
+ ldi
+ ldi
+ ld de,PLY_LW_Track2_PtTrack
+ ldi
+ ldi
+ ld de,PLY_LW_Track3_PtTrack
+ ldi
+ ldi
+ ld (PLY_LW_Linker + 1),hl
+
+;Reads the Tracks.
+;---------------------------------
+PLY_LW_ReadLine:
+dknr3:
+PLY_LW_PtInstruments: ld de,0
+ exx
+ ld ix,PLY_LW_Track1_Data
+ call PLY_LW_ReadTrack
+ ld ix,PLY_LW_Track2_Data
+ call PLY_LW_ReadTrack
+ ld ix,PLY_LW_Track3_Data
+ call PLY_LW_ReadTrack
+
+ xor a
+PLY_LW_TickCounterManaged:
+ ld (PLY_LW_TickCounter + 1),a
+
+
+
+;Plays the sound stream.
+;---------------------------------
+ ld de,PLY_LW_PeriodTable
+ exx
+
+ ld c,%11100000 ;Register 7, shifted of 2 to the left. Bits 2 and 5 will be possibly changed by each iteration.
+
+ ld ix,PLY_LW_Track1_Data
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+ call PLY_LW_ManageEffects
+ ENDIF ;PLY_CFG_UseEffects
+ ld iy,PLY_LW_Track1_Registers
+ call PLY_LW_PlaySoundStream
+
+ srl c ;Not RR, because we have to make sure the b6 is 0, else no more keyboard (on CPC)!
+ ;Also, on MSX? bit 6 must be 0.
+ ld ix,PLY_LW_Track2_Data
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+ call PLY_LW_ManageEffects
+ ENDIF ;PLY_CFG_UseEffects
+ ld iy,PLY_LW_Track2_Registers
+ call PLY_LW_PlaySoundStream
+
+ IFDEF PLY_LW_HARDWARE_MSX
+ scf ;On MSX, bit 7 must be 1.
+ rr c
+ ELSE
+ rr c ;On other platforms, we don't care about b7.
+ ENDIF
+ ld ix,PLY_LW_Track3_Data
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+ call PLY_LW_ManageEffects
+ ENDIF ;PLY_CFG_UseEffects
+ ld iy,PLY_LW_Track3_Registers
+ call PLY_LW_PlaySoundStream
+
+ ld a,c
+
+;Plays the sound effects, if desired.
+;-------------------------------------------
+ IFDEF PLY_LW_MANAGE_SOUND_EFFECTS
+ call PLY_LW_PlaySoundEffectsStream
+ ELSE
+ ld (PLY_LW_MixerRegister),a
+ ENDIF ;PLY_LW_MANAGE_SOUND_EFFECTS
+
+
+
+;Sends the values to the PSG.
+;---------------------------------
+PLY_LW_SendPsg:
+ ld sp,PLY_LW_Registers_RetTable
+
+ IFDEF PLY_LW_HARDWARE_CPC
+dknr3: ld bc,#f680
+ ld a,#c0
+dknr3: ld de,#f4f6
+ out (c),a ;#f6c0 ;Madram's trick requires to start with this. out (c),b works, but will activate K7's relay! Not clean.
+ ENDIF
+
+ IFDEF PLY_LW_HARDWARE_SPECTRUM_OR_PENTAGON
+dknr3: ld de,#bfff
+dknr3: ld bc,#fffd
+ ENDIF
+
+PLY_LW_SendPsgRegister:
+ pop hl ;H = value, L = register.
+PLY_LW_SendPsgRegisterAfterPop:
+
+ IFDEF PLY_LW_HARDWARE_CPC
+ ld b,d
+ out (c),l ;#f400 + register.
+ ld b,e
+ out (c),0 ;#f600
+ ld b,d
+ out (c),h ;#f400 + value.
+ ld b,e
+ out (c),c ;#f680
+ out (c),a ;#f6c0
+ ENDIF
+
+ IFDEF PLY_LW_HARDWARE_SPECTRUM_OR_PENTAGON
+ out (c),l ;#fffd + register.
+ ld b,d
+ out (c),h ;#bffd + value
+ ld b,e
+ ENDIF
+
+ IFDEF PLY_LW_HARDWARE_MSX
+ ld a,l ;Register.
+ out (#a0),a
+ ld a,h ;Value.
+ out (#a1),a
+ ENDIF
+
+ ret
+
+ IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC
+PLY_LW_SendPsgRegisterR13:
+
+ ;Should the R13 be played? Yes only if different. No "force retrig" is managed by this player.
+PLY_LW_SetReg13: ld a,0
+PLY_LW_SetReg13Old: cp 0
+ jr z,PLY_LW_SendPsgRegisterEnd
+ ;Different. R13 must be played. Updates the old R13 value.
+ ld (PLY_LW_SetReg13Old + 1),a
+
+ ld h,a
+ ld l,13
+ IFDEF PLY_LW_HARDWARE_CPC
+ ld a,#c0
+ ENDIF
+ ret ;Sends the 13th registers.
+ ENDIF ;PLY_CFG_UseHardwareSounds
+
+PLY_LW_SendPsgRegisterEnd:
+
+dknr3:
+PLY_LW_SaveSP: ld sp,0
+ ret
+
+
+
+
+
+
+
+
+
+
+;Reads a Track.
+;IN: IX = Data block of the Track.
+; DE'= Instrument table. Do not modify!
+PLY_LW_ReadTrack:
+ ;Are there any empty lines to wait?
+ ld a,(ix + PLY_LW_Data_OffsetWaitEmptyCell)
+ sub 1
+ jr c,PLY_LW_RT_NoEmptyCell
+ ;Wait!
+ ld (ix + PLY_LW_Data_OffsetWaitEmptyCell),a
+ ret
+
+PLY_LW_RT_NoEmptyCell:
+ ;Reads the Track pointer.
+ ld l,(ix + PLY_LW_Data_OffsetPtTrack + 0)
+ ld h,(ix + PLY_LW_Data_OffsetPtTrack + 1)
+ ld a,(hl)
+ inc hl
+ ld b,a
+ and %111111 ;Keeps only the note.
+ sub 60
+ jr c,PLY_LW_RT_NoteMaybeEffect
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+ jr z,PLY_LW_RT_ReadEffect ;No note, but effect.
+ ENDIF ;PLY_CFG_UseEffects
+ dec a
+ jr z,PLY_LW_RT_WaitLong
+ dec a
+ jr z,PLY_LW_RT_WaitShort
+ ;63: Escape code for a note, because octave <2 or >5.
+ ;Reads the note.
+ ld a,(hl)
+ inc hl
+ ;The rest is exactly as the "note maybe effect", as B contains the flag to know about the possible
+ ;New Instrument and/or Effect?.
+ jr PLY_LW_RT_NMB_AfterOctaveCompensation
+
+PLY_LW_RT_NoteMaybeEffect:
+ ;A is the note from octave 2, and 60 to compensate the sub above.
+ ;Then adds the transposition.
+ add a,12 * 2 + 60
+PLY_LW_RT_NMB_AfterOctaveCompensation:
+ IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC
+ add a,(ix + PLY_LW_Data_OffsetTransposition)
+ ENDIF ;PLY_CFG_UseTranspositions
+ ld (ix + PLY_LW_Data_OffsetBaseNote),a
+
+ ;New Instrument?
+ rl b
+ jr c,PLY_LW_RT_NME_NewInstrument
+ ;Same Instrument. Retrieves the address previously stored.
+ ld a,(ix + PLY_LW_Data_OffsetPtBaseInstrument + 0)
+ ld (ix + PLY_LW_Data_OffsetPtInstrument + 0),a
+ ld a,(ix + PLY_LW_Data_OffsetPtBaseInstrument + 1)
+ ld (ix + PLY_LW_Data_OffsetPtInstrument + 1),a
+ jr PLY_LW_RT_NME_AfterInstrument
+
+PLY_LW_RT_NME_NewInstrument:
+ ;New Instrument, reads it.
+ ld a,(hl)
+ inc hl
+ exx
+ ;Gets the address of the Instrument.
+ ld l,a ;No need to *2, it is already encoded like that.
+ ld h,0
+ add hl,de ;Adds to the Instrument Table.
+ ld c,(hl)
+ inc hl
+ ld b,(hl)
+ ;Reads the header of the Instrument.
+ ld a,(bc) ;Speed.
+ ld (ix + PLY_LW_Data_OffsetInstrumentSpeed),a
+ inc bc
+ ;Stores the pointer on the data of the Instrument.
+ ld (ix + PLY_LW_Data_OffsetPtInstrument + 0),c
+ ld (ix + PLY_LW_Data_OffsetPtInstrument + 1),b
+ ld (ix + PLY_LW_Data_OffsetPtBaseInstrument + 0),c ;Useful to store the base Instrument address to retrieve it when
+ ld (ix + PLY_LW_Data_OffsetPtBaseInstrument + 1),b ;there is a new instrument, without providing its number (optimization).
+ exx
+PLY_LW_RT_NME_AfterInstrument:
+ ;Resets the step on the Instrument.
+ ld (ix + PLY_LW_Data_OffsetInstrumentCurrentStep),0
+
+ ;Resets the Track pitch.
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+ xor a
+ IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC
+ ld (ix + PLY_LW_Data_OffsetIsPitchUpDownUsed),a
+ ld (ix + PLY_LW_Data_OffsetTrackPitchInteger + 0),a
+ ld (ix + PLY_LW_Data_OffsetTrackPitchInteger + 1),a
+ ENDIF ;PLY_LW_USE_EffectPitchUpDown
+ ;ld (ix + PLY_LW_Data_OffsetTrackPitchDecimal),a ;Shouldn't be needed, the difference shouldn't be noticeable.
+ ;Resets the offset on Arpeggio and Pitch tables.
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC
+ ld (ix + PLY_LW_Data_OffsetPtArpeggioOffset),a
+ ENDIF ;PLY_CFG_UseEffect_ArpeggioTable
+ IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC
+ ld (ix + PLY_LW_Data_OffsetPtPitchOffset),a
+ ENDIF ;PLY_CFG_UseEffect_PitchTable
+
+ ENDIF ;PLY_CFG_UseEffects
+
+ ;Any effect? If no, stop.
+ rl b
+ jr nc,PLY_LW_RT_CellRead
+ ;Effect present.
+ ;jr PLY_LW_RT_ReadEffect
+
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+PLY_LW_RT_ReadEffect:
+ ;Reads effect number and possible data.
+ ld a,(hl)
+ inc hl
+ ld b,a
+ exx
+ rra
+ rra
+ rra
+ rra
+ and %1110
+ ld iy,PLY_LW_EffectTable
+ ld c,a
+ ld b,0
+ add iy,bc
+ exx
+ jp (iy)
+ ENDIF ;PLY_CFG_UseEffects
+
+PLY_LW_RT_WaitLong:
+ ;A 8-bit byte is encoded just after.
+ ld a,(hl)
+ inc hl
+ ld (ix + PLY_LW_Data_OffsetWaitEmptyCell),a
+ jr PLY_LW_RT_CellRead
+PLY_LW_RT_WaitShort:
+ ;Only a 2-bit value is encoded.
+ ld a,b
+ rla ;Transfers the bit 7/6 to 1/0.
+ rla
+ rla
+ and %11
+ ;inc a
+ ld (ix + PLY_LW_Data_OffsetWaitEmptyCell),a
+ ;jr PLY_LW_RT_CellRead
+;Jumped to after the Cell has been read.
+;IN: HL = new value of the Track pointer. Must point after the read Cell.
+PLY_LW_RT_CellRead:
+ ld (ix + PLY_LW_Data_OffsetPtTrack + 0),l
+ ld (ix + PLY_LW_Data_OffsetPtTrack + 1),h
+ ret
+
+
+;Manages the effects, if any. For the activated effects, modifies the internal data for the Track which data block is given.
+;IN: IX = data block of the Track.
+;OUT: IX, IY = unmodified.
+; C must NOT be modified!
+; DE' must NOT be modified!
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+PLY_LW_ManageEffects:
+ IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC
+ ;Pitch up/down used?
+ ld a,(ix + PLY_LW_Data_OffsetIsPitchUpDownUsed)
+ or a
+ jr z,PLY_LW_ME_PitchUpDownFinished
+
+ ;Adds the LSB of integer part and decimal part, using one 16 bits operation.
+ ld l,(ix + PLY_LW_Data_OffsetTrackPitchDecimal)
+ ld h,(ix + PLY_LW_Data_OffsetTrackPitchInteger + 0)
+
+ ld e,(ix + PLY_LW_Data_OffsetTrackPitchSpeed + 0)
+ ld d,(ix + PLY_LW_Data_OffsetTrackPitchSpeed + 1)
+
+ ld a,(ix + PLY_LW_Data_OffsetTrackPitchInteger + 1)
+
+ ;Negative pitch?
+ bit 7,d
+ jr nz,PLY_LW_ME_PitchUpDown_NegativeSpeed
+
+PLY_LW_ME_PitchUpDown_PositiveSpeed:
+ ;Positive speed. Adds it to the LSB of the integer part, and decimal part.
+ add hl,de
+
+ ;Carry? Transmits it to the MSB of the integer part.
+ adc 0
+ jr PLY_LW_ME_PitchUpDown_Save
+PLY_LW_ME_PitchUpDown_NegativeSpeed:
+ ;Negative speed. Resets the sign bit. The encoded pitch IS positive.
+ ;Subtracts it to the LSB of the integer part, and decimal part.
+ res 7,d
+
+ or a
+ sbc hl,de
+
+ ;Carry? Transmits it to the MSB of the integer part.
+ sbc 0
+
+PLY_LW_ME_PitchUpDown_Save:
+ ld (ix + PLY_LW_Data_OffsetTrackPitchInteger + 1),a
+
+ ld (ix + PLY_LW_Data_OffsetTrackPitchDecimal),l
+ ld (ix + PLY_LW_Data_OffsetTrackPitchInteger + 0),h
+
+PLY_LW_ME_PitchUpDownFinished:
+ ENDIF ;PLY_LW_USE_EffectPitchUpDown
+
+
+ ;Manages the Arpeggio Table effect, if any.
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC
+ ld a,(ix + PLY_LW_Data_OffsetIsArpeggioTableUsed)
+ or a
+ jr z,PLY_LW_ME_ArpeggioTableFinished
+ ;Reads the Arpeggio Table. Adds the Arpeggio base address to an offset.
+ ld e,(ix + PLY_LW_Data_OffsetPtArpeggioTable + 0)
+ ld d,(ix + PLY_LW_Data_OffsetPtArpeggioTable + 1)
+ ld l,(ix + PLY_LW_Data_OffsetPtArpeggioOffset)
+PLY_LW_ME_ArpeggioTableReadAgain: ld h,0
+ add hl,de
+ ld a,(hl)
+ ;End of the Arpeggio?
+ sra a
+ jr nc,PLY_LW_ME_ArpeggioTableEndNotReached
+ ;End of the Arpeggio. The loop offset is now in A.
+ ld l,a ;And read the next value!
+ ld (ix + PLY_LW_Data_OffsetPtArpeggioOffset),a
+ jr PLY_LW_ME_ArpeggioTableReadAgain
+
+PLY_LW_ME_ArpeggioTableEndNotReached:
+ ;Not the end. A = arpeggio note.
+ ld (ix + PLY_LW_Data_OffsetCurrentArpeggioValue),a
+ ;Increases the offset for next time.
+ inc (ix + PLY_LW_Data_OffsetPtArpeggioOffset)
+PLY_LW_ME_ArpeggioTableFinished:
+ ENDIF ;PLY_CFG_UseEffect_ArpeggioTable
+
+
+ ;Manages the Pitch Table effect, if any.
+ IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC
+ ld a,(ix + PLY_LW_Data_OffsetIsPitchTableUsed)
+ or a
+ ret z
+ ;Reads the Pitch Table. Adds the Pitch base address to an offset.
+ ld e,(ix + PLY_LW_Data_OffsetPtPitchTable + 0)
+ ld d,(ix + PLY_LW_Data_OffsetPtPitchTable + 1)
+ ld l,(ix + PLY_LW_Data_OffsetPtPitchOffset)
+PLY_LW_ME_PitchTableReadAgain: ld h,0
+ add hl,de
+ ld a,(hl)
+ ;End of the Pitch?
+ sra a
+ jr nc,PLY_LW_ME_PitchTableEndNotReached
+ ;End of the Pitch. The loop offset is now in A.
+ ld l,a ;And read the next value!
+ ld (ix + PLY_LW_Data_OffsetPtPitchOffset),a
+ jr PLY_LW_ME_PitchTableReadAgain
+
+PLY_LW_ME_PitchTableEndNotReached:
+ ;Not the end. A = pitch note. It is converted to 16 bits.
+ ld h,0
+ or a
+ jp p,PLY_LW_ME_PitchTableEndNotReached_Positive
+ dec h
+PLY_LW_ME_PitchTableEndNotReached_Positive:
+ ld (ix + PLY_LW_Data_OffsetCurrentPitchTableValue + 0),a
+ ld (ix + PLY_LW_Data_OffsetCurrentPitchTableValue + 1),h
+ ;Increases the offset for next time.
+ inc (ix + PLY_LW_Data_OffsetPtPitchOffset)
+ ENDIF ;PLY_CFG_UseEffect_PitchTable
+ ret
+
+ ENDIF ;PLY_CFG_UseEffects
+
+
+
+
+
+
+
+;---------------------------------------------------------------------
+;Sound stream.
+;---------------------------------------------------------------------
+
+;Plays the sound stream, filling the PSG registers table (but not playing it).
+;The Instrument pointer must be updated as it evolves inside the Instrument.
+;IN: IX = Data block of the Track.
+; IY = Points at the beginning of the register structure related to the channel.
+; C = R7. Only bit 2 (sound) must be *set* to cut the sound if needed, and bit 5 (noise) must be *reset* if there is noise.
+; DE' = Period table. Must not be modified.
+PLY_LW_PlaySoundStream:
+ ;Gets the pointer on the Instrument, from its base address and the offset.
+ ld l,(ix + PLY_LW_Data_OffsetPtInstrument + 0)
+ ld h,(ix + PLY_LW_Data_OffsetPtInstrument + 1)
+
+ ;Reads the first byte of the cell of the Instrument. What type?
+PLY_LW_PSS_ReadFirstByte:
+ ld a,(hl)
+ ld b,a
+ inc hl
+ rra
+ jr c,PLY_LW_PSS_SoftOrSoftAndHard
+
+ ;NoSoftNoHard or SoftwareToHardware
+ rra
+ IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC
+ jr c,PLY_LW_PSS_SoftwareToHardware
+ ENDIF ;PLY_CFG_UseHardwareSounds
+
+ ;No software no hardware, or end of sound (loop)!
+ ;End of sound?
+ rra
+ jr nc,PLY_LW_PSS_NSNH_NotEndOfSound
+ ;The sound loops/ends. Where?
+ ld a,(hl)
+ inc hl
+ ld h,(hl)
+ ld l,a
+ ;As a sound always has at least one cell, we should safely be able to read its bytes without storing the instrument pointer.
+ ;However, we do it anyway to remove the overhead of the Speed management: if looping, the same last line will be read,
+ ;if several channels do so, it will be costly. So...
+ ld (ix + PLY_LW_Data_OffsetPtInstrument + 0),l
+ ld (ix + PLY_LW_Data_OffsetPtInstrument + 1),h
+ jr PLY_LW_PSS_ReadFirstByte
+
+PLY_LW_PSS_NSNH_NotEndOfSound:
+ ;No software, no hardware.
+ ;-------------------------
+ ;Stops the sound.
+ set 2,c
+
+ ;Volume. A now contains the volume on b0-3.
+ call PLY_LW_PSS_Shared_AdjustVolume
+ ld (iy + PLY_LW_Registers_OffsetVolume),a
+
+ ;Read noise?
+ rl b
+ IFDEF PLY_CFG_NoSoftNoHard_Noise ;CONFIG SPECIFIC
+ call c,PLY_LW_PSS_ReadNoise
+ ENDIF ;PLY_CFG_NoSoftNoHard_Noise
+ jr PLY_LW_PSS_Shared_StoreInstrumentPointer
+
+ ;Software sound, or Software and Hardware?
+PLY_LW_PSS_SoftOrSoftAndHard:
+ rra
+ IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC
+ jr c,PLY_LW_PSS_SoftAndHard
+ ENDIF ;PLY_CFG_UseHardwareSounds
+
+ ;Software sound.
+ ;-----------------
+ ;A is the volume. Already shifted twice, so it can be used directly.
+ call PLY_LW_PSS_Shared_AdjustVolume
+ ld (iy + PLY_LW_Registers_OffsetVolume),a
+
+ ;Arp and/or noise?
+ ld d,0 ;Default arpeggio.
+ rl b
+ jr nc,PLY_LW_PSS_S_AfterArpAndOrNoise
+ ld a,(hl)
+ inc hl
+ ;Noise?
+ sra a
+ ;A is now the signed Arpeggio. It must be kept.
+ ld d,a
+ ;Now takes care of the noise, if there is a Carry.
+ IFDEF PLY_LW_USE_Noise ;CONFIG SPECIFIC
+ call c,PLY_LW_PSS_ReadNoise
+ ENDIF ;PLY_LW_USE_Noise
+PLY_LW_PSS_S_AfterArpAndOrNoise:
+
+ ld a,d ;Gets the instrument arpeggio, if any.
+ call PLY_LW_CalculatePeriodForBaseNote
+
+ ;Read pitch?
+ rl b
+ IFDEF PLY_CFG_SoftOnly_SoftwarePitch ;CONFIG SPECIFIC
+ call c,PLY_LW_ReadPitchAndAddToPeriod
+ ENDIF ;PLY_CFG_SoftOnly_SoftwarePitch
+
+ ;Stores the new period of this channel.
+ exx
+ ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodLSB),l
+ ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodMSB),h
+ exx
+
+ ;The code below is mutualized!
+ ;Stores the new instrument pointer, if Speed allows it.
+ ;--------------------------------------------------
+PLY_LW_PSS_Shared_StoreInstrumentPointer:
+ ;Checks the Instrument speed, and only stores the Instrument new pointer if the speed is reached.
+ ld a,(ix + PLY_LW_Data_OffsetInstrumentCurrentStep)
+ cp (ix + PLY_LW_Data_OffsetInstrumentSpeed)
+ jr z,PLY_LW_PSS_S_SpeedReached
+ ;Increases the current step.
+ inc (ix + PLY_LW_Data_OffsetInstrumentCurrentStep)
+ ret
+PLY_LW_PSS_S_SpeedReached:
+ ;Stores the Instrument new pointer, resets the speed counter.
+ ld (ix + PLY_LW_Data_OffsetPtInstrument + 0),l
+ ld (ix + PLY_LW_Data_OffsetPtInstrument + 1),h
+ ld (ix + PLY_LW_Data_OffsetInstrumentCurrentStep),0
+ ret
+
+
+ IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC
+
+ ;Software and Hardware.
+ ;----------------------------
+PLY_LW_PSS_SoftAndHard:
+ ;Reads the envelope bit, the possible pitch, and sets the software period accordingly.
+ call PLY_LW_PSS_Shared_ReadEnvBitPitchArp_SoftPeriod_HardVol_HardEnv
+ ;Reads the hardware period.
+ ld a,(hl)
+ ld (PLY_LW_Reg11),a
+ inc hl
+ ld a,(hl)
+ ld (PLY_LW_Reg12),a
+ inc hl
+
+ jr PLY_LW_PSS_Shared_StoreInstrumentPointer
+
+
+ ;Software to Hardware.
+ ;-------------------------
+PLY_LW_PSS_SoftwareToHardware:
+ call PLY_LW_PSS_Shared_ReadEnvBitPitchArp_SoftPeriod_HardVol_HardEnv
+
+ ;Now we can calculate the hardware period thanks to the ratio.
+ ld a,b
+ rra
+ rra
+ and %11100
+ ld (PLY_LW_PSS_STH_Jump + 1),a
+ exx
+PLY_LW_PSS_STH_Jump: jr $ + 2 ;Automodified by the line above to jump to the right place.
+ srl h
+ rr l
+ srl h
+ rr l
+ srl h
+ rr l
+ srl h
+ rr l
+ srl h
+ rr l
+ srl h
+ rr l
+ srl h
+ rr l
+ jr nc,PLY_LW_PSS_STH_RatioEnd
+ inc hl
+PLY_LW_PSS_STH_RatioEnd:
+ ld a,l
+ ld (PLY_LW_Reg11),a
+ ld a,h
+ ld (PLY_LW_Reg12),a
+ exx
+
+ jr PLY_LW_PSS_Shared_StoreInstrumentPointer
+
+;A shared code for hardware sound.
+;Reads the envelope bit in bit 1, arpeggio in bit 7 pitch in bit 2 from A. If pitch present, adds it to BC'.
+;Converts the note to period, adds the instrument pitch, sets the software period of the channel.
+;Also sets the hardware volume, and sets the hardware curve.
+PLY_LW_PSS_Shared_ReadEnvBitPitchArp_SoftPeriod_HardVol_HardEnv:
+ ;Envelope bit? R13 = 8 + 2 * (envelope bit?). Allows to have hardware envelope to 8 or 0xa.
+ ;Shifted by 2 to the right, bit 1 is now envelope bit, which is perfect for us.
+ and %10
+ add a,8
+ ld (PLY_LW_SetReg13 + 1),a
+
+ ;Volume to 16 to trigger the hardware envelope.
+ ld (iy + PLY_LW_Registers_OffsetVolume),16
+
+ ;Arpeggio?
+ xor a ;Default arpeggio.
+ IFDEF PLY_LW_ArpeggioInHardwareInstrument ;CONFIG SPECIFIC
+ bit 7,b ;Not shifted yet.
+ jr z,PLY_LW_PSS_Shared_REnvBAP_AfterArpeggio
+ ;Reads the Arpeggio.
+ ld a,(hl)
+ inc hl
+PLY_LW_PSS_Shared_REnvBAP_AfterArpeggio:
+ ENDIF ;PLY_LW_ArpeggioInHardwareInstrument
+ ;Calculates the software period.
+ call PLY_LW_CalculatePeriodForBaseNote
+
+ ;Pitch?
+ IFDEF PLY_LW_PitchInHardwareInstrument ;CONFIG SPECIFIC
+ bit 2,b ;Not shifted yet.
+ call nz,PLY_LW_ReadPitchAndAddToPeriod
+ ENDIF ;PLY_LW_PitchInHardwareInstrument
+
+ ;Stores the new period of this channel.
+ exx
+ ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodLSB),l
+ ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodMSB),h
+ exx
+ ret
+
+ ENDIF ;PLY_CFG_UseHardwareSounds
+
+;Decreases the given volume (encoded in possibly more then 4 bits). If <0, forced to 0.
+;IN: A = volume, not ANDed.
+;OUT: A = new volume.
+PLY_LW_PSS_Shared_AdjustVolume:
+ and %1111
+ sub (ix + PLY_LW_Data_OffsetTrackInvertedVolume)
+ ret nc
+ xor a
+ ret
+
+;Reads and stores the noise pointed by HL, opens the noise channel.
+;IN: HL = instrument data where the noise is.
+;OUT: HL = HL++.
+;MOD: A.
+ IFDEF PLY_LW_USE_Noise ;CONFIG SPECIFIC
+PLY_LW_PSS_ReadNoise:
+ ld a,(hl)
+ inc hl
+ ld (PLY_LW_NoiseRegister),a
+ res 5,c ;Opens the noise channel.
+ ret
+ ENDIF ;PLY_LW_USE_Noise
+
+;Calculates the period according to the base note and put it in BC'. Used by both software and hardware codes.
+;IN: DE' = period table.
+; A = instrument arpeggio (0 if not used).
+;OUT: HL' = period.
+;MOD: A
+PLY_LW_CalculatePeriodForBaseNote:
+ ;Gets the period from the current note.
+ exx
+ ld h,0
+ add a,(ix + PLY_LW_Data_OffsetBaseNote) ;Adds the instrument Arp to the base note (including the transposition).
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC
+ add (ix + PLY_LW_Data_OffsetCurrentArpeggioValue) ;Adds the Arpeggio Table effect.
+ ENDIF ;PLY_CFG_UseEffect_ArpeggioTable
+ ld l,a
+ sla l ;Note encoded on 7 bits, so should be fine.
+ add hl,de
+ ld a,(hl)
+ inc hl
+ ld h,(hl)
+ ld l,a ;HL' = period.
+
+ ;Adds the Pitch Table value, if used.
+ IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC
+ ld a,(ix + PLY_LW_Data_OffsetIsPitchTableUsed)
+ or a
+ jr z,PLY_LW_CalculatePeriodForBaseNote_NoPitchTable
+ ld c,(ix + PLY_LW_Data_OffsetCurrentPitchTableValue + 0)
+ ld b,(ix + PLY_LW_Data_OffsetCurrentPitchTableValue + 1)
+ add hl,bc
+PLY_LW_CalculatePeriodForBaseNote_NoPitchTable:
+ ENDIF ;PLY_CFG_UseEffect_PitchTable
+ ;Adds the Track Pitch.
+ IFDEF PLY_LW_USE_EffectPitchUpDown
+ ld c,(ix + PLY_LW_Data_OffsetTrackPitchInteger + 0)
+ ld b,(ix + PLY_LW_Data_OffsetTrackPitchInteger + 1)
+ add hl,bc
+ ENDIF ;PLY_LW_USE_EffectPitchUpDown
+ exx
+ ret
+
+ IFDEF PLY_LW_PitchInInstrument ;CONFIG SPECIFIC
+;Reads the pitch in the Instruments (16 bits) and adds it to HL', which should contain the software period.
+;IN: HL = points on the pitch value.
+;OUT: HL = points after the pitch.
+;MOD: A, BC', HL' updated.
+PLY_LW_ReadPitchAndAddToPeriod:
+ ;Reads 2 * 8 bits for the pitch. Slow...
+ ld a,(hl)
+ inc hl
+ exx
+ ld c,a ;Adds the read pitch to the note period.
+ exx
+ ld a,(hl)
+ inc hl
+ exx
+ ld b,a
+ add hl,bc
+ exx
+ ret
+ ENDIF ;PLY_LW_PitchInInstrument
+
+
+
+
+
+
+
+
+
+
+
+
+
+;---------------------------------------------------------------------
+;Effect management.
+;---------------------------------------------------------------------
+
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+
+;IN: HL = points after the first byte.
+; B = data of the first byte on bits 0-4 (will probably needed to be ANDed, as bits 5-7 are undetermined).
+; DE'= Instrument Table (not useful here). Do not modify!
+; IX = data block of the Track.
+;OUT: HL = points after the data of the effect (maybe nothing to do).
+; Each effect must jump to PLY_LW_RT_CellRead.
+
+;Clears all the effects (volume, pitch table, arpeggio table).
+ IFDEF PLY_CFG_UseEffect_Reset ;CONFIG SPECIFIC.
+PLY_LW_EffectReset:
+ ;Inverted volume.
+ call PLY_LW_ReadInvertedVolumeFromB
+
+ xor a
+ ;The inverted volume is managed above, so don't change it.
+ IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC
+ ld (ix + PLY_LW_Data_OffsetIsPitchUpDownUsed),a
+ ENDIF ;PLY_LW_USE_EffectPitchUpDown
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC
+ ld (ix + PLY_LW_Data_OffsetIsArpeggioTableUsed),a
+ ld (ix + PLY_LW_Data_OffsetCurrentArpeggioValue),a ;Contrary to the Pitch, the value must be reset.
+ ENDIF ;PLY_CFG_UseEffect_ArpeggioTable
+ IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC
+ ld (ix + PLY_LW_Data_OffsetIsPitchTableUsed),a
+ ENDIF ;PLY_CFG_UseEffect_PitchTable
+ jp PLY_LW_RT_CellRead
+ ENDIF ;PLY_CFG_UseEffect_Reset
+
+;Changes the volume. Possibly changes the Track pitch.
+ IFDEF PLY_LW_USE_Volume_And_PitchUpDown_Effects ;CONFIG SPECIFIC.
+PLY_LW_EffectVolumeAndPitchUpDown:
+ ;Stores the new inverted volume.
+ call PLY_LW_ReadInvertedVolumeFromB
+
+ ;Pitch? Warning, the code below is shared with the PitchUp/Down effect.
+ bit 4,b
+ jp z,PLY_LW_RT_CellRead
+ ;Pitch present. Reads and stores its 16 bits value (integer/decimal).
+PLY_LW_EffectPitchUpDown_Activated:
+ ;Code shared with the effect above.
+ ;Activates the effect.
+ ld (ix + PLY_LW_Data_OffsetIsPitchUpDownUsed),255
+ ld a,(hl)
+ inc hl
+ ld (ix + PLY_LW_Data_OffsetTrackPitchSpeed + 0),a
+ ld a,(hl)
+ inc hl
+ ld (ix + PLY_LW_Data_OffsetTrackPitchSpeed + 1),a
+
+ jp PLY_LW_RT_CellRead
+ ENDIF ;PLY_LW_USE_Volume_And_PitchUpDown_Effects
+
+
+;Effect table. Each entry jumps to an effect management code.
+;Put after the code above so that the JR are within bound.
+PLY_LW_EffectTable:
+ IFDEF PLY_LW_EffectReset ;CONFIG SPECIFIC
+ jr PLY_LW_EffectReset ;000
+ ELSE
+ jr $
+ ENDIF
+
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC
+ jr PLY_LW_EffectArpeggioTable ;001
+ ELSE
+ jr $
+ ENDIF
+
+ IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC
+ jr PLY_LW_EffectPitchTable ;010
+ ELSE
+ jr $
+ ENDIF
+
+ IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC
+ jr PLY_LW_EffectPitchUpDown ;011
+ ELSE
+ jr $
+ ENDIF
+
+ IFDEF PLY_LW_USE_Volume_And_PitchUpDown_Effects ;CONFIG SPECIFIC
+ jr PLY_LW_EffectVolumeAndPitchUpDown ;100
+ ELSE
+ jr $
+ ENDIF
+
+ IFDEF PLY_LW_USE_Volume_And_ArpeggioTable_Effects ;CONFIG SPECIFIC
+ jr PLY_LW_EffectVolumeArpeggioTable ;101
+ ELSE
+ jr $
+ ENDIF
+
+ IFDEF PLY_LW_USE_Reset_And_ArpeggioTable_Effects ;CONFIG SPECIFIC
+ jr PLY_LW_EffectResetArpeggioTable ;110
+ ELSE
+ jr $
+ ENDIF
+
+ ;111 Unused.
+
+
+
+;Pitch up/down effect, activation or stop.
+ IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC
+PLY_LW_EffectPitchUpDown:
+ rr b ;Pitch present or pitch stop?
+ jr c,PLY_LW_EffectPitchUpDown_Activated
+ ;Pitch stop.
+ ld (ix + PLY_LW_Data_OffsetIsPitchUpDownUsed),0
+ jp PLY_LW_RT_CellRead
+ ENDIF ;PLY_LW_USE_EffectPitchUpDown
+
+;Arpeggio table effect, activation or stop.
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC
+PLY_LW_EffectArpeggioTable:
+ ld a,b
+ and %11111
+PLY_LW_EffectArpeggioTable_AfterMask:
+ ld (ix + PLY_LW_Data_OffsetIsArpeggioTableUsed),a ;Sets to 0 if the Arpeggio is stopped, or any other value if it starts.
+ jr z,PLY_LW_EffectArpeggioTable_Stop
+
+ ;Gets the Arpeggio address.
+ add a,a
+ exx
+ ld l,a
+ ld h,0
+dknr3:
+PLY_LW_PtArpeggios: ld bc,0
+ add hl,bc
+ ld a,(hl)
+ inc hl
+ ld (ix + PLY_LW_Data_OffsetPtArpeggioTable + 0),a
+ ld a,(hl)
+ ld (ix + PLY_LW_Data_OffsetPtArpeggioTable + 1),a
+ exx
+
+ ;Resets the offset of the Arpeggio, to force a restart.
+ xor a
+ ld (ix + PLY_LW_Data_OffsetPtArpeggioOffset),a
+ jp PLY_LW_RT_CellRead
+PLY_LW_EffectArpeggioTable_Stop:
+ ;Contrary to the Pitch, the Arpeggio must also be set to 0 when stopped.
+ ld (ix + PLY_LW_Data_OffsetCurrentArpeggioValue),a
+ jp PLY_LW_RT_CellRead
+ ENDIF ;PLY_CFG_UseEffect_ArpeggioTable
+
+;Pitch table effect, activation or stop.
+;This is exactly the same code as for the Arpeggio, but I can't find a way to share it...
+ IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC
+PLY_LW_EffectPitchTable:
+ ld a,b
+ and %11111
+PLY_LW_EffectPitchTable_AfterMask:
+ ld (ix + PLY_LW_Data_OffsetIsPitchTableUsed),a ;Sets to 0 if the Pitch is stopped, or any other value if it starts.
+ jp z,PLY_LW_RT_CellRead
+
+ ;Gets the Pitch address.
+ add a,a
+ exx
+ ld l,a
+ ld h,0
+dknr3:
+PLY_LW_PtPitches: ld bc,0
+ add hl,bc
+ ld a,(hl)
+ inc hl
+ ld (ix + PLY_LW_Data_OffsetPtPitchTable + 0),a
+ ld a,(hl)
+ inc hl
+ ld (ix + PLY_LW_Data_OffsetPtPitchTable + 1),a
+ exx
+
+ ;Resets the offset of the Pitch, to force a restart.
+ xor a
+ ld (ix + PLY_LW_Data_OffsetPtPitchOffset),a
+
+ jp PLY_LW_RT_CellRead
+ ENDIF ;PLY_CFG_UseEffect_PitchTable
+
+
+
+;Volume, and Arpeggio Table, activation or stop.
+ IFDEF PLY_LW_USE_Volume_And_ArpeggioTable_Effects ;CONFIG SPECIFIC
+PLY_LW_EffectVolumeArpeggioTable:
+ ;Stores the new inverted volume.
+ call PLY_LW_ReadInvertedVolumeFromB
+
+ ;Manages the Arpeggio, encoded just after.
+ ld a,(hl)
+ inc hl
+ or a ;Required, else a volume of 0 will disturb the flag test after the jump!
+ jr PLY_LW_EffectArpeggioTable_AfterMask
+ ENDIF ;PLY_LW_USE_Volume_And_ArpeggioTable_Effects
+
+;Reset, and Arpeggio Table (activation only).
+ IFDEF PLY_LW_USE_Reset_And_ArpeggioTable_Effects ;CONFIG SPECIFIC
+PLY_LW_EffectResetArpeggioTable:
+ ;Resets effects and read volume.
+ ;A bit of loss of CPU because we're going to set the Arpeggio just after, AND the effect pointer is stored!
+ ;Oh well, less memory taken this way.
+ call PLY_LW_EffectReset
+
+ ;Reads the Arpeggio.
+ ld a,(hl)
+ inc hl
+ or a ;Required, else a volume of 0 will disturb the flag test after the jump!
+ jp PLY_LW_EffectArpeggioTable_AfterMask ;No need to use the mask, the value is clean.
+ ENDIF ;PLY_LW_USE_Reset_And_ArpeggioTable_Effects
+
+
+;Reads the inverted volume from B, stored it after masking the bits in A.
+PLY_LW_ReadInvertedVolumeFromB:
+ ld a,b
+ and %1111
+ ld (ix + PLY_LW_Data_OffsetTrackInvertedVolume),a
+ ret
+
+ ENDIF ;PLY_CFG_UseEffects
+
+
+
+
+
+
+
+
+;---------------------------------------------------------------------
+;Data blocks for the three channels. Make sure NOTHING is added between, as the init clears everything!
+;---------------------------------------------------------------------
+
+;Data block for channel 1.
+PLY_LW_Track1_Data:
+dkbs:
+PLY_LW_Track1_WaitEmptyCell: db 0 ;How many empty cells have to be waited. 0 = none.
+ IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC
+PLY_LW_Track1_Transposition: db 0
+ ENDIF ;PLY_CFG_UseTranspositions
+PLY_LW_Track1_BaseNote: db 0 ;Base note, such as the note played. The transposition IS included.
+PLY_LW_Track1_InstrumentCurrentStep: db 0 ;The current step on the Instrument (>=0, till it reaches the Speed).
+PLY_LW_Track1_InstrumentSpeed: db 0 ;The Instrument speed (>=0).
+PLY_LW_Track1_TrackInvertedVolume: db 0
+dkbe:
+dkws:
+PLY_LW_Track1_PtTrack: dw 0 ;Points on the next Cell of the Track to read. Evolves.
+PLY_LW_Track1_PtInstrument: dw 0 ;Points on the Instrument, evolves.
+PLY_LW_Track1_PtBaseInstrument: dw 0 ;Points on the base of the Instrument, does not evolve.
+dkwe:
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+dkbs:
+PLY_LW_Track1_IsPitchUpDownUsed: db 0 ;>0 if a Pitch Up/Down is currently in use.
+PLY_LW_Track1_TrackPitchDecimal: db 0 ;The decimal part of the Track pitch. Evolves as the pitch goes up/down.
+dkbe:
+dkws:
+PLY_LW_Track1_TrackPitchSpeed: dw 0 ;The integer and decimal part of the Track pitch speed. Is added to the Track Pitch every frame.
+PLY_LW_Track1_TrackPitchInteger: dw 0 ;The integer part of the Track pitch. Evolves as the pitch goes up/down.
+dkwe:
+dkbs:
+PLY_LW_Track1_IsArpeggioTableUsed: db 0 ;>0 if an Arpeggio Table is currently in use.
+PLY_LW_Track1_PtArpeggioOffset: db 0 ;Increases over the Arpeggio.
+PLY_LW_Track1_CurrentArpeggioValue: db 0 ;Value from the Arpeggio to add to the base note. Read even if the Arpeggio effect is deactivated.
+dkbe:
+dkws:
+PLY_LW_Track1_PtArpeggioTable: dw 0 ;Point on the base of the Arpeggio table, does not evolve.
+dkwe:
+dkbs:
+PLY_LW_Track1_IsPitchTableUsed: db 0 ;>0 if a Pitch Table is currently in use.
+PLY_LW_Track1_PtPitchOffset: db 0 ;Increases over the Pitch.
+dkbe:
+dkws:
+PLY_LW_Track1_CurrentPitchTableValue: dw 0 ;16 bit value from the Pitch to add to the base note. Not read if the Pitch effect is deactivated.
+PLY_LW_Track1_PtPitchTable: dw 0 ;Points on the base of the Pitch table, does not evolve.
+dkwe:
+ ENDIF ;PLY_CFG_UseEffects
+PLY_LW_Track1_Data_End:
+
+PLY_LW_Track1_Data_Size: equ PLY_LW_Track1_Data_End - PLY_LW_Track1_Data
+
+PLY_LW_Data_OffsetWaitEmptyCell: equ PLY_LW_Track1_WaitEmptyCell - PLY_LW_Track1_Data
+ IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC
+PLY_LW_Data_OffsetTransposition: equ PLY_LW_Track1_Transposition - PLY_LW_Track1_Data
+ ENDIF ;PLY_CFG_UseTranspositions
+
+PLY_LW_Data_OffsetPtTrack: equ PLY_LW_Track1_PtTrack - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetBaseNote: equ PLY_LW_Track1_BaseNote - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetPtInstrument: equ PLY_LW_Track1_PtInstrument - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetPtBaseInstrument: equ PLY_LW_Track1_PtBaseInstrument - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetInstrumentCurrentStep: equ PLY_LW_Track1_InstrumentCurrentStep - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetInstrumentSpeed: equ PLY_LW_Track1_InstrumentSpeed - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetTrackInvertedVolume: equ PLY_LW_Track1_TrackInvertedVolume - PLY_LW_Track1_Data
+ IFDEF PLY_CFG_UseEffects ;CONFIG SPECIFIC
+ IFDEF PLY_LW_USE_EffectPitchUpDown ;CONFIG SPECIFIC
+PLY_LW_Data_OffsetIsPitchUpDownUsed: equ PLY_LW_Track1_IsPitchUpDownUsed - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetTrackPitchInteger: equ PLY_LW_Track1_TrackPitchInteger - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetTrackPitchDecimal: equ PLY_LW_Track1_TrackPitchDecimal - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetTrackPitchSpeed: equ PLY_LW_Track1_TrackPitchSpeed - PLY_LW_Track1_Data
+ ENDIF ;PLY_LW_USE_EffectPitchUpDown
+ IFDEF PLY_CFG_UseEffect_ArpeggioTable ;CONFIG SPECIFIC
+PLY_LW_Data_OffsetIsArpeggioTableUsed: equ PLY_LW_Track1_IsArpeggioTableUsed - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetPtArpeggioTable: equ PLY_LW_Track1_PtArpeggioTable - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetPtArpeggioOffset: equ PLY_LW_Track1_PtArpeggioOffset - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetCurrentArpeggioValue: equ PLY_LW_Track1_CurrentArpeggioValue - PLY_LW_Track1_Data
+ ENDIF ;PLY_CFG_UseEffect_ArpeggioTable
+ IFDEF PLY_CFG_UseEffect_PitchTable ;CONFIG SPECIFIC
+PLY_LW_Data_OffsetIsPitchTableUsed: equ PLY_LW_Track1_IsPitchTableUsed - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetPtPitchTable: equ PLY_LW_Track1_PtPitchTable - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetCurrentPitchTableValue: equ PLY_LW_Track1_CurrentPitchTableValue - PLY_LW_Track1_Data
+PLY_LW_Data_OffsetPtPitchOffset: equ PLY_LW_Track1_PtPitchOffset - PLY_LW_Track1_Data
+ ENDIF ;PLY_CFG_UseEffect_PitchTable
+ ENDIF ;PLY_CFG_UseEffects
+
+;Data block for channel 2.
+PLY_LW_Track2_Data:
+dkbs:
+ ds PLY_LW_Track1_Data_Size, 0
+dkbe:
+PLY_LW_Track2_Data_End:
+PLY_LW_Track2_WaitEmptyCell: equ PLY_LW_Track2_Data + PLY_LW_Data_OffsetWaitEmptyCell
+ IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC
+PLY_LW_Track2_Transposition: equ PLY_LW_Track2_Data + PLY_LW_Data_OffsetTransposition
+ ENDIF ;PLY_CFG_UseTranspositions
+
+PLY_LW_Track2_PtTrack: equ PLY_LW_Track2_Data + PLY_LW_Data_OffsetPtTrack
+PLY_LW_Track2_PtInstrument: equ PLY_LW_Track2_Data + PLY_LW_Data_OffsetPtInstrument
+
+;Data block for channel 3.
+PLY_LW_Track3_Data:
+dkbs:
+ ds PLY_LW_Track1_Data_Size, 0
+dkbe:
+PLY_LW_Track3_Data_End:
+PLY_LW_Track3_WaitEmptyCell: equ PLY_LW_Track3_Data + PLY_LW_Data_OffsetWaitEmptyCell
+ IFDEF PLY_CFG_UseTranspositions ;CONFIG SPECIFIC
+PLY_LW_Track3_Transposition: equ PLY_LW_Track3_Data + PLY_LW_Data_OffsetTransposition
+ ENDIF ;PLY_CFG_UseTranspositions
+PLY_LW_Track3_PtTrack: equ PLY_LW_Track3_Data + PLY_LW_Data_OffsetPtTrack
+PLY_LW_Track3_PtInstrument: equ PLY_LW_Track3_Data + PLY_LW_Data_OffsetPtInstrument
+
+ ;Makes sure the structure all have the same size!
+ ASSERT (PLY_LW_Track1_Data_End - PLY_LW_Track1_Data) == (PLY_LW_Track2_Data_End - PLY_LW_Track2_Data)
+ ASSERT (PLY_LW_Track1_Data_End - PLY_LW_Track1_Data) == (PLY_LW_Track3_Data_End - PLY_LW_Track3_Data)
+ ;No holes between the blocks, the init makes a LDIR to clear everything!
+ ASSERT PLY_LW_Track1_Data_End == PLY_LW_Track2_Data
+ ASSERT PLY_LW_Track2_Data_End == PLY_LW_Track3_Data
+
+
+
+;---------------------------------------------------------------------
+;Register block for all the channels. They are "polluted" with pointers to code because all this
+;is actually a RET table!
+;---------------------------------------------------------------------
+;DB register, DB value then DW code to jump to once the value is read.
+PLY_LW_Registers_RetTable:
+PLY_LW_Track1_Registers:
+dkbs: db 8
+PLY_LW_Track1_Volume: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+dkbs: db 0
+PLY_LW_Track1_SoftwarePeriodLSB: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+dkbs: db 1
+PLY_LW_Track1_SoftwarePeriodMSB: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+PLY_LW_Track2_Registers:
+dkbs: db 9
+PLY_LW_Track2_Volume: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+dkbs: db 2
+PLY_LW_Track2_SoftwarePeriodLSB: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+dkbs: db 3
+PLY_LW_Track2_SoftwarePeriodMSB: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+
+PLY_LW_Track3_Registers:
+dkbs: db 10
+PLY_LW_Track3_Volume: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+dkbs: db 4
+PLY_LW_Track3_SoftwarePeriodLSB: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+dkbs: db 5
+PLY_LW_Track3_SoftwarePeriodMSB: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+;Generic registers.
+ IFDEF PLY_LW_USE_NoiseRegister ;CONFIG SPECIFIC
+dkbs: db 6
+PLY_LW_NoiseRegister: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+ ENDIF ;PLY_LW_USE_NoiseRegister
+
+dkbs: db 7
+PLY_LW_MixerRegister: db 0
+dkbe:
+ IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+
+dkbs: db 11
+PLY_LW_Reg11: db 0
+dkbe:
+dkps: dw PLY_LW_SendPsgRegister
+dkpe:
+
+dkbs: db 12
+PLY_LW_Reg12: db 0
+dkbe:
+dkps:
+ dw PLY_LW_SendPsgRegisterR13
+ ;This one is a trick to send the register after R13 is managed.
+ dw PLY_LW_SendPsgRegisterAfterPop
+
+ dw PLY_LW_SendPsgRegisterEnd
+dkpe:
+ ELSE
+dkps:
+ dw PLY_LW_SendPsgRegisterEnd
+dkpe:
+ ENDIF ;PLY_CFG_UseHardwareSounds
+
+
+
+PLY_LW_Registers_OffsetVolume: equ PLY_LW_Track1_Volume - PLY_LW_Track1_Registers
+PLY_LW_Registers_OffsetSoftwarePeriodLSB: equ PLY_LW_Track1_SoftwarePeriodLSB - PLY_LW_Track1_Registers
+PLY_LW_Registers_OffsetSoftwarePeriodMSB: equ PLY_LW_Track1_SoftwarePeriodMSB - PLY_LW_Track1_Registers
+
+;The period table for each note (from 0 to 127 included).
+PLY_LW_PeriodTable:
+dkws
+ IFDEF PLY_LW_HARDWARE_CPC
+ ;PSG running to 1000000 Hz.
+ dw 3822,3608,3405,3214,3034,2863,2703,2551,2408,2273,2145,2025 ;0
+ dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012 ;12
+ dw 956,902,851,804,758,716,676,638,602,568,536,506 ;24
+ dw 478,451,426,402,379,358,338,319,301,284,268,253 ;36
+ dw 239,225,213,201,190,179,169,159,150,142,134,127 ;48
+ dw 119,113,106,100,95,89,84,80,75,71,67,63 ;60
+ dw 60,56,53,50,47,45,42,40,38,36,34,32 ;72
+ dw 30,28,27,25,24,22,21,20,19,18,17,16 ;84
+ dw 15,14,13,13,12,11,11,10,9,9,8,8 ;96
+ dw 7,7,7,6,6,6,5,5,5,4,4,4 ;108
+ dw 4,4,3,3,3,3,3,2 ;,2,2,2,2 ;120 -> 127
+ ENDIF
+
+ IFDEF PLY_LW_HARDWARE_SPECTRUM_OR_MSX
+ ;PSG running to 1773400 Hz.
+ dw 6778, 6398, 6039, 5700, 5380, 5078, 4793, 4524, 4270, 4030, 3804, 3591 ; Octave 0
+ dw 3389, 3199, 3019, 2850, 2690, 2539, 2397, 2262, 2135, 2015, 1902, 1795 ; Octave 1
+ dw 1695, 1599, 1510, 1425, 1345, 1270, 1198, 1131, 1068, 1008, 951, 898 ; Octave 2
+ dw 847, 800, 755, 712, 673, 635, 599, 566, 534, 504, 476, 449 ; Octave 3
+ dw 424, 400, 377, 356, 336, 317, 300, 283, 267, 252, 238, 224 ; Octave 4
+ dw 212, 200, 189, 178, 168, 159, 150, 141, 133, 126, 119, 112 ; Octave 5
+ dw 106, 100, 94, 89, 84, 79, 75, 71, 67, 63, 59, 56 ; Octave 6
+ dw 53, 50, 47, 45, 42, 40, 37, 35, 33, 31, 30, 28 ; Octave 7
+ dw 26, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14 ; Octave 8
+ dw 13, 12, 12, 11, 11, 10, 9, 9, 8, 8, 7, 7 ; Octave 9
+ dw 7, 6, 6, 6, 5, 5, 5, 4 ; Octave 10
+ ENDIF
+
+ IFDEF PLY_LW_HARDWARE_PENTAGON
+ ;PSG running to 1750000 Hz.
+ dw 6689, 6314, 5959, 5625, 5309, 5011, 4730, 4464, 4214, 3977, 3754, 3543 ; Octave 0
+ dw 3344, 3157, 2980, 2812, 2655, 2506, 2365, 2232, 2107, 1989, 1877, 1772 ; Octave 1
+ dw 1672, 1578, 1490, 1406, 1327, 1253, 1182, 1116, 1053, 994, 939, 886 ; Octave 2
+ dw 836, 789, 745, 703, 664, 626, 591, 558, 527, 497, 469, 443 ; Octave 3
+ dw 418, 395, 372, 352, 332, 313, 296, 279, 263, 249, 235, 221 ; Octave 4
+ dw 209, 197, 186, 176, 166, 157, 148, 140, 132, 124, 117, 111 ; Octave 5
+ dw 105, 99, 93, 88, 83, 78, 74, 70, 66, 62, 59, 55 ; Octave 6
+ dw 52, 49, 47, 44, 41, 39, 37, 35, 33, 31, 29, 28 ; Octave 7
+ dw 26, 25, 23, 22, 21, 20, 18, 17, 16, 16, 15, 14 ; Octave 8
+ dw 13, 12, 12, 11, 10, 10, 9, 9, 8, 8, 7, 7 ; Octave 9
+ dw 7, 6, 6, 5, 5, 5, 5, 4 ; Octave 10
+ ENDIF
+dkwe
+PLY_LW_End:
+
+
+
diff --git a/lib/plw/player/PlayerLightWeight_SoundEffects.asm b/lib/plw/player/PlayerLightWeight_SoundEffects.asm
new file mode 100644
index 0000000..cd15cb8
--- /dev/null
+++ b/lib/plw/player/PlayerLightWeight_SoundEffects.asm
@@ -0,0 +1,458 @@
+; Player of sound effects, for the Lightweight player.
+
+ ;Is there a loaded Player Configuration source? If no, use a default configuration.
+ IFNDEF PLY_CFG_SFX_ConfigurationIsPresent
+ PLY_CFG_UseHardwareSounds = 1
+ PLY_CFG_SFX_LoopTo = 1
+ PLY_CFG_SFX_NoSoftNoHard = 1
+ PLY_CFG_SFX_NoSoftNoHard_Noise = 1
+ PLY_CFG_SFX_SoftOnly = 1
+ PLY_CFG_SFX_SoftOnly_Noise = 1
+ PLY_CFG_SFX_HardOnly = 1
+ PLY_CFG_SFX_HardOnly_Noise = 1
+ PLY_CFG_SFX_HardOnly_Retrig = 1
+ PLY_CFG_SFX_SoftAndHard = 1
+ PLY_CFG_SFX_SoftAndHard_Noise = 1
+ PLY_CFG_SFX_SoftAndHard_Retrig = 1
+ ENDIF
+
+; Agglomerates some Player Configuration flags.
+; --------------------------------------------
+; Mixes the Hardware flags into one.
+ IFDEF PLY_CFG_SFX_HardOnly
+ PLY_LW_SE_HardwareSounds = 1
+ ENDIF
+ IFDEF PLY_CFG_SFX_SoftAndHard
+ PLY_LW_SE_HardwareSounds = 1
+ ENDIF
+; Mixes the Hardware Noise flags into one.
+ IFDEF PLY_CFG_SFX_HardOnly_Noise
+ PLY_LW_SE_HardwareNoise = 1
+ ENDIF
+ IFDEF PLY_CFG_SFX_SoftAndHard_Noise
+ PLY_LW_SE_HardwareNoise = 1
+ ENDIF
+; Mixes the Noise flags into one.
+ IFDEF PLY_LW_SE_HardwareNoise
+ PLY_LW_SE_Noise = 1
+ ENDIF
+ IFDEF PLY_CFG_SFX_NoSoftNoHard_Noise
+ PLY_LW_SE_Noise = 1
+ ENDIF
+ IFDEF PLY_CFG_SFX_SoftOnly
+ PLY_LW_SE_Noise = 1
+ ENDIF
+; Noise in Sound Effects? Then noise register code must be compiled.
+ IFDEF PLY_LW_SE_Noise
+ PLY_LW_USE_NoiseRegister = 1
+ ENDIF
+; Mixes the Software Volume flags into one.
+ IFDEF PLY_CFG_SFX_NoSoftNoHard
+ PLY_LW_SE_VolumeSoft = 1
+ PLY_LW_SE_VolumeSoftOrHard = 1
+ ENDIF
+ IFDEF PLY_CFG_SFX_SoftOnly
+ PLY_LW_SE_VolumeSoft = 1
+ PLY_LW_SE_VolumeSoftOrHard = 1
+ ENDIF
+; Mixes the volume (soft/hard) into one.
+ IFDEF PLY_CFG_UseHardwareSounds
+ PLY_LW_SE_VolumeSoftOrHard = 1
+ ENDIF
+; Mixes the retrig flags into one.
+ IFDEF PLY_CFG_SFX_HardOnly_Retrig
+ PLY_LW_SE_Retrig = 1
+ ENDIF
+ IFDEF PLY_CFG_SFX_SoftAndHard_Retrig
+ PLY_LW_SE_Retrig = 1
+ ENDIF
+
+
+;Initializes the sound effects. It MUST be called at any times before a first sound effect is triggered.
+;It doesn't matter whether the song is playing or not, or if it has been initialized or not.
+;IN: HL = Address to the sound effects data.
+PLY_LW_InitSoundEffectsDisarkGenerateExternalLabel:
+PLY_LW_InitSoundEffects:
+ ld (PLY_LW_SE_PtSoundEffectTable + 1),hl
+ ret
+
+
+;Plays a sound effect. If a previous one was already playing on the same channel, it is replaced.
+;This does not actually plays the sound effect, but programs its playing.
+;The music player, when called, will call the PLY_LW_PlaySoundEffectsStream method below.
+;IN: A = Sound effect number (>0!).
+; C = The channel where to play the sound effect (0, 1, 2).
+; B = Inverted volume (0 = full volume, 16 = no sound). Hardware sounds are also lowered.
+PLY_LW_PlaySoundEffectDisarkGenerateExternalLabel:
+PLY_LW_PlaySoundEffect:
+ ;Gets the address to the sound effect.
+ dec a ;The 0th is not encoded.
+dknr3:
+PLY_LW_SE_PtSoundEffectTable: ld hl,0
+ ld e,a
+ ld d,0
+ add hl,de
+ add hl,de
+ ld e,(hl)
+ inc hl
+ ld d,(hl)
+ ;Reads the header of the sound effect to get the speed.
+ ld a,(de)
+ inc de
+
+ push af
+ ;ex af,af'
+
+ ld a,b
+
+ ;Finds the pointer to the sound effect of the desired channel.
+ ld hl,PLY_LW_Channel1_SoundEffectData
+ ld b,0
+ sla c
+ sla c
+ sla c
+ add hl,bc
+ ld (hl),e
+ inc hl
+ ld (hl),d
+ inc hl
+
+ ;Now stores the inverted volume.
+ ld (hl),a
+ inc hl
+
+ ;Resets the current speed, stores the instrument speed.
+ ld (hl),0
+ inc hl
+
+ ;ex af,af'
+ pop af
+
+ ld (hl),a
+
+ ret
+
+;Stops a sound effect. Nothing happens if there was no sound effect.
+;IN: A = The channel where to stop the sound effect (0, 1, 2).
+PLY_LW_StopSoundEffectFromChannelDisarkGenerateExternalLabel:
+PLY_LW_StopSoundEffectFromChannel:
+ ;Puts 0 to the pointer of the sound effect.
+ add a,a
+ add a,a
+ add a,a
+ ld e,a
+ ld d,0
+ ld hl,PLY_LW_Channel1_SoundEffectData
+ add hl,de
+ ld (hl),d ;0 means "no sound".
+ inc hl
+ ld (hl),d
+ ret
+
+;Plays the sound effects, if any has been triggered by the user.
+;This does not actually send registers to the PSG, it only overwrite the required values of the registers of the player.
+;The sound effects initialization method must have been called before!
+;As R7 is required, this must be called after the music has been played, but BEFORE the registers are sent to the PSG.
+;IN: A = R7.
+PLY_LW_PlaySoundEffectsStream:
+ ;Shifts the R7 to the left twice, so that bit 2 and 5 only can be set for each track, below.
+ rla
+ rla
+
+ ;Plays the sound effects on every track.
+ ld ix,PLY_LW_Channel1_SoundEffectData
+ ld iy,PLY_LW_Track1_Registers
+ ld c,a
+ call PLY_LW_PSES_Play
+ ld ix,PLY_LW_Channel2_SoundEffectData
+ ld iy,PLY_LW_Track2_Registers
+ srl c ;Not RR, because we have to make sure the b6 is 0, else no more keyboard (on CPC)!
+ ;Also, on MSX, bit 6 must be 0.
+ call PLY_LW_PSES_Play
+ ld ix,PLY_LW_Channel3_SoundEffectData
+ ld iy,PLY_LW_Track3_Registers
+ IFDEF PLY_LW_HARDWARE_MSX
+ scf ;On MSX, bit 7 must be 1.
+ rr c
+ ELSE
+ rr c ;On other platforms, we don't care about b7.
+ ENDIF
+ call PLY_LW_PSES_Play
+
+ ld a,c
+ ld (PLY_LW_MixerRegister),a
+ ret
+
+
+;Plays the sound stream from the given pointer to the sound effect. If 0, no sound is played.
+;The given R7 is given shift twice to the left, so that this code MUST set/reset the bit 2 (sound), and maybe reset bit 5 (noise).
+;This code MUST overwrite these bits because sound effects have priority over the music.
+;IN: IX = Points on the sound effect pointer. If the sound effect pointer is 0, nothing must be played.
+; IY = Points at the beginning of the register structure related to the channel.
+; C = R7, shifted twice to the left.
+;OUT: The pointed pointer by IX may be modified as the sound advances.
+; C = R7, MUST be modified if there is a sound effect.
+PLY_LW_PSES_Play:
+ ;Reads the pointer pointed by IX.
+ ld l,(ix + 0)
+ ld h,(ix + 1)
+ ld a,l
+ or h
+ ret z ;No sound to be played? Returns immediately.
+
+ ;Reads the first byte. What type of sound is it?
+PLY_LW_PSES_ReadFirstByte:
+ ld a,(hl)
+ inc hl
+ ld b,a
+ rra
+ jr c,PLY_LW_PSES_SoftwareOrSoftwareAndHardware
+ rra
+ IFDEF PLY_CFG_SFX_HardOnly ;CONFIG SPECIFIC
+ jr c,PLY_LW_PSES_HardwareOnly
+ ENDIF ;PLY_CFG_SFX_HardOnly
+
+ ;No software, no hardware, or end/loop.
+ ;-------------------------------------------
+ ;End or loop?
+ rra
+ IFDEF PLY_CFG_SFX_NoSoftNoHard ;CONFIG SPECIFIC. If not present, the jump is not needed, the method is just below.
+ jr c,PLY_LW_PSES_S_EndOrLoop
+
+ ;No software, no hardware.
+ ;-------------------------------------------
+ ;Gets the volume.
+ call PLY_LW_PSES_ManageVolumeFromA_Filter4Bits
+
+ ;Noise?
+ IFDEF PLY_CFG_SFX_NoSoftNoHard_Noise ;CONFIG SPECIFIC
+ rl b
+ call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel
+ ENDIF ;PLY_CFG_SFX_NoSoftNoHard_Noise
+
+ jr PLY_LW_PSES_SavePointerAndExit
+ ENDIF ;PLY_CFG_SFX_NoSoftNoHard
+
+ ;**Warning!** Do not put any instruction between EndOrLoop and NoSoftNoHard.
+
+PLY_LW_PSES_S_EndOrLoop:
+ IFDEF PLY_CFG_SFX_LoopTo ;CONFIG SPECIFIC. If no "loop to", the sounds always end, no need to test.
+ ;Is it an end?
+ rra
+ jr c,PLY_LW_PSES_S_Loop
+ ENDIF ;PLY_CFG_SFX_LoopTo
+ ;End of the sound. Marks the sound pointer with 0, meaning "no sound".
+ xor a
+ ld (ix + 0),a
+ ld (ix + 1),a
+ ret
+ IFDEF PLY_CFG_SFX_LoopTo ;CONFIG SPECIFIC.
+PLY_LW_PSES_S_Loop:
+ ;Loops. Reads the pointer and directly uses it.
+ ld a,(hl)
+ inc hl
+ ld h,(hl)
+ ld l,a
+ jr PLY_LW_PSES_ReadFirstByte
+ ENDIF ;PLY_CFG_SFX_LoopTo
+
+
+;Saves HL into IX, and exits. This must be called at the end of each Cell.
+;If the speed has not been reached, it is not saved.
+PLY_LW_PSES_SavePointerAndExit:
+ ;Speed reached?
+ ld a,(ix + PLY_LW_SoundEffectData_OffsetCurrentStep)
+ cp (ix + PLY_LW_SoundEffectData_OffsetSpeed)
+ jr c,PLY_LW_PSES_NotReached
+ ;The speed has been reached, so resets it and saves the pointer to the next cell to read.
+ ld (ix + PLY_LW_SoundEffectData_OffsetCurrentStep),0
+ ld (ix + 0),l
+ ld (ix + 1),h
+ ret
+PLY_LW_PSES_NotReached:
+ ;Speed not reached. Increases it, that's all. The same cell will be read next time.
+ inc (ix + PLY_LW_SoundEffectData_OffsetCurrentStep)
+ ret
+
+ IFDEF PLY_CFG_SFX_HardOnly ;CONFIG SPECIFIC
+ ;Hardware only.
+ ;-------------------------------------------
+PLY_LW_PSES_HardwareOnly:
+ ;Calls the shared code that manages everything.
+ call PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise
+ ;Cuts the sound.
+ set 2,c
+
+ jr PLY_LW_PSES_SavePointerAndExit
+ ENDIF ;PLY_CFG_SFX_HardOnly
+
+
+
+PLY_LW_PSES_SoftwareOrSoftwareAndHardware:
+ ;Software only?
+ rra
+ IFDEF PLY_CFG_SFX_SoftAndHard ;CONFIG SPECIFIC
+ jr c,PLY_LW_PSES_SoftwareAndHardware
+ ENDIF ;PLY_CFG_SFX_SoftAndHard
+
+ ;Software.
+ ;-------------------------------------------
+ IFDEF PLY_CFG_SFX_SoftOnly ;CONFIG SPECIFIC
+ ;Volume.
+ call PLY_LW_PSES_ManageVolumeFromA_Filter4Bits
+
+ ;Noise?
+ rl b
+ IFDEF PLY_CFG_SFX_SoftOnly_Noise ;CONFIG SPECIFIC
+ call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel
+ ENDIF ;PLY_CFG_SFX_SoftOnly_Noise
+
+ ;Opens the "sound" channel.
+ res 2,c
+
+ ;Reads the software period.
+ call PLY_LW_PSES_ReadSoftwarePeriod
+
+ jr PLY_LW_PSES_SavePointerAndExit
+ ENDIF ;PLY_CFG_SFX_SoftOnly
+
+
+ ;Software and Hardware.
+ ;-------------------------------------------
+ IFDEF PLY_LW_SE_HardwareSounds ;CONFIG SPECIFIC
+PLY_LW_PSES_SoftwareAndHardware:
+ ;Calls the shared code that manages everything.
+ call PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise
+
+ ;Reads the software period.
+ call PLY_LW_PSES_ReadSoftwarePeriod
+
+ ;Opens the sound.
+ res 2,c
+
+ jr PLY_LW_PSES_SavePointerAndExit
+ ENDIF ;PLY_LW_SE_HardwareSounds
+
+
+ IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC
+ ;Shared code used by the "hardware only" and "software and hardware" part.
+ ;Reads the Retrig flag, the Hardware Envelope, the possible noise, the hardware period,
+ ;and sets the volume to 16. The R7 sound channel is NOT modified.
+PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise:
+ ;Retrig?
+ rra
+ IFDEF PLY_LW_SE_Retrig ;CONFIG SPECIFIC
+ jr nc,PLY_LW_PSES_H_AfterRetrig
+ ld d,a
+ ld a,255
+ ld (PLY_LW_SetReg13Old + 1),a
+ ld a,d
+PLY_LW_PSES_H_AfterRetrig:
+ ENDIF ;PLY_LW_SE_Retrig
+
+ ;The hardware envelope can be set (8-15).
+ and %111
+ add a,8
+ ld (PLY_LW_SetReg13 + 1),a
+
+ ;Noise?
+ IFDEF PLY_LW_SE_HardwareNoise ;CONFIG SPECIFIC. B not needed after, we can put it in the condition too.
+ rl b
+ call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel
+ ENDIF ;PLY_LW_SE_HardwareNoise
+
+ ;Reads the hardware period.
+ call PLY_LW_PSES_ReadHardwarePeriod
+
+ ;Sets the volume to "hardware". It still may be decreased.
+ ld a,16
+ jp PLY_LW_PSES_ManageVolumeFromA_Hard
+ ENDIF ;PLY_CFG_UseHardwareSounds
+
+
+ IFDEF PLY_LW_SE_Noise
+;Reads the noise pointed by HL, increases HL, and opens the noise channel.
+PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel:
+ ;Reads the noise.
+ ld a,(hl)
+ ld (PLY_LW_NoiseRegister),a
+ inc hl
+
+ ;Opens noise channel.
+ res 5,c
+ ret
+ ENDIF ;PLY_LW_SE_Noise
+
+ IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC
+;Reads the hardware period from HL and sets the R11/R12 registers. HL is incremented of 2.
+PLY_LW_PSES_ReadHardwarePeriod:
+ ld a,(hl)
+ ld (PLY_LW_Reg11),a
+ inc hl
+ ld a,(hl)
+ ld (PLY_LW_Reg12),a
+ inc hl
+ ret
+ ENDIF ;PLY_CFG_UseHardwareSounds
+
+;Reads the software period from HL and sets the period registers thanks to IY. HL is incremented of 2.
+PLY_LW_PSES_ReadSoftwarePeriod:
+ ld a,(hl)
+ ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodLSB),a
+ inc hl
+ ld a,(hl)
+ ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodMSB),a
+ inc hl
+ ret
+
+ IFDEF PLY_LW_SE_VolumeSoft ;CONFIG SPECIFIC
+;Reads the volume in A, decreases it from the inverted volume of the channel, and sets the volume via IY.
+;IN: A = volume, from 0 to 15 (no hardware envelope).
+PLY_LW_PSES_ManageVolumeFromA_Filter4Bits:
+ and %1111
+ ENDIF ;PLY_LW_SE_VolumeSoft
+ IFDEF PLY_LW_SE_VolumeSoftOrHard ;CONFIG SPECIFIC
+;After the filtering. Useful for hardware sound (volume has been forced to 16).
+PLY_LW_PSES_ManageVolumeFromA_Hard:
+ ;Decreases the volume, checks the limit.
+ sub (ix + PLY_LW_SoundEffectData_OffsetInvertedVolume)
+ jr nc,PLY_LW_PSES_MVFA_NoOverflow
+ xor a
+PLY_LW_PSES_MVFA_NoOverflow:
+ ld (iy + PLY_LW_Registers_OffsetVolume),a
+ ret
+ ENDIF ;PLY_LW_SE_VolumeSoftOrHard
+
+
+;The data of the Channels MUST be consecutive.
+PLY_LW_Channel1_SoundEffectData:
+dkws
+ dw 0 ;Points to the sound effect for the track 1, or 0 if not playing.
+PLY_LW_Channel1_SoundEffectInvertedVolume:
+dkwe
+dkbs
+ db 0 ;Inverted volume.
+PLY_LW_Channel1_SoundEffectCurrentStep:
+ db 0 ;Current step (>=0).
+PLY_LW_Channel1_SoundEffectSpeed:
+ db 0 ;Speed (>=0).
+ ds 3,0 ;Padding.
+dkbe
+PLY_LW_Channel_SoundEffectDataSize: equ $ - PLY_LW_Channel1_SoundEffectData
+
+dkbs
+PLY_LW_Channel2_SoundEffectData:
+ ds PLY_LW_Channel_SoundEffectDataSize, 0
+PLY_LW_Channel3_SoundEffectData:
+ ds PLY_LW_Channel_SoundEffectDataSize, 0
+dkbe
+
+;Offset from the beginning of the data, to reach the inverted volume.
+PLY_LW_SoundEffectData_OffsetInvertedVolume: equ PLY_LW_Channel1_SoundEffectInvertedVolume - PLY_LW_Channel1_SoundEffectData
+PLY_LW_SoundEffectData_OffsetCurrentStep: equ PLY_LW_Channel1_SoundEffectCurrentStep - PLY_LW_Channel1_SoundEffectData
+PLY_LW_SoundEffectData_OffsetSpeed: equ PLY_LW_Channel1_SoundEffectSpeed - PLY_LW_Channel1_SoundEffectData
+
+ ;Checks that the pointers are consecutive.
+ assert (PLY_LW_Channel1_SoundEffectData + PLY_LW_Channel_SoundEffectDataSize) == PLY_LW_Channel2_SoundEffectData
+ assert (PLY_LW_Channel2_SoundEffectData + PLY_LW_Channel_SoundEffectDataSize) == PLY_LW_Channel3_SoundEffectData
+
diff --git a/lib/plw/player/player.asm b/lib/plw/player/player.asm
new file mode 100644
index 0000000..3c2d137
--- /dev/null
+++ b/lib/plw/player/player.asm
@@ -0,0 +1,43 @@
+org #0b06
+
+PLY_LW_HARDWARE_CPC = 1
+PLY_LW_MANAGE_SOUND_EFFECTS = 1
+PLY_LW_USE_HOOKS = 0
+PLY_LW_STOP_SOUNDS = 1
+
+PLY_CFG_ConfigurationIsPresent = 1
+PLY_CFG_SFX_ConfigurationIsPresent = 1
+PLY_CFG_SFX_SoftOnly = 1
+PLY_CFG_SFX_SoftOnly_Noise = 1
+PLY_CFG_NoSoftNoHard = 1
+PLY_CFG_SoftOnly = 1
+PLY_CFG_SoftOnly_Noise = 1
+PLY_CFG_SoftOnly_SoftwarePitch = 1
+
+ ; my hook table
+
+ jp PLY_LW_Init
+ jp PLY_LW_Play
+ jp PLY_LW_Stop
+ jp PLY_LW_InitSoundEffects
+ jp PLY_LW_PlaySoundEffect
+ jp PLW_LW_IsSoundEffectOn
+
+include "PlayerLightWeight.asm"
+
+; IN: L = channel
+; OUT: L = 0 if is not on
+PLW_LW_IsSoundEffectOn:
+ ld a,l
+ add a,a
+ add a,a
+ add a,a
+ ld c,a
+ ld b,0
+ ld hl,PLY_LW_Channel1_SoundEffectData
+ add hl,bc
+ ld a,(hl)
+ inc hl
+ or (hl)
+ ld l,a
+ ret
diff --git a/lib/plw/plw_init.z80 b/lib/plw/plw_init.z80
new file mode 100644
index 0000000..aaa6ba5
--- /dev/null
+++ b/lib/plw/plw_init.z80
@@ -0,0 +1,14 @@
+.globl _PLW_Init
+.globl _plw_player
+
+PLY_LW_INIT = 0x0b06
+
+_PLW_Init::
+ ld ix,#2
+ add ix,sp
+
+ ld l,0 (ix)
+ ld h,1 (ix)
+ ld a,2 (ix)
+
+ jp PLY_LW_INIT
diff --git a/lib/plw/plw_init_sound_effects.z80 b/lib/plw/plw_init_sound_effects.z80
new file mode 100644
index 0000000..a82cfdc
--- /dev/null
+++ b/lib/plw/plw_init_sound_effects.z80
@@ -0,0 +1,9 @@
+.globl _PLW_InitSoundEffects
+.globl plw_current_efx
+
+PLY_LW_INIT_SOUND_EFFECTS = 0x0b06 + 0x9
+
+_PLW_InitSoundEffects::
+ xor a
+ ld (plw_current_efx), a
+ jp PLY_LW_INIT_SOUND_EFFECTS
diff --git a/lib/plw/plw_is_sound_effect_on.z80 b/lib/plw/plw_is_sound_effect_on.z80
new file mode 100644
index 0000000..5953cce
--- /dev/null
+++ b/lib/plw/plw_is_sound_effect_on.z80
@@ -0,0 +1,7 @@
+.globl _PLW_IsSoundEffectOn
+
+PLY_LW_IS_SOUND_EFFECT_ON = 0x0b06 + 0xf
+
+_PLW_IsSoundEffectOn::
+ jp PLY_LW_IS_SOUND_EFFECT_ON
+
diff --git a/lib/plw/plw_play.z80 b/lib/plw/plw_play.z80
new file mode 100644
index 0000000..a1f0ac8
--- /dev/null
+++ b/lib/plw/plw_play.z80
@@ -0,0 +1,6 @@
+.globl _PLW_Play
+
+PLY_LW_PLAY = 0x0b06 + 0x3
+
+_PLW_Play::
+ jp PLY_LW_PLAY
diff --git a/lib/plw/plw_play_sound_effect.z80 b/lib/plw/plw_play_sound_effect.z80
new file mode 100644
index 0000000..a20fcfe
--- /dev/null
+++ b/lib/plw/plw_play_sound_effect.z80
@@ -0,0 +1,48 @@
+.globl _PLW_PlaySoundEffect
+.globl _PLW_IsSoundEffectOn
+.globl _PLW_PlaySoundEffectP
+.globl plw_current_efx
+
+PLY_LW_PLAY_SOUND_EFFECT = 0x0b06 + 0xc
+
+_PLW_PlaySoundEffect::
+ ld hl,#2
+ add hl,sp
+
+ ld a, (hl)
+ inc hl
+ ld c, (hl)
+ inc hl
+ ld b, (hl)
+
+ jp PLY_LW_PLAY_SOUND_EFFECT
+
+_PLW_PlaySoundEffectP::
+ ; check if current is over
+ ; de is not used
+ ld e, l
+ ; fixed channel 2
+ ld l, #2
+ call _PLW_IsSoundEffectOn
+ ld a, l
+ or a
+ jr z, play_efx
+
+ ld a, (plw_current_efx)
+ cp e
+ ret nc
+
+play_efx:
+ ; all good, play the effect
+ ld a, e
+ ld (plw_current_efx), a
+
+ ; fixed channel 2, full volume
+ ld bc, #0x0002
+
+ jp PLY_LW_PLAY_SOUND_EFFECT
+
+.area _DATA
+
+plw_current_efx: .ds 1
+
diff --git a/lib/plw/plw_player.asm b/lib/plw/plw_player.asm
new file mode 100644
index 0000000..f47a9bf
--- /dev/null
+++ b/lib/plw/plw_player.asm
@@ -0,0 +1,1193 @@
+;--------------------------------------------------------
+; File Created by SDCC : free open source ANSI-C Compiler
+; Version 4.0.0 #11528 (Linux)
+;--------------------------------------------------------
+ .module plw_player
+ .optsdcc -mz80
+
+;--------------------------------------------------------
+; Public variables in this module
+;--------------------------------------------------------
+ .globl _plw_player
+;--------------------------------------------------------
+; special function registers
+;--------------------------------------------------------
+;--------------------------------------------------------
+; ram data
+;--------------------------------------------------------
+ .area _DATA
+;--------------------------------------------------------
+; ram data
+;--------------------------------------------------------
+ .area _INITIALIZED
+;--------------------------------------------------------
+; absolute external ram data
+;--------------------------------------------------------
+ .area _DABS (ABS)
+;--------------------------------------------------------
+; global & static initialisations
+;--------------------------------------------------------
+ .area _HOME
+ .area _GSINIT
+ .area _GSFINAL
+ .area _GSINIT
+;--------------------------------------------------------
+; Home
+;--------------------------------------------------------
+ .area _HOME
+ .area _HOME
+;--------------------------------------------------------
+; code
+;--------------------------------------------------------
+ .area _CODE
+ .area _CODE
+_plw_player:
+ .db #0xc3 ; 195
+ .db #0xf6 ; 246
+ .db #0x0b ; 11
+ .db #0xc3 ; 195
+ .db #0x55 ; 85 'U'
+ .db #0x0c ; 12
+ .db #0xc3 ; 195
+ .db #0x3f ; 63
+ .db #0x0c ; 12
+ .db #0xc3 ; 195
+ .db #0x18 ; 24
+ .db #0x0b ; 11
+ .db #0xc3 ; 195
+ .db #0x1c ; 28
+ .db #0x0b ; 11
+ .db #0xc3 ; 195
+ .db #0x71 ; 113 'q'
+ .db #0x0f ; 15
+ .db #0x22 ; 34
+ .db #0x1e ; 30
+ .db #0x0b ; 11
+ .db #0xc9 ; 201
+ .db #0x3d ; 61
+ .db #0x21 ; 33
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x5f ; 95
+ .db #0x16 ; 22
+ .db #0x00 ; 0
+ .db #0x19 ; 25
+ .db #0x19 ; 25
+ .db #0x5e ; 94
+ .db #0x23 ; 35
+ .db #0x56 ; 86 'V'
+ .db #0x1a ; 26
+ .db #0x13 ; 19
+ .db #0xf5 ; 245
+ .db #0x78 ; 120 'x'
+ .db #0x21 ; 33
+ .db #0xde ; 222
+ .db #0x0b ; 11
+ .db #0x06 ; 6
+ .db #0x00 ; 0
+ .db #0xcb ; 203
+ .db #0x21 ; 33
+ .db #0xcb ; 203
+ .db #0x21 ; 33
+ .db #0xcb ; 203
+ .db #0x21 ; 33
+ .db #0x09 ; 9
+ .db #0x73 ; 115 's'
+ .db #0x23 ; 35
+ .db #0x72 ; 114 'r'
+ .db #0x23 ; 35
+ .db #0x77 ; 119 'w'
+ .db #0x23 ; 35
+ .db #0x36 ; 54 '6'
+ .db #0x00 ; 0
+ .db #0x23 ; 35
+ .db #0xf1 ; 241
+ .db #0x77 ; 119 'w'
+ .db #0xc9 ; 201
+ .db #0x87 ; 135
+ .db #0x87 ; 135
+ .db #0x87 ; 135
+ .db #0x5f ; 95
+ .db #0x16 ; 22
+ .db #0x00 ; 0
+ .db #0x21 ; 33
+ .db #0xde ; 222
+ .db #0x0b ; 11
+ .db #0x19 ; 25
+ .db #0x72 ; 114 'r'
+ .db #0x23 ; 35
+ .db #0x72 ; 114 'r'
+ .db #0xc9 ; 201
+ .db #0x17 ; 23
+ .db #0x17 ; 23
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0xde ; 222
+ .db #0x0b ; 11
+ .db #0xfd ; 253
+ .db #0x21 ; 33
+ .db #0x45 ; 69 'E'
+ .db #0x0e ; 14
+ .db #0x4f ; 79 'O'
+ .db #0xcd ; 205
+ .db #0x7f ; 127
+ .db #0x0b ; 11
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0xe6 ; 230
+ .db #0x0b ; 11
+ .db #0xfd ; 253
+ .db #0x21 ; 33
+ .db #0x51 ; 81 'Q'
+ .db #0x0e ; 14
+ .db #0xcb ; 203
+ .db #0x39 ; 57 '9'
+ .db #0xcd ; 205
+ .db #0x7f ; 127
+ .db #0x0b ; 11
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0xee ; 238
+ .db #0x0b ; 11
+ .db #0xfd ; 253
+ .db #0x21 ; 33
+ .db #0x5d ; 93
+ .db #0x0e ; 14
+ .db #0xcb ; 203
+ .db #0x19 ; 25
+ .db #0xcd ; 205
+ .db #0x7f ; 127
+ .db #0x0b ; 11
+ .db #0x79 ; 121 'y'
+ .db #0x32 ; 50 '2'
+ .db #0x6e ; 110 'n'
+ .db #0x0e ; 14
+ .db #0xc9 ; 201
+ .db #0xdd ; 221
+ .db #0x6e ; 110 'n'
+ .db #0x00 ; 0
+ .db #0xdd ; 221
+ .db #0x66 ; 102 'f'
+ .db #0x01 ; 1
+ .db #0x7d ; 125
+ .db #0xb4 ; 180
+ .db #0xc8 ; 200
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x47 ; 71 'G'
+ .db #0x1f ; 31
+ .db #0x38 ; 56 '8'
+ .db #0x21 ; 33
+ .db #0x1f ; 31
+ .db #0x1f ; 31
+ .db #0xaf ; 175
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x00 ; 0
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x01 ; 1
+ .db #0xc9 ; 201
+ .db #0xdd ; 221
+ .db #0x7e ; 126
+ .db #0x03 ; 3
+ .db #0xdd ; 221
+ .db #0xbe ; 190
+ .db #0x04 ; 4
+ .db #0x38 ; 56 '8'
+ .db #0x0b ; 11
+ .db #0xdd ; 221
+ .db #0x36 ; 54 '6'
+ .db #0x03 ; 3
+ .db #0x00 ; 0
+ .db #0xdd ; 221
+ .db #0x75 ; 117 'u'
+ .db #0x00 ; 0
+ .db #0xdd ; 221
+ .db #0x74 ; 116 't'
+ .db #0x01 ; 1
+ .db #0xc9 ; 201
+ .db #0xdd ; 221
+ .db #0x34 ; 52 '4'
+ .db #0x03 ; 3
+ .db #0xc9 ; 201
+ .db #0x1f ; 31
+ .db #0xcd ; 205
+ .db #0xd2 ; 210
+ .db #0x0b ; 11
+ .db #0xcb ; 203
+ .db #0x10 ; 16
+ .db #0xdc ; 220
+ .db #0xbf ; 191
+ .db #0x0b ; 11
+ .db #0xcb ; 203
+ .db #0x91 ; 145
+ .db #0xcd ; 205
+ .db #0xc7 ; 199
+ .db #0x0b ; 11
+ .db #0x18 ; 24
+ .db #0xd9 ; 217
+ .db #0x7e ; 126
+ .db #0x32 ; 50 '2'
+ .db #0x6a ; 106 'j'
+ .db #0x0e ; 14
+ .db #0x23 ; 35
+ .db #0xcb ; 203
+ .db #0xa9 ; 169
+ .db #0xc9 ; 201
+ .db #0x7e ; 126
+ .db #0xfd ; 253
+ .db #0x77 ; 119 'w'
+ .db #0x05 ; 5
+ .db #0x23 ; 35
+ .db #0x7e ; 126
+ .db #0xfd ; 253
+ .db #0x77 ; 119 'w'
+ .db #0x09 ; 9
+ .db #0x23 ; 35
+ .db #0xc9 ; 201
+ .db #0xe6 ; 230
+ .db #0x0f ; 15
+ .db #0xdd ; 221
+ .db #0x96 ; 150
+ .db #0x02 ; 2
+ .db #0x30 ; 48 '0'
+ .db #0x01 ; 1
+ .db #0xaf ; 175
+ .db #0xfd ; 253
+ .db #0x77 ; 119 'w'
+ .db #0x01 ; 1
+ .db #0xc9 ; 201
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x11 ; 17
+ .db #0x05 ; 5
+ .db #0x00 ; 0
+ .db #0x19 ; 25
+ .db #0x11 ; 17
+ .db #0xb1 ; 177
+ .db #0x0c ; 12
+ .db #0xed ; 237
+ .db #0xa0 ; 160
+ .db #0xed ; 237
+ .db #0xa0 ; 160
+ .db #0x11 ; 17
+ .db #0x04 ; 4
+ .db #0x00 ; 0
+ .db #0x19 ; 25
+ .db #0x5f ; 95
+ .db #0x16 ; 22
+ .db #0x00 ; 0
+ .db #0x19 ; 25
+ .db #0x19 ; 25
+ .db #0x5e ; 94
+ .db #0x23 ; 35
+ .db #0x56 ; 86 'V'
+ .db #0x1a ; 26
+ .db #0x13 ; 19
+ .db #0xed ; 237
+ .db #0x53 ; 83 'S'
+ .db #0x6d ; 109 'm'
+ .db #0x0c ; 12
+ .db #0x32 ; 50 '2'
+ .db #0x5d ; 93
+ .db #0x0c ; 12
+ .db #0x3d ; 61
+ .db #0x32 ; 50 '2'
+ .db #0x5a ; 90 'Z'
+ .db #0x0c ; 12
+ .db #0xaf ; 175
+ .db #0x32 ; 50 '2'
+ .db #0x62 ; 98 'b'
+ .db #0x0c ; 12
+ .db #0x21 ; 33
+ .db #0x24 ; 36
+ .db #0x0e ; 14
+ .db #0x11 ; 17
+ .db #0x25 ; 37
+ .db #0x0e ; 14
+ .db #0x01 ; 1
+ .db #0x0a ; 10
+ .db #0x00 ; 0
+ .db #0x36 ; 54 '6'
+ .db #0x00 ; 0
+ .db #0xed ; 237
+ .db #0xb0 ; 176
+ .db #0x2a ; 42
+ .db #0xb1 ; 177
+ .db #0x0c ; 12
+ .db #0x5e ; 94
+ .db #0x23 ; 35
+ .db #0x56 ; 86 'V'
+ .db #0x13 ; 19
+ .db #0xed ; 237
+ .db #0x53 ; 83 'S'
+ .db #0x2b ; 43
+ .db #0x0e ; 14
+ .db #0xed ; 237
+ .db #0x53 ; 83 'S'
+ .db #0x36 ; 54 '6'
+ .db #0x0e ; 14
+ .db #0xed ; 237
+ .db #0x53 ; 83 'S'
+ .db #0x41 ; 65 'A'
+ .db #0x0e ; 14
+ .db #0xc9 ; 201
+ .db #0xed ; 237
+ .db #0x73 ; 115 's'
+ .db #0x1a ; 26
+ .db #0x0d ; 13
+ .db #0xaf ; 175
+ .db #0x32 ; 50 '2'
+ .db #0x46 ; 70 'F'
+ .db #0x0e ; 14
+ .db #0x32 ; 50 '2'
+ .db #0x52 ; 82 'R'
+ .db #0x0e ; 14
+ .db #0x32 ; 50 '2'
+ .db #0x5e ; 94
+ .db #0x0e ; 14
+ .db #0x3e ; 62
+ .db #0x3f ; 63
+ .db #0x32 ; 50 '2'
+ .db #0x6e ; 110 'n'
+ .db #0x0e ; 14
+ .db #0xc3 ; 195
+ .db #0xfc ; 252
+ .db #0x0c ; 12
+ .db #0xed ; 237
+ .db #0x73 ; 115 's'
+ .db #0x1a ; 26
+ .db #0x0d ; 13
+ .db #0x3e ; 62
+ .db #0x00 ; 0
+ .db #0x3c ; 60
+ .db #0xfe ; 254
+ .db #0x01 ; 1
+ .db #0xc2 ; 194
+ .db #0xca ; 202
+ .db #0x0c ; 12
+ .db #0x3e ; 62
+ .db #0x00 ; 0
+ .db #0xd6 ; 214
+ .db #0x01 ; 1
+ .db #0x38 ; 56 '8'
+ .db #0x05 ; 5
+ .db #0x32 ; 50 '2'
+ .db #0x62 ; 98 'b'
+ .db #0x0c ; 12
+ .db #0x18 ; 24
+ .db #0x44 ; 68 'D'
+ .db #0x21 ; 33
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0xaf ; 175
+ .db #0x32 ; 50 '2'
+ .db #0x24 ; 36
+ .db #0x0e ; 14
+ .db #0x32 ; 50 '2'
+ .db #0x2f ; 47
+ .db #0x0e ; 14
+ .db #0x32 ; 50 '2'
+ .db #0x3a ; 58
+ .db #0x0e ; 14
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x1f ; 31
+ .db #0x38 ; 56 '8'
+ .db #0x06 ; 6
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x66 ; 102 'f'
+ .db #0x6f ; 111 'o'
+ .db #0x18 ; 24
+ .db #0xeb ; 235
+ .db #0x1f ; 31
+ .db #0x47 ; 71 'G'
+ .db #0xcb ; 203
+ .db #0x18 ; 24
+ .db #0x30 ; 48 '0'
+ .db #0x07 ; 7
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x32 ; 50 '2'
+ .db #0x92 ; 146
+ .db #0x0c ; 12
+ .db #0x18 ; 24
+ .db #0x02 ; 2
+ .db #0x3e ; 62
+ .db #0x00 ; 0
+ .db #0x32 ; 50 '2'
+ .db #0x62 ; 98 'b'
+ .db #0x0c ; 12
+ .db #0xcb ; 203
+ .db #0x18 ; 24
+ .db #0x11 ; 17
+ .db #0x29 ; 41
+ .db #0x0e ; 14
+ .db #0xed ; 237
+ .db #0xa0 ; 160
+ .db #0xed ; 237
+ .db #0xa0 ; 160
+ .db #0x11 ; 17
+ .db #0x34 ; 52 '4'
+ .db #0x0e ; 14
+ .db #0xed ; 237
+ .db #0xa0 ; 160
+ .db #0xed ; 237
+ .db #0xa0 ; 160
+ .db #0x11 ; 17
+ .db #0x3f ; 63
+ .db #0x0e ; 14
+ .db #0xed ; 237
+ .db #0xa0 ; 160
+ .db #0xed ; 237
+ .db #0xa0 ; 160
+ .db #0x22 ; 34
+ .db #0x6d ; 109 'm'
+ .db #0x0c ; 12
+ .db #0x11 ; 17
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0xd9 ; 217
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0x24 ; 36
+ .db #0x0e ; 14
+ .db #0xcd ; 205
+ .db #0x1d ; 29
+ .db #0x0d ; 13
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0x2f ; 47
+ .db #0x0e ; 14
+ .db #0xcd ; 205
+ .db #0x1d ; 29
+ .db #0x0d ; 13
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0x3a ; 58
+ .db #0x0e ; 14
+ .db #0xcd ; 205
+ .db #0x1d ; 29
+ .db #0x0d ; 13
+ .db #0xaf ; 175
+ .db #0x32 ; 50 '2'
+ .db #0x5a ; 90 'Z'
+ .db #0x0c ; 12
+ .db #0x11 ; 17
+ .db #0x71 ; 113 'q'
+ .db #0x0e ; 14
+ .db #0xd9 ; 217
+ .db #0x0e ; 14
+ .db #0xe0 ; 224
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0x24 ; 36
+ .db #0x0e ; 14
+ .db #0xfd ; 253
+ .db #0x21 ; 33
+ .db #0x45 ; 69 'E'
+ .db #0x0e ; 14
+ .db #0xcd ; 205
+ .db #0x93 ; 147
+ .db #0x0d ; 13
+ .db #0xcb ; 203
+ .db #0x39 ; 57 '9'
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0x2f ; 47
+ .db #0x0e ; 14
+ .db #0xfd ; 253
+ .db #0x21 ; 33
+ .db #0x51 ; 81 'Q'
+ .db #0x0e ; 14
+ .db #0xcd ; 205
+ .db #0x93 ; 147
+ .db #0x0d ; 13
+ .db #0xcb ; 203
+ .db #0x19 ; 25
+ .db #0xdd ; 221
+ .db #0x21 ; 33
+ .db #0x3a ; 58
+ .db #0x0e ; 14
+ .db #0xfd ; 253
+ .db #0x21 ; 33
+ .db #0x5d ; 93
+ .db #0x0e ; 14
+ .db #0xcd ; 205
+ .db #0x93 ; 147
+ .db #0x0d ; 13
+ .db #0x79 ; 121 'y'
+ .db #0xcd ; 205
+ .db #0x52 ; 82 'R'
+ .db #0x0b ; 11
+ .db #0x31 ; 49 '1'
+ .db #0x45 ; 69 'E'
+ .db #0x0e ; 14
+ .db #0x01 ; 1
+ .db #0x80 ; 128
+ .db #0xf6 ; 246
+ .db #0x3e ; 62
+ .db #0xc0 ; 192
+ .db #0x11 ; 17
+ .db #0xf6 ; 246
+ .db #0xf4 ; 244
+ .db #0xed ; 237
+ .db #0x79 ; 121 'y'
+ .db #0xe1 ; 225
+ .db #0x42 ; 66 'B'
+ .db #0xed ; 237
+ .db #0x69 ; 105 'i'
+ .db #0x43 ; 67 'C'
+ .db #0xed ; 237
+ .db #0x71 ; 113 'q'
+ .db #0x42 ; 66 'B'
+ .db #0xed ; 237
+ .db #0x61 ; 97 'a'
+ .db #0x43 ; 67 'C'
+ .db #0xed ; 237
+ .db #0x49 ; 73 'I'
+ .db #0xed ; 237
+ .db #0x79 ; 121 'y'
+ .db #0xc9 ; 201
+ .db #0x31 ; 49 '1'
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0xc9 ; 201
+ .db #0xdd ; 221
+ .db #0x7e ; 126
+ .db #0x00 ; 0
+ .db #0xd6 ; 214
+ .db #0x01 ; 1
+ .db #0x38 ; 56 '8'
+ .db #0x04 ; 4
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x00 ; 0
+ .db #0xc9 ; 201
+ .db #0xdd ; 221
+ .db #0x6e ; 110 'n'
+ .db #0x05 ; 5
+ .db #0xdd ; 221
+ .db #0x66 ; 102 'f'
+ .db #0x06 ; 6
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x47 ; 71 'G'
+ .db #0xe6 ; 230
+ .db #0x3f ; 63
+ .db #0xd6 ; 214
+ .db #0x3c ; 60
+ .db #0x38 ; 56 '8'
+ .db #0x0a ; 10
+ .db #0x3d ; 61
+ .db #0x28 ; 40
+ .db #0x42 ; 66 'B'
+ .db #0x3d ; 61
+ .db #0x28 ; 40
+ .db #0x46 ; 70 'F'
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x18 ; 24
+ .db #0x02 ; 2
+ .db #0xc6 ; 198
+ .db #0x54 ; 84 'T'
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x01 ; 1
+ .db #0xcb ; 203
+ .db #0x10 ; 16
+ .db #0x38 ; 56 '8'
+ .db #0x0e ; 14
+ .db #0xdd ; 221
+ .db #0x7e ; 126
+ .db #0x09 ; 9
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x07 ; 7
+ .db #0xdd ; 221
+ .db #0x7e ; 126
+ .db #0x0a ; 10
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x08 ; 8
+ .db #0x18 ; 24
+ .db #0x1c ; 28
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0xd9 ; 217
+ .db #0x6f ; 111 'o'
+ .db #0x26 ; 38
+ .db #0x00 ; 0
+ .db #0x19 ; 25
+ .db #0x4e ; 78 'N'
+ .db #0x23 ; 35
+ .db #0x46 ; 70 'F'
+ .db #0x0a ; 10
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x03 ; 3
+ .db #0x03 ; 3
+ .db #0xdd ; 221
+ .db #0x71 ; 113 'q'
+ .db #0x07 ; 7
+ .db #0xdd ; 221
+ .db #0x70 ; 112 'p'
+ .db #0x08 ; 8
+ .db #0xdd ; 221
+ .db #0x71 ; 113 'q'
+ .db #0x09 ; 9
+ .db #0xdd ; 221
+ .db #0x70 ; 112 'p'
+ .db #0x0a ; 10
+ .db #0xd9 ; 217
+ .db #0xdd ; 221
+ .db #0x36 ; 54 '6'
+ .db #0x02 ; 2
+ .db #0x00 ; 0
+ .db #0xcb ; 203
+ .db #0x10 ; 16
+ .db #0x30 ; 48 '0'
+ .db #0x10 ; 16
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x00 ; 0
+ .db #0x18 ; 24
+ .db #0x09 ; 9
+ .db #0x78 ; 120 'x'
+ .db #0x17 ; 23
+ .db #0x17 ; 23
+ .db #0x17 ; 23
+ .db #0xe6 ; 230
+ .db #0x03 ; 3
+ .db #0xdd ; 221
+ .db #0x77 ; 119 'w'
+ .db #0x00 ; 0
+ .db #0xdd ; 221
+ .db #0x75 ; 117 'u'
+ .db #0x05 ; 5
+ .db #0xdd ; 221
+ .db #0x74 ; 116 't'
+ .db #0x06 ; 6
+ .db #0xc9 ; 201
+ .db #0xdd ; 221
+ .db #0x6e ; 110 'n'
+ .db #0x07 ; 7
+ .db #0xdd ; 221
+ .db #0x66 ; 102 'f'
+ .db #0x08 ; 8
+ .db #0x7e ; 126
+ .db #0x47 ; 71 'G'
+ .db #0x23 ; 35
+ .db #0x1f ; 31
+ .db #0x38 ; 56 '8'
+ .db #0x1c ; 28
+ .db #0x1f ; 31
+ .db #0x1f ; 31
+ .db #0x30 ; 48 '0'
+ .db #0x0c ; 12
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x66 ; 102 'f'
+ .db #0x6f ; 111 'o'
+ .db #0xdd ; 221
+ .db #0x75 ; 117 'u'
+ .db #0x07 ; 7
+ .db #0xdd ; 221
+ .db #0x74 ; 116 't'
+ .db #0x08 ; 8
+ .db #0x18 ; 24
+ .db #0xea ; 234
+ .db #0xcb ; 203
+ .db #0xd1 ; 209
+ .db #0xcd ; 205
+ .db #0xf8 ; 248
+ .db #0x0d ; 13
+ .db #0xfd ; 253
+ .db #0x77 ; 119 'w'
+ .db #0x01 ; 1
+ .db #0xcb ; 203
+ .db #0x10 ; 16
+ .db #0x18 ; 24
+ .db #0x26 ; 38
+ .db #0x1f ; 31
+ .db #0xcd ; 205
+ .db #0xf8 ; 248
+ .db #0x0d ; 13
+ .db #0xfd ; 253
+ .db #0x77 ; 119 'w'
+ .db #0x01 ; 1
+ .db #0x16 ; 22
+ .db #0x00 ; 0
+ .db #0xcb ; 203
+ .db #0x10 ; 16
+ .db #0x30 ; 48 '0'
+ .db #0x08 ; 8
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0xcb ; 203
+ .db #0x2f ; 47
+ .db #0x57 ; 87 'W'
+ .db #0xdc ; 220
+ .db #0x00 ; 0
+ .db #0x0e ; 14
+ .db #0x7a ; 122 'z'
+ .db #0xcd ; 205
+ .db #0x08 ; 8
+ .db #0x0e ; 14
+ .db #0xcb ; 203
+ .db #0x10 ; 16
+ .db #0xdc ; 220
+ .db #0x18 ; 24
+ .db #0x0e ; 14
+ .db #0xd9 ; 217
+ .db #0xfd ; 253
+ .db #0x75 ; 117 'u'
+ .db #0x05 ; 5
+ .db #0xfd ; 253
+ .db #0x74 ; 116 't'
+ .db #0x09 ; 9
+ .db #0xd9 ; 217
+ .db #0xdd ; 221
+ .db #0x7e ; 126
+ .db #0x02 ; 2
+ .db #0xdd ; 221
+ .db #0xbe ; 190
+ .db #0x03 ; 3
+ .db #0x28 ; 40
+ .db #0x04 ; 4
+ .db #0xdd ; 221
+ .db #0x34 ; 52 '4'
+ .db #0x02 ; 2
+ .db #0xc9 ; 201
+ .db #0xdd ; 221
+ .db #0x75 ; 117 'u'
+ .db #0x07 ; 7
+ .db #0xdd ; 221
+ .db #0x74 ; 116 't'
+ .db #0x08 ; 8
+ .db #0xdd ; 221
+ .db #0x36 ; 54 '6'
+ .db #0x02 ; 2
+ .db #0x00 ; 0
+ .db #0xc9 ; 201
+ .db #0xe6 ; 230
+ .db #0x0f ; 15
+ .db #0xdd ; 221
+ .db #0x96 ; 150
+ .db #0x04 ; 4
+ .db #0xd0 ; 208
+ .db #0xaf ; 175
+ .db #0xc9 ; 201
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x32 ; 50 '2'
+ .db #0x6a ; 106 'j'
+ .db #0x0e ; 14
+ .db #0xcb ; 203
+ .db #0xa9 ; 169
+ .db #0xc9 ; 201
+ .db #0xd9 ; 217
+ .db #0x26 ; 38
+ .db #0x00 ; 0
+ .db #0xdd ; 221
+ .db #0x86 ; 134
+ .db #0x01 ; 1
+ .db #0x6f ; 111 'o'
+ .db #0xcb ; 203
+ .db #0x25 ; 37
+ .db #0x19 ; 25
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0x66 ; 102 'f'
+ .db #0x6f ; 111 'o'
+ .db #0xd9 ; 217
+ .db #0xc9 ; 201
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0xd9 ; 217
+ .db #0x4f ; 79 'O'
+ .db #0xd9 ; 217
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0xd9 ; 217
+ .db #0x47 ; 71 'G'
+ .db #0x09 ; 9
+ .db #0xd9 ; 217
+ .db #0xc9 ; 201
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x08 ; 8
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x00 ; 0
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x01 ; 1
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x09 ; 9
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x02 ; 2
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x03 ; 3
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x0a ; 10
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x04 ; 4
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x05 ; 5
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x06 ; 6
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x0d ; 13
+ .db #0x07 ; 7
+ .db #0x00 ; 0
+ .db #0x19 ; 25
+ .db #0x0d ; 13
+ .db #0xee ; 238
+ .db #0x0e ; 14
+ .db #0x18 ; 24
+ .db #0x0e ; 14
+ .db #0x4d ; 77 'M'
+ .db #0x0d ; 13
+ .db #0x8e ; 142
+ .db #0x0c ; 12
+ .db #0xda ; 218
+ .db #0x0b ; 11
+ .db #0x2f ; 47
+ .db #0x0b ; 11
+ .db #0x8f ; 143
+ .db #0x0a ; 10
+ .db #0xf7 ; 247
+ .db #0x09 ; 9
+ .db #0x68 ; 104 'h'
+ .db #0x09 ; 9
+ .db #0xe1 ; 225
+ .db #0x08 ; 8
+ .db #0x61 ; 97 'a'
+ .db #0x08 ; 8
+ .db #0xe9 ; 233
+ .db #0x07 ; 7
+ .db #0x77 ; 119 'w'
+ .db #0x07 ; 7
+ .db #0x0c ; 12
+ .db #0x07 ; 7
+ .db #0xa7 ; 167
+ .db #0x06 ; 6
+ .db #0x47 ; 71 'G'
+ .db #0x06 ; 6
+ .db #0xed ; 237
+ .db #0x05 ; 5
+ .db #0x98 ; 152
+ .db #0x05 ; 5
+ .db #0x47 ; 71 'G'
+ .db #0x05 ; 5
+ .db #0xfc ; 252
+ .db #0x04 ; 4
+ .db #0xb4 ; 180
+ .db #0x04 ; 4
+ .db #0x70 ; 112 'p'
+ .db #0x04 ; 4
+ .db #0x31 ; 49 '1'
+ .db #0x04 ; 4
+ .db #0xf4 ; 244
+ .db #0x03 ; 3
+ .db #0xbc ; 188
+ .db #0x03 ; 3
+ .db #0x86 ; 134
+ .db #0x03 ; 3
+ .db #0x53 ; 83 'S'
+ .db #0x03 ; 3
+ .db #0x24 ; 36
+ .db #0x03 ; 3
+ .db #0xf6 ; 246
+ .db #0x02 ; 2
+ .db #0xcc ; 204
+ .db #0x02 ; 2
+ .db #0xa4 ; 164
+ .db #0x02 ; 2
+ .db #0x7e ; 126
+ .db #0x02 ; 2
+ .db #0x5a ; 90 'Z'
+ .db #0x02 ; 2
+ .db #0x38 ; 56 '8'
+ .db #0x02 ; 2
+ .db #0x18 ; 24
+ .db #0x02 ; 2
+ .db #0xfa ; 250
+ .db #0x01 ; 1
+ .db #0xde ; 222
+ .db #0x01 ; 1
+ .db #0xc3 ; 195
+ .db #0x01 ; 1
+ .db #0xaa ; 170
+ .db #0x01 ; 1
+ .db #0x92 ; 146
+ .db #0x01 ; 1
+ .db #0x7b ; 123
+ .db #0x01 ; 1
+ .db #0x66 ; 102 'f'
+ .db #0x01 ; 1
+ .db #0x52 ; 82 'R'
+ .db #0x01 ; 1
+ .db #0x3f ; 63
+ .db #0x01 ; 1
+ .db #0x2d ; 45
+ .db #0x01 ; 1
+ .db #0x1c ; 28
+ .db #0x01 ; 1
+ .db #0x0c ; 12
+ .db #0x01 ; 1
+ .db #0xfd ; 253
+ .db #0x00 ; 0
+ .db #0xef ; 239
+ .db #0x00 ; 0
+ .db #0xe1 ; 225
+ .db #0x00 ; 0
+ .db #0xd5 ; 213
+ .db #0x00 ; 0
+ .db #0xc9 ; 201
+ .db #0x00 ; 0
+ .db #0xbe ; 190
+ .db #0x00 ; 0
+ .db #0xb3 ; 179
+ .db #0x00 ; 0
+ .db #0xa9 ; 169
+ .db #0x00 ; 0
+ .db #0x9f ; 159
+ .db #0x00 ; 0
+ .db #0x96 ; 150
+ .db #0x00 ; 0
+ .db #0x8e ; 142
+ .db #0x00 ; 0
+ .db #0x86 ; 134
+ .db #0x00 ; 0
+ .db #0x7f ; 127
+ .db #0x00 ; 0
+ .db #0x77 ; 119 'w'
+ .db #0x00 ; 0
+ .db #0x71 ; 113 'q'
+ .db #0x00 ; 0
+ .db #0x6a ; 106 'j'
+ .db #0x00 ; 0
+ .db #0x64 ; 100 'd'
+ .db #0x00 ; 0
+ .db #0x5f ; 95
+ .db #0x00 ; 0
+ .db #0x59 ; 89 'Y'
+ .db #0x00 ; 0
+ .db #0x54 ; 84 'T'
+ .db #0x00 ; 0
+ .db #0x50 ; 80 'P'
+ .db #0x00 ; 0
+ .db #0x4b ; 75 'K'
+ .db #0x00 ; 0
+ .db #0x47 ; 71 'G'
+ .db #0x00 ; 0
+ .db #0x43 ; 67 'C'
+ .db #0x00 ; 0
+ .db #0x3f ; 63
+ .db #0x00 ; 0
+ .db #0x3c ; 60
+ .db #0x00 ; 0
+ .db #0x38 ; 56 '8'
+ .db #0x00 ; 0
+ .db #0x35 ; 53 '5'
+ .db #0x00 ; 0
+ .db #0x32 ; 50 '2'
+ .db #0x00 ; 0
+ .db #0x2f ; 47
+ .db #0x00 ; 0
+ .db #0x2d ; 45
+ .db #0x00 ; 0
+ .db #0x2a ; 42
+ .db #0x00 ; 0
+ .db #0x28 ; 40
+ .db #0x00 ; 0
+ .db #0x26 ; 38
+ .db #0x00 ; 0
+ .db #0x24 ; 36
+ .db #0x00 ; 0
+ .db #0x22 ; 34
+ .db #0x00 ; 0
+ .db #0x20 ; 32
+ .db #0x00 ; 0
+ .db #0x1e ; 30
+ .db #0x00 ; 0
+ .db #0x1c ; 28
+ .db #0x00 ; 0
+ .db #0x1b ; 27
+ .db #0x00 ; 0
+ .db #0x19 ; 25
+ .db #0x00 ; 0
+ .db #0x18 ; 24
+ .db #0x00 ; 0
+ .db #0x16 ; 22
+ .db #0x00 ; 0
+ .db #0x15 ; 21
+ .db #0x00 ; 0
+ .db #0x14 ; 20
+ .db #0x00 ; 0
+ .db #0x13 ; 19
+ .db #0x00 ; 0
+ .db #0x12 ; 18
+ .db #0x00 ; 0
+ .db #0x11 ; 17
+ .db #0x00 ; 0
+ .db #0x10 ; 16
+ .db #0x00 ; 0
+ .db #0x0f ; 15
+ .db #0x00 ; 0
+ .db #0x0e ; 14
+ .db #0x00 ; 0
+ .db #0x0d ; 13
+ .db #0x00 ; 0
+ .db #0x0d ; 13
+ .db #0x00 ; 0
+ .db #0x0c ; 12
+ .db #0x00 ; 0
+ .db #0x0b ; 11
+ .db #0x00 ; 0
+ .db #0x0b ; 11
+ .db #0x00 ; 0
+ .db #0x0a ; 10
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x00 ; 0
+ .db #0x09 ; 9
+ .db #0x00 ; 0
+ .db #0x08 ; 8
+ .db #0x00 ; 0
+ .db #0x08 ; 8
+ .db #0x00 ; 0
+ .db #0x07 ; 7
+ .db #0x00 ; 0
+ .db #0x07 ; 7
+ .db #0x00 ; 0
+ .db #0x07 ; 7
+ .db #0x00 ; 0
+ .db #0x06 ; 6
+ .db #0x00 ; 0
+ .db #0x06 ; 6
+ .db #0x00 ; 0
+ .db #0x06 ; 6
+ .db #0x00 ; 0
+ .db #0x05 ; 5
+ .db #0x00 ; 0
+ .db #0x05 ; 5
+ .db #0x00 ; 0
+ .db #0x05 ; 5
+ .db #0x00 ; 0
+ .db #0x04 ; 4
+ .db #0x00 ; 0
+ .db #0x04 ; 4
+ .db #0x00 ; 0
+ .db #0x04 ; 4
+ .db #0x00 ; 0
+ .db #0x04 ; 4
+ .db #0x00 ; 0
+ .db #0x04 ; 4
+ .db #0x00 ; 0
+ .db #0x03 ; 3
+ .db #0x00 ; 0
+ .db #0x03 ; 3
+ .db #0x00 ; 0
+ .db #0x03 ; 3
+ .db #0x00 ; 0
+ .db #0x03 ; 3
+ .db #0x00 ; 0
+ .db #0x03 ; 3
+ .db #0x00 ; 0
+ .db #0x02 ; 2
+ .db #0x00 ; 0
+ .db #0x7d ; 125
+ .db #0x87 ; 135
+ .db #0x87 ; 135
+ .db #0x87 ; 135
+ .db #0x4f ; 79 'O'
+ .db #0x06 ; 6
+ .db #0x00 ; 0
+ .db #0x21 ; 33
+ .db #0xde ; 222
+ .db #0x0b ; 11
+ .db #0x09 ; 9
+ .db #0x7e ; 126
+ .db #0x23 ; 35
+ .db #0xb6 ; 182
+ .db #0x6f ; 111 'o'
+ .db #0xc9 ; 201
+ .area _INITIALIZER
+ .area _CABS (ABS)
diff --git a/lib/plw/plw_player.c b/lib/plw/plw_player.c
new file mode 100644
index 0000000..4ab2598
--- /dev/null
+++ b/lib/plw/plw_player.c
@@ -0,0 +1,3 @@
+#define LOCAL
+#include "player/plw_player.h"
+
diff --git a/lib/plw/plw_stop.z80 b/lib/plw/plw_stop.z80
new file mode 100644
index 0000000..6bb3daf
--- /dev/null
+++ b/lib/plw/plw_stop.z80
@@ -0,0 +1,6 @@
+.globl _PLW_Stop
+
+PLY_LW_STOP = 0x0b06 + 0x6
+
+_PLW_Stop::
+ jp PLY_LW_STOP