Making a Game Server

Given what we're learned so far, we're ready to make a small process "server" that will hold our game's state. We can then send messages to it that will execute the functions we've defined. Here's a list of the commands we need to support in order to play the game:

  • look
  • walk (we'll use "go" instead)
  • pickup (we'll use "take" instead)
  • inv
  • weld
  • dunk
  • splash

Assuming that you've already defined the variables in this function, you can create a game-state initializer like so:

(defun init-state ()
  (make-state
    objects objects
    places (list living-room garden attic netherworld)
    player-location 'living-room
    goals goals))

There's one more thing we can do, though: take pity on the overly-curious and inclined-to-steal-frogs. Let's make sure that a player who takes too strong an interest in making new amphibian friends can amend their ways:

(defun spell-of-mercy ()
  (timer:sleep 2000)
  (io:format (++ "~nFrom deep in the mists, you hear a familiar intonation ...~n"
                 "Great relief washes over you, as you recognize the "
                 "time-travel spell -- you're~nnot doomed!~n~n"))
  (timer:sleep 4000)
  (io:format (++ "Confident that you will never pick up the frog again, "
                 "things get a bit fuzzy.~nYou start to lose consciousness"
                 "as the wizard pulls you back in time. Your~nlast thought is "
                 "that you're probably not going to remember any of this "
                 "...~n~n"))
  (timer:sleep 4000)
  (let ((state (init-state)))
    (display-scene state)
    state))

Now we can create our state holder "server":

(defun loop-server (state)
  (receive
    (`#(look)
      (display-scene state)
      (case (state-player-location state)
        ('netherworld (loop-server (hope-for-mercy state)))
        (_ (loop-server state))))
    (`#(exits)
      (display-exits state)
      (loop-server state))
    (`#(go ,direction)
      (loop-server (walk-direction direction state)))
    (`#(take ,item)
      (loop-server (pickup-item item state)))
    (`#(inv)
      (display-inv state)
      (loop-server state))
    (`#(weld ,subj ,obj)
      (loop-server (do-weld subj obj state)))
    (`#(dunk ,subj ,obj)
      (loop-server (do-dunk subj obj state)))
    (`#(splash ,subj ,obj)
      (loop-server (do-splash subj obj state)))))

(defun loop-server ()
  (loop-server (init-state)))
(defun start ()
  (case (whereis 'game-server)
    ('undefined
      (let ((server-pid (spawn #'loop-server/0)))
        (register 'game-server server-pid)
        '#(status started)))
    (_ '#(status already-started))))

(defun stop
  (('undefined _)
    '#(status already-stopped))
  ((pid msg)
    (exit pid msg)
    `#(status ,msg)))

(defun stop ()
  (stop (whereis 'game-server) 'game-over))

Start up your new game server!

> (start)
#(status started)

Try starting (again), stopping and restarting:

> (start)
#(status already-started)
> (stop)
#(status game-over)
> (stop)
#(status already-stopped)
> (start)
#(status started)

Next, we can cast some new SPELs for use with our server ...