;*****************************************************************************
; MOOSE.M68 - MARVIN the Magical MOOSE!
;
; Sends "cute" messages to users who haven't used any CPU time
; in the last minute or so - FUN!
;
; Get MOSEFX.M68 and MOOSYS.M68 while your at it.
;
; by Dave Heyliger - AMUS
;
; NOTES: 1) You need MOOSYS.M68 that assembles into MOOSYS.LIT.
;           RENAME MOOSE.SYS=MOOSYS.LIT, copy MOOSE.SYS down to
;           SYS: and then have in AMOSL.INI:
;                               SYSTEM MOOSE.SYS
;           Also, once MOOSE.M68 is assembled, place MOOSE in SYS:
;           (DSK0:[1,4]).
;
;        2) MARVIN the Magical MOOSE needs to be run on a JOB for
;           MARVIN to be "awake". This may be a mini-JOB with a
;           PSEUDO,NULL terminal or any JOB on your system.
;
;        3) To start MARVIN, either FORCE jobname MOOSE/delay    ,or
;           from the terminal that will run MOOSE, type MOOSE/delay.
;           where "delay" in both cases is the delay MARVIN will wait
;           before sending out a funny message (if CPU time unchanged).
;           I suggest a delay of at least 500, i.e., MOOSE/500.
;
;        4) For the end-user to hear MARVIN's great jokes and replies,
;           the user must type MOOSE ON from the dot at any time. To have
;           MARVIN "shut-up" on a particular JOB, type MOOSE OFF. Error
;           handling is thorough, so don't panic. Typing in MOOSE produces
;           directions if you forget.
;
;        5) If you would like to add to MARVIN's vocabulary, simply read the
;           instructions contained near the end of the code. HAVE FUN W/MARVIN
;*****************************************************************************


       SEARCH SYS
       SEARCH SYSSYM
       SEARCH TRM


       OBJNAM  MOOSE.LIT

;VARIABLES
;----------
       .OFINI
       .OFDEF  ONMSG,4                         ;Current ON message pointer
       .OFDEF  CURMSG,4                        ;Current running message ptr
       .OFDEF  OFFMSG,4                        ;Current OFF message pointer
       .OFDEF  USERS,512.                      ;Array of [JOBIDX,JOBCPU]
       .OFDEF  MOOSYS,6                        ;buffer for MOOSE.SYS
       .OFSIZ  IMPSIZ

;.MOOSE
;-------
       BYP                                     ;bypass whitespace
       LIN                                     ;just MOOSE?
       BNE     OK1                             ;no, so bypass
ERRMSG: TYPECR  <Usage: MOOSE ON to turn on talking moose>
       TYPECR  <       MOOSE OFF to turn him off (if you dare)>
       EXIT

;.MOOSE/delay
;.MOOSE ON
;.MOOSE OFF
;------------
OK1:    CMPB    @A2,#'/                         ;initialization? (MOOSE/del)
       BEQ     GETDEL                          ;yup
       CMPB    1(A2),#'N                       ;nope, see if N in "ON"
       BNE     CHKOFF                          ;nope, check for F in "OFF"
       CALL    MOSEON                          ;is MOOSE ON, so start
       EXIT                                    ;and quit

CHKOFF: CMPB    1(A2),#'F                       ;"OFF"?
       BNE     ERRMSG                          ;nope, no more possibilities
       CALL    MOSOFF                          ;yup, MOOSE OFF
       EXIT

GETDEL: BYP                                     ;bypass whitespace
       INC     A2                              ;bypass "/"
       CLR     D1                              ;be safe
       GTDEC                                   ;get the decimal value to D1
       MOV     D1,D4                           ;D4 dedicated sleep value
       MULS    D4,#1000.                       ;actual sleep value
       GETIMP  IMPSIZ,A3                       ;A3 dedicated variable regi
       CALL    SERCH                           ;search for system memory
       LEA     A0,MSGON                        ;pointer to MOOSE ON replies
       MOV     A0,ONMSG(A3)                    ;store initial ON message ptr
       MOV     A0,(A1)+                        ;in sys mem too
       LEA     A0,MSGCUR                       ;similar...
       MOV     A0,4+ONMSG(A3)
       LEA     A0,MSGOFF
       MOV     A0,10+ONMSG(A3)
       MOV     A0,@A1

