MODULE Snow;

(*----------------------------------------------------------------------------
 * System-Version: MOS 3.5
 *----------------------------------------------------------------------------
 * Version       : 1.0
 *----------------------------------------------------------------------------
 * Text-Version  : V#00034
 *----------------------------------------------------------------------------
 * Modul-Holder  : Meinolf Schneider
 *----------------------------------------------------------------------------
 * Copyright July 1990 by Digital Art Meinolf Schneider
 *----------------------------------------------------------------------------
 * MS  : Meinolf Schneider
 *----------------------------------------------------------------------------
 * Datum    Autor Version Bemerkung (Arbeitsbericht)
 *----------------------------------------------------------------------------
 * 27.07.90 MS    1.0     Grundversion
 *----------------------------------------------------------------------------
 * Modul-Beschreibung:
 *
 * Residentes Gimmick-Programm fr Atari ST mit monochromen Monitor, bei dem
 * Schneefall und Vereisung simuliert wird. Die Vereisung kann mit einem
 * Eiskratzer entfernt werden.
 *----------------------------------------------------------------------------
 *) (*$S-,R-,C-,N+,M-*)


FROM    System          IMPORT  ADDRESS, ADR, BYTE;

FROM    MSSystems       IMPORT  MinMaxRandom, EnterSupervisorMode,
                                Allocate;

FROM    MSGraphics      IMPORT  Sprite, CopyScreen, Switch, SwitchSides,
                                DisplayScreen, WorkScreen,
                                DrawText, GetSystemScreen, FillScreen,
                                ClearScreen;

FROM    MSMouse         IMPORT  MouseRec, ReadMouse;

FROM    MSSounds        IMPORT  Sound, StartASound, StopASound, NewSound,
                                ASoundIsActive, SetSampleFrequency;


CONST   PicFreq                 =       4; (* Alle vier VBLs ein Bild malen *)
        PicsPerSec              =       72 DIV PicFreq;
         
        sTRUE                   =       BYTE ( $00 );
        sFALSE                  =       BYTE ( $FF );
        
        TitleTime               =       3 * 60 * PicsPerSec;
                                        (* 3 Minuten *)
        SnowBegin               =       60 * PicsPerSec;
                                        (* 1 Minute *)
        
        MaxNoOfSnowFlakes       =       200;
 
 
TYPE     Bool            =       BYTE; (* 00=FALSE, FF=TRUE *)
         
         SnowFlake       =       RECORD
                                  IsThere                       : Bool;
                                  
                                  WordPosition                  : CARDINAL;
                                  FallOffset                    : CARDINAL;
                                  (* Offset in Bytes fr neue Fallposition der
                                   * Schneeflocke *)
                                  
                                  HorPosition                   : CARDINAL;
                                  HorCenterLongWordPosition     : CARDINAL;
                                  
                                  ThreePointPattern             : LONGCARD;
                                  OnePointPattern               : LONGCARD;
                                
                                  CheckANDPattern               : LONGCARD;
                                  CheckStopValue                : LONGCARD;
                                  CheckRightFallValue           : LONGCARD;
                                  CheckLeftFallValue            : LONGCARD;
                                  CheckRightLeftOrStopValue     : LONGCARD;
                                END;
 
 
VAR     VBLStack                : ARRAY[0..99] OF CARDINAL;
        VBLTimer                : CARDINAL;
        OldVBLIRQ               : ADDRESS;
        
        TOSScreen               : ADDRESS;
        
        TOSScreenOnDisplay      : BOOLEAN;
        DirectTOSScreenShow     : BOOLEAN;
        
        SnowScreen              : ADDRESS;
        SnowSpriteList          : ADDRESS;
        
        SnowRate                : CARDINAL;
        (* 0 = jedes mal eine neue Schneeflocke
         * x = Mglichkeit einer neuer Schneeflocke 1:x
         *)
        SnowFlakes              : ARRAY[0..MaxNoOfSnowFlakes] OF SnowFlake;
        SnowLines               : ARRAY[0..400] OF Byte;
        SnowThere               : BOOLEAN;
        (* TRUE, wenn es anfngt zu schneien *)
        SnowWait                : CARDINAL;
        (* Wartezeit, bis es anfngt zu schneien *)
        
        ShowTitle               : BOOLEAN;
        (* TRUE, wenn die Copyright-Meldung zu sehen ist. *)
        TitleWasThere           : BOOLEAN;
        (* TRUE, wenn die Copyright-Meldung zu sehen war. *)
        TitleTimer              : CARDINAL;
        
        ScratchSoundADR         : ADDRESS;
        ScratchSound            : Sound;
        
        IceScratchThere         : BOOLEAN;
        MyMouse                 : MouseRec;
        
        
