Skip to content

Tutorial 4

Alex May edited this page Mar 22, 2020 · 1 revision

Creating New Rooms

Rooms are just objects like everything else but we need some extra control to handle exits and travelling between them.

To store the exits between rooms, we shall add a new property to the Generic Room that we created in the previous tutorial:

;moo.system.room:propadd( "exits", {} )

We shall create a @dig verb that will allow us to easily make new rooms and link locations together:

@verbadd $generic_programmer:@dig any any any

Verb code:

if #moo.args ~= 1 and #moo.args ~= 3 then
   moo.notify( "Usage: @dig \"new room name\"" )
   moo.notify( "Usage: @dig <exit> to \"new room name\"" )
   moo.notify( "Usage: @dig <exit> to <room>" )
   return
end

local RoomName = ""
local RoomObject = nil
local ExitSpec = ""

if #moo.args == 1 then
   RoomName = moo.args[ 1 ]

   RoomObject = moo.create( moo.system.room )

   if RoomObject == nil then
      moo.notify( "Unable to create room" )
   else
      RoomObject.name = RoomName

      moo.notify( "Created room \"" .. RoomName .. "\" (#" .. RoomObject.id .. ")" )
   end

   return
end

ExitSpec = moo.args[ 1 ]

RoomName = moo.args[ 3 ]

RoomObject = moo.find( RoomName )

if RoomObject == nil then
   RoomObject = moo.create( moo.system.room )
   RoomObject.name = RoomName

   moo.notify( "Created room \"" .. RoomName .. "\" (#" .. RoomObject.id .. ")" )
else
   RoomName = RoomObject.name
end

if string.find( ExitSpec, "|" ) ~= nil then
   Exit1, Exit2 = string.match( ExitSpec, "(.*)|(.*)" )
else
   Exit1 = ExitSpec
   Exit2 = nil
end

RoomExits1 = moo.here.exits

for Exit in string.gmatch( Exit1, "%a+" ) do
    RoomExits1[ Exit ] = RoomObject
end

moo.here.exits = RoomExits1

RoomExits2 = RoomObject.exits

for Exit in string.gmatch( Exit2, "%a+" ) do
    RoomExits2[ Exit ] = moo.here
end

RoomObject.exits = RoomExits2

Create a new 'go' verb for players to move about:

@verbadd $generic_player:go any none none

Verb code:

moo.programmer = moo.player

local Exit = moo.here.exits[ moo.dobjstr ]

if Exit == nil then
    moo.notify( "You can't go that way" )
    return
end

moo.player.location = Exit

Let us now create a second room and link to it, creating exits to the east (from the first room) and the west (from the second room):

@dig e|w to "The Second Room"

We can now move between the two rooms using the 'go' verb:

;moo.notify( moo.here.name )
The First Room
go e
;moo.notify( moo.here.name )
The Second Room
go w
;moo.notify( moo.here.name )
The First Room

It would be preferable to have the system print some feedback to the player as they move between rooms. Let's add a description to our generic thing:

@propadd $thing.description "You don't notice anything of interest"

Rather than just having a text string, we are going to add a description verb that can be overridden by objects to provide dynamic descriptions:

@verbadd $thing:description

Verb code:

return moo.object:prop( "description" ):value()

We can now add a basic 'look' verb:

@verbadd $generic_player:look none none none

Verb code:

moo.notify( moo.here.name )
moo.notify( moo.here:description() )

As we want this verb to be called automatically when the player moves between rooms, we can create verbs called 'enterfunc' and 'exitfunc' that will called internally by the system:

@verbadd $room:enterfunc

Verb code:

local Object, From = ...

if Object.player == true then
    moo.object:tell( moo.player.name .. " has arrived" )
    Object:look()
end

And exitfunc:

@verbadd $room:exitfunc

Verb code:

local Object, To = ...

if Object.player == true then
    moo.object:tell( moo.player.name .. " has left" )
end

And finally, we need to add the verb to tell messages to the other players in a room:

@verbadd $room:tell

Verb code:

for k, v in ipairs( moo.caller:players() ) do
    if v.id ~= moo.player.id then
        v:notify( args[ 1 ] )
    end
end

It would also be nice for the look verb to show what exits are available:

@edit $generic_player:look

Updated verb code:

moo.notify( moo.here.name )
moo.notify( moo.here:description() )

local ExitDesc = {}

local ExitNames = { n = "north", s = "south", e = "east", w = "west",
    u = "up", d = "down" }

for k, v in pairs( moo.here.exits ) do
    table.insert( ExitDesc, "To the " .. ExitNames[ k ] .. " is " .. v.name .. "." )
end

if #ExitDesc ~= 0 then
    moo.notify( table.concat( ExitDesc, " " ) )
end

We can now move around like so:

look
The First Room
You don't notice anything of interest
To the east is The Second Room.
go e
The Second Room
You don't notice anything of interest
To the west is The First Room.

Summary

We have created a @dig verb to allow easy creation of new rooms and the exits between them. We've also added a look verb and a way of adding dynamic descriptions to objects that will be reported to players.

The next stage is adding support for multiple users to log into the system!

Clone this wiki locally