home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 20 / AACD20.BIN / AACD / Programming / AmiSlate-Source / SlateRexx / checkers.rexx < prev    next >
Encoding:
OS/2 REXX Batch file  |  1995-12-21  |  17.7 KB  |  643 lines

  1. /* Checkers for AmiSlate v1.0! */
  2. /* This program should be run on a screen with at least 4 colors */
  3.  
  4. /* Get our host's name--always given as first argument when run from Amislate */
  5. parse arg CommandPort ActiveString
  6.  
  7. if (length(CommandPort) == 0) then do
  8.     say ""
  9.     say "Usage:  rx checkers.rexx <REXXPORTNAME>"
  10.     say "        (REXXPORTNAME is usually AMISLATE)"
  11.     say ""
  12.     say "Or run from the Rexx menu within AmiSlate."
  13.     say ""
  14.     exit 0
  15.     end
  16.     
  17. /* Send all commands to this host */
  18. address (CommandPort) 
  19. options results
  20.  
  21. lock ON
  22.  
  23. /* See if we're connected */
  24. GetRemoteStateAttrs stem rstateattrs.
  25. if (rstateattrs.mode > -1) then do
  26.         /* Parse command line argument to see if we've been activated by 
  27.            a remote request or a local user */
  28.         check = upper(left(ActiveString,3))
  29.         if (upper(left(ActiveString,3)) ~= 'RE') then 
  30.             GlobData.localplayer = 1
  31.         else
  32.             GlobData.localplayer = -1
  33.         end
  34.     else do
  35.         GlobData.localplayer = 0    /* i.e. we're both players */
  36.         end
  37.         
  38. if (GlobData.localplayer > 0) then do
  39.     call SetStatus("Requesting game from remote user... please wait.")
  40.     RemoteRexxCommand '"'||"Would you like to play Checkers?"||'"' "slaterexx:Checkers.rexx"
  41.     
  42.         waitevent stem handshake. MESSAGE
  43.         if (handshake.message == 0) then 
  44.         do
  45.             call SetStatus("Checkers Game Refused")
  46.             lock off
  47.             exit 0
  48.         end
  49.     end
  50.  
  51. call SetStatus("Beginning Checkers...")
  52.  
  53. call ResetGameState
  54. call SetGlobalData
  55. if (GlobData.localplayer >= 0) then call DrawBoard
  56.  
  57. call NextTurn
  58. call HandleEvents
  59.  
  60. lock OFF
  61. exit 0
  62.  
  63. /* Global Data structure:
  64.  
  65.     GlobData.Xspace.[step] (int)     : horizontal pixel offsets to the center of each coord (0-16)
  66.     GlobData.XSize    (int)         : total width of each element
  67.     GlobData.Yspace.[step] (int)     : vertical pixel offsets to the center of each coord (0-16)
  68.     GlobData.YSize    (int)         : total height of each element
  69.  
  70.     (board state)
  71.     GlobData.board.[0..8].[0..8]     : two-dimensional board array
  72.     
  73.     (game state)
  74.     GlobData.turn             : whose turn it is
  75.     GlobData.localplayer              : which player is on local machine; 0 if both are
  76.  
  77.      (color info)
  78.     GlobData.PieceColor.[playernum]  : color of pieces for this player
  79.  
  80. */
  81.  
  82. /* --------------------------------------------------------------- */
  83. /* procedure HandleEvents                        */
  84. /* --------------------------------------------------------------- */
  85. HandleEvents: procedure expose GlobData. AMessage.
  86.  
  87. AMessage.TIMEOUT     = 1    /* No events occurred in specified time period */
  88. AMessage.MESSAGE     = 2    /* Message recieved from remote Amiga */
  89. AMessage.MOUSEDOWN   = 4    /* Left mouse button press in drawing area */
  90. AMessage.MOUSEUP     = 8    /* Left mouse button release in drawing area */
  91. AMessage.RESIZE      = 16    /* Window was resized--time to redraw screen? */ 
  92. AMessage.QUIT        = 32    /* AmiSlate is shutting down */
  93. AMessage.CONNECT     = 64    /* Connection established */
  94. AMessage.DISCONNECT  = 128    /* Connection broken */
  95. AMessage.TOOLSELECT  = 256    /* Tool Selected */
  96. AMessage.COLORSELECT = 512    /* Palette Color selected */
  97. AMessage.KEYPRESS    = 1024    /* Key pressed */
  98. AMessage.MOUSEMOVE   = 2048     /* Mouse was moved */
  99.  
  100. fromx = -1
  101. fromy = -1
  102. jumponlymode = 0
  103.  
  104. do while(1)
  105.     waitevent stem event. RESIZE MOUSEDOWN MOUSEUP TOOLSELECT MESSAGE DISCONNECT
  106.  
  107.     if (event.type == AMessage.QUIT) then exit 0
  108.     
  109.     if (event.type == AMessage.DISCONNECT) then do
  110.         call SetStatus("Connection broken--both players now local.")
  111.         GlobData.localplayer = 0
  112.         end
  113.    
  114.     if (event.type == AMessage.MESSAGE) then do
  115.         parse var event.message fx fy tx ty
  116.         if (fx = -1) then 
  117.             call NextTurn
  118.         else 
  119.             call PlaceMove((fx+0), (fy+0), (tx+0), (ty+0), 0)  /* update our internals--the (+0) forces the vars back into numeric format */
  120.         end
  121.  
  122.     if (event.type == AMessage.RESIZE) then do
  123.         if ((GlobData.localplayer == GlobData.turn)|(GlobData.localplayer == 0)) then do
  124.             cturn = GlobData.turn
  125.             call SetGlobalData
  126.             call DrawBoard
  127.             call ColorBorder(GlobData.PieceColor.cturn)
  128.             call SetStatus("_LAST")
  129.         end
  130.         else do
  131.             /* else just update our internal vars */
  132.             call SetGlobalData
  133.             call SetStatus("_LAST")
  134.         end
  135.     end
  136.     
  137.     if ((event.type == AMessage.MOUSEDOWN)&((GlobData.turn = GlobData.localplayer)|(GlobData.localplayer == 0))) then do
  138.         whatclickedx = ChopRange(trunc((event.x-GlobData.BORDER_H)/(GlobData.XSize)),0,7)
  139.         whatclickedy = ChopRange(trunc((event.y-GlobData.BORDER_V)/(GlobData.YSize)),0,7)
  140.         if (fromx >= 0) then do
  141.             if ((whatclickedx == fromx)&(whatclickedy == fromy)) then do
  142.                 /* cancel that move! */
  143.                 call HilitePiece(fromx, fromy)
  144.                 fromx = -1
  145.                 fromy = -1
  146.                 if (jumponlymode > 0) then do
  147.                     /* that's all for the move then */
  148.                     jumponlymode = 0
  149.                     call NextTurn
  150.                     if (localplayer ~= 0) then call TransmitMove(-1, -1, -1, -1)
  151.                     end
  152.                 end
  153.             else do
  154.                 if (MoveOkay(fromx, fromy, whatclickedx, whatclickedy) == 1) then do
  155.                     if (localplayer ~= 0) then call TransmitMove(fromx, fromy, whatclickedx, whatclickedy)
  156.                     if (PlaceMove(fromx, fromy, whatclickedx, whatclickedy, 1) == 2) then do
  157.                         call HilitePiece(whatclickedx, whatclickedy)
  158.                         jumponlymode = jumponlymode + 1
  159.                         call TellExtraJump(jumponlymode)
  160.                         fromx = whatclickedx
  161.                         fromy = whatclickedy
  162.                         end
  163.                     else do
  164.                         if (localplayer ~= 0) then call TransmitMove(-1, -1, -1, -1)
  165.                         jumponlymode = 0
  166.                         call NextTurn
  167.                         fromx = -1
  168.                         fromy = -1
  169.                         end
  170.                     end 
  171.                     else DisplayBeep LOCAL
  172.                 end 
  173.             end
  174.         else do
  175.             if ((GlobData.board.whatclickedx.whatclickedy * GlobData.turn) > 0) then do
  176.                 fromx = whatclickedx
  177.                 fromy = whatclickedy
  178.                 call HilitePiece(fromx, fromy)
  179.                 end
  180.             end
  181.     end
  182.     end
  183.     return 1
  184.  
  185.  
  186. /* --------------------------------------------------------------- */
  187. /* procedure NextTurn                           */
  188. /*                                    */
  189. /* --------------------------------------------------------------- */
  190. NextTurn: procedure expose GlobData.
  191.     /* Swap turns */
  192.     GlobData.turn = -GlobData.turn
  193.  
  194.     negone = -1
  195.     player.1 = "Player 1"
  196.     player.negone = "Player 2"
  197.     cturn = GlobData.turn
  198.         
  199.     call SetStatus("Just a sec...")
  200.     if (GlobData.turn == GlobData.localplayer) then call ColorBorder(0)
  201.     
  202.     /* Check to see if the new player has a move available */
  203.     if (CanMove() == 0) then do
  204.         call SetStatus("Sorry, " || player.cturn || ", but you must forfeit your turn.")
  205.         call Delay(100)
  206.         if (localplayer ~= 0) then TransmitMove(-1,-1,-1,-1)
  207.         call NextTurn    /* recursive! :) */
  208.         return 1
  209.         end
  210.  
  211.     /* local game code */
  212.     if (Globdata.localplayer == 0) then do
  213.         call SetStatus(player.cturn || ", it's your turn to move a checker.")
  214.         call ColorBorder(GlobData.PieceColor.cturn)
  215.         return 1
  216.         end
  217.     
  218.     /* two machine game code */
  219.     if (GlobData.turn == GlobData.localplayer) then do
  220.         call SetStatus(player.cturn || ", it's your turn to move a checker.")
  221.         call ColorBorder(GlobData.PieceColor.cturn)
  222.         end    
  223.     else call SetStatus("Wait for other player to move.")    
  224.     return 1
  225.  
  226.  
  227. /* --------------------------------------------------------------- */
  228. /* procedure ColorBorder                       */
  229. /*                                    */
  230. /* Colors the border the color indicated in the param            */
  231. /*                                   */
  232. /* --------------------------------------------------------------- */
  233. ColorBorder: procedure expose GlobData.
  234.     parse arg color
  235.     
  236.     SetFPen color
  237.     
  238.     /* Fill each side of the border with a square */
  239.     /* rely on AmiSlate's clipping to deal with extra material */
  240.     square 0 0 10000 (GlobData.YSpace.0)-1 FILL
  241.     square 0 0 (GlobData.XSpace.0)-1 10000 FILL
  242.     square (GlobData.XSpace.8)+1 0 10000 10000 FILL
  243.     square 0 (GlobData.YSpace.8)+1 10000 10000 FILL
  244.     return 1
  245.     
  246.  
  247. /* --------------------------------------------------------------- */
  248. /* procedure CanMove                           */
  249. /*                                    */
  250. /* Returns 1 if there is a move available for the current player   */
  251. /* else 0                               */
  252. /*                                    */
  253. /* --------------------------------------------------------------- */
  254. CanMove: procedure expose GlobData.
  255.     
  256.     num1 = 0
  257.     num2 = 0
  258.     negone = -1
  259.     
  260.     return 1
  261.  
  262.  
  263. /* --------------------------------------------------------------- */
  264. /* procedure PieceCanJump                       */
  265. /*                                    */
  266. /* Returns 1 if there is a jump available for the piece at the     */
  267. /* give spot, else returns 0                        */
  268. /*                                    */
  269. /* --------------------------------------------------------------- */
  270. PieceCanJump: procedure expose GlobData.
  271.     parse arg fx, fy
  272.     
  273.     if (MoveOkay(fx,fy,fx+2,fy+2) == 1) then return 1
  274.     if (MoveOkay(fx,fy,fx-2,fy+2) == 1) then return 1
  275.     if (MoveOkay(fx,fy,fx+2,fy-2) == 1) then return 1
  276.     if (MoveOkay(fx,fy,fx-2,fy-2) == 1) then return 1
  277.     return 0
  278.     
  279.  
  280.  
  281. /* --------------------------------------------------------------- */
  282. /* procedure GameWon                           */
  283. /*                                    */
  284. /* displays a message saying who won, based on the arg, and exits. */
  285. /*                                   */
  286. /* --------------------------------------------------------------- */
  287. GameWon: procedure
  288.     parse arg winner
  289.     
  290.     if (winner == "Tie") then winstring = "The game ends in a tie."
  291.     else winstring = winner || " has won the game!"
  292.     
  293.     EasyRequest "Winner!" '"'||winstring||'"' "Okay"
  294.     call SetStatus("Game over.  Rerun script to play again.")
  295.     lock off
  296.     exit 0
  297.     
  298.  
  299. /* --------------------------------------------------------------- */
  300. /* procedure PlaceMove                           */
  301. /*                                    */
  302. /* does a move by placing a piece at (x,y) and turning over all    */
  303. /* appropriate pieces                           */
  304. /*                                   */
  305. /* returns 2 if the piece should be given the option of another    */
  306. /* jump after this one.                        */
  307. /*                                   */
  308. /* --------------------------------------------------------------- */
  309. PlaceMove: procedure expose GlobData.
  310.     parse arg fx, fy, tx, ty, draw
  311.     
  312.     negone = -1
  313.     piece = GlobData.board.fx.fy
  314.     GlobData.board.fx.fy = 0
  315.  
  316.     /* If it wasn't a king, check to see if it needs to be kinged */
  317.     if (((piece == 1)&(ty == 7))|((piece == -1)&(ty == 0))) then piece = piece * 2
  318.  
  319.     GlobData.board.tx.ty = piece
  320.  
  321.     if (draw == 1) then do
  322.         call DrawPiece(fx, fy)
  323.         call DrawPiece(tx, ty)
  324.         end
  325.     
  326.     /* check to see if it was a jump */
  327.     if (abs(tx-fx) > 1) then do
  328.         mx = (tx+fx)%2
  329.         my = (ty+fy)%2
  330.         GlobData.board.mx.my = 0
  331.         if (draw == 1) then call DrawPiece(mx, my)
  332.  
  333.         /* decrement appropriate piece-counter */
  334.         opponent = -GlobData.turn
  335.         GlobData.pieces.opponent = GlobData.pieces.opponent - 1
  336.  
  337.         /* check for a win */
  338.         if (GlobData.pieces.1 == 0) then do
  339.             call ColorBorder(GlobData.PieceColor.1)
  340.             call GameWon("Player 1")
  341.             end
  342.         else if (GlobData.pieces.negone == 0) then do
  343.             call ColorBorder(GlobData.PieceColor.negone)
  344.             call GameWon("Player 2")
  345.             end
  346.             
  347.         /* Can we jump again? */
  348.         if (PieceCanJump(tx,ty) == 1) then return 2
  349.         end
  350.     
  351.     return 1
  352.  
  353.  
  354. /* --------------------------------------------------------------- */
  355. /* procedure MoveOkay                           */
  356. /*                                    */
  357. /* returns 1 if move is acceptable, or -1 if it is illegal.       */
  358. /*                                    */
  359. /* --------------------------------------------------------------- */
  360. MoveOkay: procedure expose GlobData.
  361.     parse arg fx, fy, tx, ty
  362.  
  363.     negone = -1
  364.     
  365.     /* First rule: all moves on the board */
  366.     if ((fx < 0)|(fy < 0)|(fx > 7)|(fy > 7)|(tx < 0)|(ty < 0)|(tx > 7)|(ty > 7)) then return 0
  367.     
  368.     /* Must be moving our own piece */
  369.     if ((GlobData.board.fx.fy * GlobData.turn) <= 0) then return 0
  370.  
  371.     /* Place we move to must be empty */
  372.     if (GlobData.board.tx.ty ~= 0) then return 0
  373.     
  374.     /* If it is a regular piece, is it in the right direction? */
  375.     if (abs(GlobData.board.fx.fy) == 1) then do
  376.         if ((GlobData.turn == 1)&(fy > ty)) then return 0
  377.         if ((GlobData.turn == -1)&(fy < ty)) then return 0
  378.         end
  379.     
  380.     /* No moving too far! */
  381.     if (abs(tx-fx) > 2) then return 0
  382.     if (abs(ty-fy) > 2) then return 0
  383.     
  384.     /* must be diagonal */
  385.     if (abs(tx-fx) ~= abs(ty-fy)) then return 0
  386.     
  387.     /* If it is a jump, make sure there is someone there to jump */    
  388.     if (abs(tx-fx) > 1) then do
  389.         mx = (fx+tx)%2
  390.         my = (fy+ty)%2
  391.         if (GlobData.board.mx.my * GlobData.turn >= 0) then return 0
  392.         end
  393.                 
  394.     /* No move available */    
  395.     return 1
  396.     
  397.     
  398.  
  399. /* --------------------------------------------------------------- */
  400. /* procedure ResetGameState                       */
  401. /* --------------------------------------------------------------- */
  402. ResetGameState: procedure expose GlobData.
  403.     negone = -1;
  404.     
  405.     GlobData.turn = -1;
  406.     
  407.     /* first clear the board */
  408.     do i = 0 to 7
  409.         do j = 0 to 7
  410.             GlobData.board.i.j = 0
  411.         end
  412.     end
  413.  
  414.     /* then add in initial pieces --play on color 3 */
  415.     do i = 0 to 2
  416.         do j = 0 to 3
  417.             x = j*2
  418.             if (i==1) then x = x + 1
  419.             GlobData.board.x.i = 1
  420.             xx = 7 - x
  421.             yy = i + 5
  422.             GlobData.board.xx.yy = -1
  423.             end
  424.         end    
  425.     
  426.     GlobData.pieces.1 = 12
  427.     GlobData.pieces.negone = 12
  428.     
  429.     return 1
  430.  
  431. /* --------------------------------------------------------------- */
  432. /* procedure SetGlobalData                       */
  433. /* --------------------------------------------------------------- */
  434. SetGlobalData: procedure expose GlobData.
  435.     negone = -1
  436.     
  437.     /* constants */
  438.     GlobData.BORDER_H = 5
  439.     GlobData.BORDER_V = 10
  440.     
  441.     /* Check to see whether we are connected */
  442.        GetWindowAttrs stem winattrs.
  443.        BoardWidth = winattrs.width  - 58 - (GlobData.BORDER_H*2)
  444.        BoardHeight= winattrs.height - 55 - (GlobData.BORDER_V*2)
  445.  
  446.     /* Set up offsets */
  447.     DO i=0 to 8
  448.       GlobData.Xspace.i = trunc(BoardWidth  * i / 8) + GlobData.BORDER_H
  449.       GlobData.Yspace.i = trunc(BoardHeight * i / 8) + GlobData.BORDER_V
  450.       end
  451.  
  452.     GlobData.XSize = trunc(BoardWidth / 8)
  453.     GlobData.YSize = trunc(BoardHeight / 8)
  454.  
  455.        if (winattrs.depth < 2) then do
  456.         EasyRequest Checkers_Error '"'||"You need at least a 4-color screen to play Checkers!"||'"' '"'||"Abort Checkers"||'"'
  457.         call SetStatus("Checkers game exited.")
  458.         lock off
  459.         exit 0
  460.         end 
  461.  
  462.     GlobData.PieceColor.1 = 1
  463.     GlobData.PieceColor.negone = 2
  464.     GlobData.OutlineColor.1 = 2
  465.     GlobData.OutlineColor.negone = 1
  466.     return 1
  467.  
  468.  
  469. /* --------------------------------------------------------------- */
  470. /* procedure DrawBoard                                             */
  471. /* --------------------------------------------------------------- */
  472. DrawBoard: procedure expose GlobData.
  473.     SetFColor 0 0 0        /* Get a black pen */
  474.  
  475.     Clear
  476.  
  477.     SetWindowTitle '"' || "Hang on, drawing the board..." || '"'
  478.  
  479.     do i = 0 to 7
  480.         do j = 0 to 7
  481.             call DrawPiece(i,j)
  482.             end
  483.         end
  484.         
  485.     call SetStatus("_LAST")
  486.     return 1
  487.  
  488.  
  489. /* XORs the given piece */
  490. HiLitePiece: procedure expose GlobData.
  491.     parse arg xc, yc
  492.     
  493.     /* Draw the piece in the square on the LOWER RIGHT of this intersection */
  494.     cx = MidwayBetween(xc,xc+1,X)
  495.     cy = MidwayBetween(yc,yc+1,Y)    
  496.     circle cx cy trunc(GlobData.XSize/3) trunc(GlobData.YSize/3) FILL XOR
  497.     return 1
  498.  
  499.     
  500. /* Draws the piece listed at coords xc, yc */
  501. DrawPiece: procedure expose GlobData.
  502.     parse arg xc, yc
  503.  
  504.     isking = 0
  505.     piece = GlobData.board.xc.yc
  506.     
  507.     if (abs(piece) == 2) then do
  508.         piece = piece % 2
  509.         isking = 1
  510.         end
  511.         
  512.     /* Draw the square in the correct background color */
  513.     if ((xc//2) == (yc//2)) then 
  514.         SetFPen 3
  515.     else
  516.         SetFPen 0
  517.  
  518.     nx = xc + 1
  519.     ny = yc + 1        
  520.  
  521.     square GlobData.XSpace.xc+1 GlobData.YSpace.yc+1 GlobData.XSpace.nx-1 GlobData.YSpace.ny-1 FILL    
  522.  
  523.     SetFPen 1
  524.     square GlobData.XSpace.xc GlobData.YSpace.yc GlobData.XSpace.nx GlobData.YSpace.ny
  525.  
  526.     /* If there's no piece here, we're done */
  527.     if (piece == 0) then return 0
  528.     
  529.     /* Draw the piece in the square on the LOWER RIGHT of this intersection */
  530.     cx = MidwayBetween(xc,nx,X)
  531.     cy = MidwayBetween(yc,ny,Y)    
  532.     
  533.     SetFPen GlobData.PieceColor.piece
  534.     circle cx cy GlobData.XSize%3 GlobData.YSize%3 FILL
  535.     SetFPen GlobData.OutlineColor.piece
  536.     circle cx cy GlobData.XSize%3 GlobData.YSize%3 
  537.     
  538.     /* Draw a crown if it's a king */
  539.     if (isking == 1) then do
  540.         left  = cx - (GlobData.XSize%6)
  541.         right = cx + (GlobData.XSize%6)
  542.         top   = cy - (GlobData.YSize%6)
  543.         bottom= cy + (GlobData.YSize%6)
  544.         width = right - left
  545.         height= bottom - top
  546.         
  547.         /* Draw outline of crown */
  548.         penreset
  549.         pen left top
  550.         pen (left + (width%5)) bottom
  551.         pen (right - (width%5)) bottom
  552.         pen right top
  553.         pen (right - (width%3)) (top+(height%2))
  554.         pen (left + (width%2)) (top+(height%4))
  555.         pen (left + (width%3)) (top+(height%2))
  556.         pen left top
  557.         
  558.         /* fill it */
  559.         flood (left + (width%2)) (bottom-1)
  560.         
  561.         end
  562.     return 1
  563.  
  564.  
  565.  
  566. SetStatus: procedure
  567.     parse arg newstatus
  568.     
  569.     if (newstatus == "_LAST") then do
  570.         SetWindowTitle '"' || getclip("PrevString") || '"'
  571.         end
  572.     else do
  573.         call setclip("PrevString",newstatus)
  574.         SetWindowTitle '"' || newstatus || '"'
  575.     end
  576.     return 1
  577.     
  578.  
  579.     
  580.     
  581.     
  582.  
  583. /* Returns the point midway between two coords */
  584. MidWayBetween: procedure expose GlobData.
  585.     parse arg left, right, XorY
  586.  
  587.     if (XorY = X) then 
  588.         return trunc((GlobData.XSpace.left + GlobData.XSpace.right)/2)
  589.     else    
  590.         return trunc((GlobData.YSpace.left + GlobData.YSpace.right)/2)
  591.  
  592. ChopRange: procedure
  593.     parse arg myval, lo, hi
  594.     if (myval < lo) then return lo
  595.     if (myval > hi) then return hi
  596.     return myval
  597.     
  598.     
  599. /* --------------------------------------------------------------- */
  600. /* procedure CheckForWin                                           */
  601. /* --------------------------------------------------------------- */
  602. CheckForWin: procedure expose GlobData.
  603.     winner = nobody
  604.     negone = -1
  605.     
  606.     if (GlobData.exited.1 == 15) then winner = "Player 1"
  607.     else if (GlobData.exited.negone == 15) then winner = "Player 2"
  608.     
  609.     /* nobody one yet */
  610.     if (winner == nobody) then return 1
  611.     
  612.     EasyRequest "Winner!" '"'||winner||" has won the game!"||'"' "Okay"
  613.     call SetStatus("Game Over.  Rerun the script to play again.")
  614.     lock off
  615.     exit
  616.     return 0
  617.     
  618.         
  619. /* Transmit our move to our opponent */
  620. TransmitMove: procedure 
  621.     parse arg fx, fy, tx, ty
  622.     
  623.     sstring = '"' || fx || " " || fy || " " || tx || " " || ty || '"'
  624.     sendmessage sstring
  625.     return 1
  626.     
  627.  
  628.  
  629. TellExtraJump: procedure
  630.     parse arg jumpnum
  631.     
  632.     if (jumpnum == 1) then x = "double"
  633.     if (jumpnum == 2) then x = "triple"
  634.     if (jumpnum == 3) then x = "quadruple"
  635.     if (jumpnum == 4) then x = "quintuple"
  636.     if (jumpnum == 5) then x = "sextuple"
  637.     if (jumpnum == 6) then x = "septuple"
  638.     if (jumpnum == 7) then x = "octuple"
  639.     if (jumpnum >= 8) then x = "maliciously"
  640.     
  641.     call SetStatus("You may " || x || " jump if you wish.")
  642.     return 1
  643.