;MAIN LOOP
;---------
LOOP:   LEA     A0,USERS(A3)                    ;point to user array
       MOV     MOOSYS(A3),A1                   ;A1 points to system module
       CTRLC   EXIT
       CALL    UPDATE                          ;nope, update user pointers
       CALL    MSGOUT                          ;output messages if nec
       CALL    SNOOZE                          ;sleep a bit
       BR      LOOP                            ;reload and repeat
EXIT:   MOV     MOOSYS(A3),A4                   ;point to system memory
       CLR     (A4)+                           ;clear pointers of messages
CLRPTR: CLR     (A4)+                           ;and JOBIDX's
       CMP     @A4,#0                          ;end of list?
       BNE     CLRPTR                          ;nope
       EXIT                                    ;yup, quit

;SEARCH FOR SYSTEM MEMORY MODULE
;-------------------------------
SERCH:  LEA     A2,MOOSE                        ;point to system file
       LEA     A4,MOOSYS(A3)                   ;and to variable in memory
       FILNAM  @A4                             ;convert to RAD50 filespec
       SRCH    @A4,A1                          ;search for the file
       BEQ     FOUND                           ;found MOOSE.SYS
       TYPECR  <?MOOSE.SYS not installed>      ;not found, so err msg
       EXIT                                    ;and quit
FOUND:  LEA     A4,MOOSYS(A3)                   ;repoint to variable
       MOV     A1,@A4                          ;store pointer to MOOSE.SYS
       RTN

;UPDATE MOOSE USERS
;------------------
UPDATE: ADD     #10,A1                          ;bypass pointers to msgs
UD:     CMP     @A1,#0                          ;end of list?
       BNE     NOTEOL                          ;nope
       BR      NOBAD                           ;yup, get rid of bad apples
NOTEOL: CMM     @A0,@A1                         ;local ptr = sys ptr?
       BEQ     MEMSYS                          ;yup
       CMP     @A0,#0                          ;end of local list?
       BEQ     ADDGUY                          ;yes, add new member
       ADD     #10,A0                          ;no, bypass the non match
       BR      NOTEOL                          ;and compare again
ADDGUY: MOV     @A1,(A0)+                       ;end local list, move in new
MEMSYS: ADD     #4,A1                           ;bypass this user in sys
       LEA     A0,USERS(A3)                    ;repoint to start of list
       BR      UD                              ;and scan for next user
NOBAD:  LEA     A0,USERS(A3)                    ;point to user list
REPONT: MOV     MOOSYS(A3),A1                   ;point to sys list
       ADD     #10,A1                          ;bypass msg ptrs
PTMACH: CMM     @A0,@A1                         ;pointers match?
       BEQ     NXTGUY                          ;yup, get next mem guy
       ADD     #4,A1                           ;nope, maybe next guy in sys
       CMP     @A1,#0                          ;end of list (no match?)
       BNE     PTMACH                          ;nope, still compare
       CALL    BUMP                            ;yup, bump guys to the left
       BR      NOBAD                           ;and scan again
NXTGUY: ADD     #10,A0                          ;match found, get next guy
       CMP     @A0,#0                          ;end of list?
       BNE     REPONT                          ;nope, repoint to sys and scan
       RTN

;MESSAGE SENDING CENTER
;----------------------
MSGOUT: LEA     A1,USERS(A3)                    ;point to user list
CHKMSG: MOV     (A1)+,A4                        ;A4 holds JOBIDX
       MOV     A4,D0                           ;for flags
       BNE     NOTEND                          ;if not at end, continue
       RTN                                     ;else return
NOTEND: CMM     JOBCPU(A4),(A1)+                ;same cpu time as last time?
       BEQ     TYPEIT                          ;yup, type message
       MOV     JOBCPU(A4),-4(A1)               ;else store new time
       BR      CHKMSG                          ;and check next guy
TYPEIT: JOBIDX  A6                              ;this JOBIDX
       MOV     JOBTRM(A6),A5                   ;this TB^
       PUSH    A5                              ;save it
       MOV     JOBTRM(A4),A5                   ;their TB^
       PUSH    A5                              ;save it
       LEA     A5,JOBTRM(A4)                   ;address of their TB^
       JLOCK   ;----------------------------------------------------------
       CLR     @A5                     ;"detach" their terminal
       LEA     A0,JOBTRM(A6)           ;A4 points to this TB^ memory area
       POP     @A0                     ;TB^ now is their terminal
       PUSH    @A0                     ;and save it too (need it later)
       LEA     A4,CURMSG(A3)           ;point to pointer
       MOV     @A4,A2                  ;get pointer to message line
       MOVB    (A2)+,D1                ;get character by character
