Jump to content

Photo

Colossal Cave Adventure diary


243 replies to this topic

#201 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Fri Feb 24, 2012 7:35 PM

By the way, the build tools are available in Cygwin. In any case, you can get the free Active Perl.


I've sometimes had problems with Cygwin. Their whole "cygdrive" fiction, trying to transform Windows paths into Unix paths and flipping slashes around really messes things up. Dunno if they've stopped doing that, but that was the reason I left Cygwin. That said, I have plenty of happy coworkers, so maybe the problem's just me.

The ActiveState Perl is what I use. It worked first-time with this script. It may not be the world's sexiest build script, but it gets the job done.

#202 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Fri Feb 24, 2012 7:38 PM

Oops, one tiny, tiny bug crept in. In "build.pl", delete this line (near the end of the file):

binmode($cfh);

That's not supposed to be there. The only real effect it has is to generate a .cfg file with *nix-style newlines instead of Windows-style on a Windows machine. jzIntv doesn't care, but notepad does. **shrug**

#203 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 5,364 posts
  • Ranger Elf: Saviour of Christmas!
  • Location:NC, USA

Posted Fri Feb 24, 2012 7:40 PM


By the way, the build tools are available in Cygwin. In any case, you can get the free Active Perl.


I've sometimes had problems with Cygwin. Their whole "cygdrive" fiction, trying to transform Windows paths into Unix paths and flipping slashes around really messes things up. Dunno if they've stopped doing that, but that was the reason I left Cygwin. That said, I have plenty of happy coworkers, so maybe the problem's just me.

The ActiveState Perl is what I use. It worked first-time with this script. It may not be the world's sexiest build script, but it gets the job done.


Cygwin still does that. "/drives/c/program\ files/". Yup, it's rather silly. I avoid any problems by "thinking UNIX" when using Cygwin, and not interacting with any Windows-ish parts. In essence, just rooting somewhere off the C:\ drive. I also set up symlinks and environment variables to my common directories so that I don't have to remember, is it "c:/" or "/drives/c/" or "/mnt/drives/c/"?

-dZ.

Edited by DZ-Jay, Fri Feb 24, 2012 7:40 PM.


#204 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Fri Feb 24, 2012 7:44 PM

Cygwin still does that. "/drives/c/program\ files/". Yup, it's rather silly. I avoid any problems by "thinking UNIX" when using Cygwin, and not interacting with any Windows-ish parts. In essence, just rooting somewhere off the C:\ drive. I also set up symlinks and environment variables to my common directories so that I don't have to remember, is it "c:/" or "/drives/c/" or "/mnt/drives/c/"?


Yuck. :-) You know, it wasn't too much of a problem for me, actually. But, when I was building jzIntv with Cygwin, explaining to people how to tell jzIntv where to find their games made me feel like a certain textile-challenged emperor. As it is, the command line already turns a few people off. The cygdrive thing, though, would be enough for many folk to argue jzIntv didn't actually have a Windows port, but rather was a Unix program that happens to run in Windows somehow, which isn't the case at all.

Anyway... getting a little off topic. The new perl build script at least limits the dependencies to one program that has a solid Windows port and is easy to install. If we end up needing more build shenanigans, we can fold it into that perl script.

Edited by intvnut, Fri Feb 24, 2012 7:45 PM.


#205 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Sat Feb 25, 2012 7:32 PM

Ok, just a minor update. I added some word-wrapping logic (which makes the screen much more readable) and a *More* facility to pause after each screenful. Both make it much easier to playtest. I also added the build.pl fix, and renamed 26K to 34K as it should be.

Attached Files



#206 vprette OFFLINE  

vprette

    Stargunner

  • Topic Starter
  • 1,258 posts

Posted Mon Feb 27, 2012 4:25 AM

Ok, just a minor update. I added some word-wrapping logic (which makes the screen much more readable) and a *More* facility to pause after each screenful. Both make it much easier to playtest. I also added the build.pl fix, and renamed 26K to 34K as it should be.


Hello
if I see right, the text now is organised to never cut the words between two rows, right?
this is very good....

In fact, to move your code into my scheleton seems very complex for me.... so I may consider keeping my code from title to intro and hidden novel up to level 1 when your code will take place..... to do this and keep my original screen layout, I need to:

1 - reintroduce the custom font
2 - skip the initial message with request for instruction (those are exaclty the same written in the manual)
3 - use the circle/arrow instead of "more" as indicating the text will continue. When 2 pages need to be shown because of a very long text, there will be 2 yellow arrows
4 - handle the command from controller (8 direction + up/down + pause music)

in whic .asm I have to deep to make those changes?
1 -> "ansi.asm"?
2 -> ?
3 -> ?
4 -> ?

Posted Image

#207 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Mon Feb 27, 2012 12:09 PM


Ok, just a minor update. I added some word-wrapping logic (which makes the screen much more readable) and a *More* facility to pause after each screenful. Both make it much easier to playtest. I also added the build.pl fix, and renamed 26K to 34K as it should be.


Hello
if I see right, the text now is organised to never cut the words between two rows, right?
this is very good....

In fact, to move your code into my scheleton seems very complex for me.... so I may consider keeping my code from title to intro and hidden novel up to level 1 when your code will take place..... to do this and keep my original screen layout, I need to:

1 - reintroduce the custom font
2 - skip the initial message with request for instruction (those are exaclty the same written in the manual)
3 - use the circle/arrow instead of "more" as indicating the text will continue. When 2 pages need to be shown because of a very long text, there will be 2 yellow arrows
4 - handle the command from controller (8 direction + up/down + pause music)

in whic .asm I have to deep to make those changes?
1 -> "ansi.asm"?
2 -> ?
3 -> ?
4 -> ?

Posted Image


Ok, let's wade through all this. First off, I figure you'd just completely replace ansi.asm with something to handle output differently. I just used it as a quick and dirty starting point because I had it handy. All text output eventually goes through "putchar", and that's defined in puts.asm. Whatever output mechanism you define, you'd hook it up there.

For example, one idea would be to have it print everything to a virtual "frame buffer" in memory, and then you could use the disc to scroll around. That code would also handle the "more" facility and so on. The best strategy would be to slurp up all input to this off-screen buffer until the game gets to a point where it's waiting for input, and then your display code takes over presenting it to the player. All of the display update and such would then be handled by tasks you hang off of P Machinery. You hook the two together through putchar.

Changing the font over happens "automagically" when you replace ansi.asm with your own code. :-)

User input currently comes in at two places: getline.asm and more.asm. The second one, "more.asm", would go away once you have the more sophisticated output display. "getline" is where you know the engine has switched from output to input mode. When the game reaches getline, you can let the user page through the display, scrolling up and down if they like. This is also where you'd inject keystrokes for commands triggered from the controller keypad.

I would suggest removing the call to SCAN_ECS from getline, and change it to a more generic "getkey" function. Have a separate P Machinery task scan the keyboard into an input buffer that getkey consults. If someone hits the controller disc, you can flush the keyboard buffer and replace it with the user's command. Also insert an "ESC" at the start of a controller-triggered command if it's a verb, and that will cause getline to back out anything else the user has typed. (Try it -- ESC already does this actually.) Something like this (untested):

typeahead   EQU         20

            BYTEARRAY   kb,     typeahead   ;; allow some typeahead
            BYTEVAR     kb.head             ;; first char to return to player
            BYTEVAR     kb.tail             ;; most recently queued keystroke

;; ======================================================================== ;;
;;  GETKEY  Read the next key of input from the player.                     ;;
;; ======================================================================== ;;
getkey      PROC
            PSHR        R5

            ; Wait for a key to show up.
@@wait:     ;CALL       yield               ; allow time slicing properly
            MVI         kb.head,    R1
            CMP         kb.tail,    R1
            BEQ         @@wait

            INCR        R1                  ; consume keystroke
            CMPI        #typeahead, R1      ; wrap around end of buffer
            BLT         @@no_wrap     
            CLRR        R1
@@no_wrap   MVO         R1,         kb.head

            ADDI        #kb,        R1
            MVI@        R1,         R0      ; get keystroke
            PULR        PC
            ENDP

;; ======================================================================== ;;
;;  FLUSHK  Flush the keyboard buffer                                       ;;
;; ======================================================================== ;;
flushk      PROC
            CLRR        R0
            MVO         R0,         kb.head
            MVO         R0,         kb.tail
            JR          R5
            ENDP

;; ======================================================================== ;;
;;  PUTKEY  Put a keystroke into the keyboard buffer.                       ;;
;; ======================================================================== ;;
putkey      PROC

            ; Is there room?
            MVI         kb.tail,    R1
            SUB         kb.head,    R1
            BPL         @@no_wrap1
            ADDI        #typeahead, R1      ; handle tail-wrap

