String Manipulation

Posted by Kevnuke on Mon 16 Jan 2012 01:01 AM — 50 posts, 162,445 views.

USA #0
This may seem very simple but how do I remove a single character from the middle of a string?

Char.Vitals --> CharVitals
Comm.Channel.Start --> CommChannelStart

or substitute one part of that for another?

CharacterName = "Jim"

Char.Vitals { "hp": "3000", "maxhp": "3000", "mp": "2000", "maxmp": "2000"}

-->

Jim.Vitals = {"hp" = 3000, "maxhp" = 3000, "mp" = 2000, "maxmp" = 2000}

like that?
USA Global Moderator #1
See string.gsub

http://lua-users.org/wiki/StringLibraryTutorial
USA #2
I think i figured it out.


char = "Jim"

_G[char] = {}

do

local n = _G[char]

n.r = 15

end

print (_G[char].r)
Australia Forum Administrator #3
Huh?
USA Global Moderator #4
Kevnuke said:
I think i figured it out.


The code you just posted doesn't make any sense.
USA #5
I did figure out my original problem though.


msg = Char.Vitals

msg:gsub ("%.", "")

-->

CharVitals


isn't that right?

As for the second part. I was trying to make a different table for each of my characters using GMCP data.


local _G[CURRENT_CHARACTER] = {}

local VITALS = rex.new ('{ "hp": "%d+", "maxhp": "%d+", "mp": "%d+", "maxmp": "%d+", "ep": "%d+", "maxep": "%d+", "wp": "%d+", "maxwp": "%d+", "nl": "%d+", "string": "H:(?<health>%d+)/(?<healthmax>%d+) M:(?<mana>%d+)/(?<manamax>%d+) E:(?<endurance>%d+)/(?<endurancemax>%d+) W:(?<willpower>%d+)/(?<willpowermax>%d+) NL:(?<levelprogress>%d+)/100" }')

function CharVitals (content)

  local t = _G[CURRENT_CHARACTER]
  s, e, t.stats = VITALS:gmatch(content)

end

print (_G[CURRENT_CHARACTER].stats.health)

-->

Compile Error


Is there something wrong with this?
Amended on Sun 29 Jan 2012 11:50 PM by Kevnuke
USA Global Moderator #6
Quote:
Is there something wrong with this?
If you get an error then, yes, there is obviously something wrong. ;)
Luckily the error message should tell you what it is.
USA #7
Kevnuke said:
local _G[CURRENT_CHARACTER] = {}

This line is incorrect. You don't use 'local' when you're adding an entry to an table; 'local' is just to specify whether the variable you're creating is accessible from everywhere or just in the current scope.

Incidentally, since _G contains all of the global variables, it doesn't make much sense to declare a 'local global' anyways.
Amended on Mon 30 Jan 2012 02:38 AM by Twisol
USA #8
Yea that does look pretty funny now that I think about it.

I've been trying different things to get that pattern to match the test string. Adding backslashes and such to see if that's why it isn't returning any values to the table t. I'm gonna start with the pattern .+ and add things to it, one at a time.

If I were doing this in a trigger it would be way easy for me haha.

EDIT: spelling error
Amended on Mon 30 Jan 2012 03:53 AM by Kevnuke
USA #9
Ok this is pretty ugly..but it works at least


VITALS = rex.new ('\{ \"hp\"\: \"....\"\, \"maxhp\"\: \"....\"\, \"mp\"\: \"....\"\, \"maxmp\"\: \"....\"\, \"ep\"\: \".....\"\, \"maxep\"\: \".....\"\, \"wp\"\: \".....\"\, \"maxwp\"\: \".....\"\, \"nl\"\: \".+\"\, \"string\"\: \"H\:(?<health>....)/(?<healthmax>....) M\:(?<mana>....)\/(?<manamax>....) E\:(?<endurance>.....)\/(?<endurancemax>.....) W\:(?<willpower>.....)\/(?<willpowermax>.....) NL\:(?<levelprogress>.)\/100 \" \}')


I can't get the regular special characters to work in place of the dot character. \d \s \w etc. is it %d %s %w ?

EDIT:
I got it.

In a rex pattern match you have to double escape special matching characters \d \s \w etc. Although it's kinda stupid, why was it made that way?


VITALS = rex.new ('\{ \"hp\"\: \"\d+\"\, \"maxhp\"\: \"\d+\"\, \"mp\"\: \"\d+\"\, \"maxmp\"\: \"\d+\"\, \"ep\"\: \"\d+\"\, \"maxep\"\: \"\d+\"\, \"wp\"\: \"\d+"\, \"maxwp\"\: \"\d+\"\, \"nl\"\: \"\d+\"\, \"string\"\: \"H\:(?<health>\d+)/(?<healthmax>\d+) M\:(?<mana>\d+)\/(?<manamax>\d+) E\:(?<endurance>\d+)\/(?<endurancemax>\d+) W\:(?<willpower>\d+)\/(?<willpowermax>\d+) NL\:(?<levelprogress>\d+)\/100 \" \}')
Amended on Tue 31 Jan 2012 12:23 AM by Kevnuke
Australia Forum Administrator #10
Lua regular expressions use % for that very reason. If you are using the PCRE ones inside Lua strings, and since Lua strings use backslash for special characters (like newline) then you have to double them.

The trouble is, the inventors of regular expressions thought "I'll use a backslash to 'escape' special characters - no-one uses them for much else".

And so did the inventors of the C language. And the Lua language. And so on.

So now you get "backslash confusion".
USA #11
Why did the forum remove the leading backslashes from my post? -.-
USA #12
Kevnuke said:

Why did the forum remove the leading backslashes from my post? -.-


You may as well ask why "\n" doesn't print \n. :P The backslash is how the forum software determines whether you want foo[i] = "stuff" or foo = "stuff".
USA #13
I still have this problem, although i figured out the other problem.


char = "Jim"

_G[char] = {}

do

local n = _G[char]

n.r = 15

end

print (_G[char].r)


This works, but if you add another field in depth it doesn't..


char = "Jim"

_G[char] = {}

do

local n = _G[char]

n.r.a = 15

end

print (_G[char].r.a)

-->

Run-time error


Can anyone tell me a way around this?
Australia Forum Administrator #14
I don't understand what you are doing here, at all.

You shouldn't be storing your own variables in the global variable space. eg.


char = "Jim"

_G[char] = {}


Is basically:


 Jim = {}


What if you have a character one day called "math" ? Then all your math functions go away.

You should be storing game-related stuff in your own table, not _G.


print (_G[char].r.a)


That is getting "a" from table "r" from the item indexed by char in table _G. That will fail if "r" is not a table.

And in your example "r" does not even exist, let alone be a table.
USA #15
Nick Gammon said:

I don't understand what you are doing here, at all.

You shouldn't be storing your own variables in the global variable space. eg.


char = "Jim"

_G[char] = {}


Is basically:


 Jim = {}



True statement, that's exactly what I wanted it to be equivalent to. And I wasn't actually planning to put it in the global variable space when I used it, just done here as an example.

Nick Gammon said:

What if you have a character one day called "math" ? Then all your math functions go away.


I don't plan on naming my characters after any Lua libraries. :P

Nick Gammon said:

You should be storing game-related stuff in your own table, not _G.


I will be. The actual implementation will be something like this.


system[current_character] = "Jim"

system[system.current_character] = {} -- Creates a table that is the same as system.Jim

--Put GMCP data into the table I just created.

system[system.current_character] = {

	vitals = {

		hp	= t.hp,
		maxhp	= t.maxhp -- t is the table created from the rex.match function, hp and maxhp are named wildcards in the pattern.
	},
}

--Later I want to be able to do something like this to access the values of those stored variables, like this.

system[system.current_character]vitals.hp


See now?
Australia Forum Administrator #16
Your idea of system [system.xxx] is very confusing. This code compiles at least, but I'm not sure it is the way to go:


t = {hp = 42, maxhp = 100}
system = { }

system.current_character = "Jim"

system [system.current_character] = {} -- Creates a table that is the same as system.Jim

--Put GMCP data into the table I just created.

system [system.current_character] = {

	vitals = {

		hp	= t.hp,
		maxhp	= t.maxhp -- t is the table created from the rex.match function, hp and maxhp are named wildcards in the pattern.
	},
}

--Later I want to be able to do something like this to access the values of those stored variables, like this.

print (system [system.current_character].vitals.hp )

USA #17
Well I did learn something important from testing in the Immediate script environment in MUSHclient

I was actually more worried about Lua having a syntax for -retrieving- a value specified by a variable more than setting it..which I already knew was possible. I just wasn't sure the specifics of how that worked.


char = "Jim"

system[char]  =  {
  vitals  =  {
    hp  =  300
  }
}

print (system[char].vitals.hp)

-->

300


char  =  "Jim"
test  =  "vitals"

system[char]  =  {
  [test]  =  {
    hp  =  300
  }
}

print (system[char].vitals.hp)
print (system[char][test].hp)

-->

300
300


They both work, but..


char = "Jim"

system[char]  =  {
  vitals  =  {
    hp  =  300
  }
}

print (system[char]vitals.hp)

-->

Compile Error


char  =  "Jim"
test  =  "vitals"

system[char]  =  {
  test  =  {
    hp  =  300
  }
}

print (system[char].test.hp)

-->

Compile Error


Does not work.

I did several other variations just to see what would work and what wouldn't. I'm just glad I got it sorted out before I coded the entire plugin and then realized it was one huge compile error.
USA #18
Kevnuke said:

char  =  "Jim"
test  =  "vitals"

system[char]  =  {
  test  =  {
    hp  =  300
  }
}

print (system[char].test.hp)

-->

Compile Error

That one does work, actually; I just tried it. (Assuming a missing system = {}, anyways.)

You might be confused about how the table initializer syntax works. When you have {test=42}, it isn't using the value of the variable called 'test'; it's using the actual string value "test". In other words, {test=42} is a shorthand provided by Lua that's equivalent to {["test"]=42}. And in a similar vein, if you -do- want to use the value of a variable as the key, you can use {[test]=42}.

This also mimics the behavior of the table accessor syntax, where you have tbl.foo as a shorthand for tbl["foo"].
Australia Forum Administrator #19
Yeah, I suggest you read the stuff about tables:

http://www.gammon.com.au/forum/?id=6036

Get comfortable with the simple stuff first. Naturally you can retrive things based on a variable.

But pay close attention to what Twisol said.

This syntax:

 
a = t [ bar ]


... indexes into table "t" by the contents of variable "bar", whatever that is.

However both of these do the same thing:

 
a = t [ "foo" ]
a = t.foo


They find the entry by the word "foo" - not some variable "foo".
USA #20
Twisol said:

Kevnuke said:

char  =  "Jim"
test  =  "vitals"

system[char]  =  {
  test  =  {
    hp  =  300
  }
}

print (system[char].test.hp)

-->

Compile Error

That one does work, actually; I just tried it. (Assuming a missing system = {}, anyways.)


Correct! Sorry, it was supposed to be
print (system[char].vitals.hp) demonstrating that unless you use the proper syntax it thinks you are literally making "test" the index, not the -contents- of a variable named "test", as you said.

Twisol said:

You might be confused about how the table initializer syntax works. When you have {test=42}, it isn't using the value of the variable called 'test'; it's using the actual string value "test". In other words, {test=42} is a shorthand provided by Lua that's equivalent to {["test"]=42}. And in a similar vein, if you -do- want to use the value of a variable as the key, you can use {[test]=42}.

This also mimics the behavior of the table accessor syntax, where you have tbl.foo as a shorthand for tbl["foo"].


Also correct! The point of all the experimenting I did was so that i wouldn't be confused about how the table initializer syntax worked anymore.

Thanks for all the help so far!
USA #21
Nick Gammon said:

Yeah, I suggest you read the stuff about tables:

http://www.gammon.com.au/forum/?id=6036

Get comfortable with the simple stuff first. Naturally you can retrive things based on a variable.


Thanks for the link, Nick. The part about using metatables to create defaults was really inspiring. It will likely save me a lot of time setting the same value for multiple sub-tables.

I guess I should just use the literal tables I'm going to be using. The two characters i have are Setru and Christopher on Achaea.

I wanted to create a separate sub-table within the table "system" for each character. BUT I was also going to put everything else in system = {} as well. For starters, just my balances (for use in my curing system). Eventually I wanted to do this..


a = some rex.new pattern with named wildcards that matches the Room.Info string

content = "the Room.Info string"

function RoomInfo (content)

_, _2, t = a:match(content)

