mudgangster

Tiny, scriptable MUD client
Log | Files | Refs | README

handlers.lua (5431B)


      1 local action = require( "action" )
      2 local alias = require( "alias" )
      3 local intercept = require( "intercept" )
      4 local gag = require( "gag" )
      5 local macro = require( "macro" )
      6 local sub = require( "sub" )
      7 local interval = require( "interval" )
      8 
      9 local lpeg = require( "lpeg" )
     10 
     11 local GA = "\255\249"
     12 
     13 local bold = false
     14 local fg = 7
     15 local bg = 0
     16 
     17 local lastWasChat = false
     18 local lastWasGA = false
     19 
     20 local receiving = false
     21 local showInput = true
     22 
     23 local dataBuffer = ""
     24 local pendingInputs = { }
     25 
     26 local function echoOn()
     27 	showInput = true
     28 
     29 	return ""
     30 end
     31 
     32 local function echoOff()
     33 	showInput = false
     34 
     35 	return ""
     36 end
     37 
     38 local function setFG( colour )
     39 	return function()
     40 		fg = colour
     41 	end
     42 end
     43 
     44 local function setBG( colour )
     45 	return function()
     46 		bg = colour
     47 	end
     48 end
     49 
     50 local Escapes = {
     51 	m = {
     52 		[ "0" ] = function()
     53 			bold = false
     54 			fg = 7
     55 			bg = 0
     56 		end,
     57 
     58 		[ "1" ] = function()
     59 			bold = true
     60 		end,
     61 
     62 		[ "30" ] = setFG( 0 ),
     63 		[ "31" ] = setFG( 1 ),
     64 		[ "32" ] = setFG( 2 ),
     65 		[ "33" ] = setFG( 3 ),
     66 		[ "34" ] = setFG( 4 ),
     67 		[ "35" ] = setFG( 5 ),
     68 		[ "36" ] = setFG( 6 ),
     69 		[ "37" ] = setFG( 7 ),
     70 
     71 		[ "40" ] = setBG( 0 ),
     72 		[ "41" ] = setBG( 1 ),
     73 		[ "42" ] = setBG( 2 ),
     74 		[ "43" ] = setBG( 3 ),
     75 		[ "44" ] = setBG( 4 ),
     76 		[ "45" ] = setBG( 5 ),
     77 		[ "46" ] = setBG( 6 ),
     78 		[ "47" ] = setBG( 7 ),
     79 	},
     80 }
     81 
     82 local function printPendingInputs()
     83 	if lastWasChat then
     84 		mud.newlineMain()
     85 
     86 		lastWasChat = false
     87 	end
     88 
     89 	for i = 1, #pendingInputs do
     90 		mud.printr( pendingInputs[ i ] )
     91 
     92 		lastWasGA = false
     93 	end
     94 
     95 	pendingInputs = { }
     96 end
     97 
     98 local function handleChat( message )
     99 	lastWasChat = true
    100 	lastWasGA = false
    101 
    102 	if not message then
    103 		return
    104 	end
    105 
    106 	local oldFG = fg
    107 	local oldBG = bg
    108 	local oldBold = bold
    109 
    110 	fg = 1
    111 	bg = 0
    112 	bold = true
    113 
    114 	local noAnsi = message:gsub( "\27%[[%d;]*%a", "" )
    115 
    116 	action.doChatPreActions( noAnsi )
    117 	action.doChatAnsiPreActions( message )
    118 
    119 	mud.newlineMain()
    120 	mud.newlineChat()
    121 
    122 	for line, newLine in message:gmatch( "([^\n]*)(\n?)" ) do
    123 		for text, opts, escape in ( line .. "\27[m" ):gmatch( "(.-)\27%[([%d;]*)(%a)" ) do
    124 			if text ~= "" then
    125 				mud.printMain( text, fg, bg, bold )
    126 				mud.printChat( text, fg, bg, bold )
    127 			end
    128 
    129 			for opt in opts:gmatch( "([^;]+)" ) do
    130 				if Escapes[ escape ][ opt ] then
    131 					Escapes[ escape ][ opt ]()
    132 				end
    133 			end
    134 		end
    135 
    136 		if newLine == "\n" then
    137 			mud.newlineMain()
    138 			mud.newlineChat()
    139 		end
    140 	end
    141 
    142 	action.doChatActions( noAnsi )
    143 	action.doChatAnsiActions( message )
    144 
    145 	fg = oldFG
    146 	bg = oldBG
    147 	bold = oldBold
    148 end
    149 
    150 local function handleData( data )
    151 	receiving = true
    152 
    153 	dataBuffer = dataBuffer .. data
    154 
    155 	-- TODO: this sucks!
    156 	-- can insert newlines in random places if we receive a GA followed by partial data
    157 	if data:match( GA ) then
    158 		dataBuffer = dataBuffer:gsub( "\r", "" )
    159 
    160 		dataBuffer = dataBuffer:gsub( "\255\252\1", echoOn )
    161 		dataBuffer = dataBuffer:gsub( "\255\251\1", echoOff )
    162 
    163 		dataBuffer = dataBuffer:gsub( "\255\253\24", "" )
    164 		dataBuffer = dataBuffer:gsub( "\255\253\31", "" )
    165 		dataBuffer = dataBuffer:gsub( "\255\253\34", "" )
    166 
    167 		dataBuffer = dataBuffer .. "\n"
    168 
    169 		for line in dataBuffer:gmatch( "([^\n]*)\n" ) do
    170 			if lastWasGA then
    171 				if line ~= "" then
    172 					mud.newlineMain()
    173 				end
    174 
    175 				lastWasGA = false
    176 			end
    177 
    178 			if lastWasChat then
    179 				mud.newlineMain()
    180 
    181 				lastWasChat = false
    182 			end
    183 
    184 			local clean, subs = line:gsub( GA, "" )
    185 			local hasGA = subs ~= 0
    186 
    187 			local noAnsi = clean:gsub( "\27%[%d*%a", "" )
    188 
    189 			local gagged = gag.doGags( noAnsi ) or gag.doAnsiGags( clean )
    190 
    191 			action.doPreActions( noAnsi )
    192 			action.doAnsiPreActions( clean )
    193 
    194 			local subbed = sub.doSubs( clean )
    195 
    196 			for text, opts, escape in ( subbed .. "\27[m" ):gmatch( "(.-)\27%[([%d;]*)(%a)" ) do
    197 				if text ~= "" and not gagged then
    198 					mud.printMain( text, fg, bg, bold )
    199 				end
    200 
    201 				for opt in opts:gmatch( "([^;]+)" ) do
    202 					if Escapes[ escape ] and Escapes[ escape ][ opt ] then
    203 						Escapes[ escape ][ opt ]()
    204 					end
    205 				end
    206 			end
    207 
    208 			if hasGA then
    209 				lastWasGA = true
    210 				printPendingInputs()
    211 			else
    212 				if not gagged then
    213 					mud.newlineMain()
    214 				end
    215 			end
    216 
    217 			action.doActions( noAnsi )
    218 			action.doAnsiActions( clean )
    219 		end
    220 
    221 		dataBuffer = ""
    222 		receiving = false
    223 	end
    224 end
    225 
    226 local function handleCommand( input, hide )
    227 	if not alias.doAlias( input ) then
    228 		if not mud.connected then
    229 			mud.print( "\n#s> You're not connected..." )
    230 
    231 			return
    232 		end
    233 
    234 		intercept.doIntercept( input )
    235 
    236 		if not hide and input ~= "" then
    237 			local toShow = ( showInput and input or ( "*" ):rep( input:len() ) ) .. "\n"
    238 
    239 			if receiving then
    240 				table.insert( pendingInputs, toShow )
    241 			else
    242 				if lastWasChat then
    243 					mud.newlineMain()
    244 
    245 					lastWasChat = false
    246 				end
    247 
    248 				lastWasGA = false
    249 
    250 				mud.printr( toShow )
    251 			end
    252 		end
    253 
    254 		mud.send( input .. "\n" )
    255 	end
    256 end
    257 
    258 local function handleInput( input, display )
    259 	mud.last_human_input_time = mud.now()
    260 
    261 	for command in ( input .. ";" ):gmatch( "([^;]*);" ) do
    262 		handleCommand( command, display )
    263 	end
    264 end
    265 
    266 mud.input = handleInput
    267 
    268 local function handleMacro( key, shift, ctrl, alt )
    269 	mud.last_human_input_time = mud.now()
    270 
    271 	if shift then
    272 		key = "s" .. key
    273 	end
    274 
    275 	if ctrl then
    276 		key = "c" .. key
    277 	end
    278 
    279 	if alt then
    280 		key = "a" .. key
    281 	end
    282 
    283 	macro.doMacro( key )
    284 end
    285 
    286 local function handleClose()
    287 	mud.event( "shutdown" )
    288 end
    289 
    290 return {
    291 	data = handleData,
    292 	chat = handleChat,
    293 	input = handleInput,
    294 	macro = handleMacro,
    295 	interval = interval.doIntervals,
    296 	socket = handleSocketData,
    297 	close = handleClose,
    298 }