@@no_wrap1  CMPI        #typeahead, R1
            BGE         @@leave             ; no room


            MVI         kb.tail,    R1
            INCR        R1
            CMPI        #typeahead, R1
            BLT         @@no_wrap2
            CLRR        R1
@@no_wrap2  MVO         R1,         kb.tail ; Make room for keystroke

            ADDI        #kb,        R1
            MVO@        R0,         R1      ; put in keystroke

@@leave     JR          R5
            ENDP

;; ======================================================================== ;;
;;  KEYSCAN Keyboard scanning task                                          ;;
;; ======================================================================== ;;
keyscan     PROC
            PSHR        R5

            CALL        SCAN_KBD
            CMPI        #KEY.NONE,  R0
            BEQ         @@no_key

            PULR        R5
            B           putkey              ; queue the keystroke

@@nokey     PULR        PC
            ENDP


;; ======================================================================== ;;
;;  KEYPAD  Handle numeric keys on controller keypad.                       ;;
;;          This function goes in the controller dispatch table.            ;;
;; ======================================================================== ;;
keypad      PROC
            ANDI        #$FF,       R2      ; ignore controller number
            CMPI        #$80,       R2      ; ignore key release events
            BLT         @@press
            JR          R5

@@press:    PSHR        R5

            MOVR        R2,         R1
            ADDI        #@@cmdptr,  R1      ; Command string pointer table
            MVI@        R1,         R4      ; Is it a 'macro'?
            TSTR        R4
            BNEQ        @@do_macro

            ; put code here to process R1 if it isn't a macro command
            ; ie. pause/unpause music, etc.

@@done:     PULR        PC

@@do_macro:
            CALL        flushk              ; flush queued keystrokes
            MVII        #KEY.ESC,   R0
            CALL        putkey              ; queue an ESC to flush getline

@@keyloop:  MVI@        R4,         R0
            TSTR        R0
            BEQ         @@done

            CALL        putkey
            B           @@keyloop

;                       0 
@@cmdptr    DECLE       @@look;
;                       1       2       3
            DECLE       @@get,  @@n,    @@drop
;                       4       5       6
            DECLE       @@w,    @@out,  @@e
;                       7       8       9
            DECLE       0,      @@s,    0           ; 7 and 9 -- leave open?
;                       C               E
            DECLE       0,              0           ; C and E -- leave open?

@@look:     STRING      "look",  $A, 0
@@get:      STRING      "get ",      0
@@n:        STRING      "north", $A, 0
@@drop:     STRING      "drop ",     0
@@w:        STRING      "west",  $A, 0
@@out:      STRING      "out",   $A, 0        
@@e:        STRING      "east",  $A, 0
@@s:        STRING      "south", $A, 0

            ENDP

That integrates the two input streams into one. Then in getline, instead of calling SCAN_ECS, you just call getkey:

            CALL        SCAN_KBD
            CMPI        #KEY.NONE,  R0
            BEQ         @@loop

becomes

            CALL        getkey


The initial welcome message gets triggered by this code in adv.asm:
        MVII    #INITIAL,   R0
        CALL    process

@@forever:
        MVII    #REPEAT,    R0
        CALL    process
        B       @@forever

That part gets replaced entirely when you pull everything into your framework. The adv.asm file needs to go away--it's just a placeholder since I didn't build this directly on P Machinery. This loop should become a P Machinery task of sorts when you're in the "in game" state:

@@forever:
        MVII    #REPEAT,    R0
        CALL    process
        B       @@forever


Got all that?

Attached Files



#208 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Mon Feb 27, 2012 5:01 PM

Attached is a quick stab at an ansi.asm replacement. It also defines control characters 16 thru 31 to change foreground colors. You'd call 'refresh' from an interrupt context to keep the display refreshed. I haven't tested this code -- I don't even know if it assembles correctly -- but I thought I'd at least get this stab down in writing.

To integrate it w/ CC, you'd delete the 'putchar' function from puts.asm. Also, you need to change all references to A_r and A_c in the code to vfb.r and vfb.c. The 'more' functionality will be broken for now, but that can be fixed later.

The main idea of this code is that you can scroll the screen by simply updating vfb.tos and setting vfb.do_refr. The next frame, the screen will scroll to the new line. So, you can write your disc handler to manipulate the scroll position, and allow the player to scroll back through several pages of text. (Right now I've set it to 64 lines, which is just over 5 screenfuls of text.) This should fit comfortably in JLP RAM alongside the other buffers.

Attached Files

  • Attached File  vfb.asm   8.22KB   44 downloads


#209 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 12:10 PM

Just a quick bit of status from my end: I've updated the engine to "yield" periodically while running as a self-triggering task via RUNQ, and have converted it to use the VFB approach for text instead of the ANSI interpreter. The "more" functionality is absent in this version, but we can add it back later.

At this point, I probably need to start integrating it with P Machinery. The core engine is pretty much ready for that now.

EDIT: Valter, if you send me the code you have, I can try integrating mine with yours and sending you back the result. You can email it to me or PM me if you prefer not to post it here.

Attached Files


Edited by intvnut, Tue Feb 28, 2012 12:14 PM.


#210 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 5,364 posts
  • Ranger Elf: Saviour of Christmas!
  • Location:NC, USA

Posted Tue Feb 28, 2012 12:24 PM

Just a quick bit of status from my end: I've updated the engine to "yield" periodically while running as a self-triggering task via RUNQ, and have converted it to use the VFB approach for text instead of the ANSI interpreter. The "more" functionality is absent in this version, but we can add it back later. At this point, I probably need to start integrating it with P Machinery. The core engine is pretty much ready for that now. EDIT: Valter, if you send me the code you have, I can try integrating mine with yours and sending you back the result. You can email it to me or PM me if you prefer not to post it here.


I'm sorry I haven't been able to help much with the integration, I've been busy with many things at the same time and I haven't even had the chance of running your engine.

Joe, let me know if you have any questions regarding P-Machinery, of if I can help in any way.

-dZ.

#211 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 12:25 PM

BTW, one nifty feature that comes with the latest code drop above is "typeahead": You can continue to type while the engine "thinks", and it'll buffer up to 20 keystrokes.

The code uses a (bugfixed) version of the getkey code I posted earlier. Once it drops into P Machinery and we hook up a controller scanner, then getkey can return keystrokes from both the hand controller and the ECS keyboard as one unified input stream.

#212 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 12:28 PM

I'm sorry I haven't been able to help much with the integration, I've been busy with many things at the same time and I haven't even had the chance of running your engine.

Joe, let me know if you have any questions regarding P-Machinery, of if I can help in any way.


Sure thing, and I understand. I believe Valter has already been hanging some code off of P-Machinery, so I'd like to start with whatever he has. I downloaded a version from the other thread, but I think I should set to modifying whatever Valter already has to avoid further integration issues.

One thing I did run into: I can't just trivially get rid of the introduction screen. We'll have to modify the actual game database (the .d files), since all the variable initialization occurs in the same execution stream that prints out the welcome message. Either that, or I'll have to run the init once, capture the memory image, and bypass the intro that way. That may actually be better, since it'll speed up "boot".

#213 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 5,364 posts
  • Ranger Elf: Saviour of Christmas!
  • Location:NC, USA

Posted Tue Feb 28, 2012 12:36 PM

Joe,

Does your engine include its own keyboard input processor, or were you expecting to hook it up to P-Machinery?

P-Machinery offers hooks for input processors. They just need to be defined in the state dispatch table, and that's all.

My intention was to create a generic getKey() keyboard handler that reads the keyboard input, and then a keyboard input processor which is just a wrapper to it with the purpose of triggering key-down and key-up events.

A similar architecture exists for the game controllers in P-Machinery, where there's an internal "getKey()" function that handles de-bouncing and de-noising the input signal; and individual input processors that wrap around it, decode the results, and trigger the appropriate events.

However, for this game perhaps it'll be easier to just ignore the future re-use of this architecture and write an all-in-one input processor for your getKey() function that will handle the buffer and all.

-dZ.

#214 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 5,364 posts
  • Ranger Elf: Saviour of Christmas!
  • Location:NC, USA

Posted Tue Feb 28, 2012 12:43 PM

Once it drops into P Machinery and we hook up a controller scanner, then getkey can return keystrokes from both the hand controller and the ECS keyboard as one unified input stream.


The architecture in P-Machinery is similar to your SCANHAND routine, in that it decodes the input and triggers events. The event handlers are the game-specific parts, which in this case should be the ones handling the buffer. This allows for other applications using the keyboard without buffering.

Then for this input processor you'll have events for:
  • Keypad
  • Action buttons
  • Disc
  • ECS Keyboard

Edited by DZ-Jay, Tue Feb 28, 2012 12:44 PM.


#215 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 12:46 PM

Joe,

Does your engine include its own keyboard input processor, or were you expecting to hook it up to P-Machinery?

P-Machinery offers hooks for input processors. They just need to be defined in the state dispatch table, and that's all.

My intention was to create a generic getKey() keyboard handler that reads the keyboard input, and then a keyboard input processor which is just a wrapper to it with the purpose of triggering key-down and key-up events.

A similar architecture exists for the game controllers in P-Machinery, where there's an internal "getKey()" function that handles de-bouncing and de-noising the input signal; and individual input processors that wrap around it, decode the results, and trigger the appropriate events.

However, for this game perhaps it'll be easier to just ignore the future re-use of this architecture and write an all-in-one input processor for your getKey() function that will handle the buffer and all.

-dZ.


dZ,

For the ECS keyboard, I'm expecting something to call "keyscan" periodically to scan the ECS keyboard and drop keystrokes into my typeahead buffer. The rest of the game calls "getkey" which consumes from that buffer. (I also just modified getkey to pump keyscan if the keyboard buffer is empty.) I'd suggest keyscan get called, say, once per frame. In my simple driver program (adv.asm), I just call it from the ISR.

For controller input, I'm expecting something else to call a controller scanner and do decode/dispatch, like I've done in the past with SCANHAND / QTASK. For controller events that translate into keystrokes, I've written (and posted upthread) code that receives those events and expands them into the typeahead buffer. That particular handler expects SCANHAND-style events, but it can be adapted to whatever controller scanner you like. The main thing is that it wants to be called when it sees a keypad key that it has to process.

Colossal Cave doesn't need keydown/keyup, just keydown. (I figure autorepeat isn't really useful in this game.) So if your input processor framework just calls keyscan, that's sufficient. The keystrokes, though, won't generate events into the event queue. Rather, they go straight to my typeahead buffer.

