T2T Mapper from scratch

Post Reply
Tagon
Posts: 24
Joined: Thu Sep 19, 2013 8:38 pm

T2T Mapper from scratch

Post by Tagon »

Okay, so I'm new to Mudlet. I'm trying to emulate the mapper functionality that was in zMud/cMud which plain don't run, at least for me, any more. I should say right now that the trigger/alias support in Mudlet is lovely, if I can get the mapper working how I want then I'm golden! Hopefully along the way I can turn this into a how-to and maybe even release it as a package.

Before I go into the specifics of T2T and how the info is to be triggered, I want to do some manual functions to understand how it's working and I'll ask lots of questions along the way. The only exception being, this mud doesn't send room ids or provide a pre-written map.

Step 1

Create new script, name "My T2T Map"

Contents:
Code: [show] | [select all] lua
mudlet = mudlet or {}; mudlet.mapper_script = true
exitmap = {
  n = 1,
  north = 1,
  ne = 2,
  northeast = 2,
  nw = 3,
  northwest = 3,
  e = 4,
  east = 4,
  w = 5,
  west = 5,
  s = 6,
  south = 6,
  se = 7,
  southeast = 7,
  sw = 8,
  southwest = 8,
  u = 9,
  up = 9,
  d = 10,
  down = 10,
  ["in"] = 11,
  out = 12,
  [1] = "north",
  [2] = "northeast",
  [3] = "northwest",
  [4] = "east",
  [5] = "west",
  [6] = "south",
  [7] = "southeast",
  [8] = "southwest",
  [9] = "up",
  [10] = "down",
  [11] = "in",
  [12] = "out",
}
This will, as I understand it, tell the client that there is a mapper script enabled. It will also define a table which will translate directions into numbers and visa-versa for example exitmap[1] returns "north".

Question 1: Should be an easy one, why is "in" in quite marks, while "out" isn't? I assume that's due to reserved words in lua? To be syntactically correct should all of the direction names be in quote marks?

Step 2

Opening the mapper using the button in the top bar.
Manually creating an area, returns 1.
Code: [show] | [select all] lua
 addAreaName("Arda")
