! christmas.bas
! This program displays a simple Christmas message in a snowy envireonment.
! limitations
! - graphics setup, including display mode, colors, etc. are not set
! - the snow is a bit more like a blizard
! - the snowflakes that are further away should visually not be as affected
!   by the wind as those closer to the view port
! change history
! 10/15/2025 mrvan initial version

dim y(32) as integer               ! snowflake y
dim x(32) as integer               ! snowflake x
dim sy(32) as integer              ! snowflake y speed
dim sxc(32) as integer             ! snowflake x speed counter
dim sxl(32) as integer             ! snowflake x speed level before tripping actual movement
dim wind as integer                ! wind

dim restore_mode as integer
dim restore_rows as integer
dim restore_cols as integer

! writes the program message
sub message_write ()                       
   call clear ()

   int i
   for i = 1 to 7                          ! drop down 7 lines
      print
   next i

   call fontload ("/fonts/oldwfonts");

   print "XXXor unto us a child is born,"
   print "XXXunto us a son is given: and"
   print "XXXthe government shall be upon"
   print "his shoulder: and his name"
   print "shall be called Wonderful,"
   print "Counsellor, The mighty God, The"
   print "everlasting Father, The Prince"
   print "of Peace."
   print
   print "Isaiah 9:6"

   int j
   int c

   c = 16

   for j = 0 to 2
      for i = 7 to 9
         call hchar (i, j, c, 1)
         c = c + 1
      next i
   next j
end sub

! sets the character defs
SUB chars_create_snowflake_patterns ()     
   call char (128, "0000001008000000")     ! most distant snowflake
   call char (129, "0000102810000000")
   call char (130, "0008503814200000")
   call char (131, "301852FE94301800")     ! closest
end sub

! sets new sprite values (sprites are snowflakes)
SUB sprite_set_new_values (i as integer, top as integer)
   if top <> 0 then                        ! place sprite at top when top is set
      y(i) = 0
   else
      y(i) = RNDI (192)                    ! otherwise generate a random y
   end if
   x(i)    = rndi (256)                    ! generate a random x
   sy(i)   = rndi (4) + 1                  ! generate a random speed (and distance)
   sxc(i)  = 0                             ! counter for wind ticks for movement
   sxl(i)  = 20 - sy(i) * 4                ! set the number of wind ticks before movement
                                           ! closest move x more quickly; should be set
                                           ! to a minimum of max wind speed
   call sprite (i, 127 + sy(i), 15, y(i), x(i), 0, 0) ! place the sprite on the screen
end sub

! intialize all sprites
SUB SPRITES_INIT () 
   dim i as integer
   for i = 0 to 31                         ! loop through all sprites
      call sprite_set_new_values (i, 0)    ! set this sprite's values
   next i
end sub

! initialize wind
SUB WIND_INIT ()
   wind = 0
END SUB

! adjust wind
SUB WIND_ADJUST ()
   IF RNDI (100) < 1 THEN             ! generate wind
      WIND = WIND + RNDI (3) - 1      ! adjust wind by +/- 1 
      if WIND > 4 then                ! max out wind
         wind = 4
      else
         if wind < -4 then            ! max out wind
            wind = -4
         end if
      end if
   END IF
END SUB

sub sprite_adjust_for_wind (i as integer)
   dim wind_effect as integer
   wind_effect = 0
   sxc(i) = sxc(i) + wind
   if sxc(i) >= sxl(i) then
      sxc(i) = sxc(i) - sxl(i)
      wind_effect = 1
   else
      if sxc(i) <= -sxl(i) then
         sxc(i) = sxc(i) + sxl(i)
         wind_effect = -1
      end if
   end if           
   x(i) = x(i) + wind_effect    ! increment x pos by wind value
end sub

! make it snow!
sub snow ()
   dim i as integer

   do
      call wind_adjust ()                ! adjust wind
      for i = 0 to 31                    ! loop through all sprites
         call locate (i, y(i), x(i))     ! move the sprite to current location
         y(i) = y(i) + sy(i)             ! increment the y pos by speed s
         if y(i) >= 192 then             ! test for sprite off the screen
            sprite_set_new_values (i, 1) ! generate new starting position
         else 
            call sprite_adjust_for_wind (i)
         end if
      next i
      if inkey () <> 0 then
         break
      end if
   loop
end sub

sub display_setup ()
   call display_mode_get (restore_mode)
   call display_rows_and_cols (restore_rows, restore_cols)

   call display_mode (0, 24)
!  call screen (4)
   dim g as integer
   for g = 2 to 3          ! the boxed F
      call color (g, 8, 0)
   next g
   for g = 4 to 15         ! all other characters
      call color (g, 12, 0)
   next g
end sub

sub term ()
   call display_mode (restore_mode, restore_rows)
   call clear ()
   call charset ()
end sub

! the main program
SUB BMAIN () 

   ! perform setup
   call display_setup ()
   call message_write ()
   call chars_create_snowflake_patterns ()
   call sprites_init ()
   call wind_init ()

   ! make it snow!
   call snow ()
   
   ! terminate
   call term ()

END SUB
