Advertisement
KBM-Quine

powerstarEXT.lua prerelease 1

May 16th, 2022
643
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -------------------------------------------------
  2. --[[   powerstarEXT.lua v1.0 by KBM-Quine    ]]--
  3. --[[  with code help/advice from: Rednaxela  ]]--
  4. --[[      Based on SMBX source code and      ]]--
  5. --[[        chucks.lua by snoruntpyro        ]]--
  6. -------------------------------------------------
  7. local npcutils = require("npcs/npcutils")
  8. local npcManager = require("npcManager")
  9. local iniParse = require("configFileReader")
  10.  
  11. local powerstarEXT = {
  12.     starIDsMap = {},
  13.     starIDs = {}
  14. }
  15.  
  16. local GM_STAR_ADDR = mem(0x00B25714, FIELD_DWORD)
  17.  
  18. local function addStar(npc, filename)
  19.     -- do some fact checking since we're shoving our hands in memory addresses
  20.     if filename == nil or type(filename) ~= "string" then
  21.         error("invalid or nil fileString")
  22.     end
  23.     if (npc == nil or type(npc) ~= "NPC") then
  24.         error("invalid or nil NPC")
  25.     end
  26.     if (npc.data._settings.starIndex == nil or type(npc.data._settings.starIndex) ~= "number") then
  27.         error("invalid or nil star index")
  28.     end
  29.     if (mem(0x00B251E0, FIELD_WORD) + 1) == 1001 then return end -- don't add if we're going over internal array limit
  30.     mem(0x00B251E0, FIELD_WORD, mem(0x00B251E0, FIELD_WORD) + 1) -- add to star count...
  31.     mem(GM_STAR_ADDR+(mem(0x00B251E0, FIELD_WORD) - 1)*0x08+0x00, FIELD_STRING, filename) -- set level file it's obtained from...
  32.     mem(GM_STAR_ADDR+(mem(0x00B251E0, FIELD_WORD) - 1)*0x08+0x04, FIELD_WORD, 1000 + npc.data._settings.starIndex ) --and use the section field as an index. use 20 as a base so not to erase basegame stars
  33. end
  34.  
  35. function powerstarEXT.isStarCollected(npc, filename)
  36.     local collected = false
  37.     for i=1, mem(0x00B251E0, FIELD_WORD) do
  38.         if mem(GM_STAR_ADDR+(i - 1)*0x08+0x00, FIELD_STRING) == filename and mem(GM_STAR_ADDR+(i - 1)*0x08+0x04, FIELD_WORD) == (1000 + npc.data._settings.starIndex) then
  39.             collected = true
  40.         end
  41.     end
  42.     return collected
  43. end
  44.  
  45.  
  46.  
  47. local match = string.match
  48. local tableinsert = table.insert
  49.  
  50. local function ParselvlxNPCs(objectPath) -- get npcs from a lvlx file, taken from configfilereader
  51.     local finalArray = {}
  52.     if objectPath ~= nil then
  53.         local lns = io.readFileLines(objectPath)
  54.         local readLines = false
  55.         if lns == nil then
  56.             error("Error loading level file "..objectPath, 2)
  57.         end
  58.             for _,line in ipairs(lns) do
  59.                 if line == "NPC" then
  60.                     readLines = true
  61.                 end
  62.                 if readLines and not (line == "NPC" or line == "NPC_END") then
  63.                     local matchedID = match(line, '%d+') -- since the first number is always the ID and we only need the ID, grab only that
  64.                     tableinsert(finalArray, tonumber(matchedID))
  65.                 end
  66.                 if line == "NPC_END" then
  67.                     readLines = false
  68.                 end
  69.             end
  70.             return finalArray
  71.         else
  72.     end
  73. end
  74.  
  75. function powerstarEXT.getStarsCollected()
  76.     local t = {}
  77.     for i=1, mem(0x00B251E0, FIELD_WORD) do
  78.         t[i] = {filename = mem(GM_STAR_ADDR+(i - 1)*0x08+0x00, FIELD_STRING), index = mem(GM_STAR_ADDR+(i - 1)*0x08+0x04, FIELD_WORD)}
  79.     end
  80.     return t
  81. end
  82.  
  83. local function addToWarpsonStart()
  84.     if isOverworld then return end
  85.     for _, warp in ipairs(Warp.get()) do
  86.         if warp.levelFilename == "" then return end
  87.         local IDs = ParselvlxNPCs(Misc.episodePath() .. warp.levelFilename)
  88.         for _,v in ipairs(IDs) do
  89.             if powerstarEXT.starIDsMap[v] then
  90.                 warp:mem(0x8C, FIELD_WORD, warp:mem(0x8C, FIELD_WORD) + 1)
  91.             end
  92.         end
  93.     end
  94. end
  95.  
  96. local function addToWarpsonCollect(filename)
  97.     for _, warp in ipairs(Warp.get()) do
  98.         if warp.levelFilename == "" then return end
  99.         if filename == warp.levelFilename then
  100.             warp:mem(0x8A, FIELD_WORD, warp:mem(0x8A, FIELD_WORD) + 1)
  101.         end
  102.     end
  103. end
  104.  
  105. function powerstarEXT.collect(star, plyr)
  106.     if not powerstarEXT.isStarCollected(star, Level.filename()) then
  107.         addStar(star, Level.filename())
  108.         addToWarpsonCollect(Level.filename())
  109.         if not star.data._settings.endLevel then
  110.             SFX.play(NPC.config[star.id].collectionsfx)
  111.         end
  112.     else
  113.         Misc.coins(5, true)
  114.         Effect.spawn(11, star.x + (star.width*0.5), star.y + (star.height*0.5))
  115.     end
  116.     if star.data._settings.endLevel then
  117.         Level.endState(LEVEL_END_STATE_STAR)
  118.         for i=1,  Player.count() do
  119.             if Player(i) ~= plyr then
  120.                 Player(i).section = plyr.section
  121.                 Player(i).x = plyr.x
  122.                 Player(i).y = plyr.y
  123.                 Player(i).forcedState = FORCEDSTATE_INVISIBLE
  124.                 Player(i).forcedTimer = -plyr.idx
  125.             end
  126.         end
  127.         SFX.play(NPC.config[star.id].levelendsfx)
  128.         Audio.SeizeStream(-1)
  129.         Audio.MusicStop()
  130.     end
  131. end
  132.  
  133. function powerstarEXT.registerStar(npcID)
  134.     npcManager.registerEvent(npcID, powerstarEXT, "onDrawNPC", "onDrawStar")
  135.     npcManager.registerEvent(npcID, powerstarEXT, "onTickEndNPC", "onTickEndStar")
  136.     powerstarEXT.starIDsMap[npcID] = true
  137.     table.insert(powerstarEXT.starIDs, npcID)
  138. end
  139.  
  140. function powerstarEXT.onInitAPI()
  141.     registerEvent(powerstarEXT, "onStart")
  142.     registerEvent(powerstarEXT, "onNPCKill")
  143. end
  144.  
  145.  
  146. function powerstarEXT.onStart()
  147.     addToWarpsonStart()
  148. end
  149.  
  150. function powerstarEXT.animateNPC(v)
  151.     v.data.animationTimer = v.data.animationTimer + 1
  152.     if v.data.animationTimer%NPC.config[v.id].framespeed == 0 then
  153.         v.data.frame = v.data.frame + 1
  154.         if v.data.frame > ((NPC.config[v.id].frames*v.data.frameMulti)-1) then
  155.             v.data.frame = ((NPC.config[v.id].frames*v.data.frameMulti)-1)
  156.         end
  157.         v.data.animationTimer = 0
  158.     end
  159.     v.animationFrame = npcutils.getFrameByFramestyle(v, {frame=v.data.frame})
  160. end
  161.  
  162. function powerstarEXT.onDrawStar(v)
  163.     v.animationTimer = -1 -- clamp the basegame animation timer at 0
  164. end
  165.  
  166. function powerstarEXT.onTickEndStar(v)
  167.     local data = v.data
  168.  
  169.     if not data.initialized then
  170.         data._settings.starIndex = data._settings.starIndex or 1
  171.        
  172.         data.collected = powerstarEXT.isStarCollected(v, Level.filename())
  173.         if data.collected then
  174.             data.frameMulti = 1
  175.         else
  176.             data.frameMulti = 0.5
  177.         end
  178.         data.frame = ((NPC.config[v.id].frames*data.frameMulti)-1)
  179.         data.animationTimer = 0
  180.         data.initialized = true
  181.     end
  182.  
  183.     if Defines.levelFreeze then return end
  184.  
  185.     powerstarEXT.animateNPC(v)
  186.  
  187.     if NPC.config[v.id].sparkles then
  188.         v.ai4 = v.ai4 + 1
  189.         if v.ai4 >= 10*data.frameMulti then
  190.             v.ai4 = 0
  191.             local e = Effect.spawn(80, v.x + RNG.random()*v.width - 2, v.y + RNG.random()*v.height)
  192.             e.speedX = RNG.random()*1 - 0.5
  193.             e.speedY = RNG.random()*1 - 0.5
  194.             if data.frameMulti == 1 then -- set frame of effects only for collected stars
  195.                 e.animationFrame = 1
  196.             end
  197.         end
  198.     end
  199.  
  200.     if NPC.config[v.id].floats and not v:mem(0x136, FIELD_BOOL) then
  201.         if v.ai2 == 0 then
  202.             v.speedY = v.speedY - 0.04
  203.             if v.speedY <= -1.4 then v.ai2 = 1 end
  204.         else
  205.             v.speedY = v.speedY + 0.04
  206.             if v.speedY >= 1.4 then v.ai2 = 0 end
  207.         end
  208.         -- if v.ai3 == 0 then -- idk what this for but it's in source?
  209.         --     v.speedX = v.speedX - 0.03
  210.         --     if v.speedX <= -0.6 then v.ai3 = 1 end
  211.         -- else
  212.         --     v.speedX = v.speedX + 0.03
  213.         --     if v.speedX >= 0.6 then v.ai3 = 0 end
  214.         -- end
  215.     end
  216.  
  217.     if NPC.config[v.id].uselayerspeed then -- can't be used in conjunction with floats
  218.         v.speedX, v.speedY = npcutils.getLayerSpeed(v)
  219.     end
  220.  
  221. end
  222.  
  223. function powerstarEXT.onNPCKill(obj, n, r)
  224.     if powerstarEXT.starIDsMap[n.id] and r == 9 then
  225.         if (npcManager.collected(n, r) or n:mem(0x138, FIELD_WORD) == 5) then
  226.             powerstarEXT.collect(n, npcManager.collected(n, r))
  227.         end
  228.     end
  229. end
  230.  
  231. return powerstarEXT
Advertisement
RAW Paste Data Copied
Advertisement