Manually creating a room, createRoomID() lets me auto-increment room creation. Repeat for 2 rooms.
Code: [show] | [select all] lua
addRoom(createRoomID())
Put rooms into the Area
Code: [show] | [select all] lua
setRoomArea(1,1)
setRoomArea(2,1)
Give rooms names.
Code: [show] | [select all] lua
setRoomName(1,"First Room")
setRoomName(2,"Second Room")
Set room coordinates, putting room 1 north of room 2
Code: [show] | [select all] lua
setRoomCoordinates(1,0,0,0)
setRoomCoordinates(2,0,-1,0)
Add edit stubs to rooms (south from room 1, north from room 2)
Code: [show] | [select all] lua
setExitStub(1, exitmap.s,true)
setExitStub(2, exitmap.n,true)
Here's the problem. I created a function in my scripts file as follows. Now it could be down to my limit knowledge of lua, but I'm learning fast (I code in dozens of other languages so it's more syntax than anything).
Code: [show] | [select all] lua
function showExits(roomID)
	local tmp = 	getRoomExits(roomID)
	echo(#tmp)
	for i = 0, #tmp do echo(tmp[i]) end
end
Running showExits(1) only echoes out "0" indicating that the returned table "tmp" is empty.

Main questions/roadblock: Given that I ran all the above commands and have a viewable map, why am I not getting a return from showExits(1) ?

Thanks in advance!
Last edited by Tagon on Fri Sep 20, 2013 6:26 pm, edited 1 time in total.

Curudan
Posts: 9
Joined: Fri Aug 23, 2013 4:49 pm

Re: T2T Mapper from scratch

Post by Curudan »

"in" is a reserved word, so it as a key has to be declared in quotes, otherwise the parser will throw an error.

Appending "#" to the front of a array will only return the length of Tables, that is an array with consecutive digits starting at one for the values. The pound sign will not work with any other kind of array. This is because Lua does not store any internal count of array lengths.

Using pairs is the simplest way to loop through the contents of an array.
Code: [show] | [select all] lua
function showExits(roomID)
        local tmp =     getRoomExits(roomID)
        for k, v in pairs(tmp) do echo(k.." - "..v.."\n") end
end
I hope this helps.

User avatar
Vadi
Posts: 5042
Joined: Sat Mar 14, 2009 3:13 pm

Re: T2T Mapper from scratch

Post by Vadi »

Confirming what Curudan says. We have also defined table.size() which does the loop and counts for you.

Jor'Mox
Posts: 1146
Joined: Wed Apr 03, 2013 2:19 am

Re: T2T Mapper from scratch

Post by Jor'Mox »

Also, your for loop will cause problems. Since most tables start at an index of 1, rather than 0, the value for index 0 will be nil, which will generate an error in the echo function.

Tagon
Posts: 24
Joined: Thu Sep 19, 2013 8:38 pm

Re: T2T Mapper from scratch

Post by Tagon »

Thanks for the help guys, things are progressing well now and I'll post again soon with an update.

I thought I'd check back to find where I went wrong on the loop function and it seems like I used the example at the bottom of http://wiki.mudlet.org/w/Mapping_script ... directions. This might want changing.

User avatar
Vadi
Posts: 5042
Joined: Sat Mar 14, 2009 3:13 pm

Re: T2T Mapper from scratch

Post by Vadi »

The example is correct, http://wiki.mudlet.org/w/Manual:Mapper_ ... tExitStubs returns an indexed table (while http://wiki.mudlet.org/w/Manual:Mapper_ ... tRoomExits returns a key-value table).

Tagon
Posts: 24
Joined: Thu Sep 19, 2013 8:38 pm

Re: T2T Mapper from scratch

Post by Tagon »

Okay, here's the update, and it's quite a step forwards! I'm open to any advice on optimising it and since I'm a lua newbie if there's a better way to achieve the same thing, let me know.

First up, here's my map script file
Code: [show] | [select all] lua
mudlet = mudlet or {}; mudlet.mapper_script = true

exitmap = {
  n = 1,
  north = 1,
  ne = 2,
  northeast = 2,
  nw = 3,
  northwest = 3,
  e = 4,
  east = 4,
  w = 5,
  west = 5,
  s = 6,
  south = 6,
  se = 7,
  southeast = 7,
  sw = 8,
  southwest = 8,
  u = 9,
  up = 9,
  d = 10,
  down = 10,
  ["in"] = 11,
  out = 12,
  [1] = "north",
  [2] = "northeast",
  [3] = "northwest",
  [4] = "east",
  [5] = "west",
  [6] = "south",
  [7] = "southeast",
  [8] = "southwest",
  [9] = "up",
  [10] = "down",
  [11] = "in",
  [12] = "out",
}

function showExits(roomID)
	local tmp = getRoomExits(roomID)
	local size = table.size(tmp)
	echo(getRoomName(roomID).." leads ")
	for k, v in pairs(tmp) do 
		if size>2 then
			echo(k.."("..getRoomName(v).."), ")
		elseif size==2 then
			echo(k.."("..getRoomName(v)..") and ")
		else
			echo(k.."("..getRoomName(v)..")\n")
		end
		size = size-1
	end
end

function showStubs(roomID)
	local tmp = getExitStubs(roomID)
	local size = table.size(tmp)
	echo(getRoomName(roomID).." leads ")
	for k, v in pairs(tmp) do 
		if size>2 then
			echo(exitmap[v]..", ")
		elseif size==2 then
			echo(exitmap[v].." and ")
		else
			echo(exitmap[v].."\n")
		end
		size = size-1
	end
end

currentRoom = 0
currentArea = 0
lastCommand = ""

registerAnonymousEventHandler("sysDataSendRequest", "parseCommands")

function parseCommands(_,command)
	lastCommand=command
end

function newCoords(id,dir)
	local x,y,z = getRoomCoordinates(id)
	if type(dir)~="number" then dir=exitmap[dir] end
	if dir==1 or dir==2 or dir==3 then y=y+1 
	elseif dir==6 or dir==7 or dir==8 then y=y-1 end
	if dir==2 or dir==4 or dir==7 then x=x+1 
	elseif dir==3 or dir==5 or dir==8 then x=x-1 end
	return x,y,z
end

function isRoomNear(id,area,dir)
	local x,y,z=newCoords(id,dir)
	local otherroom = select(2, next(getRoomsByPosition(area,x,y,z)))
	if not otherroom then return 0
	else return otherroom end
end

function reverseStub(dir)
	if dir==1 then return 6
	elseif dir==2 then return 8
	elseif dir==3 then return 7
	elseif dir==4 then return 5
	elseif dir==5 then return 4
	elseif dir==6 then return 1
	elseif dir==7 then return 3
	elseif dir==8 then return 2
	elseif dir==9 then return 10
	elseif dir==10 then return 9
	elseif dir==11 then return 12
	elseif dir==12 then return 11
	end
end
I wrote a few functions to make life easier for myself (working out relative coords and reversing directions etc).

Then the mapper functionality itself is all contained in a single trigger. I know I'm going to need to add more triggers later for things like party following and "you can't go there" style actions. I'll also have to tackle special exits (which I have an issue with already). The trigger pattern matches on the room description and exits when entering a room, example "The White Stallion Inn(e, u and s)", there is the potential for an extra " [n and s]" style exit on the end, which are water exits (swimming or boating only) but for now I'm ignoring those entirely!

Trigger Line 1 (regexp): ^(.*)\((.*)[\)|\) \[.*\]]$
Trigger Line 2 (color trigger): Light White/Blue (I couldn't set the bg color on the example above, it's white on blue)

Script:
Code: [show] | [select all] lua
room=multimatches[1][2]
exits = {}
index = 1
for value in string.gmatch(multimatches[1][3],"%w+") do
	if value~="and" then
		exits[index] = value
		index = index + 1
	end
end

if currentRoom==0 then -- If lost
	-- Compare room name to DB, if it's a unique name, you're found
	local tmp = searchRoom(multimatches[1][2])
	if (table.size(tmp)==1) then
		for k,v in pairs(tmp) do
			if (v==multimatches[1][2]) then
				currentRoom = k
				currentArea = getRoomArea(k)
				centerview(currentRoom)
			end
		end
	end
else -- Not lost
	local tmp = getRoomExits(currentRoom)
	if tmp[lastCommand]~=null then --if exit exists
		if multimatches[1][2]==getRoomName(tmp[lastCommand]) then -- and room name matches
			currentRoom=tmp[lastCommand]
			centerview(currentRoom) --update location
		else -- exit exists but room name doesn't
			currentRoom=0
		end
	else -- exit doesn't exist
		tmp2 = getExitStubs(currentRoom) -- check stubs, maybe make a new room
		if table.contains(tmp2,exitmap[lastCommand]) then -- exit stub exists in that direction PROBLEM
			nextroom=isRoomNear(currentRoom,currentArea,lastCommand)
			if nextroom~=0 then
				-- does IT have the appropriate exit stub?
				tmpStub=getExitStubs(nextRoom)
				if tmpStub[reverseStub(exitmap[lastCommand])]~=null then
					connectExitStub(currentRoom,exitmap[lastCommand])-- connect them
					currentRoom=nextroom
					centerview(currentRoom)
				else
					echo("Failed connect, room but no reverse stub")
					currentRoom=0
				end
			else
				-- make the room
				local newRoom = createRoomID()
				addRoom(newRoom)
				setRoomArea(newRoom,currentArea)
				setRoomName(newRoom,multimatches[1][2])
				local x,y,z=newCoords(currentRoom,lastCommand)
				setRoomCoordinates(newRoom,x,y,z)
				echo("Making new room: "..newRoom.." at "..x.."/"..y.."/"..z)
				-- add Exit stubs
				for i = 1, #exits do setExitStub(newRoom,exitmap[exits[i]],true) end --problem with non-standard exits here!
				-- connect to current room
				connectExitStub(currentRoom,exitmap[lastCommand])
				-- update location
				currentRoom=newRoom
				centerview(currentRoom)
			end
		else
			currentRoom=0 -- give in, you're lost
		end
	end
end
if currentRoom==0 then
	echo("lost")
else
	echo(currentRoom)
end(0,0,0)
I need to add some more comments so I can follow the logic in a week's time but it flows 'fairly' well. The current issue comes up when I enter a room with a special exit (e.g. "enter"), in which case it throws an error to the error console and fails to connect the exit stubs. I suspect the best way to handle that will be to use an if statement
Code: [show] | [select all] lua
if exit[i]==n or exit[i]=s or etc then setExitStub(stuff)
else specialExitStuff() end
I just thought that I'd made enough progress that it was worth coming back here to check I'm not heading for disaster. I've managed to map "most" of a town just by walking around, and towns are tricky with lots of overlapping rooms (make room, move room, carry on mostly). I do need to tackle to issue of moving to a new area, though I "think" the current code should cover it well enough, it tracks and updates the currentArea variable.

Anyway, taking a break means I actually get time to play the game too :) Look forwards to any feedback and as always, it's much appreciated!

User avatar
chris
Posts: 493
Joined: Fri Jun 17, 2011 5:39 am

Re: T2T Mapper from scratch

Post by chris »

If you are looking for a fairly complete mapper that works off muds which do not have room ids/prebuilt maps, you might want to check out my mapper for 3kingdoms (https://github.com/Chris7/3k-Scripts)

Tagon
Posts: 24
Joined: Thu Sep 19, 2013 8:38 pm

Re: T2T Mapper from scratch

Post by Tagon »

Not wanting to sound ungrateful but I'd rather build my own up.

Not only does it mean I'm learning lua as I go (as of 2 days ago I've never touched it) but I get an understanding of how each section works and where/how to make changes. I've downloaded and read about 5 different scripts from here and I just can't follow them, I'm sure some people think the same about mine though!

Post Reply