; -----------------------------------------------------------------
;
; resident screen-saver
;
; -----------------------------------------------------------------

org 100h
use16


  _start:
	jmp	_init

  ; constants

	maxcount	dw ?	; timer ticks for delay 2186 = 2 min
	old9_ofs	dw ?	; old int 9 address
	old9_seg	dw ?
	old1C_ofs	dw ?	; old int 1C address
	old1C_seg	dw ?

	blank		db 0
	turn_on 	db 0
	count		dw 0
	pass_phase	db 0

	buf		rb 4050

	szPass		db "Computer locked. You must enter password to release computer",24h
	szPassword	db 0,"u",0,"n",0,"l",0,"o",0,"c",0,"k"
	pass_len	equ 12
	pass_ofs	dw 0

  ; code

  _printd:
	push	ax ds es
	test	si,si
	jz	_no_si

	mov	ax,0b800h
	mov	es,ax
	xor	bx,bx
	mov	ah,0Ah

  @@:
	lodsb
	cmp	al,24h
	jz	_no_si
	mov	word [es:bx],ax
	add	bx,2
	jmp	@B

  _no_si:
	pop	es ds ax
	ret

  _getc:
	push	ds es
	mov	ax,40h
	mov	es,ax
	mov	si,[es:1ch]
	mov	al,[es:si-2]
	movzx	ax,al
	pop	es ds
	ret

  _printc:
	push	ax ds es
	test	al,al
	jz	_no_al

	push	ax
	mov	ax,0b800h
	mov	es,ax
	xor	bx,bx
	pop	ax

	mov	ah,0Ah
	mov	word [es:bx],ax

  _no_al:
	pop	es ds ax
	ret

  _printc2:
	push	ax ds es
	test	al,al
	jz	_no_al2

	push	ax
	mov	ax,0b800h
	mov	es,ax
	xor	bx,bx
	pop	ax

	mov	ah,0Ah
	mov	word [es:bx+2],ax

  _no_al2:
	pop	es ds ax
	ret

  _savevid:
	push	ax ds es
	lea	di,[cs:buf]
	xor	si,si
	mov	ax,0b800h
	mov	es,ax
	mov	cx,2000

  _save_lop:
	mov	ax,[es:si]
	mov	[cs:di],ax
	add	di,2
	add	si,2
	dec	cx
	jnz	_save_lop

	pop	es ds ax
	ret

  _restvid:
	push	ax ds es
	lea	si,[cs:buf]
	xor	di,di
	mov	ax,0b800h
	mov	es,ax
	mov	cx,2000

  _rest_lop:
	mov	ax,[cs:si]
	mov	[es:di],ax
	add	di,2
	add	si,2
	dec	cx
	jnz	_rest_lop

	pop	es ds ax
	ret

  _clrbuf:
	push	ax ds es
	mov	ax,40h
	mov	es,ax
	mov	al,[es:1ch]
	mov	[es:1ah],al
	pop	es ds ax
	ret

  _showtime:
	push	ax ds es

	mov	ah,2
	int	1ah
	; now in BCD: ch = h, cl = m, dh = s

	mov	ax,0b800h
	mov	es,ax
	mov	bx,1992

	; set color
	mov	ah,0ah

	; print hours: 1st digit
	mov	al,ch
	shr	al,4
	add	al,'0'
	mov	word [es:bx],ax

	; print hours: 2nd digit
	inc	bx
	inc	bx
	mov	al,ch
	and	al,0fh
	add	al,'0'
	mov	word [es:bx],ax

	inc	bx
	inc	bx
	mov	al, ':'
	mov	word [es:bx],ax

	; m1
	inc	bx
	inc	bx
	mov	al,cl
	shr	al,4
	add	al,'0'
	mov	word [es:bx],ax

	; m2
	inc	bx
	inc	bx
	mov	al,cl
	and	al,0fh
	add	al,'0'
	mov	word [es:bx],ax

	inc	bx
	inc	bx
	mov	al,':'
	mov	word [es:bx],ax

	; s1
	inc	bx
	inc	bx
	mov	al,dh
	shr	al,4
	add	al,'0'
	mov	word [es:bx],ax

	; s2
	inc	bx
	inc	bx
	mov	al,dh
	and	al,0fh
	add	al,'0'
	mov	word [es:bx],ax

	pop	es ds ax
	ret

	; keyboard hook

  _new9:
	push	es ds ax
	push	cs
	pop	ds

	mov	ax,40h
	mov	es,ax

	pushf
	call	dword [old9_ofs]

	cmp	[pass_phase],0
	jnz	_pass
	cmp	[blank],0
	jnz	_rest_scrn
	mov	[count],0
	jmp	_exit_9

  _rest_scrn:
	mov	[pass_phase],1
	jmp	_exit_9_clr

  _pass:
	lea	si,[szPass]
	call	_printd

	mov	cx,[pass_ofs]
	lea	si,[szPassword]
	add	si,cx
	lodsb
	inc	cx
	mov	[pass_ofs],cx
	test	al,al
	jz	_exit_9_clr

	mov	cl,al
	call	_getc
	cmp	al,cl
	jz	_ok_char

	mov	[pass_ofs],0
	jmp	_exit_9_clr

  _ok_char:
	cmp	[pass_ofs],pass_len
	jnz	_exit_9_clr

	mov	[pass_ofs],0
	mov	[pass_phase],0
	mov	[turn_on],1

  _exit_9_clr:
	call	_clrbuf

  _exit_9:
	pop	ax ds es
	sti
	iret

	; timer hook

  _new1C:
	sti
	push	es ds dx ax
	push	cs
	pop	ds
	mov	ax,40h
	mov	es,ax
	cmp	[turn_on],0
	jz	_if_blank

	mov	[turn_on],0
	mov	[blank],0

	; restore video buffer

	call	_restvid
	mov	[count],0
	jmp	_exit_1C

  _if_blank:
	cmp	[blank],0
	jne	_chk_shift

	inc	[count]
	mov	ax,[maxcount]
	cmp	[count],ax
	jne	_exit_1C

	; set video buffer

	call	_savevid
	mov	[blank],1
	jmp	_do_crt

  _chk_shift:
	inc	[count]
	cmp	[count],37	; 2 sec
	jne	_exit_1C

  _do_crt:
	; video processing

	xor	ax,ax
	push	ax
	mov	ax,0b800h
	mov	es,ax
	xor	bx,bx
	cmp	[pass_phase],1
	jnz	@F
	add	bx,320
  @@:
	lea	di,[bx]
	cmp	[pass_phase],1
	jnz	@F
	add	di,320
  @@:
	mov	cx,2000
	cmp	[pass_phase],1
	jnz	@F
	sub	cx,320
  @@:
	pop	ax
	cld
	rep	stosw

	call	_showtime
	mov	[count],0

  _exit_1C:
	pop	ax dx ds es
	jmp	dword [cs:old1C_ofs]

	; messages

  _init_junk:
	szLoad	db "~ Resident screen-saver ~",13,10,13,10
		db "Resident screen-saver enabled",13,10,24h

	; initialization

  _init:
	push	cs
	pop	ds

	mov	dx,szLoad
	mov	ah,9
	int	21h		; display message

	; y = 1093 * 2
	mov	ax,2186
	mov	[maxcount],ax

	mov	ax,3509h	; get old int 9 address
	int	21h
	mov	ax,es
	mov	[old9_seg],ax	; save old int 9 address  (keyboard)
	mov	[old9_ofs],bx
	mov	dx,_new9	; set int 9 to point to our code
	mov	ax,2509h
	int	21h

	mov	ax,351Ch	; get old int 1C address  (timer tick)
	int	21h
	mov	ax,es
	mov	[old1C_seg],ax	; save old int 1C address
	mov	[old1C_ofs],bx
	mov	dx,_new1C	; set int 1C to point to our code
	mov	ax,251Ch
	int	21h

	mov	dx,(_init_junk-_start+256+16)/16
	mov	ax,3100h	; terminate and stay resident
	int	21h

; eof