模块:Dialog

来自PRTS
跳转到导航 跳转到搜索

此模块的文档可以在模块:Dialog/doc创建

local parse = function(text)
  local list = {}
  for i in string.gmatch(text, "[^\r\n]+") do
    if i ~= "" then
      local commentPattern = "^%s*//"
      if string.find(i, commentPattern) ~= nil then
        table.insert(list, {
          type = "comment",
          comment = string.gsub(i, commentPattern, ""),
        })
      elseif string.find(i, "%[") ~= nil then
        local command, text = string.match(i, "%[([^%]]+)%]%s*(.*)")
        if command ~= nil then
          local func, args = string.match(command, "([^%s]+)%(([^%)]*)%)")
          local setKey, setValue = string.match(command, "([^%s=]+)=\"?([^%s=\"]+)\"?")

          if func ~= nil then
            local argList = {}
            for k, v in string.gmatch(args, "([^%s=,]+)=\"?([^%s=,\"]+)\"?") do
              argList[k] = v
            end -- for

            table.insert(list, {
              type = "function",
              name = func,
              args = argList
            })
          elseif setKey ~= nil then
            table.insert(list, {
              type = "set",
              key = setKey,
              value = setValue,
            })
          else
            table.insert(list, {
              type = "function",
              name = command
            })
          end -- if func ~= nil then
        end -- if string.find(i, commentPattern) ~= nil then

        if text ~= nil and text ~= "" then
          table.insert(list, {
            type = "text",
            text = text
          })
        end -- if text ~= nil and text ~= "" then
      else
        table.insert(list, {
          type = "text",
          text = i
        })
      end -- if string.find(i, commentPattern) ~= nil then
    end -- if i ~= "" then
  end -- for
  return list
end



