SPRITE_HAUTEUR EQU 77
SPRITE_LARGEUR EQU 19
SPRITE_ADR_ECRAN EQU &5B30
tailleraster1 EQU 200
gfx_fonte EQU &7F00
TEMPO EQU 3
TEMPO2 EQU 2
FRAME1 EQU &C000
FRAME2 EQU &C000+1463
FRAME3 EQU &C000+2926
FRAME4 EQU &C000+4389
FRAME5 EQU &C000+5852
FRAME6 EQU &C000+7315
FRAME7 EQU &C000+8778
FRAME8 EQU &C000+10241
ORG &7F80
;WRITE DIRECT "PRS.BIN"
CALL AFF_COULEURS
CALL OUT_OVERSCAN
CALL EFFET_RIDEAU_R6_VERS_LE_BAS
CALL TIR_LANGUE:LD A,25:CALL DELAY
CALL LESRASTERS
CALL TIR_LANGUE:LD A,25:CALL DELAY
CALL EFFET_RIDEAU_R6_VERS_LE_HAUT
CALL FRAME
CALL OUT_NORMAL
RET
;------------------------------------------------------------------------------
; LES RASTERS
;------------------------------------------------------------------------------
LESRASTERS
CALL &BB00
DI ; Desactiver les interruptions
LD HL,(&38) ; Lire l'ancienne interruption
LD (Sauver),HL ; Sauvegarder la valeur 16 bits
LD HL,&C9FB ; Registre 16 bits EI (&FB) + RET (&C9)
LD (&38),HL ; Ecrire en &0038 et &0039 le contenu du registre HL
EI ; Interruption autorisees
.Programme
;raster rotation vers le bas
LD A,(Raster1+tailleraster1-1)
LD HL,Raster1+tailleraster1-2
LD DE,Raster1+tailleraster1-1
LD BC,tailleraster1-1
LDDR
LD (Raster1),A
LD B,&F5 ; Se connecter au PPI/8255 port B accessible via &F5xx
.Balayage
IN A,(C) ; Lire le contenu
RRA ; On teste si le bit 0 = 1
JP nc,Balayage ; Si le bit 0 = 0 on boucle jusqu'a la fin du balayage
; On est en haut de l'ecran, on peut continuer le programme
;HALT ; Attendre interruption 1
;HALT ; Attendre interruption 2
DS 10 ; Debut de ligne
LD B,&7F ; On selection le Gate Array
LD HL,Raster ; HL pointe sur la table de couleurs
.BoucleRaster
LD a,(hl) ; On charge la couleur dans A
CP &00 ; Si A=0 alors
JP z,Touche ; Saute au test clavier
LD C,14
OUT (C),C ; Selection encre 14
OUT (C),A ; Ecrire la couleur
INC HL ; Couleur suivante dans le tableau
DS 42 ; Attendre fin de ligne
JP BoucleRaster
; Test touche
.Touche
LD BC,&F40E
OUT (C),C
LD BC,&F6C0
OUT (C),C
XOR A
OUT (C),A
LD BC,&F792
OUT (C),C
LD BC,&F645 ;ligne 5
OUT (C),C
LD B,&F4
IN A,(C)
LD BC,&F782
OUT (C),C
LD BC,&F600
OUT (C),C
RLA ;Charge dans A la valeur du bit 7 (touche ESPACE)
JR NC,Sortir
LD BC,&F40E
OUT (C),C
LD BC,&F6C0
OUT (C),C
XOR A
OUT (C),A
LD BC,&F792
OUT (C),C
LD BC,&F649 ;ligne 9
OUT (C),C
LD B,&F4
IN A,(C)
LD BC,&F782
OUT (C),C
LD BC,&F600
OUT (C),C
RLA ;Charge dans A la valeur du bit 7 (touche DEL)
RLA ;Charge dans A la valeur du bit 6 (touche JOY_FIRE0)
RLA ;Charge dans A la valeur du bit 5 (touche JOY_FIRE1 Z)
RLA ;Charge dans A la valeur du bit 4 (touche JOY_FIRE2 X)
JP C,Programme ;Si TIR du joystick n'a pas etait enfonce on boucle
.Sortir
;retour au BASIC
DI ; Desactiver les interruptions
LD HL,(Sauver) ; Restauration des anciennes interruptions
LD (&38),hl ; Ecrire
EI ; Interruption autorisees
RET
.Sauver
DW #0000
.Raster
;00 = &54 noir
;01 = &44 bleu
;02 = &55 bleu vif
;03 = &5C rouge fonce
;04 = &58 magenta
;05 = &5D mauve
;06 = &4C rouge vif
;07 = &45 pourpre
;08 = &4D magenta vif
;09 = &56 vert
;10 = &46 turquoise
;11 = &57 bleu ciel
;12 = &5E jaune
;13 = &40 gris
;14 = &5F bleu pastel
;15 = &4E orange
;16 = &47 rose
;17 = &4F magenta pastel
;18 = &52 vert vif
;19 = &42 vert marin
;20 = &53 turquoise vif
;21 = &5A vert citron
;22 = &59 vert pastel
;23 = &5B turquoise pastel
;24 = &4A jaune vif
;25 = &43 jaune pastel
;26 = &4B blanc
DB &43 ; jaune pastel (mon encre 14)
.Raster1
;raster 8x25=200
DB &5E,&5E,&4C,&5E,&5E,&4C,&5E,&4C
DB &4C,&4C,&4C,&45,&4C,&4C,&45,&4C
DB &45,&45,&4C,&45,&45,&45,&45,&4D
DB &45,&45,&4D,&45,&4D,&4D,&45,&4D
DB &4D,&4F,&4D,&4D,&4F,&4D,&4F,&4F
DB &4D,&4F,&4F,&4F,&47,&4F,&4F,&47
DB &4F,&47,&47,&4F,&47,&47,&47,&47
DB &47,&47,&47,&4E,&47,&47,&4E,&47
DB &4E,&4E,&47,&4E,&4E,&5E,&4E,&4E
DB &5E,&4E,&5E,&5E,&4E,&5E,&5E,&5E
DB &5E,&5E,&56,&5E,&5E,&56,&5E,&56
DB &56,&5E,&56,&56,&56,&5E,&56,&56
DB &56,&56,&4E,&56,&56,&56,&56,&4E
DB &56,&56,&56,&4E,&56,&56,&4E,&56
DB &4E,&4E,&4E,&52,&4E,&4E,&52,&4E
DB &52,&52,&4E,&52,&52,&52,&52,&59
DB &52,&52,&59,&52,&59,&59,&52,&59
DB &59,&5B,&59,&59,&5B,&59,&5B,&5B
DB &59,&5B,&5B,&5B,&5B,&5B,&4B,&5B
DB &5B,&4B,&5B,&4B,&4B,&5B,&4B,&4B
DB &4B,&4B,&4B,&53,&4B,&4B,&53,&4B
DB &53,&53,&4B,&53,&53,&5F,&53,&53
DB &5F,&53,&5F,&5F,&53,&5F,&5F,&5F
DB &5F,&5F,&46,&5F,&5F,&46,&5F,&46
DB &46,&5F,&46,&46,&46,&5F,&46,&46
DB &43 ; jaune pastel (mon encre 14)
DB 0 ;fin
; -----------------------------------------------------------------------------
; Tirage langue
; -----------------------------------------------------------------------------
TIR_LANGUE
LD A,25:CALL DELAY:LD HL,FRAME1:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME2:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME3:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME4:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME5:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME6:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME7:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME8:CALL AFF_SPRITE
LD A,25:CALL DELAY:LD HL,FRAME8:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME7:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME6:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME5:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME4:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME3:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME2:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME1:CALL AFF_SPRITE
RET
; -----------------------------------------------------------------------------
; Palette
; -----------------------------------------------------------------------------
AFF_COULEURS
;charger les couleurs
LD HL,couleurs
XOR A
loopcouleurs
PUSH AF
PUSH HL
LD B,(HL)
LD C,B
CALL &BC32
POP HL
INC HL
POP AF
INC A
CP 16
JR NZ,loopcouleurs
RET
.couleurs
DEFB 0,1,2,3,4,5,6,9,13,14,15,16,18,23,25,26
; -----------------------------------------------------------------------------
; OUT OVERSCAN AVEC R6=0
; -----------------------------------------------------------------------------
OUT_OVERSCAN
LD HL,OUT_OVERSCAN_R6_A_ZERO
LD BC,&BC00
LOOPR6
LD A,(HL)
AND A
RET Z
OUT (C),A
INC B
INC HL
LD A,(HL)
OUT(C),A
INC HL
DEC B
JR LOOPR6
OUT_OVERSCAN_R6_A_ZERO
DB &01,&30 ;largeur
DB &02,&32
DB &06,&00
DB &07,&23
DB &0C,&0D ;page 32 Ko
DB &0D,&00 ;offset a zero
DB &00,&00 ;fin de la routine
; -----------------------------------------------------------------------------
; RIDEAU DESCENDANT OVERSCAN AVEC R6=&00 a &22 inclus
; -----------------------------------------------------------------------------
EFFET_RIDEAU_R6_VERS_LE_BAS
XOR A
looprideau
LD (R6rideau+1),A
CALL FRAME:CALL FRAME
LD BC,&BC06
OUT(C),C
R6rideau
LD BC,&BD00 ;01 XX BC
OUT(C),C
INC A
CP &23 ;Ira de &00 a &22
JR NZ,looprideau
RET
; -----------------------------------------------------------------------------
; RIDEAU DESCENDANT OVERSCAN AVEC R6=&00 a &22 inclus
; -----------------------------------------------------------------------------
EFFET_RIDEAU_R6_VERS_LE_HAUT
LD A,&22
looprideauH
LD (R6rideauH+1),A
CALL FRAME:CALL FRAME
LD BC,&BC06
OUT(C),C
R6rideauH
LD BC,&BD00 ;01 XX BC
OUT(C),C
DEC A
CP &FF ;Ira de &22 a &00
JR NZ,looprideauH
RET
;------------------------------------------------------------------------------
; OUT NORMAL
;------------------------------------------------------------------------------
OUT_NORMAL
;OUT R1=40
largeur
LD BC,&BC01
OUT (C),C
LD BC,&BD28
OUT (C),C
;hauteur
;LD BC,&BC06
;OUT (C),C
;LD BC,&BD19
;OUT (C),C
;decalage horizontal
LD BC,&BC02
OUT (C),C
LD BC,&BD2E
OUT (C),C
;decalage vertical
LD BC,&BC07
OUT (C),C
LD BC,&BD1E
OUT (C),C
;ecran 17 ko (&C000 a &FFFF)
LD BC,&BC0C
OUT (C),C
LD BC,&BD3C
OUT (C),C
;debut offset (en &C000)
LD BC,&BC0D
OUT (C),C
LD BC,&BD00
OUT (C),C
XOR A
CALL &BC0E ;mode 0
LD BC,&0101
CALL &BC38 ;border 1
;charger les couleurs
LD HL,couleursloading
XOR A
loopcouleursloading
PUSH AF
PUSH HL
LD B,(HL)
LD C,B
CALL &BC32
POP HL
INC HL
POP AF
INC A
CP 16
JR NZ,loopcouleursloading
LD HL,waitloading
LD A,40
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,22 ;hauteur a afficher
LD DE,&C000
CALL AFF_TABLEAU
;EFFET_RIDEAU_R6_VERS_LE_BAS(ecran normal)
XOR A
looprideauN
LD (R6rideauN+1),A
CALL FRAME:CALL FRAME
LD BC,&BC06
OUT(C),C
R6rideauN
LD BC,&BD00 ;01 XX BC
OUT(C),C
INC A
CP &1A ;Ira de &00 a &19 (25 lignes)
JR NZ,looprideauN
RET
.couleursloading
DEFB 1,23,1,10,11,20,9,12,6,3,24,15,26,13,0,16
.waitloading
DEFB " AFFF "
DEFB " AFFFAF FAF "
DEFB " AF ACC AF F "
DEFB " AF FACC AC CACC FFAF "
DEFB " AF FAC AG GAG C C "
DEFB " AFFFAC CAGGG AG GAF "
DEFB " AF AC G GACAF "
DEFB " AF ACC G DDDD AGAFF F "
DEFB " AF AC DDDDDDDDDD AGAC FF "
DEFB " AC AGGG DDDDDDDDDDDD AG C "
DEFB "AFFFAC DDDDDEEEEDDDDDD AG CAFF "
DEFB "AF AGGG DDDDDEEBEEEDDDDDDD GAF F"
DEFB "AC DDDDDEBEEEBEBDDDBDDD AC F"
DEFB "AC DDDDDEEEEEEEEBCDBDDDDD AG C"
DEFB "ACGGG DDDDDDDDDDBBBBBBBBBBBDDDDDDDD AGG "
DEFB " DDDDDEEEEEEEEBCDBDDDDD "
DEFB " DDDDDEBEEEBEBDDDBDDD "
DEFB " DDDDDEEBEEEDDDDDDD "
DEFB " DDDDDEEEEDDDDDD "
DEFB " DDDDDDDDDDDD "
DEFB " DDDDDDDDDD "
DEFB " DDDD "
;------------------------------------------------------------------------------
;TABLEAU DE TILES 2x8 octets avec exclusion des tiles vident
;------------------------------------------------------------------------------
.AFF_TABLEAU
PUSH AF
PUSH DE
.aff_tableau_largeur
LD A,0 ;longueur a afficher
.aff_tableau2
PUSH AF
LD A,(IX+&00) ;lecture caractere
INC IX
CP 32 ;ne pas afficher les tiles vident
JP Z,aff_tableau1
PUSH DE
CALL aff_TILES8_0 ;affichage caractere
POP DE
.aff_tableau1
INC DE ;decalage 2 octets (largeur d'une tuile)
INC DE
POP AF
DEC A
JR NZ,aff_tableau2
POP HL
LD BC,&0050
ADD HL,BC ;ligne suivante
EX DE,HL
POP AF
DEC A
JR NZ,AFF_TABLEAU
RET
.aff_TILES8_0
LD C,64
SUB C ;A = A-64
PUSH DE ;sauver DE
LD L,A ;L = A
LD H,0 ;H = 0
ADD HL,HL ;*2
ADD HL,HL ;*4
ADD HL,HL ;*8
ADD HL,HL ;*16
LD DE,gfx_fonte
ADD HL,DE ;HL contient l'adresse du tiles
POP DE ;recuperer l'adresse d'affichage a l'ecran
LD A,8 ;Hauteur_du_tile
.aff_TILES8_1
LDI
LDI ;8 pixels = 2 octets
EX DE,HL
LD BC,&07FE ;&800 - 2 octets (largeur ecran - largeur tiles)
ADD HL,BC
JR NC,aff_TILES8_2
LD BC,&C050 ;R1=40 alors &C050 (normal)
ADD HL,BC
.aff_TILES8_2
EX DE,HL
DEC A
JR NZ,aff_TILES8_1
RET
;;------------------------------------------------------------------------------
; DELAY SUBROUTINE
; A = Time
;------------------------------------------------------------------------------
DELAY EI
DELAY_1 LD B,15 ; 15 x 1/300th ms (HALT) = 50ms
DELAY_2 HALT ; Waits 1/300th s
DJNZ DELAY_2 ; Loop for 50ms
DEC A
JR NZ,DELAY_1 ; Loop for A x 50ms
DI
RET
;------------------------------------------------------------------------------
; AFFICHAGE FRAME
;------------------------------------------------------------------------------
AFF_SPRITE
; LD HL,&7EC0+2460
LD DE,SPRITE_ADR_ECRAN
LD A,SPRITE_HAUTEUR ;hauteur
spr_loop2
PUSH AF
PUSH DE
LD BC,SPRITE_LARGEUR ;largeur
LDIR
POP DE
EX DE,HL
CALL conv_ligne_suivante
;CALL FRAME
EX DE,HL
POP AF
DEC A
JR NZ, spr_loop2
RET
conv_ligne_suivante
;HL (adresse ecran)
LD A,H
ADD A,8
LD H,A
AND &38
RET NZ
LD A,H
SUB &40
LD H,A
LD A,L
ADD A,&60 ;si R1=40 alors &50 si R1=41 alors &52 si R1=48 alors &60
LD L,A
RET NC
INC H
LD A,H
AND 7
RET NZ
LD A,H
SUB 8
LD H,A
RET
; -----------------------------------------------------------------------------
; SYNCHRONISATION VBL
; -----------------------------------------------------------------------------
FRAME
PUSH AF
PUSH BC
WAIT_FOR_VBL
LD B,&F5
IN A,(C)
RRA
JR C,WAIT_FOR_VBL+2 ;Boucle tant que la VBL est active
WAIT_FOR_VBL2
IN A,(C)
RRA
JR NC,WAIT_FOR_VBL2 ;Boucle tant que la VBL est inactive
POP BC
POP AF
RET
NOTICE TEXTE n° 2 (92.35 Ko)
LANGUE_SP EQU 1
LANGUE_FR EQU 0
LANGUE_UK EQU 0
gfx_des_tiles EQU &6146 ;lg &800
gfx_des_sprites EQU &6646 ;20eme +&500
ZIC_RAYXAMBER1 EQU &6970 ;lg &0237
ZIC_RAYXAMBER2 EQU &6BB0 ;lg &01C2
ZIC_RAYXAMBER3 EQU &6D80 ;lg &0275
;fin &6FF5
LES_NIVEAUX EQU &C000 ;decompacte
LES_NIVEAUX_PAK EQU &7000 ;compacte lg &0E31
;fin &7E31
gfx_fonte EQU &7F4F ;lg &5B0
;fin &84FF
;CLEVER.DAT deb=&6146 lg=&23BA
load_niveau_courant EQU &8500
memoire_target EQU &85F3
teleporteur1x EQU &85F4
teleporteur1y EQU &85F5
teleporteur2x EQU &85F6
teleporteur2y EQU &85F7
taille_niveau EQU 243
largeur_niveau EQU 20
hauteur_niveau EQU 12
ecran_niveau EQU &C050
ORG &8600
if LANGUE_SP
WRITE DIRECT "CLEVER0.RSX"
endif
if LANGUE_FR
WRITE DIRECT "CLEVER1.RSX"
endif
if LANGUE_UK
WRITE DIRECT "CLEVER2.RSX"
endif
NOLIST
; ****************************
; *** RSX - INITIALISATION ***
; ****************************
.RSX_Init :
LD HL,RSX_Init
LD (HL),&C9 ; Ecrire un RET pour empecher une nouvelle initialisation
LD BC,RSX_Commandes ; BC pointe sur la table des Commandes RSX
LD HL,RSX_Tampon ; HL pointe sur 4 octets libres.
JP &BCD1
.RSX_Tampon :
DEFS 4 ; Tampon de quatre octets.
.RSX_Commandes :
DEFW RSX_Mots_Clefs ; Adresse des mots clefs
JP TILES_16x16_opaque
JP AFFICHAGE_ELEMENT_TRANSPARENT
JP TILE8
JP LEVEL
JP LIVES
JP TARGET
JP DECOR_16x16_SAUVEGARDE
JP DECOR_16x16_RESTAURATION
JP CLS2
JP AFFOHNO
JP AFFDONE
JP AFFGAMEOVER
JP OPTIONS_MENU_BASIC
JP MENU
JP CREDITS
JP INSTRUCTIONS
JP HOWTOPLAY
JP PLAYER_ARKOS
JP PLAYER_ARKOS_OFF
JP AFFICHAGE_LEVEL
JP MESSAGES
JP BADEND
JP DECOMPACK
JP WAITING
JP FIN
.RSX_Mots_Clefs
DEFB "T"+&80 ;T,element,adresse_ecran
DEFB "SP","R"+&80 ;SPR,element,adresse_ecran
DEFB "T","8"+&80 ;T8,caractere,adresse_ecran
DEFB "LEVE","L"+&80 ;LEVEL,dizaine,unite
DEFB "LIVE","S"+&80 ;LIVES,unite
DEFB "TARGE","T"+&80 ;TARGET,centaine,dizaine,unite
DEFB "SA","V"+&80 ;DECORSAVE,adresse_ecran
DEFB "AF","F"+&80 ;DECORAFF,adresse_ecran
DEFB "CLS","2"+&80 ;CLS2
DEFB "OHN","O"+&80 ;OHNO
DEFB "DON","E"+&80 ;DONE
DEFB "LOS","T"+&80 ;LOST
DEFB "MENU","2"+&80 ;MENU2,ligne_active
DEFB "MENU","1"+&80 ;MENU1
DEFB "CREDIT","S"+&80 ;CREDITS
DEFB "INFO","S"+&80 ;INFOS
DEFB "HO","W"+&80 ;HOW
DEFB "ZICO","N"+&80 ;ZICON
DEFB "ZICOF","F"+&80 ;ZICOFF
DEFB "AFFLV","L"+&80 ;AFFLVL,x(0 a 49)
DEFB "MS","G"+&80 ;MSG,x
DEFB "BA","D"+&80 ;BAD
DEFB "UNPAC","K"+&80 ;UNPACK DONNEES NIVEAUX
DEFB "WAI","T"+&80 ;WAIT,x
DEFB "FI","N"+&80
NOP ;Fin de la table.
NOP
NOP
NOP
NOP
NOP
;------------------------------------------------------------------------------
; FIN
;------------------------------------------------------------------------------
.FIN
LD HL,&BE81
LD A,"O"
LD (HL),A
INC HL
LD A,"K"
LD (HL),A
RET
;------------------------------------------------------------------------------
; TEMPORISATION
; A = nb
;------------------------------------------------------------------------------
WAITING
LD A,(IX+&00)
LD B,A
DELAY_2 CALL &BD19
DJNZ DELAY_2
RET
;------------------------------------------------------------------------------
; MAUVAISE FIN
;------------------------------------------------------------------------------
.BADEND
if LANGUE_SP
CALL CLS2
LD HL,BADEND01:LD DE,&C1E0+9:CALL directmini
LD HL,BADEND02:LD DE,&C320+19:CALL directmini
LD HL,BADEND03:LD DE,&C460+12:CALL directmini
LD HL,BADEND04:LD DE,&C5A0+22:CALL directmini
RET
BADEND01
DEFB "HAS TERMINADO TODOS LOS NIVELES" : DB 0
BADEND02
DEFB "PERO HAS HECHO TRAMPA" : DB 0
BADEND03
DEFB "ASI QUE TE QUEDAS SIN PREMIO" : DB 0
BADEND04
DB 34 : DEFB "NO HAGAS TRAMPAS!" : DB 0
endif
if LANGUE_FR
CALL CLS2
LD HL,BADEND01:LD DE,&C1E0+9:CALL directmini
LD HL,BADEND02:LD DE,&C320+24:CALL directmini
LD HL,BADEND03:LD DE,&C460+3:CALL directmini
LD HL,BADEND04:LD DE,&C5A0+18:CALL directmini
RET
BADEND01
DEFB "VOUS AVEZ FINI TOUS LES NIVEAUX" : DB 0
BADEND02
DEFB "MAIS EN TRICHANT" : DB 0
BADEND03
DEFB "DESOLES, PAS D;ECRAN DE FIN POUR VOUS" : DB 0
BADEND04
DEFB "REJOUEZ SANS TRICHER" : DB 0
endif
if LANGUE_UK
CALL CLS2
LD HL,BADEND01:LD DE,&C1E0+12:CALL directmini
LD HL,BADEND02:LD DE,&C320+20:CALL directmini
LD HL,BADEND03:LD DE,&C460+10:CALL directmini
LD HL,BADEND04:LD DE,&C5A0+19:CALL directmini
RET
BADEND01
DEFB "YOU HAVE FINISHED ALL LEVELS" : DB 0
BADEND02
DEFB "BUT YOU HAVE CHEATED" : DB 0
BADEND03
DEFB "SORRY, NO FINAL SCREEN FOR YOU" : DB 0
BADEND04
DEFB "PLAY WITHOUT CHEATING" : DB 0
endif
;------------------------------------------------------------------------------
; LOAD LEVEL
;------------------------------------------------------------------------------
.AFFICHAGE_LEVEL
LD A,(IX+00) ;0 a 49 (numero du niveau)
LD HL,LES_NIVEAUX-taille_niveau
.calculadrniveau
LD DE,taille_niveau
ADD HL,DE
DEC A
CP &FF
JP NZ,calculadrniveau
;transfert des donnees
LD DE,load_niveau_courant
LD BC,taille_niveau
LDIR
;target=0
XOR A
LD (memoire_target),A
;teleporteur 1x 1y 2x 2y =&FF
LD A,&FF
LD (teleporteur1x),A
LD (teleporteur1y),A
LD (teleporteur2x),A
LD (teleporteur2y),A
;affichage du niveau
LD IX,load_niveau_courant
LD DE,ecran_niveau
LD IY,0 ;compteur
LD A,hauteur_niveau
.aff_tableaulvl3
PUSH AF
PUSH DE ; on sauvegarde l'adresse video de la premiere ligne de sprites a afficher
LD A,largeur_niveau
.aff_tableaulvl2
PUSH AF
LD A,(IX+&00)
;sauver les registres pour faire les sous-totaux target et teleporteur
PUSH AF
PUSH IX
PUSH IY
CP 1:CALL Z,TARGET_PLUS
CP 2:CALL Z,TARGET_PLUS
CP 3:CALL Z,TARGET_PLUS
CP 4:CALL Z,TARGET_PLUS
CP 5:CALL Z,TARGET_PLUS
CP 6:CALL Z,TARGET_PLUS
CP 7:CALL Z,TARGET_PLUS
CP 8:CALL Z,TARGET_PLUS
CP 9:CALL Z,TARGET_PLUS
CP 9:CALL Z,TELEPORTEUR
CP 17:CALL Z,TELEPORTEUR
POP IY
POP IX
POP AF
;fin sous-totaux
INC IY ;pour le teleporteur
INC IX
LD L,A
LD H,0
ADD HL,HL ; x2
ADD HL,HL ; x4
ADD HL,HL ; x8
ADD HL,HL ; x16
ADD HL,HL ; x32
ADD HL,HL ; x64 (16x16 = 4 octets x 16)
LD BC,gfx_des_tiles
ADD HL,BC
PUSH DE
CALL TILES_1
POP DE
.aff_tableaulvl1
INC DE ;Case suivante 16 pixels = 4 octets
INC DE
INC DE
INC DE
POP AF
DEC A
JR NZ,aff_tableaulvl2
POP HL
LD BC,&00A0
ADD HL,BC
EX DE,HL ;Ligne suivante
POP AF
DEC A
JR NZ,aff_tableaulvl3
RET
.TARGET_PLUS
LD HL,memoire_target
INC (HL)
RET
.TELEPORTEUR
LD A,(teleporteur1x)
CP &FF
CALL Z,teleporteur1xvide
CP &FE
RET Z ;on traite le premier donc fin
LD A,(teleporteur2x)
CP &FF
CALL Z,teleporteur2xvide
RET
.teleporteur1xvide
PUSH IY
POP IX
LD (teleporteur1x),IX
LD A,&FE
RET
.teleporteur2xvide
PUSH IY
POP IX
LD (teleporteur2x),IX
RET
;------------------------------------------------------------------------------
; HOW TO PLAY
;------------------------------------------------------------------------------
.HOWTOPLAY
CALL CLS2
CALL &BB03
;HOW TO PLAY
LD HL,HOW00:LD DE,&C050+22:CALL directmini
;LADYBUG
LD DE,&C140
LD HL,gfx_des_tiles+768 ;adresse tile 12
CALL TILES_1
LD DE,&C140+4
LD HL,gfx_des_tiles+640 ;adresse tile 10
CALL TILES_1
LD DE,&C140+4 ;adresse ecran
LD HL,gfx_des_sprites ;adresse sprite(0*4*16)
LD B,16
LD C,4
CALL TRAN_SPR_PR
LD HL,HOW01:LD DE,&C140+10:CALL directmini
LD HL,HOW02:LD DE,&C190+10:CALL directmini
LD HL,HOW03:LD DE,&C230:CALL directmini
LD HL,HOW04:LD DE,&C320:CALL directmini
LD HL,HOW05:LD DE,&C410:CALL directmini
LD HL,HOW06:LD DE,&C4B0:CALL directmini
LD HL,HOW07:LD DE,&C5F0:CALL directmini
LD HL,HOW08:LD DE,&C733-3:CALL directmini
;wait
CALL &BB03:CALL &BB06
RET
if LANGUE_SP
HOW00 DEFB "\]] como jugar ]]^": DB 0
HOW01 DEFB "la mariquita ODIA EL AGUA":DB 0
HOW02 DEFB "UN NUEVO MINI HEROE":DB 0
;-------------0123456789012345678901234567890123456789------------
HOW03 DEFB "TU MISION PUEDE PARECER FACIL, HAY QUE"
DEFB "ELIMINAR TODAS LAS HOJAS DE LA PANTALLA." : DB 0
HOW04 DEFB "EL CONTADOR objetivo TE MUESTRA CUANTAS"
DEFB "QUEDAN." : DB 0
HOW05 DEFB "AL PASAR POR LAS PIEDRAS NO TE HUNDIRAS." : DB 0
HOW06 DEFB "NO OLVIDES LEER LAS INSTRUCCIONES PARA"
DEFB "CONOCER LAS CARACTERISTICAS ESPECIFICAS"
DEFB "DE CADA ELEMENTO." : DB 0
HOW07 DEFB "EL JUEGO SE PUEDE USAR CON joystick,"
DEFB "TECLADO qaop O LOS cursores." : DB 0
HOW08 DEFB "m: MUSICA SI/NO esc: SALIR DEL JUEGO" : DB 0
endif
if LANGUE_FR
HOW00 DEFB "\]] comment jouer ]]^": DB 0
HOW01 DEFB "la coccinelle DETESTE L;EAU":DB 0
HOW02 DEFB "UN NOUVEAU MINI HEROS":DB 0
;-------------0123456789012345678901234567890123456789------------
HOW03 DEFB "VOTRE MISSION SEMBLE FACILE, VOUS DEVEZ "
DEFB "DETRUIRE TOUTES LES FEUILLES A L;ECRAN." : DB 0
HOW04 DEFB "LE COMPTEUR DE cible VOUS MONTRE COMBIEN"
DEFB "IL EN RESTE A DETRUIRE." : DB 0
HOW05 DEFB "LES ROCHES VOUS EVITERONT DE COULER." : DB 0
HOW06 DEFB "N;OUBLIEZ PAS DE LIRE LES INSTRUCTIONS "
DEFB "POUR CONNAITRE LES CARACTERISTIQUES "
DEFB "SPECIFIQUES DE CHAQUE ELEMENT." : DB 0
HOW07 DEFB "LE JEU PEUT ETRE JOUE AVEC LE joystick, "
DEFB "LE CLAVIER qaop OU LES touches curseurs." : DB 0
HOW08 DEFB "m:MUSIQUE OUI/NON esc:QUITTER LA PARTIE" : DB 0
endif
if LANGUE_UK
HOW00 DEFB "\]] how to play ]]^": DB 0
HOW01 DEFB "ladybug HATE THE WATER":DB 0
HOW02 DEFB "A NEW MINI HERO":DB 0
;-------------0123456789012345678901234567890123456789------------
HOW03 DEFB "YOUR MISSION SEEMS TO BE EASY, YOU HAVE"
DEFB "TO DESTROY ALL THE LEAVES AT SCREEN." : DB 0
HOW04 DEFB "THE target COUNTER SHOW YOU HOW MANY"
DEFB "REMAINS." : DB 0
HOW05 DEFB "USING STONES WILL PREVENT YOU TO SINK." : DB 0
HOW06 DEFB "DON;T FORGET TO READ THE INSTRUCTIONS"
DEFB "TO KNOW SPECIFIC FEATURES OF EACH"
DEFB "ELEMENT." : DB 0
HOW07 DEFB "THE GAME CAN BE PLAYED WITH THE joystick"
DEFB "KEYBOARD qaop OR THE arrows keys." : DB 0
HOW08 DEFB "m: MUSIC ON/OFF esc: EXIT THE GAME" : DB 0
endif
;------------------------------------------------------------------------------
; MESSAGES
;------------------------------------------------------------------------------
.MESSAGES
LD A,(IX)
CP 0:CALL Z,cheatoff
CP 1:CALL Z,cheaton
CP 2:CALL Z,illegalH
CP 3:CALL Z,illegalV
CP 4:CALL Z,illegalM
LD DE,&C000:CALL directmini
RET
.cheatoff
LD HL,cheatmode1
RET
.cheaton
LD HL,cheatmode2
RET
.illegalH
LD HL,msg_illegalH
RET
.illegalV
LD HL,msg_illegalV
RET
.illegalM
LD HL,msg_illegalM
RET
if LANGUE_SP
.cheatmode1
;----------------------------------------
DEFB "]]]]]]]]]]]] desactiva cheat ]]]]]]]]]]]":DB 0
.cheatmode2
DEFB "]]]]]]]]]]]] activa cheat ]]]]]]]]]]]]":DB 0
.msg_illegalH
DEFB " aqui solo te puedes mover en horizontal":DB 0
.msg_illegalV
DEFB " aqui solo te puedes mover en vertical ":DB 0
.msg_illegalM
DEFB " no, no puedes ir en esa direccion ":DB 0
endif
if LANGUE_FR
.cheatmode1
DEFB "]]]]]]]]]]] mode triche non ]]]]]]]]]]]]":DB 0
.cheatmode2
DEFB "]]]]]]]]]]] mode triche oui ]]]]]]]]]]]]":DB 0
.msg_illegalH
DEFB " deplacement horizontal uniquement ":DB 0
.msg_illegalV
DEFB " deplacement vertical uniquement ":DB 0
.msg_illegalM
DEFB " non non, cette direction est interdite ":DB 0
endif
if LANGUE_UK
.cheatmode1
DEFB "]]]]]]]]]]]] cheat mode no ]]]]]]]]]]]]":DB 0
.cheatmode2
DEFB "]]]]]]]]]]]] cheat mode yes ]]]]]]]]]]]]":DB 0
.msg_illegalH
DEFB " illegal move - cross horizontally only ":DB 0
.msg_illegalV
DEFB " illegal move - cross verticaly only ":DB 0
.msg_illegalM
DEFB " no no, this direction is prohibited ":DB 0
endif
;------------------------------------------------------------------------------
; INSTRUCTION
;------------------------------------------------------------------------------
.INSTRUCTIONS
CALL CLS2
CALL &BB03
;Instructions - PAGE 1/2
LD HL,INS00:LD DE,&C050+22:CALL directmini
;LEAF
LD DE,&C140+4
LD HL,gfx_des_tiles+128 ;adresse tile 2
CALL TILES_1
LD HL,INS01:LD DE,&C140+10:CALL directmini
LD HL,INS02:LD DE,&C190+10:CALL directmini
;NENUPHAR
LD DE,&C280+4
LD HL,gfx_des_tiles+64 ;adresse tile 1
CALL TILES_1
LD HL,INS03:LD DE,&C280+10:CALL directmini
LD HL,INS04:LD DE,&C2D0+10:CALL directmini
;STONE
LD DE,&C3C0+4
LD HL,gfx_des_tiles+640 ;adresse tile 10
CALL TILES_1
LD HL,INS05:LD DE,&C3C0+10:CALL directmini
LD HL,INS06:LD DE,&C410+10:CALL directmini
;TREE TRUNCK
LD DE,&C500+4
LD HL,gfx_des_tiles+1216 ;adresse tile 19
CALL TILES_1
LD HL,INS07:LD DE,&C500+10:CALL directmini
LD HL,INS06:LD DE,&C550+10:CALL directmini
;JUMP X2
LD DE,&C640+4
LD HL,gfx_des_tiles+1152 ;adresse tile 18
CALL TILES_1
LD HL,INS08:LD DE,&C640+10:CALL directmini
LD HL,INS06:LD DE,&C690+10:CALL directmini
;PAGE 1/2
if LANGUE_SP
LD HL,INS09:LD DE,&C780+58:CALL directmini
endif
if LANGUE_FR
LD HL,INS09:LD DE,&C780+62:CALL directmini
endif
if LANGUE_UK
LD HL,INS09:LD DE,&C780+62:CALL directmini
endif
;wait
CALL &BB03:CALL &BB06
;CLS CLASSIQUE
CALL &BB6C
;Instructions - PAGE 2/2
LD HL,INS00:LD DE,&C050+22:CALL directmini
;CROSS H
LD DE,&C140
LD HL,gfx_des_tiles+256 ;adresse tile 4
CALL TILES_1
LD DE,&C140+6
LD HL,gfx_des_tiles+768 ;adresse tile 12
CALL TILES_1
LD HL,INS11:LD DE,&C140+12:CALL directmini
LD HL,INS10:LD DE,&C190+12:CALL directmini
;CROSS V
LD DE,&C280
LD HL,gfx_des_tiles+192 ;adresse tile 3
CALL TILES_1
LD DE,&C280+6
LD HL,gfx_des_tiles+704 ;adresse tile 11
CALL TILES_1
LD HL,INS12:LD DE,&C280+12:CALL directmini
LD HL,INS10:LD DE,&C2D0+12:CALL directmini
;TELEPORTEUR
LD DE,&C3C0
LD HL,gfx_des_tiles+576 ;adresse tile 9
CALL TILES_1
LD DE,&C3C0+6
LD HL,gfx_des_tiles+1088 ;adresse tile 17
CALL TILES_1
LD HL,INS13:LD DE,&C3C0+12:CALL directmini
LD HL,INS10:LD DE,&C410+12:CALL directmini
;FOLLOW DIRECTION
LD HL,INS14:LD DE,&C500:CALL directmini
LD DE,&C550
LD HL,gfx_des_tiles+320 ;adresse tile 5
CALL TILES_1
LD DE,&C550+6
LD HL,gfx_des_tiles+832 ;adresse tile 13
CALL TILES_1
LD HL,INS16:LD DE,&C550+12:CALL directmini
LD HL,INS15:LD DE,&C5A0+12:CALL directmini
LD DE,&C550+40
LD HL,gfx_des_tiles+512 ;adresse tile 8
CALL TILES_1
LD DE,&C550+46
LD HL,gfx_des_tiles+1024 ;adresse tile 16
CALL TILES_1
LD HL,INS17:LD DE,&C550+52:CALL directmini
LD HL,INS15:LD DE,&C5A0+52:CALL directmini
LD DE,&C640
LD HL,gfx_des_tiles+448 ;adresse tile 7
CALL TILES_1
LD DE,&C640+6
LD HL,gfx_des_tiles+960 ;adresse tile 15
CALL TILES_1
LD HL,INS18:LD DE,&C640+12:CALL directmini
LD HL,INS15:LD DE,&C690+12:CALL directmini
LD DE,&C640+40
LD HL,gfx_des_tiles+384 ;adresse tile 6
CALL TILES_1
LD DE,&C640+46
LD HL,gfx_des_tiles+896 ;adresse tile 14
CALL TILES_1
LD HL,INS19:LD DE,&C640+52:CALL directmini
LD HL,INS15:LD DE,&C690+52:CALL directmini
;PAGE 2/2
if LANGUE_SP
LD HL,INS20:LD DE,&C780+58:CALL directmini
endif
if LANGUE_FR
LD HL,INS20:LD DE,&C780+62:CALL directmini
endif
if LANGUE_UK
LD HL,INS20:LD DE,&C780+62:CALL directmini
endif
;wait
CALL &BB03:CALL &BB06
RET
if LANGUE_SP
INS00 DEFB "\]] instrucciones ]]^": DB 0
INS01 DEFB "hoja":DB 0
INS02 DEFB "DESAPARECE AL PASAR POR ENCIMA":DB 0
INS03 DEFB "nenufar":DB 0
INS04 DEFB "DESAPARECE AL PISARLA DOS VECES":DB 0
INS05 DEFB "piedra":DB 0
INS06 DB 34 : DEFB "NO DESAPARECE, NO SE HUNDE!":DB 0
INS07 DEFB "tronco - transporta a la mariquita":DB 0
INS08 DEFB "@pega un salto[":DB 0
INS09 DEFB "PAGINA 1/2":DB 0
INS10 DEFB "PUEDE SER HOJA O PIEDRA":DB 0
INS11 DEFB "aqui solo te mueves en horizontal":DB 0
INS12 DEFB "aqui solo te mueves en vertical":DB 0
INS13 DEFB "teletransportador":DB 0
INS14 DEFB "SIGUE LA DIRECCION DE LA FLECHA":DB 0
INS15 DEFB "HOJA/PIEDRA":DB 0
INS16 DEFB "hacia arriba":DB 0
INS17 DEFB "a la izquierda":DB 0
INS18 DEFB "hacia abajo":DB 0
INS19 DEFB "a la derecha":DB 0
INS20 DEFB "PAGINA 2/2":DB 0
endif
if LANGUE_FR
INS00 DEFB "\]] instructions ]]^": DB 0
INS01 DEFB "feuille":DB 0
INS02 DEFB "CASE DESTRUCTIBLE APRES 1 PASSAGE":DB 0
INS03 DEFB "nenuphar":DB 0
INS04 DEFB "CASE DESTRUCTIBLE APRES 2 PASSAGES":DB 0
INS05 DEFB "rocher":DB 0
INS06 DEFB "CASE INDESTRUCTIBLE":DB 0
INS07 DEFB "tronc - transporte la coccinelle":DB 0
INS08 DEFB "sauter a la deuxieme case":DB 0
INS09 DEFB "PAGE 1/2":DB 0
INS10 DEFB "FEUILLE OU ROCHER":DB 0
INS11 DEFB "deplacement horizontal uniquement":DB 0
INS12 DEFB "deplacement vertical uniquement":DB 0
INS13 DEFB "teleporteur vers teleporteur":DB 0
INS14 DEFB "SUIVRE LA DIRECTION AUTOMATIQUEMENT":DB 0
INS15 DEFB "FEUILLE/ROCHER":DB 0
INS16 DEFB "vers le haut":DB 0
INS17 DEFB "vers la gauche":DB 0
INS18 DEFB "vers le bas":DB 0
INS19 DEFB "vers la droite":DB 0
INS20 DEFB "PAGE 2/2":DB 0
endif
if LANGUE_UK
INS00 DEFB "\]] instructions ]]^": DB 0
INS01 DEFB "leaf":DB 0
INS02 DEFB "CASE DESTRUCTIBLE AFTER ONE PASS":DB 0
INS03 DEFB "nenuphar":DB 0
INS04 DEFB "CASE DESTRUCTIBLE AFTER TWO PASS":DB 0
INS05 DEFB "stone":DB 0
INS06 DEFB "CASE INDESTRUCTIBLE":DB 0
INS07 DEFB "tree trunck - transports ladybug":DB 0
INS08 DEFB "jump to the second case":DB 0
INS09 DEFB "PAGE 1/2":DB 0
INS10 DEFB "LEAF OR STONE":DB 0
INS11 DEFB "cross horizontally only":DB 0
INS12 DEFB "cross vertically only":DB 0
INS13 DEFB "teleporter to teleporter":DB 0
INS14 DEFB "LADYBUG FOLLOW DIRECTION AUTOMATICALLY":DB 0
INS15 DEFB "LEAF/STONE":DB 0
INS16 DEFB "go up":DB 0
INS17 DEFB "go left":DB 0
INS18 DEFB "go down":DB 0
INS19 DEFB "go right":DB 0
INS20 DEFB "PAGE 2/2":DB 0
endif
;------------------------------------------------------------------------------
; CREDITS
;------------------------------------------------------------------------------
.CREDITS
CALL CLS2
CALL &BB03
if LANGUE_SP
.AFFCREDITS
LD HL,txtcredits01:LD DE,&C06E:CALL directmini
LD HL,txtcredits02:LD DE,&C0BE:CALL directmini
LD HL,txtcredits03:LD DE,&C1A2-16:CALL directmini
LD HL,txtcredits04:LD DE,&C244-10:CALL directmini
LD HL,txtcredits05:LD DE,&C2A0:CALL directmini
LD HL,txtcredits06:LD DE,&C330-2:CALL directmini
LD HL,txtcredits07:LD DE,&C3D0-16:CALL directmini
LD HL,txtcredits08:LD DE,&C470-2:CALL directmini
LD HL,txtcredits09:LD DE,&C50C-6:CALL directmini
LD HL,txtcredits10:LD DE,&C570:CALL directmini
LD HL,txtcredits11:LD DE,&C5C0:CALL directmini
LD HL,txtcredits12:LD DE,&C610:CALL directmini
LD HL,txtcredits13:LD DE,&C660:CALL directmini
LD HL,txtcredits14:LD DE,&C6B0:CALL directmini
LD HL,txtcredits15:LD DE,&C700:CALL directmini
LD HL,txtcredits16:LD DE,&C750:CALL directmini
LD DE,&C730 ;adresse ecran
LD HL,gfx_des_tiles+128 ;adresse tiles(2*4*16)
CALL TILES_1
LD DE,&C730 ;adresse ecran
LD HL,gfx_des_sprites ;adresse sprite(0*4*16)
LD B,16
LD C,4
CALL TRAN_SPR_PR
LD DE,&C734
LD HL,gfx_des_tiles+64 ;adresse tiles(1*4*16)
CALL TILES_1
LD DE,&C694 ;adresse ecran
LD HL,gfx_des_tiles+640 ;adresse tiles(10*4*16)
CALL TILES_1
CALL &BB03
CALL &BB06
RET
.txtcredits01
DEFB "creditos" : DB 0
.txtcredits02
DEFB "\]]]]]]^" : DB 0
.txtcredits03
DEFB "PROGRAMACION : kukulcan" : DB 0
.txtcredits04
DEFB "GRAFICOS : ced" : DB 0
.txtcredits05
DEFB "christophe petit" : DB 0
.txtcredits06
DEFB "MUSICA : rayxamber" : DB 0
.txtcredits07
DEFB "ILUSTRACIONES : toto" : DB 0
.txtcredits08
DEFB "TEXTOS : johnny farragut" : DB 0
.txtcredits09
DEFB "PROBADORES : arnaud bouche" : DB 0
.txtcredits10
DEFB "cpcmaniaco" : DB 0
.txtcredits11
DEFB "fredbezies" : DB 0
.txtcredits12
DEFB "fredouille" : DB 0
.txtcredits13
DEFB "johnny farragut" : DB 0
.txtcredits14
DEFB "johnny olsen" : DB 0
.txtcredits15
DEFB "maxit" : DB 0
.txtcredits16
DEFB "zisquier" : DB 0
endif
if LANGUE_FR
.AFFCREDITS
LD HL,txtcredits01:LD DE,&C06E:CALL directmini
LD HL,txtcredits02:LD DE,&C0BE:CALL directmini
LD HL,txtcredits03:LD DE,&C1A2-18:CALL directmini
LD HL,txtcredits04:LD DE,&C244-12:CALL directmini
LD HL,txtcredits05:LD DE,&C2A0:CALL directmini
LD HL,txtcredits06:LD DE,&C330-4:CALL directmini
LD HL,txtcredits07:LD DE,&C3D0-16:CALL directmini
LD HL,txtcredits08:LD DE,&C470-2:CALL directmini
LD HL,txtcredits09:LD DE,&C50C-2:CALL directmini
LD HL,txtcredits10:LD DE,&C570:CALL directmini
LD HL,txtcredits11:LD DE,&C5C0:CALL directmini
LD HL,txtcredits12:LD DE,&C610:CALL directmini
LD HL,txtcredits13:LD DE,&C660:CALL directmini
LD HL,txtcredits14:LD DE,&C6B0:CALL directmini
LD HL,txtcredits15:LD DE,&C700:CALL directmini
LD HL,txtcredits16:LD DE,&C750:CALL directmini
LD DE,&C730 ;adresse ecran
LD HL,gfx_des_tiles+128 ;adresse tiles(2*4*16)
CALL TILES_1
LD DE,&C730 ;adresse ecran
LD HL,gfx_des_sprites ;adresse sprite(0*4*16)
LD B,16
LD C,4
CALL TRAN_SPR_PR
LD DE,&C734
LD HL,gfx_des_tiles+64 ;adresse tiles(1*4*16)
CALL TILES_1
LD DE,&C694 ;adresse ecran
LD HL,gfx_des_tiles+640 ;adresse tiles(10*4*16)
CALL TILES_1
CALL &BB03
CALL &BB06
RET
.txtcredits01
DEFB "credits" : DB 0
.txtcredits02
DEFB "\]]]]]^" : DB 0
.txtcredits03
DEFB "PROGRAMMATION : kukulcan" : DB 0
.txtcredits04
DEFB "GRAPHISTE : ced" : DB 0
.txtcredits05
DEFB "christophe petit" : DB 0
.txtcredits06
DEFB "MUSIQUE : rayxamber" : DB 0
.txtcredits07
DEFB "ILLUSTRATIONS : toto" : DB 0
.txtcredits08
DEFB "TEXTES : galamoth" : DB 0
.txtcredits09
DEFB "TESTEURS : arnaud bouche" : DB 0
.txtcredits10
DEFB "cpcmaniaco" : DB 0
.txtcredits11
DEFB "fredbezies" : DB 0
.txtcredits12
DEFB "fredouille" : DB 0
.txtcredits13
DEFB "johnny farragut" : DB 0
.txtcredits14
DEFB "johnny olsen" : DB 0
.txtcredits15
DEFB "maxit" : DB 0
.txtcredits16
DEFB "zisquier" : DB 0
endif
if LANGUE_UK
.AFFCREDITS
LD HL,txtcredits01:LD DE,&C06E:CALL directmini
LD HL,txtcredits02:LD DE,&C0BE:CALL directmini
LD HL,txtcredits03:LD DE,&C1A2:CALL directmini
LD HL,txtcredits04:LD DE,&C244:CALL directmini
LD HL,txtcredits05:LD DE,&C2A0:CALL directmini
LD HL,txtcredits06:LD DE,&C330:CALL directmini
LD HL,txtcredits07:LD DE,&C3D0-16:CALL directmini
LD HL,txtcredits08:LD DE,&C470:CALL directmini
LD HL,txtcredits09:LD DE,&C50C:CALL directmini
LD HL,txtcredits10:LD DE,&C570:CALL directmini
LD HL,txtcredits11:LD DE,&C5C0:CALL directmini
LD HL,txtcredits12:LD DE,&C610:CALL directmini
LD HL,txtcredits13:LD DE,&C660:CALL directmini
LD HL,txtcredits14:LD DE,&C6B0:CALL directmini
LD HL,txtcredits15:LD DE,&C700:CALL directmini
LD HL,txtcredits16:LD DE,&C750:CALL directmini
LD DE,&C730 ;adresse ecran
LD HL,gfx_des_tiles+128 ;adresse tiles(2*4*16)
CALL TILES_1
LD DE,&C730 ;adresse ecran
LD HL,gfx_des_sprites ;adresse sprite(0*4*16)
LD B,16
LD C,4
CALL TRAN_SPR_PR
LD DE,&C734
LD HL,gfx_des_tiles+64 ;adresse tiles(1*4*16)
CALL TILES_1
LD DE,&C694 ;adresse ecran
LD HL,gfx_des_tiles+640 ;adresse tiles(10*4*16)
CALL TILES_1
CALL &BB03
CALL &BB06
RET
.txtcredits01
DEFB "credits" : DB 0
.txtcredits02
DEFB "\]]]]]^" : DB 0
.txtcredits03
DEFB "CODE : kukulcan" : DB 0
.txtcredits04
DEFB "GFX : ced" : DB 0
.txtcredits05
DEFB "christophe petit" : DB 0
.txtcredits06
DEFB "MUSIC : rayxamber" : DB 0
.txtcredits07
DEFB "ILLUSTRATIONS : toto" : DB 0
.txtcredits08
DEFB "TEXTS : galamoth" : DB 0
.txtcredits09
DEFB "TESTERS : arnaud bouche" : DB 0
.txtcredits10
DEFB "cpcmaniaco" : DB 0
.txtcredits11
DEFB "fredbezies" : DB 0
.txtcredits12
DEFB "fredouille" : DB 0
.txtcredits13
DEFB "johnny farragut" : DB 0
.txtcredits14
DEFB "johnny olsen" : DB 0
.txtcredits15
DEFB "maxit" : DB 0
.txtcredits16
DEFB "zisquier" : DB 0
endif
;------------------------------------------------------------------------------
; MENU PRINCIPAL
;------------------------------------------------------------------------------
OPTIONS_MENU_BASIC
LD A,(IX)
CALL OPTIONS_MENU
RET
OPTIONS_MENU
LD HL,MENU02b:LD (SUB2A+1),HL:CP 0:JR Z,NEXTSUB3:LD HL,MENU02a:LD (SUB2A+1),HL
NEXTSUB3
LD HL,MENU03b:LD (SUB3A+1),HL:CP 1:JR Z,NEXTSUB4:LD HL,MENU03a:LD (SUB3A+1),HL
NEXTSUB4
LD HL,MENU04b:LD (SUB4A+1),HL:CP 2:JR Z,NEXTSUB5:LD HL,MENU04a:LD (SUB4A+1),HL
NEXTSUB5
LD HL,MENU05b:LD (SUB5A+1),HL:CP 3:JR Z,NEXTSUB6:LD HL,MENU05a:LD (SUB5A+1),HL
NEXTSUB6
LD HL,MENU06b:LD (SUB6A+1),HL:CP 4:JR Z,NEXTSUB7:LD HL,MENU06a:LD (SUB6A+1),HL
NEXTSUB7
LD HL,MENU07b:LD (SUB7A+1),HL:CP 5:JR Z,NEXTSUB8:LD HL,MENU07a:LD (SUB7A+1),HL
NEXTSUB8
SUB2A LD HL,MENU02a:LD DE,&E190+34-4:CALL directmini
SUB3A LD HL,MENU03a:LD DE,&E280+34-2:CALL directmini
SUB4A LD HL,MENU04a:LD DE,&E370+34:CALL directmini
SUB5A LD HL,MENU05a:LD DE,&E460+34-2:CALL directmini
SUB6A LD HL,MENU06a:LD DE,&E550+34-4:CALL directmini
SUB7A LD HL,MENU07a:LD DE,&E640+34-6:CALL directmini
RET
.MENU
CALL CLS2
CALL AFFLADYBUG
LD HL,MENU01:LD DE,&C050+24:CALL directmini
XOR A
CALL OPTIONS_MENU
LD HL,MENU08:LD DE,&C780+18-4:CALL directmini
RET
MENU01
DEFB "\]] clevermind ]]": DB 94 : DB 0
if LANGUE_SP
MENU02a
DEFB " EMPEZAR PARTIDA" : DB 0
MENU02b
DEFB "* empezar partida" : DB 0
MENU03a
DEFB " INSTRUCCIONES" : DB 0
MENU03b
DEFB "* instrucciones" : DB 0
MENU04a
DEFB " COMO JUGAR" : DB 0
MENU04b
DEFB "* como jugar" : DB 0
MENU05a
DEFB " MUSICA" : DB 0
MENU05b
DEFB "* musica" : DB 0
MENU06a
DEFB " CREDITOS" : DB 0
MENU06b
DEFB "* creditos" : DB 0
MENU07a
DEFB " INT CODIGO " : DB 0
MENU07b
DEFB "* int codigo .... " : DB 0
endif
if LANGUE_FR
MENU02a
DEFB " DEMARRER DEFI" : DB 0
MENU02b
DEFB "* demarrer defi" : DB 0
MENU03a
DEFB " INSTRUCTIONS" : DB 0
MENU03b
DEFB "* instructions" : DB 0
MENU04a
DEFB " COMMENT JOUER" : DB 0
MENU04b
DEFB "* comment jouer" : DB 0
MENU05a
DEFB " MUSIQUE" : DB 0
MENU05b
DEFB "* musique" : DB 0
MENU06a
DEFB " CREDITS" : DB 0
MENU06b
DEFB "* credits" : DB 0
MENU07a
DEFB " SAISIR CODE " : DB 0
MENU07b
DEFB "* saisir code .... " : DB 0
endif
if LANGUE_UK
MENU02a
DEFB " START MISSION" : DB 0
MENU02b
DEFB "* start mission" : DB 0
MENU03a
DEFB " INSTRUCTIONS" : DB 0
MENU03b
DEFB "* instructions" : DB 0
MENU04a
DEFB " HOW TO PLAY" : DB 0
MENU04b
DEFB "* how to play" : DB 0
MENU05a
DEFB " MUSIC" : DB 0
MENU05b
DEFB "* music" : DB 0
MENU06a
DEFB " CREDITS" : DB 0
MENU06b
DEFB "* credits" : DB 0
MENU07a
DEFB " ENTER CODE " : DB 0
MENU07b
DEFB "* enter code .... " : DB 0
endif
MENU08
DEFB "< 2019 #$ WWW.CPC-POWER.COM": DB 0
;------------------------------------------------------------------------------
; INFORMATIONS INGAME
;------------------------------------------------------------------------------
.LEVEL
;lecture valeur adresse_ecran
LD A,(IX+00)
ADD A,&30
LD (INFOS1+8),A ;dizaine
LD A,(IX+02)
ADD A,&30
LD (INFOS1+7),A ;unite
LD HL,INFOS1
LD DE,&C000
CALL directmini
RET
if LANGUE_SP
INFOS1 DEFB " nivel*XX cdgo????" : DB 0
endif
if LANGUE_FR
INFOS1 DEFB "niveau*XX code????" : DB 0
endif
if LANGUE_UK
INFOS1 DEFB " level*XX code????" : DB 0
endif
.LIVES
;lecture valeur adresse_ecran
LD A,(IX+00)
ADD A,&30
LD (INFOS2+6),A ;unite
LD HL,INFOS2
LD DE,&C042
CALL directmini
RET
if LANGUE_SP
INFOS2 DEFB "vidas*X" : DB 0
endif
if LANGUE_FR
INFOS2 DEFB " vies*X" : DB 0
endif
if LANGUE_UK
INFOS2 DEFB "lives*X" : DB 0
endif
.TARGET
;lecture valeur adresse_ecran
LD A,(IX+00)
ADD A,&30
LD (INFOS3+11),A ;centaine
LD A,(IX+02)
ADD A,&30
LD (INFOS3+10),A ;dizaine
LD A,(IX+04)
ADD A,&30
LD (INFOS3+9),A ;unite
LD HL,INFOS3
LD DE,&C028
CALL directmini
RET
if LANGUE_SP
INFOS3 DEFB "objetivo*XXX" : DB 0
endif
if LANGUE_FR
INFOS3 DEFB " cible*XXX" : DB 0
endif
if LANGUE_UK
INFOS3 DEFB " target*XXX" : DB 0
endif
;------------------------------------------------------------------------------
; SAUVER LE DECOR DE FOND
;------------------------------------------------------------------------------
.tampon_tile_sauvegarde :
DEFS 64 ;TILE = 16px*16px = 4*16 = 64 octets
.DECOR_16x16_SAUVEGARDE
;lecture adresse_ecran
LD E,(IX+00)
LD D,(IX+01)
LD HL,tampon_tile_sauvegarde
LD A,16 ;hauteur
EX DE,HL
.sauver_fond1
LDI ; 16 pixels = 4 octets
LDI
LDI
LDI
LD BC,&7FC ;ligne suivante &800-4(largeur du tile)
ADD HL,BC
JR NC,sauver_fond2
LD BC,&C050
ADD HL,BC
.sauver_fond2
DEC A
JR NZ,sauver_fond1
RET
;------------------------------------------------------------------------------
; RESTAURER LE DECOR DE FOND
;------------------------------------------------------------------------------
.DECOR_16x16_RESTAURATION
;lecture adresse_ecran
LD E,(IX+00)
LD D,(IX+01)
LD HL,tampon_tile_sauvegarde
LD A,16 ;hauteur
.restore_fond1
LDI ; 16 pixels = 4 octets
LDI
LDI
LDI
EX DE,HL
LD BC,&7FC ;ligne suivante &800-4(largeur du tile)
ADD HL,BC
JR NC,restore_fond2
LD BC,&C050
ADD HL,BC
.restore_fond2
EX DE,HL
DEC A
JR NZ,restore_fond1
RET
;------------------------------------------------------------------------------
; TILES 16x16 opaque
; Entrees ;
; A = element
; DE = adresse ecran
;------------------------------------------------------------------------------
.TILES_16x16_opaque
;lecture valeur adresse_ecran
LD E,(IX+00)
LD D,(IX+01)
PUSH DE
;element opaque
LD A,(IX+02) ;0 a 18
LD L,A ;L = A
LD H,0 ;H = 0
ADD HL,HL ;*2
ADD HL,HL ;*4
ADD HL,HL ;*8
ADD HL,HL ;*16
ADD HL,HL ;*32
ADD HL,HL ;*64
LD DE,gfx_des_tiles
ADD HL,DE ;HL contient l'adresse du tiles
POP DE ;DE adresse ecran
.TILES_1
LD A,16
.TILES_2
LDI ;16 pixels = 4 octets
LDI
LDI
LDI
EX DE,HL
LD BC,&07FC
ADD HL,BC
JR NC,TILES_3
LD BC,&C050
ADD HL,BC
.TILES_3
EX DE,HL
DEC A
JR NZ,TILES_2
RET
.directmini
LD A,(HL)
CP 0
RET Z
PUSH HL
PUSH DE
CALL aff_TILES8_0
POP DE
INC DE:INC DE ;+2 pixels
POP HL
INC HL ;position caractere suivant
JR directmini
;------------------------------------------------------------------------------
; ELEMENTS TRANSPARENT
; Entrees ;
; A = element
; DE = adresse ecran
;------------------------------------------------------------------------------
AFFICHAGE_ELEMENT_TRANSPARENT
;lecture valeur adresse_ecran
LD E,(IX+00)
LD D,(IX+01)
PUSH DE
;element transparent
LD A,(IX+02) ;0 a 5
.SPRDIRECT
LD L,A ;L = A
LD H,0 ;H = 0
ADD HL,HL ;*2
ADD HL,HL ;*4
ADD HL,HL ;*8
ADD HL,HL ;*16
ADD HL,HL ;*32
ADD HL,HL ;*64
LD DE,gfx_des_sprites
ADD HL,DE ;HL contient l'adresse de la tuile
LD B,16
LD C,4
POP DE
CALL TRAN_SPR_PR
RET
;------------------------------------------------------------------------------
; Sprite transparent en mode 0
; Entrees ;
; - B = nombre de lignes
; - C = largeur du sprite en octets
; - HL = adresse du sprite
; - DE = adresse ecran.
;------------------------------------------------------------------------------
TRAN_SPR_PR PUSH BC
PUSH DE
TRAN_SPR_P0 LD A,(HL) ; A = octet courant
LD B,A
OR A ; Octet transparent?
JR Z,TRAN_SPR_P1 ; Oui => prochain octet (couleurs inchangees)
AND %10101010 ; Couleur gauche transparente?
JR NZ,TRAN_SPR_P3 ; Non => TRAN_SPR_P3
LD A,(DE) ; Oui => octet = couleur droite du sprite + couleur gauche du fond d'ecran
AND %10101010
OR B
LD (DE),A ; Octet paint
TRAN_SPR_P1 INC HL
INC DE
DEC C
JR NZ,TRAN_SPR_P0
POP DE ; DE = ligne ecran suivante (+&0800 or +&C800)
EX HL,DE
LD BC,&800
ADD HL,BC
JR NC,TRAN_SPR_P2
LD BC,&C050
ADD HL,BC
TRAN_SPR_P2 EX HL,DE
POP BC
DJNZ TRAN_SPR_PR
RET
TRAN_SPR_P3 LD A,B
AND %01010101 ; Is sprite right color black?
JR NZ,TRAN_SPR_P5 ; No => TRAN_SPR_P5
LD A,(DE) ; Oui => octet = couleur gauche du sprite + couleur droite du fond d'ecran
AND %01010101
OR B
LD (DE),A ; Octet paint
INC HL
INC DE
DEC C
JR NZ,TRAN_SPR_P0
POP DE ; DE = ligne ecran suivante (+&0800 or +&C800)
EX HL,DE
LD BC,&800
ADD HL,BC
JR NC,TRAN_SPR_P4
LD BC,&C050
ADD HL,BC
TRAN_SPR_P4 EX HL,DE
POP BC
DJNZ TRAN_SPR_PR
RET
TRAN_SPR_P5 LD A,(DE)
LD A,B
LD (DE),A ; Octet = octet entier du sprite
JR TRAN_SPR_P1
RET
;------------------------------------------------------------------------------
; TILE8 OPAQUE
;------------------------------------------------------------------------------
.TILE8
;lecture valeur caractere
LD A,(IX+2)
;lecture valeur adresse_ecran
LD D,(IX+1)
LD E,(IX+0)
.aff_TILES8_0
LD C,32
SUB C ;A = A-32
PUSH DE ;sauver DE
LD L,A ;L = A
LD H,0 ;H = 0
ADD HL,HL ;*2
ADD HL,HL ;*4
ADD HL,HL ;*8
ADD HL,HL ;*16
LD DE,gfx_fonte
ADD HL,DE ;HL contient l'adresse du tiles
POP DE ;recuperer l'adresse d'affichage a l'ecran
LD A,8 ;Hauteur_du_tile
.aff_TILES8_1
LDI
LDI ;8 pixels = 2 octets
EX DE,HL
LD BC,&07FE ;&800 - 2 octets (largeur ecran - largeur tiles)
ADD HL,BC
JR NC,aff_TILES8_2
LD BC,&C050 ;R1=40 alors &C050 (normal)
ADD HL,BC
.aff_TILES8_2
EX DE,HL
DEC A
JR NZ,aff_TILES8_1
RET
;------------------------------------------------------------------------------
;syntax |CLS2
;Vider l'ecran
;------------------------------------------------------------------------------
.CLS2
LD HL,&C000
LD BC,&4000
clsloop2:
LD (HL),&0C;remplir avec l'encre 2 (bleu)
LD DE,&0059
ADD HL,DE
JR NC,clsloop1
;CALL &BD19
LD DE,&C000
ADD HL,DE
clsloop1:
DEC BC
LD A,B
OR C
JR NZ,clsloop2
RET
;------------------------------------------------------------------------------
;FEUILLE AVEC LADYBUG POUR LE MENU PRINCIPAL
;------------------------------------------------------------------------------
.txtladybug
DEFB " < "
DEFB " <<< "
DEFB " <<<<< "
DEFB " <<<<<<< "
DEFB " <=<<<=< "
DEFB " <<<=<=<<< "
DEFB " <<<<<=<<<<< "
DEFB " <<<<%=%<<<< "
DEFB " <<<<=====<<<< "
DEFB " <<<>>>=>>><<< "
DEFB "<<<>>=>=>=>><<<"
DEFB "<<<>>>>=>>>><<<"
DEFB "<<<>=>>=>>=><<<"
DEFB "<<<>>>>=>>>><<<"
DEFB " <<<>=>=>=><<< "
DEFB " <<<<>>=>><<<< "
DEFB " <<<<>=><<<< "
DEFB " <<<<<<<<< "
DEFB " <<<<<<< "
DEFB " <<<<< "
DEFB " <<< "
DEFB " < "
DEFB " < "
DEFB " < "
.AFFLADYBUG
LD HL,txtladybug
LD A,15
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,24 ;hauteur a afficher
LD DE,&C000
CALL AFF_TABLEAU
RET
;------------------------------------------------------------------------------
;syntax |OHNO
;
;------------------------------------------------------------------------------
if LANGUE_SP
;SP = !OH NO!
;Debut ligne texte 11, colonne 7/40
;Largeur = 26
;Hauteur = 5
.txtohno
DEFB "' '' ' ' ' ' '' '"
DEFB " ' ' ' ' '' ' ' ' '"
DEFB "' ' ' '''' ' '' ' ' '"
DEFB "' ' ' ' ' ' ' ' ' "
DEFB "' '' ' ' ' ' '' '"
.AFFOHNO
LD HL,txtohno
LD A,26
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,5 ;hauteur a afficher
LD DE,&C320+14
CALL AFF_TABLEAU
RET
endif
if LANGUE_FR
;FR = AH NON!
;Debut ligne texte 11, colonne 6/40
;Largeur = 28
;Hauteur = 5
.txtohno
DEFB " '' ' ' ' ' '' ' ' '"
DEFB "' ' ' ' '' ' ' ' '' ' '"
DEFB "'''' '''' ' '' ' ' ' '' '"
DEFB "' ' ' ' ' ' ' ' ' ' "
DEFB "' ' ' ' ' ' '' ' ' '"
.AFFOHNO
LD HL,txtohno
LD A,28
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,5 ;hauteur a afficher
LD DE,&C320+12
CALL AFF_TABLEAU
RET
endif
if LANGUE_UK
;UK = OH NO!
;Debut ligne texte 11, colonne 8/40
;Largeur = 24
;Hauteur = 5
.txtohno
DEFB " '' ' ' ' ' '' '"
DEFB "' ' ' ' '' ' ' ' '"
DEFB "' ' '''' ' '' ' ' '"
DEFB "' ' ' ' ' ' ' ' "
DEFB " '' ' ' ' ' '' '"
.AFFOHNO
LD HL,txtohno
LD A,24
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,5 ;hauteur a afficher
LD DE,&C320+16
CALL AFF_TABLEAU
RET
endif
;------------------------------------------------------------------------------
;syntax |DONE
;------------------------------------------------------------------------------
if LANGUE_SP
;SP = !BRAVO!
;Debut ligne texte 11, colonne 5,5/40
;Largeur = 29
;Hauteur = 5
.txtwelldone
DEFB "' ''' ''' '' ' ' '' '"
DEFB " ' ' ' ' ' ' ' ' ' ' '"
DEFB "' '''' ''' '''' ' ' ' ' '"
DEFB "' ' ' ' ' ' ' ' ' ' ' "
DEFB "' ''' ' ' ' ' ' '' '"
.AFFDONE
LD HL,txtwelldone
LD A,29
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,5 ;hauteur a afficher
LD DE,&C320+11
CALL AFF_TABLEAU
RET
endif
if LANGUE_FR
;FR = BRAVO!
;Debut ligne texte 11, colonne 6,5/40
;Largeur = 27
;Hauteur = 5
.txtwelldone
DEFB "''' ''' '' ' ' '' '"
DEFB "' ' ' ' ' ' ' ' ' ' '"
DEFB "'''' ''' '''' ' ' ' ' '"
DEFB "' ' ' ' ' ' ' ' ' ' "
DEFB "''' ' ' ' ' ' '' '"
.AFFDONE
LD HL,txtwelldone
LD A,27
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,5 ;hauteur a afficher
LD DE,&C320+13
CALL AFF_TABLEAU
RET
endif
if LANGUE_UK
;UK = WELL DONE!
;Debut ligne texte 7, colonne 9/40
;Largeur = 22
;Hauteur = 11
.txtwelldone
DEFB " ' ' '''' ' ' "
DEFB " ' ' ' ' ' "
DEFB " ' ' '' ' ' "
DEFB " ' ' ' ' ' ' "
DEFB " ' ' '''' '''' '''' "
DEFB " "
DEFB "''' '' ' ' '''' '"
DEFB "' ' ' ' '' ' ' '"
DEFB "' ' ' ' ' '' '' '"
DEFB "' ' ' ' ' ' ' "
DEFB "''' '' ' ' '''' '"
.AFFDONE
LD HL,txtwelldone
LD A,22
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,11 ;hauteur a afficher
LD DE,&C1E0+18
CALL AFF_TABLEAU
RET
endif
;------------------------------------------------------------------------------
;syntax |LOST
;------------------------------------------------------------------------------
if LANGUE_SP
;SP = FIN DE LA PARTIDA
;Debut ligne texte 8, colonne 1,5/40
;Largeur = 37
;Hauteur = 11
.txtgameover
DEFB "'''' ''' ' ' ''' '''' ' '' "
DEFB "' ' '' ' ' ' ' ' ' '"
DEFB "''' ' ' '' ' ' ''' ' ''''"
DEFB "' ' ' ' ' ' ' ' ' '"
DEFB "' ''' ' ' ''' '''' '''' ' '"
DEFB " "
DEFB " ''' '' ''' ''' ''' ''' '' "
DEFB " ' ' ' ' ' ' ' ' ' ' ' ' "
DEFB " ''' '''' ''' ' ' ' ' '''' "
DEFB " ' ' ' ' ' ' ' ' ' ' ' "
DEFB " ' ' ' ' ' ' ''' ''' ' ' "
.AFFGAMEOVER
LD HL,txtgameover
LD A,37
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,11 ;hauteur a afficher
LD DE,&C230+3
CALL AFF_TABLEAU
RET
endif
if LANGUE_FR
;FR = FIN DE PARTIE
;Debut ligne texte 8, colonne 6,5/40
;Largeur = 27
;Hauteur = 11
.txtgameover
DEFB " '''' ''' ' ' ''' '''' "
DEFB " ' ' '' ' ' ' ' "
DEFB " ''' ' ' '' ' ' ''' "
DEFB " ' ' ' ' ' ' ' "
DEFB " ' ''' ' ' ''' '''' "
DEFB " "
DEFB "''' '' ''' ''' ''' ''''"
DEFB "' ' ' ' ' ' ' ' ' "
DEFB "''' '''' ''' ' ' ''' "
DEFB "' ' ' ' ' ' ' ' "
DEFB "' ' ' ' ' ' ''' ''''"
.AFFGAMEOVER
LD HL,txtgameover
LD A,27
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,11 ;hauteur a afficher
LD DE,&C230+13
CALL AFF_TABLEAU
RET
endif
if LANGUE_UK
;UK = GAME OVER!
;Debut ligne texte 8, colonne 9/40
;Largeur = 22
;Hauteur = 11
.txtgameover
DEFB " '''' '' ' ' '''' "
DEFB " ' ' ' '' '' ' "
DEFB " ' '' '''' ' ' ' '' "
DEFB " ' ' ' ' ' ' ' "
DEFB " '''' ' ' ' ' '''' "
DEFB " "
DEFB " '' ' ' '''' ''' '"
DEFB "' ' ' ' ' ' ' '"
DEFB "' ' ' ' '' ''' '"
DEFB "' ' ' ' ' ' ' "
DEFB " '' ' '''' ' ' '"
.AFFGAMEOVER
LD HL,txtgameover
LD A,22
LD (aff_tableau_largeur+1),A ;largeur a afficher
PUSH HL ;sauver dans HL
POP IX ;restaurer dans IX
LD A,11 ;hauteur a afficher
LD DE,&C230+18
CALL AFF_TABLEAU
RET
endif
;------------------------------------------------------------------------------
;TABLEAU DE TILES 2x8 octets avec exclusion des tiles vident
;------------------------------------------------------------------------------
.AFF_TABLEAU
PUSH AF
PUSH DE
.aff_tableau_largeur
LD A,0 ;longueur a afficher
.aff_tableau2
PUSH AF
LD A,(IX+&00) ;lecture caractere
INC IX
CP 32 ;ne pas afficher les tiles vident
JP Z,aff_tableau1
PUSH DE
CALL aff_TILES8_0 ;affichage caractere
POP DE
.aff_tableau1
INC DE ;decalage 2 octets (largeur d'une tuile)
INC DE
POP AF
DEC A
JR NZ,aff_tableau2
POP HL
LD BC,&0050
ADD HL,BC ;ligne suivante
EX DE,HL
POP AF
DEC A
JR NZ,AFF_TABLEAU
RET
;------------------------------------------------------------------------------
list
; Aplib decrunching routine
nolist
; (c) CNGSOFT
; En entree, on a :
; HL = implantation du code compacte
; DE = implantation du code decompacte
;------------------------------------------------------------------------------
DECOMPACK
;DI
LD HL,LES_NIVEAUX_PAK
LD DE,&C000
CALL boot
JP &000F
; Maxam source by T&J/GPA - 01/18/2008
; Nothing changed, except thy damned hidden opcodes
; and a new variable for Maxam ( 13+8*0 = 0 for Maxam )
; Attention, cette routine contient un assemblage conditionnel.
; Si Aplib8flag = 0, le code decompacte est ecrite du bas de la
; memoire vers le haut de la memoire. C est ce que font par defaut
; les programmes modifies par Dadman/CEZ - Team (APPACK.EXE et
; aPPackWin.exe.
; Si Aplib8flag = 1, le code decompacte est ecrit du haut de la
; memoire vers le bas de la memoire. Le code compacte doit bien
; evidemment etre organise en consequence.
aplib8flag equ &0 ; = DEC &00 pour INC
flagdecde equ aplib8flag*8 ; for Maxam compatibility
Boot
PUSH HL ; used for EX HL,(SP)
PUSH HL
POP IX
DB &FD,&26,&80 ; LD IYh,&80
aplib8literal
LD A,(IX+ &00)
DB &DD,&23 + flagdecde ; INC IX/DEC IX
LD (DE),A
DB &13 + flagdecde ; INC DE/DEC DE
DB &FD,&2E,&02 ; LD IYl,&2
aplib8nexttag
CALL aplib8getbit
JR NC, aplib8literal
LD BC,&0000
CALL aplib8getbit
JR NC, aplib8codepair
LD H,B
CALL aplib8getbit
JR NC, aplib8shortmatch
DB &FD,&2E,&02 ; LD IYl,2
INC C ; bc
LD L,&10
aplib8getmorebits
CALL aplib8getbit
RL L
JR NC, aplib8getmorebits
JR NZ, aplib8domatch
LD A,L
LD (DE),A
DB &13+ flagdecde ; INC DE/DEC DE
JR aplib8nexttag
aplib8codepair
CALL aplib8getgamma
DB &FD,&4D ; LD C,IYl
SBC HL,BC
JR NZ, aplib8normalcodepair
CALL aplib8getgamma
LD B,H
JR aplib8domatch_lastpos
aplib8normalcodepair
DEC L
LD H,L
LD L,(IX + &00)
DB &DD,&23+ flagdecde ; INC IX/DEC IX
PUSH HL
CALL aplib8getgamma
LD B,H
POP HL
LD A,H
CP 125 ; cmp eax,32000
JR NC, aplib8domatch_with_2inc
CP &05
JR NC, aplib8domatch_with_inc
AND A
JR NZ, aplib8domatch_new_lastpos
LD A,L
ADD A
JR C, aplib8domatch_new_lastpos
aplib8domatch_with_2inc
INC BC
aplib8domatch_with_inc
INC BC
aplib8domatch_new_lastpos
EX (SP),HL
aplib8domatch_lastpos
POP HL
PUSH HL
DB &FD,&2E,&01 ; LD IYl,1
aplib8domatch
if aplib8flag ; LDIR/LDDR
ADD HL,DE
LDDR
else
AND A
EX DE,HL
SBC HL,DE
EX DE,HL
ADD HL,DE
EX DE,HL
LDIR
endif
JR aplib8nexttag
aplib8shortmatch
LD L,(IX+&00)
DB &DD,&23+ flagdecde ; INC IX/DEC IX
SRL L
JR Z, aplib8donedepacking
RL C
JR aplib8domatch_with_2inc
aplib8getbit
DB &FD,&7C ; LD A,IYh
ADD A
JR NZ,aplib8getbit_
LD A,(IX + &00)
DB &DD,&23+ flagdecde ; INC IX/DEC IX
ADC A
aplib8getbit_
DB &FD,&67 ; LD IYh,A
RET
aplib8getgamma
LD HL,&0001
aplib8getgamma_
CALL aplib8getbit
ADC HL,HL
CALL aplib8getbit
JR C, aplib8getgamma_
LD C,L
RET
aplib8donedepacking
POP HL ; used for EX HL,(SP)
PUSH IX
POP HL
RET ; Warning, A might not be 0!
;------------------------------------------------------------------------------
; Player Arkos tracker
;------------------------------------------------------------------------------
PLAYER_ARKOS
list
;*** Start of Arkos Tracker Player
nolist
; music selector
LD A,(IX+00) ; numero de la musique
JP start_music ; front-end minable mais bon
PLAYER_ARKOS_OFF
JP PLY_InterruptionOff ; routine Arkos tracker
JP PLY_InterruptionContinue ; routine Arkos tracker
JP PLY_SetFadeValue
jp PLY_SFX_Init ;Call Player + 9 to initialise the sound effect music.
jp PLY_BasicSoundEffectInterface_PlaySound ;Call Player + 12 to add sound effect in BASIC.
jp PLY_SFX_Stop
start_music
LD A,E
ADD A,A ; x2
LD C,A
LD B,&0
LD HL,musiques
ADD HL,BC ; on pointe sur la table contenant l'adresse de depart d'une musique
LD E,(HL)
INC HL
LD D,(HL)
JP PLY_InterruptionOn
musiques
defw ZIC_RAYXAMBER1
defw ZIC_RAYXAMBER2
defw ZIC_RAYXAMBER3
defw &0000 ; rien
; Arkos Tracker Player V1.01 - CPC & MSX version.
; 21/09/09
; Code By Targhan/Arkos.
; PSG registers sendings based on Madram/Overlander's optimisation trick.
; Restoring interruption status snippet by Grim/Arkos.
; V1.01 additions
; ---------------
; - Small (but not useless !) optimisations by Grim/Arkos at the PLY_Track1_WaitCounter / PLY_Track2_WaitCounter / PLY_Track3_WaitCounter labels.
; - Optimisation of the R13 management by Grim/Arkos.
; This player can adapt to the following machines =
; Amstrad CPC and MSX.
; Output codes are specific, as well as the frequency tables.
; This player modifies all these registers = HL, DE, BC, AF, HL', DE', BC', AF', IX, IY.
; The Stack is used in conventionnal manners (Call, Ret, Push, Pop) so integration with any of your code should be seamless.
; The player does NOT modifies the Interruption state, unless you use the PLY_SystemFriendly flag, which will cut the
; interruptions at the beginning, and will restore them ONLY IF NEEDED.
; Basically, there are three kind of players.
; ASM
; ---
; Used in your Asm productions. You call the Player by yourself, you don't care if all the registers are modified.
; Set PLY_SystemFriendly and PLY_UseFirmwareInterruptions to 0.
; In Assembler =
; ld de,MusicAddress
; call Player / PLY_Init to initialise the player with your song.
; then
; call Player + 3 / PLY_Play whenever you want to play/continue the song.
; call Player + 6 / PLY_Stop to stop the song.
; BASIC
; -----
; Used in Basic (on CPC), or under the helm of any OS. Interruptions will be cut by the player, but restored ONLY IF NECESSARY.
; Also, some registers are saved (AF', BC', IX and IY), as they are used by the CPC Firmware.
; If you need to add/remove more registers, take care to do it at PLY_Play, but also at PLY_Stop.
; Registers are restored at PLY_PSGREG13_RecoverSystemRegisters.
; Set PLY_SystemFriendly to 1 and PLY_UseFirmwareInterruptions to 0.
; The Calls in Assembler are the same as above.
; In Basic =
; call Player, MusicAddress to initialise the player with your song.
; then
; call Player + 3 whenever you want to play/continue the song.
; call Player + 6 to stop the song.
; INTERRUPTIONS
; -------------
; CPC Only ! Uses the Firmware Interruptions to put the Player on interruption. Very useful in Basic.
; Set PLY_SystemFriendly and PLY_UseFirmwareInterruptions to 1.
; In Assembler =
; ld de,MusicAddress
; call Player / PLY_InterruptionOn to play the song from start.
; call Player + 3 / PLY_InterruptionOff to stop the song.
; call Player + 6 / PLY_InterruptionContinue to continue the song once it's been stopped.
; In Basic=
; call Player, MusicAddress to play the song from start.
; call Player + 3 to stop the song.
; call Player + 6 to continue the song once it's been stopped.
; FADES IN/OUT
; ------------
; The player allows the volume to be modified. It provides the interface, but you'll have to set the volume by yourself.
; Set PLY_UseFades to 1.
; In Assembler =
; ld e,Volume (0=full volume, 16 or more=no volume)
; call PLY_SetFadeValue
; In Basic =
; call Player + 9 (or + 18, see just below), Volume (0=full volume, 16 or more=no volume)
; WARNING ! You must call Player + 18 if PLY_UseBasicSoundEffectInterface is set to 1.
; SOUND EFFECTS
; -------------
; The player manages Sound Effects. They must be defined in another song, generated as a "SFX Music" in the Arkos Tracker.
; Set the PLY_UseSoundEffects to 1. If you want to use sound effects in Basic, set PLY_UseBasicSoundEffectInterface to 1.
; In Assembler =
; ld de,SFXMusicAddress
; call PLY_SFX_Init to initialise the SFX Song.
; Then initialise and play the "music" song normally.
; To play a sound effect =
; A = No Channel (0,1,2)
; L = SFX Number (>0)
; H = Volume (0...F)
; E = Note (0...143)
; D = Speed (0 = As original, 1...255 = new Speed (1 is the fastest))
; BC = Inverted Pitch (-#FFFF -> FFFF). 0 is no pitch. The higher the pitch, the lower the sound.
; call PLY_SFX_Play
; To stop a sound effect =
; ld e,No Channel (0,1,2)
; call PLY_SFX_Stop
; To stop the sound effects on all the channels =
; call PLY_SFX_StopAll
; In Basic =
; call Player + 9, SFXMusicAddress to initialise the SFX Song.
; To play a sound effect =
; call Player + 12, No Channel, SFX Number, Volume, Note, Speed, Inverted Pitch. No parameter should be ommited !
; To stop a sound effect =
; call Player + 15, No Channel (0,1,2)
; For more information, check the manual.
; Any question, complaint, a need to reward ? Write to contact@julien-nevo.com
PLY_UseCPCMachine equ 1 ;Indicates what frequency table and output code to use. 1 to use it.
PLY_UseMSXMachine equ 0
PLY_UseSoundEffects equ 1 ;Set to 1 if you want to use Sound Effects in your player. Both CPU and memory consuming.
PLY_UseFades equ 1 ;Set to 1 to allow fades in/out. A little CPU and memory consuming.
;PLY_SetFadeValue becomes available.
PLY_SystemFriendly equ 1 ;Set to 1 if you want to save the Registers used by AMSDOS (AF', BC', IX, IY)
;(which allows you to call this player in BASIC)
;As this option is system-friendly, it cuts the interruption, and restore them ONLY IF NECESSARY.
PLY_UseFirmwareInterruptions equ 1
;Set to 1 to use a Player under interruption. Only works on CPC, as it uses the CPC Firmware.
;WARNING, PLY_SystemFriendly must be set to 1 if you use the Player under interruption !
;SECOND WARNING, make sure the player is above #3fff, else it won't be played (system limitation).
PLY_UseBasicSoundEffectInterface equ 1 ;Set to 1 if you want a little interface to be added if you are a BASIC programmer who wants
;to use sound effects. Of course, you must also set PLY_UseSoundEffects to 1.
PLY_RetrigValue equ #fe ;Value used to trigger the Retrig of Register 13. #FE corresponds to CP xx. Do not change it !
Player
if PLY_UseFirmwareInterruptions
;******* Interruption Player ********
;You can remove these JPs if using the sub-routines directly.
jp PLY_InterruptionOn ;Call Player = Start Music.
jp PLY_InterruptionOff ;Call Player + 3 = Stop Music.
jp PLY_InterruptionContinue ;Call Player + 6 = Continue (after stopping).
if PLY_UseBasicSoundEffectInterface
jp PLY_SFX_Init ;Call Player + 9 to initialise the sound effect music.
jp PLY_BasicSoundEffectInterface_PlaySound ;Call Player + 12 to add sound effect in BASIC.
jp PLY_SFX_Stop ;Call Player + 15 to stop a sound effect.
endif
if PLY_UseFades
jp PLY_SetFadeValue ;Call Player + 9 or + 18 to set Fades values.
endif
PLY_InterruptionOn call PLY_Init
ld hl,PLY_Interruption_Convert
PLY_ReplayFrequency ld de,0
ld a,d
ld (PLY_Interruption_Cpt + 1),a
add hl,de
ld a,(hl) ;Chope nbinter wait
ld (PLY_Interruption_Value + 1),a
PLY_InterruptionContinue
ld hl,PLY_Interruption_ControlBloc
ld bc,%10000001*256+0
ld de,PLY_Interruption_Play
jp #bce0
PLY_InterruptionOff ld hl,PLY_Interruption_ControlBloc
call #bce6
jp PLY_Stop
PLY_Interruption_ControlBloc defs 10,0 ;Buffer used by the OS.
;Code run by the OS on each interruption.
PLY_Interruption_Play di
PLY_Interruption_Cpt ld a,0 ;Run the player only if it has to, according to the music frequency.
PLY_Interruption_Value cp 5
jr z,PLY_Interruption_NoWait
inc a
ld (PLY_Interruption_Cpt + 1),a
ret
PLY_Interruption_NoWait xor a
ld (PLY_Interruption_Cpt + 1),a
jp PLY_Play
;Table to convert PLY_ReplayFrequency into a Frequency value for the AMSDOS.
PLY_Interruption_Convert defb 17, 11, 5, 2, 1, 0
else
;***** Normal Player *****
;To be called when you want.
;You can remove these following JPs if using the sub-routines directly.
jp PLY_Init ;Call Player = Initialise song (DE = Song address).
jp PLY_Play ;Call Player + 3 = Play song.
jp PLY_Stop ;Call Player + 6 = Stop song.
endif
if PLY_UseBasicSoundEffectInterface
jp PLY_SFX_Init ;Call Player + 9 to initialise the sound effect music.
jp PLY_BasicSoundEffectInterface_PlaySound ;Call Player + 12 to add sound effect in BASIC.
jp PLY_SFX_Stop ;Call Player + 15 to stop a sound effect.
endif
if PLY_UseFades
jp PLY_SetFadeValue ;Call Player + 9 or + 18 to set Fades values.
endif
PLY_Digidrum db 0 ;Read here to know if a Digidrum has been played (0=no).
PLY_Play
if PLY_SystemFriendly
call PLY_DisableInterruptions
ex af,af'
exx
push af
push bc
push ix
push iy
endif
xor a
ld (PLY_Digidrum),a ;Reset the Digidrum flag.
;Manage Speed. If Speed counter is over, we have to read the Pattern further.
PLY_SpeedCpt ld a,1
dec a
jp nz,PLY_SpeedEnd
;Moving forward in the Pattern. Test if it is not over.
PLY_HeightCpt ld a,1
dec a
jr nz,PLY_HeightEnd
;Pattern Over. We have to read the Linker.
;Get the Transpositions, if they have changed, or detect the Song Ending !
PLY_Linker_PT ld hl,0
ld a,(hl)
inc hl
rra
jr nc,PLY_SongNotOver
;Song over ! We read the address of the Loop point.
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
ld a,(hl) ;We know the Song won't restart now, so we can skip the first bit.
inc hl
rra
PLY_SongNotOver
rra
jr nc,PLY_NoNewTransposition1
ld de,PLY_Transposition1 + 1
ldi
PLY_NoNewTransposition1
rra
jr nc,PLY_NoNewTransposition2
ld de,PLY_Transposition2 + 1
ldi
PLY_NoNewTransposition2
rra
jr nc,PLY_NoNewTransposition3
ld de,PLY_Transposition3 + 1
ldi
PLY_NoNewTransposition3
;Get the Tracks addresses.
ld de,PLY_Track1_PT + 1
ldi
ldi
ld de,PLY_Track2_PT + 1
ldi
ldi
ld de,PLY_Track3_PT + 1
ldi
ldi
;Get the Special Track address, if it has changed.
rra
jr nc,PLY_NoNewHeight
ld de,PLY_Height + 1
ldi
PLY_NoNewHeight
rra
jr nc,PLY_NoNewSpecialTrack
PLY_NewSpecialTrack
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld (PLY_SaveSpecialTrack + 1),de
PLY_NoNewSpecialTrack
ld (PLY_Linker_PT + 1),hl
PLY_SaveSpecialTrack ld hl,0
ld (PLY_SpecialTrack_PT + 1),hl
;Reset the SpecialTrack/Tracks line counter.
;We can't rely on the song data, because the Pattern Height is not related to the Tracks Height.
ld a,1
ld (PLY_SpecialTrack_WaitCounter + 1),a
ld (PLY_Track1_WaitCounter + 1),a
ld (PLY_Track2_WaitCounter + 1),a
ld (PLY_Track3_WaitCounter + 1),a
PLY_Height ld a,1
PLY_HeightEnd
ld (PLY_HeightCpt + 1),a
;Read the Special Track/Tracks.
;------------------------------
;Read the Special Track.
PLY_SpecialTrack_WaitCounter ld a,1
dec a
jr nz,PLY_SpecialTrack_Wait
PLY_SpecialTrack_PT ld hl,0
ld a,(hl)
inc hl
srl a ;Data (1) or Wait (0) ?
jr nc,PLY_SpecialTrack_NewWait ;If Wait, A contains the Wait value.
;Data. Effect Type ?
srl a ;Speed (0) or Digidrum (1) ?
;First, we don't test the Effect Type, but only the Escape Code (=0)
jr nz,PLY_SpecialTrack_NoEscapeCode
ld a,(hl)
inc hl
PLY_SpecialTrack_NoEscapeCode
;Now, we test the Effect type, since the Carry didn't change.
jr nc,PLY_SpecialTrack_Speed
ld (PLY_Digidrum),a
jr PLY_PT_SpecialTrack_EndData
PLY_SpecialTrack_Speed
ld (PLY_Speed + 1),a
PLY_PT_SpecialTrack_EndData
ld a,1
PLY_SpecialTrack_NewWait
ld (PLY_SpecialTrack_PT + 1),hl
PLY_SpecialTrack_Wait
ld (PLY_SpecialTrack_WaitCounter + 1),a
;Read the Track 1.
;-----------------
;Store the parameters, because the player below is called every frame, but the Read Track isn't.
PLY_Track1_WaitCounter ld a,1
dec a
jr nz,PLY_Track1_NewInstrument_SetWait
PLY_Track1_PT ld hl,0
call PLY_ReadTrack
ld (PLY_Track1_PT + 1),hl
jr c,PLY_Track1_NewInstrument_SetWait
;No Wait command. Can be a Note and/or Effects.
ld a,d ;Make a copy of the flags+Volume in A, not to temper with the original.
rra ;Volume ? If bit 4 was 1, then volume exists on b3-b0
jr nc,PLY_Track1_SameVolume
and %1111
ld (PLY_Track1_Volume),a
PLY_Track1_SameVolume
rl d ;New Pitch ?
jr nc,PLY_Track1_NoNewPitch
ld (PLY_Track1_PitchAdd + 1),ix
PLY_Track1_NoNewPitch
rl d ;Note ? If no Note, we don't have to test if a new Instrument is here.
jr nc,PLY_Track1_NoNoteGiven
ld a,e
PLY_Transposition1 add a,0 ;Transpose Note according to the Transposition in the Linker.
ld (PLY_Track1_Note),a
ld hl,0 ;Reset the TrackPitch.
ld (PLY_Track1_Pitch + 1),hl
rl d ;New Instrument ?
jr c,PLY_Track1_NewInstrument
PLY_Track1_SavePTInstrument ld hl,0 ;Same Instrument. We recover its address to restart it.
ld a,(PLY_Track1_InstrumentSpeed + 1) ;Reset the Instrument Speed Counter. Never seemed useful...
ld (PLY_Track1_InstrumentSpeedCpt + 1),a
jr PLY_Track1_InstrumentResetPT
PLY_Track1_NewInstrument ;New Instrument. We have to get its new address, and Speed.
ld l,b ;H is already set to 0 before.
add hl,hl
PLY_Track1_InstrumentsTablePT ld bc,0
add hl,bc
ld a,(hl) ;Get Instrument address.
inc hl
ld h,(hl)
ld l,a
ld a,(hl) ;Get Instrument speed.
inc hl
ld (PLY_Track1_InstrumentSpeed + 1),a
ld (PLY_Track1_InstrumentSpeedCpt + 1),a
ld a,(hl)
or a ;Get IsRetrig?. Code it only if different to 0, else next Instruments are going to overwrite it.
jr z,$+5
ld (PLY_PSGReg13_Retrig + 1),a
inc hl
ld (PLY_Track1_SavePTInstrument + 1),hl ;When using the Instrument again, no need to give the Speed, it is skipped.
PLY_Track1_InstrumentResetPT
ld (PLY_Track1_Instrument + 1),hl
PLY_Track1_NoNoteGiven
ld a,1
PLY_Track1_NewInstrument_SetWait
ld (PLY_Track1_WaitCounter + 1),a
;Read the Track 2.
;-----------------
;Store the parameters, because the player below is called every frame, but the Read Track isn't.
PLY_Track2_WaitCounter ld a,1
dec a
jr nz,PLY_Track2_NewInstrument_SetWait
PLY_Track2_PT ld hl,0
call PLY_ReadTrack
ld (PLY_Track2_PT + 1),hl
jr c,PLY_Track2_NewInstrument_SetWait
;No Wait command. Can be a Note and/or Effects.
ld a,d ;Make a copy of the flags+Volume in A, not to temper with the original.
rra ;Volume ? If bit 4 was 1, then volume exists on b3-b0
jr nc,PLY_Track2_SameVolume
and %1111
ld (PLY_Track2_Volume),a
PLY_Track2_SameVolume
rl d ;New Pitch ?
jr nc,PLY_Track2_NoNewPitch
ld (PLY_Track2_PitchAdd + 1),ix
PLY_Track2_NoNewPitch
rl d ;Note ? If no Note, we don't have to test if a new Instrument is here.
jr nc,PLY_Track2_NoNoteGiven
ld a,e
PLY_Transposition2 add a,0 ;Transpose Note according to the Transposition in the Linker.
ld (PLY_Track2_Note),a
ld hl,0 ;Reset the TrackPitch.
ld (PLY_Track2_Pitch + 1),hl
rl d ;New Instrument ?
jr c,PLY_Track2_NewInstrument
PLY_Track2_SavePTInstrument ld hl,0 ;Same Instrument. We recover its address to restart it.
ld a,(PLY_Track2_InstrumentSpeed + 1) ;Reset the Instrument Speed Counter. Never seemed useful...
ld (PLY_Track2_InstrumentSpeedCpt + 1),a
jr PLY_Track2_InstrumentResetPT
PLY_Track2_NewInstrument ;New Instrument. We have to get its new address, and Speed.
ld l,b ;H is already set to 0 before.
add hl,hl
PLY_Track2_InstrumentsTablePT ld bc,0
add hl,bc
ld a,(hl) ;Get Instrument address.
inc hl
ld h,(hl)
ld l,a
ld a,(hl) ;Get Instrument speed.
inc hl
ld (PLY_Track2_InstrumentSpeed + 1),a
ld (PLY_Track2_InstrumentSpeedCpt + 1),a
ld a,(hl)
or a ;Get IsRetrig?. Code it only if different to 0, else next Instruments are going to overwrite it.
jr z,$+5
ld (PLY_PSGReg13_Retrig + 1),a
inc hl
ld (PLY_Track2_SavePTInstrument + 1),hl ;When using the Instrument again, no need to give the Speed, it is skipped.
PLY_Track2_InstrumentResetPT
ld (PLY_Track2_Instrument + 1),hl
PLY_Track2_NoNoteGiven
ld a,1
PLY_Track2_NewInstrument_SetWait
ld (PLY_Track2_WaitCounter + 1),a
;Read the Track 3.
;-----------------
;Store the parameters, because the player below is called every frame, but the Read Track isn't.
PLY_Track3_WaitCounter ld a,1
dec a
jr nz,PLY_Track3_NewInstrument_SetWait
PLY_Track3_PT ld hl,0
call PLY_ReadTrack
ld (PLY_Track3_PT + 1),hl
jr c,PLY_Track3_NewInstrument_SetWait
;No Wait command. Can be a Note and/or Effects.
ld a,d ;Make a copy of the flags+Volume in A, not to temper with the original.
rra ;Volume ? If bit 4 was 1, then volume exists on b3-b0
jr nc,PLY_Track3_SameVolume
and %1111
ld (PLY_Track3_Volume),a
PLY_Track3_SameVolume
rl d ;New Pitch ?
jr nc,PLY_Track3_NoNewPitch
ld (PLY_Track3_PitchAdd + 1),ix
PLY_Track3_NoNewPitch
rl d ;Note ? If no Note, we don't have to test if a new Instrument is here.
jr nc,PLY_Track3_NoNoteGiven
ld a,e
PLY_Transposition3 add a,0 ;Transpose Note according to the Transposition in the Linker.
ld (PLY_Track3_Note),a
ld hl,0 ;Reset the TrackPitch.
ld (PLY_Track3_Pitch + 1),hl
rl d ;New Instrument ?
jr c,PLY_Track3_NewInstrument
PLY_Track3_SavePTInstrument ld hl,0 ;Same Instrument. We recover its address to restart it.
ld a,(PLY_Track3_InstrumentSpeed + 1) ;Reset the Instrument Speed Counter. Never seemed useful...
ld (PLY_Track3_InstrumentSpeedCpt + 1),a
jr PLY_Track3_InstrumentResetPT
PLY_Track3_NewInstrument ;New Instrument. We have to get its new address, and Speed.
ld l,b ;H is already set to 0 before.
add hl,hl
PLY_Track3_InstrumentsTablePT ld bc,0
add hl,bc
ld a,(hl) ;Get Instrument address.
inc hl
ld h,(hl)
ld l,a
ld a,(hl) ;Get Instrument speed.
inc hl
ld (PLY_Track3_InstrumentSpeed + 1),a
ld (PLY_Track3_InstrumentSpeedCpt + 1),a
ld a,(hl)
or a ;Get IsRetrig?. Code it only if different to 0, else next Instruments are going to overwrite it.
jr z,$+5
ld (PLY_PSGReg13_Retrig + 1),a
inc hl
ld (PLY_Track3_SavePTInstrument + 1),hl ;When using the Instrument again, no need to give the Speed, it is skipped.
PLY_Track3_InstrumentResetPT
ld (PLY_Track3_Instrument + 1),hl
PLY_Track3_NoNoteGiven
ld a,1
PLY_Track3_NewInstrument_SetWait
ld (PLY_Track3_WaitCounter + 1),a
PLY_Speed ld a,1
PLY_SpeedEnd
ld (PLY_SpeedCpt + 1),a
;Play the Sound on Track 3
;-------------------------
;Plays the sound on each frame, but only save the forwarded Instrument pointer when Instrument Speed is reached.
;This is needed because TrackPitch is involved in the Software Frequency/Hardware Frequency calculation, and is calculated every frame.
ld iy,PLY_PSGRegistersArray + 4
PLY_Track3_Pitch ld hl,0
PLY_Track3_PitchAdd ld de,0
add hl,de
ld (PLY_Track3_Pitch + 1),hl
sra h ;Shift the Pitch to slow its speed.
rr l
sra h
rr l
ex de,hl
exx
PLY_Track3_Volume equ $+2
PLY_Track3_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_Track3_Instrument ld hl,0
call PLY_PlaySound
PLY_Track3_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_Track3_PlayNoForward
ld (PLY_Track3_Instrument + 1),hl
PLY_Track3_InstrumentSpeed ld a,6
PLY_Track3_PlayNoForward
ld (PLY_Track3_InstrumentSpeedCpt + 1),a
;***************************************
;Play Sound Effects on Track 3 (only assembled used if PLY_UseSoundEffects is set to one)
;***************************************
if PLY_UseSoundEffects
PLY_SFX_Track3_Pitch ld de,0
exx
PLY_SFX_Track3_Volume equ $+2
PLY_SFX_Track3_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_SFX_Track3_Instrument ld hl,0 ;If 0, no sound effect.
ld a,l
or h
jr z,PLY_SFX_Track3_End
ld a,1
ld (PLY_PS_EndSound_SFX + 1),a
call PLY_PlaySound
xor a
ld (PLY_PS_EndSound_SFX + 1),a
ld a,l ;If the new address is 0, the instrument is over. Speed is set in the process, we don't care.
or h
jr z,PLY_SFX_Track3_Instrument_SetAddress
PLY_SFX_Track3_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_SFX_Track3_PlayNoForward
PLY_SFX_Track3_Instrument_SetAddress
ld (PLY_SFX_Track3_Instrument + 1),hl
PLY_SFX_Track3_InstrumentSpeed ld a,6
PLY_SFX_Track3_PlayNoForward
ld (PLY_SFX_Track3_InstrumentSpeedCpt + 1),a
PLY_SFX_Track3_End
endif
;******************************************
ld a,ixl ;Save the Register 7 of the Track 3.
ex af,af'
;Play the Sound on Track 2
;-------------------------
ld iy,PLY_PSGRegistersArray + 2
PLY_Track2_Pitch ld hl,0
PLY_Track2_PitchAdd ld de,0
add hl,de
ld (PLY_Track2_Pitch + 1),hl
sra h ;Shift the Pitch to slow its speed.
rr l
sra h
rr l
ex de,hl
exx
PLY_Track2_Volume equ $+2
PLY_Track2_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_Track2_Instrument ld hl,0
call PLY_PlaySound
PLY_Track2_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_Track2_PlayNoForward
ld (PLY_Track2_Instrument + 1),hl
PLY_Track2_InstrumentSpeed ld a,6
PLY_Track2_PlayNoForward
ld (PLY_Track2_InstrumentSpeedCpt + 1),a
;***************************************
;Play Sound Effects on Track 2 (only assembled used if PLY_UseSoundEffects is set to one)
;***************************************
if PLY_UseSoundEffects
PLY_SFX_Track2_Pitch ld de,0
exx
PLY_SFX_Track2_Volume equ $+2
PLY_SFX_Track2_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_SFX_Track2_Instrument ld hl,0 ;If 0, no sound effect.
ld a,l
or h
jr z,PLY_SFX_Track2_End
ld a,1
ld (PLY_PS_EndSound_SFX + 1),a
call PLY_PlaySound
xor a
ld (PLY_PS_EndSound_SFX + 1),a
ld a,l ;If the new address is 0, the instrument is over. Speed is set in the process, we don't care.
or h
jr z,PLY_SFX_Track2_Instrument_SetAddress
PLY_SFX_Track2_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_SFX_Track2_PlayNoForward
PLY_SFX_Track2_Instrument_SetAddress
ld (PLY_SFX_Track2_Instrument + 1),hl
PLY_SFX_Track2_InstrumentSpeed ld a,6
PLY_SFX_Track2_PlayNoForward
ld (PLY_SFX_Track2_InstrumentSpeedCpt + 1),a
PLY_SFX_Track2_End
endif
;******************************************
ex af,af'
add a,a ;Mix Reg7 from Track2 with Track3, making room first.
or ixl
rla
ex af,af'
;Play the Sound on Track 1
;-------------------------
ld iy,PLY_PSGRegistersArray
PLY_Track1_Pitch ld hl,0
PLY_Track1_PitchAdd ld de,0
add hl,de
ld (PLY_Track1_Pitch + 1),hl
sra h ;Shift the Pitch to slow its speed.
rr l
sra h
rr l
ex de,hl
exx
PLY_Track1_Volume equ $+2
PLY_Track1_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_Track1_Instrument ld hl,0
call PLY_PlaySound
PLY_Track1_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_Track1_PlayNoForward
ld (PLY_Track1_Instrument + 1),hl
PLY_Track1_InstrumentSpeed ld a,6
PLY_Track1_PlayNoForward
ld (PLY_Track1_InstrumentSpeedCpt + 1),a
;***************************************
;Play Sound Effects on Track 1 (only assembled used if PLY_UseSoundEffects is set to one)
;***************************************
if PLY_UseSoundEffects
PLY_SFX_Track1_Pitch ld de,0
exx
PLY_SFX_Track1_Volume equ $+2
PLY_SFX_Track1_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_SFX_Track1_Instrument ld hl,0 ;If 0, no sound effect.
ld a,l
or h
jr z,PLY_SFX_Track1_End
ld a,1
ld (PLY_PS_EndSound_SFX + 1),a
call PLY_PlaySound
xor a
ld (PLY_PS_EndSound_SFX + 1),a
ld a,l ;If the new address is 0, the instrument is over. Speed is set in the process, we don't care.
or h
jr z,PLY_SFX_Track1_Instrument_SetAddress
PLY_SFX_Track1_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_SFX_Track1_PlayNoForward
PLY_SFX_Track1_Instrument_SetAddress
ld (PLY_SFX_Track1_Instrument + 1),hl
PLY_SFX_Track1_InstrumentSpeed ld a,6
PLY_SFX_Track1_PlayNoForward
ld (PLY_SFX_Track1_InstrumentSpeedCpt + 1),a
PLY_SFX_Track1_End
endif
;***********************************
ex af,af'
or ixl ;Mix Reg7 from Track3 with Track2+1.
;Send the registers to PSG. Various codes according to the machine used.
PLY_SendRegisters
;A=Register 7
if PLY_UseMSXMachine
ld b,a
ld hl,PLY_PSGRegistersArray
;Register 0
xor a
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 1
ld a,1
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 2
ld a,2
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 3
ld a,3
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 4
ld a,4
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 5
ld a,5
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 6
ld a,6
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 7
ld a,7
out (#a0),a
ld a,b ;Use the stored Register 7.
out (#a1),a
;Register 8
ld a,8
out (#a0),a
ld a,(hl)
if PLY_UseFades
PLY_Channel1_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+3
xor a
endif
out (#a1),a
inc hl
inc hl ;Skip unused byte.
;Register 9
ld a,9
out (#a0),a
ld a,(hl)
if PLY_UseFades
PLY_Channel2_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+3
xor a
endif
out (#a1),a
inc hl
inc hl ;Skip unused byte.
;Register 10
ld a,10
out (#a0),a
ld a,(hl)
if PLY_UseFades
PLY_Channel3_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+3
xor a
endif
out (#a1),a
inc hl
;Register 11
ld a,11
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 12
ld a,12
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 13
if PLY_SystemFriendly
call PLY_PSGReg13_Code
PLY_PSGREG13_RecoverSystemRegisters
pop iy
pop ix
pop bc
pop af
exx
ex af,af'
;Restore Interrupt status
PLY_RestoreInterruption nop ;Will be automodified to an DI/EI.
ret
endif
PLY_PSGReg13_Code
ld a,13
out (#a0),a
ld a,(hl)
PLY_PSGReg13_Retrig cp 255 ;If IsRetrig?, force the R13 to be triggered.
ret z
out (#a1),a
ld (PLY_PSGReg13_Retrig + 1),a
ret
endif
if PLY_UseCPCMachine
ld de,#c080
ld b,#f6
out (c),d ;#f6c0
exx
ld hl,PLY_PSGRegistersArray
ld e,#f6
ld bc,#f401
;Register 0
defb #ed,#71 ;#f400+Register
ld b,e
defb #ed,#71 ;#f600
dec b
outi ;#f400+value
exx
out (c),e ;#f680
out (c),d ;#f6c0
exx
;Register 1
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 2
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 3
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 4
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 5
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 6
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 7
out (c),c
ld b,e
defb #ed,#71
dec b
dec b
out (c),a ;Read A register instead of the list.
exx
out (c),e
out (c),d
exx
inc c
;Register 8
out (c),c
ld b,e
defb #ed,#71
dec b
if PLY_UseFades
dec b
ld a,(hl)
PLY_Channel1_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+6
defb #ed,#71
jr $+4
out (c),a
inc hl
else
outi
endif
exx
out (c),e
out (c),d
exx
inc c
inc hl ;Skip unused byte.
;Register 9
out (c),c
ld b,e
defb #ed,#71
dec b
if PLY_UseFades ;If PLY_UseFades is set to 1, we manage the volume fade.
dec b
ld a,(hl)
PLY_Channel2_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+6
defb #ed,#71
jr $+4
out (c),a
inc hl
else
outi
endif
exx
out (c),e
out (c),d
exx
inc c
inc hl ;Skip unused byte.
;Register 10
out (c),c
ld b,e
defb #ed,#71
dec b
if PLY_UseFades
dec b
ld a,(hl)
PLY_Channel3_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+6
defb #ed,#71
jr $+4
out (c),a
inc hl
else
outi
endif
exx
out (c),e
out (c),d
exx
inc c
;Register 11
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 12
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 13
if PLY_SystemFriendly
call PLY_PSGReg13_Code
PLY_PSGREG13_RecoverSystemRegisters
pop iy
pop ix
pop bc
pop af
exx
ex af,af'
;Restore Interrupt status
PLY_RestoreInterruption nop ;Will be automodified to an DI/EI.
ret
endif
PLY_PSGReg13_Code
ld a,(hl)
PLY_PSGReg13_Retrig cp 255 ;If IsRetrig?, force the R13 to be triggered.
ret z
ld (PLY_PSGReg13_Retrig + 1),a
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
ret
endif
;There are two holes in the list, because the Volume registers are set relatively to the Frequency of the same Channel (+7, always).
;Also, the Reg7 is passed as a register, so is not kept in the memory.
PLY_PSGRegistersArray
PLY_PSGReg0 db 0
PLY_PSGReg1 db 0
PLY_PSGReg2 db 0
PLY_PSGReg3 db 0
PLY_PSGReg4 db 0
PLY_PSGReg5 db 0
PLY_PSGReg6 db 0
PLY_PSGReg8 db 0 ;+7
db 0
PLY_PSGReg9 db 0 ;+9
db 0
PLY_PSGReg10 db 0 ;+11
PLY_PSGReg11 db 0
PLY_PSGReg12 db 0
PLY_PSGReg13 db 0
PLY_PSGRegistersArray_End
;Plays a sound stream.
;HL=Pointer on Instrument Data
;IY=Pointer on Register code (volume, frequency).
;E=Note
;D=Inverted Volume
;DE'=TrackPitch
;RET=
;HL=New Instrument pointer.
;IXL=Reg7 mask (x00x)
;Also used inside =
;B,C=read byte/second byte.
;IXH=Save original Note (only used for Independant mode).
PLY_PlaySound
ld b,(hl)
inc hl
rr b
jp c,PLY_PS_Hard
;**************
;Software Sound
;**************
;Second Byte needed ?
rr b
jr c,PLY_PS_S_SecondByteNeeded
;No second byte needed. We need to check if Volume is null or not.
ld a,b
and %1111
jr nz,PLY_PS_S_SoundOn
;Null Volume. It means no Sound. We stop the Sound, the Noise, and it's over.
ld (iy + 7),a ;We have to make the volume to 0, because if a bass Hard was activated before, we have to stop it.
ld ixl,%1001
ret
PLY_PS_S_SoundOn
;Volume is here, no Second Byte needed. It means we have a simple Software sound (Sound = On, Noise = Off)
;We have to test Arpeggio and Pitch, however.
ld ixl,%1000
sub d ;Code Volume.
jr nc,$+3
xor a
ld (iy + 7),a
rr b ;Needed for the subroutine to get the good flags.
call PLY_PS_CalculateFrequency
ld (iy + 0),l ;Code Frequency.
ld (iy + 1),h
exx
ret
PLY_PS_S_SecondByteNeeded
ld ixl,%1000 ;By defaut, No Noise, Sound.
;Second Byte needed.
ld c,(hl)
inc hl
;Noise ?
ld a,c
and %11111
jr z,PLY_PS_S_SBN_NoNoise
ld (PLY_PSGReg6),a
ld ixl,%0000 ;Open Noise Channel.
PLY_PS_S_SBN_NoNoise
;Here we have either Volume and/or Sound. So first we need to read the Volume.
ld a,b
and %1111
sub d ;Code Volume.
jr nc,$+3
xor a
ld (iy + 7),a
;Sound ?
bit 5,c
jr nz,PLY_PS_S_SBN_Sound
;No Sound. Stop here.
inc ixl ;Set Sound bit to stop the Sound.
ret
PLY_PS_S_SBN_Sound
;Manual Frequency ?
rr b ;Needed for the subroutine to get the good flags.
bit 6,c
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (iy + 0),l ;Code Frequency.
ld (iy + 1),h
exx
ret
;**********
;Hard Sound
;**********
PLY_PS_Hard
;We don't set the Volume to 16 now because we may have reached the end of the sound !
rr b ;Test Retrig here, it is common to every Hard sounds.
jr nc,PLY_PS_Hard_NoRetrig
ld a,(PLY_Track1_InstrumentSpeedCpt + 1) ;Retrig only if it is the first step in this line of Instrument !
ld c,a
ld a,(PLY_Track1_InstrumentSpeed + 1)
cp c
jr nz,PLY_PS_Hard_NoRetrig
ld a,PLY_RetrigValue
ld (PLY_PSGReg13_Retrig + 1),a
PLY_PS_Hard_NoRetrig
;Independant/Loop or Software/Hardware Dependent ?
bit 1,b ;We don't shift the bits, so that we can use the same code (Frequency calculation) several times.
jp nz,PLY_PS_Hard_LoopOrIndependent
;Hardware Sound.
ld (iy + 7),16 ;Set Volume
ld ixl,%1000 ;Sound is always On here (only Independence mode can switch it off).
;This code is common to both Software and Hardware Dependent.
ld c,(hl) ;Get Second Byte.
inc hl
ld a,c ;Get the Hardware Envelope waveform.
and %1111 ;We don't care about the bit 7-4, but we have to clear them, else the waveform might be reset.
ld (PLY_PSGReg13),a
bit 0,b
jr z,PLY_PS_HardwareDependent
;******************
;Software Dependent
;******************
;Calculate the Software frequency
bit 4-2,b ;Manual Frequency ? -2 Because the byte has been shifted previously.
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (iy + 0),l ;Code Software Frequency.
ld (iy + 1),h
exx
;Shift the Frequency.
ld a,c
rra
rra ;Shift=Shift*4. The shift is inverted in memory (7 - Editor Shift).
and %11100
ld (PLY_PS_SD_Shift + 1),a
ld a,b ;Used to get the HardwarePitch flag within the second registers set.
exx
PLY_PS_SD_Shift jr $+2
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,$+3
inc hl
;Hardware Pitch ?
bit 7-2,a
jr z,PLY_PS_SD_NoHardwarePitch
exx ;Get Pitch and add it to the just calculated Hardware Frequency.
ld a,(hl)
inc hl
exx
add a,l ;Slow. Can be optimised ? Probably never used anyway.....
ld l,a
exx
ld a,(hl)
inc hl
exx
adc a,h
ld h,a
PLY_PS_SD_NoHardwarePitch
ld (PLY_PSGReg11),hl
exx
;This code is also used by Hardware Dependent.
PLY_PS_SD_Noise
;Noise ?
bit 7,c
ret z
ld a,(hl)
inc hl
ld (PLY_PSGReg6),a
ld ixl,%0000
ret
;******************
;Hardware Dependent
;******************
PLY_PS_HardwareDependent
;Calculate the Hardware frequency
bit 4-2,b ;Manual Hardware Frequency ? -2 Because the byte has been shifted previously.
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (PLY_PSGReg11),hl ;Code Hardware Frequency.
exx
;Shift the Hardware Frequency.
ld a,c
rra
rra ;Shift=Shift*4. The shift is inverted in memory (7 - Editor Shift).
and %11100
ld (PLY_PS_HD_Shift + 1),a
ld a,b ;Used to get the Software flag within the second registers set.
exx
PLY_PS_HD_Shift jr $+2
sla l
rl h
sla l
rl h
sla l
rl h
sla l
rl h
sla l
rl h
sla l
rl h
sla l
rl h
;Software Pitch ?
bit 7-2,a
jr z,PLY_PS_HD_NoSoftwarePitch
exx ;Get Pitch and add it to the just calculated Software Frequency.
ld a,(hl)
inc hl
exx
add a,l
ld l,a ;Slow. Can be optimised ? Probably never used anyway.....
exx
ld a,(hl)
inc hl
exx
adc a,h
ld h,a
PLY_PS_HD_NoSoftwarePitch
ld (iy + 0),l ;Code Frequency.
ld (iy + 1),h
exx
;Go to manage Noise, common to Software Dependent.
jr PLY_PS_SD_Noise
PLY_PS_Hard_LoopOrIndependent
bit 0,b ;We mustn't shift it to get the result in the Carry, as it would be mess the structure
jr z,PLY_PS_Independent ;of the flags, making it uncompatible with the common code.
;The sound has ended.
;If Sound Effects activated, we mark the "end of sound" by returning a 0 as an address.
if PLY_UseSoundEffects
PLY_PS_EndSound_SFX ld a,0 ;Is the sound played is a SFX (1) or a normal sound (0) ?
or a
jr z,PLY_PS_EndSound_NotASFX
ld hl,0
ret
PLY_PS_EndSound_NotASFX
endif
;The sound has ended. Read the new pointer and restart instrument.
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
jp PLY_PlaySound
;***********
;Independent
;***********
PLY_PS_Independent
ld (iy + 7),16 ;Set Volume
;Sound ?
bit 7-2,b ;-2 Because the byte has been shifted previously.
jr nz,PLY_PS_I_SoundOn
;No Sound ! It means we don't care about the software frequency (manual frequency, arpeggio, pitch).
ld ixl,%1001
jr PLY_PS_I_SkipSoftwareFrequencyCalculation
PLY_PS_I_SoundOn
ld ixl,%1000 ;Sound is on.
ld ixh,e ;Save the original note for the Hardware frequency, because a Software Arpeggio will modify it.
;Calculate the Software frequency
bit 4-2,b ;Manual Frequency ? -2 Because the byte has been shifted previously.
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (iy + 0),l ;Code Software Frequency.
ld (iy + 1),h
exx
ld e,ixh
PLY_PS_I_SkipSoftwareFrequencyCalculation
ld b,(hl) ;Get Second Byte.
inc hl
ld a,b ;Get the Hardware Envelope waveform.
and %1111 ;We don't care about the bit 7-4, but we have to clear them, else the waveform might be reset.
ld (PLY_PSGReg13),a
;Calculate the Hardware frequency
rr b ;Must shift it to match the expected data of the subroutine.
rr b
bit 4-2,b ;Manual Hardware Frequency ? -2 Because the byte has been shifted previously.
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (PLY_PSGReg11),hl ;Code Hardware Frequency.
exx
;Noise ? We can't use the previous common code, because the setting of the Noise is different, since Independent can have no Sound.
bit 7-2,b
ret z
ld a,(hl)
inc hl
ld (PLY_PSGReg6),a
ld a,ixl ;Set the Noise bit.
res 3,a
ld ixl,a
ret
;Subroutine that =
;If Manual Frequency? (Flag Z off), read frequency (Word) and adds the TrackPitch (DE').
;Else, Auto Frequency.
; if Arpeggio? = 1 (bit 3 from B), read it (Byte).
; if Pitch? = 1 (bit 4 from B), read it (Word).
; Calculate the frequency according to the Note (E) + Arpeggio + TrackPitch (DE').
;HL = Pointer on Instrument data.
;DE'= TrackPitch.
;RET=
;HL = Pointer on Instrument moved forward.
;HL'= Frequency
; RETURN IN AUXILIARY REGISTERS
PLY_PS_CalculateFrequency_TestManualFrequency
jr z,PLY_PS_CalculateFrequency
;Manual Frequency. We read it, no need to read Pitch and Arpeggio.
;However, we add TrackPitch to the read Frequency, and that's all.
ld a,(hl)
inc hl
exx
add a,e ;Add TrackPitch LSB.
ld l,a
exx
ld a,(hl)
inc hl
exx
adc a,d ;Add TrackPitch HSB.
ld h,a
ret
PLY_PS_CalculateFrequency
;Pitch ?
bit 5-1,b
jr z,PLY_PS_S_SoundOn_NoPitch
ld a,(hl)
inc hl
exx
add a,e ;If Pitch found, add it directly to the TrackPitch.
ld e,a
exx
ld a,(hl)
inc hl
exx
adc a,d
ld d,a
exx
PLY_PS_S_SoundOn_NoPitch
;Arpeggio ?
ld a,e
bit 4-1,b
jr z,PLY_PS_S_SoundOn_ArpeggioEnd
add a,(hl) ;Add Arpeggio to Note.
inc hl
cp 144
jr c,$+4
ld a,143
PLY_PS_S_SoundOn_ArpeggioEnd
;Frequency calculation.
exx
ld l,a
ld h,0
add hl,hl
ld bc,PLY_FrequencyTable
add hl,bc
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
add hl,de ;Add TrackPitch + InstrumentPitch (if any).
ret
;Read one Track.
;HL=Track Pointer.
;Ret =
;HL=New Track Pointer.
;Carry = 1 = Wait A lines. Carry=0=Line not empty.
;A=Wait (0(=256)-127), if Carry.
;D=Parameters + Volume.
;E=Note
;B=Instrument. 0=RST
;IX=PitchAdd. Only used if Pitch? = 1.
PLY_ReadTrack
ld a,(hl)
inc hl
srl a ;Full Optimisation ? If yes = Note only, no Pitch, no Volume, Same Instrument.
jr c,PLY_ReadTrack_FullOptimisation
sub 32 ;0-31 = Wait.
jr c,PLY_ReadTrack_Wait
jr z,PLY_ReadTrack_NoOptimisation_EscapeCode
dec a ;0 (32-32) = Escape Code for more Notes (parameters will be read)
;Note. Parameters are present. But the note is only present if Note? flag is 1.
ld e,a ;Save Note.
;Read Parameters
PLY_ReadTrack_ReadParameters
ld a,(hl)
ld d,a ;Save Parameters.
inc hl
rla ;Pitch ?
jr nc,PLY_ReadTrack_Pitch_End
ld b,(hl) ;Get PitchAdd
ld ixl,b
inc hl
ld b,(hl)
ld ixh,b
inc hl
PLY_ReadTrack_Pitch_End
rla ;Skip IsNote? flag.
rla ;New Instrument ?
ret nc
ld b,(hl)
inc hl
or a ;Remove Carry, as the player interpret it as a Wait command.
ret
;Escape code, read the Note and returns to read the Parameters.
PLY_ReadTrack_NoOptimisation_EscapeCode
ld e,(hl)
inc hl
jr PLY_ReadTrack_ReadParameters
PLY_ReadTrack_FullOptimisation
;Note only, no Pitch, no Volume, Same Instrument.
ld d,%01000000 ;Note only.
sub 1
ld e,a
ret nc
ld e,(hl) ;Escape Code found (0). Read Note.
inc hl
or a
ret
PLY_ReadTrack_Wait
add a,32
ret
PLY_FrequencyTable
if PLY_UseCPCMachine
dw 3822,3608,3405,3214,3034,2863,2703,2551,2408,2273,2145,2025
dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012
dw 956,902,851,804,758,716,676,638,602,568,536,506
dw 478,451,426,402,379,358,338,319,301,284,268,253
dw 239,225,213,201,190,179,169,159,150,142,134,127
dw 119,113,106,100,95,89,84,80,75,71,67,63
dw 60,56,53,50,47,45,42,40,38,36,34,32
dw 30,28,27,25,24,22,21,20,19,18,17,16
dw 15,14,13,13,12,11,11,10,9,9,8,8
dw 7,7,7,6,6,6,5,5,5,4,4,4
dw 4,4,3,3,3,3,3,2,2,2,2,2
dw 2,2,2,2,1,1,1,1,1,1,1,1
endif
if PLY_UseMSXMachine
dw 4095,4095,4095,4095,4095,4095,4095,4095,4095,4030,3804,3591
dw 3389,3199,3019,2850,2690,2539,2397,2262,2135,2015,1902,1795
dw 1695,1599,1510,1425,1345,1270,1198,1131,1068,1008,951,898
dw 847,800,755,712,673,635,599,566,534,504,476,449
dw 424,400,377,356,336,317,300,283,267,252,238,224
dw 212,200,189,178,168,159,150,141,133,126,119,112
dw 106,100,94,89,84,79,75,71,67,63,59,56
dw 53,50,47,45,42,40,37,35,33,31,30,28
dw 26,25,24,22,21,20,19,18,17,16,15,14
dw 13,12,12,11,11,10,9,9,8,8,7,7
dw 7,6,6,6,5,5,5,4,4,4,4,4
dw 3,3,3,3,3,2,2,2,2,2,2,2
endif
;DE = Music
PLY_Init
if PLY_UseFirmwareInterruptions
ld hl,8 ;Skip Header, SampleChannel, YM Clock (DB*3). The Replay Frequency is used in Interruption mode.
add hl,de
ld de,PLY_ReplayFrequency + 1
ldi
else
ld hl,9 ;Skip Header, SampleChannel, YM Clock (DB*3), and Replay Frequency.
add hl,de
endif
ld de,PLY_Speed + 1
ldi ;Copy Speed.
ld c,(hl) ;Get Instruments chunk size.
inc hl
ld b,(hl)
inc hl
ld (PLY_Track1_InstrumentsTablePT + 1),hl
ld (PLY_Track2_InstrumentsTablePT + 1),hl
ld (PLY_Track3_InstrumentsTablePT + 1),hl
add hl,bc ;Skip Instruments to go to the Linker address.
;Get the pre-Linker information of the first pattern.
ld de,PLY_Height + 1
ldi
ld de,PLY_Transposition1 + 1
ldi
ld de,PLY_Transposition2 + 1
ldi
ld de,PLY_Transposition3 + 1
ldi
ld de,PLY_SaveSpecialTrack + 1
ldi
ldi
ld (PLY_Linker_PT + 1),hl ;Get the Linker address.
ld a,1
ld (PLY_SpeedCpt + 1),a
ld (PLY_HeightCpt + 1),a
ld a,#ff
ld (PLY_PSGReg13),a
;Set the Instruments pointers to Instrument 0 data (Header has to be skipped).
ld hl,(PLY_Track1_InstrumentsTablePT + 1)
ld e,(hl)
inc hl
ld d,(hl)
ex de,hl
inc hl ;Skip Instrument 0 Header.
inc hl
ld (PLY_Track1_Instrument + 1),hl
ld (PLY_Track2_Instrument + 1),hl
ld (PLY_Track3_Instrument + 1),hl
ret
;Stop the music, cut the channels.
PLY_Stop
if PLY_SystemFriendly
call PLY_DisableInterruptions
ex af,af'
exx
push af
push bc
push ix
push iy
endif
ld hl,PLY_PSGReg8
ld bc,#0300
ld (hl),c
inc hl
djnz $-2
ld a,%00111111
jp PLY_SendRegisters
if PLY_UseSoundEffects
;Initialize the Sound Effects.
;DE = SFX Music.
PLY_SFX_Init
;Find the Instrument Table.
ld hl,12
add hl,de
ld (PLY_SFX_Play_InstrumentTable + 1),hl
;Clear the three channels of any sound effect.
PLY_SFX_StopAll
ld hl,0
ld (PLY_SFX_Track1_Instrument + 1),hl
ld (PLY_SFX_Track2_Instrument + 1),hl
ld (PLY_SFX_Track3_Instrument + 1),hl
ret
PLY_SFX_OffsetPitch equ 0
PLY_SFX_OffsetVolume equ PLY_SFX_Track1_Volume - PLY_SFX_Track1_Pitch
PLY_SFX_OffsetNote equ PLY_SFX_Track1_Note - PLY_SFX_Track1_Pitch
PLY_SFX_OffsetInstrument equ PLY_SFX_Track1_Instrument - PLY_SFX_Track1_Pitch
PLY_SFX_OffsetSpeed equ PLY_SFX_Track1_InstrumentSpeed - PLY_SFX_Track1_Pitch
PLY_SFX_OffsetSpeedCpt equ PLY_SFX_Track1_InstrumentSpeedCpt - PLY_SFX_Track1_Pitch
;Plays a Sound Effects along with the music.
;A = No Channel (0,1,2)
;L = SFX Number (>0)
;H = Volume (0...F)
;E = Note (0...143)
;D = Speed (0 = As original, 1...255 = new Speed (1 is fastest))
;BC = Inverted Pitch (-#FFFF -> FFFF). 0 is no pitch. The higher the pitch, the lower the sound.
PLY_SFX_Play
ld ix,PLY_SFX_Track1_Pitch
or a
jr z,PLY_SFX_Play_Selected
ld ix,PLY_SFX_Track2_Pitch
dec a
jr z,PLY_SFX_Play_Selected
ld ix,PLY_SFX_Track3_Pitch
PLY_SFX_Play_Selected
ld (ix + PLY_SFX_OffsetPitch + 1),c ;Set Pitch
ld (ix + PLY_SFX_OffsetPitch + 2),b
ld a,e ;Set Note
ld (ix + PLY_SFX_OffsetNote),a
ld a,15 ;Set Volume
sub h
ld (ix + PLY_SFX_OffsetVolume),a
ld h,0 ;Set Instrument Address
add hl,hl
PLY_SFX_Play_InstrumentTable ld bc,0
add hl,bc
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
ld a,d ;Read Speed or use the user's one ?
or a
jr nz,PLY_SFX_Play_UserSpeed
ld a,(hl) ;Get Speed
PLY_SFX_Play_UserSpeed
ld (ix + PLY_SFX_OffsetSpeed + 1),a
ld (ix + PLY_SFX_OffsetSpeedCpt + 1),a
inc hl ;Skip Retrig
inc hl
ld (ix + PLY_SFX_OffsetInstrument + 1),l
ld (ix + PLY_SFX_OffsetInstrument + 2),h
ret
;Stops a sound effect on the selected channel
;E = No Channel (0,1,2)
;I used the E register instead of A so that Basic users can call this code in a straightforward way (call player+15, value).
PLY_SFX_Stop
ld a,e
ld hl,PLY_SFX_Track1_Instrument + 1
or a
jr z,PLY_SFX_Stop_ChannelFound
ld hl,PLY_SFX_Track2_Instrument + 1
dec a
jr z,PLY_SFX_Stop_ChannelFound
ld hl,PLY_SFX_Track3_Instrument + 1
dec a
PLY_SFX_Stop_ChannelFound
ld (hl),a
inc hl
ld (hl),a
ret
endif
if PLY_UseFades
;Sets the Fade value.
;E = Fade value (0 = full volume, 16 or more = no volume).
;I used the E register instead of A so that Basic users can call this code in a straightforward way (call player+9/+18, value).
PLY_SetFadeValue
ld a,e
ld (PLY_Channel1_FadeValue + 1),a
ld (PLY_Channel2_FadeValue + 1),a
ld (PLY_Channel3_FadeValue + 1),a
ret
endif
if PLY_SystemFriendly
;Save Interrupt status and Disable Interruptions
PLY_DisableInterruptions
ld a,i
di
;IFF in P/V flag.
;Prepare opcode for DI.
ld a,#f3
jp po,PLY_DisableInterruptions_Set_Opcode
;Opcode for EI.
ld a,#fb
PLY_DisableInterruptions_Set_Opcode
ld (PLY_RestoreInterruption),a
ret
endif
;A little convient interface for BASIC user, to allow them to use Sound Effects in Basic.
if PLY_UseBasicSoundEffectInterface
PLY_BasicSoundEffectInterface_PlaySound
ld c,(ix+0) ;Get Pitch
ld b,(ix+1)
ld d,(ix+2) ;Get Speed
ld e,(ix+4) ;Get Note
ld h,(ix+6) ;Get Volume
ld l,(ix+8) ;Get SFX number
ld a,(ix+10) ;Get Channel
jp PLY_SFX_Play
endif
list
;*** End of Arkos Tracker Player
nolist
NOTICE TEXTE n° 3 (56.45 Ko)
- - - - - - - - - - - - - - - - - [ assemble_fichier_final.asm ] - - - - - - - - - - - - - - - - -
;LOAD"-BASIC.BAS
;ASSEMBLE
;CALL &A000
ORG &1F0
;transfert de la fin vers le debut pour eviter l'ecrasement des donnees
; LD HL,&200
LD HL,&447F
; LD DE,&4000
LD DE,&827F
LD BC,&4280
; LDIR
LDDR
JP &76C0
RET
;&200 FIN.PRG
ORG &A000
;ECRAN.DAT en &0200
LD B,&0C
LD HL,fichier1
LD DE,&C000
CALL &BC77 ;lecture entete
LD HL,&0200
CALL &BC83 ;lecture fichier
CALL &BC7A ;ferme le fichier
;sauvegarde
LD B,&0C
LD HL,fichier_final
LD DE,&C000
CALL &BC8C
LD HL,&0170 ;adresse debut
LD DE,&4320 ;longueur (on arrondi)
LD BC,&FADA ;execution (n'importe quoi, mais on s'amuse)
LD A,0 ;fichier basic
CALL &BC98
CALL &BC8F
CALL &BC89
CALL &BC92
fichier1
DEFM "FIN .PRG"
fichier_final
DEFM "END .BAS"
- - - - - - - - - - - - - - - - - [ fin.asm ] - - - - - - - - - - - - - - - - -
SPRITE_HAUTEUR EQU 38
SPRITE_LARGEUR EQU 9
SPRITE_ADR_ECRAN EQU &CCBF
;SPRITES.SPR lg &1560
FRAME1 EQU &4000
FRAME2 EQU &4000+342
FRAME3 EQU &4000+684
FRAME4 EQU &4000+1026
FRAME5 EQU &4000+1368
FRAME6 EQU &4000+1710
FRAME7 EQU &4000+2052
FRAME8 EQU &4000+2394
FRAME9 EQU &4000+2736
FRAME10 EQU &4000+3078
FRAME11 EQU &4000+3420
FRAME12 EQU &4000+3762
FRAME13 EQU &4000+4104
FRAME14 EQU &4000+4446
FRAME15 EQU &4000+4788
FRAME16 EQU &4000+5130
;fin &555F
;FIN2.MUS
ZIC_RAYXAMBER EQU &5600 ;lg &1C2
;fin &57C1
;ENDFIN.SPR
ETOILE_FIN EQU &5800 ;lg &474
;fin &5C73
;FIN.PAK
ECRAN_FIN_PAK EQU &5C80 ;lg &1A34
;fin &76B4
TEMPO EQU 2
TEMPO2 EQU 1
ORG &76C0
WRITE DIRECT "FIN.BIN"
CALL TEST
CALL DECOMPACK
CALL ETOILES
LD A,0
LD B,0
LD C,0
LD D,0
LD E,0
LD H,0
LD L,0
CALL PLAYER_ARKOS
CALL AFF_COULEURS
.loop_anim
LD A,25:CALL DELAYN:LD HL,FRAME1:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME2:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME3:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME4:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME5:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME6:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME7:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME8:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME9:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME10:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME11:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME12:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME13:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME14:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME15:CALL AFF_SPRITE
LD A,TEMPO:CALL DELAY:LD HL,FRAME16:CALL AFF_SPRITE
LD A,25:CALL DELAYN:LD HL,FRAME15:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME14:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME13:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME12:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME11:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME10:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME9:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME8:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME7:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME6:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME5:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME4:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME3:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME2:CALL AFF_SPRITE
LD A,TEMPO2:CALL DELAY:LD HL,FRAME1:CALL AFF_SPRITE
LD A,50:CALL DELAY
JP loop_anim
RET
;------------------------------------------------------------------------------
; Couleurs
;------------------------------------------------------------------------------
.AFF_COULEURS
LD HL,couleurs
XOR A
loopcouleurs
PUSH AF
PUSH HL
LD B,(HL)
LD C,B
CALL &BC32
CALL &BD19:CALL &BD19:CALL &BD19:CALL &BD19
POP HL
INC HL
POP AF
INC A
CP 16
JR NZ,loopcouleurs
;encre 2 clignotante
LD A,2
LD B,11
LD C,23
CALL &BC32
RET
.couleurs
DEFB 0,1,11,3,4,5,6,9,11,12,14,16,21,23,24,26
;------------------------------------------------------------------------------
; Test
;------------------------------------------------------------------------------
.TEST
LD A,(&BE81)
CP "O" ;&4F
JP Z,suite
CALL 0
.suite
LD A,(&BE82)
CP "K" ;&4B
JP Z,suite2
CALL 0
.suite2
RET
;------------------------------------------------------------------------------
; Etoiles FIN (0=SP, 1=FR) ou END (2=UK)
;------------------------------------------------------------------------------
.ETOILES
LD A,(&BE80)
CP 0:CALL Z,ETOILES_SP_FR
CP 1:CALL Z,ETOILES_SP_FR
CP 2:CALL Z,ETOILES_UK
.AFF_SPRITEB
LD DE,&C121
LD A,19
AFF_SPRITEB1
PUSH DE
LD BC,30
LDIR
POP DE
PUSH HL
LD HL,&800
ADD HL,DE
JR NC,AFF_SPRITEB2
LD BC,&C050
ADD HL,BC
AFF_SPRITEB2
EX HL,DE
POP HL
DEC A
JR NZ,AFF_SPRITEB1
RET
.ETOILES_SP_FR
LD HL,ETOILE_FIN+&23A
RET
.ETOILES_UK
LD HL,ETOILE_FIN
RET
;------------------------------------------------------------------------------
; Sprite opaque
; Entrees ;
; - LIGNES = nombre de lignes
; - LARGEUR = largeur du sprite en octets
; - HL = adresse du sprite
; - DE = adresse ecran.
;------------------------------------------------------------------------------
.AFF_SPRITE
LD DE,SPRITE_ADR_ECRAN
LD A,SPRITE_HAUTEUR
AFF_SPRITE1
PUSH DE
LD BC,SPRITE_LARGEUR
LDIR
POP DE
PUSH HL
LD HL,&800
ADD HL,DE
JR NC,AFF_SPRITE2
LD BC,&C050
ADD HL,BC
AFF_SPRITE2
EX HL,DE
POP HL
DEC A
JR NZ,AFF_SPRITE1
RET
;------------------------------------------------------------------------------
; DELAY SUBROUTINE
; A = Time
;------------------------------------------------------------------------------
DELAY EI
DELAY_1 LD B,5 ; 15 x 1/300th ms (HALT) = 50ms
DELAY_2 HALT ; Waits 1/300th s
DJNZ DELAY_2 ; Loop for 50ms
DEC A
JR NZ,DELAY_1 ; Loop for A x 50ms
DI
RET
;------------------------------------------------------------------------------
; DELAY SUBROUTINE (0.05s to 12.75s)
; A = Timeout / 50ms
;------------------------------------------------------------------------------
DELAYN EI
DELAYN_1 LD B,15 ; 15 x 1/300th ms (HALT) = 50ms
DELAYN_2 HALT ; Waits 1/300th s
DJNZ DELAYN_2 ; Loop for 50ms
DEC A
JR NZ,DELAYN_1 ; Loop for A x 50ms
DI
RET
;------------------------------------------------------------------------------
; Player Arkos tracker
;------------------------------------------------------------------------------
PLAYER_ARKOS
list
;*** Start of Arkos Tracker Player
nolist
; music selector
JP start_music ; front-end minable mais bon
PLAYER_ARKOS_OFF
JP PLY_InterruptionOff ; routine Arkos tracker
JP PLY_InterruptionContinue ; routine Arkos tracker
JP PLY_SetFadeValue
jp PLY_SFX_Init ;Call Player + 9 to initialise the sound effect music.
jp PLY_BasicSoundEffectInterface_PlaySound ;Call Player + 12 to add sound effect in BASIC.
jp PLY_SFX_Stop
start_music
LD A,E
ADD A,A ; x2
LD C,A
LD B,&0
LD HL,musiques
ADD HL,BC ; on pointe sur la table contenant l'adresse de depart d'une musique
LD E,(HL)
INC HL
LD D,(HL)
JP PLY_InterruptionOn
musiques
defw ZIC_RAYXAMBER
defw &0000 ; rien
defw &0000 ; rien
;end &5D03
; Arkos Tracker Player V1.01 - CPC & MSX version.
; 21/09/09
; Code By Targhan/Arkos.
; PSG registers sendings based on Madram/Overlander's optimisation trick.
; Restoring interruption status snippet by Grim/Arkos.
; V1.01 additions
; ---------------
; - Small (but not useless !) optimisations by Grim/Arkos at the PLY_Track1_WaitCounter / PLY_Track2_WaitCounter / PLY_Track3_WaitCounter labels.
; - Optimisation of the R13 management by Grim/Arkos.
; This player can adapt to the following machines =
; Amstrad CPC and MSX.
; Output codes are specific, as well as the frequency tables.
; This player modifies all these registers = HL, DE, BC, AF, HL', DE', BC', AF', IX, IY.
; The Stack is used in conventionnal manners (Call, Ret, Push, Pop) so integration with any of your code should be seamless.
; The player does NOT modifies the Interruption state, unless you use the PLY_SystemFriendly flag, which will cut the
; interruptions at the beginning, and will restore them ONLY IF NEEDED.
; Basically, there are three kind of players.
; ASM
; ---
; Used in your Asm productions. You call the Player by yourself, you don't care if all the registers are modified.
; Set PLY_SystemFriendly and PLY_UseFirmwareInterruptions to 0.
; In Assembler =
; ld de,MusicAddress
; call Player / PLY_Init to initialise the player with your song.
; then
; call Player + 3 / PLY_Play whenever you want to play/continue the song.
; call Player + 6 / PLY_Stop to stop the song.
; BASIC
; -----
; Used in Basic (on CPC), or under the helm of any OS. Interruptions will be cut by the player, but restored ONLY IF NECESSARY.
; Also, some registers are saved (AF', BC', IX and IY), as they are used by the CPC Firmware.
; If you need to add/remove more registers, take care to do it at PLY_Play, but also at PLY_Stop.
; Registers are restored at PLY_PSGREG13_RecoverSystemRegisters.
; Set PLY_SystemFriendly to 1 and PLY_UseFirmwareInterruptions to 0.
; The Calls in Assembler are the same as above.
; In Basic =
; call Player, MusicAddress to initialise the player with your song.
; then
; call Player + 3 whenever you want to play/continue the song.
; call Player + 6 to stop the song.
; INTERRUPTIONS
; -------------
; CPC Only ! Uses the Firmware Interruptions to put the Player on interruption. Very useful in Basic.
; Set PLY_SystemFriendly and PLY_UseFirmwareInterruptions to 1.
; In Assembler =
; ld de,MusicAddress
; call Player / PLY_InterruptionOn to play the song from start.
; call Player + 3 / PLY_InterruptionOff to stop the song.
; call Player + 6 / PLY_InterruptionContinue to continue the song once it's been stopped.
; In Basic=
; call Player, MusicAddress to play the song from start.
; call Player + 3 to stop the song.
; call Player + 6 to continue the song once it's been stopped.
; FADES IN/OUT
; ------------
; The player allows the volume to be modified. It provides the interface, but you'll have to set the volume by yourself.
; Set PLY_UseFades to 1.
; In Assembler =
; ld e,Volume (0=full volume, 16 or more=no volume)
; call PLY_SetFadeValue
; In Basic =
; call Player + 9 (or + 18, see just below), Volume (0=full volume, 16 or more=no volume)
; WARNING ! You must call Player + 18 if PLY_UseBasicSoundEffectInterface is set to 1.
; SOUND EFFECTS
; -------------
; The player manages Sound Effects. They must be defined in another song, generated as a "SFX Music" in the Arkos Tracker.
; Set the PLY_UseSoundEffects to 1. If you want to use sound effects in Basic, set PLY_UseBasicSoundEffectInterface to 1.
; In Assembler =
; ld de,SFXMusicAddress
; call PLY_SFX_Init to initialise the SFX Song.
; Then initialise and play the "music" song normally.
; To play a sound effect =
; A = No Channel (0,1,2)
; L = SFX Number (>0)
; H = Volume (0...F)
; E = Note (0...143)
; D = Speed (0 = As original, 1...255 = new Speed (1 is the fastest))
; BC = Inverted Pitch (-#FFFF -> FFFF). 0 is no pitch. The higher the pitch, the lower the sound.
; call PLY_SFX_Play
; To stop a sound effect =
; ld e,No Channel (0,1,2)
; call PLY_SFX_Stop
; To stop the sound effects on all the channels =
; call PLY_SFX_StopAll
; In Basic =
; call Player + 9, SFXMusicAddress to initialise the SFX Song.
; To play a sound effect =
; call Player + 12, No Channel, SFX Number, Volume, Note, Speed, Inverted Pitch. No parameter should be ommited !
; To stop a sound effect =
; call Player + 15, No Channel (0,1,2)
; For more information, check the manual.
; Any question, complaint, a need to reward ? Write to contact@julien-nevo.com
PLY_UseCPCMachine equ 1 ;Indicates what frequency table and output code to use. 1 to use it.
PLY_UseMSXMachine equ 0
PLY_UseSoundEffects equ 1 ;Set to 1 if you want to use Sound Effects in your player. Both CPU and memory consuming.
PLY_UseFades equ 1 ;Set to 1 to allow fades in/out. A little CPU and memory consuming.
;PLY_SetFadeValue becomes available.
PLY_SystemFriendly equ 1 ;Set to 1 if you want to save the Registers used by AMSDOS (AF', BC', IX, IY)
;(which allows you to call this player in BASIC)
;As this option is system-friendly, it cuts the interruption, and restore them ONLY IF NECESSARY.
PLY_UseFirmwareInterruptions equ 1
;Set to 1 to use a Player under interruption. Only works on CPC, as it uses the CPC Firmware.
;WARNING, PLY_SystemFriendly must be set to 1 if you use the Player under interruption !
;SECOND WARNING, make sure the player is above #3fff, else it won't be played (system limitation).
PLY_UseBasicSoundEffectInterface equ 1 ;Set to 1 if you want a little interface to be added if you are a BASIC programmer who wants
;to use sound effects. Of course, you must also set PLY_UseSoundEffects to 1.
PLY_RetrigValue equ #fe ;Value used to trigger the Retrig of Register 13. #FE corresponds to CP xx. Do not change it !
Player
if PLY_UseFirmwareInterruptions
;******* Interruption Player ********
;You can remove these JPs if using the sub-routines directly.
jp PLY_InterruptionOn ;Call Player = Start Music.
jp PLY_InterruptionOff ;Call Player + 3 = Stop Music.
jp PLY_InterruptionContinue ;Call Player + 6 = Continue (after stopping).
if PLY_UseBasicSoundEffectInterface
jp PLY_SFX_Init ;Call Player + 9 to initialise the sound effect music.
jp PLY_BasicSoundEffectInterface_PlaySound ;Call Player + 12 to add sound effect in BASIC.
jp PLY_SFX_Stop ;Call Player + 15 to stop a sound effect.
endif
if PLY_UseFades
jp PLY_SetFadeValue ;Call Player + 9 or + 18 to set Fades values.
endif
PLY_InterruptionOn call PLY_Init
ld hl,PLY_Interruption_Convert
PLY_ReplayFrequency ld de,0
ld a,d
ld (PLY_Interruption_Cpt + 1),a
add hl,de
ld a,(hl) ;Chope nbinter wait
ld (PLY_Interruption_Value + 1),a
PLY_InterruptionContinue
ld hl,PLY_Interruption_ControlBloc
ld bc,%10000001*256+0
ld de,PLY_Interruption_Play
jp #bce0
PLY_InterruptionOff ld hl,PLY_Interruption_ControlBloc
call #bce6
jp PLY_Stop
PLY_Interruption_ControlBloc defs 10,0 ;Buffer used by the OS.
;Code run by the OS on each interruption.
PLY_Interruption_Play di
PLY_Interruption_Cpt ld a,0 ;Run the player only if it has to, according to the music frequency.
PLY_Interruption_Value cp 5
jr z,PLY_Interruption_NoWait
inc a
ld (PLY_Interruption_Cpt + 1),a
ret
PLY_Interruption_NoWait xor a
ld (PLY_Interruption_Cpt + 1),a
jp PLY_Play
;Table to convert PLY_ReplayFrequency into a Frequency value for the AMSDOS.
PLY_Interruption_Convert defb 17, 11, 5, 2, 1, 0
else
;***** Normal Player *****
;To be called when you want.
;You can remove these following JPs if using the sub-routines directly.
jp PLY_Init ;Call Player = Initialise song (DE = Song address).
jp PLY_Play ;Call Player + 3 = Play song.
jp PLY_Stop ;Call Player + 6 = Stop song.
endif
if PLY_UseBasicSoundEffectInterface
jp PLY_SFX_Init ;Call Player + 9 to initialise the sound effect music.
jp PLY_BasicSoundEffectInterface_PlaySound ;Call Player + 12 to add sound effect in BASIC.
jp PLY_SFX_Stop ;Call Player + 15 to stop a sound effect.
endif
if PLY_UseFades
jp PLY_SetFadeValue ;Call Player + 9 or + 18 to set Fades values.
endif
PLY_Digidrum db 0 ;Read here to know if a Digidrum has been played (0=no).
PLY_Play
if PLY_SystemFriendly
call PLY_DisableInterruptions
ex af,af'
exx
push af
push bc
push ix
push iy
endif
xor a
ld (PLY_Digidrum),a ;Reset the Digidrum flag.
;Manage Speed. If Speed counter is over, we have to read the Pattern further.
PLY_SpeedCpt ld a,1
dec a
jp nz,PLY_SpeedEnd
;Moving forward in the Pattern. Test if it is not over.
PLY_HeightCpt ld a,1
dec a
jr nz,PLY_HeightEnd
;Pattern Over. We have to read the Linker.
;Get the Transpositions, if they have changed, or detect the Song Ending !
PLY_Linker_PT ld hl,0
ld a,(hl)
inc hl
rra
jr nc,PLY_SongNotOver
;Song over ! We read the address of the Loop point.
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
ld a,(hl) ;We know the Song won't restart now, so we can skip the first bit.
inc hl
rra
PLY_SongNotOver
rra
jr nc,PLY_NoNewTransposition1
ld de,PLY_Transposition1 + 1
ldi
PLY_NoNewTransposition1
rra
jr nc,PLY_NoNewTransposition2
ld de,PLY_Transposition2 + 1
ldi
PLY_NoNewTransposition2
rra
jr nc,PLY_NoNewTransposition3
ld de,PLY_Transposition3 + 1
ldi
PLY_NoNewTransposition3
;Get the Tracks addresses.
ld de,PLY_Track1_PT + 1
ldi
ldi
ld de,PLY_Track2_PT + 1
ldi
ldi
ld de,PLY_Track3_PT + 1
ldi
ldi
;Get the Special Track address, if it has changed.
rra
jr nc,PLY_NoNewHeight
ld de,PLY_Height + 1
ldi
PLY_NoNewHeight
rra
jr nc,PLY_NoNewSpecialTrack
PLY_NewSpecialTrack
ld e,(hl)
inc hl
ld d,(hl)
inc hl
ld (PLY_SaveSpecialTrack + 1),de
PLY_NoNewSpecialTrack
ld (PLY_Linker_PT + 1),hl
PLY_SaveSpecialTrack ld hl,0
ld (PLY_SpecialTrack_PT + 1),hl
;Reset the SpecialTrack/Tracks line counter.
;We can't rely on the song data, because the Pattern Height is not related to the Tracks Height.
ld a,1
ld (PLY_SpecialTrack_WaitCounter + 1),a
ld (PLY_Track1_WaitCounter + 1),a
ld (PLY_Track2_WaitCounter + 1),a
ld (PLY_Track3_WaitCounter + 1),a
PLY_Height ld a,1
PLY_HeightEnd
ld (PLY_HeightCpt + 1),a
;Read the Special Track/Tracks.
;------------------------------
;Read the Special Track.
PLY_SpecialTrack_WaitCounter ld a,1
dec a
jr nz,PLY_SpecialTrack_Wait
PLY_SpecialTrack_PT ld hl,0
ld a,(hl)
inc hl
srl a ;Data (1) or Wait (0) ?
jr nc,PLY_SpecialTrack_NewWait ;If Wait, A contains the Wait value.
;Data. Effect Type ?
srl a ;Speed (0) or Digidrum (1) ?
;First, we don't test the Effect Type, but only the Escape Code (=0)
jr nz,PLY_SpecialTrack_NoEscapeCode
ld a,(hl)
inc hl
PLY_SpecialTrack_NoEscapeCode
;Now, we test the Effect type, since the Carry didn't change.
jr nc,PLY_SpecialTrack_Speed
ld (PLY_Digidrum),a
jr PLY_PT_SpecialTrack_EndData
PLY_SpecialTrack_Speed
ld (PLY_Speed + 1),a
PLY_PT_SpecialTrack_EndData
ld a,1
PLY_SpecialTrack_NewWait
ld (PLY_SpecialTrack_PT + 1),hl
PLY_SpecialTrack_Wait
ld (PLY_SpecialTrack_WaitCounter + 1),a
;Read the Track 1.
;-----------------
;Store the parameters, because the player below is called every frame, but the Read Track isn't.
PLY_Track1_WaitCounter ld a,1
dec a
jr nz,PLY_Track1_NewInstrument_SetWait
PLY_Track1_PT ld hl,0
call PLY_ReadTrack
ld (PLY_Track1_PT + 1),hl
jr c,PLY_Track1_NewInstrument_SetWait
;No Wait command. Can be a Note and/or Effects.
ld a,d ;Make a copy of the flags+Volume in A, not to temper with the original.
rra ;Volume ? If bit 4 was 1, then volume exists on b3-b0
jr nc,PLY_Track1_SameVolume
and %1111
ld (PLY_Track1_Volume),a
PLY_Track1_SameVolume
rl d ;New Pitch ?
jr nc,PLY_Track1_NoNewPitch
ld (PLY_Track1_PitchAdd + 1),ix
PLY_Track1_NoNewPitch
rl d ;Note ? If no Note, we don't have to test if a new Instrument is here.
jr nc,PLY_Track1_NoNoteGiven
ld a,e
PLY_Transposition1 add a,0 ;Transpose Note according to the Transposition in the Linker.
ld (PLY_Track1_Note),a
ld hl,0 ;Reset the TrackPitch.
ld (PLY_Track1_Pitch + 1),hl
rl d ;New Instrument ?
jr c,PLY_Track1_NewInstrument
PLY_Track1_SavePTInstrument ld hl,0 ;Same Instrument. We recover its address to restart it.
ld a,(PLY_Track1_InstrumentSpeed + 1) ;Reset the Instrument Speed Counter. Never seemed useful...
ld (PLY_Track1_InstrumentSpeedCpt + 1),a
jr PLY_Track1_InstrumentResetPT
PLY_Track1_NewInstrument ;New Instrument. We have to get its new address, and Speed.
ld l,b ;H is already set to 0 before.
add hl,hl
PLY_Track1_InstrumentsTablePT ld bc,0
add hl,bc
ld a,(hl) ;Get Instrument address.
inc hl
ld h,(hl)
ld l,a
ld a,(hl) ;Get Instrument speed.
inc hl
ld (PLY_Track1_InstrumentSpeed + 1),a
ld (PLY_Track1_InstrumentSpeedCpt + 1),a
ld a,(hl)
or a ;Get IsRetrig?. Code it only if different to 0, else next Instruments are going to overwrite it.
jr z,$+5
ld (PLY_PSGReg13_Retrig + 1),a
inc hl
ld (PLY_Track1_SavePTInstrument + 1),hl ;When using the Instrument again, no need to give the Speed, it is skipped.
PLY_Track1_InstrumentResetPT
ld (PLY_Track1_Instrument + 1),hl
PLY_Track1_NoNoteGiven
ld a,1
PLY_Track1_NewInstrument_SetWait
ld (PLY_Track1_WaitCounter + 1),a
;Read the Track 2.
;-----------------
;Store the parameters, because the player below is called every frame, but the Read Track isn't.
PLY_Track2_WaitCounter ld a,1
dec a
jr nz,PLY_Track2_NewInstrument_SetWait
PLY_Track2_PT ld hl,0
call PLY_ReadTrack
ld (PLY_Track2_PT + 1),hl
jr c,PLY_Track2_NewInstrument_SetWait
;No Wait command. Can be a Note and/or Effects.
ld a,d ;Make a copy of the flags+Volume in A, not to temper with the original.
rra ;Volume ? If bit 4 was 1, then volume exists on b3-b0
jr nc,PLY_Track2_SameVolume
and %1111
ld (PLY_Track2_Volume),a
PLY_Track2_SameVolume
rl d ;New Pitch ?
jr nc,PLY_Track2_NoNewPitch
ld (PLY_Track2_PitchAdd + 1),ix
PLY_Track2_NoNewPitch
rl d ;Note ? If no Note, we don't have to test if a new Instrument is here.
jr nc,PLY_Track2_NoNoteGiven
ld a,e
PLY_Transposition2 add a,0 ;Transpose Note according to the Transposition in the Linker.
ld (PLY_Track2_Note),a
ld hl,0 ;Reset the TrackPitch.
ld (PLY_Track2_Pitch + 1),hl
rl d ;New Instrument ?
jr c,PLY_Track2_NewInstrument
PLY_Track2_SavePTInstrument ld hl,0 ;Same Instrument. We recover its address to restart it.
ld a,(PLY_Track2_InstrumentSpeed + 1) ;Reset the Instrument Speed Counter. Never seemed useful...
ld (PLY_Track2_InstrumentSpeedCpt + 1),a
jr PLY_Track2_InstrumentResetPT
PLY_Track2_NewInstrument ;New Instrument. We have to get its new address, and Speed.
ld l,b ;H is already set to 0 before.
add hl,hl
PLY_Track2_InstrumentsTablePT ld bc,0
add hl,bc
ld a,(hl) ;Get Instrument address.
inc hl
ld h,(hl)
ld l,a
ld a,(hl) ;Get Instrument speed.
inc hl
ld (PLY_Track2_InstrumentSpeed + 1),a
ld (PLY_Track2_InstrumentSpeedCpt + 1),a
ld a,(hl)
or a ;Get IsRetrig?. Code it only if different to 0, else next Instruments are going to overwrite it.
jr z,$+5
ld (PLY_PSGReg13_Retrig + 1),a
inc hl
ld (PLY_Track2_SavePTInstrument + 1),hl ;When using the Instrument again, no need to give the Speed, it is skipped.
PLY_Track2_InstrumentResetPT
ld (PLY_Track2_Instrument + 1),hl
PLY_Track2_NoNoteGiven
ld a,1
PLY_Track2_NewInstrument_SetWait
ld (PLY_Track2_WaitCounter + 1),a
;Read the Track 3.
;-----------------
;Store the parameters, because the player below is called every frame, but the Read Track isn't.
PLY_Track3_WaitCounter ld a,1
dec a
jr nz,PLY_Track3_NewInstrument_SetWait
PLY_Track3_PT ld hl,0
call PLY_ReadTrack
ld (PLY_Track3_PT + 1),hl
jr c,PLY_Track3_NewInstrument_SetWait
;No Wait command. Can be a Note and/or Effects.
ld a,d ;Make a copy of the flags+Volume in A, not to temper with the original.
rra ;Volume ? If bit 4 was 1, then volume exists on b3-b0
jr nc,PLY_Track3_SameVolume
and %1111
ld (PLY_Track3_Volume),a
PLY_Track3_SameVolume
rl d ;New Pitch ?
jr nc,PLY_Track3_NoNewPitch
ld (PLY_Track3_PitchAdd + 1),ix
PLY_Track3_NoNewPitch
rl d ;Note ? If no Note, we don't have to test if a new Instrument is here.
jr nc,PLY_Track3_NoNoteGiven
ld a,e
PLY_Transposition3 add a,0 ;Transpose Note according to the Transposition in the Linker.
ld (PLY_Track3_Note),a
ld hl,0 ;Reset the TrackPitch.
ld (PLY_Track3_Pitch + 1),hl
rl d ;New Instrument ?
jr c,PLY_Track3_NewInstrument
PLY_Track3_SavePTInstrument ld hl,0 ;Same Instrument. We recover its address to restart it.
ld a,(PLY_Track3_InstrumentSpeed + 1) ;Reset the Instrument Speed Counter. Never seemed useful...
ld (PLY_Track3_InstrumentSpeedCpt + 1),a
jr PLY_Track3_InstrumentResetPT
PLY_Track3_NewInstrument ;New Instrument. We have to get its new address, and Speed.
ld l,b ;H is already set to 0 before.
add hl,hl
PLY_Track3_InstrumentsTablePT ld bc,0
add hl,bc
ld a,(hl) ;Get Instrument address.
inc hl
ld h,(hl)
ld l,a
ld a,(hl) ;Get Instrument speed.
inc hl
ld (PLY_Track3_InstrumentSpeed + 1),a
ld (PLY_Track3_InstrumentSpeedCpt + 1),a
ld a,(hl)
or a ;Get IsRetrig?. Code it only if different to 0, else next Instruments are going to overwrite it.
jr z,$+5
ld (PLY_PSGReg13_Retrig + 1),a
inc hl
ld (PLY_Track3_SavePTInstrument + 1),hl ;When using the Instrument again, no need to give the Speed, it is skipped.
PLY_Track3_InstrumentResetPT
ld (PLY_Track3_Instrument + 1),hl
PLY_Track3_NoNoteGiven
ld a,1
PLY_Track3_NewInstrument_SetWait
ld (PLY_Track3_WaitCounter + 1),a
PLY_Speed ld a,1
PLY_SpeedEnd
ld (PLY_SpeedCpt + 1),a
;Play the Sound on Track 3
;-------------------------
;Plays the sound on each frame, but only save the forwarded Instrument pointer when Instrument Speed is reached.
;This is needed because TrackPitch is involved in the Software Frequency/Hardware Frequency calculation, and is calculated every frame.
ld iy,PLY_PSGRegistersArray + 4
PLY_Track3_Pitch ld hl,0
PLY_Track3_PitchAdd ld de,0
add hl,de
ld (PLY_Track3_Pitch + 1),hl
sra h ;Shift the Pitch to slow its speed.
rr l
sra h
rr l
ex de,hl
exx
PLY_Track3_Volume equ $+2
PLY_Track3_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_Track3_Instrument ld hl,0
call PLY_PlaySound
PLY_Track3_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_Track3_PlayNoForward
ld (PLY_Track3_Instrument + 1),hl
PLY_Track3_InstrumentSpeed ld a,6
PLY_Track3_PlayNoForward
ld (PLY_Track3_InstrumentSpeedCpt + 1),a
;***************************************
;Play Sound Effects on Track 3 (only assembled used if PLY_UseSoundEffects is set to one)
;***************************************
if PLY_UseSoundEffects
PLY_SFX_Track3_Pitch ld de,0
exx
PLY_SFX_Track3_Volume equ $+2
PLY_SFX_Track3_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_SFX_Track3_Instrument ld hl,0 ;If 0, no sound effect.
ld a,l
or h
jr z,PLY_SFX_Track3_End
ld a,1
ld (PLY_PS_EndSound_SFX + 1),a
call PLY_PlaySound
xor a
ld (PLY_PS_EndSound_SFX + 1),a
ld a,l ;If the new address is 0, the instrument is over. Speed is set in the process, we don't care.
or h
jr z,PLY_SFX_Track3_Instrument_SetAddress
PLY_SFX_Track3_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_SFX_Track3_PlayNoForward
PLY_SFX_Track3_Instrument_SetAddress
ld (PLY_SFX_Track3_Instrument + 1),hl
PLY_SFX_Track3_InstrumentSpeed ld a,6
PLY_SFX_Track3_PlayNoForward
ld (PLY_SFX_Track3_InstrumentSpeedCpt + 1),a
PLY_SFX_Track3_End
endif
;******************************************
ld a,ixl ;Save the Register 7 of the Track 3.
ex af,af'
;Play the Sound on Track 2
;-------------------------
ld iy,PLY_PSGRegistersArray + 2
PLY_Track2_Pitch ld hl,0
PLY_Track2_PitchAdd ld de,0
add hl,de
ld (PLY_Track2_Pitch + 1),hl
sra h ;Shift the Pitch to slow its speed.
rr l
sra h
rr l
ex de,hl
exx
PLY_Track2_Volume equ $+2
PLY_Track2_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_Track2_Instrument ld hl,0
call PLY_PlaySound
PLY_Track2_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_Track2_PlayNoForward
ld (PLY_Track2_Instrument + 1),hl
PLY_Track2_InstrumentSpeed ld a,6
PLY_Track2_PlayNoForward
ld (PLY_Track2_InstrumentSpeedCpt + 1),a
;***************************************
;Play Sound Effects on Track 2 (only assembled used if PLY_UseSoundEffects is set to one)
;***************************************
if PLY_UseSoundEffects
PLY_SFX_Track2_Pitch ld de,0
exx
PLY_SFX_Track2_Volume equ $+2
PLY_SFX_Track2_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_SFX_Track2_Instrument ld hl,0 ;If 0, no sound effect.
ld a,l
or h
jr z,PLY_SFX_Track2_End
ld a,1
ld (PLY_PS_EndSound_SFX + 1),a
call PLY_PlaySound
xor a
ld (PLY_PS_EndSound_SFX + 1),a
ld a,l ;If the new address is 0, the instrument is over. Speed is set in the process, we don't care.
or h
jr z,PLY_SFX_Track2_Instrument_SetAddress
PLY_SFX_Track2_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_SFX_Track2_PlayNoForward
PLY_SFX_Track2_Instrument_SetAddress
ld (PLY_SFX_Track2_Instrument + 1),hl
PLY_SFX_Track2_InstrumentSpeed ld a,6
PLY_SFX_Track2_PlayNoForward
ld (PLY_SFX_Track2_InstrumentSpeedCpt + 1),a
PLY_SFX_Track2_End
endif
;******************************************
ex af,af'
add a,a ;Mix Reg7 from Track2 with Track3, making room first.
or ixl
rla
ex af,af'
;Play the Sound on Track 1
;-------------------------
ld iy,PLY_PSGRegistersArray
PLY_Track1_Pitch ld hl,0
PLY_Track1_PitchAdd ld de,0
add hl,de
ld (PLY_Track1_Pitch + 1),hl
sra h ;Shift the Pitch to slow its speed.
rr l
sra h
rr l
ex de,hl
exx
PLY_Track1_Volume equ $+2
PLY_Track1_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_Track1_Instrument ld hl,0
call PLY_PlaySound
PLY_Track1_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_Track1_PlayNoForward
ld (PLY_Track1_Instrument + 1),hl
PLY_Track1_InstrumentSpeed ld a,6
PLY_Track1_PlayNoForward
ld (PLY_Track1_InstrumentSpeedCpt + 1),a
;***************************************
;Play Sound Effects on Track 1 (only assembled used if PLY_UseSoundEffects is set to one)
;***************************************
if PLY_UseSoundEffects
PLY_SFX_Track1_Pitch ld de,0
exx
PLY_SFX_Track1_Volume equ $+2
PLY_SFX_Track1_Note equ $+1
ld de,0 ;D=Inverted Volume E=Note
PLY_SFX_Track1_Instrument ld hl,0 ;If 0, no sound effect.
ld a,l
or h
jr z,PLY_SFX_Track1_End
ld a,1
ld (PLY_PS_EndSound_SFX + 1),a
call PLY_PlaySound
xor a
ld (PLY_PS_EndSound_SFX + 1),a
ld a,l ;If the new address is 0, the instrument is over. Speed is set in the process, we don't care.
or h
jr z,PLY_SFX_Track1_Instrument_SetAddress
PLY_SFX_Track1_InstrumentSpeedCpt ld a,1
dec a
jr nz,PLY_SFX_Track1_PlayNoForward
PLY_SFX_Track1_Instrument_SetAddress
ld (PLY_SFX_Track1_Instrument + 1),hl
PLY_SFX_Track1_InstrumentSpeed ld a,6
PLY_SFX_Track1_PlayNoForward
ld (PLY_SFX_Track1_InstrumentSpeedCpt + 1),a
PLY_SFX_Track1_End
endif
;***********************************
ex af,af'
or ixl ;Mix Reg7 from Track3 with Track2+1.
;Send the registers to PSG. Various codes according to the machine used.
PLY_SendRegisters
;A=Register 7
if PLY_UseMSXMachine
ld b,a
ld hl,PLY_PSGRegistersArray
;Register 0
xor a
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 1
ld a,1
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 2
ld a,2
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 3
ld a,3
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 4
ld a,4
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 5
ld a,5
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 6
ld a,6
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 7
ld a,7
out (#a0),a
ld a,b ;Use the stored Register 7.
out (#a1),a
;Register 8
ld a,8
out (#a0),a
ld a,(hl)
if PLY_UseFades
PLY_Channel1_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+3
xor a
endif
out (#a1),a
inc hl
inc hl ;Skip unused byte.
;Register 9
ld a,9
out (#a0),a
ld a,(hl)
if PLY_UseFades
PLY_Channel2_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+3
xor a
endif
out (#a1),a
inc hl
inc hl ;Skip unused byte.
;Register 10
ld a,10
out (#a0),a
ld a,(hl)
if PLY_UseFades
PLY_Channel3_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+3
xor a
endif
out (#a1),a
inc hl
;Register 11
ld a,11
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 12
ld a,12
out (#a0),a
ld a,(hl)
out (#a1),a
inc hl
;Register 13
if PLY_SystemFriendly
call PLY_PSGReg13_Code
PLY_PSGREG13_RecoverSystemRegisters
pop iy
pop ix
pop bc
pop af
exx
ex af,af'
;Restore Interrupt status
PLY_RestoreInterruption nop ;Will be automodified to an DI/EI.
ret
endif
PLY_PSGReg13_Code
ld a,13
out (#a0),a
ld a,(hl)
PLY_PSGReg13_Retrig cp 255 ;If IsRetrig?, force the R13 to be triggered.
ret z
out (#a1),a
ld (PLY_PSGReg13_Retrig + 1),a
ret
endif
if PLY_UseCPCMachine
ld de,#c080
ld b,#f6
out (c),d ;#f6c0
exx
ld hl,PLY_PSGRegistersArray
ld e,#f6
ld bc,#f401
;Register 0
defb #ed,#71 ;#f400+Register
ld b,e
defb #ed,#71 ;#f600
dec b
outi ;#f400+value
exx
out (c),e ;#f680
out (c),d ;#f6c0
exx
;Register 1
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 2
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 3
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 4
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 5
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 6
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 7
out (c),c
ld b,e
defb #ed,#71
dec b
dec b
out (c),a ;Read A register instead of the list.
exx
out (c),e
out (c),d
exx
inc c
;Register 8
out (c),c
ld b,e
defb #ed,#71
dec b
if PLY_UseFades
dec b
ld a,(hl)
PLY_Channel1_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+6
defb #ed,#71
jr $+4
out (c),a
inc hl
else
outi
endif
exx
out (c),e
out (c),d
exx
inc c
inc hl ;Skip unused byte.
;Register 9
out (c),c
ld b,e
defb #ed,#71
dec b
if PLY_UseFades ;If PLY_UseFades is set to 1, we manage the volume fade.
dec b
ld a,(hl)
PLY_Channel2_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+6
defb #ed,#71
jr $+4
out (c),a
inc hl
else
outi
endif
exx
out (c),e
out (c),d
exx
inc c
inc hl ;Skip unused byte.
;Register 10
out (c),c
ld b,e
defb #ed,#71
dec b
if PLY_UseFades
dec b
ld a,(hl)
PLY_Channel3_FadeValue sub 0 ;Set a value from 0 (full volume) to 16 or more (volume to 0).
jr nc,$+6
defb #ed,#71
jr $+4
out (c),a
inc hl
else
outi
endif
exx
out (c),e
out (c),d
exx
inc c
;Register 11
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 12
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
exx
inc c
;Register 13
if PLY_SystemFriendly
call PLY_PSGReg13_Code
PLY_PSGREG13_RecoverSystemRegisters
pop iy
pop ix
pop bc
pop af
exx
ex af,af'
;Restore Interrupt status
PLY_RestoreInterruption nop ;Will be automodified to an DI/EI.
ret
endif
PLY_PSGReg13_Code
ld a,(hl)
PLY_PSGReg13_Retrig cp 255 ;If IsRetrig?, force the R13 to be triggered.
ret z
ld (PLY_PSGReg13_Retrig + 1),a
out (c),c
ld b,e
defb #ed,#71
dec b
outi
exx
out (c),e
out (c),d
ret
endif
;There are two holes in the list, because the Volume registers are set relatively to the Frequency of the same Channel (+7, always).
;Also, the Reg7 is passed as a register, so is not kept in the memory.
PLY_PSGRegistersArray
PLY_PSGReg0 db 0
PLY_PSGReg1 db 0
PLY_PSGReg2 db 0
PLY_PSGReg3 db 0
PLY_PSGReg4 db 0
PLY_PSGReg5 db 0
PLY_PSGReg6 db 0
PLY_PSGReg8 db 0 ;+7
db 0
PLY_PSGReg9 db 0 ;+9
db 0
PLY_PSGReg10 db 0 ;+11
PLY_PSGReg11 db 0
PLY_PSGReg12 db 0
PLY_PSGReg13 db 0
PLY_PSGRegistersArray_End
;Plays a sound stream.
;HL=Pointer on Instrument Data
;IY=Pointer on Register code (volume, frequency).
;E=Note
;D=Inverted Volume
;DE'=TrackPitch
;RET=
;HL=New Instrument pointer.
;IXL=Reg7 mask (x00x)
;Also used inside =
;B,C=read byte/second byte.
;IXH=Save original Note (only used for Independant mode).
PLY_PlaySound
ld b,(hl)
inc hl
rr b
jp c,PLY_PS_Hard
;**************
;Software Sound
;**************
;Second Byte needed ?
rr b
jr c,PLY_PS_S_SecondByteNeeded
;No second byte needed. We need to check if Volume is null or not.
ld a,b
and %1111
jr nz,PLY_PS_S_SoundOn
;Null Volume. It means no Sound. We stop the Sound, the Noise, and it's over.
ld (iy + 7),a ;We have to make the volume to 0, because if a bass Hard was activated before, we have to stop it.
ld ixl,%1001
ret
PLY_PS_S_SoundOn
;Volume is here, no Second Byte needed. It means we have a simple Software sound (Sound = On, Noise = Off)
;We have to test Arpeggio and Pitch, however.
ld ixl,%1000
sub d ;Code Volume.
jr nc,$+3
xor a
ld (iy + 7),a
rr b ;Needed for the subroutine to get the good flags.
call PLY_PS_CalculateFrequency
ld (iy + 0),l ;Code Frequency.
ld (iy + 1),h
exx
ret
PLY_PS_S_SecondByteNeeded
ld ixl,%1000 ;By defaut, No Noise, Sound.
;Second Byte needed.
ld c,(hl)
inc hl
;Noise ?
ld a,c
and %11111
jr z,PLY_PS_S_SBN_NoNoise
ld (PLY_PSGReg6),a
ld ixl,%0000 ;Open Noise Channel.
PLY_PS_S_SBN_NoNoise
;Here we have either Volume and/or Sound. So first we need to read the Volume.
ld a,b
and %1111
sub d ;Code Volume.
jr nc,$+3
xor a
ld (iy + 7),a
;Sound ?
bit 5,c
jr nz,PLY_PS_S_SBN_Sound
;No Sound. Stop here.
inc ixl ;Set Sound bit to stop the Sound.
ret
PLY_PS_S_SBN_Sound
;Manual Frequency ?
rr b ;Needed for the subroutine to get the good flags.
bit 6,c
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (iy + 0),l ;Code Frequency.
ld (iy + 1),h
exx
ret
;**********
;Hard Sound
;**********
PLY_PS_Hard
;We don't set the Volume to 16 now because we may have reached the end of the sound !
rr b ;Test Retrig here, it is common to every Hard sounds.
jr nc,PLY_PS_Hard_NoRetrig
ld a,(PLY_Track1_InstrumentSpeedCpt + 1) ;Retrig only if it is the first step in this line of Instrument !
ld c,a
ld a,(PLY_Track1_InstrumentSpeed + 1)
cp c
jr nz,PLY_PS_Hard_NoRetrig
ld a,PLY_RetrigValue
ld (PLY_PSGReg13_Retrig + 1),a
PLY_PS_Hard_NoRetrig
;Independant/Loop or Software/Hardware Dependent ?
bit 1,b ;We don't shift the bits, so that we can use the same code (Frequency calculation) several times.
jp nz,PLY_PS_Hard_LoopOrIndependent
;Hardware Sound.
ld (iy + 7),16 ;Set Volume
ld ixl,%1000 ;Sound is always On here (only Independence mode can switch it off).
;This code is common to both Software and Hardware Dependent.
ld c,(hl) ;Get Second Byte.
inc hl
ld a,c ;Get the Hardware Envelope waveform.
and %1111 ;We don't care about the bit 7-4, but we have to clear them, else the waveform might be reset.
ld (PLY_PSGReg13),a
bit 0,b
jr z,PLY_PS_HardwareDependent
;******************
;Software Dependent
;******************
;Calculate the Software frequency
bit 4-2,b ;Manual Frequency ? -2 Because the byte has been shifted previously.
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (iy + 0),l ;Code Software Frequency.
ld (iy + 1),h
exx
;Shift the Frequency.
ld a,c
rra
rra ;Shift=Shift*4. The shift is inverted in memory (7 - Editor Shift).
and %11100
ld (PLY_PS_SD_Shift + 1),a
ld a,b ;Used to get the HardwarePitch flag within the second registers set.
exx
PLY_PS_SD_Shift jr $+2
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,$+3
inc hl
;Hardware Pitch ?
bit 7-2,a
jr z,PLY_PS_SD_NoHardwarePitch
exx ;Get Pitch and add it to the just calculated Hardware Frequency.
ld a,(hl)
inc hl
exx
add a,l ;Slow. Can be optimised ? Probably never used anyway.....
ld l,a
exx
ld a,(hl)
inc hl
exx
adc a,h
ld h,a
PLY_PS_SD_NoHardwarePitch
ld (PLY_PSGReg11),hl
exx
;This code is also used by Hardware Dependent.
PLY_PS_SD_Noise
;Noise ?
bit 7,c
ret z
ld a,(hl)
inc hl
ld (PLY_PSGReg6),a
ld ixl,%0000
ret
;******************
;Hardware Dependent
;******************
PLY_PS_HardwareDependent
;Calculate the Hardware frequency
bit 4-2,b ;Manual Hardware Frequency ? -2 Because the byte has been shifted previously.
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (PLY_PSGReg11),hl ;Code Hardware Frequency.
exx
;Shift the Hardware Frequency.
ld a,c
rra
rra ;Shift=Shift*4. The shift is inverted in memory (7 - Editor Shift).
and %11100
ld (PLY_PS_HD_Shift + 1),a
ld a,b ;Used to get the Software flag within the second registers set.
exx
PLY_PS_HD_Shift jr $+2
sla l
rl h
sla l
rl h
sla l
rl h
sla l
rl h
sla l
rl h
sla l
rl h
sla l
rl h
;Software Pitch ?
bit 7-2,a
jr z,PLY_PS_HD_NoSoftwarePitch
exx ;Get Pitch and add it to the just calculated Software Frequency.
ld a,(hl)
inc hl
exx
add a,l
ld l,a ;Slow. Can be optimised ? Probably never used anyway.....
exx
ld a,(hl)
inc hl
exx
adc a,h
ld h,a
PLY_PS_HD_NoSoftwarePitch
ld (iy + 0),l ;Code Frequency.
ld (iy + 1),h
exx
;Go to manage Noise, common to Software Dependent.
jr PLY_PS_SD_Noise
PLY_PS_Hard_LoopOrIndependent
bit 0,b ;We mustn't shift it to get the result in the Carry, as it would be mess the structure
jr z,PLY_PS_Independent ;of the flags, making it uncompatible with the common code.
;The sound has ended.
;If Sound Effects activated, we mark the "end of sound" by returning a 0 as an address.
if PLY_UseSoundEffects
PLY_PS_EndSound_SFX ld a,0 ;Is the sound played is a SFX (1) or a normal sound (0) ?
or a
jr z,PLY_PS_EndSound_NotASFX
ld hl,0
ret
PLY_PS_EndSound_NotASFX
endif
;The sound has ended. Read the new pointer and restart instrument.
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
jp PLY_PlaySound
;***********
;Independent
;***********
PLY_PS_Independent
ld (iy + 7),16 ;Set Volume
;Sound ?
bit 7-2,b ;-2 Because the byte has been shifted previously.
jr nz,PLY_PS_I_SoundOn
;No Sound ! It means we don't care about the software frequency (manual frequency, arpeggio, pitch).
ld ixl,%1001
jr PLY_PS_I_SkipSoftwareFrequencyCalculation
PLY_PS_I_SoundOn
ld ixl,%1000 ;Sound is on.
ld ixh,e ;Save the original note for the Hardware frequency, because a Software Arpeggio will modify it.
;Calculate the Software frequency
bit 4-2,b ;Manual Frequency ? -2 Because the byte has been shifted previously.
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (iy + 0),l ;Code Software Frequency.
ld (iy + 1),h
exx
ld e,ixh
PLY_PS_I_SkipSoftwareFrequencyCalculation
ld b,(hl) ;Get Second Byte.
inc hl
ld a,b ;Get the Hardware Envelope waveform.
and %1111 ;We don't care about the bit 7-4, but we have to clear them, else the waveform might be reset.
ld (PLY_PSGReg13),a
;Calculate the Hardware frequency
rr b ;Must shift it to match the expected data of the subroutine.
rr b
bit 4-2,b ;Manual Hardware Frequency ? -2 Because the byte has been shifted previously.
call PLY_PS_CalculateFrequency_TestManualFrequency
ld (PLY_PSGReg11),hl ;Code Hardware Frequency.
exx
;Noise ? We can't use the previous common code, because the setting of the Noise is different, since Independent can have no Sound.
bit 7-2,b
ret z
ld a,(hl)
inc hl
ld (PLY_PSGReg6),a
ld a,ixl ;Set the Noise bit.
res 3,a
ld ixl,a
ret
;Subroutine that =
;If Manual Frequency? (Flag Z off), read frequency (Word) and adds the TrackPitch (DE').
;Else, Auto Frequency.
; if Arpeggio? = 1 (bit 3 from B), read it (Byte).
; if Pitch? = 1 (bit 4 from B), read it (Word).
; Calculate the frequency according to the Note (E) + Arpeggio + TrackPitch (DE').
;HL = Pointer on Instrument data.
;DE'= TrackPitch.
;RET=
;HL = Pointer on Instrument moved forward.
;HL'= Frequency
; RETURN IN AUXILIARY REGISTERS
PLY_PS_CalculateFrequency_TestManualFrequency
jr z,PLY_PS_CalculateFrequency
;Manual Frequency. We read it, no need to read Pitch and Arpeggio.
;However, we add TrackPitch to the read Frequency, and that's all.
ld a,(hl)
inc hl
exx
add a,e ;Add TrackPitch LSB.
ld l,a
exx
ld a,(hl)
inc hl
exx
adc a,d ;Add TrackPitch HSB.
ld h,a
ret
PLY_PS_CalculateFrequency
;Pitch ?
bit 5-1,b
jr z,PLY_PS_S_SoundOn_NoPitch
ld a,(hl)
inc hl
exx
add a,e ;If Pitch found, add it directly to the TrackPitch.
ld e,a
exx
ld a,(hl)
inc hl
exx
adc a,d
ld d,a
exx
PLY_PS_S_SoundOn_NoPitch
;Arpeggio ?
ld a,e
bit 4-1,b
jr z,PLY_PS_S_SoundOn_ArpeggioEnd
add a,(hl) ;Add Arpeggio to Note.
inc hl
cp 144
jr c,$+4
ld a,143
PLY_PS_S_SoundOn_ArpeggioEnd
;Frequency calculation.
exx
ld l,a
ld h,0
add hl,hl
ld bc,PLY_FrequencyTable
add hl,bc
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
add hl,de ;Add TrackPitch + InstrumentPitch (if any).
ret
;Read one Track.
;HL=Track Pointer.
;Ret =
;HL=New Track Pointer.
;Carry = 1 = Wait A lines. Carry=0=Line not empty.
;A=Wait (0(=256)-127), if Carry.
;D=Parameters + Volume.
;E=Note
;B=Instrument. 0=RST
;IX=PitchAdd. Only used if Pitch? = 1.
PLY_ReadTrack
ld a,(hl)
inc hl
srl a ;Full Optimisation ? If yes = Note only, no Pitch, no Volume, Same Instrument.
jr c,PLY_ReadTrack_FullOptimisation
sub 32 ;0-31 = Wait.
jr c,PLY_ReadTrack_Wait
jr z,PLY_ReadTrack_NoOptimisation_EscapeCode
dec a ;0 (32-32) = Escape Code for more Notes (parameters will be read)
;Note. Parameters are present. But the note is only present if Note? flag is 1.
ld e,a ;Save Note.
;Read Parameters
PLY_ReadTrack_ReadParameters
ld a,(hl)
ld d,a ;Save Parameters.
inc hl
rla ;Pitch ?
jr nc,PLY_ReadTrack_Pitch_End
ld b,(hl) ;Get PitchAdd
ld ixl,b
inc hl
ld b,(hl)
ld ixh,b
inc hl
PLY_ReadTrack_Pitch_End
rla ;Skip IsNote? flag.
rla ;New Instrument ?
ret nc
ld b,(hl)
inc hl
or a ;Remove Carry, as the player interpret it as a Wait command.
ret
;Escape code, read the Note and returns to read the Parameters.
PLY_ReadTrack_NoOptimisation_EscapeCode
ld e,(hl)
inc hl
jr PLY_ReadTrack_ReadParameters
PLY_ReadTrack_FullOptimisation
;Note only, no Pitch, no Volume, Same Instrument.
ld d,%01000000 ;Note only.
sub 1
ld e,a
ret nc
ld e,(hl) ;Escape Code found (0). Read Note.
inc hl
or a
ret
PLY_ReadTrack_Wait
add a,32
ret
PLY_FrequencyTable
if PLY_UseCPCMachine
dw 3822,3608,3405,3214,3034,2863,2703,2551,2408,2273,2145,2025
dw 1911,1804,1703,1607,1517,1432,1351,1276,1204,1136,1073,1012
dw 956,902,851,804,758,716,676,638,602,568,536,506
dw 478,451,426,402,379,358,338,319,301,284,268,253
dw 239,225,213,201,190,179,169,159,150,142,134,127
dw 119,113,106,100,95,89,84,80,75,71,67,63
dw 60,56,53,50,47,45,42,40,38,36,34,32
dw 30,28,27,25,24,22,21,20,19,18,17,16
dw 15,14,13,13,12,11,11,10,9,9,8,8
dw 7,7,7,6,6,6,5,5,5,4,4,4
dw 4,4,3,3,3,3,3,2,2,2,2,2
dw 2,2,2,2,1,1,1,1,1,1,1,1
endif
if PLY_UseMSXMachine
dw 4095,4095,4095,4095,4095,4095,4095,4095,4095,4030,3804,3591
dw 3389,3199,3019,2850,2690,2539,2397,2262,2135,2015,1902,1795
dw 1695,1599,1510,1425,1345,1270,1198,1131,1068,1008,951,898
dw 847,800,755,712,673,635,599,566,534,504,476,449
dw 424,400,377,356,336,317,300,283,267,252,238,224
dw 212,200,189,178,168,159,150,141,133,126,119,112
dw 106,100,94,89,84,79,75,71,67,63,59,56
dw 53,50,47,45,42,40,37,35,33,31,30,28
dw 26,25,24,22,21,20,19,18,17,16,15,14
dw 13,12,12,11,11,10,9,9,8,8,7,7
dw 7,6,6,6,5,5,5,4,4,4,4,4
dw 3,3,3,3,3,2,2,2,2,2,2,2
endif
;DE = Music
PLY_Init
if PLY_UseFirmwareInterruptions
ld hl,8 ;Skip Header, SampleChannel, YM Clock (DB*3). The Replay Frequency is used in Interruption mode.
add hl,de
ld de,PLY_ReplayFrequency + 1
ldi
else
ld hl,9 ;Skip Header, SampleChannel, YM Clock (DB*3), and Replay Frequency.
add hl,de
endif
ld de,PLY_Speed + 1
ldi ;Copy Speed.
ld c,(hl) ;Get Instruments chunk size.
inc hl
ld b,(hl)
inc hl
ld (PLY_Track1_InstrumentsTablePT + 1),hl
ld (PLY_Track2_InstrumentsTablePT + 1),hl
ld (PLY_Track3_InstrumentsTablePT + 1),hl
add hl,bc ;Skip Instruments to go to the Linker address.
;Get the pre-Linker information of the first pattern.
ld de,PLY_Height + 1
ldi
ld de,PLY_Transposition1 + 1
ldi
ld de,PLY_Transposition2 + 1
ldi
ld de,PLY_Transposition3 + 1
ldi
ld de,PLY_SaveSpecialTrack + 1
ldi
ldi
ld (PLY_Linker_PT + 1),hl ;Get the Linker address.
ld a,1
ld (PLY_SpeedCpt + 1),a
ld (PLY_HeightCpt + 1),a
ld a,#ff
ld (PLY_PSGReg13),a
;Set the Instruments pointers to Instrument 0 data (Header has to be skipped).
ld hl,(PLY_Track1_InstrumentsTablePT + 1)
ld e,(hl)
inc hl
ld d,(hl)
ex de,hl
inc hl ;Skip Instrument 0 Header.
inc hl
ld (PLY_Track1_Instrument + 1),hl
ld (PLY_Track2_Instrument + 1),hl
ld (PLY_Track3_Instrument + 1),hl
ret
;Stop the music, cut the channels.
PLY_Stop
if PLY_SystemFriendly
call PLY_DisableInterruptions
ex af,af'
exx
push af
push bc
push ix
push iy
endif
ld hl,PLY_PSGReg8
ld bc,#0300
ld (hl),c
inc hl
djnz $-2
ld a,%00111111
jp PLY_SendRegisters
if PLY_UseSoundEffects
;Initialize the Sound Effects.
;DE = SFX Music.
PLY_SFX_Init
;Find the Instrument Table.
ld hl,12
add hl,de
ld (PLY_SFX_Play_InstrumentTable + 1),hl
;Clear the three channels of any sound effect.
PLY_SFX_StopAll
ld hl,0
ld (PLY_SFX_Track1_Instrument + 1),hl
ld (PLY_SFX_Track2_Instrument + 1),hl
ld (PLY_SFX_Track3_Instrument + 1),hl
ret
PLY_SFX_OffsetPitch equ 0
PLY_SFX_OffsetVolume equ PLY_SFX_Track1_Volume - PLY_SFX_Track1_Pitch
PLY_SFX_OffsetNote equ PLY_SFX_Track1_Note - PLY_SFX_Track1_Pitch
PLY_SFX_OffsetInstrument equ PLY_SFX_Track1_Instrument - PLY_SFX_Track1_Pitch
PLY_SFX_OffsetSpeed equ PLY_SFX_Track1_InstrumentSpeed - PLY_SFX_Track1_Pitch
PLY_SFX_OffsetSpeedCpt equ PLY_SFX_Track1_InstrumentSpeedCpt - PLY_SFX_Track1_Pitch
;Plays a Sound Effects along with the music.
;A = No Channel (0,1,2)
;L = SFX Number (>0)
;H = Volume (0...F)
;E = Note (0...143)
;D = Speed (0 = As original, 1...255 = new Speed (1 is fastest))
;BC = Inverted Pitch (-#FFFF -> FFFF). 0 is no pitch. The higher the pitch, the lower the sound.
PLY_SFX_Play
ld ix,PLY_SFX_Track1_Pitch
or a
jr z,PLY_SFX_Play_Selected
ld ix,PLY_SFX_Track2_Pitch
dec a
jr z,PLY_SFX_Play_Selected
ld ix,PLY_SFX_Track3_Pitch
PLY_SFX_Play_Selected
ld (ix + PLY_SFX_OffsetPitch + 1),c ;Set Pitch
ld (ix + PLY_SFX_OffsetPitch + 2),b
ld a,e ;Set Note
ld (ix + PLY_SFX_OffsetNote),a
ld a,15 ;Set Volume
sub h
ld (ix + PLY_SFX_OffsetVolume),a
ld h,0 ;Set Instrument Address
add hl,hl
PLY_SFX_Play_InstrumentTable ld bc,0
add hl,bc
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
ld a,d ;Read Speed or use the user's one ?
or a
jr nz,PLY_SFX_Play_UserSpeed
ld a,(hl) ;Get Speed
PLY_SFX_Play_UserSpeed
ld (ix + PLY_SFX_OffsetSpeed + 1),a
ld (ix + PLY_SFX_OffsetSpeedCpt + 1),a
inc hl ;Skip Retrig
inc hl
ld (ix + PLY_SFX_OffsetInstrument + 1),l
ld (ix + PLY_SFX_OffsetInstrument + 2),h
ret
;Stops a sound effect on the selected channel
;E = No Channel (0,1,2)
;I used the E register instead of A so that Basic users can call this code in a straightforward way (call player+15, value).
PLY_SFX_Stop
ld a,e
ld hl,PLY_SFX_Track1_Instrument + 1
or a
jr z,PLY_SFX_Stop_ChannelFound
ld hl,PLY_SFX_Track2_Instrument + 1
dec a
jr z,PLY_SFX_Stop_ChannelFound
ld hl,PLY_SFX_Track3_Instrument + 1
dec a
PLY_SFX_Stop_ChannelFound
ld (hl),a
inc hl
ld (hl),a
ret
endif
if PLY_UseFades
;Sets the Fade value.
;E = Fade value (0 = full volume, 16 or more = no volume).
;I used the E register instead of A so that Basic users can call this code in a straightforward way (call player+9/+18, value).
PLY_SetFadeValue
ld a,e
ld (PLY_Channel1_FadeValue + 1),a
ld (PLY_Channel2_FadeValue + 1),a
ld (PLY_Channel3_FadeValue + 1),a
ret
endif
if PLY_SystemFriendly
;Save Interrupt status and Disable Interruptions
PLY_DisableInterruptions
ld a,i
di
;IFF in P/V flag.
;Prepare opcode for DI.
ld a,#f3
jp po,PLY_DisableInterruptions_Set_Opcode
;Opcode for EI.
ld a,#fb
PLY_DisableInterruptions_Set_Opcode
ld (PLY_RestoreInterruption),a
ret
endif
;A little convient interface for BASIC user, to allow them to use Sound Effects in Basic.
if PLY_UseBasicSoundEffectInterface
PLY_BasicSoundEffectInterface_PlaySound
ld c,(ix+0) ;Get Pitch
ld b,(ix+1)
ld d,(ix+2) ;Get Speed
ld e,(ix+4) ;Get Note
ld h,(ix+6) ;Get Volume
ld l,(ix+8) ;Get SFX number
ld a,(ix+10) ;Get Channel
jp PLY_SFX_Play
endif
list
;*** End of Arkos Tracker Player
nolist
;------------------------------------------------------------------------------
list
; Aplib decrunching routine
nolist
; (c) CNGSOFT
; En entree, on a :
; HL = implantation du code compacte
; DE = implantation du code decompacte
;------------------------------------------------------------------------------
DECOMPACK
;DI
LD HL,ECRAN_FIN_PAK
LD DE,&C000
CALL boot
JP &000F
; Maxam source by T&J/GPA - 01/18/2008
; Nothing changed, except thy damned hidden opcodes
; and a new variable for Maxam ( 13+8*0 = 0 for Maxam )
; Attention, cette routine contient un assemblage conditionnel.
; Si Aplib8flag = 0, le code decompacte est ecrite du bas de la
; memoire vers le haut de la memoire. C est ce que font par defaut
; les programmes modifies par Dadman/CEZ - Team (APPACK.EXE et
; aPPackWin.exe.
; Si Aplib8flag = 1, le code decompacte est ecrit du haut de la
; memoire vers le bas de la memoire. Le code compacte doit bien
; evidemment etre organise en consequence.
aplib8flag equ &0 ; = DEC &00 pour INC
flagdecde equ aplib8flag*8 ; for Maxam compatibility
Boot
PUSH HL ; used for EX HL,(SP)
PUSH HL
POP IX
DB &FD,&26,&80 ; LD IYh,&80
aplib8literal
LD A,(IX+ &00)
DB &DD,&23 + flagdecde ; INC IX/DEC IX
LD (DE),A
DB &13 + flagdecde ; INC DE/DEC DE
DB &FD,&2E,&02 ; LD IYl,&2
aplib8nexttag
CALL aplib8getbit
JR NC, aplib8literal
LD BC,&0000
CALL aplib8getbit
JR NC, aplib8codepair
LD H,B
CALL aplib8getbit
JR NC, aplib8shortmatch
DB &FD,&2E,&02 ; LD IYl,2
INC C ; bc
LD L,&10
aplib8getmorebits
CALL aplib8getbit
RL L
JR NC, aplib8getmorebits
JR NZ, aplib8domatch
LD A,L
LD (DE),A
DB &13+ flagdecde ; INC DE/DEC DE
JR aplib8nexttag
aplib8codepair
CALL aplib8getgamma
DB &FD,&4D ; LD C,IYl
SBC HL,BC
JR NZ, aplib8normalcodepair
CALL aplib8getgamma
LD B,H
JR aplib8domatch_lastpos
aplib8normalcodepair
DEC L
LD H,L
LD L,(IX + &00)
DB &DD,&23+ flagdecde ; INC IX/DEC IX
PUSH HL
CALL aplib8getgamma
LD B,H
POP HL
LD A,H
CP 125 ; cmp eax,32000
JR NC, aplib8domatch_with_2inc
CP &05
JR NC, aplib8domatch_with_inc
AND A
JR NZ, aplib8domatch_new_lastpos
LD A,L
ADD A
JR C, aplib8domatch_new_lastpos
aplib8domatch_with_2inc
INC BC
aplib8domatch_with_inc
INC BC
aplib8domatch_new_lastpos
EX (SP),HL
aplib8domatch_lastpos
POP HL
PUSH HL
DB &FD,&2E,&01 ; LD IYl,1
aplib8domatch
if aplib8flag ; LDIR/LDDR
ADD HL,DE
LDDR
else
AND A
EX DE,HL
SBC HL,DE
EX DE,HL
ADD HL,DE
EX DE,HL
LDIR
endif
JR aplib8nexttag
aplib8shortmatch
LD L,(IX+&00)
DB &DD,&23+ flagdecde ; INC IX/DEC IX
SRL L
JR Z, aplib8donedepacking
RL C
JR aplib8domatch_with_2inc
aplib8getbit
DB &FD,&7C ; LD A,IYh
ADD A
JR NZ,aplib8getbit_
LD A,(IX + &00)
DB &DD,&23+ flagdecde ; INC IX/DEC IX
ADC A
aplib8getbit_
DB &FD,&67 ; LD IYh,A
RET
aplib8getgamma
LD HL,&0001
aplib8getgamma_
CALL aplib8getbit
ADC HL,HL
CALL aplib8getbit
JR C, aplib8getgamma_
LD C,L
RET
aplib8donedepacking
POP HL ; used for EX HL,(SP)
PUSH IX
POP HL
RET ; Warning, A might not be 0!