//This was used to attempt to speed patch drawing up by reducing the amount of v.cachePatch calls used. There is code at the end of the per-frame function to clear unused parts of the cache.
local function create_cachePatch(v,patchName)
if cachedIcons[patchName] == nil then
cachedIcons[patchName] = v.cachePatch(patchName)
print("Added "..patchName.." to cache") //For debug purposes. Will naturally be removed before release. And yes, I have a corresponding message for removal, so I know the automatic cache clearing is working properly.
end
cacheUsed[patchName] = leveltime
return cachedIcons[patchName]
end
//Return the string representing the icon for the item in question. This could be handled by an array IN THEORY, but some items change icon depending on circumstances.
local function getIcon(p,inventory,num)
local item = inventory[num]
if item == 1 then
if P_IsObjectOnGround(p.mo) == false and p.powers[pw_shield] == 4 then
return "ICONARMA"
elseif interactText[p.mo.subsector.sector.tag] != nil then
return "ICONINTE"
elseif interactDialogue[p.mo.subsector.sector.tag] != nil then
return "ICONINTT"
else
return "ICONINTN"
end
elseif item == 2 then
if checkSectors(p,701) or checkSectors(p,702) or checkSectors(p,703) then return "ICONTHOP"
else return "ICONTHER" end
elseif item == 3 then return "ICONTHWA"
elseif item == 4 then return "ICONTHHT"
elseif item == 5 then return "ICONTHCD"
elseif item == 6 then return "ICONREBR"
//Empty Card
elseif item == 7 then
local nearestMonitor = nil //The nearest monitor within melee range.
local monitorDist = 50*FRACUNIT //The distance away the nearest monitor is. The starting distance sets the max distance a monitor can be away to be affected by this item.
for spot in mapthings.iterate do
if spot.mobj != nil then
local mon = spot.mobj
if mon.type == MT_SUPERRINGBOX or mon.type == MT_BLACKTV or mon.type == MT_BLUETV or mon.type == MT_EGGMANBOX or mon.type == MT_GREENTV or mon.type == MT_PITYTV or mon.type == MT_INV or mon.type == MT_SNEAKERTV or mon.type == MT_WHITETV or mon.type == MT_YELLOWTV or mon.type == MT_FIRETV or mon.type == MT_WATERTV then //If it's ANY valid monitor type.
if P_CheckSight(p.mo,mon) then
if R_PointToDist2(p.mo.x,p.mo.y,mon.x,mon.y) < monitorDist then
monitorDist = R_PointToDist2(p.mo.x,p.mo.y,mon.x,mon.y)
nearestMonitor = mon
end
end
end
end
end
if nearestMonitor == nil then return "ICONCDEM" end
if nearestMonitor.type == MT_SUPERRINGBOX or nearestMonitor.type == MT_SNEAKERTV then
if p.energy >= 500 then return "ICONCDYS" else return "ICONCDNO" end
elseif nearestMonitor.type == MT_PITYTV then
if p.energy >= 1000 then return "ICONCDYS" else return "ICONCDNO" end
elseif nearestMonitor.type == MT_FIRETV or nearestMonitor.type == MT_WATERTV then
if p.energy >= 1500 then return "ICONCDYS" else return "ICONCDNO" end
elseif nearestMonitor.type == MT_BLUETV or nearestMonitor.type == MT_BLACKTV or nearestMonitor.type == MT_GREENTV or nearestMonitor.type == MT_WHITETV or nearestMonitor.type == MT_YELLOWTV then
if p.energy >= 2000 then return "ICONCDYS" else return "ICONCDNO" end
elseif nearestMonitor.type == MT_EGGMANBOX or nearestMonitor.type == MT_INV then
if p.energy >= 3000 then return "ICONCDYS" else return "ICONCDNO" end
end
return "ICONCDEM"
elseif item == 8 then return "ICONCDRG"
elseif item == 9 then return "ICONMEDI"
elseif item == 10 then return "ICONCDAR"
elseif item == 11 then return "ICONCDFO"
elseif item == 12 then return "ICONCDEG"
elseif item == 13 then return "ICONCDEL"
elseif item == 14 then return "ICONCDPI"
elseif item == 15 then return "ICONCDIN"
elseif item == 16 then return "ICONCDSP"
elseif item == 17 then return "ICONCDWH"
elseif item == 18 then return "ICONCDMA"
elseif item == 19 then return "ICONSLNG"
elseif item == 20 then return "ICONCDFI"
elseif item == 21 then return "ICONCDWA"
elseif item == 22 then return "ICONFISD"
else return "" end
end
//Return the number to show under the item's icon.
local function getItemNum(p,num,overrideShopMode)
if p.shopMode == 1 and num > 0 then
local item = shopInv
if item == 19 then return shopSlingBullets
elseif item == 22 then return shopSeeds
else return "" end
elseif p.shopMode == 3 and num > 0 then
local item = buyBack
if item == 19 then return shopSlingBulletsBuyback
elseif item == 22 then return shopSeedsBuyback
else return "" end
else
local item = p.slots[num]
if item == 19 then return p.bullets
elseif item == 22 then return p.seeds
else return "" end
end
end
//Return the string representing the name for the item in question. This could be handled by an array IN THEORY, but some items change name depending on circumstances.
local function getName(p,num)
local item = p.slots[num]
if item == 1 then
if P_IsObjectOnGround(p.mo) == false and p.powers[pw_shield] == 4 then
return "Detonate"
elseif interactText[p.mo.subsector.sector.tag] != nil then
return "Examine"
elseif interactDialogue[p.mo.subsector.sector.tag] != nil then
return "Talk"
else
return ""
end
elseif item == 2 then return "Thermos"
elseif item == 3 then return "Water"
elseif item == 4 then return "Warm Drink"
elseif item == 5 then return "Cold Drink"
elseif item == 6 then return "Rebreather"
elseif item == 7 then return "Egg Card"
elseif item == 8 then return "10 Rings"
elseif item == 9 then return "Medikit"
elseif item == 10 then return "Armageddon"
elseif item == 11 then return "Force"
elseif item == 12 then return "Robotnik"
elseif item == 13 then return "Elemental"
elseif item == 14 then return "Shield"
elseif item == 15 then return "Invincibility"
elseif item == 16 then return "Speed"
elseif item == 17 then return "Whirlwind"
elseif item == 18 then return "Attraction"
elseif item == 19 then return "Sling"
elseif item == 20 then return "Inferno"
elseif item == 21 then return "Liquid"
elseif item == 22 then return "Fire Seeds"
else return "" end
end
local function drawInventory(v,p)
if p.playerstate != PST_LIVE then return nil end //This should not show anything if the player is dead or if the menu is open.
//Draw the top three boxes, the labels for them, and the items in them.
v.drawString(100-v.stringWidth("SPIN")/2,10,"SPIN",V_SNAPTOTOP) //The button to press to use the item.
if p.slots[-3] == 19 and p.attackTimer > 0 //Draw a semitransparent red box to indicate you can't attack again yet. As more weapons are coded in, the first condition will be replaced with isItemWeapon().
v.draw(89,22,create_cachePatch(v,"NOATTACK"),V_SNAPTOTOP|V_50TRANS)
end
if p.slots[-3] > 0 then v.draw(91,24,create_cachePatch(v,getIcon(p,p.slots,-3)),V_SNAPTOTOP) end //Draw the icon for the item.
v.drawString(108,34,getItemNum(p,-3),V_SNAPTOTOP,"right") //If the item has a quantity attached (for example, you can carry up to 99 Fire Seeds in one slot), draw it
v.draw(88,21,create_cachePatch(v,"MENUCURS"),V_SNAPTOTOP) //Draw the box itself for the item.
v.drawString(160-v.stringWidth("C1")/2,10,"C1",V_SNAPTOTOP) //Repeat two more times for the other boxes.
if p.slots[-1] == 19 and p.attackTimer > 0
v.draw(149,22,create_cachePatch(v,"NOATTACK"),V_SNAPTOTOP|V_50TRANS)
end
if p.slots[-1] > 0 then v.draw(151,24,create_cachePatch(v,getIcon(p,p.slots,-1)),V_SNAPTOTOP) end
v.drawString(168,34,getItemNum(p,-1),V_SNAPTOTOP,"right")
v.draw(148,21,create_cachePatch(v,"MENUCURS"),V_SNAPTOTOP)
v.drawString(220-v.stringWidth("C2")/2,10,"C2",V_SNAPTOTOP)
if p.slots[-2] == 19 and p.attackTimer > 0
v.draw(209,22,create_cachePatch(v,"NOATTACK"),V_SNAPTOTOP|V_50TRANS)
end
if p.slots[-2] > 0 then v.draw(211,24,create_cachePatch(v,getIcon(p,p.slots,-2)),V_SNAPTOTOP) end
v.drawString(228,34,getItemNum(p,-2),V_SNAPTOTOP,"right")
v.draw(208,21,create_cachePatch(v,"MENUCURS"),V_SNAPTOTOP)
//Draw the names if the screen is large enough and the menu is not open. Otherwise, don't bother. The text is either illegibly small or potentially covered up by the inventory.
if not p.menuOpen and v.width() >= 640 and v.height() >= 400 then
v.drawString(100-v.stringWidth(getName(p,-3),0,"small")/2,48,getName(p,-3),V_SNAPTOTOP,"small")
v.drawString(160-v.stringWidth(getName(p,-1),0,"small")/2,48,getName(p,-1),V_SNAPTOTOP,"small")
v.drawString(220-v.stringWidth(getName(p,-2),0,"small")/2,48,getName(p,-2),V_SNAPTOTOP,"small")
end
if not p.menuOpen then return nil end //Don't show the inventory menu if it's closed.
//The global offset for all things on the menu. The menu should be centered on the screen horizontally. The global vertical offset will likely be consistently 50, but this may change.
local offsetX = 7
local offsetY = 50 //This should be AT LEAST 50.
//Heading
if p.shopMode == 0 then
v.drawString(160,offsetY,"Inventory",0,"center") //Draw inventory heading.
else
v.drawString(160,offsetY,shopName,0,"center") //Draw inventory heading.
end
v.drawString(310,offsetY,"Rings: "..p.ringCount,0,"right") //Draw rings.
v.draw(offsetX,offsetY+10,create_cachePatch(v,"INVENBOX")) //Draw main panel.
v.draw(offsetX+218,offsetY+10,create_cachePatch(v,"SIDEBOX")) //Draw side panel.
v.draw(offsetX,offsetY+124,create_cachePatch(v,"DESCBOX")) //Draw description panel.
//Draw current inventory.
local invUsed = p.slots //The inventory table to draw. This could be the player's, the shop's, or the shop's buyback (not yet implemented).
if p.shopMode == 1 then invUsed = shopInv end
//Draw inventory items.
for i=1, 32
if invUsed[i] > 0 then v.draw(offsetX+9+((i-1)%8)*26,offsetY+19+((i-1)/8)*26,create_cachePatch(v,getIcon(p,invUsed,i))) end //Draw item icon.
v.drawString(offsetX+26+((i-1)%8)*26,offsetY+29+((i-1)/8)*26,getItemNum(p,i),0,"right") //Draw quantity, if applicable.
end
if p.shopMode > 0 then //If the player is in a shop.
//Draw buy icon, translucent out if not in buy mode.
if p.shopMode == 1 then
v.draw(offsetX+227,offsetY+19,create_cachePatch(v,"ICONBUY"))
else
v.draw(offsetX+227,offsetY+19,create_cachePatch(v,"ICONBUY"),V_TRANSLUCENT)
end
//Draw sell icon, translucent out if not in sell mode.
if p.shopMode == 2 then
v.draw(offsetX+253,offsetY+19,create_cachePatch(v,"ICONSELL"))
else
v.draw(offsetX+253,offsetY+19,create_cachePatch(v,"ICONSELL"),V_TRANSLUCENT)
end
//Draw buyback icon, translucent out if not in buyback mode.
if p.shopMode == 3 then
v.draw(offsetX+279,offsetY+19,create_cachePatch(v,"ICONBUYB"))
else
v.draw(offsetX+279,offsetY+19,create_cachePatch(v,"ICONBUYB"),V_TRANSLUCENT)
end
//Draw sell price.
if p.shopMode == 2 and p.slots[8*p.cY+p.cX+1] > 0 then
if price[p.slots[8*p.cY+p.cX+1]] == 0 then //If the selected item has no price...
v.drawString(10,offsetY,"NO SALE") //...it cannot be sold.
else
v.drawString(10,offsetY,"Price: "..(price[p.slots[8*p.cY+p.cX+1]]/2)) //Otherwise, draw its selling price.
end
end
//Draw shop option descriptions in the description panel.
if p.cX == 8 and p.cY == 0 then
if v.width() < 640 or v.height() < 400 then
v.drawString(offsetX+5,offsetY+129,"Buy items for rings",0,"thin")
else
v.drawString(offsetX+5,offsetY+129,"Buy items for rings.",0,"small")
end
elseif p.cX == 9 and p.cY == 0 then
if v.width() < 640 or v.height() < 400 then
v.drawString(offsetX+5,offsetY+129,"Sell items for rings",0,"thin")
else
v.drawString(offsetX+5,offsetY+129,"Sell items for rings.",0,"small")
end
elseif p.cX == 10 and p.cY == 0 then
if v.width() < 640 or v.height() < 400 then
v.drawString(offsetX+5,offsetY+129,"Buy items back at selling price",0,"thin")
else
v.drawString(offsetX+5,offsetY+129,"Buy items back at selling price.",0,"small")
v.drawString(offsetX+5,offsetY+135,"Items not bought back are cleared at the end of each level.",0,"small")
end
end
else //If the player is viewing their inventory normally, outside of a shop.
//Draw converter.
if p.convertMode == 1 then v.draw(offsetX+227,offsetY+97,create_cachePatch(v,"ICONCONH")) end
if p.convertMode == 2 then v.draw(offsetX+227,offsetY+97,create_cachePatch(v,"ICONCONE")) end
//Draw batteries owned.
if p.maxEnergy >= 1 then
if leveltime%2 == 1 then
v.draw(offsetX+248,offsetY+93,create_cachePatch(v,"ICONBATT"))
else
v.draw(offsetX+248,offsetY+93,create_cachePatch(v,"ICONBAT2"))
end
if p.maxEnergy < 10 then v.drawString(offsetX+263,offsetY+104,p.maxEnergy)
else v.drawString(offsetX+262,offsetY+104,p.maxEnergy,0,"thin") end
end
//Draw any emeralds currently owned.
if emeralds & EMERALD1 then v.draw(offsetX+284,offsetY+102,create_cachePatch(v,"TEMER1")) end
if emeralds & EMERALD2 then v.draw(offsetX+280,offsetY+96,create_cachePatch(v,"TEMER2")) end
if emeralds & EMERALD3 then v.draw(offsetX+288,offsetY+96,create_cachePatch(v,"TEMER3")) end
if emeralds & EMERALD4 then v.draw(offsetX+292,offsetY+102,create_cachePatch(v,"TEMER4")) end
if emeralds & EMERALD5 then v.draw(offsetX+288,offsetY+108,create_cachePatch(v,"TEMER5")) end
if emeralds & EMERALD6 then v.draw(offsetX+280,offsetY+108,create_cachePatch(v,"TEMER6")) end
if emeralds & EMERALD7 then v.draw(offsetX+276,offsetY+102,create_cachePatch(v,"TEMER7")) end
//Battery description.
if p.cX == 9 and p.cY == 3 and p.maxEnergy > 0 then
if v.width() < 640 or v.height() < 400 then
v.drawString(offsetX+5,offsetY+129,"Your batteries. Used to power devices built by Eggman.",0,"thin")
else
v.drawString(offsetX+5,offsetY+129,"Your collected Egg Batteries.",0,"small")
v.drawString(offsetX+5,offsetY+135,"Used to power any of Eggman's devices you have taken.",0,"small")
end
//Emeralds description.
elseif p.cX == 10 and p.cY == 3 and emeralds != 0 then
if v.width() < 640 or v.height() < 400 then
v.drawString(offsetX+5,offsetY+129,"Your chaos emeralds. Can often boost devices built by Eggman.",0,"thin")
else
v.drawString(offsetX+5,offsetY+129,"Your collected chaos emeralds.",0,"small")
v.drawString(offsetX+5,offsetY+135,"Devices built by Eggman can often be boosted by these.",0,"small")
end
//Converter description.
elseif p.cX == 8 and p.cY == 3 and p.convertMode != 0 then
if v.width() < 640 or v.height() < 400 then
v.drawString(offsetX+5,offsetY+129,"Converts rings to health or energy Select to toggle preference",0,"thin")
else
v.drawString(offsetX+5,offsetY+129,"This converter converts collected rings to health or energy.",0,"small")
v.drawString(offsetX+5,offsetY+135,"Select to toggle which one is prioritized.",0,"small")
end
//Debug room description.
elseif p.cY == 1 and p.cX == 9 and gamemap != 172 then
if v.width() < 640 or v.height() < 400 then
v.drawString(offsetX+5,offsetY+129,"Nothing to see in this slot",0,"thin")
else
v.drawString(offsetX+5,offsetY+129,"Nothing to see in this slot.",0,"small")
v.drawString(offsetX+5,offsetY+135,"Yup, completely blank.",0,"small")
end
end
end
//Draw item selection cursor.
if (leveltime/10)%2 == 1 then
if p.cX < 8 then v.draw(offsetX+6+(p.cX*26),offsetY+16+(p.cY*26),create_cachePatch(v,"MENUCURS"))
else v.draw(offsetX+16+(p.cX*26),offsetY+16+(p.cY*26),create_cachePatch(v,"MENUCURS")) end
end
//Draw the selected item's name and description.
if p.cX < 8 and invUsed[8*p.cY+p.cX+1] > 0 then
//Draw a single thin line if at low res.
if v.width() < 640 or v.height() < 400 then
v.drawString(offsetX+5,offsetY+129,itemName[invUsed[8*p.cY+p.cX+1]]..":",V_YELLOWMAP,"thin")
v.drawString(offsetX+5+v.stringWidth(itemName[invUsed[8*p.cY+p.cX+1]]..": ",0,"thin"),offsetY+129,itemShortDesc[invUsed[8*p.cY+p.cX+1]],0,"thin")
else
v.drawString(offsetX+5,offsetY+129,itemName[invUsed[8*p.cY+p.cX+1]]..":",V_YELLOWMAP,"small")
v.drawString(offsetX+5+v.stringWidth(itemName[invUsed[8*p.cY+p.cX+1]]..": ",0,"small"),offsetY+129,itemDesc[invUsed[8*p.cY+p.cX+1]],0,"small")
v.drawString(offsetX+5,offsetY+135,itemDesc2[invUsed[8*p.cY+p.cX+1]],0,"small")
end
end
end
hud.add(drawInventory,"game")