(*---------------------------------------------------------------------------*)

TABLE.L  TabSnowSpriteList:
         $0000061C, $00028000, $00000010, $00000460, $FFF7FFF7, $00120012,
         $00080001, $0000004C, $0000008A, $000000C8, $00000106, $00000144,
         $00000182, $000001C0, $000001FE, $0000024E, $0000028C, $000002CA,
         $00000308, $00000346, $00000384, $000003C2, $00000400, $0000003E,
         $00030012, $00010107, $071E1D7A, $756A351A, $0D060301, $000000C0,
         $E0B058AC, $56AB55AA, $55AB56AC, $58B0E000, $00000000, $00000000,
         $80808000, $00000000, $00000000, $003E0003, $00120000, $0003030F,
         $0E3D3A35, $1A0D0603, $01000000, $00E0F0D8, $AC56AB55, $AA55AA55,
         $AB56ACD8, $70000000, $00000000, $0080C040, $C0800000, $00000000,
         $0000003E, $00030012, $00000001, $0107071E, $1D1A0D06, $03010000,
         $00000070, $78ECD6AB, $55AA55AA, $55AA55AB, $D66C3800, $00000000,
         $000080C0, $60A060C0, $80000000, $00000000, $003E0003, $00120000,
         $00000003, $030F0E0D, $06030100, $00000000, $00383CF6, $EBD5AA55,
         $AA55AA55, $AAD56B36, $1C000000, $00000080, $C060B050, $B060C080,
         $00000000, $0000003E, $00030012, $00000000, $00010107, $07060301,
         $00000000, $0000001C, $1E7B75EA, $D5AA55AA, $55AAD56A, $351B0E00,
         $00000000, $80C060B0, $58A858B0, $60C08000, $00000000, $003E0003,
         $00120000, $00000000, $00030303, $01000000, $00000000, $000E0F3D,
         $3AF5EAD5, $AA55AAD5, $6A351A0D, $07000000, $0080C060, $B058AC54,
         $AC58B060, $C0800000, $0000003E, $00030012, $00000000, $00000001,
         $01010000, $00000000, $00000007, $071E1D7A, $75EAD5AA, $D56A351A,
         $0D060300, $000080C0, $60B058AC, $56AA56AC, $58B060C0, $80000000,
         $00500004, $00120000, $00000000, $00000000, $00000000, $00000000,
         $0003030F, $0E3D3AF5, $EAD56A35, $1A0D0603, $01000080, $C060B058,
         $AC56AB55, $AB56AC58, $B060C000, $00000000, $00000000, $00000000,
         $00000000, $00000000, $003E0003, $0012FCFC, $F0F0C0C0, $00000000,
         $0080C0E0, $F0F8FCFE, $1F0F0703, $01000000, $00000000, $00000103,
         $070FFFFF, $FFFFFFFF, $7F3F3F3F, $3F3F7FFF, $FFFFFFFF, $0000003E,
         $00030012, $FEFEF8F8, $E0E08080, $808080C0, $E0F0F8FC, $FEFF0F07,
         $03010000, $00000000, $00000000, $00010307, $FFFFFFFF, $FF7F3F1F,
         $1F1F1F1F, $3F7FFFFF, $FFFF0000, $003E0003, $0012FFFF, $FCFCF0F0,
         $C0C0C0C0, $C0E0F0F8, $FCFEFFFF, $07030100, $00000000, $00000000,
         $00000000, $0183FFFF, $FFFF7F3F, $1F0F0F0F, $0F0F1F3F, $7FFFFFFF,
         $0000003E, $00030012, $FFFFFEFE, $F8F8E0E0, $E0E0E0F0, $F8FCFEFF,
         $FFFF8381, $00000000, $00000000, $00000000, $000080C1, $FFFFFF7F,
         $3F1F0F07, $07070707, $0F1F3F7F, $FFFF0000, $003E0003, $0012FFFF,
         $FFFFFCFC, $F0F0F0F0, $F0F8FCFE, $FFFFFFFF, $C1C00000, $00000000,
         $00000000, $00000080, $C0E0FFFF, $7F3F1F0F, $07030303, $0303070F,
         $1F3F7FFF, $0000003E, $00030012, $FFFFFFFF, $FEFEF8F8, $F8F8F8FC,
         $FEFFFFFF, $FFFFE0E0, $80800000, $00000000, $00000000, $80C0E0F0,
         $FF7F3F1F, $0F070301, $01010101, $03070F1F, $3F7F0000, $003E0003,
         $0012FFFF, $FFFFFFFF, $FCFCFCFC, $FCFEFFFF, $FFFFFFFF, $F0F0C0C0,
         $00000000, $00000000, $0080C0E0, $F0F87F3F, $1F0F0703, $01000000,
         $00000103, $070F1F3F, $00000050, $00040012, $FFFFFFFF, $FFFFFEFE,
         $FEFEFEFF, $FFFFFFFF, $FFFFF8F8, $E0E08080, $00000000, $000080C0,
         $E0F0F8FC, $3F1F0F07, $03010000, $00000000, $00010307, $0F1FFFFF,
         $FFFFFFFF, $FF7F7F7F, $7F7FFFFF, $FFFFFFFF, $FFF7FFF7, $00080008,
         $00080001, $0000004C, $0000005C, $00000074, $0000008C, $000000A4,
         $000000BC, $000000D4, $000000EC, $00000104, $00000114, $0000012C,
         $00000144, $0000015C, $00000174, $0000018C, $000001A4, $00000010,
         $00010008, $03030C0C, $3030C0C0, $00000018, $00020008, $01010606,
         $18186060, $80800000, $00000000, $00000018, $00020008, $00000303,
         $0C0C3030, $C0C00000, $00000000, $00000018, $00020008, $00000101,
         $06061818, $60608080, $00000000, $00000018, $00020008, $00000000,
         $03030C0C, $3030C0C0, $00000000, $00000018, $00020008, $00000000,
         $01010606, $18186060, $80800000, $00000018, $00020008, $00000000,
         $00000303, $0C0C3030, $C0C00000, $00000018, $00020008, $00000000,
         $00000101, $06061818, $60608080, $00000010, $00010008, $FCFCF3F3,
         $CFCF3F3F, $00000018, $00020008, $FEFEF9F9, $E7E79F9F, $7F7FFFFF,
         $FFFFFFFF, $00000018, $00020008, $FFFFFCFC, $F3F3CFCF, $3F3FFFFF,
         $FFFFFFFF, $00000018, $00020008, $FFFFFEFE, $F9F9E7E7, $9F9F7F7F,
         $FFFFFFFF, $00000018, $00020008, $FFFFFFFF, $FCFCF3F3, $CFCF3F3F,
         $FFFFFFFF, $00000018, $00020008, $FFFFFFFF, $FEFEF9F9, $E7E79F9F,
         $7F7FFFFF, $00000018, $00020008, $FFFFFFFF, $FFFFFCFC, $F3F3CFCF,
         $3F3FFFFF, $00000018, $00020008, $FFFFFFFF, $FFFFFEFE, $F9F9E7E7,
         $9F9F7F7F;
         
         TabScratchSound:
         $7F7F7F7F, $7F7F8080, $80808080, $81828282, $83848484, $86868889,
         $898A8B8C, $8D8E9091, $92929496, $97979899, $9A9B9C9D, $9E9E9E9F,
         $A0A1A2A4, $A5A7A8A9, $A9AAACAC, $AEAFB2B4, $B7BABCBE, $C2C5C9CC,
         $D0D4D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D4, $CCC5C1BD, $BDBDBFC1, $C3C5C9CF, $D6D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D2D4D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D2, $B596817E,
         $8797A3A4, $9B8F898B, $92A2BAD0, $D8D8D8D8, $D4BCA08B, $7E777576,
         $7A7F8382, $7E808B96, $A7A6977B, $502D2727, $375A788D, $97928E94,
         $A5B3BABC, $C1D3D8D8, $D8D8D8D8, $D8C5B2B0, $B7C2D1D8, $D8D8D8D8,
         $D09E7567, $80B1CDCB, $C0B6AEA5, $94806242, $2F344559, $68696358,
         $4236342B, $27272727, $3A779C81, $46272727, $27577E73, $634B3B38,
         $46482A27, $2727347D, $BCC8B092, $77574654, $5E56698B, $9C896E47,
         $27272727, $27272727, $27273B52, $6C7C5227, $2727272D, $739FA27E,
         $67524D40, $34364341, $272B4881, $9981582B, $27273B6C, $81705B55,
         $6167798D, $A9AEB0B0, $BEC38C52, $2A2A3546, $6E878C89, $7A643C28,
         $27272728, $47798A57, $2C272727, $27272D46, $5D8DCCD5, $C3A9772F,
         $27273862, $756C5E46, $2A272727, $27272738, $4D6C8F80, $7A603B39,
         $608CB4D8, $D8BB7130, $27272727, $27272727, $27272727, $27272727,
         $27272727, $27272727, $27272727, $27272727, $27272727, $283C363D,
         $4A617D86, $68272727, $27272A28, $27272727, $27272727, $27272727,
         $27272727, $27272727, $27272727, $27272727, $27272727, $27272727,
         $27272727, $27272727, $27272727, $27272727, $27272727, $27272727,
         $27272727, $27272727, $27272727, $27272A39, $2C272727, $27272727,
         $27272727, $27272727, $27272727, $27272727, $27272727, $27272727,
         $27272727, $27272727, $27272727, $27272727, $27272727, $27272838,
         $28272727, $27272727, $27272727, $27272727, $27272727, $27272A38,
         $28272727, $2728507A, $7A4E2727, $272A5C8B, $86584468, $A5C9B273,
         $2F272738, $78B3D6D8, $D8D7B88A, $65666C56, $41364472, $B7D8D8CA,
         $8C645962, $7A8F9EAC, $C7D8D8D8, $BB90777A, $8B9FA79D, $866F6264,
         $625D5756, $5771A0C8, $D8D8D3AF, $868093B0, $C8CAB9A2, $9AA9BDCC,
         $D0BD9772, $5956636D, $65493644, $77BED8D8, $D8D8D8D8, $D3CDD8D8,
         $D8D7CAC6, $D4D8D8D8, $D8D8D0AD, $A2B6D6D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D3AD, $94898074, $6C7389A8, $C8D8D8D8, $D8D8D8D8,
         $D8D8BEAB, $ACC1D7D8, $D8D8D7CE, $C6BDB1A0, $908DA9D4, $D8D8D8D8,
         $D8D4AE93, $8D9AB0C7, $D6D8D8D8, $D8D8D7CF, $CDD6D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D7, $D7D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8, $D8D8D8D8,
         $D8D8D8D8, $D8D8D8D8, $D6D4D2D0, $CDCBC8C6, $C5C3C1C0, $BEBDBCBB,
         $BAB8B7B6, $B5B3B2B1, $B0AEADAC, $AAA9A7A5, $A2A1A09E, $9D9C9B9A,
         $99989796, $94949290, $908E8D8C, $8B8A8988, $87868585, $84848300;


         

