Mini-window for public chatter

Posted by Leonhardt on Wed 10 Nov 2010 04:07 AM — 122 posts, 511,073 views.

#0
I play a mud called Ansalon and I need help making a mini-window that the OOC,Tells and Says can go into for easy access while im in fights and such. Any help would be GREATLY appreciated as im very new to scripting.


Im using MushClient 4.58 not sure if this matter but thought I would add it just in case.
Amended on Wed 10 Nov 2010 04:09 AM by Leonhardt
Australia Forum Administrator #1
Fiendish did a scrolling chat window for Aardwolf which you could adapt:

http://code.google.com/p/aardwolfclientpackage/source/browse/trunk/Aardwolf_Chat_Capture_mw.xml

Alternatively, look at this thread:

http://www.gammon.com.au/forum/bbshowpost.php?id=10515

In there is a plugin (Messages_Window) which lets you send coloured text from a script (eg. a trigger) and have it scroll by in a miniwindow).

The Messages_Window plugin has the disadvantage that it doesn't scroll back, but for just keeping an eye on chats that could be adequate.

Fiendish's window however has scroll bars I think.
#2
I cant seem to get either of these to work for me as I said im really new to this whole scripting thing it took me 3 weeks to get your inventory window up and running. Would it be possible for you to post the working file for that fiendish one so I can just download the whole thing and paste it into my plugin folder?
Australia Forum Administrator #3
Well, to save creating a character on Ansalon can you at least paste a few lines of the sort of chatter you want captured?
#4
You say 'testing testing 123'
You tell Emilio 'testing testing 123'
You OOC 'testing testing 123'

These are the types of chatter Say,Tell and OOC.
Im wanting them to pop up in a miniwindow because while im playing the text sometimes flys by so fast I cant see when someone is trying to communicate.
Australia Forum Administrator #5
OK well I adapated Fiendish's plugin to make it work with non-Aardwolf MUDs.

Template:saveplugin=Chat_Capture_Miniwindow
To save and install the Chat_Capture_Miniwindow plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Chat_Capture_Miniwindow.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Chat_Capture_Miniwindow.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.



<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>

<!-- Bits of this plugin and ideas were borrowed and remixed from the MUSHclient community. http://www.gammon.com.au/forum/?id=9385 and others. -->
<!-- Modifications for Aardwolf and extra awesome sauce added by Fiendish with help from Orogan -->
<!-- Adapated by Nick Gammon for Smaug and similar MUDs -->

<muclient>
    <plugin
    name="Chat_Capture_Miniwindow"
    author="Fiendish"
    id="565dae21eb816a2fdb8d50f9"
    language="Lua"
    purpose="Move chats to a miniwindow"
    date_written="2010-04-04"
    date_modified="2011-01-05"
    requires="4.52"
    version="2.4"
    save_state="y"
    >
    
<description trim="y">
USAGE:

  chats echo on    : echo chats in main window
  chats echo off   : do not echo chats
  chats show       : show chats window
  chats hide       : hide chats window
  
  LH-click a line to copy it to the clipboard
  RH-click main window to see menu of options
  
  Click title bar to drag window.
</description>
  
</plugin>

<triggers>
    <trigger
    enabled="y"
    match="You say '*'"
    script="chats"
    omit_from_output="y"
    sequence="100"
    ></trigger>

    <trigger
    enabled="y"
    match="You tell * '*'"
    script="chats"
    omit_from_output="y"
    sequence="100"
    ></trigger>

    <trigger
    enabled="y"
    match="You OOC '*'"
    script="chats"
    omit_from_output="y"
    sequence="100"
    ></trigger>
</triggers>

<aliases>
    <alias
    script="chat_echo"
    match="^chats echo( on| off)?$"
    enabled="y"
    regexp="y"
    sequence="100"
    ignore_case="y"
    ></alias>

    <alias
    script="chat_show"
    match="chats show"
    enabled="y"
    sequence="100"
    ignore_case="y"
    ></alias>

    <alias
    script="chat_hide"
    match="chats hide"
    enabled="y"
    sequence="100"
    ignore_case="y"
    ></alias>
        
</aliases>