local read = function(list)
  local vars = {
    background = nil,
    image = nil,
    name = nil,
    char1 = nil,
    char2 = nil,
    options = nil,
    references = nil,
  }
  
  local old = {
    background = nil,
    image = nil,
    char1 = nil,
    char2 = nil,
  }

  local meta = {
    header = nil
  }
  local state = nil
  local result = {}

  local noop = function() end
  
  local funcHandlers = {
    HEADER = function(statement)
      state = 'WAIT_HEADER_TEXT'
    end,
    Dialog = noop,
    Delay = noop,
    Blocker = noop,
    PlayMusic = noop,
    PlaySound = noop,
    StopMusic = noop,
    ImageTween = noop,
    Background = function(s)
      local newbg
      if s.args ~= nil then
        newbg = s.args.image
      else
        newbg = nil
      end
      
      if newbg ~= nil then
        newbg = string.gsub(newbg, '#.*$', '')
  	  end
      
      if newbg ~= old.background then
        if newbg ~= nil then
          state = 'VISUAL'
        end
        old.background = newbg
        vars.backgroud = newbg
      end
    end,
    Image = function(s)
      local newimg
      if s.args ~= nil then
        newimg = s.args.image
      else
        newimg = nil
      end
      
      if newimg ~= nil then
        newimg = string.gsub(newimg, '#.*$', '')
  	  end
      
      if newimg ~= old.image then
        state = 'VISUAL'
        old.image = newimg
        vars.image = newimg
      end
    end,
    Character = function(s)
      local new1
      local new2

      if s.args ~= nil then
        new1 = s.args.name
        new2 = s.args.name2
      else
        new1 = nil
        new2 = nil
      end
      
      if new1 ~= nil then
        new1 = string.gsub(new1, '#.*$', '')
  	  end
      
      if new2 ~= nil then
        new2 = string.gsub(new2, '#.*$', '')
  	  end
      
      if new1 ~= old.char1 or new2 ~= old.char2 then
        if new1 ~= nil or new2 ~= nil then
          state = 'VISUAL'
        end

        old.char1 = new1
        old.char2 = new2
        vars.char1 = new1
        vars.char2 = new2
      end
    end,
    Decision = function(s)
      local opts = {}
      local values = {}
      local options = {}
      
      if s.args ~= nil then
        for i in string.gmatch(s.args.options, "([^;]+)") do
          table.insert(opts, i)
        end
        for i in string.gmatch(s.args.values, "([^;]+)") do
          table.insert(values, i)
        end
        for k, v in pairs(opts) do
          options[values[k]] = v
        end
      end
      
      state = 'DECISION'
      vars.options = options
    end,
    Predicate = function(s)
      local references = {}

      if s.args ~= nil then
        for i in string.gmatch(s.args.references, "([^;]+)") do
          table.insert(references, i)
        end
      end

      state = 'PREDICATE'
      vars.references = references
    end,
  }

  local handlers = {
    text = function(statement)
      if state == 'WAIT_HEADER_TEXT' then
        meta.header = statement.text
        state = nil
      else
        table.insert(result, {
          type = "dialog",
          name = vars.name,
          text = statement.text
        })
        vars.name = nil
      end
    end,
    set = function(statement)
      vars[statement.key] = statement.value
    end,
    ['function'] = function(statement)
      if funcHandlers[statement.name] ~= nil then
        funcHandlers[statement.name](statement)
      else
        -- print("Unkown function: " .. statement.name)
      end
    end,
    comment = noop,
  }
  for index, statement in pairs(list) do
    if handlers[statement.type] ~= nil then
      handlers[statement.type](statement)
    else
      -- print("Unkown statement: " .. statement.type)
    end
    
    if state == 'VISUAL' then
      local visual = {
        type = "image",
        background = vars.backgroud,
        image = vars.image,
        char1 = vars.char1,
        char2 = vars.char2,
      }
      if #result > 0 then
        if result[#result].type == "image" then
          result[#result] = visual
        else
          table.insert(result, visual)
        end
      else
        table.insert(result, visual)
      end

      state = nil
    end
    
    if state == 'DECISION' then
      table.insert(result, {
        type = "decision",
        options = vars.options
      })
      state = nil
    end
    
    if state == 'PREDICATE' then
      table.insert(result, {
        type = "predicate",
        options = vars.options,
        references = vars.references
      })
      state = nil
    end
  end
  
  return result, meta
end


local wiki = function(result, meta)
  local html = ""
  if meta.header ~= nil then
	html = html .. string.format([[<div class="avg-title">%s</div>]], meta.header)
  end
  
  for k, r in pairs(result) do
    if r.type == "image" then
      html = html .. '<div class="avg-scene">'
      if r.background ~= nil then
        html = html .. '<div class="avg-background">[[Image:avg_' .. r.background .. '.png|500px]]</div>'
      end
      if r.image ~= nil then
        html = html .. '<div class="avg-image">[[Image:avg_' .. r.image .. '.png|500px]]</div>'
      end
      if r.char1 ~= nil and r.char2 ~= nil then
        html = html .. '<div class="avg-char1">[[Image:avg_' .. r.char1 .. '.png|250px]]</div>'
        html = html .. '<div class="avg-char2">[[Image:avg_' .. r.char2 .. '.png|250px]]</div>'
      end
      if r.char1 ~= nil and r.char2 == nil then
        html = html .. '<div class="avg-char">[[Image:avg_' .. r.char1 .. '.png|250px]]</div>'
      end
      html = html .. '</div>\n'
    end
    if r.type == "dialog" then
      html = html .. '<div class="avg-dialog">'
      if r.name ~= nil then
        html = html .. '<div class="avg-name">' .. r.name .. '</div>'
      end
      html = html .. '<div class="avg-text">' .. r.text .. '</div>'
      html = html .. '</div>\n'
    end
    if r.type == "decision" then
      html = html .. '<div class="avg-decision">选项'
      for v, o in pairs(r.options) do
        html = html .. '<div class="avg-option">' .. o .. '</div>'
      end
      html = html .. '</div>\n'
    end
    if r.type == "predicate" then
      html = html .. '<div class="avg-predicate">选择'
      for k, v in pairs(r.references) do
        html = html .. '<div class="avg-reference">' .. r.options[v] .. '</div>'
      end
      html = html .. '时:</div>\n'
    end
  end

  return html
end

return {
	render = function (frame)
		return wiki(read(parse(mw.text.unstripNoWiki(frame.args[1]))))
	end
}