(*---------------------------------------------------------------------------*)
  
(*$L-*)
PROCEDURE CopySnowScreen;
BEGIN
  ASSEMBLER
  movem.l       A3-A6/D2-D7,-(A7)
  
  move.l        SnowScreen,A4
  move.l        WorkScreen,A5
  move.l        TOSScreen,A6
  lea           SnowLines,A0
  bra           NextLine
  
 !ED
  movem.l       (A7)+,A3-A6/D2-D7
  rts
  
 !NextLine
  tst.b         (A0)+
  bmi.s         ED
 
  movem.l       (A4)+,D0-D3
  movem.l       (A6)+,D4-D7
  and.l         D0,D4
  and.l         D1,D5
  and.l         D2,D6
  and.l         D3,D7
  movem.l       D4-D7,(A5)
  lea           16(A5),A5
  
  movem.l       (A4)+,D0-D3
  movem.l       (A6)+,D4-D7
  and.l         D0,D4
  and.l         D1,D5
  and.l         D2,D6
  and.l         D3,D7
  movem.l       D4-D7,(A5)
  lea           16(A5),A5
  
  movem.l       (A4)+,D0-D3
  movem.l       (A6)+,D4-D7
  and.l         D0,D4
  and.l         D1,D5
  and.l         D2,D6
  and.l         D3,D7
  movem.l       D4-D7,(A5)
  lea           16(A5),A5
  
  movem.l       (A4)+,D0-D3
  movem.l       (A6)+,D4-D7
  and.l         D0,D4
  and.l         D1,D5
  and.l         D2,D6
  and.l         D3,D7
  movem.l       D4-D7,(A5)
  lea           16(A5),A5
  
  movem.l       (A4)+,D0-D3
  movem.l       (A6)+,D4-D7
  and.l         D0,D4
  and.l         D1,D5
  and.l         D2,D6
  and.l         D3,D7
  movem.l       D4-D7,(A5)
  lea           16(A5),A5
  
  bra           NextLine
  END;
