Merge pull request #5469 from Mailaender/fort-lonestar-lua

Ported Fort Lonestar to Lua
This commit is contained in:
Paul Chote
2014-06-14 17:47:06 +12:00
9 changed files with 1540 additions and 413 deletions

View File

@@ -37,6 +37,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common Lua scripts", "Commo
mods\common\lua\supportpowers.lua = mods\common\lua\supportpowers.lua
mods\common\lua\team.lua = mods\common\lua\team.lua
mods\common\lua\utils.lua = mods\common\lua\utils.lua
mods\common\lua\facing.lua = mods\common\lua\facing.lua
mods\common\lua\production.lua = mods\common\lua\production.lua
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tiberian Dawn Lua scripts", "Tiberian Dawn Lua scripts", "{62FCD0D0-6D24-435D-9DD8-3CCADCF7ECAB}"
@@ -48,6 +50,24 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tiberian Dawn Lua scripts",
mods\cnc\maps\nod03a\nod03a.lua = mods\cnc\maps\nod03a\nod03a.lua
mods\cnc\maps\nod03b\nod03b.lua = mods\cnc\maps\nod03b\nod03b.lua
mods\cnc\maps\shellmap\shellmap.lua = mods\cnc\maps\shellmap\shellmap.lua
mods\cnc\maps\gdi04a\gdi04a.lua = mods\cnc\maps\gdi04a\gdi04a.lua
mods\cnc\maps\gdi04b\gdi04b.lua = mods\cnc\maps\gdi04b\gdi04b.lua
mods\cnc\maps\gdi04c\gdi04c.lua = mods\cnc\maps\gdi04c\gdi04c.lua
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Red Alert Lua scripts", "Red Alert Lua scripts", "{B35D533F-BEB6-4674-A466-324EEFD97259}"
ProjectSection(SolutionItems) = preProject
mods\ra\maps\allies-01-classic\allies01.lua = mods\ra\maps\allies-01-classic\allies01.lua
mods\ra\maps\allies-02-classic\allies02.lua = mods\ra\maps\allies-02-classic\allies02.lua
mods\ra\maps\desert-shellmap\desert-shellmap.lua = mods\ra\maps\desert-shellmap\desert-shellmap.lua
mods\ra\maps\fort-lonestar\fort-lonestar.lua = mods\ra\maps\fort-lonestar\fort-lonestar.lua
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "System Lua scripts", "System Lua scripts", "{A4D6AEA4-8009-4256-903B-8D227E50452B}"
ProjectSection(SolutionItems) = preProject
lua\sandbox.lua = lua\sandbox.lua
lua\scriptwrapper.lua = lua\scriptwrapper.lua
lua\stacktraceplus.lua = lua\stacktraceplus.lua
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.CrashDialog", "OpenRA.CrashDialog\OpenRA.CrashDialog.csproj", "{47F1B0EE-EB35-47F2-93E4-273C70909157}"

View File

@@ -1,411 +1,411 @@
-- tables
local _G = _G
local string, io, debug, coroutine = string, io, debug, coroutine
-- functions
local tostring, print, require = tostring, print, require
local next, assert = next, assert
local pcall, type, pairs, ipairs = pcall, type, pairs, ipairs
local error = error
assert(debug, "debug table must be available at this point")
local io_open = io.open
local string_gmatch = string.gmatch
local string_sub = string.sub
local table_concat = table.concat
local _M = {
max_tb_output_len = 70 -- controls the maximum length of the 'stringified' table before cutting with ' (more...)'
}
-- this tables should be weak so the elements in them won't become uncollectable
local m_known_tables = { [_G] = "_G (global table)" }
local function add_known_module(name, desc)
local ok, mod = pcall(require, name)
if ok then
m_known_tables[mod] = desc
end
end
add_known_module("string", "string module")
add_known_module("io", "io module")
add_known_module("os", "os module")
add_known_module("table", "table module")
add_known_module("math", "math module")
add_known_module("package", "package module")
add_known_module("debug", "debug module")
add_known_module("coroutine", "coroutine module")
-- lua5.2
add_known_module("bit32", "bit32 module")
-- luajit
add_known_module("bit", "bit module")
add_known_module("jit", "jit module")
local m_user_known_tables = {}
local m_known_functions = {}
for _, name in ipairs{
-- Lua 5.2, 5.1
"assert",
"collectgarbage",
"dofile",
"error",
"getmetatable",
"ipairs",
"load",
"loadfile",
"next",
"pairs",
"pcall",
"print",
"rawequal",
"rawget",
"rawlen",
"rawset",
"require",
"select",
"setmetatable",
"tonumber",
"tostring",
"type",
"xpcall",
-- Lua 5.1
"gcinfo",
"getfenv",
"loadstring",
"module",
"newproxy",
"setfenv",
"unpack",
-- TODO: add table.* etc functions
} do
if _G[name] then
m_known_functions[_G[name]] = name
end
end
local m_user_known_functions = {}
local function safe_tostring (value)
local ok, err = pcall(tostring, value)
if ok then return err else return ("<failed to get printable value>: '%s'"):format(err) end
end
-- Private:
-- Parses a line, looking for possible function definitions (in a very na<6E>ve way)
-- Returns '(anonymous)' if no function name was found in the line
local function ParseLine(line)
assert(type(line) == "string")
--print(line)
local match = line:match("^%s*function%s+(%w+)")
if match then
--print("+++++++++++++function", match)
return match
end
match = line:match("^%s*local%s+function%s+(%w+)")
if match then
--print("++++++++++++local", match)
return match
end
match = line:match("^%s*local%s+(%w+)%s+=%s+function")
if match then
--print("++++++++++++local func", match)
return match
end
match = line:match("%s*function%s*%(") -- this is an anonymous function
if match then
--print("+++++++++++++function2", match)
return "(anonymous)"
end
return "(anonymous)"
end
-- Private:
-- Tries to guess a function's name when the debug info structure does not have it.
-- It parses either the file or the string where the function is defined.
-- Returns '?' if the line where the function is defined is not found
local function GuessFunctionName(info)
--print("guessing function name")
if type(info.source) == "string" and info.source:sub(1,1) == "@" then
local file, err = io_open(info.source:sub(2), "r")
if not file then
print("file not found: "..tostring(err)) -- whoops!
return "?"
end
local line
for i = 1, info.linedefined do
line = file:read("*l")
end
if not line then
print("line not found") -- whoops!
return "?"
end
return ParseLine(line)
else
local line
local lineNumber = 0
for l in string_gmatch(info.source, "([^\n]+)\n-") do
lineNumber = lineNumber + 1
if lineNumber == info.linedefined then
line = l
break
end
end
if not line then
print("line not found") -- whoops!
return "?"
end
return ParseLine(line)
end
end
---
-- Dumper instances are used to analyze stacks and collect its information.
--
local Dumper = {}
Dumper.new = function(thread)
local t = { lines = {} }
for k,v in pairs(Dumper) do t[k] = v end
t.dumping_same_thread = (thread == coroutine.running())
-- if a thread was supplied, bind it to debug.info and debug.get
-- we also need to skip this additional level we are introducing in the callstack (only if we are running
-- in the same thread we're inspecting)
if type(thread) == "thread" then
t.getinfo = function(level, what)
if t.dumping_same_thread and type(level) == "number" then
level = level + 1
end
return debug.getinfo(thread, level, what)
end
t.getlocal = function(level, loc)
if t.dumping_same_thread then
level = level + 1
end
return debug.getlocal(thread, level, loc)
end
else
t.getinfo = debug.getinfo
t.getlocal = debug.getlocal
end
return t
end
-- helpers for collecting strings to be used when assembling the final trace
function Dumper:add (text)
self.lines[#self.lines + 1] = text
end
function Dumper:add_f (fmt, ...)
self:add(fmt:format(...))
end
function Dumper:concat_lines ()
return table_concat(self.lines)
end
---
-- Private:
-- Iterates over the local variables of a given function.
--
-- @param level The stack level where the function is.
--
function Dumper:DumpLocals (level)
local prefix = "\t "
local i = 1
if self.dumping_same_thread then
level = level + 1
end
local name, value = self.getlocal(level, i)
if not name then
return
end
self:add("\tLocal variables:\r\n")
while name do
if type(value) == "number" then
self:add_f("%s%s = number: %g\r\n", prefix, name, value)
elseif type(value) == "boolean" then
self:add_f("%s%s = boolean: %s\r\n", prefix, name, tostring(value))
elseif type(value) == "string" then
self:add_f("%s%s = string: %q\r\n", prefix, name, value)
elseif type(value) == "userdata" then
self:add_f("%s%s = %s\r\n", prefix, name, safe_tostring(value))
elseif type(value) == "nil" then
self:add_f("%s%s = nil\r\n", prefix, name)
elseif type(value) == "table" then
if m_known_tables[value] then
self:add_f("%s%s = %s\r\n", prefix, name, m_known_tables[value])
elseif m_user_known_tables[value] then
self:add_f("%s%s = %s\r\n", prefix, name, m_user_known_tables[value])
else
local txt = "{"
for k,v in pairs(value) do
txt = txt..safe_tostring(k)..":"..safe_tostring(v)
if #txt > _M.max_tb_output_len then
txt = txt.." (more...)"
break
end
if next(value, k) then txt = txt..", " end
end
self:add_f("%s%s = %s %s\r\n", prefix, name, safe_tostring(value), txt.."}")
end
elseif type(value) == "function" then
local info = self.getinfo(value, "nS")
local fun_name = info.name or m_known_functions[value] or m_user_known_functions[value]
if info.what == "C" then
self:add_f("%s%s = C %s\r\n", prefix, name, (fun_name and ("function: " .. fun_name) or tostring(value)))
else
local source = info.short_src
if source:sub(2,7) == "string" then
source = source:sub(9)
end
--for k,v in pairs(info) do print(k,v) end
fun_name = fun_name or GuessFunctionName(info)
self:add_f("%s%s = Lua function '%s' (defined at line %d of chunk %s)\r\n", prefix, name, fun_name, info.linedefined, source)
end
elseif type(value) == "thread" then
self:add_f("%sthread %q = %s\r\n", prefix, name, tostring(value))
end
i = i + 1
name, value = self.getlocal(level, i)
end
end
---
-- Public:
-- Collects a detailed stack trace, dumping locals, resolving function names when they're not available, etc.
-- This function is suitable to be used as an error handler with pcall or xpcall
--
-- @param thread An optional thread whose stack is to be inspected (defaul is the current thread)
-- @param message An optional error string or object.
-- @param level An optional number telling at which level to start the traceback (default is 1)
--
-- Returns a string with the stack trace and a string with the original error.
--
function _M.stacktrace(thread, message, level)
if type(thread) ~= "thread" then
-- shift parameters left
thread, message, level = nil, thread, message
end
thread = thread or coroutine.running()
level = level or 1
local dumper = Dumper.new(thread)
local original_error
if type(message) == "table" then
dumper:add("an error object {\r\n")
local first = true
for k,v in pairs(message) do
if first then
dumper:add(" ")
first = false
else
dumper:add(",\r\n ")
end
dumper:add(safe_tostring(k))
dumper:add(": ")
dumper:add(safe_tostring(v))
end
dumper:add("\r\n}")
original_error = dumper:concat_lines()
elseif type(message) == "string" then
dumper:add(message)
original_error = message
end
dumper:add("\r\n")
dumper:add[[
Stack Traceback
===============
]]
--print(error_message)
local level_to_show = level
if dumper.dumping_same_thread then level = level + 1 end
local info = dumper.getinfo(level, "nSlf")
while info do
if info.what == "main" then
if string_sub(info.source, 1, 1) == "@" then
dumper:add_f("(%d) main chunk of file '%s' at line %d\r\n", level_to_show, string_sub(info.source, 2), info.currentline)
else
dumper:add_f("(%d) main chunk of %s at line %d\r\n", level_to_show, info.short_src, info.currentline)
end
elseif info.what == "C" then
--print(info.namewhat, info.name)
--for k,v in pairs(info) do print(k,v, type(v)) end
local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name or tostring(info.func)
dumper:add_f("(%d) %s C function '%s'\r\n", level_to_show, info.namewhat, function_name)
--dumper:add_f("%s%s = C %s\r\n", prefix, name, (m_known_functions[value] and ("function: " .. m_known_functions[value]) or tostring(value)))
elseif info.what == "tail" then
--print("tail")
--for k,v in pairs(info) do print(k,v, type(v)) end--print(info.namewhat, info.name)
dumper:add_f("(%d) tail call\r\n", level_to_show)
dumper:DumpLocals(level)
elseif info.what == "Lua" then
local source = info.short_src
local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name
if source:sub(2, 7) == "string" then
source = source:sub(9)
end
local was_guessed = false
if not function_name or function_name == "?" then
--for k,v in pairs(info) do print(k,v, type(v)) end
function_name = GuessFunctionName(info)
was_guessed = true
end
-- test if we have a file name
local function_type = (info.namewhat == "") and "function" or info.namewhat
if info.source and info.source:sub(1, 1) == "@" then
dumper:add_f("(%d) Lua %s '%s' at file '%s:%d'%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
elseif info.source and info.source:sub(1,1) == '#' then
dumper:add_f("(%d) Lua %s '%s' at template '%s:%d'%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
else
dumper:add_f("(%d) Lua %s '%s' at line %d of chunk '%s'\r\n", level_to_show, function_type, function_name, info.currentline, source)
end
dumper:DumpLocals(level)
else
dumper:add_f("(%d) unknown frame %s\r\n", level_to_show, info.what)
end
level = level + 1
level_to_show = level_to_show + 1
info = dumper.getinfo(level, "nSlf")
end
return dumper:concat_lines(), original_error
end
--
-- Adds a table to the list of known tables
function _M.add_known_table(tab, description)
if m_known_tables[tab] then
error("Cannot override an already known table")
end
m_user_known_tables[tab] = description
end
--
-- Adds a function to the list of known functions
function _M.add_known_function(fun, description)
if m_known_functions[fun] then
error("Cannot override an already known function")
end
m_user_known_functions[fun] = description
end
return _M
-- tables
local _G = _G
local string, io, debug, coroutine = string, io, debug, coroutine
-- functions
local tostring, print, require = tostring, print, require
local next, assert = next, assert
local pcall, type, pairs, ipairs = pcall, type, pairs, ipairs
local error = error
assert(debug, "debug table must be available at this point")
local io_open = io.open
local string_gmatch = string.gmatch
local string_sub = string.sub
local table_concat = table.concat
local _M = {
max_tb_output_len = 70 -- controls the maximum length of the 'stringified' table before cutting with ' (more...)'
}
-- this tables should be weak so the elements in them won't become uncollectable
local m_known_tables = { [_G] = "_G (global table)" }
local function add_known_module(name, desc)
local ok, mod = pcall(require, name)
if ok then
m_known_tables[mod] = desc
end
end
add_known_module("string", "string module")
add_known_module("io", "io module")
add_known_module("os", "os module")
add_known_module("table", "table module")
add_known_module("math", "math module")
add_known_module("package", "package module")
add_known_module("debug", "debug module")
add_known_module("coroutine", "coroutine module")
-- lua5.2
add_known_module("bit32", "bit32 module")
-- luajit
add_known_module("bit", "bit module")
add_known_module("jit", "jit module")
local m_user_known_tables = {}
local m_known_functions = {}
for _, name in ipairs{
-- Lua 5.2, 5.1
"assert",
"collectgarbage",
"dofile",
"error",
"getmetatable",
"ipairs",
"load",
"loadfile",
"next",
"pairs",
"pcall",
"print",
"rawequal",
"rawget",
"rawlen",
"rawset",
"require",
"select",
"setmetatable",
"tonumber",
"tostring",
"type",
"xpcall",
-- Lua 5.1
"gcinfo",
"getfenv",
"loadstring",
"module",
"newproxy",
"setfenv",
"unpack",
-- TODO: add table.* etc functions
} do
if _G[name] then
m_known_functions[_G[name]] = name
end
end
local m_user_known_functions = {}
local function safe_tostring (value)
local ok, err = pcall(tostring, value)
if ok then return err else return ("<failed to get printable value>: '%s'"):format(err) end
end
-- Private:
-- Parses a line, looking for possible function definitions (in a very na<6E>ve way)
-- Returns '(anonymous)' if no function name was found in the line
local function ParseLine(line)
assert(type(line) == "string")
--print(line)
local match = line:match("^%s*function%s+(%w+)")
if match then
--print("+++++++++++++function", match)
return match
end
match = line:match("^%s*local%s+function%s+(%w+)")
if match then
--print("++++++++++++local", match)
return match
end
match = line:match("^%s*local%s+(%w+)%s+=%s+function")
if match then
--print("++++++++++++local func", match)
return match
end
match = line:match("%s*function%s*%(") -- this is an anonymous function
if match then
--print("+++++++++++++function2", match)
return "(anonymous)"
end
return "(anonymous)"
end
-- Private:
-- Tries to guess a function's name when the debug info structure does not have it.
-- It parses either the file or the string where the function is defined.
-- Returns '?' if the line where the function is defined is not found
local function GuessFunctionName(info)
--print("guessing function name")
if type(info.source) == "string" and info.source:sub(1,1) == "@" then
local file, err = io_open(info.source:sub(2), "r")
if not file then
print("file not found: "..tostring(err)) -- whoops!
return "?"
end
local line
for i = 1, info.linedefined do
line = file:read("*l")
end
if not line then
print("line not found") -- whoops!
return "?"
end
return ParseLine(line)
else
local line
local lineNumber = 0
for l in string_gmatch(info.source, "([^\n]+)\n-") do
lineNumber = lineNumber + 1
if lineNumber == info.linedefined then
line = l
break
end
end
if not line then
print("line not found") -- whoops!
return "?"
end
return ParseLine(line)
end
end
---
-- Dumper instances are used to analyze stacks and collect its information.
--
local Dumper = {}
Dumper.new = function(thread)
local t = { lines = {} }
for k,v in pairs(Dumper) do t[k] = v end
t.dumping_same_thread = (thread == coroutine.running())
-- if a thread was supplied, bind it to debug.info and debug.get
-- we also need to skip this additional level we are introducing in the callstack (only if we are running
-- in the same thread we're inspecting)
if type(thread) == "thread" then
t.getinfo = function(level, what)
if t.dumping_same_thread and type(level) == "number" then
level = level + 1
end
return debug.getinfo(thread, level, what)
end
t.getlocal = function(level, loc)
if t.dumping_same_thread then
level = level + 1
end
return debug.getlocal(thread, level, loc)
end
else
t.getinfo = debug.getinfo
t.getlocal = debug.getlocal
end
return t
end
-- helpers for collecting strings to be used when assembling the final trace
function Dumper:add (text)
self.lines[#self.lines + 1] = text
end
function Dumper:add_f (fmt, ...)
self:add(fmt:format(...))
end
function Dumper:concat_lines ()
return table_concat(self.lines)
end
---
-- Private:
-- Iterates over the local variables of a given function.
--
-- @param level The stack level where the function is.
--
function Dumper:DumpLocals (level)
local prefix = "\t "
local i = 1
if self.dumping_same_thread then
level = level + 1
end
local name, value = self.getlocal(level, i)
if not name then
return
end
self:add("\tLocal variables:\r\n")
while name do
if type(value) == "number" then
self:add_f("%s%s = number: %g\r\n", prefix, name, value)
elseif type(value) == "boolean" then
self:add_f("%s%s = boolean: %s\r\n", prefix, name, tostring(value))
elseif type(value) == "string" then
self:add_f("%s%s = string: %q\r\n", prefix, name, value)
elseif type(value) == "userdata" then
self:add_f("%s%s = %s\r\n", prefix, name, safe_tostring(value))
elseif type(value) == "nil" then
self:add_f("%s%s = nil\r\n", prefix, name)
elseif type(value) == "table" then
if m_known_tables[value] then
self:add_f("%s%s = %s\r\n", prefix, name, m_known_tables[value])
elseif m_user_known_tables[value] then
self:add_f("%s%s = %s\r\n", prefix, name, m_user_known_tables[value])
else
local txt = "{"
for k,v in pairs(value) do
txt = txt..safe_tostring(k)..":"..safe_tostring(v)
if #txt > _M.max_tb_output_len then
txt = txt.." (more...)"
break
end
if next(value, k) then txt = txt..", " end
end
self:add_f("%s%s = %s %s\r\n", prefix, name, safe_tostring(value), txt.."}")
end
elseif type(value) == "function" then
local info = self.getinfo(value, "nS")
local fun_name = info.name or m_known_functions[value] or m_user_known_functions[value]
if info.what == "C" then
self:add_f("%s%s = C %s\r\n", prefix, name, (fun_name and ("function: " .. fun_name) or tostring(value)))
else
local source = info.short_src
if source:sub(2,7) == "string" then
source = source:sub(9)
end
--for k,v in pairs(info) do print(k,v) end
fun_name = fun_name or GuessFunctionName(info)
self:add_f("%s%s = Lua function '%s' (defined at line %d of chunk %s)\r\n", prefix, name, fun_name, info.linedefined, source)
end
elseif type(value) == "thread" then
self:add_f("%sthread %q = %s\r\n", prefix, name, tostring(value))
end
i = i + 1
name, value = self.getlocal(level, i)
end
end
---
-- Public:
-- Collects a detailed stack trace, dumping locals, resolving function names when they're not available, etc.
-- This function is suitable to be used as an error handler with pcall or xpcall
--
-- @param thread An optional thread whose stack is to be inspected (defaul is the current thread)
-- @param message An optional error string or object.
-- @param level An optional number telling at which level to start the traceback (default is 1)
--
-- Returns a string with the stack trace and a string with the original error.
--
function _M.stacktrace(thread, message, level)
if type(thread) ~= "thread" then
-- shift parameters left
thread, message, level = nil, thread, message
end
thread = thread or coroutine.running()
level = level or 1
local dumper = Dumper.new(thread)
local original_error
if type(message) == "table" then
dumper:add("an error object {\r\n")
local first = true
for k,v in pairs(message) do
if first then
dumper:add(" ")
first = false
else
dumper:add(",\r\n ")
end
dumper:add(safe_tostring(k))
dumper:add(": ")
dumper:add(safe_tostring(v))
end
dumper:add("\r\n}")
original_error = dumper:concat_lines()
elseif type(message) == "string" then
dumper:add(message)
original_error = message
end
dumper:add("\r\n")
dumper:add[[
Stack Traceback
===============
]]
--print(error_message)
local level_to_show = level
if dumper.dumping_same_thread then level = level + 1 end
local info = dumper.getinfo(level, "nSlf")
while info do
if info.what == "main" then
if string_sub(info.source, 1, 1) == "@" then
dumper:add_f("(%d) main chunk of file '%s' at line %d\r\n", level_to_show, string_sub(info.source, 2), info.currentline)
else
dumper:add_f("(%d) main chunk of %s at line %d\r\n", level_to_show, info.short_src, info.currentline)
end
elseif info.what == "C" then
--print(info.namewhat, info.name)
--for k,v in pairs(info) do print(k,v, type(v)) end
local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name or tostring(info.func)
dumper:add_f("(%d) %s C function '%s'\r\n", level_to_show, info.namewhat, function_name)
--dumper:add_f("%s%s = C %s\r\n", prefix, name, (m_known_functions[value] and ("function: " .. m_known_functions[value]) or tostring(value)))
elseif info.what == "tail" then
--print("tail")
--for k,v in pairs(info) do print(k,v, type(v)) end--print(info.namewhat, info.name)
dumper:add_f("(%d) tail call\r\n", level_to_show)
dumper:DumpLocals(level)
elseif info.what == "Lua" then
local source = info.short_src
local function_name = m_user_known_functions[info.func] or m_known_functions[info.func] or info.name
if source:sub(2, 7) == "string" then
source = source:sub(9)
end
local was_guessed = false
if not function_name or function_name == "?" then
--for k,v in pairs(info) do print(k,v, type(v)) end
function_name = GuessFunctionName(info)
was_guessed = true
end
-- test if we have a file name
local function_type = (info.namewhat == "") and "function" or info.namewhat
if info.source and info.source:sub(1, 1) == "@" then
dumper:add_f("(%d) Lua %s '%s' at file '%s:%d'%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
elseif info.source and info.source:sub(1,1) == '#' then
dumper:add_f("(%d) Lua %s '%s' at template '%s:%d'%s\r\n", level_to_show, function_type, function_name, info.source:sub(2), info.currentline, was_guessed and " (best guess)" or "")
else
dumper:add_f("(%d) Lua %s '%s' at line %d of chunk '%s'\r\n", level_to_show, function_type, function_name, info.currentline, source)
end
dumper:DumpLocals(level)
else
dumper:add_f("(%d) unknown frame %s\r\n", level_to_show, info.what)
end
level = level + 1
level_to_show = level_to_show + 1
info = dumper.getinfo(level, "nSlf")
end
return dumper:concat_lines(), original_error
end
--
-- Adds a table to the list of known tables
function _M.add_known_table(tab, description)
if m_known_tables[tab] then
error("Cannot override an already known table")
end
m_user_known_tables[tab] = description
end
--
-- Adds a function to the list of known functions
function _M.add_known_function(fun, description)
if m_known_functions[fun] then
error("Cannot override an already known function")
end
m_user_known_functions[fun] = description
end
return _M

View File

@@ -579,7 +579,7 @@ Rules:
-SpawnMPUnits:
-MPStartLocations:
LuaScriptInterface:
LuaScripts: mission.lua
LuaScripts: allies01.lua
TRAN.Extraction:
Inherits: TRAN
RenderUnit:

View File

@@ -874,7 +874,7 @@ Rules:
-SpawnMPUnits:
-MPStartLocations:
LuaScriptInterface:
LuaScripts: mission.lua
LuaScripts: allies02.lua
^Infantry:
MustBeDestroyed:
^Tank:

View File

@@ -0,0 +1,148 @@
Patrol = { "e1", "e2", "e1" }
Infantry = { "e4", "e1", "e1", "e2", "e1", "e2" }
Vehicles = { "arty", "ftrk", "ftrk", "apc", "apc" }
Tank = { "3tnk" }
LongRange = { "v2rl" }
Boss = { "4tnk" }
SovietEntryPoints = { Entry1, Entry2, Entry3, Entry4, Entry5, Entry6, Entry7, Entry8 }
PatrolWaypoints = { Patrol1, Patrol2, Patrol3, Patrol4 }
ParadropWaypoints = { Paradrop1, Paradrop2, Paradrop3, Paradrop4 }
OilDerricks = { OilDerrick1, OilDerrick2, OilDerrick3, OilDerrick4 }
SpawnPoints = { Spawn1, Spawn2, Spawn3, Spawn4 }
Snipers = { Sniper1, Sniper2, Sniper3, Sniper4, Sniper5, Sniper6, Sniper7, Sniper8, Sniper9, Sniper10, Sniper11, Sniper12 }
Wave = 0
Waves =
{
{ 500, SovietEntryPoints, Infantry, SpawnPoints },
{ 750, PatrolWaypoints, Patrol, ParadropWaypoints },
{ 750, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Vehicles, SpawnPoints },
{ 1500, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1500, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Vehicles, SpawnPoints },
{ 1500, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Tank, SpawnPoints },
{ 1, SovietEntryPoints, Vehicles, SpawnPoints },
{ 1500, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Tank, SpawnPoints },
{ 1, SovietEntryPoints, Tank, SpawnPoints },
{ 1500, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, LongRange, SpawnPoints },
{ 1500, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, LongRange, SpawnPoints },
{ 1, SovietEntryPoints, Tank, SpawnPoints },
{ 1, SovietEntryPoints, LongRange, SpawnPoints },
{ 1500, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, LongRange, SpawnPoints },
{ 1, SovietEntryPoints, LongRange, SpawnPoints },
{ 1, SovietEntryPoints, Tank, SpawnPoints },
{ 1, SovietEntryPoints, Tank, SpawnPoints },
{ 1, SovietEntryPoints, Vehicles, SpawnPoints },
{ 1500, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Infantry, SpawnPoints },
{ 1, SovietEntryPoints, Boss, SpawnPoints }
}
SendUnits = function(entryCell, unitTypes, interval, targetCell)
local i = 0
Utils.Do(unitTypes, function(type)
local a = Actor.Create(type, false, { Owner = soviets, Location = entryCell })
Trigger.OnIdle(a, function(a) a.AttackMove(targetCell) end)
Trigger.AfterDelay(i * interval, function() a.IsInWorld = true end)
i = i + 1
end)
if (Wave < #Waves) then
SendWave()
else
Trigger.AfterDelay(3000, SovietsRetreating)
end
end
SendWave = function()
Wave = Wave + 1
local wave = Waves[Wave]
local delay = wave[1]
local entry = Utils.Random(wave[2]).Location
local units = wave[3]
local target = Utils.Random(wave[4]).Location
print(string.format("Sending wave %i in %i.", Wave, delay))
Trigger.AfterDelay(delay, function() SendUnits(entry, units, 40, target) end)
end
SovietsRetreating = function()
Utils.Do(Snipers, function(a)
if not a.IsDead and a.Owner == soviets then
a.Destroy()
end
end)
end
WorldLoaded = function()
soviets = Player.GetPlayer("Soviets")
Utils.Do(Snipers, function(a)
if a.Owner == soviets then
a.Invulnerable = true
end
end)
SendWave()
end

Binary file not shown.

View File

@@ -0,0 +1,959 @@
Selectable: True
MapFormat: 6
RequiresMod: ra
Title: Fort Lonestar
Description: Survive multiple waves of attacking enemies.
Author: Nuke'm Bro.
Tileset: TEMPERAT
MapSize: 96,96
Bounds: 8,8,48,48
UseAsShellmap: False
Type: Minigame
Options:
Fog: True
Shroud: True
AllyBuildRadius: False
FragileAlliances: False
StartingCash: 50
ConfigurableStartingUnits: False
Players:
PlayerReference@Neutral:
Name: Neutral
OwnsWorld: True
NonCombatant: True
Race: allies
PlayerReference@Multi0:
Name: Multi0
Playable: True
AllowBots: False
LockTeam: True
Allies: Multi1,Multi2,Multi3
Enemies: Soviets
PlayerReference@Multi1:
Name: Multi1
Playable: True
AllowBots: False
LockTeam: True
Allies: Multi0,Multi2,Multi3
Enemies: Soviets
PlayerReference@Multi2:
Name: Multi2
Playable: True
AllowBots: False
LockTeam: True
Allies: Multi0,Multi1,Multi3
Enemies: Soviets
PlayerReference@Multi3:
Name: Multi3
Playable: True
AllowBots: False
LockTeam: True
Allies: Multi0,Multi1,Multi2
Enemies: Soviets
PlayerReference@Soviets:
Name: Soviets
Race: soviet
ColorRamp: 0,255,128
Enemies: Multi0,Multi1,Multi2,Multi3
Actors:
Actor76: t11
Location: 47,27
Owner: Neutral
Actor47: t12
Location: 55,24
Owner: Neutral
Actor25: tc03
Location: 54,49
Owner: Neutral
Actor14: tc04
Location: 24,7
Owner: Neutral
Actor10: tc04
Location: 38,53
Owner: Neutral
Actor0: t14
Location: 32,16
Owner: Neutral
Actor75: tc04
Location: 45,25
Owner: Neutral
Actor72: tc01
Location: 49,16
Owner: Neutral
Actor58: t10
Location: 22,54
Owner: Neutral
Actor26: tc01
Location: 54,41
Owner: Neutral
Actor37: tc01
Location: 54,21
Owner: Neutral
Actor60: tc05
Location: 7,16
Owner: Neutral
Actor69: t17
Location: 23,8
Owner: Neutral
Actor4: tc04
Location: 29,45
Owner: Neutral
Actor6: t17
Location: 33,43
Owner: Neutral
Actor16: tc04
Location: 53,16
Owner: Neutral
Actor21: tc03
Location: 8,14
Owner: Neutral
Actor8: t14
Location: 49,37
Owner: Neutral
Actor29: tc01
Location: 8,42
Owner: Neutral
Actor49: t15
Location: 54,47
Owner: Neutral
Actor62: tc05
Location: 6,43
Owner: Neutral
Actor73: tc05
Location: 16,34
Owner: Neutral
Actor30: barr
Location: 36,26
Owner: Multi0
Actor84: brik
Location: 35,25
Owner: Neutral
Actor32: tc01
Location: 8,24
Owner: Neutral
Actor59: tc05
Location: 7,39
Owner: Neutral
Actor5: tc01
Location: 44,44
Owner: Neutral
Actor67: brik
Location: 29,25
Owner: Neutral
Actor41: brik
Location: 25,25
Owner: Neutral
Actor56: brik
Location: 26,25
Owner: Neutral
Actor85: brik
Location: 39,26
Owner: Neutral
Actor81: brik
Location: 38,25
Owner: Neutral
Actor65: brik
Location: 27,25
Owner: Neutral
Actor66: brik
Location: 28,25
Owner: Neutral
Actor51: t08
Location: 55,46
Owner: Neutral
Actor57: t12
Location: 19,54
Owner: Neutral
Actor54: t11
Location: 26,54
Owner: Neutral
Actor33: tc01
Location: 21,7
Owner: Neutral
Actor27: tc01
Location: 42,54
Owner: Neutral
Actor23: tc03
Location: 16,54
Owner: Neutral
Actor15: tc04
Location: 38,8
Owner: Neutral
Actor19: tc03
Location: 18,7
Owner: Neutral
Actor17: tc03
Location: 54,26
Owner: Neutral
Actor83: brik
Location: 36,25
Owner: Neutral
Actor197: brik
Location: 39,37
Owner: Neutral
Actor11: tc04
Location: 20,53
Owner: Neutral
Actor9: tc04
Location: 53,37
Owner: Neutral
Actor7: tc02
Location: 44,36
Owner: Neutral
Actor3: t15
Location: 19,25
Owner: Neutral
Actor1: t05
Location: 29,16
Owner: Neutral
Actor82: brik
Location: 37,25
Owner: Neutral
Actor86: brik
Location: 39,27
Owner: Neutral
Actor80: brik
Location: 39,25
Owner: Neutral
Actor71: tc02
Location: 15,40
Owner: Neutral
Actor64: t06
Location: 18,16
Owner: Neutral
Actor63: t14
Location: 8,22
Owner: Neutral
Actor53: t08
Location: 41,55
Owner: Neutral
Actor61: tc05
Location: 54,39
Owner: Neutral
Actor48: t01
Location: 54,23
Owner: Neutral
Actor50: t17
Location: 54,44
Owner: Neutral
Actor36: tc01
Location: 42,8
Owner: Neutral
Actor52: t12
Location: 44,53
Owner: Neutral
Actor87: brik
Location: 39,28
Owner: Neutral
Actor91: brik
Location: 37,39
Owner: Neutral
Actor196: brik
Location: 39,38
Owner: Neutral
Actor195: brik
Location: 39,39
Owner: Neutral
Actor45: brik
Location: 25,28
Owner: Neutral
Actor92: brik
Location: 39,29
Owner: Neutral
Actor194: brik
Location: 38,39
Owner: Neutral
Actor55: brik
Location: 25,39
Owner: Neutral
Actor200: brik
Location: 28,39
Owner: Neutral
Actor233: brik
Location: 29,39
Owner: Neutral
Actor240: brik
Location: 39,35
Owner: Neutral
Actor199: brik
Location: 27,39
Owner: Neutral
Spawn1: mpspawn
Location: 36,28
Owner: Neutral
Actor28: tc01
Location: 24,54
Owner: Neutral
Actor22: tc03
Location: 7,46
Owner: Neutral
Actor24: tc03
Location: 45,54
Owner: Neutral
Actor18: tc03
Location: 45,8
Owner: Neutral
Actor12: tc04
Location: 7,37
Owner: Neutral
Actor13: tc04
Location: 8,19
Owner: Neutral
Actor2: tc04
Location: 14,23
Owner: Neutral
Actor74: t06
Location: 19,36
Owner: Neutral
Actor46: t11
Location: 54,19
Owner: Neutral
Actor42: t16
Location: 53,19
Owner: Neutral
Actor68: tc05
Location: 35,7
Owner: Neutral
Actor239: brik
Location: 39,36
Owner: Neutral
Actor89: brik
Location: 35,39
Owner: Neutral
Actor90: brik
Location: 36,39
Owner: Neutral
OilDerrick1: oilb
Location: 32,30
Owner: Multi0
Actor237: brik
Location: 25,35
Owner: Neutral
Actor236: brik
Location: 25,36
Owner: Neutral
Actor235: brik
Location: 25,37
Owner: Neutral
Actor234: brik
Location: 25,38
Owner: Neutral
Actor44: brik
Location: 25,27
Owner: Neutral
Actor43: brik
Location: 25,26
Owner: Neutral
Actor198: brik
Location: 26,39
Owner: Neutral
Actor88: brik
Location: 25,29
Owner: Neutral
Entry1: waypoint
Location: 8,8
Owner: Neutral
Entry2: waypoint
Location: 31,8
Owner: Neutral
Entry3: waypoint
Location: 55,8
Owner: Neutral
Entry4: waypoint
Location: 55,32
Owner: Neutral
Entry5: waypoint
Location: 55,55
Owner: Neutral
Entry6: waypoint
Location: 32,55
Owner: Neutral
Entry7: waypoint
Location: 8,55
Owner: Neutral
Entry8: waypoint
Location: 8,32
Owner: Neutral
Paradrop1: waypoint
Location: 32,28
Owner: Neutral
Paradrop2: waypoint
Location: 27,32
Owner: Neutral
Paradrop3: waypoint
Location: 32,36
Owner: Neutral
Paradrop4: waypoint
Location: 36,32
Owner: Neutral
Patrol3: waypoint
Location: 32,46
Owner: Neutral
Patrol4: waypoint
Location: 46,32
Owner: Neutral
Patrol2: waypoint
Location: 17,32
Owner: Neutral
Patrol1: waypoint
Location: 32,18
Owner: Neutral
Sniper1: sniper
Location: 9,26
Owner: Soviets
Sniper2: sniper
Location: 10,21
Owner: Soviets
Sniper3: sniper
Location: 26,9
Owner: Soviets
Sniper4: sniper
Location: 40,10
Owner: Soviets
Sniper5: sniper
Location: 53,21
Owner: Soviets
Sniper6: sniper
Location: 54,25
Owner: Soviets
Sniper7: sniper
Location: 53,40
Owner: Soviets
Sniper8: sniper
Location: 54,43
Owner: Soviets
Sniper9: sniper
Location: 54,46
Owner: Soviets
Sniper10: sniper
Location: 43,53
Owner: Soviets
Sniper11: sniper
Location: 8,36
Owner: Soviets
Sniper12: sniper
Location: 28,55
Owner: Soviets
Actor100: barr
Location: 27,26
Owner: Multi3
Actor99: barr
Location: 27,36
Owner: Multi2
Actor31: barr
Location: 36,36
Owner: Multi1
OilDerrick2: oilb
Location: 32,32
Owner: Multi1
OilDerrick3: oilb
Location: 30,32
Owner: Multi2
OilDerrick4: oilb
Location: 30,30
Owner: Multi3
Spawn2: mpspawn
Location: 27,28
Owner: Neutral
Spawn3: mpspawn
Location: 27,38
Owner: Neutral
Spawn4: mpspawn
Location: 36,38
Owner: Neutral
Smudges:
Rules:
World:
CrateSpawner:
Maximum: 1
SpawnInterval: 100
-SpawnMPUnits:
-MPStartLocations:
LuaScript:
Scripts: fort-lonestar.lua
CRATE:
-LevelUpCrateAction:
-GiveMcvCrateAction:
-RevealMapCrateAction:
-HideMapCrateAction:
-ExplodeCrateAction@nuke:
-ExplodeCrateAction@boom:
-ExplodeCrateAction@fire:
-GiveUnitCrateAction@jeep:
-GiveUnitCrateAction@arty:
-GiveUnitCrateAction@v2rl:
-GiveUnitCrateAction@1tnk:
-GiveUnitCrateAction@2tnk:
-GiveUnitCrateAction@3tnk:
-GiveUnitCrateAction@4tnk:
SupportPowerCrateAction@parabombs:
SelectionShares: 30
HealUnitsCrateAction:
SelectionShares: 30
GiveCashCrateAction:
Amount: 400
UseCashTick: yes
SelectionShares: 30
GiveUnitCrateAction@e7:
Unit: e7
SelectionShares: 10
Player:
PlayerResources:
InitialCash: 50
ClassicProductionQueue@Infantry:
Type: Infantry
BuildSpeed: 1
LowPowerSlowdown: 3
ClassicProductionQueue@Defense:
Type: Defense
BuildSpeed: .4
LowPowerSlowdown: 3
^Infantry:
MustBeDestroyed:
^Vehicle:
MustBeDestroyed:
^Tank:
MustBeDestroyed:
OILB:
Health:
HP: 3000
Armor:
Type: Wood
Bib:
RevealsShroud:
Range: 3c0
CashTrickler:
Period: 250
Amount: 50
BARR:
Buildable:
Owner: allies,soviet
Building:
Power: 0
Health:
HP: 1000
Production:
Produces: Defense,Infantry
-Sellable:
BaseProvider:
Range: 12
FTUR:
Building:
Power: 0
Valued:
Cost: 400
PBOX:
Building:
Power: 0
Buildable:
Prerequisites: barr,oilb
Valued:
Cost: 400
Health:
HP: 200
Armor:
Type: Heavy
HBOX:
Building:
Power: 0
GUN:
Buildable:
Owner: None
SAM:
Buildable:
Owner: None
SBAG:
Buildable:
Owner: None
FENC:
Buildable:
Owner: None
MSLO:
Buildable:
Owner: None
GAP:
Buildable:
Owner: None
IRON:
Buildable:
Owner: None
PDOX:
Buildable:
Owner: None
AGUN:
Buildable:
Owner: None
TSLA:
Buildable:
Owner: None
DOG:
Buildable:
Owner: soviet,allies
Prerequisites: barr,oilb
Valued:
Cost: 20
E1:
Buildable:
Owner: soviet,allies
Prerequisites: barr,oilb
Valued:
Cost: 20
E2:
Buildable:
Owner: soviet,allies
Prerequisites: barr,oilb
Valued:
Cost: 40
Explodes:
Weapon: UnitExplodeSmall
Chance: 20
E3:
Buildable:
Owner: soviet,allies
Prerequisites: barr,oilb
Valued:
Cost: 60
E4:
Buildable:
Owner: soviet,allies
Prerequisites: barr,oilb
Valued:
Cost: 100
E6:
Buildable:
Owner: soviet,allies
Prerequisites: barr
Valued:
Cost: 100
E7:
Buildable:
Owner: soviet,allies
Prerequisites: barr,oilb
Valued:
Cost: 750
3TNK:
Inherits: ^Tank
Armament:
Weapon: TankNapalm
Recoil: 200
RecoilRecovery: 38
LocalOffset: 0,85,0, 0,-85,0
MECH:
Buildable:
Owner: None
HIJACKER:
Buildable:
Owner: None
MEDI:
Buildable:
Owner: soviet,allies
Prerequisites: barr,oilb
Valued:
Cost: 100
SHOK:
Buildable:
Owner: soviet,allies
Prerequisites: barr,oilb
Valued:
Cost: 150
SNIPER:
Valued:
Cost: 200
Buildable:
Owner: soviet, allies
Prerequisites: barr,oilb
Health:
HP: 200
AutoTarget:
InitialStance: Defend
ScriptInvulnerable:
SPY:
Inherits: ^Infantry
Buildable:
Queue: Infantry
BuildPaletteOrder: 60
Prerequisites: barr,oilb
Owner: allies, soviet
Valued:
Cost: 300
ARTY:
Inherits: ^Tank
Valued:
Cost: 600
Health:
HP: 75
RevealsShroud:
Range: 7c0
V2RL:
Health:
HP: 100
4TNK:
Health:
HP: 2500
Armor:
Type: Heavy
Mobile:
Speed: 56
RevealsShroud:
Range: 14c0
Turreted:
ROT: 1
AttackTurreted:
PrimaryWeapon: 120mm
SecondaryWeapon: MammothTusk
PrimaryLocalOffset: -4,-5,0,0,0, 4,-5,0,0,0
SecondaryLocalOffset: -7,2,0,0,25, 7,2,0,0,-25
PrimaryRecoil: 8
PrimaryRecoilRecovery: 0.7
SecondaryRecoil: 2
Explodes:
Weapon: napalm
EmptyWeapon: napalm
SelfHealing:
Step: 2
Ticks: 1
HealIfBelow: 40%
DamageCooldown: 150
BRIK:
Buildable:
Owner: None
BADR.Bomber:
Inherits: ^Plane
AttackBomber:
Armament:
Weapon: ParaBomb
Health:
HP: 60
Armor:
Type: Light
Plane:
ROT: 5
Speed: 280
LimitedAmmo:
Ammo: 30
RenderUnit:
Image: mig
WithShadow:
-Selectable:
-GainsExperience:
Tooltip:
Name: Mig Bomber
-EjectOnDeath:
Sequences:
VoxelSequences:
Weapons:
120mm:
ROF: 150
Range: 10c0
Report: CANNON1.AUD
Burst: 6
Projectile: Bullet
Speed: 204
High: true
Inaccuracy: 1c682
Image: 120MM
ContrailLength: 50
Warhead:
Spread: 256
Versus:
None: 75%
Wood: 75%
Light: 75%
Concrete: 100%
Explosion: self_destruct
WaterExplosion: self_destruct
InfDeath: 4
SmudgeType: Crater
Damage: 150
MammothTusk:
ROF: 300
Range: 10c0
Report: MISSILE6.AUD
Burst: 2
ValidTargets: Ground, Air
Projectile: Missile
Speed: 128
Arm: 2
High: true
Shadow: false
Proximity: true
Trail: smokey
ContrailLength: 150
Inaccuracy: 853
Image: DRAGON
ROT: 10
RangeLimit: 80
Warhead:
Spread: 640
Versus:
None: 125%
Wood: 110%
Light: 110%
Heavy: 100%
Concrete: 200%
Explosion: nuke
WaterExplosion: nuke
InfDeath: 3
SmudgeType: Crater
Damage: 250
TankNapalm:
ROF: 40
Range: 8c0
Report: AACANON3.AUD
ValidTargets: Ground
Burst: 6
BurstDelay: 1
Projectile: Bullet
Speed: 426
Image: 120MM
Inaccuracy: 2c512
Trail: smokey
ContrailLength: 2
Warhead:
Spread: 341
Versus:
None: 90%
Wood: 170%
Light: 100%
Heavy: 100%
Concrete: 100%
Explosion: small_explosion
WaterExplosion: small_explosion
InfDeath: 4
SmudgeType: Scorch
ImpactSound: firebl3.aud
Damage: 15
ParaBomb:
ROF: 5
Range: 5c0
Report: CHUTE1.AUD
Projectile: GravityBomb
Image: BOMBLET
Warhead:
Spread: 426
Versus:
None: 125%
Wood: 100%
Light: 60%
Concrete: 25%
Explosion: napalm
ImpactSound: firebl3.aud
WaterExplosion: napalm
InfDeath: 5
SmudgeType: Crater
Damage: 200
155mm:
ROF: 10
Range: 7c5
Burst: 20
MinRange: 3c0
-Report:
Projectile: Bullet
Speed: 170
Trail: fb4
Image: fb3
High: true
Angle: 30
Inaccuracy: 1c682
ContrailLength: 2
Warhead:
Spread: 426
Versus:
None: 80%
Wood: 100%
Light: 60%
Heavy: 75%
Concrete: 35%
Explosion: small_napalm
WaterExplosion: small_napalm
InfDeath: 5
SmudgeType: Scorch
ImpactSound: firebl3.aud
Damage: 10
FLAK-23:
ROF: 10
Range: 8c0
Report: AACANON3.AUD
ValidTargets: Air,Ground
Projectile: Bullet
Speed: 1c682
High: true
Warhead:
Spread: 213
Versus:
None: 35%
Wood: 30%
Light: 30%
Heavy: 40%
Concrete: 30%
Explosion: med_explosion
Damage: 25
SCUD:
ROF: 280
Range: 7c0
MinRange: 3c0
Report: MISSILE1.AUD
Projectile: Bullet
Speed: 170
Arm: 10
High: true
Shadow: false
Proximity: true
Trail: smokey
Inaccuracy: 426
Image: V2
Angle: 216
Warhead:
Spread: 853
Versus:
None: 100%
Wood: 90%
Light: 80%
Heavy: 70%
Explosion: nuke
WaterExplosion: large_splash
InfDeath: 3
SmudgeType: Crater
Damage: 500
ImpactSound: kaboom1.aud
WaterImpactSound: kaboom1.aud
SilencedPPK:
ROF: 80
Range: 25c0
Report: silppk.aud
Projectile: Bullet
Speed: 1c682
Warhead:
Spread: 128
Versus:
Wood: 0%
Light: 0%
Heavy: 50%
Concrete: 0%
Explosion: piffs
InfDeath: 2
Damage: 150
Voices:
Notifications:
Translations: