<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>


<muclient>
<plugin
   name="PromptProcessor"
   author="Keldar"
   id="9f182a333c462078704116cd"
   language="Lua"
   purpose="Terminates prompts with newlines and displays stat changes"
   save_state="y"
   date_written="2006-05-29"
   requires="3.80"
   version="1.8"
   >
 <description trim="y">
<![CDATA[
Terminates prompts with newlines and appends information about stat changes
to them.

hintprompt on|off    -   turn stat hints on and off.

fixprompt on|off     -   turn newline termination on and off*.

hintmode #           -   choose a display mode for hints**.

hintconfig hmew      -   select which vitals should have hints displayed.

kaibar on|off        -   controls whether a gauge for kai should be displayed.

unique on|off        -   toggles whether redundant*** prompts should be 
                         gagged (on) or displayed (off).

gagclot on|off       -   suppress successive prompts caused by clotting

limits on|off        -   when this is enabled (together with the unique option)
                         only stat changes that exceed the specified limits will
                         be considered when displaying a prompt. Limits can be set
                         individually for each stat.

limit h|m|e|w <num>  -   sets the change limit for the respective stat, for use
                         with the limits option****.
                         

Hint display modes:

  1 - displays hints only for changed vitals, appends vital labels;
  
  2 - displays hints for all vitals (regardless of changes), doesn't
      append labels to conserve space;
      
  3 - displays hints for all vitals, like mode 2 above, but appends
      labels also like mode 1.

Notes: 
  * - Stat hints may not always work consistently if newline termination is
      switched off.
 ** - Switching to a different display mode turns hinting on if it is currently
      disabled.
*** - Redundant prompts are the ones that immediately follow each other without
      containing any new changes.
****- To disable limits for some stats (i.e. health and mana) but leave them
      enabled for others, set the limits you want to disable to 0.
      
]]>
    </description>

</plugin>


<!--  Triggers  -->

<triggers>
  <trigger
   enabled="n"
   name="prompt"
   match="^(?P&lt;h&gt;\d+)h, (?P&lt;m&gt;\d+)m(?:, (?P&lt;e&gt;\d+)e|)(?:, (?P&lt;w&gt;\d+)w|) (?P&lt;str&gt;c?e?x?k?d?b?\@?)-(?P&lt;kai&gt;[+]{1,5}--)?$"
   omit_from_output="y"
   regexp="y"
   script="displayPrompt"
   sequence="100"
  >
  </trigger>
</triggers>

<!--  Variables  -->

<aliases>
  <alias
   match="^\s*gagclot\s+(on|off)\s*$"
   enabled="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>if "%1" == "on" then
  SetVariable("gagclot", "1")
  PromptProcessor.gagclot = true
  DoNote("Clotting prompts will be omitted.")
else
  SetVariable("gagclot", "0")
  PromptProcessor.gagclot = false
  DoNote("Clotting prompts will now be displayed.")
end</send>
  </alias>
</aliases>


<aliases>
  <alias
   match="^\s*limits\s+(on|off)\s*$"
   enabled="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>if "%1" == "on" then
  SetVariable("limits", "1")
  PromptProcessor.limits = true
  DoNote("Only stat changes that exceed set limits will be considered.")
else
  SetVariable("limits", "0")
  PromptProcessor.limits = false
  DoNote("All stat changes will be displayed.")
end</send>
  </alias>
</aliases>

<aliases>
  <alias
   match="^\s*limit\s+([hmew])\s+(\d+)\s*$"
   enabled="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>local limnames = {h="health", m="mana", e="endurance", w="willpower"}
  limits["%1"] = %2
  DoNote("Display limit for " .. limnames["%1"] .. " set to %2.")</send>
  </alias>
</aliases>



<aliases>
<alias enabled="y" match="^\s*hintprompt\s+(on|off)\s*$" regexp="y" script="SetHints" />
<alias enabled="y" match="^\s*fixprompt\s+(on|off)\s*$" regexp="y" script="SetFixes" />
<alias enabled="y" match="^\s*hintmode\s+(\d+)\s*$" regexp="y" script="SetMode" />
<alias enabled="y" match="^\s*hintconfig\s+(h?m?e?w?)\s*$" regexp="y" script="SetVitals" />
<alias enabled="y" match="^\s*kaibar\s+(on|off)\s*$" regexp="y" script="SetKaiBar" />
<alias enabled="y" match="^\s*unique\s+(on|off)\s*$" regexp="y" script="SetUnique" />
</aliases>