END CopySnowScreen;
(*$L+*)


(*$L-*)
PROCEDURE DrawAndAnimateSnowFlakes;
BEGIN
  ASSEMBLER
  movem.l       D6/D7/A4,-(A7)
  
  lea           SnowFlakes,A0
  move.l        WorkScreen,A1
  move.l        TOSScreen,A2
  move.l        SnowScreen,A4
  
  move.w        #MaxNoOfSnowFlakes,D7
 
 !NextSnowFlake
  tst.b         SnowFlake.IsThere(A0)
  beq.w         NewSnowFlake
  
  move.w        SnowFlake.FallOffset(A0),D6
  add.w         SnowFlake.WordPosition(A0),D6
  move.w        D6,SnowFlake.WordPosition(A0)
  
 !DrawSnowFlake ; --> auf die WorkScreen
  move.l        SnowFlake.ThreePointPattern(A0),D1
  and.l         D1,0(A1,D6.W)
  move.l        SnowFlake.OnePointPattern(A0),D1
  and.l         D1,-80(A1,D6.W)
  and.l         D1,80(A1,D6.W)
  
  ; Testen, ob Schneeflocke liegen bleibt oder weiter fllt:
  move.l        80(A2,D6.W),D1  ; Zeile unter der Schneeflocke auf TOSScreen
  and.l         SnowFlake.CheckANDPattern(A0),D1
  beq.w         StopSnowFlake
  cmp.l         SnowFlake.CheckStopValue(A0),D1
  beq.w         StopSnowFlake
  cmp.l         SnowFlake.CheckLeftFallValue(A0),D1
  beq           SnowFlakeLeftFall
  cmp.l         SnowFlake.CheckRightFallValue(A0),D1
  beq           SnowFlakeRightFall
  move.l        80(A4,D6.W),D1  ; Zeile unter der Schneeflocke auf SnowScreen
  not.l         D1
  and.l         SnowFlake.CheckANDPattern(A0),D1
  cmp.l         SnowFlake.CheckStopValue(A0),D1
  beq.w         StopSnowFlake
  cmp.l         SnowFlake.CheckRightLeftOrStopValue(A0),D1
  beq           SnowFlakeRightLeftOrStop
  cmp.l         SnowFlake.CheckRightFallValue(A0),D1
  beq           SnowFlakeRightFall
  cmp.l         SnowFlake.CheckLeftFallValue(A0),D1
  beq           SnowFlakeLeftFall
  
 !SnowFlakeGoon
 !NoSnowFlakeChanges
 !NoSnowFlake
  lea           38(A0),A0
  dbf           D7,NextSnowFlake
  movem.l       (A7)+,A4/D6/D7
  rts
 
 
 !SnowFlakeLeftFall
  ; Schneeflocke ein Pixel nach links schieben
  subq.w        #1,SnowFlake.HorPosition(A0)
  beq.w         NewSnowFlake
  addq.w        #1,SnowFlake.HorCenterLongWordPosition(A0)
  cmpi.w        #31,SnowFlake.HorCenterLongWordPosition(A0)
  bne           SetUpPatterns
  ; Wordberlauf:
  subq.w        #2,SnowFlake.WordPosition(A0)
  subi.w        #16,SnowFlake.HorCenterLongWordPosition(A0)
  bra           SetUpPatterns
 
 
 !SnowFlakeRightFall
  ; Schneeflocke ein Pixel nach rechts schieben
  addq.w        #1,SnowFlake.HorPosition(A0)
  cmpi.w        #639,SnowFlake.HorPosition(A0)
  beq           NewSnowFlake
  subq.w        #1,SnowFlake.HorCenterLongWordPosition(A0)
  bne           SetUpPatterns
  ; Wordberlauf:
  addq.w        #2,SnowFlake.WordPosition(A0)
  addi.w        #16,SnowFlake.HorCenterLongWordPosition(A0)
  bra           SetUpPatterns
 
 
 !SnowFlakeRightLeftOrStop
  move.w        #0,(A3)+
  move.w        #1,(A3)+
  jsr           MinMaxRandom
  move.w        -(A3),D1
  beq           SnowFlakeLeftFall
  bra.w         SnowFlakeRightFall
  
 
 !SetUpPatterns
  move.w        SnowFlake.HorCenterLongWordPosition(A0),D6
  moveq.l       #-1,D1
  bclr          D6,D1
  move.l        D1,SnowFlake.OnePointPattern(A0)
  not.l         D1
  move.l        D1,SnowFlake.CheckRightLeftOrStopValue(A0)
  subq.w        #1,D6
  bset          D6,D1
  move.l        D1,SnowFlake.CheckLeftFallValue(A0)
  bclr          D6,D1
  addq.w        #2,D6
  bset          D6,D1
  move.l        D1,SnowFlake.CheckRightFallValue(A0)
  subq.w        #2,D6
  bset          D6,D1
  move.l        D1,SnowFlake.CheckANDPattern(A0)
  move.l        D1,SnowFlake.CheckStopValue(A0)
  not.l         D1
  move.l        D1,SnowFlake.ThreePointPattern(A0)
  bra           SnowFlakeGoon
  
 !NewSnowFlake
  move.w        #0,(A3)+
  move.w        SnowRate,(A3)+
  jsr           MinMaxRandom
  tst.w         -(A3)
  bne.w         SnowFlakeGoon
  
  move.w        #1,(A3)+
  move.w        #3,(A3)+
  jsr           MinMaxRandom
  move.w        -(A3),D6
  mulu          #80,D6
  move.w        D6,SnowFlake.FallOffset(A0)
  st            SnowFlake.IsThere(A0)
  
  move.w        #1,(A3)+
  move.w        #638,(A3)+
  jsr           MinMaxRandom            ; horizontale Position der Flocke
  move.w        #2,(A3)+
  move.w        #360,(A3)+
  jsr           MinMaxRandom            ; Startzeile der Flocke
  move.w        -(A3),D6
  mulu          #80,D6
  moveq.l       #0,D1
  move.w        -(A3),D1
  move.w        D1,SnowFlake.HorPosition(A0)
  divu          #16,D1
  add.w         D1,D1
  cmpi.w        #78,D1
  bne           IsNotLastWord
  add.w         D1,D6
  subq.w        #2,D6
  move.w        D6,SnowFlake.WordPosition(A0)
  swap          D1
  not.w         D1
  andi.w        #$F,D1
  move.w        D1,SnowFlake.HorCenterLongWordPosition(A0)
  bra           SetUpPatterns
  
 !IsNotLastWord
  add.w         D1,D6
  move.w        D6,SnowFlake.WordPosition(A0)
  swap          D1
  not.w         D1
  andi.w        #$F,D1
  add.w         #$10,D1
  cmpi.w        #$1F,D1
  beq           IsWordBoundary
  move.w        D1,SnowFlake.HorCenterLongWordPosition(A0)
  bra           SetUpPatterns
 !IsWordBoundary
  subq.w        #2,SnowFlake.WordPosition(A0)
  subi.w        #16,D1
  move.w        D1,SnowFlake.HorCenterLongWordPosition(A0)
  bra           SetUpPatterns
 
 
 
 !StopSnowFlake
  sf            SnowFlake.IsThere(A0)
  move.w        #0,(A3)+
  move.w        #1,(A3)+
  jsr           MinMaxRandom
  tst.w         -(A3)
  beq           BIGSnowFlake
  move.l        SnowFlake.OnePointPattern(A0),D1
  and.l         D1,0(A4,D6.W)                   ; Einzeichnen in die SnowScreen
  bra           SnowFlakeGoon
 !BIGSnowFlake
  move.l        SnowFlake.OnePointPattern(A0),D1
  and.l         D1,-80(A4,D6.W)                   ; Einzeichnen in die SnowScreen
  and.l         D1,80(A4,D6.W)                   ; Einzeichnen in die SnowScreen
  move.l        SnowFlake.ThreePointPattern(A0),D1
  and.l         D1,0(A4,D6.W)                   ; Einzeichnen in die SnowScreen
  bra           SnowFlakeGoon
  END;
END DrawAndAnimateSnowFlakes;
(*$L+*)



PROCEDURE DrawTitle;
BEGIN
  DrawText ( WorkScreen, 14, 9, TRUE,
  '                       S N O W                     ' );
  DrawText ( WorkScreen, 14, 10, TRUE,
  ' Written with MEGAMAX MODULA-2 for the TOS-Magazin ' );
  DrawText ( WorkScreen, 14, 11, TRUE,
  '            July 1990 by Meinolf Schneider        ' );
END DrawTitle;


PROCEDURE MakeSnow;
BEGIN
  IF ~TitleWasThere
  THEN
    IF ShowTitle
    THEN
      DrawTitle;
      IF MyMouse.RightButton.JustPressed
      THEN
        TitleWasThere := TRUE;
        ShowTitle := FALSE;
      END;
    ELSE
      INC ( TitleTimer );
      ShowTitle := (TitleTimer > TitleTime);
    END;
  END;
  DrawAndAnimateSnowFlakes;
END MakeSnow;


PROCEDURE IceScratchSteering;
BEGIN
  ReadMouse ( MyMouse );
  WITH MyMouse DO
    IF RightButton.Pressed
    THEN
      IF RightButton.JustPressed
      THEN
        IceScratchThere := TRUE;
        ASSEMBLER
        dc.w      $A00A         ; Hide Mouse
        END;
      END;
    ELSIF RightButton.JustReleased
    THEN
      StopASound ( ScratchSound );
      IceScratchThere := FALSE;
      ASSEMBLER
      dc.w      $A009   ; Mauscursor wieder einschalten
      END;
    END;
  END;
END IceScratchSteering;



PROCEDURE WaitForSnow;
BEGIN
  INC ( SnowWait );
  IF SnowWait > SnowBegin
  THEN
    SnowThere := TRUE;
  END;
END WaitForSnow;
  
  
PROCEDURE ScratchLine ( x1, y1, x2, y2    : INTEGER );
VAR     dx, dy, t, vx, vy       : INTEGER;
BEGIN
  dx := ABS ( x2 - x1 );
  dy := ABS ( y2 - y1 );
  IF (x2-x1) < 0
  THEN
    vx := -1;
  ELSE
    vx := 1;
  END;
  IF (y2-y1) < 0
  THEN
    vy := -1;
  ELSE
    vy := 1;
  END;
  dx := dx + 1;
  dy := dy + 1;
  Sprite ( SnowScreen, SnowSpriteList, 1, x1, y1 );
  IF dx > dy
  THEN
    t := dx - dy;
    REPEAT
      IF x1 # x2
      THEN
        x1 := x1 + vx;
        t := t - dy;
        IF t < 0
        THEN
          t := t + dx;
          y1 := y1 + vy;
        END;
        Sprite ( SnowScreen, SnowSpriteList, 1, x1, y1 );
      END;
    UNTIL x1 = x2;
  ELSE
    t := dy - dx;
    REPEAT
      IF y1 # y2
      THEN
        y1 := y1 + vy;
        t := t - dx;
        IF t < 0
        THEN
          t := t + dy;
          x1 := x1 + vx
        END;
        Sprite ( SnowScreen, SnowSpriteList, 1, x1, y1 );
      END;
    UNTIL y1 = y2;
  END;