CKMSG:  CMPB    @A2,#0                  ;end of messages?
       BNE     STLMOR                  ;nope
       TTY                             ;yup, type out LF
       LEA     A2,MSGCUR               ;repoint to start of list
       BR      SAVPTR                  ;and save the pointer
STLMOR: CMPB    @A2,#7                  ;at the next ding?
       BNE     NODING                  ;nope
       TTY                             ;type out line feed
SAVPTR: MOV     A2,CURMSG(A3)           ;yup, save the pointer
       BR      ATTACH                  ;and branch to attach
NODING: TTY                             ;type out the line
       MOVB    (A2)+,D1                ;get next character
       BR      CKMSG                   ;and check for ding char
ATTACH: POP     @A5                     ;attach it back to original owner
       POP     @A0                     ;attach OUR original terminal back
       JUNLOK  ;-----------------------------------------------------------
       JMP     CHKMSG                  ;and see if next guy needs a message


;BUMP USERS TO THE LEFT
;-----------------------
BUMP:   MOV     10(A0),(A0)+            ;bump IDX to left
       MOV     10(A0),(A0)+            ;bump JOBCPU to left
       CMP     @A0,#0                  ;end of bumping?
       BNE     BUMP                    ;nope
       RTN                             ;yup

;SLEEP FOR A BIT (depends on "delay")
;------------------------------------
SNOOZE: MOV     D4,D6
       SLEEP
       RTN

;MOOSE OFF routine
;-------------------
MOSOFF: GETIMP  IMPSIZ,A3                       ;A3 dedicated variable regi
       CALL    SERCH                           ;search for system memory
       JOBIDX  A6                              ;A6 holds JOBIDX pointer
       MOV     MOOSYS(A3),A4                   ;A4 points to system memory
       CMP     @A4,#0                          ;moose awake?
       BNE     YUP                             ;yup
       TYPECR  <MOOSE not awake at this time>  ;else err msg
       EXIT                                    ;and quit
YUP:    ADD     #4,A4                           ;bypass first pointer
LSTSCH: ADD     #4,A4                           ;bypass pointer or user
       CMP     @A4,#0                          ;end of list?
       BNE     NOERR1                          ;should never be 0
       TYPECR  <?MOOSE never turned ON>        ;err msg
       EXIT                                    ;and quit
NOERR1: CMP     A6,@A4                          ;find yourself?
       BNE     LSTSCH                          ;nope, error check & cont.
MOVE:   MOV     4(A4),(A4)+                     ;yup, bump people left
       CMP     @A4,#0                          ;end of list?
       BNE     MOVE                            ;nope
       MOV     MOOSYS(A3),A4                   ;get pointer to sys mem
       ADD     #4,A4                           ;bypass ON pointer
       MOV     @A4,A2                          ;A2 points to current off msg
       MOVB    (A2)+,D1                        ;get char to D1
CHKBYE: CMPB    @A2,#0                          ;end of message?
       BNE     BYE                             ;nope
       TTY                                     ;type out lf
       LEA     A2,MSGOFF                       ;yup, repoint to start
       MOV     MOOSYS(A3),A4                   ;get pointer to sys mem
       ADD     #4,A4                           ;bypass ON pointer
       BR      SAVBYE                          ;save bye message pointer
BYE:    CMPB    @A2,#7                          ;at a ding?
       BNE     NDING2                          ;nope
       TTY                                     ;type out LF
SAVBYE: MOV     A2,@A4                          ;save pointer in sys mem
       RTN                                     ;and return
NDING2: TTY                                     ;else type out character
       MOVB    (A2)+,D1                        ;get next character
       BR      CHKBYE                          ;until done

;MOOSE ON routine
;----------------
MOSEON: GETIMP  IMPSIZ,A3                       ;A3 dedicated variable regi
       CALL    SERCH                           ;search for system memory
       JOBIDX  A6                              ;A6 hold JOBIDX pointer
       MOV     MOOSYS(A3),A4                   ;A4 points to system memory
       CMP     @A4,#0                          ;moose awake?
       BNE     INUSER                          ;yup
       TYPECR  <MOOSE not awake at this time>
       EXIT
