;*********************************************************;
;* GRAVITY.ASM -- Simple little gravity (orbits) demo in *;
;* assembly language -- this is totally public domain    *;
;*********************************************************;

Ideal
Jumps

Model Tiny
P186
CodeSeg
Org 100h

Proc        Prog

            push 0                 ;ES = 0
            pop es
            mov ax,[es:046Ch]      ;Seed random number
            mov [word RandNum],ax  ;with BIOS timer
            mov ax,[es:046Eh]
            mov [word RandNum+2],ax

            mov bx,5               ;Blocks 0-5
InitLoop:   shl bx,1               ;Adjust BX
            mov ax,160             ;Calculate XPos:
            call Rand              ;XPos = 80 + Rand(160)
            add ax,80
            mov [XPos+bx],ax
            mov ax,100             ;Calculate YPos:
            call Rand              ;YPos = 50 + Rand(100)
            add ax,50
            mov [YPos+bx],ax
            mov ax,17              ;Calculate Speed:
            call Rand              ;XSpeed = Rand(17) - 8
            sub ax,8               ;YSpeed = Rand(13) - 6
            mov [XSpeed+bx],ax
            mov ax,13
            call Rand
            sub ax,6
            mov [YSpeed+bx],ax
            shr bx,1               ;Adjust BX
            dec bx                 ;Decrement counter
            jns InitLoop           ;Loop back

            mov ax,13h             ;Switch to mode 13h
            int 10h                ;using Video BIOS
            push 0A000h            ;Point ES to video memory
            pop es

MainLoop:   mov ah,1               ;Check for a key
            int 16h                ;BIOS keyboard
            jnz Done               ;Quit if there's a key

            xor bx,bx              ;Blocks 0-5
DrawLoop:   shl bx,1               ;Adjust BX
            mov cx,[XPos+bx]       ;CX = X
            mov dx,[YPos+bx]       ;DX = Y

            cmp cx,0               ;Check to see if
            jl NoDraw              ;it's off the screen
            cmp cx,316
            jg NoDraw
            cmp dx,0
            jl NoDraw
            cmp dx,196
            jg NoDraw

            add ch,dl              ;Calculate offset
            shl dx,6
            add cx,dx
            mov di,cx              ;Offset in DI
            shr bx,1               ;Adjust BX
            inc bx                 ;Color in BX
            mov al,bl              ;Color in AL, AH
            mov ah,bl
            add ah,8
            stosb                  ;First line
            add di,318             ;Next row
            stosw                  ;Second line
            stosb
            add di,318             ;Next row
            stosb                  ;Third line
            cmp bx,6               ;Done?
            jl DrawLoop            ;Loop back
            jmp Delay

NoDraw:     shr bx,1               ;Adjust BX
            inc bx                 ;Increment BX
            cmp bx,6               ;Done?
            jl DrawLoop            ;Loop back

Delay:      xor cx,cx              ;Delay for 62500 microseconds
            mov dx,62500           ;which is 1/16 second
            mov ah,86h
            int 15h

            mov bx,5               ;Blocks 0-5
EraseLoop:  shl bx,1               ;Adjust BX
            mov cx,[XPos+bx]       ;CX = X
            mov dx,[YPos+bx]       ;DX = Y
            add ch,dl              ;Calculate offset
            shl dx,6
            add cx,dx
            mov di,cx              ;Offset in DI
            xor ax,ax              ;Color in AL, AH
            stosb                  ;First line
            add di,318             ;Next row
            stosw                  ;Second line
            stosb
            add di,318             ;Next row
            stosb                  ;Third line
            shr bx,1               ;Adjust BX
            dec bx                 ;Done?
            jns EraseLoop          ;Loop back

            mov bx,5               ;Blocks 0-5
            mov cx,3               ;Dividing by 3
MoveLoop:   shl bx,1               ;Adjust BX
            mov ax,[XSpeed+bx]     ;Adjust X position
            cwd                    ;Divide
            idiv cx
            add [XPos+bx],ax
            mov ax,[YSpeed+bx]     ;Adjust Y position
            cwd                    ;Divide
            idiv cx
            add [YPos+bx],ax
            shr bx,1               ;Adjust BX
            dec bx                 ;Decrement
            jns MoveLoop           ;Loop back

            mov bx,5               ;Blocks 0-5