END ScratchLine;
  
  
PROCEDURE MakePicture;
BEGIN
  IF TOSScreenOnDisplay
  THEN
    IceScratchSteering;
    IF DirectTOSScreenShow
    THEN
      IF SnowThere OR IceScratchThere
      THEN
        DirectTOSScreenShow := FALSE;
      ELSE
        WaitForSnow;
      END;
      Switch ( TOSScreen );
    ELSE
      IF IceScratchThere
      THEN (* Eis entfernen *)
        ScratchLine ( MyMouse.Position.X.I, MyMouse.Position.Y.I,
                      MyMouse.OldPosition.X.I, MyMouse.OldPosition.Y.I );
        IF (MyMouse.Speed.X.I = 0) & (MyMouse.Speed.Y.I = 0)
        THEN
          StopASound ( ScratchSound );
        ELSIF ~ASoundIsActive ( ScratchSound )
        THEN
          StartASound ( ScratchSound, 10 );
        END;
      END;
      IF SnowThere
      THEN
        IF SnowRate # 0
        THEN
          DEC ( SnowRate );
        END;
        CopySnowScreen;
        MakeSnow;
      ELSE
        CopyScreen ( TOSScreen, WorkScreen );
        WaitForSnow;
      END;
      IF IceScratchThere
      THEN (* Eiskratzer einzeichnen *)
        Sprite ( WorkScreen, SnowSpriteList, 0,
                 MyMouse.Position.X.I, MyMouse.Position.Y.I );
      END;
      DirectTOSScreenShow := ~SnowThere & ~IceScratchThere;
      SwitchSides;
    END;
  END;