if system.map[t.ID] then
  if content == system.map[t.ID].LAST_CONTENT then

    return

  else

    system.map = {

      [t.ID] = {

        roomName     = t.name,
        area         = t.area,
        environment  = t.environment,
        --etc
        LAST_CONTENT = content,

      },

    },

  end

else

  system.map = {

    [t.ID] = {

      roomName     = t.name,
      area         = t.area,
      environment  = t.environment,
      --etc
      LAST_CONTENT = content

    },

  },

  system[current_character].map = {

    [t.ID]         = system.map[t.ID]

  },

end --if

end --function


with the index of each entry in the system["map"] being the ID number of every room I've walked into. The first time I enter a room (ever, on any character) it is added to the system["map"] table as well as system[current_character].map (the map of the character I entered it with. This is so that later I have the option of comparing the system["map"] table with the map entries of the character I'm currently using to see if there are any I've missed. Whew!

OWWWW! My brain hurts now. I just did that code on the fly. Anything wrong with it?

EDIT: entered a few commas after table entries, just to be safe.
Amended on Tue 07 Feb 2012 12:53 AM by Kevnuke
USA #22
I've also been wrestling with this one. This is the rex pattern I'm using to attempt to get exits and details from the string in content which is a sample GMCP Room.Info string.


ROOM_INFO  =  rex.new ('\{ \"num\"\: (?<ID>\d+)\, \"name\"\: \"(?<name>.+)\"\, \"area\"\: \"(?<area>.+)\"\, \"environment\"\: \"(?<environment>.+)\"\, \"coords\"\: \"[0-9\,]\"\, \"map\"\: \"\.+\"\, \"exits\"\: \{ (\"(?<exit>\w+)\"\: (?<exitID>\d+)[,]?[ ]?)* \}, \"details\"\: [ ("(?<detail>\w+)\"[,]?[ ]?])* ] }')

content  =  '{ "num": 12345, "name": "On a hill", "area": "Barren hills", "environment": "Hills", "coords": "45,5,4,3", "map": "www.imperian.com/itex/maps/clientmap.php?map=45&level=3 5 4", "exits": { "n": 12344, "se": 12336 }, "details": [ "shop", "bank" ] }'

function RoomInfo (content)

_, _2, t = ROOM_INFO:match(content)

if not system.map[t.exitID] then

	system.map[t.exitID] = {}

end

if system.map[t.ID] then

	if next (system.map[t.ID]) == nil then

		system.map[t.ID]	=	{

			name	=	t.name,
			area	=	t.area,
			--etc
			exits	=	{
				[t.exit]	=	system.map[t.exitID],
			},
			details	=	{
				t.details,
			},

		},

			LAST_ROOMINFO = content

	else

		if content == system.map[t.ID].LAST_ROOMINFO then

			return

		else

			system.map[t.ID]	=	{

				name	=	t.name,
				area	=	t.area,
				--etc
				exits	=	{
					[t.exit]	=	system.map[t.exitID],
				},
				details	=	{
					t.details,
				},

			},

			LAST_ROOMINFO = content

		end

	end

else

	system.map[t.ID]	=	{

		name	=	t.name,
		area	=	t.area,
		--etc
		exits	=	{
			[t.exit]	=	system.map[t.exitID],
		},
		details	=	{
			t.details,
		},

	},

		LAST_ROOMINFO = content

end

end


I -think- that code works. I'll check it while I'm offline. Also done on the fly, by the way.

EDIT: Quoted the string, I also forgot a space at the beginning of the object.
Amended on Tue 07 Feb 2012 05:04 AM by Kevnuke
USA #23
Whoa. Just run the GMCP payload through MUSHclient's bundled JSON library. A regexp is extremely brittle in this situation.

(Also, your code doesn't work. You dropped the GMCP payload directly into Lua without quoting it, and the JSON notation isn't syntactically compatible with Lua directly.)

local JSON = require "json"

content = [=[
{
  "num": 12345,
  "name": "On a hill",
  "area": "Barren hills",
  "environment": "Hills",
  "coords": "45,5,4,3",
  "map": "www.imperian.com/itex/maps/clientmap.php?map=45&level=3 5 4",
  "exits": { "n": 12344, "se": 12336 },
  "details": [ "shop", "bank" ]
}
]=]

tprint(JSON.decode("[" .. content .. "]")[0])


(The extra JSON array and subsequent index after decoding is to smooth out certain incompatibilies between JSON parsers. It doesn't matter for this particular payload, but for other GMCP messages it does matter. So I figured I'd play it safe and not assume anything about MUSHclient's JSON parser.)
Amended on Tue 07 Feb 2012 04:56 AM by Twisol
USA #24
Umm..error


local JSON = require "json"
require "tprint"

content = [=[
{
  "num": 12345,
  "name": "On a hill",
  "area": "Barren hills",
  "environment": "Hills",
  "coords": "45,5,4,3",
  "map": "www.imperian.com/itex/maps/clientmap.php?map=45&level=3 5 4",
  "exits": { "n": 12344, "se": 12336 },
  "details": [ "shop", "bank" ]
}
]=]

tprint(JSON.decode("[" .. content .. "]")[0])

-->

Run-time error
World: Achaea
Immediate execution
C:\Games\MUSHclient\lua\tprint.lua:34: bad argument #1 to 'pairs' (table expected, got nil)
stack traceback:
        [C]: in function 'pairs'
        C:\Games\MUSHclient\lua\tprint.lua:34: in function 'tprint'
        [string "Immediate"]:16: in main chunk
USA #25
Sorry, I'm used to working with 0-based arrays again.

local JSON = require "json"

content = [=[
{
  "num": 12345,
  "name": "On a hill",
  "area": "Barren hills",
  "environment": "Hills",
  "coords": "45,5,4,3",
  "map": "www.imperian.com/itex/maps/clientmap.php?map=45&level=3 5 4",
  "exits": { "n": 12344, "se": 12336 },
  "details": [ "shop", "bank" ]
}
]=]

tprint(JSON.decode("[" .. content .. "]")[1])
Amended on Tue 07 Feb 2012 07:38 AM by Twisol
USA #26
Ohh just change the 0 to 1?
USA #27
So what does surrounding the GMCP data with [=[ ]=] do? I've never seen that used before.
USA #28
Kevnuke said:
Ohh just change the 0 to 1?

Yep. Lua array indices start from 1, as opposed to indexing in languages like Java or C++, where indices start at 0.

Kevnuke said:
So what does surrounding the GMCP data with [=[ ]=] do? I've never seen that used before.

It's another way of making string literals, without dealing with escape characters. [[a"b'c]] is a string literal containing, a"b'c, and none of those quotes needed to be escaped. A possible issue is that the literal may contain ]] itself (just like you don't want " inside a "foo" literal), so Lua allows you to insert a number of ='s between the start and end brackets, as long as the number is the same.
USA #29
Twisol said:

Kevnuke said:
So what does surrounding the GMCP data with [=[ ]=] do? I've never seen that used before.

It's another way of making string literals, without dealing with escape characters. [[a"b'c]] is a string literal containing, a"b'c, and none of those quotes needed to be escaped. A possible issue is that the literal may contain ]] itself (just like you don't want " inside a "foo" literal), so Lua allows you to insert a number of ='s between the start and end brackets, as long as the number is the same.

That's nifty! I was wondering what I'd do if there were single and double quotes in the same string.
USA #30

local JSON = require"json"
require "tprint"


content = [=[
[
  { "name": "Vision", "rank": "Adept" },
  { "name": "Avoidance", "rank": "Capable" },
  { "name": "Tattoos", "rank": "Inept" },
  { "name": "Survival", "rank": "Transcendent" },
  { "name": "Weaponry", "rank": "Adept" },
  { "name": "Riding", "rank": "Inept" },
  { "name": "Venom", "rank": "Transcendent" },
  { "name": "Hypnosis", "rank": "Mythical" },
  { "name": "Subterfuge", "rank": "Transcendent" },
  { "name": "Constitution", "rank": "Inept" },
  { "name": "Thermology", "rank": "Inept" },
  { "name": "Frost", "rank": "Inept" },
  { "name": "Antidotes", "rank": "Inept" },
  { "name": "Fitness", "rank": "Apprentice" },
  { "name": "Galvanism", "rank": "Inept" },
  { "name": "Philosophy", "rank": "Inept" },
  { "name": "InkMilling", "rank": "Inept" },
  { "name": "Gathering", "rank": "Inept" }
]
]=]

local t = {}
system["char"] = "Setru"

t  =  (JSON.decode("[" .. content .. "]")[1])

for i = 1, #t in ipairs (t) do

  system[system.char]  =  {

    skills  =  {

      [t[i].name]  =  {

        rank      =  t[i].rank,

        abilities  =  {

        },

      },

    },
	
  }

end

tprint (system[system.char].skills)

end


I keep getting a compile error
Compile error
World: Achaea
Immediate execution
[string "Immediate"]:11: 'do' expected near 'in'

I'm trying to end up with this..


system["Setru"].skills = {
  Vision  =  {
    rank = "Adept"
  },
  Avoidance  =  {
    rank = "Capable"
  },
  Tattoos  =  {
    rank = "Inept"
  },
  Survival  =  {
    rank = "Transcendent"
  },
  Weaponry  =  {
    rank = "Adept"
  },
  Riding  =  {
    rank = "Inept"
  },
  Venom  =  {
    rank = "Transcendent"
  },
  Hypnosis  =  {
    rank = "Mythical"
  },
  Subterfuge  =  {
    rank = "Transcendent"
  },
  Constitution  =  {
    rank = "Inept"
  },
  Thermology  =  {
    rank = "Inept"
  },
  Frost  =  {
    rank = "Inept"
  },
  Antidotes  =  {
    rank = "Inept"
  },
  Fitness  =  {
    rank = "Apprentice"
  },
  Galvanism  =  {
    rank = "Inept"
  },
  Philosophy  =  {
    rank = "Inept"
  },
  InkMilling  =  {
    rank = "Inept"
  },
  Gathering  =  {
    rank = "Inept"
  }
}