CalcLoop:   shl bx,1               ;Adjust BX
            mov ax,[XSpeed+bx]     ;Put X in 'new' array
            mov [NewXSpeed+bx],ax
            mov ax,[YSpeed+bx]     ;Put Y in 'new' array
            mov [NewYSpeed+bx],ax

            cmp [XPos+bx],160      ;Compare X to center
            jl c_1                 ;Less?
            jz c_2                 ;Same?
            sub [NewXSpeed+bx],2   ;No, subtract 1
c_1:        inc [NewXSpeed+bx]     ;Yes, add 1
c_2:        cmp [YPos+bx],100      ;Compare Y to center
            jl c_3                 ;Less?
            jz c_4                 ;Same?
            sub [NewYSpeed+bx],2   ;No, subtract 1
c_3:        inc [NewYSpeed+bx]     ;Yes, add 1

c_4:        mov si,5               ;Blocks 0-5
CompLoop:   shl si,1               ;Adjust SI
            mov ax,[XPos+si]       ;Load X position 2
            cmp [XPos+bx],ax       ;Compare X positions
            jl c_5                 ;Less?
            jz c_6                 ;Same?
            sub [NewXSpeed+bx],2   ;No, subtract 2
c_5:        inc [NewXSpeed+bx]     ;Yes, add 1
c_6:        mov ax,[YPos+si]       ;Load Y position 2
            cmp [YPos+bx],ax       ;Compare Y positions
            jl c_7                 ;Less?
            jz c_8                 ;Same?
            sub [NewYSpeed+bx],2   ;No, subtract 2
c_7:        inc [NewYSpeed+bx]     ;Yes, add 1
c_8:        shr si,1               ;Adjust SI
            dec si                 ;Decrement SI
            jns CompLoop           ;Loop back

            cmp [NewXSpeed+bx],45  ;X too fast?
            jl c_9                 ;No, skip
            mov [NewXSpeed+bx],45  ;Yes, adjust
c_9:        cmp [NewXSpeed+bx],-45 ;X too fast?
            jg c_10                ;No, skip
            mov [NewXSpeed+bx],-45 ;Yes, adjust
c_10:       cmp [NewXSpeed+bx],45  ;Y too fast?
            jl c_11                ;No, skip
            mov [NewYSpeed+bx],45  ;Yes, adjust
c_11:       cmp [NewYSpeed+bx],-45 ;Y too fast?
            jg c_12                ;No, skip
            mov [NewYSpeed+bx],-45 ;Yes, adjust

c_12:       shr bx,1               ;Adjust BX
            dec bx                 ;Decrement SI
            jns CalcLoop           ;Loop back

            mov bx,5               ;Blocks 0-5
ChangeLoop: shl bx,1               ;Adjust BX
            mov ax,[NewXSpeed+bx]  ;Adjust X speed
            mov [XSpeed+bx],ax
            mov ax,[NewYSpeed+bx]  ;Adjust Y speed
            mov [YSpeed+bx],ax
            shr bx,1               ;Adjust BX
            dec bx                 ;Decrement
            jns ChangeLoop         ;Loop back

            jmp MainLoop           ;Next iteration

Done:       xor ax,ax              ;Eat the key
            int 16h
            mov ax,3               ;Set text mode
            int 10h
            mov ax,4C00h           ;Return to DOS
            int 21h

EndP        Prog

Proc        Rand

            push bx cx dx          ;This RNG routine was
            push ax                ;taken from the TurboC
            mov ax,[word RandNum]  ;runtime library, but
            mov dx,4E35h           ;it is a big kludge.
            mul dx
            mov cx,dx
            mov bx,ax
            mov ax,[word RandNum]
            mov dx,015Ah
            mul dx
            add cx,ax
            mov ax,[word RandNum+2]
            mov dx,4E35h
            mul dx
            add cx,ax
            add bx,1
            adc cx,1
            mov [word RandNum],bx
            mov [word RandNum+2],cx
            mov ax,cx
            shl ax,1
            and bx,1
            add ax,bx
            pop bx
            xor dx,dx
            div bx
            mov ax,dx
            pop dx cx bx
            ret

EndP        Rand

XPos        dw 6 dup(?)            ;X Position
YPos        dw 6 dup(?)            ;Y Position
XSpeed      dw 6 dup(?)            ;X Speed
YSpeed      dw 6 dup(?)            ;Y Speed
NewXSpeed   dw 6 dup(?)            ;New X Speed
NewYSpeed   dw 6 dup(?)            ;New Y Speed
RandNum     dd ?                   ;Random number

End Prog