For reference, here's all the keyboard logic. SCAN_KBD is the keyboard scanner I posted on the ECS keyboard tutorial.

typeahead   EQU         20

            BYTEARRAY   kb,     typeahead   ;; allow some typeahead
            BYTEVAR     kb.head             ;; first char to return to player
            BYTEVAR     kb.tail             ;; most recently queued keystroke

;; ======================================================================== ;;
;;  GETKEY  Read the next key of input from the player.                     ;;
;; ======================================================================== ;;
getkey      PROC
            PSHR        R5

            ; Wait for a key to show up.
            B           @@first
@@wait:     CALL        yield               ; allow time slicing properly
            CALL        keyscan             ; why not?
@@first:    MVI         kb.head,    R1
            CMP         kb.tail,    R1
            BEQ         @@wait

            INCR        R1                  ; consume keystroke
            CMPI        #typeahead, R1      ; wrap around end of buffer
            BLT         @@no_wrap     
            CLRR        R1
@@no_wrap   MVO         R1,         kb.head

            ADDI        #kb,        R1
            MVI@        R1,         R0      ; get keystroke
            PULR        PC
            ENDP

;; ======================================================================== ;;
;;  FLUSHK  Flush the keyboard buffer                                       ;;
;; ======================================================================== ;;
flushk      PROC
            CLRR        R0
            MVO         R0,         kb.head
            MVO         R0,         kb.tail
            JR          R5
            ENDP

;; ======================================================================== ;;
;;  PUTKEY  Put a keystroke into the keyboard buffer.                       ;;
;; ======================================================================== ;;
putkey      PROC

            ; Is there room?
            MVI         kb.tail,    R1
            SUB         kb.head,    R1
            BPL         @@no_wrap1
            ADDI        #typeahead, R1      ; handle tail-wrap

@@no_wrap1  CMPI        #typeahead, R1
            BGE         @@leave             ; no room


            MVI         kb.tail,    R1
            INCR        R1
            CMPI        #typeahead, R1
            BLT         @@no_wrap2
            CLRR        R1
@@no_wrap2  MVO         R1,         kb.tail ; Make room for keystroke

            ADDI        #kb,        R1
            MVO@        R0,         R1      ; put in keystroke

@@leave     JR          R5
            ENDP

