|
|
|
|
|
|
|
function animate(animation)
|
|
|
|
add(animations, animation, 1)
|
|
|
|
animation.before()
|
|
|
|
end
|
|
|
|
|
|
|
|
function contains(haystack, needle)
|
|
|
|
for h in all(haystack) do
|
|
|
|
if needle == h then return true end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
function deepcopy(orig)
|
|
|
|
local orig_type = type(orig)
|
|
|
|
local copy
|
|
|
|
if orig_type == 'table' then
|
|
|
|
copy = {}
|
|
|
|
for orig_key, orig_value in next, orig, nil do
|
|
|
|
copy[deepcopy(orig_key)] = deepcopy(orig_value)
|
|
|
|
end
|
|
|
|
setmetatable(copy, deepcopy(getmetatable(orig)))
|
|
|
|
else -- number, string, boolean, etc
|
|
|
|
copy = orig
|
|
|
|
end
|
|
|
|
return copy
|
|
|
|
end
|
|
|
|
|
|
|
|
function filter_list(arr, func)
|
|
|
|
new = {}
|
|
|
|
|
|
|
|
for old_index, v in ipairs(arr) do
|
|
|
|
if func(v, old_index) then add(new, v) end
|
|
|
|
end
|
|
|
|
|
|
|
|
return new
|
|
|
|
end
|
|
|
|
|
|
|
|
function player_has(requirement, count, traits)
|
|
|
|
if count == nil then count = 1 end
|
|
|
|
output = {}
|
|
|
|
for x in all(inventory) do
|
|
|
|
if x.title == requirement or contains(x.tags, requirement) then
|
|
|
|
for t in all(traits) do
|
|
|
|
if not contains(x.traits, t) then
|
|
|
|
goto continue
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if count == 1 then return x end
|
|
|
|
add(output, x)
|
|
|
|
|
|
|
|
::continue::
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if #output >= count then
|
|
|
|
return filter_list(output, function(x,i) return i<=count end)
|
|
|
|
end
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
function make_item(bp)
|
|
|
|
--if bp.description == nil then
|
|
|
|
-- bp = library.i_bps[bp]
|
|
|
|
--end
|
|
|
|
|
|
|
|
local i = deepcopy(bp)
|
|
|
|
|
|
|
|
i.quality = flr(bp.quality_base + rnd(bp.quality_range))
|
|
|
|
if bp.tags then i.tags = deepcopy(bp.tags)
|
|
|
|
else i.tags = {} end
|
|
|
|
i.traits = {}
|
|
|
|
if rnd(100) < bp.trait_chance then
|
|
|
|
add(i.traits, rnd(bp.trait_pool))
|
|
|
|
end
|
|
|
|
if rnd(100) < bp.trait_chance then
|
|
|
|
local t = rnd(bp.trait_pool)
|
|
|
|
if not contains(i.traits, t) then add(i.traits, t) end
|
|
|
|
end
|
|
|
|
return i
|
|
|
|
end
|
|
|
|
|
|
|
|
function at(trait, x,y)
|
|
|
|
if x < 0 or x >= trait[4] or y < 0 or y >= trait[5] then return false end
|
|
|
|
return mget(trait[2]+x, trait[3]+y) ~= 0
|
|
|
|
end
|
|
|
|
|
|
|
|
function at_absolute(trait, x,y)
|
|
|
|
return at(trait.trait, x-trait.x, y-trait.y)
|
|
|
|
end
|
|
|
|
|
|
|
|
function overlaps(trait1, trait2)
|
|
|
|
t1_width = trait1.trait[4]
|
|
|
|
t1_height = trait1.trait[5]
|
|
|
|
for i=0,(t1_width-1) do
|
|
|
|
for j=0,(t1_height-1) do
|
|
|
|
x = trait1.x + i
|
|
|
|
y = trait1.y + j
|
|
|
|
if at_absolute(trait1, x, y) and at_absolute(trait2, x, y) then
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
function change_screen(new_screen)
|
|
|
|
prev_screen = current_screen
|
|
|
|
if new_screen.before ~= nil then new_screen.before() end
|
|
|
|
current_screen = new_screen
|
|
|
|
end
|
|
|
|
|
|
|
|
-- add newlines to a string to fit it into lines.
|
|
|
|
function wrap(str, line_length)
|
|
|
|
-- thanks to https://stackoverflow.com/questions/17586/best-word-wrap-algorithm, i did not feel like thinking this out myself
|
|
|
|
local words = split(str, " ", false)
|
|
|
|
local output = ""
|
|
|
|
|
|
|
|
local c = 0
|
|
|
|
for w in all(words) do
|
|
|
|
while sub(w, 1, 1) == "\n" do
|
|
|
|
output = output .. "\n"
|
|
|
|
c = 0
|
|
|
|
w = sub(w, 2)
|
|
|
|
end
|
|
|
|
if c + #w > line_length then
|
|
|
|
if c > 0 then
|
|
|
|
output = output .. "\n"
|
|
|
|
c = 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
output = output .. w .. " "
|
|
|
|
c += #w + 1
|
|
|
|
end
|
|
|
|
return output
|
|
|
|
end
|