<script>
<![CDATA[

require "movewindow"  -- load the movewindow.lua module
require "copytable"

BODY_FONT_NAME = "Dina"
BODY_FONT_SIZE = 8
SCROLL_BAR_WIDTH = 15
MAX_LINES = 10000 -- how many lines to store in scrollback

-- date_format = "[%d %b %H:%M:%S] "        -- [30 Aug 13:29:49]   date and time 24 hour
-- date_format = "[%d %b %I:%M:%S%p] "  -- [30 Aug 01:20:12PM]     date and time 12 hour
-- date_format = "[%H:%M:%S] "          -- [13:29:08]          time 24 hour
-- date_format = "[%X] "                  -- [1:22:06 PM]            time 12 hour

TIMESTAMP_TEXT_COLOUR = "white"
TIMESTAMP_BACK_COLOUR = "black"

-- doing it this way makes them default to true the first time around
timestamp = not (GetVariable("timestamp") == "false")
echo = not (GetVariable("echo") == "false")

date_format = GetVariable("date_format")
WINDOW_WIDTH = tonumber(GetVariable("WINDOW_WIDTH"))
WINDOW_HEIGHT = tonumber(GetVariable("WINDOW_HEIGHT"))

-- offset of text from edge
TEXT_INSET = 5

-- where to store the chat line
lines = {}  -- table of recent chat lines
rawlines = {}

lineStart = ""
lineEnd = ""
WINDOW_COLUMNS = ""
WINDOW_LINES = ""

theme = {
    WINDOW_BACKGROUND = ColourNameToRGB ("#000000"), -- for miniwindow body
    WINDOW_BORDER = ColourNameToRGB("#E8E8E8"), -- for miniwindow body
    
    HIGHLIGHT=ColourNameToRGB("#FFFFFF"), -- for 3D surfaces
    FACE=ColourNameToRGB("#D4D0C8"), -- for 3D surfaces
    INNERSHADOW=ColourNameToRGB("#808080"), -- for 3D surfaces
    OUTERSHADOW = ColourNameToRGB("#404040"), -- for 3D surfaces
   
    BACK_FACE = ColourNameToRGB ("#E8E8E8"), -- for contrasting details
    DETAIL = ColourNameToRGB ("#000000"), -- for contrasting details

    TITLE_HEIGHT = 17, -- for miniwindow title area
    SUBTITLE_HEIGHT = 17, -- for miniwindow title area
    TITLE_FONT_NAME = "Dina", -- for miniwindow title area
    TITLE_FONT_SIZE = 8 -- for miniwindow title area
}  -- end theme table


-- replacement for WindowRectOp action 5, which allows for a 3D look while maintaining color theme
-- Requires global theme.HIGHLIGHT, theme.FACE, theme.INNERSHADOW, and theme.OUTERSHADOW rgb colors to be set.
function DrawThemed3DRect(Window, left, top, right, bottom)
    WindowRectOp(Window, miniwin.rect_fill, left, top, right, bottom, theme.FACE)
    WindowLine(Window, left, top, right, top, theme.HIGHLIGHT, 
                miniwin.pen_solid + miniwin.pen_endcap_flat, 1)
    WindowLine(Window, left, top, left, bottom, theme.HIGHLIGHT, 
                miniwin.pen_solid + miniwin.pen_endcap_flat, 1)
    WindowLine(Window, left, bottom-2, right, bottom-2, theme.INNERSHADOW, 
                miniwin.pen_solid + miniwin.pen_endcap_flat, 1)
    WindowLine(Window, right-2, top, right-2, bottom-2, theme.INNERSHADOW, 
                miniwin.pen_solid + miniwin.pen_endcap_flat, 1)
    WindowLine(Window, left, bottom-1, right, bottom-1, theme.OUTERSHADOW, 
                miniwin.pen_solid + miniwin.pen_endcap_flat, 1)
    WindowLine(Window, right-1, top, right-1, bottom-1, theme.OUTERSHADOW, 
                miniwin.pen_solid + miniwin.pen_endcap_flat, 1)    
end

function DrawThemedResizeTag(Window, x1, y1, size)
    local x2, y2 = x1+size, y1+size
    DrawThemed3DRect(Window, x1, y1, x2, y2)
    local m = 2
    local n = 2
    while (x1+m+2 <= x2-3 and y1+n+1 <= y2-4) do
        WindowLine(Window, x1+m+1, y2-4, x2-3, y1+n, theme.HIGHLIGHT, 
                    miniwin.pen_solid, 1)
        WindowLine(Window, x1+m+2, y2-4, x2-3, y1+n+1, theme.INNERSHADOW, 
                    miniwin.pen_solid, 1)
        m = m+3
        n = n+3
    end
end  -- function DrawThemedResizeTag


Win = GetPluginID()
font_height = ""
line_height = ""
windowinfo = ""
startx = ""
starty = ""

function ResizeMoveCallback()
    posx, posy = WindowInfo (Win, 17), WindowInfo (Win, 18)
    if (WindowTextWidth(Win, "titlefont"..Win, "WWWCOMMUNICATION")+2*SCROLL_BAR_WIDTH <= WINDOW_WIDTH+posx-startx) then
        WINDOW_WIDTH = WINDOW_WIDTH+posx-startx
        startx = posx
    end  -- if
    if (3*SCROLL_BAR_WIDTH+10+line_height+theme.TITLE_HEIGHT <= WINDOW_HEIGHT+posy-starty) then
        WINDOW_HEIGHT = WINDOW_HEIGHT+posy-starty
        starty = posy
    end -- if
    init(false)
end -- function ResizeMoveCallback

function ResizeReleaseCallback()
    WINDOW_HEIGHT = theme.TITLE_HEIGHT+(line_height*(WINDOW_LINES-1))+3
    init(true)
end  -- ResizeReleaseCallback

function OnPluginInstall()
    -- Dummy window to get font characteristics
    check (WindowCreate (Win, 0, 0, 1, 1, 0, 0, theme.WINDOW_BACKGROUND) )
    check (WindowFont(Win, "bodyfont"..Win, BODY_FONT_NAME, BODY_FONT_SIZE))
    check (WindowFont(Win, "titlefont"..Win, theme.TITLE_FONT_NAME, theme.TITLE_FONT_SIZE))
    font_height = WindowFontInfo (Win, "bodyfont"..Win, 1) -  WindowFontInfo (Win, "bodyfont"..Win, 4) + 1
    line_height = font_height+1
    font_width = WindowTextWidth (Win, "bodyfont"..Win, "W")
    
    -- install the window movement handler, get back the window position
    windowinfo = movewindow.install (Win, miniwin.pos_top_right, miniwin.create_absolute_location, true)

    -- check for Echo/Timestamp/date_format/window size (in pixels) variables, if not there, set them
    if date_format == nil then
        date_format = "[%d %b %H:%M:%S] "
    end -- if
    if WINDOW_WIDTH == nil then
        WINDOW_WIDTH = (font_width*80)+SCROLL_BAR_WIDTH -- 80 columns
    end
    if WINDOW_HEIGHT == nil then
        WINDOW_HEIGHT = theme.TITLE_HEIGHT+(line_height*6)+2 -- 6 lines
    end -- if
    init(true)
    OnPluginEnable ()  -- do initialization stuff
end -- function OnPluginInstall

function init(firstTime)
    -- how many lines and columns will fit?
    WINDOW_LINES = math.ceil((WINDOW_HEIGHT-theme.TITLE_HEIGHT)/line_height)
    WINDOW_COLUMNS = math.ceil((WINDOW_WIDTH-SCROLL_BAR_WIDTH)/font_width)

    if firstTime then
        WindowCreate(Win, windowinfo.window_left, windowinfo.window_top, WINDOW_WIDTH, WINDOW_HEIGHT, windowinfo.window_mode, windowinfo.window_flags, theme.WINDOW_BACKGROUND)

        -- catch for right-click menu and line selection
        WindowAddHotspot(Win, "textarea", 0, theme.TITLE_HEIGHT, WINDOW_WIDTH-SCROLL_BAR_WIDTH,0, 
            "", "", "MouseDown", "CancelMouseDown", "MouseUp", "", 
            miniwin.cursor_ibeam, 0)
        -- add the drag handler so they can move the window around
        movewindow.add_drag_handler (Win, 0, 0, 0, theme.TITLE_HEIGHT)
        
        -- scroll bar up/down buttons
        WindowAddHotspot(Win, "up", WINDOW_WIDTH-SCROLL_BAR_WIDTH, theme.TITLE_HEIGHT, 0, theme.TITLE_HEIGHT+SCROLL_BAR_WIDTH, 
            "MouseOver", "CancelMouseOver", "MouseDown", "CancelMouseDown", "MouseUp", "", 
            miniwin.cursor_hand, 0)
        WindowAddHotspot(Win, "down", WINDOW_WIDTH-SCROLL_BAR_WIDTH, WINDOW_HEIGHT-(2*SCROLL_BAR_WIDTH), 0, WINDOW_HEIGHT-SCROLL_BAR_WIDTH, 
            "MouseOver", "CancelMouseOver", "MouseDown", "CancelMouseDown", "MouseUp", "", 
            miniwin.cursor_hand, 0)

        -- add the resize widget hotspot
        WindowAddHotspot(Win, "resizer", WINDOW_WIDTH-SCROLL_BAR_WIDTH, WINDOW_HEIGHT-SCROLL_BAR_WIDTH, WINDOW_WIDTH, WINDOW_HEIGHT, 
            "MouseOver", "CancelMouseOver", "MouseDown", "CancelMouseDown", "MouseUp", "", 
            miniwin.cursor_nw_se_arrow, 0)
        WindowDragHandler(Win, "resizer", "ResizeMoveCallback", "ResizeReleaseCallback", 0)    
    else
        WindowResize(Win, WINDOW_WIDTH, WINDOW_HEIGHT, theme.WINDOW_BACKGROUND)
        WindowMoveHotspot(Win, "textarea", 0, theme.TITLE_HEIGHT, WINDOW_WIDTH-SCROLL_BAR_WIDTH, 0)
        WindowMoveHotspot(Win, "up", WINDOW_WIDTH-SCROLL_BAR_WIDTH, theme.TITLE_HEIGHT, 0, theme.TITLE_HEIGHT+SCROLL_BAR_WIDTH)
        WindowMoveHotspot(Win, "down", WINDOW_WIDTH-SCROLL_BAR_WIDTH, WINDOW_HEIGHT-(2*SCROLL_BAR_WIDTH), 0, WINDOW_HEIGHT-SCROLL_BAR_WIDTH)
        WindowMoveHotspot(Win, "resizer", WINDOW_WIDTH-SCROLL_BAR_WIDTH, WINDOW_HEIGHT-SCROLL_BAR_WIDTH, WINDOW_WIDTH, 0)
    end -- if
    WindowShow(Win, true)
    
    if (firstTime == true) then
        lines = {}
        for _,styles in ipairs(rawlines) do 
            fillBuffer(styles)
        end  -- for each line
    end -- if

    lineStart = math.max(1, #lines-WINDOW_LINES+2)
    lineEnd = math.max(1, #lines)
    refresh()
end  -- function init

function OnPluginClose ()
    -- if enabled
    if GetPluginInfo (GetPluginID(), 17) then
        OnPluginDisable()
    end -- if enabled
end -- function OnPluginClose

function OnPluginEnable ()
    WindowShow (Win, true)
end -- function OnPluginEnable

function OnPluginSaveState ()
    -- save window current location for next time  
    SetVariable ("enabled", tostring (GetPluginInfo (GetPluginID(), 17)))
    movewindow.save_state (Win)
    -- save echo/timestamp status
    SetVariable ("echo", tostring (echo))
    SetVariable ("timestamp", tostring (timestamp))
    SetVariable("date_format", date_format)
    SetVariable("WINDOW_WIDTH", WINDOW_WIDTH)
    SetVariable("WINDOW_HEIGHT", WINDOW_HEIGHT)
end -- function OnPluginSaveState

function OnPluginDisable ()
    WindowShow( Win, false )
end -- function OnPluginDisable

-- display one line
function Display_Line (line, styles)
 
  local left    = TEXT_INSET
  local top     = theme.TITLE_HEIGHT + (line * line_height) + 1
  local bottom  = top + line_height
  local font    = "bodyfont" .. Win

  if backfill then
      WindowRectOp (Win, miniwin.rect_fill, 1, top, WINDOW_WIDTH - SCROLL_BAR_WIDTH, bottom, ColourNameToRGB("#333333"))
  end -- backfill
  
  if (styles) then
    for _, style in ipairs (styles) do
      local width = WindowTextWidth (Win, font, style.text) -- get width of text
      local right = left + width
      WindowRectOp (Win, miniwin.rect_fill, left, top, right, bottom, style.backcolour)  -- draw background
      WindowText (Win, font, style.text, left, top, 0, 0, style.textcolour)  -- draw text
      left = left + width  -- advance horizontally
    end -- for each style run        
  end -- if  styles
  
end -- Display_Line


-- display all visible lines
function writeLines()
    for count = lineStart, lineEnd do
        Display_Line( count-lineStart, lines[count][1], false )
    end  -- for each line
    Redraw()

end  -- function writeLines

-- clear and redraw
function refresh()
    WindowRectOp(Win, miniwin.rect_fill, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, theme.WINDOW_BACKGROUND)
    drawStuff()
end  -- function refresh

barPos = ""
barSize = ""
totalSteps = ""

function drawStuff()
    -- draw border
    WindowRectOp (Win, miniwin.rect_frame, 0, 0, 0, 0, theme.WINDOW_BORDER)
    
    -- Title bar
    DrawThemed3DRect(Win, 0, 0, WINDOW_WIDTH, theme.TITLE_HEIGHT)

    -- Title text
    WindowText(Win, "titlefont"..Win, "COMMUNICATION", ((WINDOW_WIDTH)-(7.5*line_height))/2, (theme.TITLE_HEIGHT-line_height)/2, WINDOW_WIDTH, theme.TITLE_HEIGHT, theme.DETAIL, false)

    if #lines >= 1 then
        writeLines()
    end -- if
        
    -- Scrollbar base
    WindowRectOp(Win, miniwin.rect_fill, WINDOW_WIDTH-SCROLL_BAR_WIDTH, theme.TITLE_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT, theme.BACK_FACE) -- scroll bar background
    WindowRectOp(Win, miniwin.rect_frame, WINDOW_WIDTH-SCROLL_BAR_WIDTH+1, SCROLL_BAR_WIDTH+theme.TITLE_HEIGHT+1, WINDOW_WIDTH-1, WINDOW_HEIGHT-(2*SCROLL_BAR_WIDTH)-1, theme.DETAIL) -- scroll bar background inset rectangle
    DrawThemed3DRect(Win, WINDOW_WIDTH-SCROLL_BAR_WIDTH, theme.TITLE_HEIGHT, WINDOW_WIDTH, theme.TITLE_HEIGHT+SCROLL_BAR_WIDTH) -- top scroll button
    DrawThemed3DRect(Win, WINDOW_WIDTH-SCROLL_BAR_WIDTH, WINDOW_HEIGHT-(SCROLL_BAR_WIDTH*2), WINDOW_WIDTH, WINDOW_HEIGHT-SCROLL_BAR_WIDTH) -- bottom scroll button
    
    -- draw triangle in up button
    points = string.format ("%i,%i,%i,%i,%i,%i", (WINDOW_WIDTH-SCROLL_BAR_WIDTH)+2, theme.TITLE_HEIGHT+8,(WINDOW_WIDTH-SCROLL_BAR_WIDTH)+6, theme.TITLE_HEIGHT+4,(WINDOW_WIDTH-SCROLL_BAR_WIDTH)+10, theme.TITLE_HEIGHT+8)
    WindowPolygon (Win, points,
        theme.DETAIL, miniwin.pen_solid, 1,   -- pen (solid, width 1)
        theme.DETAIL, miniwin.brush_solid, --brush (solid)
        true, --close
        false)  --alt fill

    -- draw triangle in down button    
    points = string.format ("%i,%i,%i,%i,%i,%i", (WINDOW_WIDTH-SCROLL_BAR_WIDTH)+2, (WINDOW_HEIGHT-SCROLL_BAR_WIDTH)-10,(WINDOW_WIDTH-SCROLL_BAR_WIDTH)+6, (WINDOW_HEIGHT-SCROLL_BAR_WIDTH)-6, (WINDOW_WIDTH-SCROLL_BAR_WIDTH)+10,(WINDOW_HEIGHT-SCROLL_BAR_WIDTH)-10)
    WindowPolygon (Win, points,
        theme.DETAIL, miniwin.pen_solid, 1,   -- pen (solid, width 1)
        theme.DETAIL, miniwin.brush_solid, --brush (solid)
        true, --close
        false) --alt fill
    
    -- The scrollbar position indicator
    totalSteps = #lines
    if (totalSteps <= WINDOW_LINES-1) then totalSteps = 1 end
    SCROLL_BAR_HEIGHT = (WINDOW_HEIGHT-(3*SCROLL_BAR_WIDTH)-theme.TITLE_HEIGHT)
    if (not dragscrolling) then
        stepNum = lineStart-1
        barPos = SCROLL_BAR_WIDTH +theme.TITLE_HEIGHT+ ((SCROLL_BAR_HEIGHT/totalSteps) * stepNum)
        barSize = (SCROLL_BAR_HEIGHT/math.max(WINDOW_LINES-1,totalSteps)) * (WINDOW_LINES-1)
        if barSize < 10 then
            barSize = 10
        end
        if barPos+barSize > SCROLL_BAR_WIDTH+theme.TITLE_HEIGHT+SCROLL_BAR_HEIGHT then
            barPos = SCROLL_BAR_WIDTH+theme.TITLE_HEIGHT+SCROLL_BAR_HEIGHT - barSize
        end
        WindowAddHotspot(Win, "scroller", (WINDOW_WIDTH-SCROLL_BAR_WIDTH), barPos, WINDOW_WIDTH, barPos+barSize, 
                        "MouseOver", "CancelMouseOver", "MouseDown", "CancelMouseDown", "MouseUp", "", 
                        miniwin.cursor_hand, 0)
        WindowDragHandler(Win, "scroller", "ScrollerMoveCallback", "ScrollerReleaseCallback", 0)
    end  -- if
    DrawThemed3DRect(Win, WINDOW_WIDTH-SCROLL_BAR_WIDTH, barPos, WINDOW_WIDTH, barPos+barSize)
    
    -- resizer tag
    DrawThemedResizeTag(Win, WINDOW_WIDTH-SCROLL_BAR_WIDTH, WINDOW_HEIGHT-SCROLL_BAR_WIDTH, SCROLL_BAR_WIDTH)
    
    Redraw()
end  -- function drawStuff

function ScrollerMoveCallback(flags, hotspot_id)
    mouseposy = WindowInfo(Win, 18)
    windowtop = WindowInfo(Win, 2)
    barPos = math.max(mouseposy-windowtop+clickdelta, SCROLL_BAR_WIDTH+theme.TITLE_HEIGHT)
    if barPos > WINDOW_HEIGHT-(SCROLL_BAR_WIDTH*2)-barSize then
        barPos = WINDOW_HEIGHT-(SCROLL_BAR_WIDTH*2)-barSize
        lineStart = math.max(1,#lines-WINDOW_LINES+2)
        lineEnd = #lines
    else
        lineStart = math.floor((barPos-SCROLL_BAR_WIDTH-theme.TITLE_HEIGHT)/(SCROLL_BAR_HEIGHT/totalSteps)+1)
        lineEnd = math.min(lineStart + WINDOW_LINES-2, #lines)
    end -- if
    refresh()
end  -- function ScrollerMoveCallback

function ScrollerReleaseCallback(flags, hotspot_id)
    dragscrolling = false
    refresh()
end  -- function ScrollerReleaseCallback

function fillBuffer(rawstyles)
    local avail = 0
    local line_styles
    local beginning = true
    -- keep pulling out styles and trying to fit them on the current line
    local styles = copytable.deep (rawstyles)
    local remove = table.remove
    local insert = table.insert
    while #styles > 0 do
        if avail <= 0 then -- no room available? start new line
            -- remove first line if filled up
            if #lines >= MAX_LINES then
                remove (lines, 1)
            end -- if 
            avail = WINDOW_WIDTH - (TEXT_INSET * 2) - 9
            line_styles = {}
            add_line( line_styles, beginning )
            beginning = false
        end -- line full

        -- get next style, work out how long it is
        local style = remove (styles, 1)
        local width = WindowTextWidth (Win, "bodyfont"..Win, style.text)

        -- if it fits, copy whole style in
        if width <= avail then
            insert (line_styles, style)
            avail = avail - width
        else -- otherwise, have to split style   
            -- look for trailing space (work backwards). remember where space is
            local col = style.length - 1
            local split_col
            -- keep going until out of columns
            while col > 1 do
                width = WindowTextWidth (Win, "bodyfont"..Win, style.text:sub (1, col)) 
                if width <= avail then
                    if not split_col then
                        split_col = col  -- in case no space found, this is where we can split
                    end -- if
                    -- see if space here
                    if style.text:sub (col, col) == " " then
                        split_col = col
                        break
                    end -- if space
                end -- if will now fit
                col = col - 1
            end -- while
          
            -- if we found a place to split, use old style, and make it shorter. Also make a copy and put the rest in that
            if split_col then
                insert (line_styles, style)
                local style_copy = copytable.shallow (style)
                style.text = style.text:sub (1, split_col)
                style.length = split_col 
                style_copy.text = style_copy.text:sub (split_col + 1)
                style_copy.length = #style_copy.text
                insert (styles, 1, style_copy)
            elseif next (line_styles) == nil then
                insert (line_styles, style)
            else
                insert (styles, 1, style)
            end -- if    
            avail = 0  -- now we need to wrap     
        end -- if could not fit whole thing in
    end -- while we still have styles over
end  -- function fillBuffer

-- Main capture routine
function chats (name, line, wildcards, styles)
    
    -- echo in this world as well if the user wants
    if echo then
        for _, v in ipairs (styles) do
            ColourTell (RGBColourToName (v.textcolour),RGBColourToName (v.backcolour),v.text)
        end -- for each style run
        Note ("")  -- wrap up line
    end -- echo wanted

    -- inject timestamp if wanted
    if timestamp then
        local tstamp = os.date (date_format)
        table.insert (styles, 1, {
          text = tstamp,
          textcolour  = ColourNameToRGB (TIMESTAMP_TEXT_COLOUR),
          backcolour = ColourNameToRGB (TIMESTAMP_BACK_COLOUR),
          length = string.len (tstamp),
          style = 0,
        } )
    end -- if
    
    -- store the raw lines for use during resizing
    if #rawlines >= MAX_LINES then
        table.remove(rawlines, 1)
    end
    table.insert(rawlines, styles)
    
    fillBuffer(styles)
    refresh( )
end -- function chats 

function add_line ( line, is_beginning_of_message )
    -- add new line
    table.insert (lines, {line, false} )
    lines[#lines][2] = is_beginning_of_message

    -- advance the count
    if #lines >= WINDOW_LINES then
        lineStart = lineStart + 1
    end -- if
        
    if #lines > 1 then
        lineEnd = lineEnd + 1
    end -- if
end -- function add_line

keepscrolling = false
require "wait"

function scrollbar(calledBy)
    wait.make (function()
        while keepscrolling == true do
            if calledBy == "up" then
                if (lineStart > 1) then
                    lineStart = lineStart - 1
                    lineEnd = lineEnd - 1
                    WindowRectOp(Win, miniwin.rect_draw_edge, (WINDOW_WIDTH-SCROLL_BAR_WIDTH), theme.TITLE_HEIGHT, 0, theme.TITLE_HEIGHT+SCROLL_BAR_WIDTH, 
                        miniwin.rect_edge_sunken,  miniwin.rect_edge_at_all + miniwin.rect_option_fill_middle) -- up arrow pushed
                    points = string.format ("%i,%i,%i,%i,%i,%i", (WINDOW_WIDTH-SCROLL_BAR_WIDTH)+3, theme.TITLE_HEIGHT+9,(WINDOW_WIDTH-SCROLL_BAR_WIDTH)+7, theme.TITLE_HEIGHT+5,(WINDOW_WIDTH-SCROLL_BAR_WIDTH)+11, theme.TITLE_HEIGHT+9)
                    WindowPolygon (Win, points,
                        theme.DETAIL, miniwin.pen_solid, 1, -- pen (solid, width 1)
                        theme.DETAIL, miniwin.brush_solid, -- brush (solid)
                        true, -- close
                        false) -- alt fill
                else
                    keepscrolling = false
                end
            elseif calledBy == "down" then
                if (lineEnd < #lines) then
                    lineStart = lineStart + 1
                    lineEnd = lineEnd + 1
                WindowRectOp(Win, miniwin.rect_draw_edge, (WINDOW_WIDTH-SCROLL_BAR_WIDTH), WINDOW_HEIGHT-(SCROLL_BAR_WIDTH*2), 0, WINDOW_HEIGHT-SCROLL_BAR_WIDTH-1, 
                    miniwin.rect_edge_sunken,  miniwin.rect_edge_at_all + miniwin.rect_option_fill_middle) -- down arrow pushed
                points = string.format ("%i,%i,%i,%i,%i,%i", (WINDOW_WIDTH-SCROLL_BAR_WIDTH)+3, (WINDOW_HEIGHT-SCROLL_BAR_WIDTH)-11,(WINDOW_WIDTH-SCROLL_BAR_WIDTH)+7, (WINDOW_HEIGHT-SCROLL_BAR_WIDTH)-7, (WINDOW_WIDTH-SCROLL_BAR_WIDTH)+11,(WINDOW_HEIGHT-SCROLL_BAR_WIDTH)-11) -- draw triangle in up button
                WindowPolygon (Win, points,
                    theme.DETAIL, miniwin.pen_solid, 1, -- pen (solid, width 1)
                    theme.DETAIL, miniwin.brush_solid, -- brush (solid)
                    true, -- close
                    false) -- alt fill
                else
                    keepscrolling = false
                end
            end -- if
            wait.time(0.1)
            refresh()
        end -- while keepscrolling
    end)  -- wait.make
end  -- function scrollbar

function GetLineText (styles)
  local t = {}
  for _, style in ipairs (styles) do
    table.insert (t, style.text)
  end -- for
  return table.concat (t)
end -- function GetLineText

function GetAllBufferedMessages()
    local t = {}
    for _,styles in ipairs(rawlines) do
      table.insert (t, GetLineText (styles))
    end -- for
    SetClipboard(table.concat(t,"\r\n"))
end -- function GetAllBufferedMessages

function GetBufferedMessage(xpos, ypos)
    windowline = math.floor(((ypos-theme.TITLE_HEIGHT)/line_height)+1)-1
    text = ""
    if (#lines > windowline) then
        local line = windowline+lineStart
        -- go to beginning of message
        while lines[line][2] ~= true and line > 1 do
            line = line - 1
        end -- while
        -- first line
        local styles = copytable.deep(lines[line][1])
        if (line-lineStart+1 > 0) then
            Display_Line (line-lineStart, styles, true)
        end -- if
        text = GetLineText (styles)
        -- remaining lines
        line = line + 1
        while line <= #lines and lines[line][2] ~= true do
            local styles = copytable.deep(lines[line][1])
            if (line-lineStart+1 > 0 and line-lineStart < WINDOW_LINES) then
                Display_Line (line-lineStart, styles, true)
            end
            text = text.. GetLineText (styles)
            line = line + 1
        end -- while
        SetClipboard(text)
    end -- if
    Redraw()
    
end  -- function GetBufferedMessage

function MouseOver(flags, hotspot_id)
    keepscrolling = false
end  -- function MouseOver

function CancelMouseOver(flags, hotspot_id)
    keepscrolling = false
end  -- function CancelMouseOver

function MouseDown(flags, hotspot_id)
    if (hotspot_id == "resizer") then
        startx, starty = WindowInfo (Win, 17), WindowInfo (Win, 18)
    elseif (hotspot_id == "scroller") then
        clickdelta = WindowHotspotInfo(Win, "scroller", 2)-WindowInfo (Win, 15)
        dragscrolling = true
    elseif (hotspot_id == "textarea" and flags == miniwin.hotspot_got_lh_mouse) then
        GetBufferedMessage(WindowInfo(Win, 14), WindowInfo(Win,15))
    else
        keepscrolling = true
        scrollbar(hotspot_id)
    end -- if
end  -- function MouseDown

function CancelMouseDown(flags, hotspot_id)
    keepscrolling = false
    refresh()
end  -- function CancelMouseDown

function MouseUp(flags, hotspot_id)
    if (hotspot_id == "textarea" and flags == miniwin.hotspot_got_rh_mouse) then
        -- build menu for current state
        right_click_menu()
    else
        refresh()
    end -- if
    keepscrolling = false
end  -- function MouseUp

function chat_echo (name, line, wildcards)
    if wildcards [1] == false then
      echo = not echo  -- toggle
    else
      echo = wildcards [1]:lower () == " on"
    end -- if

    if echo then
        ColourNote ("yellow", "", "Echoing chats in main window ENABLED.")
    else
        ColourNote ("yellow", "", "Echoing chats in main window DISABLED.")
    end -- if
end -- function chat_echo

function chat_show (name, line, wildcards)
   WindowShow( Win, true )
   ColourNote ("yellow", "", "Chats window now shown. Type 'chats hide' to hide it.")
end -- function chat_show

function chat_hide (name, line, wildcards)
   WindowShow( Win, false )
   ColourNote ("yellow", "", "Chats window now hidden. Type 'chats show' to see it again.")
end -- function chat_hide

-- right click menu
function right_click_menu ()
    menustring ="Copy All To Clipboard|Change Font|Turn Echo "
    
    if echo then
        menustring = menustring .. "Off"
    else
        menustring = menustring .. "On"
    end -- if
    
    menustring = menustring.."|>Timestamp|No Timestamps|30 Aug 13:29:49|30 Aug 01:20:12PM|13:29:08|1:22:06 PM"
    result = WindowMenu (Win, 
        WindowInfo (Win, 14),  -- x position
        WindowInfo (Win, 15),   -- y position
        menustring) -- content
    if result == "Copy All To Clipboard" then
        GetAllBufferedMessages()
        ColourNote ("yellow", "", "All buffered messages copied to clipboard.")
    elseif result == "Change Font" then
        wanted_font = utils.fontpicker (BODY_FONT_NAME, BODY_FONT_SIZE) --font dialog
        if wanted_font then
            BODY_FONT_NAME = wanted_font.name
            BODY_FONT_SIZE = wanted_font.size
            SetVariable ("bodyfont", BODY_FONT_NAME)
            SetVariable ("font_size", BODY_FONT_SIZE)
            OnPluginInstall()
        end
    elseif result == "Turn Echo Off" then
        echo = false
        ColourNote ("yellow", "", "Echoing chats in main window DISABLED.")
    elseif result == "Turn Echo On" then
        echo = true
        ColourNote ("yellow", "", "Echoing chats in main window ENABLED.")
    elseif result == "No Timestamps" then
        timestamp = false
        ColourNote ("yellow", "", "Timestamps in communication window DISABLED.")
    elseif result == "30 Aug 13:29:49" then
        timestamp = true
        date_format = "[%d %b %H:%M:%S] "
        ColourNote ("yellow", "", "Timestamps in communication window ENABLED using format like '30 Aug 13:29:49'.")
    elseif result == "30 Aug 01:20:12PM" then
        timestamp = true
        date_format = "[%d %b %I:%M:%S%p] "
        ColourNote ("yellow", "", "Timestamps in communication window ENABLED using format like '30 Aug 01:20:12PM'.")
    elseif result == "13:29:08" then
        timestamp = true
        date_format = "[%H:%M:%S] "
        ColourNote ("yellow", "", "Timestamps in communication window ENABLED using format like '13:29:08'.")
    elseif result == "1:22:06 PM" then
        timestamp = true
        date_format = "[%I:%M:%S%p] "
        ColourNote ("yellow", "", "Timestamps in communication window ENABLED using format like '1:22:06 PM'.")
    end -- if
end -- function right_click_menu
]]>
</script>
</muclient>


You may need to adapt or add to the triggers (lines in bold) to make it match your particular MUD. It should work on the test lines Leonhardt posted.

[EDIT] Modified to version 2 to clean up the code a bit.

Version 2.2 - modified to require version 4.52 of MUSHclient.

Version 2.3 - modified to add "chats show" and "chats hide" aliases.

Version 2.4 - modified to show background colours as well in chat window, and have timestamp in white on black.
Amended on Wed 05 Jan 2011 12:26 AM by Nick Gammon
Australia Forum Administrator #6
This is what the window looks like:



You can:

  • Move it by dragging the title bar
  • Resize it
  • RH-click to bring up a menu of options
  • LH-click to copy one line of chat to the clipboard

USA Global Moderator #7
It looks like a caveat with this version is that if you use the copy functions you won't be getting color codes. Yes? Also, I don't see anything in bold. Maybe it's my browser, though.
Amended on Sat 13 Nov 2010 04:16 AM by Fiendish
Australia Forum Administrator #8
Oops, I improved it again, and left out the bold codes. Put back now.

Yes, the colour codes were Aardwolf-specific, so this version just copies the text.

Fiendish, in your version you were prepending the plugin ID to the variables. Why do that? The variables are local to the plugin anyway, that just seems to make it wordier than it has to be.

Also I cleaned up some of the WindowXXX operations to put in the new symbolic constants, rather than 2 for "fill rectangle" and so on.
USA Global Moderator #9
Nick Gammon said:
Fiendish, in your version you were prepending the plugin ID to the variables. Why do that? The variables are local to the plugin anyway, that just seems to make it wordier than it has to be.


Because I'd been away from writing plugins for too long and forgot details like that. :)
In one of the next versions I'll probably undo that particular change.
#10
I did like you said but I keep getting this error message.



Run-time error
Plugin: Chat_Capture_Miniwindow (called from world: Ansalon)
Function/Sub: OnPluginInstall called by Plugin Chat_Capture_Miniwindow
Reason: Executing plugin Chat_Capture_Miniwindow sub OnPluginInstall
[string "Plugin"]:58: attempt to perform arithmetic on field 'pen_endcap_flat' (a nil value)
stack traceback:
[string "Plugin"]:58: in function 'DrawThemed3DRect'
[string "Plugin"]:250: in function 'drawStuff'
[string "Plugin"]:238: in function 'refresh'
[string "Plugin"]:184: in function 'init'
[string "Plugin"]:134: in function <[string "Plugin"]:112>
Error context in script:
USA Global Moderator #11
Leonhardt said:

I did like you said but I keep getting this error message.



Run-time error
Plugin: Chat_Capture_Miniwindow (called from world: Ansalon)
Function/Sub: OnPluginInstall called by Plugin Chat_Capture_Miniwindow
Reason: Executing plugin Chat_Capture_Miniwindow sub OnPluginInstall
[string "Plugin"]:58: attempt to perform arithmetic on field 'pen_endcap_flat' (a nil value)
stack traceback:
[string "Plugin"]:58: in function 'DrawThemed3DRect'
[string "Plugin"]:250: in function 'drawStuff'
[string "Plugin"]:238: in function 'refresh'
[string "Plugin"]:184: in function 'init'
[string "Plugin"]:134: in function <[string "Plugin"]:112>
Error context in script:

That's because Nick made your version of MUSHclient obsolete by replacing some numbers with some newfangled keywords that I've never heard of. Try getting the latest MUSHclient installer. :)
#12
ok its working now but I moved it up too high and cant get to the top of the miniwindow to move it around anymore what should I do? I tried removing the plugin and re-installing it but it still shows up at the top where I cant get to the bar where you move it around the screen.
Australia Forum Administrator #13
The remembering of window positions shouldn't do that, but since it has ...

  • Close the world so the plugin is not in use.
  • Look in your worlds/plugins/state folder for a file with "565dae21eb816a2fdb8d50f9" in the name.

    In my case the file was "3bcfeeb548c77aa15ae19061-565dae21eb816a2fdb8d50f9-state.xml" but yours will have a different front part, as that is the world "id".
  • If you edit that file with Notepad you will see something like this in it:

    
    <?xml version="1.0" encoding="iso-8859-1"?>
    <!DOCTYPE muclient>
    <!-- Saved on Saturday, November 13, 2010, 6:18 PM -->
    <!-- MuClient version 4.69 -->
    <!-- Written by Nick Gammon -->
    <!-- Home Page: http://www.mushclient.com/ -->
    
    <!-- Plugin state saved. Plugin: "Chat_Capture_Miniwindow". World: "SmaugFUSS". -->
    
    <muclient>
    
    <!-- variables -->
    
    <variables
       muclient_version="4.69"
       world_file_version="15"
       date_saved="2010-11-13 18:18:14"
      >
      <variable name="WINDOW_HEIGHT">296</variable>
      <variable name="WINDOW_WIDTH">460</variable>
      <variable name="bodyfont">Dina</variable>
      <variable name="date_format">[%d %b %I:%M:%S%p] </variable>
      <variable name="echo">true</variable>
      <variable name="enabled">true</variable>
      <variable name="font_size">8</variable>
      <variable name="mw_565dae21eb816a2fdb8d50f9_windowflags">2</variable>
      <variable name="mw_565dae21eb816a2fdb8d50f9_windowmode">0</variable>
      <variable name="mw_565dae21eb816a2fdb8d50f9_windowx">883</variable>
      <variable name="mw_565dae21eb816a2fdb8d50f9_windowy">680</variable>
      <variable name="timestamp">true</variable>
    </variables>
    </muclient>
    

  • You can just simply delete the file, to go back to default positions, or remove the lines which specify the "windowx" and "windowy" positions (in my case they are 883 and 680) and then save the file.
  • Start MUSHclient again and the chats should be back to default positions.

Amended on Sat 13 Nov 2010 06:52 PM by Nick Gammon
Australia Forum Administrator #14
Fiendish said:

That's because Nick made your version of MUSHclient obsolete by replacing some numbers with some newfangled keywords that I've never heard of. Try getting the latest MUSHclient installer. :)


Strangely, you required 4.51, whereas I added that stuff in 4.52. Missed by one version!

I've updated the plugin to require 4.52.

Also, I think the problem with positioning might have been that you asked for absolute window positions in the movewindow.install line, which I don't think is really wanted, because absolute positions really only apply once they have dragged the window from its default position. I changed that bit.
#15
Hot damn its all up and running great now thanks for helping the newbie guys. I just got one more thing to ask is there a way to hide the window like using noinv for the inventory miniwindow?
Amended on Sat 13 Nov 2010 10:28 PM by Leonhardt
Australia Forum Administrator #16
Modified on page 1, to add "chats hide" and "chats show" aliases.
#17
Perfect it works great man thanks again for all the help.
USA Global Moderator #18
Nick Gammon said:
Also, I think the problem with positioning might have been that you asked for absolute window positions in the movewindow.install line, which I don't think is really wanted, because absolute positions really only apply once they have dragged the window from its default position. I changed that bit.

I don't think I've ever had a situation where the window allowed me to move the movewindow area offscreen. It always just jumps back into view if it goes too far. Hmm.
#19
I downloaded MUSHClient v4.71 and now the plug-in works, in part:

The MiniWindow displays my tells (You tell Bilbo 'thanks') but doesn't display the replies back, nor most other forms of chat.

My question is, how can I make the MiniWindow display other forms of communication:

Bilbo tells you 'no problem'
Leto shouts 'next time'
Korgan says 'yes'
Aristox tells your clan 'durka durka'
Shayd tells your group 'run away!'

Thanks, and keep up the great work!
Grim
Australia Forum Administrator #20
Inside the plugin, near where it has triggers, like this:


 <trigger
    enabled="y"
    match="You tell * '*'"
    script="chats"
    omit_from_output="y"
    sequence="100"
    ></trigger>


Add more to match what you want, eg.


 <trigger
    enabled="y"
    match="* tells you '*'"
    script="chats"
    omit_from_output="y"
    sequence="100"
    ></trigger>

 <trigger
    enabled="y"
    match="* shouts '*'"
    script="chats"
    omit_from_output="y"
    sequence="100"
    ></trigger>

 <trigger
    enabled="y"
    match="* tells your clan '*'"
    script="chats"
    omit_from_output="y"
    sequence="100"
    ></trigger>



And so on. Just put them into a gap between triggers, and the reinstall the plugin.
Amended on Sun 19 Dec 2010 05:30 AM by Nick Gammon
#21
Thanks Nick - works great. Also, very easy solution for a non-programmer (such as myself) to adapt to any type of chat.

One other question: is there a way to re-size the MiniWindow? Preferably in-game via click-and-drag on the MiniWindow border, or perhaps via a right-click menu (like current the time stamp option).

Currently, my MiniWindow is "locked" at six lines of chat and has a fixed width as well.

Thanks again,
Grim
Australia Forum Administrator #22
If you are using the plugin on page 1 it has a resize capability.



See circled resize icon.
Amended on Mon 20 Dec 2010 05:38 AM by Nick Gammon
#23
Great - that's perfect!

Perhaps another thread (if so, apologies - I can move it there or start a new one), I'm looking to do a MiniWindow for other things such as spells being Memorized, which looks something like this:

------------
Spells currently memorized:
1: [ 3]bless [ 1]know alignment [3]curse
[ 2]create food
2: [ 7]prismatic spray [11]heal
3: [ 3]stoneskin


Spells left (level-number): 1-0 2-0 3-2

899H 78V 280C Exits:NEW>
------------

Is there something I can cut/paste/save as a plug-in that will capture everything above (except for the prompt line at the bottom)? I tried modifying a MiniWindow (for inventory on another thread) as a base script but no luck.

And thank you the quick and on-target responses.
Grim

P.S. I guess the next step I'm looking for is a very basic MiniWindow script that one can (1) modify for various uses, and (2) move around like the chat MiniWindow in this thread.
Australia Forum Administrator #24
Best to start a new thread I think.
USA #25
using this plugin seems to break the command echo on triggers for me.

the problem shows up when something the plugin is set to match, also triggers something else...

for example


You hear Bymox hrm.
say moo

<Relina 1066/1066hp 1523/1523mp 735mv 199/350wtg HT 14,045,487g> You say 'moo'

<Relina 1066/1066hp 1523/1523mp 735mv 199/350wtg HT 14,045,487g> 
Bymox says 'hrm'

<Relina 1066/1066hp 1523/1523mp 735mv 199/350wtg HT 14,045,487g> You say 'mooo'


so the trigger that fires off "You hear Bymox hrm." echo's the command like its supposed to...
But the trigger that fires off the say doesn't echo like its supposed to... because the plugin is set to match the same message. the trigger still fires it just doesn't echo the command.



Oh and is there any way to edit out the prompt from the chat window?

[01 Jan 04:11:18] <Relina 1066/1066hp 1523/1523mp 735mv 199/350wtg HT 14,045,487g> You say 'moo'
[01 Jan 04:11:21] Bymox says 'hrm'
[01 Jan 04:11:21] <Relina 1066/1066hp 1523/1523mp 735mv 199/350wtg HT 14,045,487g> You say 'mooo'
Amended on Sat 01 Jan 2011 11:22 AM by Chyort
Australia Forum Administrator #26
I was going to say just edit out the prompt with a regular expression but it will probably be harder than that, because the prompt will probably have different colours, and thus span style runs. If it is all one colour it would be simple enough.

Your simplest thing is probably to make the prompts on a new line. To do that:

Template:faq=11
Please read the MUSHclient FAQ - point 11.


Then the problem goes away because prompts and chats are not on the same line.
USA #27
Yeah i found the FAQ years ago when i was first playing around with triggers... and simply adding a new line to my prompt does break up the prompt and says(or anything else) but it also adds an extra blank line on occasions.

so i get stuff like this


<Chyort 1578/1082hp 984mv 457/500wtg T 8,232,231g>   

Relina says 'hrm'

<Chyort 1578/1082hp 984mv 457/500wtg T 8,232,231g> 

instead of this

<Chyort 1578/1082hp 984mv 457/500wtg T 8,232,231g>   
Relina says 'hrm'

<Chyort 1578/1082hp 984mv 457/500wtg T 8,232,231g> 


Adding extra blank lines like that never appealed to me so i just worked around it in my simple triggers.
But since this is just a stored record i was wondering if the script could be made to just remove everything between the < > automatically if it detects them.
It isnt a big deal though, i have lived with similar issues for years :) and i can live with seeing a prompt in the chat window.

But none of this should affect my triggers failing to echo the commands into my window when they fire... Correct? That was my main issue, just figured i would tack the prompt question on since i was already posting.

I know the problem is related to the chat miniwindow plugin because when i disable the plugin, my triggers that match off says start to echo what they sent properly again.

Amended on Sun 02 Jan 2011 08:08 AM by Chyort
Australia Forum Administrator #28
The problem is that, if the prompt is in different colours like a lot are, then removing it is slightly complicated. You have to work your way through the style runs, omitting the relevant ones, and possibly having to split the last one into the part you want to keep and the part you want to omit.

As for the blank lines:

http://www.gammon.com.au/forum/?id=8768
USA #29
After poking around a bit, I figured out a solution to my main problem on my own :P

The sample triggers in the plugin have "Omit from output" checked, and the chat script can then echo the says back to the main window, and a copy to the mini-window. Or flat out redirect them to the mini-window, and leave them omitted from the main window.

"Omit from output" also hides any commands sent by the trigger though.
So i got this...

<Bymox 1092/1092hp 1383/1518mp 610mv 43/500wtg H 90,002g 6,615,119> 
Relina says 'sanc'

<Bymox 1092/1092hp 1518/1518mp 610mv 43/500wtg H 90,002g 6,615,119> A luminous aura spreads slowly over Relina's body. 

Apparently, the plugin managed to omit the commands being sent by my standard triggers. (Kind of surprised by that interaction between a stand alone plugin, and standard triggers)

Removing the "Omit from output" in the plugin then gave me this...

<Bymox 1092/1092hp 1518/1518mp 604mv 43/500wtg H 90,002g 6,615,119> 
Relina says 'sanc'
c sanc Relina
trance
Relina says 'sanc'

<Bymox 1092/1092hp 1518/1518mp 604mv 43/500wtg H 90,002g 6,615,119> A luminous aura spreads slowly over Relina's body.

the first say being the original text, the c sanc and trance being the standard trigger send, and the 2nd say being the echo from the plugin.

i then just turned off the plugin echo and tada back to working like normal. while still having the mini-window chat.


<Bymox 1092/1092hp 1518/1518mp 610mv 43/500wtg H 90,002g 6,615,119> 
Relina says 'sanc'
c sanc Relina
trance

<Bymox 1092/1092hp 1518/1518mp 610mv 43/500wtg H 90,002g 6,615,119> A luminous aura spreads slowly over Relina's body.
Australia Forum Administrator #30
Chyort said:

Apparently, the plugin managed to omit the commands being sent by my standard triggers. (Kind of surprised by that interaction between a stand alone plugin, and standard triggers)


That behaviour of omitting from output also omitting other stuff should have been fixed in version 4.54 onwards.

http://www.gammon.com.au/scripts/showrelnote.php?version=4.54&productid=0
USA #31
I'm using Version 4.61... So your guess is as good as mine.

Edit
i managed to repeat it using a dirt simple plugin and matching world trigger. Here they are...


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Monday, January 03, 2011, 1:00 AM -->
<!-- MuClient version 4.61 -->

<!-- Plugin "Test" generated by Plugin Wizard -->

<muclient>
<plugin
   name="Test"
   author="Chyort"
   id="15e86600d1df02b666794e90"
   language="Lua"
   save_state="y"
   date_written="2011-01-03 00:59:13"
   requires="4.61"
   version="1.0"
   >

</plugin>


<!--  Triggers  -->

<triggers>
  <trigger
   enabled="y"
   match="You say 'test'"
   omit_from_output="y"
   sequence="100"
  >
  </trigger>
</triggers>

</muclient>


and


<triggers>
  <trigger
   enabled="y"
   match="You say 'test'"
   sequence="100"
  >
  <send>say test2</send>
  </trigger>
</triggers>



Not using world.note or any other notes like described in your release notes...

with Just the world trigger i get this

<49/49hp 91/91m 110/110mv> <Type HELP START>
say test
You say 'test'
say test2

<49/49hp 91/91m 110/110mv> <Type HELP START>You say 'test2'


With the plugin as well i get this instead


<49/49hp 91/91m 110/110mv> <Type HELP START>
say test

<49/49hp 91/91m 110/110mv> <Type HELP START>You say 'test2'


Amended on Mon 03 Jan 2011 08:16 AM by Chyort
Australia Forum Administrator #32
First of all, major compliments on making such a detailed bug report, that describes the problem exactly, and shows how to reproduce it.

As soon as I saw your detailed description I guessed what the problem was, and looking at the code confirmed it.

The change made in 4.54 addressed the problem of notes being omitted if they were made during an "omit from output" trigger. I overlooked that you might send a command (as you did).

A very minor change to the code preserves player commands as well as notes (this will be in version 4.72).

However there is one small problem. It actually preserves the lines which were previously omitted, waits until the omitting is done, then puts them back. However the mouse-over which pops up an "information box" will now show the line as a note line and not a player input line. I don't think this is going to be a major issue (after all, previously the lines were omitted completely and no-one complained) but it is worth knowing it happens.

I could store an extra flag to note the type of line, but this is likely to add to memory consumption in general for probably very little return.
#33
I am using this plugin in Achaea and it captures fine, although it only ever displays text in the foreground colour. Some of my channels I use background colours on, but it isn't displaying them with that.

Any thoughts/suggestions?

Also is there way to change the colour the timestamp displays in? I prefer a uniform colour for all timestamps and the current method in the plugin injects the timestamp in the same colour as the foreground of the text.
Australia Forum Administrator #34
In the middle of the plugin, try changing:


-- display one line
function Display_Line (line, styles, backfill)
    local left = TEXT_INSET
    if (backfill) then
        WindowRectOp(Win, miniwin.rect_fill, 1, theme.TITLE_HEIGHT+(line*line_height)+1, WINDOW_WIDTH-SCROLL_BAR_WIDTH, theme.TITLE_HEIGHT+(line*line_height)+line_height+1, ColourNameToRGB("#333333"))
    end -- backfill
    if (styles) then
        for _, v in ipairs (styles) do
            left = left + WindowText (Win, "bodyfont"..Win, v.text, left, theme.TITLE_HEIGHT+(line*line_height), 0, 0, v.textcolour)
        end -- for each style run
    end -- if
    Redraw()
end -- function Display_Line


to:


-- display one line
function Display_Line (line, styles)
 
  local left    = TEXT_INSET
  local top     = theme.TITLE_HEIGHT + (line * line_height) + 1
  local bottom  = top + line_height
  local font    = "bodyfont" .. Win

  if backfill then
      WindowRectOp (Win, miniwin.rect_fill, 1, top, WINDOW_WIDTH - SCROLL_BAR_WIDTH, bottom, ColourNameToRGB("#333333"))
  end -- backfill
  
  if styles then
    for _, style in ipairs (styles) do
      local width = WindowTextWidth (Win, font, style.text) -- get width of text
      local right = left + width
      WindowRectOp (Win, miniwin.rect_fill, left, top, right, bottom, style.backcolour)  -- draw background
      WindowText (Win, font, style.text, left, top, 0, 0, style.textcolour)  -- draw text
      left = left + width  -- advance horizontally
    end -- for each style run        
  end -- if  styles
  Redraw()
  
end -- Display_Line




As for the timestamp colour, try changing:


    -- inject timestamp if wanted
    if timestamp then
        tstamp = os.date (date_format)
        styles[1].text = tstamp..styles[1].text
        styles[1].length = styles[1].length+string.len(tstamp)
    end -- if


to:


    -- inject timestamp if wanted
    if timestamp then
        local tstamp = os.date (date_format)
        table.insert (styles, 1, {
          text = tstamp,
          textcolour  = ColourNameToRGB ("white"),
          backcolour = ColourNameToRGB ("black"),
          length = string.len (tstamp),
          style = 0,
        } )
    end -- if


This adds a new style at the start of the line with the timestamp in whatever colours you specify.
Amended on Tue 04 Jan 2011 08:47 PM by Nick Gammon
Australia Forum Administrator #35
Now modified the posting on page 1 of this thread to have the amended features discussed above.
#36
Works great, thanks!

Your copy on page 1 though needs all the '\]' and '\[' fixed though.
#37
I'm trying to start coding again since I've actually found enough time to start doing it again. I am now looking at how other people have done Plugins, Scripts, and etc..

I'm having a problem with this Plugin though, could be some minor /[ or some such problem but here is what I am getting

[WARNING] C:\Program Files (x86)\MUSHclient\worlds\plugins\ChatMiniwindow.xml
Line   34: Attribute name must start with letter or underscore, but starts with "[" (Cannot load)
USA #38
Yeah, Nick seems to have accidentally left the [b][/b] forum bold tags in his post unescaped, so when you copied the plugin you got those too.
Australia Forum Administrator #39
Sorry about that, fixed up on page 1 now.
USA Global Moderator #40
For those intrepid adventurers from MUDs other than Aardwolf, I figured I'd re-re-re-announce that I've developed the channel capture plugin significantly since Nick made those conversion mods earlier in the thread. It now uses GMCP (sorry about that) and has a bunch of new features like logging to a file and allowing for arbitrary text selection (and therefore copying) inside the window. The new version probably requires way more modification to work with other MUDs, but I think that the new features (especially that last one) are really worth it.

https://aardwolfclientpackage.googlecode.com/svn/trunk/MUSHclient/worlds/plugins/aard_channels_fiendish.xml
#41
Alright, I would like a miniwindow something like this to capture pages and channel chatter, example of the text are:

[Public] Com Title Bob says, "Testing" (Public would need to be a wildcard as there are several channels)

and pages come in one of two formats, normal talking:

John pages: testing
You paged Bob with 'testing'

and then page poses

From afar, Bob testing
Long distance to Bob: John testing

I want to have all this in a window with a width of 80 characters and a height of 50 characters justified to the top left of the screen. I would want the window to have a black background with standard silver text in a 9pt fixedsys font, however, I would also want for any ansi colors the game sends to show up in the window as well. And preferably no scroll bar or anything. Also, some kind option when I can choose if I want the text sent to the main window as well. Would this be terribly complicated?

Any help with this would be greatly appreciated.
#42
Justified to the top right not to the top left. Sorry... Slightly dyslexic.
USA Global Moderator #43
Quote:
I want to have all this in a window with a width of 80 characters and a height of 50 characters justified to the top left of the screen. I would want the window to have a black background with standard silver text in a 9pt fixedsys font, however, I would also want for any ansi colors the game sends to show up in the window as well. And preferably no scroll bar or anything.

Do you mind if I ask why you want the user interface to be locked down like that? No scrolling, moving, or resizing seems like a giant step backward for usability.

If you're absolutely certain you want to have those limitations, you should perhaps look at another thread on the subject like maybe...
Template:post=10515
Please see the forum thread: http://gammon.com.au/forum/?id=10515.


#44
Well, I was thinking it would look like a column setup. With my widescreen monitor, I could have a column for RP, room desc's and so on. Then a column for pages and channel chat. It's a matter of trying to keep the whole world window uncluttered with stuff I really don't need; like the scroll bar and such.
Australia Forum Administrator #45
The link Fiendish gave should probably do it for you. Although I would have thought the scroll bar (hardly clutter, really) is handy if an important message scrolls off the top of the window.
USA #46
Is there a way for the mini-window to scroll up/down when using the mouse wheel when it's focused?
USA Global Moderator #47
Yes there is. Take a look at the Aardwolf GMCP channel capture plugin I posted not long ago:
https://aardwolfclientpackage.googlecode.com/svn/trunk/MUSHclient/worlds/plugins/aard_channels_fiendish.xml

search for lines containing "wheel_move" to see how it can be done.
Amended on Thu 28 Apr 2011 11:36 PM by Fiendish
USA #48
is there any way to reset the miniwindow position?

it starts out stuck to the top right corner. As you resize the world window, the miniwindow moves with... But if you move the miniwindow, it remembers where you left it despite resizing the world window. Cool feature... But also a pain when you want the miniwindow back in the corner moving with the world window when you resize it again.

i tried disabling/enabling the plugin, as well as reinstalling the plugin. neither worked.
Australia Forum Administrator #49
It's clever the way it does that, eh? Even if you reinstall?

There is a "state" file - in your "state" directory under the plugins directory. Inside that will be files which have long names like this:


a7046428ba477ebb729250df-b0a9cef2629fae2eacf97603-state.xml


One part is the "world ID" and the other part (the second part) is the "plugin ID".

If you open up your plugin and find the plugin ID, near the start, like this:


id="b0a9cef2629fae2eacf97603"


Then look for a state file with that ID in it. Delete it. Then it will revert to the default behaviour.

Do that with the plugin not running (installed) or it will overwrite the state file.
Amended on Wed 25 May 2011 08:11 AM by Nick Gammon
USA #50
yeah, i knew plugins could save info like the window position... i was really just hoping for something easier than hunting the saved info down in some obscure folder and deleting it manually :P

Oh well at least i know where to look now :P
USA Global Moderator #51
I'm sure you could modify OnPluginSaveState to optionally call DeleteVariable or something.
USA #52
I changed


function OnPluginSaveState ()
    -- save window current location for next time  
    SetVariable ("enabled", tostring (GetPluginInfo (GetPluginID(), 17)))
    movewindow.save_state (Win)
    -- save echo/timestamp status
    SetVariable ("echo", tostring (echo))
    SetVariable ("timestamp", tostring (timestamp))
    SetVariable("date_format", date_format)
    SetVariable("WINDOW_WIDTH", WINDOW_WIDTH)
    SetVariable("WINDOW_HEIGHT", WINDOW_HEIGHT)
end -- function OnPluginSaveState


to this


function OnPluginSaveState ()
    -- save window current location for next time  
    -- SetVariable ("enabled", tostring (GetPluginInfo (GetPluginID(), 17)))
    -- movewindow.save_state (Win)
    -- save echo/timestamp status
    SetVariable ("echo", tostring (echo))
    SetVariable ("timestamp", tostring (timestamp))
    SetVariable("date_format", date_format)
    SetVariable("WINDOW_WIDTH", WINDOW_WIDTH)
    SetVariable("WINDOW_HEIGHT", WINDOW_HEIGHT)
end -- function OnPluginSaveState


Basically I just commented the save state and set variable... In very limited testing it seems that when ever i move the window now, it resets back into the corner after closing/opening the window again... It still saves everything else (echo, window height/width, so on... I think so at least :P) but this simple modification is at the limits of my non-existent scripting skills :P

So I guess I'm just asking for a more experienced person to tell me if I'm right, and that it wont mess something else up...

I think it's safe enough to comment this line out of the script. " -- movewindow.save_state (Win)"

But I'm not entirely sure if i should be commenting this line out. " -- SetVariable ("enabled", tostring (GetPluginInfo (GetPluginID(), 17)))"

As I said, in very limited testing it seems to be working.. but I would like to know for sure.
Amended on Sun 05 Jun 2011 04:01 AM by Chyort
Australia Forum Administrator #53
Yes commenting out the save_state means it will never remember where you moved it to.

The "enabled" stuff is just to remember for next time if you happened to disable the window. If you comment it out it will always come back enabled, which you might prefer.
#54
Okay my MUD doesn't have linebreaks imbedded into it so some chats are multiple lines. how would i capture multiple lines for the chat box? Heres my trigger

^(.*?) chats\: \'(.*?)\\n(.*?)\'\\Z$"


What would i do differently?
USA #55
Renox Dashin said:
Okay my MUD doesn't have linebreaks imbedded into it so some chats are multiple lines.

No, they're not. If there are no newlines, MUSHclient wraps the line but it's still treated as one single line for triggers. If there were newlines, then you'd have to deal with a multi-line trigger.

Renox Dashin said:
^(.*?) chats\: \'(.*?)\n(.*?)\'\Z$"
What would i do differently?


^(.+?) chats\: '([^']*)'$
Amended on Mon 06 Jun 2011 08:41 PM by Twisol
#56
I' ve got it picking up the one liners, its the multi-liners that aren't getting picked up, so i guess it does have linebreaks embedded into the MUD. Whichever. I need to pick up multi lines, how would i do that
USA #57
If possible, the best solution is to disable server-side wrapping and let MUSHclient wrap the lines, so you can treat it as a single line in your trigger. Some MUDs let you do this (in Achaea, you'd use CONFIG SCREENWIDTH 0), but others don't. In those cases you'll need a multiline trigger, but I'm no good at those. Hopefully someone else will stop by and lend a hand here.
#58
Anyone know how to do multiline triggers?
Australia Forum Administrator #59
Template:faq=23
Please read the MUSHclient FAQ - point 23.


Also:

Template:post=7991
Please see the forum thread: http://gammon.com.au/forum/?id=7991.


There are pages of discussion about it there.
#60
Okay that told me nothing,
^(.*?) chats\: \'(.*?)\\n(.*?)\'\\Z$
thats my attempt at a multi-line chat trigger, All i need to know is what to change to make it pick up multiline chats, I can figure the rest out on my own. All i need is the updated trigger. I've got the blasted thing to work, EXCEPT for multi-lines, I feel like i'm on a customer service line, Always being transfered to a different operator and never quite getting the service i request.
USA Global Moderator #61
Renox Dashin said:

Okay that told me nothing,

Then you didn't actually read it.
USA #62
Further down on the first page of that thread, Nick explains how to capture variable-length, server-wrapped lines using multiple triggers. You have one trigger for the start (^.+? chats: '(.+)), one for the middle (^(.+)$), and one for the end (^(.+)'$, with a lower sequence value). All but the first start out disabled. When the first triggers, it enables the other two. When the third matches, it disables itself and the second again. In each of the triggers, you can get the pieces of the message and put them back together.
Australia Forum Administrator #63
Renox Dashin said:

Okay that told me nothing,
^(.*?) chats\: \'(.*?)\\n(.*?)\'\\Z$
thats my attempt at a multi-line chat trigger,


I repeatedly ask people here to post their triggers using the inbuilt copy function.

Template:copying
For advice on how to copy aliases, timers or triggers from within MUSHclient, and paste them into a forum message, please see Copying XML.


Just pasting the match line tells me nothing about whether you have regular expressions checked, multi-line checked, and other relevant things.

Also you haven't posted what you are trying to match on (copy and paste some samples). Maybe there is an extra space there you didn't spot.

Renox Dashin said:

All i need to know is what to change to make it pick up multiline chats, I can figure the rest out on my own. All i need is the updated trigger. I've got the blasted thing to work, EXCEPT for multi-lines, I feel like i'm on a customer service line, Always being transfered to a different operator and never quite getting the service i request.


The service, huh? Would that be the free technical support for the free software you downloaded? I get around 2000 to 3000 downloads of MUSHclient every month. As an unpaid supporter it really isn't feasible for me to give lengthy detailed support to every one of those downloaders. I try very hard to support people, but after typing in pages and pages of examples of doing multiple line triggers, and then looking up where those pages are, I expect you to at least make an attempt to read them and implement the suggestions in them.

The fact is that the multiple-line trigger feature in the client, whilst it works, can easily match too much or too little. For example with two chats in a row it might match both of them, and maybe the stuff inbetween. The techniques I describe are more likely to work.

If what you posted above is really what you have it is wrong on at least two counts, the \\Z should be \Z and then \\n should be \n.

I can't force you to read the documentation but I put a lot of work into it, and reading it will help you.

Template:regexp
Regular expressions
  • Regular expressions (as used in triggers and aliases) are documented on the Regular expression tips forum page.
  • Also see how Lua string matching patterns work, as documented on the Lua string.find page.
Netherlands #64
Ok, I have been trying to edit this to make it work for New Worlds ateraan.
But I ran into a problem, as the chats don't always end in the same symbol, and wrap around.
(so far I have only managed to have it recognise the first line)

sample output here:

 Neechi <OOC> no it wasn't
 Drustian <OOC> Going back in time; dingy acts like it never was out in the
                first place. there will be some odd things. Also, ask things
                like that on question. :)
 Kegan <OOC> so this is YOUR fault Walter!
 <OOC> Reana chuckles.
Alzheni <CHAT> Neechi clearly has no sense of humor
Alzheni <CHAT> I forgive her, though
Reana <CHAT> I think that was her sense of humor. lol.
 <OOC> Elani winks at Walter.
Alzheni <CHAT> Don't hit me with your logic!
<CHAT> Drustian mutters under his breath
<CHAT> Airith pets Drustian soothingly
 Fericia <OOC> Andrew, quick tell?


my current thinking is that I could achieve this by having 3 triggers:
one that triggers to the first line.
two seperate triggers that trigger to: a certain number of spaces followed by at least one character of the correct colour.

the first trigger enables the 2nd.
the 2nd enables the 3rd and disables itself.
the 3rd enables the 2nd and disables itself.

Do you think that could work? or am I needlessly complicating things?
Amended on Wed 08 Jun 2011 10:16 PM by Roady
Australia Forum Administrator #65
Yes I think you are on the right track, except maybe that 3rd trigger.

The 2nd trigger (the spaces followed by the rest of the chat) is likely to stay enabled indefinitely, because there is nothing to disable it (like, if there were 4 lines).

I think I would have trigger 1 matching the start of the chat, and enable 2 and 3.

Trigger 2 matches the rest of the chat (spaces ... chat) and copies that to wherever (like the miniwindow).

Trigger 3 matches "*" but is a lower priority. Thus trigger 3 matches all lines that are *not* chat. When it fires it disables triggers 2 and 3.

I think I would leave trigger 1 enabled (because you may get 2 chats in a row).
Netherlands #66
so a trigger can't disable itself?
My idea was that the 2nd and 3rd triggers are the same and end up alternately disabling themselves and enabling the other. (until it no longer matches the correct pattern)

...thinks
realises that that indeed needs additional triggers to disable the 2nd/3rd trigger on a new line.

in that case
yes, your idea sounds like a much better approach(as it requires less triggers).
but wouldn't that 3rd trigger end up constantly disabling the 2nd trigger without it being re-enabled, resulting in it never catching more than 2 lines?
(I guess I don't really know how priority works exactly)
Amended on Thu 09 Jun 2011 05:19 PM by Roady
Australia Forum Administrator #67
Yes, a trigger can disable itself, I just don't like the idea of two triggers toggling each other.

I meant "a higher sequence number" for the 3rd trigger, which is a lower priority. If a trigger fires, and you don't have "keep evaluating" checked, that stops further trigger evaluations.

I use that often to have a specific trigger (like in your case, to catch a chat line) and then a "catch-all" trigger with a lower priority (higher sequence) which it falls through to if the specific trigger doesn't match.
Netherlands #68
ah now I see, thanks for the clarification.
that should be enough information for me to figure things out on my own.

EDIT:
and I have (Ithink), below is an example of the triggers I used.
I haven't tested it that thoroughly yet, but it seems to properly catch more than 1 line, without sending EVERYTHING to the miniwindow. (I haven't yet tested wetter it catches 3 or more lines though)


  <triggers>

  <trigger
   enabled="y"
   match="^.*\&lt;CHAT\&gt;.*$"
   match_text_colour="y"
   omit_from_output="y"
   regexp="y"
   script="chats"
   send_to="12"
   sequence="100"
   text_colour="13"
  >
  <send>EnableGroup ("CHATx" , true)
    </send>
  </trigger>

  <trigger
   enabled="n"
   group="CHATx"
   match="^\s{3,}.+$"
   match_text_colour="y"
   omit_from_output="y"
   regexp="y"
   script="chats"
   sequence="100"
   text_colour="13"
  >
  </trigger>

  <trigger
   group="CHATx"
   match="*"
   send_to="12"
   sequence="101"
  >
  <send>EnableGroup ("CHATx" , false)    
    </send>
  </trigger>

</triggers>

Amended on Fri 17 Jun 2011 11:59 AM by Roady
Australia Forum Administrator #69
I edited your triggers so they can be pasted back into the client if other people want to try them:

Template:pasting
For advice on how to copy the above, and paste it into MUSHclient, please see Pasting XML.


That looks like the right idea.
USA #70
Upgraded to 4.73 and decided to update this as well, and now the window defaults to top left instead of top right.

Which unfortunately forces me to ask... What do i need to change to put it back to defaulting to top right?
Australia #71
Is there a way to have multiple miniwindows opened from this script?

Example:
[Chat] Person waves.
[Community] Anotherperson cheers.
[Roleplay] Somebody says, "Hi."
Person pages: "Heya."

In the above example, I want the [Chat] and [Community] to go to one miniwindow called 'Communications', [Roleplay] to go to another miniwindow called 'Misc' and the page to go to a third window called 'Pages'

Do I need three seperate script files, or can it be done somehow by using the Trigger's 'group' field?
Australia Forum Administrator #72
You could adapt that one by making multiple windows. Something along the lines of, instead of:


Win = GetPluginID()


do:


Win = GetPluginID() .. "_Community"


Of course, you would change the last bit based on the trigger which has the chat channel in it.

This would need to be moved from a "global" assignment (done once) to inside the trigger script. Plus you would need to create all the windows when the plugin opens. But it could be done, yes.
Australia #73
These are the changes I have made. I do not know if they are valid changes or not, as I am not a coder and this is my first toe-dip into the xml and plugin coding.

Quote:

<trigger
enabled="y" keep_evaluating="y" regexp="y" omit_from_output="y"
match="^\[(Public|Roleplay|Code|Help|Chargen)\] .*"
script="chats"
send_to="12"
sequence="100"
>
<send>
Win = GetPluginID() .. "_Chats"
TRIGGER_TITLE_NAME = Chat Channels
</send>
</trigger>

<trigger
enabled="y" keep_evaluating="y" regexp="y" omit_from_output="y"
match="^(Long distance to |You paged |From afar, |.* pages: |\(To: .*\) ).*"
script="chats"
send_to="12"
sequence="100"
>
<send>
Win = GetPluginID() .. "_Pages"
TRIGGER_TITLE_NAME = Pages
</send>
</trigger>


Quote:

theme = {
TITLE_NAME = TRIGGER_TITLE_NAME, -- for miniwindow title area
}


Quote:

-- Title text
WindowText(Win, "titlefont"..Win, theme.TITLE_NAME, ((WINDOW_WIDTH)-(7.5*line_height))/2, (theme.TITLE_HEIGHT-line_height)/2, WINDOW_WIDTH, theme.TITLE_HEIGHT, theme.HIGHLIGHT, false)


When I install it I get the following error messages

Quote:

Error number: 0
Event: Run-time error
Description: [string "Plugin"]:116: bad argument #1 to 'WindowCreate' (string expected, got nil)

stack traceback:

[C]: in function 'WindowCreate'

[string "Plugin"]:116: in function <[string "Plugin"]:114>
Called by: Function/Sub: OnPluginInstall called by Plugin Chat_Capture_Miniwindow

Reason: Executing plugin Chat_Capture_Miniwindow sub OnPluginInstall


And when triggering the Chat trigger:

Quote:

Error number: 0
Event: Compile error
Description: [string "Trigger: "]:4: '=' expected near '<eof>'
Called by: Immediate execution


Quote:

Error number: 0
Event: Run-time error
Description: [string "Plugin"]:449: attempt to compare string with number

stack traceback:

[string "Plugin"]:449: in function 'add_line'

[string "Plugin"]:359: in function 'fillBuffer'

[string "Plugin"]:439: in function <[string "Plugin"]:411>
Called by: Function/Sub: chats called by trigger

Reason: processing trigger ""



[EDIT] (by moderator) quoted forum codes.
Amended on Fri 11 Nov 2011 02:54 AM by Nick Gammon
Australia Forum Administrator #74
After some experimenting, I think it would be easier to just make 3 plugins, once for each chat style.

Give each one a different plugin ID, eg.


81db44d9d749abe990cb39f4
6e6499aaa51cd07b6d2aa031
f560226b0139d394da61e7a6


Otherwise you'll get an error message about "plugin already loaded".

This goes here, near the start:


<muclient>
    <plugin
    name="Chat_Capture_Miniwindow"
    author="Fiendish"
    id="565dae21eb816a2fdb8d50f9"


Then make a trigger for each plugin, one for each type of chat.

Somewhere near the middle, on this line:


   -- Title text
    WindowText(Win, "titlefont"..Win, "COMMUNICATION", ((WINDOW_WIDTH)-(7.5*line_height))/2, (theme.TITLE_HEIGHT-line_height)/2, WINDOW_WIDTH, theme.TITLE_HEIGHT, theme.DETAIL, false)


Change "COMMUNICATION" to whatever for each window (eg. "CHATS", "PAGES", etc.).
#75
I'm new to mush and am in the process of trying to convert all my zmud scripts over to mush as I'v just about had it with how unstable zmud.

I am using Nick's modified version of the scrolling chat window and I have it working fine, but there is one thing I would like to be able to do and have yet to figure it out. I'm trying to make an alias that will send whatever I want to the window as if it were captured from the mud. I'v tried to decipher the script as best I could and as far as I can tell it needs to trigger off a style and so I can't just send it a text string to have it display in the window. Is there anyone that can help me do this?

Thanks!
USA Global Moderator #76
I would add the following function:


-- Takes input as a string with embedded color codes. Use via CallPlugin().
-- See:   http://mushclient.com/scripts/doc.php?function=CallPlugin
-- You can manually embed your own colors using @ codes described in mw.lua to push any colorized line you want to the log window.
-- Example: CallPlugin("565dae21eb816a2fdb8d50f9","storeFromOutside","HELLO@RHello@Mhello")

require "mw"
function storeFromOutside(text)
   chats (nil, nil, nil, mw.ColoursToStyles(text))
end


And then you can make any alias you want, or any other script you want, send lines to the plugin as if they were captured from the game using the CallPlugin interface

[EDIT] fixed invocation of ColoursToStyles per notice below
Amended on Wed 17 Oct 2012 10:12 AM by Fiendish
#77
Thanks Fiendish, I managed to get it working with that.

There is a problem minor issue though. When I require "mw" my scripts still have issue with finding the functions required in mw.lua. The only way I was able to solve this issue was by copying the mw functions I needed into the chat script file. Is there a way I can fix this so I'm not having to needlessly add code?

Thanks
USA Global Moderator #78
Hmm. Is your mw.lua in the Lua directory? And what version of MUSHclient are you using?
#79
4.73, and yea it is. Seems the movewindow.lua is found correctly since the script uses that, but mw is a no go.
USA Global Moderator #80
Ahh, oops. Try prefixing the function calls with "mw."

This is because of the line
module (..., package.seeall)
in the file. (http://lua-users.org/wiki/ModulesTutorial)

I have edited my earlier post to reflect this.
Amended on Wed 17 Oct 2012 10:12 AM by Fiendish
#81
I learned how to swap stuff out with nicks inventory window, and have made few plugins to have stats in windows, and all of them are movable.

What I'm at now is trying to figure out the resizing aspect/scrolling that you have in this plugin.

Could someone please detail how this script does that, thuroughly. I cant tell what is what, since in comparison I was told most of how the inventory window worked in Nicks video.
USA Global Moderator #82
Quote:
What I'm at now is trying to figure out the resizing aspect/scrolling that you have in this plugin. Could someone please detail how this script does that, thuroughly.

Math. Also programming. :\

*sigh* Ok, here goes...

As with just about any aspect of user interaction, the place to start looking is in functions that define what happens when the user activates the mouse button while over a hotspot. These are associated with the various hotspots in the calls to WindowAddHotspot and WindowDragHandler (see MUSHclient miniwindow docs). By inspection of the plugin code we can see that they are named MouseDown, ResizeMoveCallback, and to lesser degrees MouseUp, CancelMouseDown, and ResizeReleaseCallback.

Quote:
scrolling


Scrolling the text requires that you think of the chat window as an actual narrow window onto a much larger body of text with sequentially numbered lines. At any moment, the window view displays a set of lines of text starting from some line number (let's call it TOP_LINE) and ending at TOP_LINE+N, where N is the number of lines that fit in the window given its current size. When you scroll up and down, all you are doing is changing the value of TOP_LINE. Either subtracting from it when scrolling up, or adding to it when scrolling down. Obviously special care must be taken to not scroll off the ends (you can't show line number -1, for example).

Once you have basic scrolling, the next part is constructing a proportionally sized and spaced scrollbar widget.

The principles of a proportional scrollbar are as follows:

Starting with a chat storage buffer such that each array index contains a single printable line of text (this means chats in the buffer must already be line-wrapped for display. See function fillBuffer that breaks up styleruns according to the miniwindow width), you need to first find out how large to make the shuttle and then where to position it on the scrollbar...

You have a number of buffered text lines (Let's call this number of lines T). You also have a window that can display some number of lines at a time (let's call this number of lines D and is the text display area height divided by the text line height). The third number we'll need is the number of vertical pixels that you want the scrollbar region to fill (let's call that number of pixels P). This could be the entire vertical height of the miniwindow or some subset thereof (accounting for titlebar, resize widget, etc). The ratio of lines that can be displayed to total lines (D/T) governs both the size of the scrollbar shuttle and which set of lines gets displayed for a given bar location.

The height of the scroll shuttle is always going to be math.max(MIN_SHUTTLE_HEIGHT, math.min(P, (D/T)*P)). This means use a proportional number of the available pixels except for two cases. You want a minimum scroll shuttle height so that the shuttle doesn't get too small to grab with the cursor if you have thousands of buffered lines and a very small window. You also want to make sure the shuttle doesn't try to be larger than the designated scrollbar area if you have fewer buffered lines than will fit in the miniwindow (D/T would then be > 1).

The position of shuttle in the scrollbar should be determined in the following way. Divide the scrollbar into a proportional series of pixel increments, one step for each possible line of text to be shown, by (P/T). Now whatever line of text you want to start (or end, depending on orientation preference) the display section with can be directly related to a shuttle position and vice versa.

Quote:
the resizing


I'm actually going to explain how it *should have* been done, because in hindsight I have always made resizing functions a bit longer than they need to be. Also the implementation posted in this thread is buggy. Discovering how is left as an exercise for the reader after reading the next paragraph.

On MouseDown save the x and y distances from the mouse's position to the bottom right corner of the miniwindow (width-WindowInfo(win, 17) and height-WindowInfo(win, 18)). Call them offset_x and offset_y. Then, every ResizeMoveCallback, set the window width and height to the current mouse position relative to the miniwindow (WindowInfo(win, 17) and WindowInfo(win,18) again) plus the original offsets, bounded by some arbitrary minimum width/height and some maximum width/height equal to reaching the edges of the screen.

The method implemented at the beginning of this thread is quite similar in nature. But I think that storing and using the original corner offset is probably a philosophically better idea than tracking the mouse movement at every drag step, but they can be equally functional if both done correctly.

After the window has been resized, we want to re-wrap all the old chats so that it all fits nicely into the new width. For performance reasons we can only safely do this when the user releases the mouse button after dragging (ResizeReleaseCallback), because the mechanism for linewrapping the stored chats is, sadly, not nearly fast enough to run dozens of times per second while dragging the resizer.

[EDIT] made a few edits for organizational clarity
Amended on Sat 15 Dec 2012 02:56 PM by Fiendish
#83
I am curious if some one has adapted this to support multiple windows. I have some many channels to keep an eye on I'd like to pop more than one window and direct the output accordingly, but I don't see an easy way to have twoinstances of this or to pop a second mini-window with a distinct ID that can be re-directed to.
USA Global Moderator #84
The simplest way is to duplicate the plugin and edit the second one to have a new ID number.
Australia Forum Administrator #85
MUSHclient Edit menu -> "Generate Unique ID" will give you a plugin ID you can use. Of course in the duplicated plugin you probably need to change the triggers slightly.
#86
Thanks for the great info worked perfect. Now one other question I have turned the echo off on the second window I created because it is just noisy stuff like fishing feed back but even though they are flagged as omit from output and echo is off my prompt is cycling on each action which then defeats the purpose of moving the info to another window. Is there a good way to keep my prompt from cycling?
Australia Forum Administrator #87
What do you mean by cycling exactly? Repeating?
#88
I was getting a blank line and a new prompt in my main window for every entry redirected to the miniwindow. I added the plugin to eliminate the blank lines but now need to figure out how to gag my prompt so it doesn't repeat after these actions.
Australia Forum Administrator #89
I would suggest making a trigger that matches the prompt, compare it to the previous one, and if the same, do nothing. Otherwise echo the prompt. Of course, you omit the original one from output.
#90
I was looking through the code for a way to wipe the contents of the window and start over but nothing popped out to me as a good approach. Is it possible on a trigger to destroy clear the buffers and then recreate the window?

Thanks

Amended on Sun 06 Jan 2013 08:34 PM by CincyMush
USA Global Moderator #91
Quote:
Is it possible on a trigger to destroy clear the buffers and then recreate the window?

Of course. That is exactly the right way to do it.
#92
So did a WindowDestroy then reset the tables and forced the trigger back through the init function, seems to have done the trick.
USA #93
Depending on what you want to do, you could also use WindowRect to draw over everything with a single color, and use WindowDeleteAllHotspots to remove all the hotspots.
#94
This plugin is a godsend.
Thank you very much.
USA #95
Thanks much for putting this together!
USA #96
Hi, I'm in the process of trying to change over from tintin to MUSHclient. I really like the looks of it. Right now I'm adapting this chat mini-window to my MUD.

One thing I don't understand is that if I turn off echoing and type "say hello". I get the "You say 'hello' in the mini-window but I also get a new prompt with nothing on it from my mud. I'm not sure if that is something my mud is doing and I can't prevent or something coming from MUSHclient?

Example:

With echo ON:
<Some Prompt>
say hello
You say 'hello'
<Some Prompt>

Wth echo OFF:
<Some Prompt>
say hello
<Some Prompt>

How can I stop that second prompt? This happens when someone else is chatting and I capture in my log as well. I'll get the two prompts below. The first is when nothing has happened, then someone chats, it goes to my chat window but I still get a new prompt in the main window.

<Some Prompt>
<Some Prompt>

Can I stop the second prompt?
Australia Forum Administrator #97
This is a fairly common problem, because the MUD sends two prompts. You may have suppressed the "You say 'hello' " message but you haven't suppressed the second prompt.

One approach is to detect prompt lines in a trigger, omit them, and then in a script detect if the prompt has changed. If it is different, echo it (Note or ColourNote it). That suppresses multiple identical prompts.
USA Global Moderator #98
Nick Gammon said:

One approach is to detect prompt lines in a trigger

Detecting prompts is a path to sin. Or more poetically, "Abandon all hope, ye who enter here."

It sounds to me like the game always sends a prompt after a chat, since other people's chats also initiate prompts. So you should just be masking out the next line from the mud after any chat.
Australia Forum Administrator #99
I didn't say it was a good approach. ;)
#100
I was hoping to ask how difficult you guys thought it would be to add the feature where you could click on an empty part of the scrollbar and have it scroll in that direction by one page.

Hope this hasn't already been done and I've missed it, but I haven't found it anywhere in the code or in the newer versions of the chat window plugin.

Let me know if you can if you believe this would be an easy thing to do or more work than its worth.
USA Global Moderator #101
Mat said:

I was hoping to ask how difficult you guys thought it would be to add the feature where you could click on an empty part of the scrollbar and have it scroll in that direction by one page.


For whom? For me it would be trivial.
But my feeling is that asking that question means my answer has to be "for you, difficult". If it weren't, you probably wouldn't be asking, right? You'd find the place where all the hotspots get constructed, see how the up/down buttons and mousewheel operate, and then add a hotspot in the scrollbar background rectangle that uses relative position between mouse and slider to determine page up vs page down, and then for up you'd do something like
lineStart = math.max(1, lineStart-WINDOW_LINES)
lineEnd = math.min(#lines, lineStart+WINDOW_LINES-1)
drawStuff()

and for down you'd do similar but in the other direction.
Amended on Wed 02 Jul 2014 04:04 PM by Fiendish
#102
Thanks very much for the help!

After a bit of time I got it up and running.
Gave me a bit of trouble trying to figure out why the scrollbar background hotspot was taking priority as if it were covering the scrollbar position indicator.
But after a quick search I read that it checks for priority of overlapping hotspots by alphabetical order, not by order in which they were added.

Renamed the hotspot_id to "scroller2" and it works like a charm.

Thanks again for the help!

Also, if curious:
Hotspot firsttime area:

WindowAddHotspot(Win, "scroller2", WINDOW_WIDTH-SCROLL_BAR_WIDTH, TITLE_HEIGHT+SCROLL_BAR_WIDTH, 0, WINDOW_HEIGHT-(SCROLL_BAR_WIDTH * 2), "MouseOver", "CancelMouseOver", "MouseDown", "CancelMouseDown", "MouseUp", "", 1, 0)

Hotspot after firsttime:

WindowMoveHotspot(Win, "scroller2", WINDOW_WIDTH-SCROLL_BAR_WIDTH, TITLE_HEIGHT+SCROLL_BAR_WIDTH, 0, WINDOW_HEIGHT-(2*SCROLL_BAR_WIDTH))

Within MouseDown:

	elseif (hotspot_id == "scroller2") then
		mouseY = WindowInfo (Win, 15)
		if (mouseY < barPos) then
			lineStart = math.max(1, lineStart-WINDOW_LINES)
			lineEnd = math.min(#lines, lineStart+WINDOW_LINES-2)
		else
			lineStart = #lines-WINDOW_LINES+2
			lineEnd = #lines
		end
		drawStuff()
Amended on Wed 02 Jul 2014 06:02 PM by Mat
#103
Just wanted to add that this does not properly load font/fontsize if you change it.
Small patch to fix it.

Change

BODY_FONT_NAME = "Dina"
BODY_FONT_SIZE = 8


To



BODY_FONT_NAME = GetVariable("bodyfont") or "Dina"
BODY_FONT_SIZE = tonumber(GetVariable("font_size") or 8)
#104
There might be a better forum for this but I just wanted to say thank you for all the mini-window stuff! So much.

I've been trying to create a mini-window module, to teach myself Lua and to create widgets and stuff. It was crashing the client, seemingly at random, after I would try to resize things. It was probably my code but it hasn't crashed since I got version 4.96. So happy! Either way, thanks for the awesome client! It really is impressive how well Mushclient holds up to my repeated attempts to break it. So good. And free!
Portugal #105
Hi Nick. I see that this Mini Window is exactly what i need. I saw on your firsts posts that it has a version 2, then 2.2, till 2.4. Where can i find the last version?
USA Global Moderator #106
As far as I know, Nick doesn't constantly update his genericized version to keep pace with my whims in my Aardwolf package development. He did the original conversion as a community service.
Amended on Wed 11 Mar 2015 01:59 PM by Fiendish
Portugal #107
Thank you again Fiendish.
I'm strugling on some regex, they don't want to work.
This is what i need:

1) Player1 is in Somewhere [200]
2) Player2 is in Somewhere [200]
3) Player3 is in Somewhere [200]
4) Player4 is in Somewhere [200]
5) Player5 is in Somewhere [200]
6) Player6 is in Somewhere [200]
7) Player7 is in Somewhere [200]
8) Player8 is in Somewhere [200]

I need to capture and send to the mini window only the player name, not the rest...
When i had triggers to do that, i only had this:

(.*) (.*) is in (.*)

But if i do this, it shows nothing on the Mini Window.
USA Global Moderator #108
Quote:
i only had this:

(.*) (.*) is in (.*)

Useless incomplete information.

Template:copying
For advice on how to copy aliases, timers or triggers from within MUSHclient, and paste them into a forum message, please see Copying XML.
Amended on Wed 11 Mar 2015 04:03 PM by Fiendish
Portugal #109
<triggers>
<trigger
enabled="y"
match="(.*) (.*) is in (.*)"
regexp="y"
send_to="12"
sequence="100"
>
<send>player = "%2"

print(player)</send>
</trigger>
</triggers>


Like this it works, but how do i put that into the mini window code? Is just replace the trigger?
USA Global Moderator #110
Either replace the triggers in the plugin or follow http://mushclient.com/forum/?id=10728&reply=76#reply76
Portugal #111
If i replace the trigger it sends the print to the world, and i want it to be displayed on the mini window.
The timestamp is there, i only need the name of the player.
Australia Forum Administrator #112
That thread is so long I can't remember everything in it. However from the first page:


 <trigger
    enabled="y"
    match="You tell * '*'"
    script="chats"
    omit_from_output="y"
    sequence="100"
    ></trigger>


All the triggers intended to put things in the chat window have "chats" as their script function.

Your posted trigger does not.
Portugal #113
You are right Nick, and i changed that. Still no luck. It must be something in the Regex, but i can't figure out what.
USA Global Moderator #114
The chats script function isn't really meant to do only partial capture. If you want to only record a certain bit of information, I think you should add the storeFromOutside function as shown in http://mushclient.com/forum/?id=10728&reply=76#reply76 and then call it from your world trigger as shown in the comment for that function.
Portugal #115
Fiendish, thank you for your help, and sorry in advance for asking this.
If i want to do what you are saying, how do i do that? Where do i put that function and what would it say?
Put that inside the chat plugin? Make a new one?
Sorry for this questions, but i really didn't follow you on this.
USA Global Moderator #116
You put the function in the chat plugin next to all the other functions.
Portugal #117
Thank Fiendish. It worked.

<triggers>
<trigger
enabled="y"
match="(.*) (.*) is in (.*)"
script="chats"
send_to="12"
sequence="100"
>
<send>CallPlugin ("6e6499aaa51cd07b6d2aa031", "storeFromOutside", "%2")</send>
</trigger>
</triggers>

And then put the function:

function storeFromOutside(text)
chats (nil, nil, nil, mw.ColoursToStyles(text))
end


There is only one problem. It shows what i want, but shows the all line again, meaning, i get the name and the all sentence in the next line. How do i remove the all line and keep only the name?
Thank you again.
USA Global Moderator #118
Your new trigger has a pattern that looks like it should be a regexp but it is not flagged as one.
Amended on Fri 13 Mar 2015 12:45 AM by Fiendish
Portugal #119
I've tried that, an still no luck. It get's doubled.
It shows the name only (what i want) and the all string in the next line.


<triggers>
<trigger
enabled="y"
match="(.*) (.*) is in (.*)"
regexp="y"
script="chats"
send_to="12"
sequence="100"
>
<send>CallPlugin ("6e6499aaa51cd07b6d2aa031", "storeFromOutside", "%2")</send>
</trigger>
</triggers>
USA Global Moderator #120
It sounds to me like maybe you have multiple triggers firing.
Portugal #121
Fiendish,
Thank you for your help. I've struggle and i figure that out. Besides i had 2 triggers, i had some problems in the plugin itself, cause i changed a couple of things off the one that Nick posted.
The important thing is that it is working now.
Once again, thank you for your help.