TGC Codebase Backup



Simple Chat to Demonstrate Using Multiplayer Commands by Fluffy Paul

30th Jul 2004 5:42
Summary

A very simple chat program that highlights the use of multiplayer commands to start or connect to a game and send messages.



Description

This program was initially supposed to demonstrate the multiplayer commands but evolved into a really simple chat program. The idea was NOT to make a chat program - that's just what it ended up being.

The code is heavily commented to explain what all the code *ought* to be doing. In case there's too many comments to read, these 6 variables control the important stuff:

connection=0
connection$=""
host$=""
playername$=""
netsession=0
netsession$=""


The important stuff being:

set net connection connection, host$
select action$
case "START" : create net game netsession$, playername$, 16, 1 : endcase
case "FIND" : join net game netsession, playername$ : endcase
endselect

Please note that action$ is a string just to make things more obvious to a reader of the demo program. You might want to change this to a numerical constant or something if you're doing it for real. It's simply used to make the program switch between the mode where it starts a new game and where it looks for an existing game. The difference is subtle but important. When starting a game you use netsession$ - a string containing the name of the game. When looking for a game you use netsession - an INTEGER which is the position in a list of sessions where the game you want to join is.



Code
                                    ` This code was downloaded from The Game Creators
                                    ` It is reproduced here with full permission
                                    ` http://www.thegamecreators.com
                                    
                                    rem Title   : Simple Multiplayer Demo
rem Project : mpdemo.dbpro
rem Source  : mpdemo.dba
rem Author  : Paul "Fluffy" Morgan
rem Purpose : To demonstrate use of multiplayer commands.
rem Comments: For everyone! Use as you see fit. Get in touch via the forums if you have questions.

rem Disable escape so we can exit in a controlled manner, otherwise we might break the network!
disable escapekey

set text font "Tahoma"
set text size 12

maxPlayers = 8
Dim players$(maxPlayers)

rem Define an array to record key presses so we can monitor user input.
dim key$(1)

rem The player list and the chat space can't overlap, but we don't want them pushing
rem each other off the screen so the chat space resizes itself depending on how many
rem players we're showing.
dim chatlines$(28 - maxPlayers)
chatflag$=""
latestline=0
action$=""

rem These 6 are the important variables used to make and find games
connection=0
connection$=""
host$=""
playername$=""
netsession=0
netsession$=""

rem Ask the user if they're starting or finding a session as this changes things later
while action$ = ""
   cls
   update_keystate()
   text 0, 15, "Press 1 if you want to start a new session or 2 if you want to find an existing session."

   rem Check for key-ups. See the comments in the update_keystate() function.
   select key$(1)
      case "1" : action$ = "START" : text 0, 30, "Checking for connections..." :endcase
      case "2" : action$ = "FIND" : text 0, 30, "Checking for connections...": endcase
   endselect
   if escapekey()=1 then end
endwhile

rem Get the list of available connection types from the OS
perform checklist for net connections

rem The connection selection screen. Usually would need TCP/IP but might get
rem used for other things.
while connection$ = ""
   cls
   update_keystate()
   text 0, 15, "Please select a connection to use: "

   rem Get DB to print out the list of connection types.
   for n=1 to checklist quantity()
      output$ = str$(n) + ": "
      output$ = output$ + checklist string$(n)
      text 0, (n*15)+15, output$
   next n

   rem Check for the user pressing a key.
   if val(key$(1)) > 0 and checklist quantity() > 0 and val(key$(1)) <= checklist quantity()
      connection = val(key$(1))
      connection$ = checklist string$(connection)
   endif
   if escapekey()=1 then end
endwhile

rem   Now we need the IP or hostname of the computer running the game.
rem   If you're using the "session_finder" companion program then you
rem   need to type the same IP or host name there as was typed here.
while host$ = ""
   cls
   update_keystate()
   text 0, 15, "Using " + connection$
   gosub _handle_chat_key_input
   text 0, 30, "Please enter your host name or IP address: " + chatline$

   rem take the user-entered chatline$ and store it in a variable called host$
   if chatflag$ = "DONE"
      host$ = chatline$
      text 0, 45, "Attempting to open session on " + host$ + " - please wait a moment..."
   endif
   if escapekey()=1 then end
endwhile

set net connection connection, host$

Rem The net game needs a name
while playername$ = ""
   cls
   update_keystate()
   text 0, 15, "Using " + connection$ + " on " + host$
   gosub _handle_chat_key_input
   text 0, 30, "Please enter the name you wish to use: " + chatline$

   rem take the user-entered chatline$ and store it in a variable called session$
   if chatflag$ = "DONE"
      playername$ = chatline$
   endif
   if escapekey()=1 then end
endwhile

select action$
   case "START"
      Rem The net game needs a name
      while netsession$ = ""
         cls
         update_keystate()
         text 0, 15, "Using " + connection$ + " on " + host$ + " as " + playername$
         gosub _handle_chat_key_input
         text 0, 30, "Please enter a name for your session: " + chatline$

         rem take the user-entered chatline$ and store it in a variable called session$
         if chatflag$ = "DONE"
            netsession$ = chatline$
            text 0, 45, "Attempting to start session on " + netsession$ + " - please wait a moment..."
         endif
      endwhile

      if escapekey()=1 then end
      create net game netsession$, playername$, 16, 1
   endcase

   case "FIND"
      Rem Look for sessions on the host and make a list.
      empty checklist
      perform checklist for net sessions

      if checklist quantity()=0
         text 0, 15, "Using " + connection$ + " on " + host$ + " as " + playername$
         text 0, 45, "NO SESSIONS FOUND. Press any key to exit..."
         wait key
         end
      endif

      while netsession$ = ""
         cls
         update_keystate()
         text 0, 15, "Using " + connection$ + " on " + host$ + " as " + playername$
         text 0, 30, "Please select a session to join: "

         rem Print the list of sessions out
         for n=1 to checklist quantity()
            output$ = str$(n) + ": " + checklist string$(n)
            text 0, (n*15)+30, output$
         next n

         rem Check for key presses that match up to a checklist item
         if val(key$(1)) > 0 and checklist quantity() > 0 and val(key$(1)) <= checklist quantity()
            netsession = val( key$(1) )
            netsession$ = checklist string$(netsession)
            temp$ = str$(netsession) + ": " + checklist string$(netsession)
            text text width(temp$),30+netsession*15," - CONNECTING..."
         endif
      endwhile

      if escapekey()=1 then end
      join net game netsession, playername$
   endcase
endselect

rem note the difference in the netsession variable.
rem To create a game it's a string and to join a game it's an integer!

gosub _make_list_of_players
if checklist quantity()=0
   rem If there are no players then we didn't make/join successfully.
   text 0, 15, "Using " + connection$ + " on " + host$ + " as " + playername$
   text 0, 45, "FAILED TO " + action$ + " GAME. Press any key to exit..."
   wait key
   end
endif

do
   cls
   update_keystate()

   rem Report continuously on other players connected to the game.
   gosub _show_connection_and_players

   rem Read the keybaord input and send it out as a chat line where necessary
   gosub _handle_chat_key_input
   gosub _handle_sending_chatline

   rem Show chat line as user types it (chatline$ is use in _handle_chat_key_input)
   chatlinebase = endofplayerlist + 15

   rem Draw some lines around the chat area to make it a bit more obvious
   gosub _draw_chat_box
   text 0, chatlinebase, " SEND:" + chatline$

   gosub _handle_chat_net_input

   chatbase = chatlinebase + 15
   gosub _show_chat

   rem Print out the total count of messages sent and received in the bottom right
   rem corner of the screen.
   text screen width() - 1 - text width("Sent: " + str$(msgoutcount)), screen height() - 30, "Sent: " + str$(msgoutcount)
   text screen width() - 1 - text width("Received: " + str$(msgincount)), screen height() - 15, "Recieved: " + str$(msgincount)
   if escapekey()=1 then free net game : exit
loop

end

_make_list_of_players:
   rem Prepare the player checklist
   empty checklist
   perform checklist for net players

   rem Clear out the old data
   for n=1 to maxPlayers
      players$(n) = "<none>"
   next n

   rem Bring in the new data
   for n=1 to checklist quantity()
      players$(checklist value a(n)) = checklist string$(n)
   next n
return

_show_connection_and_players:
   rem If a player joins or leaves then re-make our list of players as there's no
   rem multiplayer command that asks them for their name.
   if net player created() > 0 or net player destroyed() > 0
      gosub _make_list_of_players
   endif

   text 0, 15, "Using " + connection$ + " on " + host$ + " in " + netsession$ + " as " + playername$
   text 0, 30, "Players Found: "

   rem loop through the list of players, printing them to the screen along with their player number.
   for n=1 to array count( players$(0))
      output$ = str$(n) + ": " + players$(n)
      text 0, (n*15)+30, output$
      endofplayerlist = (n*15)+30
   next n
return

_handle_chat_key_input:
   rem Reset the flag and clear the input line.
   if chatflag$="DONE" then chatflag$="" : chatline$=""

   rem If a key is pressed
   if key$(1)<>""
      rem Did the user press backspace? (ascii 8)
      if asc( key$(1) )=8
         rem backspace - chop off the character at the end of the line
         chatline$ = left$( chatline$, len(chatline$)-1)
      else
         rem did the user hit return? (ascii 13)
         if asc( key$(1) )=13
            rem Yep - they hit return.
            rem Mark the chat line as being DONE and ready for sending.
            chatflag$="DONE"
         else
            rem add anything else the user types to the chat line
            chatline$ = chatline$ + key$(1)
         endif
      endif
   endif
return

_handle_sending_chatline:
   if chatflag$="DONE"
      rem send out our chat line
      send net message string 0, chatline$

      rem Update the currentmessage$ variable for use with the subroutine.
      rem Add our own name to the line for our own benefit.
      currentmessage$ = playername$ + ": " + chatline$

      rem we won't receive our chat message over te network so we have to "cheat" and add
      rem it to our chat array manually.
      gosub _add_current_message_to_chat

      rem update our counter
      msgoutcount = msgoutcount+1
   endif
return

_draw_chat_box:
   rem Top of box
   line 0, chatlinebase, screen width()-1, chatlinebase

   rem Left side of box
   line 0, chatlinebase, 0, chatlinebase+15

   rem Right side of box
   line screen width()-1, chatlinebase, screen width()-1, chatlinebase+15

   rem Bottom of box
   line 0, chatlinebase+15, screen width()-1, chatlinebase+15
return

_handle_chat_net_input:
   rem get net message tells DB what the next message is.
   get net message

   rem Now we ask DB if there is a message waiting for us or not.
   while net message exists() > 0

      rem We have a message. This is a chat program so it better be a string (message type 3).
      if net message type()=3
         rem it's a string so find out who it's from and add this data to the chat area.
         currentmessage$ = players$(net message player from()) + ": " + net message string$()
         gosub _add_current_message_to_chat
      endif

      rem Update the counter for posterity.
      msgincount = msgincount+1

      rem now that we've sorted that message out, let's see if there's another one.
      get net message
   endwhile
return

_show_chat:
   rem Go through all the chat lines we've recorded and print them out to the screen.
   rem Have to do it backwards, though, so the newest one appears at the bottom of the screen.
   for n = 0 to array count(chatlines$(0))-1
      thisline = latestline-n

      rem check to make sure we wrap around to the end of the array if we count backwards
      rem past the beginning.
      if thisline < 1 then thisline = array count(chatlines$(0)) + thisline
      text 0, chatbase+15*array count(chatlines$(0))-((n+1)*15), chatlines$(thisline)
   next n
return

_add_current_message_to_chat:
   rem Move along to the next slot in our message array
   latestline = latestline+1

   rem Make sure we wrap around to the start if we count past the end of the array.
   if latestline > array count(chatlines$(0)) then latestline = 1

   rem Overwrite whatever is here with the current message.
   chatlines$(latestline)=currentmessage$
return


function update_keystate()
   remstart
      A very simple way of detecting when a key is pressed and when it's released.
      key$(0) represents a "key down" i.e. when a key is pressed.
      key$(1) represents a "key up" i.e. when a key is released.
      If key$(1) isn't empty then it's equal to a key that's just been released.
      We use this to determine what the user is typing so that we don't pause the
      program with an INPUT command.
      If we used the letter that was currently being pressed then we would get one
      letter for every frame per second.
   remend

   key$(1)=""

   if key$(0) <> inkey$()
      key$(1) = key$(0)
   endif

   key$(0)=inkey$()
endfunction