I have made a 2-part series of videos showing how to make an alias that requests your inventory and shows it in miniwindow on the top right-hand corner of your screen.
This illustrates something that is often asked: "how do I capture multiple lines?".
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("You are carrying:", 10)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if not string.match (line, "^ ") then
break
end -- if
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (inv) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.
The second alias (to hide the window) is as follows:
You can modify the alias shown to omit the inventory from the main window. To do this you need to modify the supplied wait.lua file in the lua folder of you MUSHclient installation.
Near the end of the file, change "match" and "regexp" as shown below (you can just replace them) ... the changes are in bold:
-- ----------------------------------------------------------
-- wait.regexp: we call this to wait for a trigger with a regexp
-- ----------------------------------------------------------
function regexp (regexp, timeout, flags)
local id = "wait_trigger_" .. GetUniqueNumber ()
threads [id] = assert (coroutine.running (), "Must be in coroutine")
check (AddTriggerEx (id, regexp,
"-- added by wait.regexp",
bit.bor (flags or 0, -- user-supplied extra flags, like omit from output
trigger_flag.Enabled,
trigger_flag.RegularExpression,
trigger_flag.Temporary,
trigger_flag.Replace,
trigger_flag.OneShot),
custom_colour.NoChange,
0, "", -- wildcard number, sound file name
"wait.trigger_resume",
12, 100)) -- send to script (in case we have to delete the timer)
-- if timeout specified, also add a timer
if timeout and timeout > 0 then
local hours, minutes, seconds = convert_seconds (timeout)
-- if timer fires, it deletes this trigger
check (AddTimer (id, hours, minutes, seconds,
"DeleteTrigger ('" .. id .. "')",
bit.bor (timer_flag.Enabled,
timer_flag.OneShot,
timer_flag.Temporary,
timer_flag.Replace),
"wait.timer_resume"))
check (SetTimerOption (id, "send_to", "12")) -- send to script
-- if trigger fires, it should delete the timer we just added
check (SetTriggerOption (id, "send", "DeleteTimer ('" .. id .. "')"))
end -- if having a timeout
return coroutine.yield () -- return line, wildcards
end -- function regexp
-- ----------------------------------------------------------
-- wait.match: we call this to wait for a trigger (not a regexp)
-- ----------------------------------------------------------
function match (match, timeout, flags)
return regexp (MakeRegularExpression (match), timeout, flags)
end -- function match
This lets you pass down extra flags to the trigger generated by the "match" function. The extra flags can be used to turn on "omit from output".
Then in the alias shown in the earlier post, change the two places it calls wait.match to add in the omit-from-output flag, like this:
local x = wait.match ("You are carrying:", 10, trigger_flag.OmitFromOutput)
...
local line, wildcards, styles = wait.match ("*", 0, trigger_flag.OmitFromOutput)
Now when you type "inv" only the miniwindow refreshes, and you don't see the inventory scroll by.
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.
This simple trigger detects when the MUD says you drop (or get, or buy) something, and then does "inv" which forces the alias to re-obtain your inventory.
Also, further testing reveals that sometimes the alias doesn't work, if a prompt appears before the inventory, like this:
<24hp 145m 110mv> <#21043> You are carrying:
(Magical) a finely honed sword
(Magical) a pitch-black longsword which flames brightly
(Magical) (Glowing) a rune-covered bag
a loaf of bread
a big chunk of beef
a cooked turkey
a slice of salami
a chocolate cake
an iron bracer
an iron shield
an iron visor
a bottle of milk
a cup of lemonade
a wheel of cheese
a steel dagger
The extra stuff before "You are carrying:" stops the trigger match. One way around that is to add a wildcard, like this:
local x = wait.match ("*You are carrying:", 10)
Now extra stuff at the front, like a prompt, won't cause the match to fail.
That's something I'd love to do, but it will probably require a fair bit of extra infrastructure. Even better would be some way for one plugin to supply widgets, and another to use those widgets. But that's a fair ways off.
I'm really glad to see someone else hopeful about the framework. :)
Aardwolf actually makes it very easy, because you can get the MUD to send you special tags around your inventory for this exact reason. To turn it on type:
tags inv on
Once you have turned inventory tags on, you see this:
{inventory}
a short stabbing sword (44)
(K) (Glow) (Hum) a long sleeved Aard Zoo tshirt (21)
( 2) (>Whispers of the Earth<) (41)
(K) (Glow) (Hum) -)Mask of Prediction(- (41)
( 3) (Glow) a bright ball of light (0)
( 3) henchman's leather vest (54)
( 5) a six shot rifle (54)
henchman's leather vest (56)
the scorpion style (39)
the centipede style (41)
(K) the iron head style (44)
(K) chin kang palm (35)
( 2) (K) a small bag (0)
(K) ashnod's Battlegear (35)
(Glow) a heavy slab of granite (36)
(K) (Hum) Vladia's Shopping List (1)
(K) a hemp bracelet (20)
{/inventory}
Then all you have to do is change the way you find the start and the end of your inventory. For example, change:
-- wait for inventory to start
local x = wait.match ("You are carrying:", 10)
to:
-- wait for inventory to start
local x = wait.match ("{inventory}", 10, trigger_flag.OmitFromOutput)
and:
-- see if end of inventory
if not string.match (line, "^ ") then
break
end -- if
to:
-- see if end of inventory
if string.match (line, "{/inventory}", trigger_flag.OmitFromOutput) then
break
end -- if
Note that the word "not" is gone from my second example, as we now match for finding something to see the end of the inventory, rather than not finding something.
I have turned inventory tags on and altered the by copy/paste the changes you suggested
display is
{inventory}
(K) (Magic) (Glow) (Hum) a demon school backpack (158)
(K) (Magic) (Glow) (Hum) a Bag of Aardwolf (47)
(K) (Magic) (Glow) (Hum) <(=Misc=)> (47)
(K) (Magic) (Glow) (Hum) <(=Portals=)> (47)
(K) (Magic) (Glow) (Hum) <(=AardEq=)> (47)
(K) (Magic) (Glow) (Hum) <(=Potions=)> (47)
( 4) (K) (Magic) (Glow) (Hum) Testament of the <(=Watchmen=)> (121)
(K) (Magic) (Hum) Aarianna's Testament (100)
{/inventory}
Does not gag, or create window for inventory.
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("{inventory}", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if string.match (line, "{/inventory}", trigger_flag.OmitFromOutput) then
break
end -- if
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (inv) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
<alias
match="noinv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
local win = GetPluginID () .. ":inventory"
WindowShow (win, false)
</send>
</alias>
</aliases>
<triggers>
<trigger
enabled="y"
match="^You (drop|get|buy) .+\.$"
regexp="y"
send_to="10"
sequence="100"
>
<send>inv</send>
</trigger>
</triggers>
Seems simple, also tried \{inventory\} but that didnt help either
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of inventory
if string.match (line, "{/inventory}") then
break
end -- if
Here is the whole alias, it seems to work OK for me now:
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("{inventory}", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of inventory
if string.match (line, "{/inventory}") then
break
end -- if
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (inv) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.
Can you please copy and paste the actual error? That will help sort it out.
hi , sorry for the late reply.
this is the error that pops up.
C:\MUDS\aardwolf\MUSHclient\lua\wait.lua:153: [string "Alias: "]:11: attempt to call global 'WindowInfo' (a nil value)
stack traceback:
[C]: ?
C:\MUDS\aardwolf\MUSHclient\lua\wait.lua:153: in function 'make'
[string "Alias: "]:5: in main chunk
does it has something to do with the client i downloaded ? it was the one Aardwold offered on their website ? i downloaded that since it was already configured with lots of stuff like stats , map and chat.
but then this error pops up when i want to make that miniwindow on Materia Magica...
Yes, probably you have a client that doesn't support miniwindows. The Aardwolf client plugins were pretty specific to their tags, you are better off downloading the latest one from this site. You can install on top of the Aardwolf one, it is basically the same program, you just have an earlier version.
The mud im playing on doesnt have the nice little tags so i was wondering if there was a change you could help me setting up an expetion so it include these (*) before the inventory.
(126/144hp 144/144m 100/100mv)
i
You are carrying:
(Glowing) a silver ring carved in the shape of a snake's tail
( 2) an iron kite shield
a ringmail shirt
(Humming) a bloodstained steel bardiche
(Glowing)(Humming) a potion of haste
a bronze necklace
a consecrated iron hammer
a floating disc
(126/144hp 144/144m 100/100mv) (126/144hp 144/144m 100/100mv)
<aliases>
<alias
name="inv"
match="inv"
enabled="y"
send_to="12"
sequence="40"
>
<send>require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("*You are carrying:", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", 0, trigger_flag.OmitFromOutput)
-- see if end of inventory
if not string.match (line, "^ ") and
not string.match (line, "^%([ %d]%d%) ") then
break
end -- if
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 4, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (inv) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine</send>
</alias>
</aliases>
In response to a query about how to move the window around, I have changed the alias into a plugin, and added a few extra lines that allow you to drag the inventory around by clicking on the top line (the one with Inventory on it).
To save and install the Inventory_Miniwindow_Demo plugin do this:
Copy the code below (in the code box) to the Clipboard
Open a text editor (such as Notepad) and paste the plugin code into it
Save to disk on your PC, preferably in your plugins directory, as Inventory_Miniwindow_Demo.xml
The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
Go to the MUSHclient File menu -> Plugins
Click "Add"
Choose the file Inventory_Miniwindow_Demo.xml (which you just saved in step 3) as a plugin
Click "Close"
Save your world file, so that the plugin loads next time you open it.
If you use this, remove your alias otherwise you will have two lots of inventory windows (the alias is now in the plugin).
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Sunday, May 02, 2010, 3:37 PM -->
<!-- MuClient version 4.51 -->
<!-- Plugin "Inventory_Miniwindow_Demo" generated by Plugin Wizard -->
<muclient>
<plugin
name="Inventory_Miniwindow_Demo"
author="Nick Gammon"
id="e49156f49854904ea8b90223"
language="Lua"
purpose="Shows Inventory in a miniwindow"
save_state="y"
date_written="2010-05-02 15:35:51"
requires="4.51"
version="1.0"
>
<description trim="y">
<![CDATA[
Type "inv" to see your inventory in a miniwindow.
]]>
</description>
</plugin>
<!-- Aliases -->
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
wait.make (function () -- coroutine starts here
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("You are carrying:", 10)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if not string.match (line, "^ ") then
break
end -- if
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + 2) + 10
-- make window correct size
WindowCreate (win,
windowinfo.window_left,
windowinfo.window_top,
window_width, window_height, -- width, height
windowinfo.window_mode,
windowinfo.window_flags,
ColourNameToRGB "#373737")
-- draw border
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- add the drag handler so they can move the window around
movewindow.add_drag_handler (win, 0, 0, 0, font_height)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (inv) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
-- now show the window
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
<!-- Script -->
<script>
<![CDATA[
require "wait" -- for waiting for inventory lines
require "movewindow" -- load the movewindow.lua module
win = GetPluginID () .. "_inventory"
font = "f"
function OnPluginInstall ()
-- install the window movement handler, get back the window position
windowinfo = movewindow.install (win, 6) -- default to 6 (on top right)
-- make window so I can grab the font info
WindowCreate (win, 0, 0, 0, 0, 1, 0, 0)
-- add the font
WindowFont (win, font, "Lucida Console", 9)
end -- OnPluginInstall
function OnPluginSaveState ()
-- save window current location for next time
movewindow.save_state (win)
end -- function OnPluginSaveState
]]>
</script>
</muclient>
Is there any way to remove the output from the screen because when I get all from backpack it overloads and boots me. And I cant seem to get the solution posted here to work where you edit the lua.wait file. PLEASE HELP ME.
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end)
Using Ver. 4.43
This is the script im using it creates the window fine I just cant figure out how to remove the inventory from the output and leave it in the miniwindow.
That seems like it should work. You're passing trigger_flag.OmitFromOutput to wait.match, and I just looked and it does properly pass that flag to MUSHclient. So it shouldn't be visible, unless it's not matching at all.
Also, what you said here confuses me:
Leonhardt said: when I get all from backpack it overloads and boots me.
By "boots me", do you mean that the MUD actually disconnects you? That's not something we can fix by gagging output. Gagging just hides things client-side, it changes nothing about what's sent between the client and the MUD.
Having trouble getting my inventory miniwindow to end the list at the prompt.
Heres my prompt:
[Cor:5000 Ener:9000 Blood:7316 ]>
Heres my trigger:
Send "inventory"
-- wait for inventory to start
local x = wait.match ("*You are carrying:", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of inventory
if string.match (line, "^[Cor*") then
break
end -- if
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
Heres my error message:
Error raised in trigger function (in wait module)
stack traceback:
[C]: in function 'match'
[string "Alias: "]:29: in function <[string "Alias: "]:3>
Run-time error
Plugin: Inventory_Miniwindow_Demo (called from world: Animus)
Function/Sub: wait.trigger_resume called by trigger
Reason: processing trigger "wait_trigger_38"
C:\Users\Nihilism\Desktop\MUSHclient\lua\wait.lua:67: [string "Alias: "]:29: malformed pattern (missing ']')
stack traceback:
[C]: in function 'error'
C:\Users\Nihilism\Desktop\MUSHclient\lua\wait.lua:67: in function <C:\Users\Nihilism\Desktop\MUSHclient\lua\wait.lua:59>
Lua regular expressions (and indeed MUSHclient ones) don't allow for solitary square brackets like that since they have a special meaning. They need to be "escaped". For regular expressions in triggers you put a backslash in front of them. For string.match you put a % symbol in front of them.
Ah see I just realized that when I pasted it on the forum, it didnt appear, but I knew it had to be escaped and used the backslash character right before the [, as outlined in
Okay, now it is giving me the following error, a few seconds after it sends "inventory" to the output window:
Error raised in timer function (in wait module).
stack traceback:
[C]: in function 'match'
[string "Alias: "]:29: in function <[string "Alias: "]:3>
Run-time error
Plugin: Inventory_Miniwindow_Demo (called from world: Animus)
Function/Sub: wait.timer_resume called by timer
Reason: processing timer "wait_trigger_114"
C:\Users\Nihilism\Desktop\MUSHclient\lua\wait.lua:51: [string "Alias: "]:29: bad argument #1 to 'match' (string expected, got nil)
stack traceback:
[C]: in function 'error'
C:\Users\Nihilism\Desktop\MUSHclient\lua\wait.lua:51: in function <C:\Users\Nihilism\Desktop\MUSHclient\lua\wait.lua:43>
Im using MUSHclient v4.61 and I looked in wait.lua and it seemed like the changes listed on page 1 were already there, but just to be sure I pasted the changed sections anyway, still gives same error. By the way I appreciate the help, very new to this.
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Sunday, May 02, 2010, 3:37 PM -->
<!-- MuClient version 4.51 -->
<!-- Plugin "Inventory_Miniwindow_Demo" generated by Plugin Wizard -->
<muclient>
<plugin
name="Inventory_Miniwindow_Demo"
author="Nick Gammon"
id="e49156f49854904ea8b90223"
language="Lua"
purpose="Shows Inventory in a miniwindow"
save_state="y"
date_written="2010-05-02 15:35:51"
requires="4.51"
version="1.0"
>
<description trim="y">
<![CDATA[
Type "inv" to see your inventory in a miniwindow.
]]>
</description>
</plugin>
<!-- Aliases -->
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
wait.make (function () -- coroutine starts here
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("*You are carrying:", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of inventory
if string.match (line, "^%[Cor") then
break
end -- if
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = 5000
local window_height = 8000
-- make window correct size
WindowCreate (win,
windowinfo.window_left,
windowinfo.window_top,
window_width, window_height, -- width, height
windowinfo.window_mode,
windowinfo.window_flags,
ColourNameToRGB "black")
-- draw border
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- add the drag handler so they can move the window around
movewindow.add_drag_handler (win, 0, 0, 0, font_height)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (inv) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
-- now show the window
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
<!-- Script -->
<script>
<![CDATA[
require "wait" -- for waiting for inventory lines
require "movewindow" -- load the movewindow.lua module
win = GetPluginID () .. "_inventory"
font = "f"
function OnPluginInstall ()
-- install the window movement handler, get back the window position
windowinfo = movewindow.install (win, 6) -- default to 6 (on top right)
-- make window so I can grab the font info
WindowCreate (win, 0, 0, 0, 0, 1, 0, 0)
-- add the font
WindowFont (win, font, "Lucida Console", 9)
end -- OnPluginInstall
function OnPluginSaveState ()
-- save window current location for next time
movewindow.save_state (win)
end -- function OnPluginSaveState
]]>
</script>
</muclient>
Edit: converted clipboard forum codes
Edit: Discovered the problem, changed the line
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
to
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", 0, trigger_flag.OmitFromOutput)
So it no longer errors, and does omit the inventory list from the main output window, but now it waits for another command to be entered (or even an empty string) before drawing the miniwindow.
Well done for spotting that! As for the wait, it is probably waiting for the prompt line which you are testing for. Maybe if you force it out somehow? Instead of:
Send "inventory"
you might do:
Send "inventory"
Send "look"
Or anything that forces out a prompt after the inventory.
Awesome, thank you. Ive used this basic format and have been able to create miniwindows for inventory, equipment, and score screens. Im also interested in how to have these windows occupy the same space but only display one at a time. My general thought is that you would make one window, add hotspots at the bottom for tabs, then when a tab is clicked you stop showing the current miniwindow and redraw the new one.
and attempted to dissect it to figure out how you are having the scripts switch between windows but at the moment its boggling me.
Another concern I have is maintaining positioning when switching windows. For example, if I have inventory showing and drag the window to the other side of the screen. Then I click to show equipment. Im guessing the new equipment window would draw back in the original location, and not the new location.
I think the tabs will be easier than maintaining multiple windows. The basic concept for tabbed windows is quite simple:
You have the "main" or "currently-displayed" tab which is the bulk of the window (eg. the top part if the tabs are at the bottom).
When you need to redraw the window you draw into the main area with a simple decision based on the currently selected tab. For example:
function redraw_main_window ()
if tab == "inventory" then
draw_inventory ()
elseif tab == "equipment" then
draw_equipment ()
elseif tab == "score" then
draw_score ()
end -- if
end -- function
Of course you can probably see ways of improving even that code, by using a table of tabs, with the tab name as the key and the function to draw the tab as the value.
At the bottom you draw your tabs using rectangles and text (or pre-rendered PNG files with the tabs in them). For example:
<Inventory> <Equipment> <Score>
Each tab is made into a hotspot, and when the hotspot is clicked on you change the "tab" variable. Eg. if <Inventory> is clicked on you do:
tab = "inventory"
redraw_main_window () -- does the decision above
You would have some way of knowing the current tab (eg. different colour, overlap the graphic, etc.).
With the displaying handled, the rest of the plugin handles gathering data, even if it isn't displayed right now. For example, if you get inventory information you still collect it into the inventory table, even though the inventory tab might not be visible. Then when you click on the inventory tab, it is ready to be displayed.
Thanks a ton Nick, Im working through it slowly but its coming along. One thing Ive come to is that when drawing the tabs, I followed this basic procedure:
1) draw a straight line horizontally at the bottom to separate the tabs from main window
2) use rounded rectangles for the tabs, with text drawn on top of each for tab lables
3) for the currently selected tab, draw a line the same color as the background on top of the above line so that the tab blends into the main window
Ive noticed it creates some small but odd edges at the top left and right corners of the active tab because of the rounded rectangle. I noticed you used Bezier curves to accomplish this but Im very bad with tables and I was wondering if you could explain some about how to use the Bezier's to create the rounded tab effect
But you might get a better result by just making a nice tab graphic in your favourite painting program, save as a PNG file, and just put a few of them next to each other (or do a separate graphic for each possible tab selected).
If you want more detail look up "Bezier curve" in Wikipiedia, although personally I find that, after understanding the first couple of paragraphs, the maths in the rest of it goes over my head a bit.
Ive been working with it this afternoon before I got a chance to see your post, and I actually ended up having a brainstorm, with seemingly pretty good results. I drew the tabs first, then laid the main rectangle over top of it, with the bottom edge overlapping the top of the tabs by a few pixels. The result is you get the nice rounded bottom corners but the top corners are buried. Im still looking into those curves though, because theres alot more that I could do with them.
I'm new to this client and I seem to be struggling, after trying the first section of the video where you merely test the command I can't get to work.
I get the message -
C:\Program Files (x86)\MUSHclient\lua\wait.lua:161: [string "Alias: "]:5: attempt to call global 'send' (a nil value)
stack traceback:
[C]: ?
C:\Program Files (x86)\MUSHclient\lua\wait.lua:161: in function 'make'
[string "Alias: "]:2: in main chunk
Obviously I'm doing something silly, I just cant see it, can you point me in the right direction.
Also you mention the wait module, do I install it and if so is it the same as a plugin?
The "wait" module should be already there, as part of the "lua" subdirectory when you installed the client. The problem was the capitalization of "send", as Twisol said.
One last thing on this subject and I will be done, and thanks for your help so far.
To see my inventory I get a double line after 'you are carrying' then the list of items I have. The code above stops as soon as it sees the line as it thinks the end of the inventory has been reached. Is there a way to have 'you are carrying:' as the search line but make it skip the next two lines before the list.
I've tried making the lines the trigger, but both lines are the same, so it stops as soon as the second line hits.
Please see below for what I mean
you are carrying:
-------------
-------------
A large brown sack
A dagger
Healing potions (5)
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
... just test for lines you don't want. Eg.
if line ~= "-------------" then
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- if wanted line
My miniwindow is blank with the exception of the word Inventory. The MUD I am applying this to is Achaea and it's inventory setup is different:
Ex)
You are holding:
obsidian dagger, 5 ebony vials, 2 oaken vials, a cherry wood vial, a simple fishing pole, a bait bucket, a snow blossom vial.
You are wearing:
a suit of ring mail, a canvas backpack
I attempted to change some lines as needed, but am uncertain as to what else I need or what is wrong with what I altered. Any input would be appreciated. Thanks!
The current script I have is as follows:
Quote: require "wait"
wait.make (function ()
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end
Send "inventory"
local x = wait.match ("You are holding:", 10)
if not x then
ColourNote ("white", "red", "No inventory was received within 10 seconds.")
return
end
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
while true do
local line, wildcards, styles = wait.match ("*")
if not string.match (line, "^You are wearing:") then
break
end
if not string.match (line, "^You are wearing:") then
break
end
That will make it stop as soon as it gets a line which doesn't match "You are wearing:". You probably want to lose the word "not", because you want go keep going until you do get the line, not until you don't get it.
Hi, this tutotorial is great!
I was able to create an Alias without much dificulty. However I quickly realized that I would need to convert this into a trigger.
After half a day of work, I was able to work out nearly all the bugs, however there's one thing I'm not sure how to do.
This is what the text looks like that I want put into a miniwindow:
-- Planter ---------------------------------------
| 1 | The Hondew Berry has sprouted.
| 2 | The Hondew Berry has sprouted.
| 3 | The Hondew Berry has sprouted.
|*4*| A Charti Berry was planted here.
--------------------------------------------------
| P# | Plant a berry |
| W# | Water a plant |
| H# | Harvest berries |
| X# | Destroy a plant |
| Q | Quit |
-------------------------
<Planter> What will you do?
And here's a copy of my conversion:
<triggers>
<trigger
enabled="y"
match="-- Planter ---------------------------------------"
send_to="12"
sequence="100"
>
<send>require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":planter"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- wait for inventory to start
local x = wait.match ("-- Planter*", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No planter data received within 10 seconds")
return
end -- if
local planter = {}
local max_width = WindowTextWidth (win, font, "Planter")
-- loop until end of planter data
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of planter data
if string.match (line, "<Planter> What will you do?") then
break
end -- if
-- save planter data lines
table.insert (planter, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#planter + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Planter", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (planter) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each planter data item
WindowShow (win, true)
end) -- end of coroutine
</send>
</trigger>
</triggers>
Just in case you wanted to know why I needed to convert it into a trigger - each time you issue a command, such as p1 to plant a seed at position 1, or w1 to water that position (etc), the data gets refreshed showing what has changed to include the seeds planted, or the watered status (indicated by the *#*).
By using a trigger I get around having to use +planter to update the window.
I'm also working on away to use the second Alias code you had to close the window after I quit the session, although simply using "Q" as a trigger here won't work.
:)
Well you don't need most of this, because being a trigger, you *know* you have the first line:
-- wait for inventory to start
local x = wait.match ("-- Planter*", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No planter data received within 10 seconds")
return
end -- if
local planter = {}
So you can probably replace it with:
local planter = { "%0" }
The %0 is "the matching line" from the trigger, so you pre-insert that line, and then the others get added as they arrive.
I attempted what you suggested but I ended up getting error after error. Each time I tried to fix an error a new one would show up. I was probably just making things worse and worse.
In other news, I was able to get the helpfil working. Turns out since I have Windows Vista, I needed to download something to allow me to view older helpfiles.
This is the error text I get when I follow your suggestion.
stack traceback:
[C]: in function 'ipairs'
[string "Trigger: "]:56: in function <[string "Trigger: "]:3>
Run-time error
World: PKFusion
Function/Sub: wait.trigger_resume called by trigger
Reason: processing trigger "wait_trigger_460"
C:\Program Files\MUs\MUSHClient\lua\wait.lua:67: [string "Trigger: "]:56: bad argument #1 to 'ipairs' (table expected, got string)
stack traceback:
[C]: in function 'error'
C:\Program Files\MUs\MUSHClient\lua\wait.lua:67: in function <C:\Program Files\MUs\MUSHClient\lua\wait.lua:59>
one time if even said this:
Error raised in trigger function (in wait module)
I'm going to keep looking but I appreciate the help.
The "ipairs" that it is talking about is where the code says " for _, style in ipairs (styles) do"
Here's the entire trigger. I hate to be a bother but I really appreciate you helping me understand how all this works.
<triggers>
<trigger
enabled="y"
match="-- Planter ---------------------------------------"
send_to="12"
sequence="100"
>
<send>require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":planter"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
local planter = { "%0" }
local max_width = WindowTextWidth (win, font, "Planter")
-- loop until end of planter data
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of planter data
if string.match (line, "<Planter> What will you do?") then
break
end -- if
-- save planter data lines
table.insert (planter, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#planter + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Planter", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (planter) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each planter data item
WindowShow (win, true)
end) -- end of coroutine
</send>
</trigger>
</triggers>
Oops. I made a mistake. The first table entry should have been the styles for that line, not just the line. This one works:
<triggers>
<trigger
enabled="y"
match="-- Planter ---------------------------------------"
send_to="14"
sequence="100"
>
<send>require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":planter"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
local planter = { TriggerStyleRuns }
local max_width = WindowTextWidth (win, font, "Planter")
-- loop until end of planter data
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of planter data
if string.match (line, "<Planter> What will you do?") then
break
end -- if
-- save planter data lines
table.insert (planter, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#planter + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Planter", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in ipairs (planter) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each planter data item
WindowShow (win, true)
end) -- end of coroutine
</send>
</trigger>
</triggers>
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.
That nearly worked perfectly! It was still showing the trigger line though for some reason. But I dug around in the help file and found something that worked to prevent that from showing up:
I also added the Alias to close the window. I'm very pleased with this progress, thank you very much Nick!!
I'm going to use this same type of thing for several other windows that I hope to create.
My big goal however is to create a window that doesn't pull output from the Mu*, but instead is based on a compilation of various useful commands that the muck uses (that I would define) that when you hover the mouse over a command, it gives you a brief message of what it does, and when you click on one of the commands it executes it.
with the new inventory you are noted of the amount of items you are carrying in the 5 spaces before the item.
how do you get around that?
Example: (copied from game)
You are carrying:
(10) (Glow) (Hum) (!(Griffon's Blood)!) (1)
(14) (!(Eyes of Allegiance)!) (4)
(12) (!(Eyes of the Wolf)!) (1)
(15) (!(Sight Beyond Sight)!) (1)
(19) (!(Triton Extract)!) (4)
(K) (Glow) a garbage can (6)
( 2) (Seekers) Elixir of Maneuverability (48)
(K) a magical pocket (180)
(K) (Glow) (Hum) Goblet of the Well Educated (1)
(K) Aylorian Academy canoe (1)
(K) (Glow) (Hum) a demon school backpack (157)
(K) a magical pocket (178)
( 4) Aylorian Academy packed lunch (1)
don't pay attention to 'what' i'm carrying, just the (##) in front of the items.
[EDIT] it works!! thank you very much!!
( i was almost going to start using the Bast inv,
but that one has an enormous annoying item id tab
that doesn't really work :P )
i'm trying to get a window to latch to the bottom of the inventory window.
the example is my demon school backpack.
completely watched your inv alias vids multiple times :P and changed everything i needed match it usable for the backpack.
only to get stuck right after tutorial1.
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID ( ) .. ":A Demon School Backpack"
local font = "f"
if not WindowInfo ( win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request backpack
Send "look in backpack"
-- wait for backpack to start
local x = wait.match ("The demon school backpack contains:", 10)
if not x then
ColourNote ("white", "blue", "No backpack received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "a demon school backpack")
-- loop until end of backpack
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of backpack
if not string.match (line, "^%([ %d]%d%) ") then
if not string.match (line, "^ ") then
break
end -- if
end -- if
save backpack line
table.insert (backpack, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
require "tprint"
tprint (backpack)
end) -- end of coroutine
ps: the only thing i wanted to know is how do i 'latch' it to the bottom of the inventory window, even if the inventory window resizes. but i first have to get the 'backpack' alias to work :P
did that. got the next message.
in 3 colours :P pink, light orange and dark orange :P
Error raised in trigger function (in wait module)
stack traceback:
[C]: in function 'insert'
[string "Alias: "]:43: in function <[string "Alias: "]:3>
Run-time error
World: Aardwolf
Function/Sub: wait.trigger_resume called by trigger
Reason: processing trigger "wait_trigger_10844"
C:\Aardwolf\MUSHclient\lua\wait.lua:67: [string "Alias: "]:43: bad argument #1 to 'insert' (table expected, got nil)
stack traceback:
[C]: in function 'error'
C:\Aardwolf\MUSHclient\lua\wait.lua:67: in function <C:\Aardwolf\MUSHclient\lua\wait.lua:59>
and right after that it shows the contents of backpack
I've been contemplating modifying this script to create a "Pager system"
On the MUCK I play on I'm pretty well known for putting chats on the wrong spot, for instance saying something on the public channel that was meant for a page to a specific player. This can have som serious implications if secret RP information is accidentally revealed.
Because of this issue that I have I have been thinking of building an Alias or trigger that, when issued, starts up a Pager window for the user specified. For instance,
"Pager Frank" would start a pager window for someone named Frank.
I want to make it so that there is a command prompt window at the bottom (similar to an Instant Messenger) that when you type anything into it, it automatically appends the text "page Frank" at the begining of the text.
Also, any output that has:
<page> Frank pages, "*", to you.
<page> In a page-pose to you, Frank *.
<page> You page, "*", to Frank.
<page> You page-pose *, to Frank.
should be redirected to that pager window.
Also, since conversations can get lengthy, is it possible to have a scroll bar for each pager window?
I've written some ideas for this down on paper but because of my long work hours I haven't had a chance to fully put it together.
Thanks for taking a look! No reply needed I just wanted to put this out there - possibly to see if it was doable, or if it has already been done since I searched the forum and couldn't find something that matched what I was looking for.
Edit: Actually I do have 1 question off the top of my head. Since I want to be able to open more than 1 window at a time, would this work to name the windows different each time?
when watching vid 2, almost complete, i get the next error after it lists whats in my backpack:
in 3 colours :P pink, light orange dark orange but i don't know if i can use the colours here.
Error raised in trigger function (in wait module)
stack traceback:
[C]: in function 'WindowCreate'
[string "Alias: "]:56: in function <[string "Alias: "]:3>
Run-time error
World: Aardwolf
Function/Sub: wait.trigger_resume called by trigger
Reason: processing trigger "wait_trigger_885"
C:\Aardwolf\MUSHclient\lua\wait.lua:67: [string "Alias: "]:56: bad argument #5 to 'WindowCreate' (number expected, got nil)
stack traceback:
[C]: in function 'error'
C:\Aardwolf\MUSHclient\lua\wait.lua:67: in function <C:\Aardwolf\MUSHclient\lua\wait.lua:59>
and this is what's inside my alias
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID ( ) .. ":A Demon School Backpack"
local font = "f"
if not WindowInfo ( win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request backpack
Send "look in backpack"
-- wait for backpack to start
local x = wait.match ("The demon school backpack contains:", 10)
if not x then
ColourNote ("white", "blue", "No backpack received within 10 seconds")
return
end -- if
local backpack = {}
local max_width = WindowTextWidth (win, font, "a demon school backpack")
-- loop until end of backpack
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of backpack
if not string.match (line, "^%([ %d]%d%) ") then
if not string.match (line, "^ ") then
break
end -- if
end -- if
--save backpack line
table.insert (backpack, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win , font , 1)
local window_width = max_width + 10
local window_heith = font_height * (#backpack + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 7, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "a Demon School Backpack", 5, 5, 0, 0, ColourNameToRGB (yellow))
-- draw each inventory line
local y = font_height * 2 + 5
for i, styles in pairs (backpack) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_eight
end -- for each backpack item
WindowShow (win, true)
end) -- end of coroutine
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. "Equipment"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 8, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request equipment
Send "eq"
-- wait for equipment to start
local x = wait.match ("You are using:", 10)
if not x then
ColourNote ("white", "blue", "No equipment recieved within 10 seconds")
return
end -- if
local equipment = {}
local max_width = WindowTextWidth (win, font, "You are using:")
-- loop until end of equipment
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of equipment
if not string.match (line, "^%[ [%a%d]%]: ") then
break
end -- if
-- save equipment line
table.insert (equipment, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#equipment + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 8, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Equipment", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each equipment line
local y = font_height * 2 + 5
for i, styles in pairs (equipment) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each equipment item
WindowShow (win, true)
end) -- end of coroutine
Can you give more information please. Not just quote tiny parts of what you are trying to match on. So you've posted the alias. Now post the entire thing (lines) from the MUD you are trying to match on.
<aliases>
<alias
name="equi"
match="equi"
enabled="y"
send_to="12"
sequence="100"
>
<send>require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. "Equipment"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 8, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request equipment
Send "eq"
-- wait for equipment to start
local x = wait.match ("You are using:", 10)
if not x then
ColourNote ("white", "blue", "No equipment recieved within 10 seconds")
return
end -- if
local equipment = {}
local max_width = WindowTextWidth (win, font, "You are using:")
-- loop until end of equipment
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of equipment
if not string.match (line, "^%[ [%a%d]%]: ") then
break
end -- if
-- save equipment line
table.insert (equipment, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#equipment + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 8, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Equipment", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each equipment line
local y = font_height * 2 + 5
for i, styles in pairs (equipment) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each equipment item
WindowShow (win, true)
end) -- end of coroutine</send>
</alias>
</aliases>
to drag the window around, does it has to be a plugin?
i know i like it when my inv and 2 backpacks are resizing at will on my right side of the window, because they see eachother.
but i would like to drag my equipment window around, which is created according to the inv alias.
cause it's size is stationary.
i read about the dragging, but i couldn't find the part where i can just copy/paste a specific part into my alias.
I need some help trying to figure out how to do this. I've searched this forum up and down using words I thought would relate to what I'm trying to do.
I want to use this code...
local battle = {}
local max_width = WindowTextWidth (win, font, "Battle")
-- loop until end of Battle text
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if string.match (line, "&lt;Battle&gt; Input command for *. +attack +item +switch +run") then
break
end -- if
-- save battle line
table.insert (battle, styles)
and make it break up multiple values on each line that are separated by the pipe character so I can turn them into variables and / or table values
I want to be able to turn each of these "table cells" into an actual table value so I can use them later (by displaying them in a mini window.
To explain the output above, Curtis owns a creature called Fang. Fang is a Rat. Joe owns a creature called Jason. Jason is a Bird.
Is there a simple way to do this, or should I follow the guidance on FAQ #37 and create multiple triggers to accomplish this?
In this case I simply need to have six seperate table items that I can refer to. I might consider using subtables to put "Fang" and "Rat" under "Curtis" and same with Joe.
This data gets refreshed during each turn where the "creature" might change.
All this stuff follows the basic idea in FAQ 37. You find a starting pattern (eg. "Your inventory is:"). You capture lines until an end pattern (eg. "End of inventory"). If there is no specific end pattern you just capture lines "that look like inventory".
In your case your starting line seems to be some "=" signs followed by one or more of O, X, S and so on. So that should be easy.
And the end seems to start with "<Battle>". So that's easy too.
As for the middle lines, excepting the hyphen lines, you should be able to break up the data, quite possibly by column position, trim trailing spaces, convert to numbers where appropriate, and save into a table.
All this stuff follows the basic idea in FAQ 37. You find a starting pattern (eg. "Your inventory is:"). You capture lines until an end pattern (eg. "End of inventory"). If there is no specific end pattern you just capture lines "that look like inventory".
In your case your starting line seems to be some "=" signs followed by one or more of O, X, S and so on. So that should be easy.
And the end seems to start with "<Battle>". So that's easy too.
As for the middle lines, excepting the hyphen lines, you should be able to break up the data, quite possibly by column position, trim trailing spaces, convert to numbers where appropriate, and save into a table.
I've already been able to put the data into a miniwindow, but I haven't quite been able to figure out how to turn the data into variables. I have no programming experience whatsoever (except formula building in Excel, which doesn't count), so I'm pretty much running with my head cut off trying to figure this out.
I'm the type of person who needs to understand every little thing about something to get that "aha!" moment where everything just clicks.
for instance,
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
I understand that "while true do" is a conditional statement.
I understand that "local line" is creating a variable called "line".
I also understand what " wait.match ("*", trigger_flag.OmitFromOutput)" is doing
but I don't really understand why/what the "wildcards, styles" part is doing here.
And although I really want to understand how that works, I REALLY want to know how to brake up a line of output into variables without creating a second trigger, and resorting to wildcards.
It will help to read the Programming in Lua book. Quite a nice read.
Anyway, functions in Lua can return multiple things.
So for a line like this:
line, wildcards, styles = wait.match (...)
We assume that wait.match is returning 3 things. And from the names we guess that we are getting back the matching line, any wildcards, and the style runs (the colours). There is only one wildcard in this particular case, so wildcards [1] and 'line' are going to be the same thing.
Your data looked pretty positional to me (ie. fixed-width) so the simplest thing would be to take "line" and just break it up. Say the first part was 20 characters long (after the "|" character) you might say:
mobname = string.sub (line, 2, 20)
Where 2 is the start column, and 20 is the end column.
A simple approach might be to take the raw inventory line, split it at commas (using string.gmatch) and then put each part of the inventory onto its own line.
I seem to have the same problem as Holliday did. Example:
In your inventory:
a vorpal platinum knife of havok
(Ghostly) A Pillar of Blue Flame
an Aesthetic's red velvet robe
a golden sash of metallic silk
( 2) a ring of rough influence
( 2) (Glowing) an etched steel bracer
(Tanned) a beautiful fur cloak
(Woven) a pair of fur leggings
a cloak of displacement
a gladiator shoulder pad
a gold earring
an owl-shaped wooden mask
a mage's robe of electrical resistance
a pair of green dragonleather riding boots
(Glowing) a pair of Albino Sleeves
(Glowing) a golden tiara
A Pair of Roc Claws
the Sphere of Astinus
a heavy clipboard
a brilliant white aura
(dinged) a burnished steel shield
I changed the match line to "In your inventory:" so the alias will work. It Brings up the Inventory window like it is supposed to but only puts the items in it up to where I have more then one of the same item. I have tried to change the if statement to break the loop to several different things and nothing I try seems to work. Unfortunately the mud I play doesn't do Inventory tags like Holliday's does. I though maybe my prompt line would work to break the loop but I cannot seem to get that to work either. Maybe Someone can help me here. This is my prompt line.
<1421/1421HP 1622/1622MP 2044XP Phase On PET: 2098/2098hp 500/500mv>
Never mind, I am an idiot sometimes. After reading some more of this topic... I.E. more pages ... I see that you already found and posted the solution to this problem.
I'm trying to do this for the who list. I watched the first part of the youtube and entered in tprint at the end to make sure it worked.
What I'm looking for is when you type "who"
you get
[IMP Djinn Mag ] [Discordia-GoS] Commander Astark Caldazar
[ 97 Gargoy Gla ] [Sehkma-Mem] Bethany slices and dices and makes Julienne cry!
[ 91 Orc Asn K] [Q-ool] Prince Dracmas <<Stalkingwolf>>
[ 7 Dracon Tem ] [Discordia-FoD] Rizk the Academy Student
Players found: 4
Here is the alias
<aliases>
<alias
match="wholist"
enabled="y"
send_to="12"
sequence="100"
>
<send>require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":who"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 8, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request who list
Send "who"
-- waiting to recieve who list
local x = wait.match ("[", 10)
if not x then
ColourNote ("white","blue","No who list recieved within 10 seconds")
return
end -- if statement
local who = {}
local max_width = WindowTextWidth (win, font, "Who List")
-- loop until end of who list
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of who list
if not string.match (line, "^[") then
break
end -- if
-- save who list
table.insert (who, styles)
--work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
require "tprint"
tprint (who)
end) -- end of coroutine</send>
</alias>
</aliases>
I'm not sure if it has to do with string.match or the brackets at this point, or if I just completely screwed up.
The first wait match was
local x = wait.match ("[", 10)
The end to see if it's the end of the list was:
if not string.match (line, "^[") then
I'm not sure if it's matching it before it goes into the string or not, so I dont know if it needs a backslash or a percent sign.
Or I could have messed up elsewhere. I get no errors, but it waits 10 seconds after I enter in the alias to tell me it didn't capture the who list.
wait.match takes "normal" wildcards, so you need to use an asterisk to indicate "and everything else", eg.
local x = wait.match ("[*", 10)
Regular expressions (as in string.match) treat "[" as a special character (start of set) so you need to "escape" that, eg.
if not string.match (line, "^%[") then
break
end -- if
With those two changes, the new alias, namely this:
<aliases>
<alias
match="wholist"
enabled="y"
send_to="12"
sequence="100"
>
<send>require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":who"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 8, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request who list
Send "who"
-- waiting to recieve who list
local x = wait.match ("[*", 10)
if not x then
ColourNote ("white","blue","No who list recieved within 10 seconds")
return
end -- if statement
local who = {}
local max_width = WindowTextWidth (win, font, "Who List")
-- loop until end of who list
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of who list
if not string.match (line, "^%[") then
break
end -- if
-- save who list
table.insert (who, styles)
--work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
require "tprint"
tprint (who)
end) -- end of coroutine</send>
</alias>
</aliases>
Gives this with your test data:
1:
1:
"textcolour"=12632256
"backcolour"=0
"length"=81
"style"=0
"text"="[ 97 Gargoy Gla ] [Sehkma-Mem] Bethany slices and dices and makes Julienne cry! "
2:
1:
"textcolour"=12632256
"backcolour"=0
"length"=59
"style"=0
"text"="[ 91 Orc Asn K] [Q-ool] Prince Dracmas <<Stalkingwolf>> "
3:
1:
"textcolour"=12632256
"backcolour"=0
"length"=59
"style"=0
"text"="[ 7 Dracon Tem ] [Discordia-FoD] Rizk the Academy Student"
The next problem. I'm not getting everything in the miniwindow.
Here's the output while using the script.
<4465/4465hp 1083/1083mn 2063/2063mv 359etl Q Clan Area> look
Before the Great Q Temple
Before you stands the mighty hall of the Q clan. I certainly hope you
are supposed to be here, because the rumours say that intruders are not
treated kindly inside the compound. As you gaze upon the mighty structure,
your mind is warped and twisted in such strange ways... How the HELL does
this thing stand without toppling over?! Chances are, your mind will never
be free enough to be able to comprehend the answer.
[Exits: north down]
(Drunk) A drunken funny man is here, telling jokes.
<4465/4465hp 1083/1083mn 2063/2063mv 359etl Q Clan Area> wholist
[IMP Djinn Mag ] [Discordia-GoS] Commander Astark Caldazar
[GOD Dryad Asn k] [Q-een] [AFK] * Lady Engel Shadowwalker
[ 92 Mantis Gla ] [Q-ool] Dozer.
[ 91 Orc Asn K] [Q-ool] Prince Dracmas <<Stalkingwolf>>
[ 15 Gholam Asn k] [Discordia-FoD] Zion I
Players found: 5
<4465/4465hp 1083/1083mn 2063/2063mv 359etl Q Clan Area>
I type wholist, which is echoed on the end of the prompt. before the who list starts. The problem is that I'm not seeing everyone on the list. I sometimes miss 2 people in the plugin if I use a trigger to catch people logging on and send to:execute wholist.
Using the Alias. The first name that shows up on the wholist miniwindow is Lady Engel. She disappears from the list when executing "wholist alias" from another trigger.
Here's the Alias:
<aliases>
<alias
match="wholist"
enabled="y"
send_to="12"
sequence="100"
>
<send>require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":who"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request who list
Execute "who"
-- waiting to recieve who list
local x = wait.match ("[*", 10)
if not x then
ColourNote ("white","blue","No who list recieved within 10 seconds")
return
end -- if statement
local whol = {} -- whol is who list as a table
local max_width = WindowTextWidth (win, font, "WhoList")
-- loop until end of who list
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of who list
if not string.match (line, "^%[") then
break
end -- if
-- save who list
table.insert (whol, styles)
--work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#whol + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#g373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "WhoList", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each who line
local y = font_height * 2 + 5
for i, styles in ipairs (whol) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each person in who
WindowShow (win, true)
end) -- end of coroutine</send>
</alias>
</aliases>
Edit: the trigger calling the alias where another name disappears off the miniwindow, being two players not showing instead of one is here:
I dont know if the who list right on the next line is causing it to miss the top player on here.
In the trigger that calls the alias when someone logs in, my command echo ends up on the info line, so my who list I need captureing, the first name ends up starting on the end of the prompt, then the 2nd name isnt shown.
<4465/4465hp 1083/1083mn 2063/2063mv 359etl Q Clan Area>
You disappear into the void.look
<4465/4465hp 1083/1083mn 2063/2063mv 359etl Limbo> Before the Great Q Temple
Before you stands the mighty hall of the Q clan. I certainly hope you
are supposed to be here, because the rumours say that intruders are not
treated kindly inside the compound. As you gaze upon the mighty structure,
your mind is warped and twisted in such strange ways... How the HELL does
this thing stand without toppling over?! Chances are, your mind will never
be free enough to be able to comprehend the answer.
[Exits: north down]
(Drunk) A drunken funny man is here, telling jokes.
<4465/4465hp 1083/1083mn 2063/2063mv 359etl Q Clan Area>
[INFO]: Sasuke has decided to join us.who
<4465/4465hp 1083/1083mn 2063/2063mv 359etl Q Clan Area> [IMP Djinn Mag ] [Discordia-GoS] Commander Astark Caldazar
[GOD Dryad Asn k] [Q-een] [AFK] * Lady Engel Shadowwalker
[ 97 Djinn Ran ] [Q-ool] Rojas
[ 92 Cyclop Gla K] [Q-ool] Sasuke the Gladiator Hero
[ 91 Orc Asn K] [Q-ool] Prince Dracmas <<Stalkingwolf>>
[ 15 Gholam Asn k] [Discordia-FoD] Zion I
Players found: 6
<4465/4465hp 1083/1083mn 2063/2063mv 359etl Q Clan Area>
Good point. In the original version the line which started the process off wasn't actually a line with a name on it. If we rejig a bit it works:
<aliases>
<alias
match="wholist"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":who"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 8, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request who list
Send "who"
local who = {}
local max_width = WindowTextWidth (win, font, "Who List")
-- waiting to recieve who list
local line, wildcards, styles = wait.match ("[*", 10)
if not line then
ColourNote ("white","blue","No who list recieved within 10 seconds")
return
end -- if statement
-- loop until end of who list
while true do
-- see if end of who list
if not string.match (line, "^%[") then
break
end -- if
-- save who list
table.insert (who, styles)
--work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
line, wildcards, styles = wait.match ("*")
end -- while loop
require "tprint"
tprint (who)
end) -- end of coroutine
</send>
</alias>
</aliases>
Output now:
1:
1:
"textcolour"=12632256
"backcolour"=0
"length"=61
"style"=0
"text"="[IMP Djinn Mag ] [Discordia-GoS] Commander Astark Caldazar "
2:
1:
"textcolour"=12632256
"backcolour"=0
"length"=81
"style"=0
"text"="[ 97 Gargoy Gla ] [Sehkma-Mem] Bethany slices and dices and makes Julienne cry! "
3:
1:
"textcolour"=12632256
"backcolour"=0
"length"=59
"style"=0
"text"="[ 91 Orc Asn K] [Q-ool] Prince Dracmas <<Stalkingwolf>> "
4:
1:
"textcolour"=12632256
"backcolour"=0
"length"=59
"style"=0
"text"="[ 7 Dracon Tem ] [Discordia-FoD] Rizk the Academy Student"
I was looking at your inventory plugin, specifically the part for window movement. The section it would be in would be at the top of the script (if you were just doing an alias and sending to script), at least from what I'm seeing. I'd like to be able to do this without a plugin though.
This is what I'm referring to:
<script>
<![CDATA[
require "wait" -- for waiting for inventory lines
require "movewindow" -- load the movewindow.lua module
win = GetPluginID () .. "_inventory"
font = "f"
function OnPluginInstall ()
-- install the window movement handler, get back the window position
windowinfo = movewindow.install (win, 6) -- default to 6 (on top right)
-- make window so I can grab the font info
WindowCreate (win, 0, 0, 0, 0, 1, 0, 0)
-- add the font
WindowFont (win, font, "Lucida Console", 9)
end -- OnPluginInstall
function OnPluginSaveState ()
-- save window current location for next time
movewindow.save_state (win)
end -- function OnPluginSaveState
]]>
</script>
I think the movewindow stuff only works in a plugin. I suppose you could duplicate the general idea outside one, but it would be simpler to turn your code into a plugin.
So something like, checking to see if the miniwindow is open for the first runing, use variables to set the miniwindow if it isnt there already. Then if the variables are already stored, move it to the window placement instead of creating the default location.
Then to reset, just delete the variables, maybe make an alias to do it.
Does this sound plausible?
I'd move the movewindow lua script into the main script as well of course.
I want to get to where I don't need to ask anymore about how the windows work. Slowly getting better at it, but allot still confuses me.
Also, for the mud I'm playing I've been noting everything on our own forums so other people can use mushclient as well. It'd be easier on some of them to just be able to select all and paste into the alias window.
Yes, but this is exactly what plugins were designed for.
To handle window dragging, your script has to respond to a mouse-down in the miniwindow. Now that isn't anything to do with someone typing an alias. And to handle loading stuff (like configuration) and saving stuff for next time, and other things, like doing something every minute, suddenly you are asking people to copy and paste a couple of aliases, copy and paste a couple of triggers, add a few timers, modify their script file, set the correct language, etc.
So instead of all this you say: download this file, install it, done!
Just a quick question is there an easy way to omit this output from my main display since it is going to the window any way. I know triggers have the flag for omitting output is their something similar for aliases?
Oh Sorry I missed that, since they had changed over to a trigger I glossed over it. One more question if I wanted to add a scroll bar to the inventory window and allow it to be resized what should I look at for reference?
Trying to get this working in my mud and having some difficulties, I got past the first few problems and its not giving any errors for now.
When the alias fires it doesn't recognize that the inventory is being displayed, most likely because of how the inventory is listed in this mud.
<aliases>
<alias
name="Inventory_Script"
match="inv"
enabled="y"
group="Inventory"
send_to="12"
sequence="100"
>
<send>require "wait"
wait.make (function ()
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "FixedSys", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("You are carrying (.*?)", 10)
if not x then
ColourNote ("white", "blue", "No inventory receieved within 10 seconds.")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if string.match (line, "^(.*?) | [Pain: (.*?)") then
break
end -- if
-- save inventory
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
require "tprint"
tprint (inv)
end)</send>
</alias>
</aliases>
Below is an example of output from my mud.
You are carrying four ruelbone monads, a bowie knife, a pair of green gauntlets, a pair of buckskin pants, a pair of green armwraps, a
silver-trimmed blue cloak, a wooden practice sword, and a canvas pouch.
-E-W-- | [Pain: 0 Fatigue: 0 Unbalance: 0 Fear: 0] | [///] >
The first few lines are my inventory and the last line is my prompt. Any suggestions on getting it to read each item?
I am baffled. I was able to get this to work in the past but now I’m running into an issue. The miniwindow is created and all the data is displayed inside as expected, but the text is not being omitted from the output window like I was striving for. I’m not sure if you would need to see the entire plugin since it seems to just be an issue with this section – I may have an error somewhere that I’m not seeing. I am operating on a Windows 8 computer, that wouldn’t cause an issue would it?
-- wait for list to start
local x = wait.match ("Player Name*", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No data received within 10 seconds")
return
end -- if
local data = {}
local max_width = WindowTextWidth (win, font, "Players")
-- loop until end of data
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of data
if string.match (line, "%d+ players are connected. %(Max was %d+%)") then
break
end -- if
Does anyone have any suggestions? If necessary I'll update this message with the full plugin - I just pulled it from earlier in this thread and modified "inv" and "inventory" to "WHO" and "player list" respectively - and added the OmitFromOutput flags.
I had thought I was using the most current version of MushClient but I'll double check that as well when I have the chance, in case it needs it.
You might want to try that, however I'm not sure it will fix this particular problem.
Alright, completed.
I noticed something today that I hadn't noticed before. One line is being omited from the output - the first wait.match.
here's the entire thing:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Sunday, May 02, 2010, 3:37 PM -->
<!-- MuClient version 4.51 -->
<!-- Plugin "PlayerList_Miniwindow_Demo" generated by Plugin Wizard -->
<muclient>
<plugin
name="PlayerList_Miniwindow_Demo"
author="Nick Gammon, mod by Curtis_D"
id="e49156f49854904ea8b90223"
language="Lua"
purpose="Shows list of players in a miniwindow"
save_state="y"
date_written="2010-05-02 15:35:51"
requires="4.51"
version="1.0"
>
<description trim="y">
<![CDATA[
Type "WHO" to see player list in a miniwindow.
]]>
</description>
</plugin>
<!-- Aliases -->
<aliases>
<alias
match="WHO"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":players"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request online player list
Send "WHO"
-- wait for list to start
local x = wait.match ("Player Name*", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No data received within 10 seconds")
return
end -- if
local data = {}
local max_width = WindowTextWidth (win, font, "Players")
-- loop until end of data
while true do
local line, wildcards, styles = wait.match ("*", trigger_flag.OmitFromOutput)
-- see if end of data
if string.match (line, "%d+ players are connected. %(Max was %d+%)") then
break
end -- if
-- save data line
table.insert (data, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#data + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Players", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each data line
local y = font_height * 2 + 5
for i, styles in ipairs (data) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each data item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
<!-- Script -->
<script>
<![CDATA[
require "wait" -- for waiting for inventory lines
require "movewindow" -- load the movewindow.lua module
win = GetPluginID () .. "_inventory"
font = "f"
function OnPluginInstall ()
-- install the window movement handler, get back the window position
windowinfo = movewindow.install (win, 6) -- default to 6 (on top right)
-- make window so I can grab the font info
WindowCreate (win, 0, 0, 0, 0, 1, 0, 0)
-- add the font
WindowFont (win, font, "Lucida Console", 9)
end -- OnPluginInstall
function OnPluginSaveState ()
-- save window current location for next time
movewindow.save_state (win)
end -- function OnPluginSaveState
]]>
</script>
</muclient>
The one with "Player name" in it? Yes, that isn't saved. Re-arrange a bit to do that:
-- wait for list to start
local line, wildcards, styles = wait.match ("Player Name*", 10, trigger_flag.OmitFromOutput)
if not line then
ColourNote ("white", "blue", "No data received within 10 seconds")
return
end -- if
local data = {}
-- save first line
table.insert (data, styles)
-- max width initially is the width of the first line
local max_width = WindowTextWidth (win, font, line)
-- loop until end of data
I saved the first line into the "data" table, therefore that will appear in the miniwindow.
The one with "Player name" in it? Yes, that isn't saved. Re-arrange a bit to do that:
-- wait for list to start
local line, wildcards, styles = wait.match ("Player Name*", 10, trigger_flag.OmitFromOutput)
if not line then
ColourNote ("white", "blue", "No data received within 10 seconds")
return
end -- if
local data = {}
-- save first line
table.insert (data, styles)
-- max width initially is the width of the first line
local max_width = WindowTextWidth (win, font, line)
-- loop until end of data
I saved the first line into the "data" table, therefore that will appear in the miniwindow.
Not tested, but that is the general idea.
Great, that would look better aesthetically. I'm still having the issue of my data not being omitted from the main window however. Should I look at the wait.match module to ensure it’s up to date as well, or would that have been updated when I updated mushclient? I’m at work again so I’ll have to look into it when I get home.
The wait.lua file should look like this (in part):
-- ----------------------------------------------------------
-- wait.regexp: we call this to wait for a trigger with a regexp
-- ----------------------------------------------------------
function regexp (regexp, timeout, flags)
local id = "wait_trigger_" .. GetUniqueNumber ()
threads [id] = assert (coroutine.running (), "Must be in coroutine")
check (AddTriggerEx (id, regexp,
"-- added by wait.regexp",
bit.bor (flags or 0, -- user-supplied extra flags, like omit from output
trigger_flag.Enabled,
trigger_flag.RegularExpression,
trigger_flag.Temporary,
trigger_flag.Replace,
trigger_flag.OneShot),
custom_colour.NoChange,
0, "", -- wildcard number, sound file name
"wait.trigger_resume",
12, 100)) -- send to script (in case we have to delete the timer)
-- if timeout specified, also add a timer
if timeout and timeout > 0 then
local hours, minutes, seconds = convert_seconds (timeout)
-- if timer fires, it deletes this trigger
check (AddTimer (id, hours, minutes, seconds,
"DeleteTrigger ('" .. id .. "')",
bit.bor (timer_flag.Enabled,
timer_flag.OneShot,
timer_flag.Temporary,
timer_flag.ActiveWhenClosed,
timer_flag.Replace),
"wait.timer_resume"))
check (SetTimerOption (id, "send_to", "12")) -- send to script
-- if trigger fires, it should delete the timer we just added
check (SetTriggerOption (id, "send", "DeleteTimer ('" .. id .. "')"))
end -- if having a timeout
return coroutine.yield () -- return line, wildcards
end -- function regexp
-- ----------------------------------------------------------
-- wait.match: we call this to wait for a trigger (not a regexp)
-- ----------------------------------------------------------
function match (match, timeout, flags)
return regexp (MakeRegularExpression (match), timeout, flags)
end -- function match
Important parts in bold. The "flags" argument (in your case trigger_flag.OmitFromOutput) should be passed to "match" which is then passed to "regexp". That then gets passed to AddTriggerEx.
I have been trying to get the original alias to work with the game that I play but have not had any success. It only shows a very small Inventory miniwindow with no text. Here is what my inventory looks like.
Inventory:
a rugged iron-buckled leather haversack (45.0 lbs)
a canvas scavenger's pack (9.0 lbs)
a bundle of maple (11.0 lbs)
a bundle of applewood (11.0 lbs)
a bundle of willow (43.0 lbs)
a bundle of hickory (79.0 lbs)
a small quiver of cypress arrows (0.0 lbs)
a small quiver of beechwood arrows (0.0 lbs)
a small quiver of bamboo arrows (0.0 lbs)
Carrying: 550 items (205.0 | 316.0) lbs.
You will notice that the first item of the inventory is not indented by one space like all of the others. Items can start with "a", "an", "some", " a", etc. How do I change the following code to allow for additional matches:
-- see if end of inventory
if not string.match (line, "^ ") then
break
end -- if
Addtionally, I would like to group like items together as the mud I play does not do that automatically. I have no idea on where to start with that.
Ok, I got the window to work by changing it to this:
-- see if end of inventory
if not string.match (line, "^%a") then
if not string.match (line, "^% a") then
if not string.match (line, "^%an") then
if not string.match (line, "^% an") then
if not string.match (line, "^%some") then
if not string.match (line, "^% some") then
break
end -- if
end -- if
end -- if
end -- if
end -- if
end -- if
Now, how do I go about sorting the inventory by item if the description matches exactly, including the weight as crafting items can have the same description but different weights?
That doesn't look right, there is no "% " in string.match.
You know you can have optional things, eg.
if not string.match (line, "^%an?") then
Matches "a" and "an".
Quote:
Now, how do I go about sorting the inventory by item if the description matches exactly, including the weight as crafting items can have the same description but different weights?
Write a custom sort function. It has to return true if a is less than b, so it would be like:
function my_sort_function (a, b)
-- name less than?
if a.name < b.name then return true end
-- name greater than?
if a.name > b.name then return false end
-- names the same, compare weights ...
-- weight less than
if a.weight < b.weight then return true end
-- not less than
return false
end -- function
That doesn't look right, there is no "% " in string.match.
You know you can have optional things, eg.
I realized that I do not have to include "%" at all for it to work. When I had initially tested it out, I had a trigger to omit blank lines. In order to account for it being turned off, I had to ad an additional if statement at the end. This is what it looks like:
-- see if end of inventory
if not string.match (line, "^an?") then
if not string.match (line, "^some") then
if not string.match (line, "^ an?") then
if not string.match (line, "^ some") then
if not string.match (line, "^$") then
break
end -- if
end -- if
end -- if
end -- if
end -- if
Thanks for the tip about multiple about including optional things. It forced me to do some research on regular expressions, much appreciated.
As far as the function to sort the items, that is far beyond my capabilities. I tried copying and pasting your example at the end of the alias but it doesn't work. I get the feeling that there is more that I'm supposed to do with it.
Edit: I figured a few things out between the time I originally posted this and now.
OK, this demonstrates the sorting. Modified code in bold. You can test for an optional space by doing " ?" as shown below.
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("Inventory:", 10)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if not string.match (line, "^ ?an?") then
if not string.match (line, "^ ?some") then
if not string.match (line, "^$") then
break
end -- if
end -- if
end -- if
if styles [1] then
styles.line = Trim (line)
styles.weight = tonumber (string.match (line, "%%(([0-9.]+) lbs?%%)"))
styles [1].text = string.gsub (styles [1].text, "^ ", "")
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- if at least one style
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
-- sort them
function my_sort_function (a, b)
-- name less than?
if a.line < b.line then return true end
-- name greater than?
if a.line > b.line then return false end
-- names the same, compare weights ...
-- weight less than
if a.weight and b.weight then
if a.weight < b.weight then return true end
end -- if
-- not less than
return false
end -- function
table.sort (inv, my_sort_function)
for i, styles in ipairs (inv) do
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.
I copied and pasted the alias and got several errors (or one long one) when attempting to use the alias.
Inventory:
Error raised in trigger function (in wait module)
stack traceback:
[string "Alias: "]:51: in function <[string "Alias: "]:5>
Run-time error
World: Shattered Isles
Function/Sub: wait.trigger_resume called by trigger
Reason: processing trigger "wait_trigger_15190"
C:\Program Files\MUSHclient\lua\wait.lua:67: [string "Alias: "]:51: attempt to index field '?' (a nil value)
stack traceback:
[C]: in function 'error'
C:\Program Files\MUSHclient\lua\wait.lua:67: in function <C:\Program Files\MUSHclient\lua\wait.lua:59>
a rugged iron-buckled leather haversack (31.0 lbs)
a canvas scavenger's pack (10.0 lbs)
Currency: 1 doubloon
Carrying: 599 items (68.0 | 316.0) lbs.
I am going to take this and attempt to consolidate the inventory by displaying multiple items on one line. The inventory for the game I'm playing doesn't do this already and the inventory can go on forever as it isn't capped at a certain number of items. Either that, or I will add a scrolling option to the window as I have seen others do.
I am getting an error now when I have more than one item in my inventory with matching description and weight.
Inventory:
a pearl-imbedded tin ATC supporter button (1.0 lb)
a canvas scavenger's pack (10.0 lbs)
a smooth bloodstone flame necklace (1.0 lb)
a long lead scepter (1.0 lb)
a long lead scepter (1.0 lb)
Error raised in trigger function (in wait module)
stack traceback:
[string "Alias: "]:91: in function <[string "Alias: "]:84>
[C]: in function 'sort'
[string "Alias: "]:98: in function <[string "Alias: "]:5>
Run-time error
World: Shattered Isles
Function/Sub: wait.trigger_resume called by trigger
Reason: processing trigger "wait_trigger_12348"
C:\Program Files\MUSHclient\lua\wait.lua:67: [string "Alias: "]:91: attempt to compare two nil values
stack traceback:
[C]: in function 'error'
C:\Program Files\MUSHclient\lua\wait.lua:67: in function <C:\Program Files\MUSHclient\lua\wait.lua:59>
Carrying: 600 items (70.0 | 316.0) lbs.
EDIT: I removed the weight portion (in bold) of the function below and it seems to be working now.
-- sort them
function my_sort_function (a, b)
-- name less than?
if a.line < b.line then return true end
-- name greater than?
if a.line > b.line then return false end
-- names the same, compare weights ...
-- weight less than
if a.weight < b.weight then return true end
-- not less than
return false
end -- function
table.sort (inv, my_sort_function)
You can get a bit fancier if you like. This amended version breaks your inventory into categories, by matching on keywords in the inventory.
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("Inventory:", 10)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
default_category = "Other"
inventory_type = {
Containers = { "pack", "bag", "sack", },
Weapons = { "scepter", "sword", },
Ammo = { "arrows", "bullets", },
Jewels = { "necklace", "bangle", "bracelet", },
[default_category] = { }, -- default
} -- end of inventory_type
category_count = 0
for name in pairs (inventory_type) do
category_count = category_count + 1
end -- for
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if not string.match (line, "^ ?an?") then
if not string.match (line, "^ ?some") then
if not string.match (line, "^$") then
break
end -- if
end -- if
end -- if
if styles [1] then
styles.line = Trim (line)
styles.weight = tonumber (string.match (line, "%%(([0-9.]+) lbs?%%)"))
styles [1].text = string.gsub (styles [1].text, "^ ", "")
for category, keywords in pairs (inventory_type) do
if styles.category then
break
end -- if
for _, item in ipairs (keywords) do
if string.find (line, item, 1, true) then
styles.category = category
break
end -- if found
end -- for each item
end -- for each category
if not styles.category then
styles.category = default_category
end -- if
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- if at least one style
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + (category_count * 2) + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
-- sort them
function my_sort_function (a, b)
-- category less than?
if a.category < b.category then return true end
-- category greater than?
if a.category > b.category then return false end
-- name less than?
if a.line < b.line then return true end
-- name greater than?
if a.line > b.line then return false end
-- names the same, compare weights ...
-- weight less than
if a.weight and b.weight then
if a.weight < b.weight then return true end
end -- if
-- not less than
return false
end -- function
table.sort (inv, my_sort_function)
old_category = nil
for i, styles in ipairs (inv) do
if styles.category ~= old_category then
y = y + font_height
WindowText (win, font, styles.category, 5, y, 0, 0, ColourNameToRGB "mediumorchid")
old_category = styles.category
y = y + font_height
end -- if new category
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.
Example output:
The part in bold above is the table of keywords. You can add more categories, and inside a category you have one or more words which, if matching, cause the item to go into that category. Once one match is found it stops looking. The default category is "Other" into which all un-matching things go.
Thank you. I always end up looking for something complex and I should know better to look for the simple fixes first. Good news is that I am now reading a beginner's guide to Lua so I can figure this stuff out on my own.
That being said, I do have another question(s). How do I remove duplicate items and show them like this:
FROM THIS:
a long lead scepter (1.0 lb)
a canvas scavenger's pack (30.0 lbs)
a small quiver of beechwood arrows (0.0 lbs)
a canvas scavenger's pack (12.0 lbs)
a long lead scepter (1.0 lb)
a small quiver of beechwood arrows (0.0 lbs)
a canvas scavenger's pack (12.0 lbs)
a canvas scavenger's pack (12.0 lbs
TO THIS:
a canvas scavenger pack (12.0 lbs) x3
a canvas scavenger pack (30.0 lbs)
a long lead scepter (1.0 lb) x2
a small quiver of beechwood arrows (0.0 lbs) x2
I have tried something like this but it seems to have no effect:
if a.line and a.weight == b.line and b.weight then
table.remove (inv)
end
It's probably clear from this example that I do not have a clear understanding of Lua. What value represents the completed inventory list that prints in the miniwindow?
I was able to look back in previous posts and got the omit from output to work. Now, I'd like to display the inventory in both the miniwindow as well as the output window.
I've tried:
print (inv)
but that's obviously wrong as well.
Any insight you can give is greatly appreciated.
p.s. I love the option to sort into categories. Thank you.
Yes, reading the Lua tutorials will help you make future changes. :)
Your idea of quantities is a good one. This seems to work:
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("Inventory:", 10)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
default_category = "Other"
inventory_type = {
Containers = { "pack", "bag", "sack", },
Weapons = { "scepter", "sword", },
Ammo = { "arrows", "bullets", },
Jewels = { "necklace", "bangle", "bracelet", },
[default_category] = { }, -- default
} -- end of inventory_type
category_count = 0
for name in pairs (inventory_type) do
category_count = category_count + 1
end -- for
-- for duplicates
existing_items = { }
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if not string.match (line, "^ ?an?") then
if not string.match (line, "^ ?some") then
if not string.match (line, "^$") then
break
end -- if
end -- if
end -- if
if styles [1] then
line = Trim (line)
styles.line = line
styles.weight = tonumber (string.match (line, "%%(([0-9.]+) lbs?%%)"))
styles [1].text = string.gsub (styles [1].text, "^ ", "")
for category, keywords in pairs (inventory_type) do
if styles.category then
break
end -- if
for _, item in ipairs (keywords) do
if string.find (line, item, 1, true) then
styles.category = category
break
end -- if found
end -- for each item
end -- for each category
if not styles.category then
styles.category = default_category
end -- if
-- look for a duplicate
item_number = existing_items [line]
-- if found, increase its quantity
if item_number then
inv [item_number].quantity = inv [item_number].quantity + 1
else
styles.quantity = 1 -- start with one of them
existing_items [line] = #inv + 1 -- remember its new position
-- save inventory line
table.insert (inv, styles)
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- if
end -- if at least one style
end -- while loop
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + (category_count * 2) + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
-- sort them
function my_sort_function (a, b)
-- category less than?
if a.category < b.category then return true end
-- category greater than?
if a.category > b.category then return false end
-- name less than?
if a.line < b.line then return true end
-- name greater than?
if a.line > b.line then return false end
-- names the same, compare weights ...
-- weight less than
if a.weight and b.weight then
if a.weight < b.weight then return true end
end -- if
-- not less than
return false
end -- function
table.sort (inv, my_sort_function)
old_category = nil
for i, styles in ipairs (inv) do
if styles.category ~= old_category then
y = y + font_height
WindowText (win, font, styles.category, 5, y, 0, 0, ColourNameToRGB "mediumorchid")
old_category = styles.category
y = y + font_height
end -- if new category
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
if styles.quantity > 1 then
WindowText (win, font, string.format (" x%i", styles.quantity), x, y, 0, 0, ColourNameToRGB "lightgreen")
end -- if
end -- for
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.
Modified code in bold. I used a separate table (existing_items) to detect duplicates. Since the weight is part of the line we don't have to test for that separately. If a line is a duplicate of an existing one, we just add one to the quantity for the existing item. Otherwise we create a new one and assign a quantity of one.
Then in the printing section we print any quantities greater than one.
This is phenomenal. I made a change to allow for the quantity. It was cutting off before.
local window_width = max_width + 40
It's also printing the quantity twice which is odd because it doesn't look like it should be.
[img]http://i60.tinypic.com/jkd6de.jpg[/img]
As you can see by the amount of items that I have in my inventory at the moment, this is a massive help without having to scroll through it to find items.
Edit: Image isn't showing. The quantities are at the end where they should be but they are also mixed in with the items at the very beginning of each line.
Ah yes, I didn't allow for the x22 being at the end of the longest line. I amended the code below to handle that better. Now it allows for the maximum quantity to be at the end of the longest line. It isn't perfect, because the longest line might have only one of them, but the worst that happens if you have a bit of a gap on the right.
Quote:
It's also printing the quantity twice which is odd because it doesn't look like it should be.
Oops, I had printing the quantity in the inner loop, so you must have had two style runs whereas I only had one in my test. I moved the quantity print outside the loop. That should work better.
<aliases>
<alias
match="inv"
enabled="y"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 9)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("Inventory:", 10)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
default_category = "Other"
inventory_type = {
Containers = { "pack", "bag", "sack", },
Weapons = { "scepter", "sword", },
Ammo = { "arrows", "bullets", },
Jewels = { "necklace", "bangle", "bracelet", },
[default_category] = { }, -- default
} -- end of inventory_type
category_count = 0
for name in pairs (inventory_type) do
category_count = category_count + 1
end -- for
-- for duplicates
existing_items = { }
max_quantity = 1
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*")
-- see if end of inventory
if not string.match (line, "^ ?an?") then
if not string.match (line, "^ ?some") then
if not string.match (line, "^$") then
break
end -- if
end -- if
end -- if
if styles [1] then
line = Trim (line)
styles.line = line
styles.weight = tonumber (string.match (line, "%%(([0-9.]+) lbs?%%)"))
styles [1].text = string.gsub (styles [1].text, "^ ", "")
for category, keywords in pairs (inventory_type) do
if styles.category then
break
end -- if
for _, item in ipairs (keywords) do
if string.find (line, item, 1, true) then
styles.category = category
break
end -- if found
end -- for each item
end -- for each category
if not styles.category then
styles.category = default_category
end -- if
-- look for a duplicate
item_number = existing_items [line]
-- if found, increase its quantity
if item_number then
inv [item_number].quantity = inv [item_number].quantity + 1
max_quantity = math.max (max_quantity, inv [item_number].quantity)
else
styles.quantity = 1 -- start with one of them
existing_items [line] = #inv + 1 -- remember its new position
-- save inventory line
inv [#inv + 1] = styles
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- if
end -- if at least one style
end -- while loop
max_quantity_digits = math.floor (math.log10 (max_quantity)) + 1
if max_quantity > 1 then
max_width = max_width + WindowTextWidth (win, font, string.format (" x%s", string.rep ("9", max_quantity_digits)))
end -- if
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + (category_count * 2) + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
-- draw each inventory line
local y = font_height * 2 + 5
-- sort them
function my_sort_function (a, b)
-- category less than?
if a.category < b.category then return true end
-- category greater than?
if a.category > b.category then return false end
-- name less than?
if a.line < b.line then return true end
-- name greater than?
if a.line > b.line then return false end
-- names the same, compare weights ...
-- weight less than
if a.weight and b.weight then
if a.weight < b.weight then return true end
end -- if
-- not less than
return false
end -- function
table.sort (inv, my_sort_function)
old_category = nil
for i, styles in ipairs (inv) do
if styles.category ~= old_category then
y = y + font_height
WindowText (win, font, styles.category, 5, y, 0, 0, ColourNameToRGB "mediumorchid")
old_category = styles.category
y = y + font_height
end -- if new category
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
if styles.quantity > 1 then
WindowText (win, font, string.format (" x%i", styles.quantity), x, y, 0, 0, ColourNameToRGB "lightgreen")
end -- if
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.
I have been playing around with the alias and have been trying to send the same info to the output window with ColourNote but it is only listing the items with quantities and putting an extra "0" too, like this:
Inventory:
Ammo
a small quiver of oak arrows (0.0 lbs) 0 x8
a small quiver of poplar arrows (0.0 lbs) 0 x13
Containers
Other
Resources
I put some lines in bold to note the changes I made to print in the output window.
<aliases>
<alias
match="inv"
enabled="y"
group="inventory"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 6)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("Inventory:", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
default_category = "Other"
inventory_type = {
Containers = { "pack", "bag", "sack", "backpack", "box", "chest", },
Weapons = { "scepter", "sword", "dirk", "dagger", },
Ammo = { "arrows", "bullets", "darts", },
Jewelry = { "necklace", "bangle", "bracelet", "ring", },
Resources = { "bundle", "salt", },
Armor = { "cuirass", "chestplate", "armor", },
[default_category] = { }, -- default
} -- end of inventory_type
category_count = 0
for name in pairs (inventory_type) do
category_count = category_count + 1
end -- for
-- for duplicates
existing_items = { }
max_quantity = 1
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", 0, trigger_flag.OmitFromOutput)
-- see if end of inventory
if not string.match (line, "^ ?an?") then
if not string.match (line, "^ ?some") then
if not string.match (line, "^$") then
break
end -- if
end -- if
end -- if
if styles [1] then
line = Trim (line)
styles.line = line
styles.weight = tonumber (string.match (line, "%%(([0-9.]+) lbs?%%)"))
styles [1].text = string.gsub (styles [1].text, "^ ", "")
for category, keywords in pairs (inventory_type) do
if styles.category then
break
end -- if
for _, item in ipairs (keywords) do
if string.find (line, item, 1, true) then
styles.category = category
break
end -- if found
end -- for each item
end -- for each category
if not styles.category then
styles.category = default_category
end -- if
-- look for a duplicate
item_number = existing_items [line]
-- if found, increase its quantity
if item_number then
inv [item_number].quantity = inv [item_number].quantity + 1
max_quantity = math.max (max_quantity, inv [item_number].quantity)
else
styles.quantity = 1 -- start with one of them
existing_items [line] = #inv + 1 -- remember its new position
-- save inventory line
inv [#inv + 1] = styles
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- if
end -- if at least one style
end -- while loop
max_quantity_digits = math.floor (math.log10 (max_quantity)) + 1
if max_quantity > 1 then
max_width = max_width + WindowTextWidth (win, font, string.format (" x%s", string.rep ("9", max_quantity_digits)))
end -- if
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + (category_count * 2) + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
ColourNote ("yellow", "black", "Inventory:")
-- draw each inventory line
local y = font_height * 2 + 5
-- sort them
function my_sort_function (a, b)
-- category less than?
if a.category < b.category then return true end
-- category greater than?
if a.category > b.category then return false end
-- name less than?
if a.line < b.line then return true end
-- name greater than?
if a.line > b.line then return false end
-- names the same, compare weights ...
-- weight less than
if a.weight and b.weight then
if a.weight < b.weight then return true end
end -- if
-- not less than
return false
end -- function
table.sort (inv, my_sort_function)
old_category = nil
for i, styles in ipairs (inv) do
if styles.category ~= old_category then
y = y + font_height
WindowText (win, font, styles.category, 5, y, 0, 0, ColourNameToRGB "lightgray")
ColourNote ("lightgray", "", (styles.category))
old_category = styles.category
y = y + font_height
end -- if new category
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
end -- for
if styles.quantity > 1 then
WindowText (win, font, string.format (" x%i", styles.quantity), x, y, 0, 0, ColourNameToRGB "lightgreen")
ColourNote ("mediumorchid", "", (styles.line .. " " .. styles.weight), "lightgreen", "", (string.format (" x%i", styles.quantity)))
end -- if
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
I am curious why it is not displaying the items with a quantity of 1 as well as why that "0" is showing up at the end of the item.
<aliases>
<alias
match="inv"
enabled="y"
group="inventory"
send_to="12"
sequence="100"
>
<send>
require "wait"
wait.make (function () -- coroutine starts here
local win = GetPluginID () .. ":inventory"
local font = "f"
if not WindowInfo (win, 1) then
WindowCreate (win, 0, 0, 0, 0, 6, 0, 0)
WindowFont (win, font, "Lucida Console", 6)
end -- if
-- request inventory
Send "inventory"
-- wait for inventory to start
local x = wait.match ("Inventory:", 10, trigger_flag.OmitFromOutput)
if not x then
ColourNote ("white", "blue", "No inventory received within 10 seconds")
return
end -- if
local inv = {}
local max_width = WindowTextWidth (win, font, "Inventory")
default_category = "Other"
inventory_type = {
Containers = { "pack", "bag", "sack", "backpack", "box", "chest", },
Weapons = { "scepter", "sword", "dirk", "dagger", },
Ammo = { "arrows", "bullets", "darts", },
Jewelry = { "necklace", "bangle", "bracelet", "ring", },
Resources = { "bundle", "salt", },
Armor = { "cuirass", "chestplate", "armor", },
[default_category] = { }, -- default
} -- end of inventory_type
category_count = 0
for name in pairs (inventory_type) do
category_count = category_count + 1
end -- for
-- for duplicates
existing_items = { }
max_quantity = 1
-- loop until end of inventory
while true do
local line, wildcards, styles = wait.match ("*", 0, trigger_flag.OmitFromOutput)
-- see if end of inventory
if not string.match (line, "^ ?an?") then
if not string.match (line, "^ ?some") then
if not string.match (line, "^$") then
break
end -- if
end -- if
end -- if
if styles [1] then
line = Trim (line)
styles.line = line
styles.weight = tonumber (string.match (line, "%%(([0-9.]+) lbs?%%)"))
styles [1].text = string.gsub (styles [1].text, "^ ", "")
for category, keywords in pairs (inventory_type) do
if styles.category then
break
end -- if
for _, item in ipairs (keywords) do
if string.find (line, item, 1, true) then
styles.category = category
break
end -- if found
end -- for each item
end -- for each category
if not styles.category then
styles.category = default_category
end -- if
-- look for a duplicate
item_number = existing_items [line]
-- if found, increase its quantity
if item_number then
inv [item_number].quantity = inv [item_number].quantity + 1
max_quantity = math.max (max_quantity, inv [item_number].quantity)
else
styles.quantity = 1 -- start with one of them
existing_items [line] = #inv + 1 -- remember its new position
-- save inventory line
inv [#inv + 1] = styles
-- work out max width
max_width = math.max (max_width, WindowTextWidth (win, font, line))
end -- if
end -- if at least one style
end -- while loop
max_quantity_digits = math.floor (math.log10 (max_quantity)) + 1
if max_quantity > 1 then
max_width = max_width + WindowTextWidth (win, font, string.format (" x%s", string.rep ("9", max_quantity_digits)))
end -- if
local font_height = WindowFontInfo (win, font, 1)
local window_width = max_width + 10
local window_height = font_height * (#inv + (category_count * 2) + 2) + 10
-- make window correct size
WindowCreate (win, 0, 0, window_width, window_height, 6, 0, ColourNameToRGB "#373737")
WindowRectOp (win, 5, 0, 0, 0, 0, 5, 15 + 0x1000)
-- heading line
WindowText (win, font, "Inventory", 5, 5, 0, 0, ColourNameToRGB "yellow")
ColourNote ("yellow", "black", "Inventory:")
-- draw each inventory line
local y = font_height * 2 + 5
-- sort them
function my_sort_function (a, b)
-- category less than?
if a.category < b.category then return true end
-- category greater than?
if a.category > b.category then return false end
-- name less than?
if a.line < b.line then return true end
-- name greater than?
if a.line > b.line then return false end
-- names the same, compare weights ...
-- weight less than
if a.weight and b.weight then
if a.weight < b.weight then return true end
end -- if
-- not less than
return false
end -- function
table.sort (inv, my_sort_function)
old_category = nil
for i, styles in ipairs (inv) do
if styles.category ~= old_category then
y = y + font_height
WindowText (win, font, styles.category, 5, y, 0, 0, ColourNameToRGB "lightgray")
ColourNote ("lightgray", "", (styles.category))
old_category = styles.category
y = y + font_height
end -- if new category
local x = 5
for _, style in ipairs (styles) do
x = x + WindowText (win, font, style.text, x, y, 0, 0, style.textcolour)
ColourTell (style.textcolour, style.backcolour, style.text)
end -- for
if styles.quantity > 1 then
WindowText (win, font, string.format (" x%i", styles.quantity), x, y, 0, 0, ColourNameToRGB "lightgreen")
ColourTell ("lightgreen", "", string.format (" x%i", styles.quantity))
end -- if
print "" -- finish off line
y = y + font_height
end -- for each inventory item
WindowShow (win, true)
end) -- end of coroutine
</send>
</alias>
</aliases>
You were only doing a ColourNote if the quantity was > 1 so naturally the other lines did not appear. I've put a ColourTell into the styles loop, which will preserve the style of the original (ie. the colour). I don't know about that zero, but it probably came from this:
styles.line .. " " .. styles.weight
The weight would have been zero (ie. not bold, underlined, etc.)