<aliases>
  <alias
   match="^\s*debug\s+(on|off)\s*$"
   enabled="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>if "%1" == "on" then
  DEBUG = true
else
  DEBUG = false
end</send>
  </alias>
</aliases>



<!--  Script  -->


<script>
<![CDATA[

require "tprint"
require "flc.kutils"

colour_map = {}

DoNote = kutils.DoNote
local DoErrorNote = kutils.DoErrorNote


function RGBToName(col)
   local cname = colour_map[col]
   if cname == nil then
      cname = RGBColourToName(col)
      colour_map[col] = cname
   end
   return cname
end

table.extend = function(tab1,tab2) 
   table.foreach(tab2, function (i,v) table.insert(tab1, v) end)
end

prev_prompt = {m=0,h=0,e=0,w=0,str="",kai=false}
limits = {h=0, m=0, e=50, w=50}


function saveLastPrompt(wildcs)
	prev_prompt.h = tonumber(wildcs.h)
	prev_prompt.m = tonumber(wildcs.m)
	if wildcs.e then prev_prompt.e = tonumber(wildcs.e) end
	if wildcs.w then prev_prompt.w = tonumber(wildcs.w) end
	prev_prompt.str = wildcs.str
	if wildcs.kai then prev_prompt.kai = wildcs.kai end
    prompt_line = wildcs[0]
end

function displayPrompt(name, output, wildcs, styles)
  	local w,e,h,m = 0,0,0,0
  	if wildcs.w then w = tonumber(wildcs.w) end
  	if wildcs.e then e = tonumber(wildcs.e) end
  	if wildcs.h then h = tonumber(wildcs.h) end
  	if wildcs.m then m = tonumber(wildcs.m) end

  	--print(PromptProcessor.limits, PromptProcessor.unique, was_prompt)
  if was_prompt and PromptProcessor.unique then
  	if (prompt_line == wildcs[0]) then
    	saveLastPrompt(wildcs)
    	return
    elseif PromptProcessor.limits then
    	if (limits.h >= math.abs(prev_prompt.h-h)) and
    		(limits.m >= math.abs(prev_prompt.m-m)) and
    		(limits.e >= math.abs(prev_prompt.e-e)) and
    		(limits.w >= math.abs(prev_prompt.w-w)) and
    		(prev_prompt.str == wildcs.str) and
    		(prev_prompt.kai == wildcs.kai) then
    		saveLastPrompt(wildcs)
    		return	
    	end
    end
  end
  if PromptProcessor.gagclot then
  	if PromptProcessor.limits then
  		if (prev_prompt.h == h) and 
  			(prev_prompt.e == e) and
  			(prev_prompt.str == wildcs.str) and 
  			(prev_prompt.kai == wildcs.kai) and
  			(prev_prompt.m - m == 60) and
  			(prev_prompt.w - w < 50) then
  			saveLastPrompt(wildcs)
  			return
  		end
  	else
  		if (limits.h >= math.abs(prev_prompt.h-h)) and
  			(limits.e >= math.abs(prev_prompt.e-e)) and
  			(prev_prompt.kai == wildcs.kai) and
  			(prev_prompt.str == wildcs.str) and
  			(prev_prompt.m -m == 60) and
  			(prev_prompt.w - w <50) then
  			saveLastPrompt(wildcs)
  			return
  		end
  	end
  end
  prompt_line = wildcs[0]
  PromptProcessor.repl_func(styles, wildcs)
  echoPrompt(styles)
  saveLastPrompt(wildcs)
  was_prompt = true
end

function showStyles(n,o,w,styles)
	tprint (styles)
end


function echoPrompt(prompt)
  local args = {}  -- a table to hold ColourNote arguments
  
  -- pack the styles into the args table
  table.foreach(prompt, function (i, style) 
    table.extend(args, {RGBToName(style.textcolour), RGBToName(style.backcolour), style.text})
  end)
  ColourNote(unpack(args))
  
end


function findInStyles(styles, pat)
	for i, style in ipairs(styles) do
		local first, last = string.find(style.text, pat)
		if first then
			return first, last, i
		end
	end
	return nil
end

rgb_map = {}

function toRGB(col_name)
	if col_name == "" or col_name == nil then return 0 end
	local rgb = rgb_map[col_name]
	if rgb == nil then
		rgb = ColourNameToRGB(col_name)
		rgb_map[col_name] = rgb
	end
	return rgb
end

function makeStyle(fore, back, txt)
	return {textcolour = toRGB(fore), backcolour = toRGB(back), text=txt}
end


PromptProcessor = {
    replFunc = nil,
    achaea = false,
    fix = nil,
    kaibar = false,
    gag_prompt = false,
    gagclot = false,
    limits = false
    }

if (GetVariable("gagclot") == nil) or (GetVariable("gagclot") == 0) then
	PromptProcessor.gagclot = false
elseif GetVariable("gagclot") == "1" then
	PromptProcessor.gagclot = true
end

if (GetVariable("limits") == nil) or (GetVariable("limits") == 0) then
	PromptProcessor.limits = false
elseif GetVariable("limits") == "1" then
	PromptProcessor.limits = true
end

for k,v in pairs(limits) do
	if (GetVariable("limits_" .. k) == nil) then
		SetVariable("limits_" .. k, tostring(v))
	end
end


function make_kaibar(kai, prompt)
  local prompt = prompt
  if PromptProcessor.kaibar and kai then
    local kaipart = table.remove(prompt)
    kaipart.text = string.gsub(kaipart.text, "[-][+]+[-][-]", "-")
    table.insert(prompt, kaipart)
    table.insert(prompt, makeStyle("silver", "", "["))
    local num = 0
    for plus in string.gmatch(kai, "[+]") do
      num = num + 1
    end
    table.insert(prompt, makeStyle("lime", "", string.rep("\127", num)))
    table.insert(prompt, makeStyle("olive", "", string.rep("\127",5-num)))
    table.insert(prompt, makeStyle("silver", "", "]"))
  end
  return prompt
end

PromptProcessor.to_hint = {}



PromptProcessor.repl1 = function(prompt, wildcs) 
  -- Displays hints only for changed vitals with
  -- labels appended

	local change, txt
	local fore, back = ""
	local style = {}
	--local wildcs = filterWildcs(wildcs)
  local order = {"h", "m", "e", "w"}
  local prompt = make_kaibar(wildcs.kai, prompt)
  
  for _, v in ipairs(order) do
    local wc = wildcs[v]
    
    if (wc ~= "") and PromptProcessor.to_hint[v] then  
      if PromptProcessor["last_"..v] then
    
        change = tonumber(wc) - PromptProcessor["last_"..v]
        if change > 0 then
          txt = "+" .. tostring(change) .. v
          fore = "lime"
        elseif change < 0 then
          txt = tostring(change) .. v
          fore = "red"
        end
        if change ~= 0 then
  				table.insert(prompt, makeStyle("silver", "", "["))
	  			table.insert(prompt, makeStyle(fore,back,txt))
		  		table.insert(prompt, makeStyle("silver", "", "]"))
        end
        
      end
      PromptProcessor["last_"..v] = tonumber(wc)
    end
  end
  return prompt
  
end


PromptProcessor.repl2 = function(prompt, wildcs)
  -- Displays hints for changed and unchanged vitals
  -- without labels to conserve space
  local change, txt
  local fore, back = ""
  local style = {}
  local order = {"h", "m", "e", "w"}
  local prompt = make_kaibar(wildcs.kai, prompt)
  
  for _,v in ipairs(order) do
    local wc = wildcs[v]

    change = nil
    
    if wc ~= "" and PromptProcessor.to_hint[v] then
      local last = PromptProcessor["last_"..v] or tonumber(wc)
      
      change = tonumber(wc) - last
      PromptProcessor["last_"..v] = tonumber(wc)

      if change > 0 then
        txt = "+" .. tostring(change)
        fore = "lime"
      elseif change < 0 then
        txt = tostring(change)
        fore = "red"
      else
        txt = "0"
        fore = "silver"
      end

  	  table.insert(prompt, makeStyle("silver", "", "["))
	  	table.insert(prompt, makeStyle(fore,back,txt))
  		table.insert(prompt, makeStyle("silver", "", "]"))
          
    end
  end
  return prompt
 
end

PromptProcessor.repl3 = function(prompt, wildcs)
  -- Displays hints for changed and unchanged vitals
  -- with labels appended
  local change, txt
  local fore, back = ""
  local style = {}
  local order = {"h", "m", "e", "w"}
  local prompt = make_kaibar(wildcs.kai, prompt)
  
  for _,v in ipairs(order) do
    local wc = wildcs[v]

    change = nil
    
    if wc ~= "" and PromptProcessor.to_hint[v] then
      local last = PromptProcessor["last_"..v] or tonumber(wc)
      
      change = tonumber(wc) - last
      PromptProcessor["last_"..v] = tonumber(wc)

      if change > 0 then
        txt = "+" .. tostring(change) .. v
        fore = "lime"
      elseif change < 0 then
        txt = tostring(change) .. v
        fore = "red"
      else
        txt = "0" .. v
        fore = "silver"
      end

  	  table.insert(prompt, makeStyle("silver", "", "["))
	  	table.insert(prompt, makeStyle(fore,back,txt))
  		table.insert(prompt, makeStyle("silver", "", "]"))
          
    end
  end
  return prompt
  

end


  

function SetKaiBar(name, output, wildcs)
  if wildcs[1] == "on" then
    SetVariable("kaibar", "1")
    PromptProcessor.kaibar = true
    if name ~= "mute" then
      DoNote("Your kai energy will be displayed as a gauge.")
    end
  elseif wildcs[1] == "off" then
    SetVariable("kaibar", "0")
    PromptProcessor.kaibar = false
    if name ~= "mute" then
      DoNote("You have disabled the gauge display for kai.")
    end  
  end
end

function SetHints(name, output, wildcs)
    if wildcs[1] == "on" then
        EnableTrigger("prompt", true)
        if name ~= "mute" then
        DoNote("You will now see hints in your prompt.")
        end
        SetVariable("hintprompt", 1)
    elseif wildcs[1] == "off" then
        EnableTrigger("prompt", false)
        if name ~= "mute" then
        DoNote("You will no longer see hints in your prompt.")
        end
        SetVariable("hintprompt", 0)
    end
end


  
function SetFixes(name, output, wildcs)
    if wildcs[1] == "on" then
        PromptProcessor.fix = true
        if name ~= "mute" then
            DoNote("Your prompts will now be fixed with newlines.")
        end
        SetVariable("fixprompt", 1)
    elseif wildcs[1] == "off" then
        PromptProcessor.fix = false
        if name ~= "mute" then
            DoNote("Your prompts will no longer be fixed with newlines.")
        end
        SetVariable("fixprompt", 0)
    end 
end


function SetMode(name, outp, wildcs)
  
  if PromptProcessor["repl" .. wildcs[1] ] then
    if tonumber(GetVariable("hintprompt")) == 0 then
      Execute("hintprompt on")
    end
    PromptProcessor.repl_func = PromptProcessor["repl" .. wildcs[1] ]
    SetVariable("hintmode", wildcs[1])
    DoNote("Hints will now be displayed in mode " .. wildcs[1])
  else
    DoErrorNote("Unknown display mode = " .. GetVariable("hintmode") )
  end
end


function SetVitals(name, outp, wildcs)
  SetVariable("hintconfig", wildcs[1])
  PromptProcessor.to_hint = {}
  for v in string.gmatch("hmew", "([hmew])") do 
    PromptProcessor.to_hint[v] = true
  end
end

function SetUnique(name, outp, wildcs)
  local map = {on = {"1", "Only unique prompts will be displayed.", true}, 
               off = {"0", "All prompts will be displayed.", false}}
  SetVariable("unique", map[wildcs[1] ][1])
  PromptProcessor.unique = map[wildcs[1]][3]
  if name ~= "mute" then
    DoNote(map[wildcs[1]][2])
  end
end

-- Initialize the settings
--

if not GetVariable("unique") then
  SetUnique("mute", "", {"off"})
end

if not GetVariable("hintconfig") then
  SetVariable("hintconfig", "hm")
end
for v in string.gmatch(GetVariable("hintconfig"), "([hmew])") do
  PromptProcessor.to_hint[v] = true
end
 
if not GetVariable("kaibar") then
  SetVariable("kaibar", "1")
  SetKaiBar("mute", "", {"on"})
else
  if tonumber(GetVariable("kaibar")) == 1 then
    SetKaiBar("mute", "", {"on"})
  else
    SetKaiBar("mute", "", {"off"})
  end
end


if not GetVariable("fixprompt") then
  SetVariable("fixprompt", "1")
  SetFixes("mute", "", {"on"})
else
  if tonumber(GetVariable("fixprompt")) == 1 then
    SetFixes("mute", "", {"on"})
  else
    SetFixes("mute", "", {"off"})
  end
end

if not GetVariable("hintprompt") then
  SetVariable("hintprompt", "1")
  SetHints("mute", "", {"on"})
else
  if tonumber(GetVariable("hintprompt")) == 1 then
    SetHints("mute", "", {"on"})
  else
    SetHints("mute", "", {"off"})
  end
end

-- Set the default replace function
if not GetVariable("hintmode") then
  SetVariable("hintmode", "1")
end
if PromptProcessor["repl" .. GetVariable("hintmode")] then
  PromptProcessor.repl_func = PromptProcessor["repl" .. GetVariable("hintmode")]
else
  DoErrorNote("Unknown display mode = " .. GetVariable("hintmode") )
  Execute("hintmode 1")
end



was_prompt = false
prompt_line = ""
prompt_pat = "^%d+h, %d+m.-c?e?x?k?d?b?@?"

function OnPluginScreendraw(ltype, log, line)
  if string.find(line, prompt_pat) then
    was_prompt = true
    --prompt_line = line
  else
    was_prompt = false
    --prompt_line = ""
  end
end




terminated = false
leftovers = ""



function OnPluginPacketReceived(packet)
--local start = GetInfo(232)
	local orig_packet = packet
    if PromptProcessor.fix then  -- fix prompts only if this option is set
        if (leftovers == "\255") then
        	if (string.sub(packet, 1, 1) == "\249") or (string.sub(packet, 1, 1) ~= "\255") then
    	    	packet = leftovers .. packet
			end
        end
        leftovers = ""
        local pat = "^(\27%[%d?;?%d%dm)\13\10(.*)"
        if terminated and ((string.sub(packet, 1,2) == "\13\10")) then 
            packet = string.sub(packet, 3, -1)
            terminated = false
        elseif terminated and string.find(packet,pat) then
            packet = string.gsub(packet, pat, "%1%2")
            terminated = false
        elseif terminated and (string.sub(packet,1,2) == "\255\249") then
            packet = string.sub(packet, 3,-1)
        end
        if string.find(packet, "\255\249") then
            packet = string.gsub(packet, "\255\249\13\10", "\13\10")
            packet = string.gsub(packet, "\255\249", "\13\10")
            terminated = true
        end
        if string.sub(packet, -2, -1) ~= "\13\10" then
            terminated = false
        end
    end

    if string.sub(packet,-1) == "\255" then
    	leftovers = "\255"
    	packet = string.sub(packet, 1, -2)
    end
    
--local timing = GetInfo(232) - start
--AppendToNotepad("test", "Timing: " .. tostring(timing) .. "\r\n")
    if DEBUG then
    	AppendToNotepad("PromptProcessor", "[OnPluginPacketReceived] \r\n  Incoming:" .. orig_packet .. "\r\n  Outgoing: " .. packet .. "\r\n")
    end
    return packet
end


function debugPrompt(n,o,w,s)
	w = filterWildcs(w)
	tprint(w)
end


function filterWildcs(w)
	local tab = {}
	for k,v in pairs(w) do
		if type(k) == "string" and v and v ~= "" then
			tab[k] = v
		end
	end
	return tab
end

-- Tests
--

tests_tab = {
function ()
    local result = true
    local packet = OnPluginPacketReceived("\255\249Testing\13\10")
    if packet ~= "\13\10Testing\13\10" then
        result = false
    end
    packet = OnPluginPacketReceived("\255\249Testing\13\10")
    packet = OnPluginPacketReceived("\255\249Testing\13\10")
    if packet ~= "Testing\13\10" then
        result = false
    end
    return result    
end,

function ()
    local result = true
    local packet = OnPluginPacketReceived("\255\249Testing")
    if packet ~= "\13\10Testing" then
        result = false
    end
    packet = OnPluginPacketReceived("\255\249Testing")
    packet = OnPluginPacketReceived("\255\249Testing")
    if packet ~= "\13\10Testing" then
        result = false
    end
    return result
end,

function ()
	local result = true
	local packet = OnPluginPacketReceived("Testing\255")
	packet = OnPluginPacketReceived("\249")
	if (packet ~= "\13\10") or (#leftovers > 0) then
		result = false
	end
	return result	
end,

function ()
	local result = true
	local packet = OnPluginPacketReceived("Testing\255")
	packet = OnPluginPacketReceived("\250\200")
	if packet ~= "\255\250\200" then
		result = false
	end
	return result
end

}

function run_tests()
    for i,v in ipairs(tests_tab) do
    	terminated = false
        print (i, "=", v())
        print(#leftovers)
    end
end

--run_tests()
]]>
</script>


</muclient>