;; ======================================================================== ;;
;;  KEYSCAN Keyboard scanning task                                          ;;
;; ======================================================================== ;;
keyscan     PROC
            PSHR        R5

            CALL        SCAN_KBD
            CMPI        #KEY.NONE,  R0
            BEQ         @@no_key

            PULR        R5
            B           putkey              ; queue the keystroke

@@no_key    PULR        PC
            ENDP

And here's the event handler that converts controller input to a sequence of keystrokes, which I called a "macro" below. My expectation was that whatever decodes the controller would eventually dispatch to this to handle keypad events.

;; ======================================================================== ;;
;;  KEYPAD  Handle numeric keys on controller keypad.                       ;;
;;          This function goes in the controller dispatch table.            ;;
;; ======================================================================== ;;
keypad      PROC
            ANDI        #$FF,       R2      ; ignore controller number
            CMPI        #$80,       R2      ; ignore key release events
            BLT         @@press
            JR          R5

@@press:    PSHR        R5

            MOVR        R2,         R1
            ADDI        #@@cmdptr,  R1      ; Command string pointer table
            MVI@        R1,         R4      ; Is it a 'macro'?
            TSTR        R4
            BNEQ        @@do_macro

            ; put code here to process R1 if it isn't a macro command
            ; ie. pause/unpause music, etc.

@@done:     PULR        PC

@@do_macro:
            CALL        flushk              ; flush queued keystrokes
            MVII        #KEY.ESC,   R0
            CALL        putkey              ; queue an ESC to flush getline

@@keyloop:  MVI@        R4,         R0
            TSTR        R0
            BEQ         @@done

            CALL        putkey
            B           @@keyloop

;                       0 
@@cmdptr    DECLE       @@look;
;                       1       2       3
            DECLE       @@get,  @@n,    @@drop
;                       4       5       6
            DECLE       @@w,    @@out,  @@e
;                       7       8       9
            DECLE       0,      @@s,    0           ; 7 and 9 -- leave open?
;                       C               E
            DECLE       0,              0           ; C and E -- leave open?

@@look:     STRING      "look",  $A, 0
@@get:      STRING      "get ",      0
@@n:        STRING      "north", $A, 0
@@drop:     STRING      "drop ",     0
@@w:        STRING      "west",  $A, 0
@@out:      STRING      "out",   $A, 0        
@@e:        STRING      "east",  $A, 0
@@s:        STRING      "south", $A, 0

            ENDP

Speaking of macros, we could add macros on the ECS keyboard side too. If you see CTRL+letter, it's pretty easy to expand that out into a word, which might make typing common verbs a little nicer.


#216 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 12:47 PM

Once it drops into P Machinery and we hook up a controller scanner, then getkey can return keystrokes from both the hand controller and the ECS keyboard as one unified input stream.


The architecture in P-Machinery is similar to your SCANHAND routine, in that it decodes the input and triggers events. The event handlers are the game-specific parts, which in this case should be the ones handling the buffer. This allows for other applications using the keyboard without buffering.

Then for this input processor you'll have events for:
  • Keypad
  • Action buttons
  • Disc
  • ECS Keyboard


It wouldn't be hard to replace my keyscan with your ECS keyboard event generator. Just have the event handler call "putkey" for each keydown event.

Edited by intvnut, Tue Feb 28, 2012 12:48 PM.


#217 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 12:55 PM


Once it drops into P Machinery and we hook up a controller scanner, then getkey can return keystrokes from both the hand controller and the ECS keyboard as one unified input stream.


The architecture in P-Machinery is similar to your SCANHAND routine, in that it decodes the input and triggers events. The event handlers are the game-specific parts, which in this case should be the ones handling the buffer. This allows for other applications using the keyboard without buffering.

Then for this input processor you'll have events for:
  • Keypad
  • Action buttons
  • Disc
  • ECS Keyboard


It wouldn't be hard to replace my keyscan with your ECS keyboard event generator. Just have the event handler call "putkey" for each keydown event.


In fact, it would look almost identical to the keypad handler I posted above. It could sort keystrokes into "macro" and "not macro", even. You might even be able to merge them into one function that handles both, just with two entry points so that you can shift the event number ranges.

#218 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 5,364 posts
  • Ranger Elf: Saviour of Christmas!
  • Location:NC, USA

Posted Tue Feb 28, 2012 12:57 PM


Once it drops into P Machinery and we hook up a controller scanner, then getkey can return keystrokes from both the hand controller and the ECS keyboard as one unified input stream.


