! Multiplayer Inform stub file
! for use with ifMUD's Floyd

! this file by Adam Cadre
! multiplayer Inform developed by Adam Cadre and Evin Robertson
! Floyd created by Evin Robertson
! Inform created by Graham Nelson

! As of this writing (07 March 1999), ifMUD's interpreter-bot Floyd is
! equipped to run multiplayer games.  This file is a starting point for
! coding them.  There are a few differences from single-player IF to keep
! in mind.  Chief among these is that all input to the game, such as DO
! THIS, is translated into the form, SPEAKER, DO THIS.  This means that
! the responses to verbs should be placed into the 'orders' block of the
! Newplayer class.  Also, whispering output to a particular player is done
! through HTML-style tags, such as: "<WHISPER SPEAKER>You can't see any such
! thing.</WHISPER>".

Constant Story "[insert name of game here]";
Constant Headline "^[insert other headers here]";

Include "Parser";

Object LibraryMessages
  with before [;
     Prompt: rtrue;   ! Multiplayer games, especially those involving
                      ! whispering, will probably not want to offer a
                      ! prompt. If you'd like a prompt, simply delete
                      ! or comment out this line.

     Miscellany:   ! These lines run on top of the "You seem to want to
                   ! talk to someone, but I can't see whom" message. If
                   ! you would like to add more verbs that people not in
                   ! the game can use, add them.

        if (lm_n==23) {
           if ((parse+2)-->4 == 'join') Addplayer();
           else if ((parse+2)-->4 == 'who') Listplayers();
           else if ((parse+2)-->4 == 'quit') quit;
           else "You must be a player to enter a command.";
        }
        rtrue;
  ];

Include "Verblib";

Array text_buffer -> 16;
Global the_named_word = 0;
Global from_char; Global to_char;

Global game_on;     ! This flag goes up when the joining phase is complete.

Attribute ingame;   ! This is an attribute given to each player in the game
                   ! upon joining. Objectloops through the player list should
                   ! be on (x has ingame), since (x ofclass Newplayer) will
                   ! include blank players, and (x in gameroom) will include
                   ! "yourself".

Class Newplayer(20)   ! If you need more than twenty players -- or want a
                     ! lower maximum -- change this.
  with number 0 0 0 0 0 0 0 0,
     description "A player not unlike yourself.",
     parse_name [i j flag;
        if (parser_action==##TheSame) {
           for (i=0:i<16:i++) {
              if ((parser_one.&number)->i ~= (parser_two.&number)->i)
                 return -2;
           }
           return -1;
        }
        for (::i++) {
           j=NextWord(); flag=0;
           if (flag==0 && ((self.&number)->0) ~= 0) {
              wn--;
              if (TextReader(0)==0) return i;
              for (j=0: j<16: j++)
                 if ((self.&number)->j ~= text_buffer->j) return i;
                 flag=1;
              }
              if (flag==0) return i;
           }
     ],
     short_name [i;
        while (((self.&number)->i) ~= 0) print (char) (self.&number)->i++;
        rtrue;
     ],
     create [i;
        wn = the_named_word;
        if (TextReader(1)==0) return i;
        for (i=0: i<16: i++) {
           (self.&number)->i = text_buffer->i;
        }
     ],
     orders [a y ct;
        Who: Listplayers(); rtrue;

        Join:    ! If the game recognizes the player well enough to pass it
                 ! here, then that player has by definition already joined.
           print_ret (name) self, " is already a player.";

        Begin:   ! Note that the following demonstrates how to code whispers
                 ! to players. print_ret and print-less strings should not
                 ! be used, as that will make Floyd output blank lines.
           if (game_on) {
              print "<whisper ", (name) self, ">The game has already
                 begun!</whisper>"; rtrue;
           }
           game_on = 1; Startgame(); rtrue;

        Leave:
           if (game_on) {
              print "<whisper ", (name) self, ">Sorry! Can't leave while
                 a game is in progress!</whisper>"; rtrue;
           }
           remove self; give self ~ingame; players--;
           print (name) self, " deleted! Current players: ";
           objectloop (y has ingame) print (name) y, " ";
           new_line; rtrue;

        MyQuit: quit;

        NotUnderstood: print "<whisper ", (name) self, ">I don't understand
                          that.</whisper>"; rtrue;
        default: print "<whisper ", (name) self, ">I can't do that, ",
                    (name) self, ".</whisper>"; rtrue;
     ],
  has animate neuter proper;

[ TextReader flag point i j len;

  if (flag==1 && from_char~=to_char)
  {   for (i=from_char, j=0:i<=to_char && j<15:i++)
      {   text_buffer->j = buffer->i;
          if (buffer->i ~= ' ' or ',' or '.') j++;
      }
      for (:j<16:j++) text_buffer->j = 0;
      from_char=0; to_char=0;
      rtrue;
  }

  for (i=0:i<16:i++) text_buffer->i = 0;
  if (wn > parse->1) { wn++; rfalse; }
  i=wn*4+1; j=parse->i; point=j+buffer; len=parse->(i-1);

  for (i=0:i<len && i<15:i++) text_buffer->i = point->i;

  wn++; rtrue;
];

Object gameroom "Waiting for players to join"
  with article "the",
     description "WHO: Who's already playing?^
                  JOIN: Add me to the list of players!^
                  LEAVE: Scratch me from the list of players!^
                  BEGIN: Everyone has arrived! Let's play!^
                  QUIT: Let's not play after all!",
  has light;

[ Initialise;
  location = gameroom;

  !!! print out your credits in here somewhere

  return(2);
];

Include "Grammar";

[ AnyWord; from_char=0; to_char=0; the_named_word=wn++; ];

[ Addplayer x y;
  if (game_on)
     "New players may not join while a game is in progress. Sorry!";
  from_char = 0; to_char = 0; the_named_word = 1;
  x = Newplayer.create(); if (x ~= nothing) move x to gameroom;
     else "Sorry, too many players have been created.";
  print (name) x, " added! Current players: "; players++; give x ingame;
  objectloop (y has ingame) print (name) y, " ";
  new_line; rtrue;
];

[ Listplayers a b;
  print "Current players: ";
  objectloop (a has ingame) { print (name) a, " "; b = 1; }
  if (~~b) print "NONE";
  new_line; rtrue;
];

[ Startgame;

  ! Insert the beginning of your game loop here.

];

[ WhoSub; "WHO must come from a person."; ];
Verb 'who'
  *         -> Who;

[ JoinSub; "JOIN must come from a person."; ];
Verb 'join'
  * AnyWord -> Join;

[ LeaveSub; "LEAVE must come from a player."; ];
Verb 'leave'
  *         -> Leave;

[ BeginSub; "BEGIN must come from a player."; ];
Verb 'begin'
  *         -> Begin;

[ MyQuitSub; "QUIT must come from a person."; ];
Verb 'quit'
  *         -> MyQuit;