END MakePicture;


(*---------------------------- VBL - Interrupt -----------------------------*)

(*$L-*)
PROCEDURE VBLXBRA;
BEGIN
  ASSEMBLER
  asc           'XBRA'
  asc           'SNOW'
  dc.w          0
  END;
END VBLXBRA;
(*$L+*)

(*$L-*)
PROCEDURE VBLIRQ;
BEGIN
  ASSEMBLER
  subq.w        #1,$452
  bmi.w         ED                      ; VBLHandler gesperrt
  
  subi.w        #1,VBLTimer
  bpl.w         ED                      ; Bildaufbau nur bei jedem
                                        ; 3. Monitorbild
  
  move.w        #PicFreq-1,VBLTimer             ; Timer zurcksetzen
  
  movem.l       D0-D7/A0-A6,-(A7)
  
  clr.l         D0                      ; Lesen der aktuellen Bildschirmadresse
  move.l        #$FF8201,A0
  movep.w       0(A0),D0
  lsl.l         #8,D0
  
  move.w        #1,TOSScreenOnDisplay
  cmp.l         TOSScreen,D0
  beq           go
  cmp.l         DisplayScreen,D0
  beq           go
  clr.w         TOSScreenOnDisplay      ; Bildschirm wurde von jemand
                                        ; anderes umgesetzt
 !go
  lea           VBLStack,A3             ; Jetzt nehmen wir unseren Stack,
  jsr           MakePicture             ; und malen das neue Bild
  
  movem.l       (A7)+,D0-D7/A0-A6
 
 !ED
  addq.w        #1,$452
  move.l        OldVBLIRQ,-(A7)      ; alte VBL-Routine macht weiter...
  END;
END VBLIRQ;
(*$L+*)


(*$L-*)
PROCEDURE InstallVBLIRQ;
BEGIN
  ASSEMBLER
  jsr           EnterSupervisorMode
  move.w        SR,-(A7)
  ori.w         #$0700,SR
  
  move.l        $70,OldVBLIRQ
  lea           VBLXBRA,A0
  lea           VBLIRQ,A0
  move.l        $70,-4(A0)              ; XBRA-Vektor setzen
  move.l        A0,$70
  
  move.w        (A7)+,SR
  andi.w        #$DFFF,SR
  END;
END InstallVBLIRQ;
(*$L+*)

(*--------------------------------------------------------------------------*)


BEGIN
  ReadMouse ( MyMouse );
  ReadMouse ( MyMouse );
  ASSEMBLER
  move.l        #TabSnowSpriteList,SnowSpriteList
  move.l        #TabScratchSound,ScratchSoundADR
  lea           SnowLines,A0
  st            400(A0)         ; Endekennung
  END;
  SnowRate := 30 * PicsPerSec;
  Allocate ( SnowScreen, 32560L );
  NewSound ( ScratchSound, ScratchSoundADR, FALSE, 0L );
  ClearScreen ( SnowScreen + 560L );
  FillScreen ( SnowScreen );
  SetSampleFrequency ( 6269 );
  TOSScreen := GetSystemScreen();
  TOSScreenOnDisplay := TRUE;
  DirectTOSScreenShow := TRUE;
  VBLTimer := PicFreq;
  InstallVBLIRQ;
END Snow.