INUSER: ADD     #10,A4                          ;point past ONMSG,OFFMSG ptrs
SCHLST: CMP     @A4,#0                          ;end of list?
       BEQ     ENDSYS                          ;yup
       CMP     A6,@A4                          ;find yourself?
       BNE     NOERR2                          ;nope
       TYPECR  <MOOSE already ON for this JOB> ;err msg
       EXIT                                    ;and quit
NOERR2: ADD     #4,A4                           ;nope, try next position
       BR      SCHLST                          ;by searching the list
ENDSYS: MOV     A6,@A4                          ;end of list, move in user
       MOV     MOOSYS(A3),A4                   ;point to system mem
       MOV     @A4,A2                          ;A2 points to current on msg
AWAKE:  MOVB    (A2)+,D1                        ;get char to D1
CHKHI:  CMPB    @A2,#0                          ;end of messages?
       BNE     HELLO                           ;nope
       TTY                                     ;type out lf
       LEA     A2,MSGON                        ;yup, repoint to start
       BR      SAVHI                           ;save hello message pointer
HELLO:  CMPB    @A2,#7                          ;at next ding?
       BNE     NDING1                          ;nope
       TTY                                     ;type out LF
SAVHI:  MOV     A2,@A4                          ;save pointer in system mem.
       RTN                                     ;and return
NDING1: TTY                                     ;else type out character
       MOVB    (A2)+,D1                        ;get next character
       BR      CHKHI                           ;until done

;MOOSE.SYS filespec data
;------------------------
MOOSE:  ASCII   /MOOSE.SYS/
       EVEN

;MESSAGE LIST MARVIN KNOW'S WHEN YOU TURN MOOSE ON
;  To add more messages, add in
;       ASCII   / blah-blah /
;       BYTE    15,12,7
; HOWEVER: MAKE SURE THAT ONLY THE LAST LINE BEFORE "EVEN" CONTAINS
;          THE BYTE 15,12,0!!! (zero, not seven), AND MSGON: BYTE 7
;          REMAINS UNTOUCHED! VERY IMPORTANT!
;-------------------------------------------------------------------
MSGON:  BYTE    7
       ASCII   /Thanks, I was getting lonely./
       BYTE    15,12,7
       ASCII   /You won't regret it./
       BYTE    15,12,7
       ASCII   /You've made my day./
       BYTE    15,12,7
       ASCII   /Friends for life, OK?/
       BYTE    15,12,7
       ASCII   /Oh boy, someone to pester!/
       BYTE    15,12,0
       EVEN

;MESSAGES MARVIN SAYS WHEN YOU TYPE MOOSE OFF.
;  To add more, same rules as MSGON apply
;---------------------------------------------
MSGOFF: BYTE    7
       ASCII   /You'll be sorry!/
       BYTE    15,12,7
       ASCII   /Why, don't you like me?/
       BYTE    15,12,7
       ASCII   /Party Pooper./
       BYTE    15,12,7
       ASCII   /I'll give you $10.00 to turn me back on.../
       BYTE    15,12,7
       ASCII   /That hurts my feelings./
       BYTE    15,12,0
       EVEN

;MESSAGES MARVIN SAYS THROUGHOUT THE DAY
;  To add more, same rules as MSGON apply
;---------------------------------------------
MSGCUR: BYTE    7
       ASCII   /Sleeping on the JOB again???/
       BYTE    15,12,7
       ASCII   /You're about as lazy as I am.. and that's pretty lazy!/
       BYTE    15,12,7
       ASCII   /What'sa matta you?/
       BYTE    15,12,7
       ASCII   /Got'ta no respect./
       BYTE    15,12,7
       ASCII   /If you don't get to work, I'm telling the Boss!/
       BYTE    15,12,7
       ASCII   /Let's order a triple-decker pizza... what do you say?/
       BYTE    15,12,7
       ASCII   /Pretend you are alive. Your boss is coming!/
       BYTE    15,12,7
       ASCII   /You look MARVIN-lous/
       BYTE    15,12,7
       ASCII   /Are you there?/
       BYTE    15,12,7
       ASCII   /Your keyboard is getting cold!/
       BYTE    15,12,0
END