The architecture in P-Machinery is similar to your SCANHAND routine, in that it decodes the input and triggers events. The event handlers are the game-specific parts, which in this case should be the ones handling the buffer. This allows for other applications using the keyboard without buffering.

Then for this input processor you'll have events for:
  • Keypad
  • Action buttons
  • Disc
  • ECS Keyboard


It wouldn't be hard to replace my keyscan with your ECS keyboard event generator. Just have the event handler call "putkey" for each keydown event.


I guess I'm muddling the waters by using terms that collide with yours. Your "getkey" function is the one that fetches from the buffer, right? My "getkey" function (which I admit is probably a misnomer) is the one that polls the controller.

In your scenario, it'll also write into the typeahead buffer, so it would be your "keyscan" routine.

If I understand your approach, the controller model should be different from the keyboard model, because both use cases are different. The former is event based, and the latter depends on a typeahead buffer that needs to get read (and thus, flushed) by the game periodically.

Is this right?

-dZ.

#219 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 5,364 posts
  • Ranger Elf: Saviour of Christmas!
  • Location:NC, USA

Posted Tue Feb 28, 2012 1:03 PM

For the ECS keyboard, I'm expecting something to call "keyscan" periodically to scan the ECS keyboard and drop keystrokes into my typeahead buffer. The rest of the game calls "getkey" which consumes from that buffer. (I also just modified getkey to pump keyscan if the keyboard buffer is empty.) I'd suggest keyscan get called, say, once per frame. In my simple driver program (adv.asm), I just call it from the ISR.


Just a note on this: By default, P-Machinery calls the assigned input processor for the current state on the "idle" task (when the queue is empty).

When I say "by default," I mean that's how it was written. Since the game loop is intended to run once per ISR, this resulted in at least 60 Hz resolution in the worse case scenario, and a much higher resolution in the normal cases. For twitchy arcade games like Pac-Man and Christmas Carol, this was a good thing.

I don't expect it should be such a big deal to change this to call the input processor at the end of the game loop from the ISR.

-dZ.

#220 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 1:04 PM


It wouldn't be hard to replace my keyscan with your ECS keyboard event generator. Just have the event handler call "putkey" for each keydown event.


I guess I'm muddling the waters by using terms that collide with yours. Your "getkey" function is the one that fetches from the buffer, right? My "getkey" function (which I admit is probably a misnomer) is the one that polls the controller.

In your scenario, it'll also write into the typeahead buffer, so it would be your "keyscan" routine.

If I understand your approach, the controller model should be different from the keyboard model, because both use cases are different. The former is event based, and the latter depends on a typeahead buffer that needs to get read (and thus, flushed) by the game periodically.

Is this right?


It's not hard to adapt to the event-based model. It is, in effect, what I have now, I've just short circuited the event queue. If you've already got an input event generator, then the keydown event handler for both the controller keypad and the ECS keyboard are pretty much identical. Both will (usually) result in one or more calls to "putkey" to insert keystrokes into my typeahead buffer.

I say "usually" because Valter does want to use certain keypad inputs for non-keystroke things, but that's OK. We may even want ECS keyboard bindings for special actions too. So really, the use model for both the keypad and keyboard are more similar than different.

So yeah, you can replace keyscan with whatever you had in mind for ECS keyboard scanning, and just register a keyboard event handler which looks almost identical (and may even share 99% of the code with) the keypad event handler I have above.

#221 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 1:07 PM


For the ECS keyboard, I'm expecting something to call "keyscan" periodically to scan the ECS keyboard and drop keystrokes into my typeahead buffer. The rest of the game calls "getkey" which consumes from that buffer. (I also just modified getkey to pump keyscan if the keyboard buffer is empty.) I'd suggest keyscan get called, say, once per frame. In my simple driver program (adv.asm), I just call it from the ISR.


Just a note on this: By default, P-Machinery calls the assigned input processor for the current state on the "idle" task (when the queue is empty).

When I say "by default," I mean that's how it was written. Since the game loop is intended to run once per ISR, this resulted in at least 60 Hz resolution in the worse case scenario, and a much higher resolution in the normal cases. For twitchy arcade games like Pac-Man and Christmas Carol, this was a good thing.

I don't expect it should be such a big deal to change this to call the input processor at the end of the game loop from the ISR.

-dZ.


One downside of the "yield" strategy is that the task queue is never actually empty, since it always immediately queues a "resume" task before returning to RUNQ. I guess a yield should also trigger the idle tasks to run? That should be easy enough. Instead of returning to RUNQ.loop, it can return to RUNQ.bktsk.

#222 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 1:10 PM



For the ECS keyboard, I'm expecting something to call "keyscan" periodically to scan the ECS keyboard and drop keystrokes into my typeahead buffer. The rest of the game calls "getkey" which consumes from that buffer. (I also just modified getkey to pump keyscan if the keyboard buffer is empty.) I'd suggest keyscan get called, say, once per frame. In my simple driver program (adv.asm), I just call it from the ISR.


Just a note on this: By default, P-Machinery calls the assigned input processor for the current state on the "idle" task (when the queue is empty).

When I say "by default," I mean that's how it was written. Since the game loop is intended to run once per ISR, this resulted in at least 60 Hz resolution in the worse case scenario, and a much higher resolution in the normal cases. For twitchy arcade games like Pac-Man and Christmas Carol, this was a good thing.

I don't expect it should be such a big deal to change this to call the input processor at the end of the game loop from the ISR.

-dZ.


One downside of the "yield" strategy is that the task queue is never actually empty, since it always immediately queues a "resume" task before returning to RUNQ. I guess a yield should also trigger the idle tasks to run? That should be easy enough. Instead of returning to RUNQ.loop, it can return to RUNQ.bktsk.


Of course, if I do that, I'll have to take this out of yield:
            MVI     TSKQHD,         R0
            CMP     TSKQTL,         R0
            BNEQ    @@doit
            JR      R5
That short-circuits the yield if no other task has been queued.

See, while 'process' is running, the queue will be empty, sure, but it always re-queues itself before returnning, so RUNQ never sees the queue empty. :-)

#223 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 5,364 posts
  • Ranger Elf: Saviour of Christmas!
  • Location:NC, USA

Posted Tue Feb 28, 2012 1:16 PM




For the ECS keyboard, I'm expecting something to call "keyscan" periodically to scan the ECS keyboard and drop keystrokes into my typeahead buffer. The rest of the game calls "getkey" which consumes from that buffer. (I also just modified getkey to pump keyscan if the keyboard buffer is empty.) I'd suggest keyscan get called, say, once per frame. In my simple driver program (adv.asm), I just call it from the ISR.


Just a note on this: By default, P-Machinery calls the assigned input processor for the current state on the "idle" task (when the queue is empty).

When I say "by default," I mean that's how it was written. Since the game loop is intended to run once per ISR, this resulted in at least 60 Hz resolution in the worse case scenario, and a much higher resolution in the normal cases. For twitchy arcade games like Pac-Man and Christmas Carol, this was a good thing.

I don't expect it should be such a big deal to change this to call the input processor at the end of the game loop from the ISR.

-dZ.


One downside of the "yield" strategy is that the task queue is never actually empty, since it always immediately queues a "resume" task before returning to RUNQ. I guess a yield should also trigger the idle tasks to run? That should be easy enough. Instead of returning to RUNQ.loop, it can return to RUNQ.bktsk.


Of course, if I do that, I'll have to take this out of yield:
			MVI	 TSKQHD,		 R0
			CMP	 TSKQTL,		 R0
			BNEQ	@@doit
			JR	  R5
That short-circuits the yield if no other task has been queued.

See, while 'process' is running, the queue will be empty, sure, but it always re-queues itself before returnning, so RUNQ never sees the queue empty. :-)


I get it. The queue is not really empty from the RUNQ perspective, but yield calls the idle task before queueing itself.

I wonder if it'll be better if P-Machinery were to just queue the input processor at the bottom of the state ISR, like it does with DOTIMER()...

Your thoughts?

#224 intvnut ONLINE  

intvnut

    Stargunner

  • 1,425 posts
  • Location:@R6 (top of stack)

Posted Tue Feb 28, 2012 1:16 PM

Ok... minor update to the code, and a neat GIF.

Attached Thumbnails

  • scrollback.gif

Attached Files



#225 DZ-Jay OFFLINE  

DZ-Jay

    Quadrunner

  • 5,364 posts
  • Ranger Elf: Saviour of Christmas!
  • Location:NC, USA

Posted Tue Feb 28, 2012 1:17 PM

Ok... minor update to the code, and a neat GIF.


Wow! NIFTY INDEED! :)




0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users