EDIT: Made the "content" string easier to read and entered a missing JSON function. Used the MUSHclient forum codes converter on this post. :P
Amended on Sat 11 Feb 2012 02:11 AM by Kevnuke
USA #31
Well, ignoring the compilation error for a moment (because I haven't found it yet), your decoding isn't doing what you want. You have something that's basically "[{'a':2},{'b':3}]", and you're decoding it and getting the first element. And then iterating over it. But that's just {a: 2}.

Basically, it looks like you dropped the "[" .. content .. "]" from the decode line. That should always be present, because you're insuring against the possibility that the incoming payload isn't an object or array. The [1] serves to unwrap the payload from this extraneous array after it's been decoded.

As for the compile error, it's because you mixed up the numeric and generic for-loops. Numeric-for is "for i=start, end, step do"; generic-for is "for i, v in ipairs(t) do". You have an odd "for i=start, end in ipairs(t) do" sort of construct, which makes no sense to Lua.

[EDIT]: You should probably also use MUSHclient's "Edit -> Convert Clipboard Forum Codes" menu item to escape your [i]'s and such. Otherwise your post will end up italicized and with broken code, like what just happened.
Amended on Fri 10 Feb 2012 02:19 AM by Twisol
USA #32
Ok so I made those changes to the post using the MUSHclient Clipboard forum codes editor.

I'm a little clueless about using for loops in my code. The ones I have are ones Trevize showed me how to do and I changed them slightly as needed. I don't even know how what I'm trying to do would look.

Any code examples or help would be appreciated. Thanks!
USA #33
I think I got it!


for k,v in pairs (t) do

  system[system.char]  =  {

    skills  =  {

      [v.name]  =  {

        rank  =  v.rank,

        abilities  =  {

        },

      },

    },
	
  }

end
USA #34
Only change I would make at this point, is using ipairs() instead of pairs(). ipairs() goes over only integer indices (so it's for array-like tables), but guarantees to go over them in order. On the other hand, pairs() goes over every key in the table, but in an officially undefined manner.

Kevnuke said:
I'm a little clueless about using for loops in my code. The ones I have are ones Trevize showed me how to do and I changed them slightly as needed. I don't even know how what I'm trying to do would look.

Generic-for is traditionally harder to grasp than numeric-for for most learners of Lua. Essentially, in the line for k,v in pairs(t) you have two parts: the "iterator" on the right, and the loop variables on the left. Every iterator supplies its own set of loop variables. You could create your own iterator if you wanted; I've written a linked-list iterator in the past that was used like this:
for item, prev in links(t) do
  -- item is the current item
  -- prev is the previous item, in case you want to remove the current one.
end

Or an iterator could be written to loop forever, perhaps going over every item in an array and wrapping around at the end.
for i, v in circle(t) do
  -- around and around
  -- use 'break' to finish if necessary
end


Generic-for is called generic precisely because you can loop differently based on your needs.
Amended on Sat 11 Feb 2012 04:17 AM by Twisol
USA #35
I got the same result with pairs and ipairs. Is ipairs faster since it doesn't check non-numerical indices?
USA #36
They might come out to the same thing in this particular case, but ipairs() better expresses that you're iterating over a list, rather than arbitrary key/value pairs.

I don't think either one is faster than the other. They're just for different things.
USA #37
If there is a difference in speed it's probably negligible. You'd have to run the same thing through both functions a few million times to see the difference.

Should I even worry about things like that when writing my scripts? Like how much clock time a script will use?
USA #38
My mantra is to make it work first, then make it beautiful, and only after that should I make it fast. You might like to do the same. :)
Australia Forum Administrator #39
Kevnuke said:

Should I even worry about things like that when writing my scripts? Like how much clock time a script will use?


No, don't worry about that. Make it readable.
USA #40
Thanks for the help guys. That takes a load off of my mind. I should be okay with that now that I have a grasp on how to do that part. I believe I said before that I was going to make a table of all the rooms I come across in achaea using the room's ID number as the index and information about the room such as it's visible name and items in that room as a sub-table.


--see if this room is already in the map table and if not create an index for it containing an empty table
if not system.map[12346] then
  system.map[12346] = {}
end

system.map[12345] = {
  name         =  "Centre Crossing",
  description  =  "blah blah blah the center of Cyrene",
  exits        =  {
    n            =  system.map[12346],
    s            =  system.map[12347],
    e            =  system.map[12348],
    w            =  system.map[12349],
    in           =  system.map[12356],
    [dash east]  =  system.map[12389],
  },
  items  =  {
    system.items[874787],
    system.items[455729],
  }
}


I was going to make a for loop to check for the existence of an index in the system.map table for each room ID.

I'm a little confused as to the syntax to use on this though. Iterate through the named indices of the "exits" table resulting from using json.decode on the Room.Info message from GMCP.

like this..


t = json.decode("[" .. content .. "]")

-->

t[exits] = {
  n = 12346,
  s = 12347,
  e = 12348,
  w = 12349
}

Not sure how to make it check for each room in the exits table.

EDIT: I just had an idea. Is this it?


for k, v in pairs (t.exits) do
  if not system.map[v] then
    system.map[v] = {}
  end
end
Amended on Fri 17 Feb 2012 03:47 AM by Kevnuke
USA #41
Kevnuke said:
EDIT: I just had an idea. Is this it?


for k, v in pairs (t.exits) do
  if not system.map[v] then
    system.map[v] = {}
  end
end

Yep, that's it. Good work!

[EDIT]: You're using things like [exits] and [dash east], though, where I assume you meant ["exits"] and ["dash east"]. Careful there.
Amended on Fri 17 Feb 2012 04:04 AM by Twisol
USA #42
Twisol said:

You're using things like [exits] and [dash east], though, where I assume you meant ["exits"] and ["dash east"]. Careful there.


Yea something I need to be mindful of. Thanks for catching that!
USA #43
This is going to have to keep track of the room I was just in as well. unless IRE decides to add an entry in the exits object for the room ID of the room you end up in if you dash in that direction, or use non-standard movement like worm warp, wings, and the parthren gare. In the case of worm warp it would have to remove the room i'm in as the destination room of -that- room's worm warp exit too.

I'm wondering what kind of administrative distance value I'm going to assign for each type of movement. The value will be different depending on if that type of movement puts me at my destination or not. Worm warp has a few seconds of balance recovery, but if using it puts me in the destination room then it doesn't matter because there won't be any movement after that anyway.

I suppose if you have the dash ability, enough endurance, and a low enough ping it will always be faster than any other way of getting from one room to another on the same plane. I've already considered that certain routes might need a standard movement to "back up" a room or two back the way you came from a dash to put you into position to dash again. Unless the script that generates the route finds a faster way to get to that place that doesn't require taking that path.

Any other things I should consider for this endeavor?
USA #44
Had a quick question about your SendGMCP function Twisol. Does it handle GMCP messages with empty string payloads, like Char.Items.Inv or number payloads like Char.Items.Contents 128976?

I was going to use such messages in an alias for INFO RIFT and INFO INV and was thinking I might be better off just putting the relevant Telnet codes and GMCP message directly into SendPkt, like so..



	<alias
		match="^INFOINV$"
		enabled="y"
		regexp="y"
		ignore_case="y"
		sequence="100"
		send_to="12"
		script="ProvokeInventory"
	/>

function ProvokeInventory()

	SendPkt("\255\250\201Char.Items.Inv\255\240")

end

	<alias
		match="^INFOCONT (\d+)$"
		enabled="y"
		regexp="y"
		ignore_case="y"
		sequence="100"
		send_to="12"
		script="ProvokeContainer"
	/>

function ProvokeContainer (name, output, wildcs)

	SendGMCP ("Char.Items.Contents ", wildcs[1])

end



I'll have checks in there once I get everything setup correctly to make sure that the number I use is actually in my inventory or in the room I'm in and make sure it's a valid argument. Number not a string, for example. But does that at least work?
Amended on Mon 16 Apr 2012 07:25 AM by Nick Gammon
USA #45
Yea it didn't work..the aliases i'm making aren't provoking a response from the server. What's wrong with them?
Australia Forum Administrator #46

function ProvokeInventory()

	SendPkt("\255\250\201Char.Items.Inv\255\240")

end


That just defines a function. It doesn't execute it.
USA #47
Wow I can't believe I didn't catch that. Rookie mistake. Thanks Nick
USA #48
Sooo I have a brand new problem. I'm trying to integrate the new curing items from achaea into my curing system without completely rewriting it. First, here's the code:


herbaff		=	{

	"addiction",
	"agoraphobia",
	"asthma",
	"blind",
	"claustrophobia"

}

herbcure	=	{

	addiction		=	GinsengFerrumChoice() or "ginseng",
	agoraphobia		=	LobeliaArgentumChoice() or "lobelia",
	asthma			=	KelpAurumChoice() or "kelp",
	blind			=	BayberryArsenicChoice() or "bayberry",
	claustrophobia		=	LobeliaArgentumChoice() or "lobelia",

}

function GinsengFerrumChoice ()

	if outr.ginseng > 0 then

		return "ginseng"

	end

	if outr.ferrum > 0 then

		return "ferrum"

	end

	if inr.ginseng > 0 then

		return "ginseng"

	end

	if inr.ferrum > 0 then

		return "ferrum"

	end
	
end

function CureHerb ()

	for k, v in ipairs (herbaff) do

		if aff[v] then

			_G["herb"] = herbcure[v]

			if not (herb == "hawthorn") then

				if (tonumber(outr[herb]) > 0) then

					if EatGo() then

						HerbEat()
						Send ("eat " .. herbcure[v])

					return

					end

				elseif (tonumber(inr[herb]) > 0) then

					if OutrGo() then

						HerbOutr()
						Send ("outr " .. herbcure[v])

					return

					end

				end

			elseif balance.hawthorn then

				if (outr.hawthorn > 0) then

					if EatGo() then

						HerbEat()
						Send ("eat hawthorn")

					return

					end

				elseif (inr.hawthorn > 0) then

					if OutrGo() then

						HerbOutr()
						Send ("outr hawthorn")

					return

					end

				end

			return

			end

		end

	end

end



They pretty much made it so each affliction has two items that can cure it. My systems fine if I want to ONLY use the existing curing items, but i wanted to make it so that my curing system automatically uses the secondary item for each cure if I run out of the primary curing item. outr.<cure> refers to items that are in my inventory (and thus ready to be eaten) inr.<cure> refers to a cure that I have more of but are still in my rift.

In the case of the example function I showed, it would first check to see if I have ginseng in my inventory, then ferrum. If neither is in my inventory, it checks to see if either one is in my rift, checking ginseng first, then ferrum.
USA #49
Actually, I had an epiphany. I think I'm just going to scrap that idea and recode it to work around the two choices each being an index in the table for each affliction. Like so:


herbcure  =  {

  addiction		=	{"ginseng", "ferrum"},
  agoraphobia		=	{"lobelia", "argentum"},
  asthma		=	{"kelp", "aurum"},
  blind			=	{"bayberry", "arsenic"},
  claustrophobia	=	{"lobelia", "argentum"},

}

And then I'll modify the CureHerb function to make it work.