Skip to content

Instantly share code, notes, and snippets.

@Bonuspunkt
Last active August 29, 2015 14:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Bonuspunkt/3d6f86af2c70728c5a6a to your computer and use it in GitHub Desktop.
Save Bonuspunkt/3d6f86af2c70728c5a6a to your computer and use it in GitHub Desktop.
Guitar Hero style item timers
require "base/internal/ui/reflexcore"
--------------------------------------------------------------------------------
-- HELPER
--------------------------------------------------------------------------------
local function add(array, value)
array[#array + 1] = value
end
local trueStack = function(player)
return math.min(
player.armor,
player.health * (player.armorProtection + 1)
) + player.health;
end
local canPickup = function(player, itemType)
if itemType == _G.PICKUP_TYPE_HEALTH100 then
return player.health < 200
elseif itemType == _G.PICKUP_TYPE_ARMOR150 then
return player.armorProtection < 2
or player.armor < 200
elseif itemType == _G.PICKUP_TYPE_ARMOR100 then
return player.armorProtection == 2 and player.armor < 133
or player.armorProtection ~= 2 and player.armor < 150
elseif itemType == _G.PICKUP_TYPE_ARMOR50 then
return player.armorProtection == 2 and player.armor < 66
or player.armorProtection == 1 and player.armor < 75
or player.armorProtection == 0 and player.armor < 100
elseif itemType == _G.PICKUP_TYPE_POWERUPCARNAGE then
return player.carnageTimer == 0
end
return false
end
local take = function(player, itemType)
if not canPickup(player, itemType) then
return {
armorProtection = player.armorProtection,
armor = player.armor,
health = player.health
}
elseif itemType == _G.PICKUP_TYPE_HEALTH100 then
return {
armorProtection = player.armorProtection,
armor = player.armor,
health = math.min(200, player.health + 100)
}
elseif itemType == _G.PICKUP_TYPE_ARMOR150 then
return {
armorProtection = 2,
armor = math.min(200, player.armor + 150),
health = player.health
}
elseif itemType == _G.PICKUP_TYPE_ARMOR100 then
return {
armorProtection = 1,
armor = math.min(150, player.armor + 100),
health = player.health
}
elseif itemType == _G.PICKUP_TYPE_ARMOR50 then
return {
armorProtection = 0,
armor = math.min(100, player.armor + 50),
health = player.health
}
end
end
local priorize = function(player, itemType)
if itemType == _G.PICKUP_TYPE_POWERUPCARNAGE then
return 401;
end
return trueStack(take(player, itemType))
end
local armorColors = {
_G.Color(0, 255, 0, 255),
_G.Color(255, 255, 0, 255),
_G.Color(255, 0, 0, 255)
}
local function colorLerp(colorA, colorB, k)
return _G.Color(
_G.lerp(colorA.r, colorB.r, k),
_G.lerp(colorA.g, colorB.g, k),
_G.lerp(colorA.b, colorB.b, k),
_G.lerp(colorA.a, colorB.a, k)
)
end
local drawArmor = function(x, y, size, armorProtection, lerpColor)
local color = armorColors[armorProtection + 1];
if lerpColor then
color = colorLerp(color, lerpColor, .75)
end
_G.nvgSave()
_G.nvgFillColor(color);
_G.nvgSvg("internal/ui/icons/armor", x, y, size)
_G.nvgRestore()
end
local drawMega = function(x, y, size, hasMega)
local healthColor
if hasMega then
healthColor = _G.Color(60,80,255)
else
healthColor = _G.Color(64,64,64)
end
_G.nvgSave()
_G.nvgFillColor(healthColor);
_G.nvgSvg("internal/ui/icons/health", x, y, size)
_G.nvgRestore()
end
local drawCarnage = function(x, y, size, carnageTimer)
if carnageTimer <= 0 then return end
_G.nvgSave()
_G.nvgFillColor(_G.Color(255,120,128))
_G.nvgSvg("internal/ui/icons/carnage", x, y, size)
_G.nvgRestore()
end
local function funcArray(array)
return {
map = function(func)
local newTable = {}
for i = 1, #array do
newTable[i] = func(array[i], i, array)
end
return funcArray(newTable)
end,
filter = function(func)
local newTable = {}
for i = 1, #array do
if func(array[i], i) then
newTable[#newTable+1] = array[i]
end
end
return funcArray(newTable)
end,
forEach = function(func)
for i = 1, #array do
func(array[i], i, array)
end
end,
reduce = function(func, initialValue)
for i = 1, #array do
initialValue = func(initialValue, array[i], i, array);
end
return initialValue
end,
sort = function(func)
local newArray = {}
for i = 1, #array do
newArray[i] = array[i]
end
table.sort(newArray, func)
return funcArray(newArray)
end,
first = function(func)
for i = 1, #array do
if func(array[i], i, array) then
return array[i]
end
end
end,
groupBy = function(func)
local newArray = funcArray({})
for i = 1, #array do
local key = func(array[i], i, array);
local match = newArray.first(function(other) return other.key == key end)
if not match then
match = { key = key, values = funcArray({ array[i] }) }
add(newArray.raw, match)
else
add(match.values.raw, array[i]);
end
end
return newArray
end,
concat = function(otherArray)
local result = {}
for i = 1, #array do
add(result, array[i])
end
if otherArray.raw then otherArray = otherArray.raw end
for j = 1, #otherArray do
add(result, otherArray[j])
end
return funcArray(result)
end,
-- escape the fancyness
raw = array
}
end
--------------------------------------------------------------------------------
-- CONFIG
--------------------------------------------------------------------------------
local lineHeight = 40
local iconRad = lineHeight/2 - 2
local fontSize = 50
local showTime = true
local showTrueStack = true
--------------------------------------------------------------------------------
-- WIDGET
--------------------------------------------------------------------------------
_G.ItemHero =
{
draw = function()
if not _G.shouldShowHUD() then return end;
local player = _G.getPlayer()
-- draw spawn area
local pickupCount = #_G.pickupTimers
_G.nvgBeginPath();
_G.nvgRoundedRect(
-100 - iconRad/2,
lineHeight/2,
iconRad*2,
lineHeight * pickupCount,
5
)
_G.nvgFillColor(_G.Color(0,0,0,128))
_G.nvgFill()
_G.nvgTextAlign(_G.NVG_ALIGN_CENTER, _G.NVG_ALIGN_MIDDLE)
_G.nvgFontSize(fontSize);
_G.nvgFillColor(_G.Color(255,255,255,127))
funcArray(_G.pickupTimers)
.groupBy(function(pickup) return pickup.type end)
.map(function(group)
return group.values.map(
function(pickup, i, array)
local index = 0
if #array > 1 then
index =i
end
return {
index = index,
respawn = pickup.timeUntilRespawn,
type = pickup.type,
canSpawn = pickup.canSpawn,
priority = priorize(player, pickup.type),
canPickup = canPickup(player, pickup.type)
}
end)
end)
.reduce(function(prev, curr)
return prev.concat(curr)
end, funcArray({}))
.sort(function(a, b)
return a.type > b.type
end)
.forEach(function(pickup, i)
-- draw time
if showTime then
local time
_G.nvgTextAlign(_G.NVG_ALIGN_RIGHT, _G.NVG_ALIGN_MIDDLE)
if pickup.respawn ~= 0 then
time = math.ceil(pickup.respawn / 1000)
elseif pickup.canSpawn then
time = "-"
else
time = "held"
end
_G.nvgText(-140, lineHeight * i, time)
end
-- draw icon
local x = pickup.respawn/100 + iconRad/2
if pickup.type == 60 then
drawCarnage(-100 + x, lineHeight * i, iconRad, 1)
elseif pickup.type < 50 then
if not pickup.canSpawn then x = 300 end
drawMega(-100 + x, lineHeight * i, iconRad, pickup.canSpawn)
else
local lerpColor
if not pickup.canPickup then
lerpColor = _G.Color(0,0,0)
end
drawArmor(-100 + x, lineHeight * i, iconRad, pickup.type - _G.PICKUP_TYPE_ARMOR50, lerpColor)
end
if pickup.index > 0 then
_G.nvgSave()
for blur, color in pairs({_G.Color(0,0,0), _G.Color(255,255,255)}) do
_G.nvgFillColor(color)
_G.nvgFontBlur((2 - blur) * 10)
_G.nvgFontSize(fontSize * 2 / 3);
_G.nvgTextAlign(_G.NVG_ALIGN_CENTER, _G.NVG_ALIGN_MIDDLE)
_G.nvgText(-100 + x + iconRad/2, lineHeight * i + iconRad/2, pickup.index)
end
_G.nvgRestore()
end
end)
end
};
_G.registerWidget("ItemHero");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment