Advertisement
KBM-Quine

blockBuster.lua prerelease 2

Nov 16th, 2021
576
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 34.48 KB | None | 0 0
  1. -------------------------------------------------------------------
  2. --[[              blockBuster.lua v0.1 by KBM-Quine            ]]--
  3. --[[                  name suggested by Enjl.                  ]]--
  4. --[[                      code help from:                      ]]--
  5. --[[                         MrDoubleA                         ]]--
  6. --[[   with code heavily borrowed from modernReserveItems.lua  ]]--
  7. -------------------------------------------------------------------
  8. local blockBuster = {}
  9. local blockManager = require("blockManager")
  10. local blockutils = require("blocks/blockutils")
  11.  
  12. blockBuster.enabled = true
  13. blockBuster.npcOwnersToBlocks = false
  14. blockBuster.playSounds = true
  15. blockBuster.bumpAmount = 12
  16. blockBuster.useCustomCoinHandling = false
  17. blockBuster.useCustomItemHandling = false
  18.  
  19. -- setup constants for reference throughout code
  20. COIN_STYLE_MARIO = 1
  21. COIN_STYLE_TOAD = 2
  22. COIN_STYLE_OTHER = 3
  23.  
  24. ITEM_STYLE_DEFAULT = 1
  25.  
  26. PROCESS_COINS = 1
  27. PROCESS_ITEMS = 2
  28.  
  29. BB_ALIGNMENT_TOPLEFT = 0
  30. BB_ALIGNMENT_MIDDLE = 0.5
  31. BB_ALIGNMENT_BOTTMRIGHT = 1
  32.  
  33. function blockBuster.randomizeLinkCoins(table) -- function to randomize links coins
  34.     if table == nil then return end
  35.     local npcID = table[1]
  36.     if RNG.random() * 20 <= 3 then
  37.         npcID = table[2]
  38.     elseif RNG.random() * 60 <= 3 then
  39.         npcID = table[3]
  40.     end
  41.     return npcID
  42. end
  43.  
  44. local properties = {
  45.     defaults = {transforms = {transformID = 2, centred = false}, coins = {style = COIN_STYLE_MARIO, npc = 10, sound = 14, effect = 11}, items = {style = ITEM_STYLE_DEFAULT, sound = 7, direction = 0, usePlayerDirection = false, forcedState = 1, forcedState2 = 0, upperForcedState = 3, upperForcedStateState2 = 0, speedX = 0, speedY = 0, upperSpeedX = 0, upperSpeedY = 0, offsetX = 0, offsetY = 0, xAlign = BB_ALIGNMENT_MIDDLE, yAlign = BB_ALIGNMENT_TOPLEFT, upperOffsetX = 0, upperOffsetY = 4, upperXAlign = BB_ALIGNMENT_MIDDLE, upperYAlign = BB_ALIGNMENT_BOTTMRIGHT, ai = {}, upperAI = {}, despawnTimer = 1000}},
  46.     mario = {transforms = {}, coins = {style = COIN_STYLE_MARIO}, items = {progressivePowerups = true}},
  47.     luigi = {transforms = {}, coins = {style = COIN_STYLE_OTHER, coinClusterMax = 21, coinClusterNulls = true}, items = {progressivePowerups = true}},
  48.     peach = {transforms = {}, coins = {style = COIN_STYLE_MARIO}, items = {progressivePowerups = true, mountID = 35}},
  49.     toad = {transforms = {}, coins = {style = COIN_STYLE_TOAD, npc = 138, multiHitAmount = 3}, items = {progressivePowerups = true, mountID = 35}},
  50.     link = {transforms = {}, coins = {style = COIN_STYLE_OTHER, coinClusterMax = 6, coinClusterNulls = true, coinTable = {251, 252, 253}, sound = 81, coinFunc = blockBuster.randomizeLinkCoins}, items = {mushID = 250, coinID = 251, progressivePowerups = false}},
  51. }
  52.  
  53. local characterProperties = {}
  54.  
  55. local propertyPresets = { -- take this table...
  56.     mario = {CHARACTER_MARIO, CHARACTER_WARIO, CHARACTER_UNCLEBROADSWORD},
  57.     luigi = {CHARACTER_LUIGI, CHARACTER_BOWSER, CHARACTER_ZELDA},
  58.     peach = {CHARACTER_PEACH, CHARACTER_NINJABOMBERMAN, CHARACTER_ROSALINA},
  59.     toad = {CHARACTER_TOAD, CHARACTER_MEGAMAN, CHARACTER_KLONOA, CHARACTER_ULTIMATERINKA},
  60.     link = {CHARACTER_LINK, CHARACTER_SNAKE, CHARACTER_SAMUS}
  61. }
  62.  
  63. for  k,v in pairs(propertyPresets) do -- and copy the defaults to the appropriate character
  64.     for  _,v2 in ipairs(v)  do
  65.         characterProperties[v2] = table.join(characterProperties[v2]  or  {}, properties[k])
  66.     end
  67. end
  68.  
  69. local blockProperties = {
  70.     [55] = {transforms = {transformID = 55}}, -- redigit, why?
  71.     [60] = {transforms = {transformID = 192}, coins = {npc = 88}},
  72.     [88] = {transforms = {transformID = 89}, coins = {npc = 33}},
  73.     [89] = {transforms = {transformID = 89}, coins = {npc = 33}},
  74.     [90] = {transforms = {transformID = 89}, coins = {npc = 33}},
  75.     [159] = {transforms = {transformID = 159}}, -- again. redigit, why?
  76.     [171] = {transforms = {transformID = 89}, coins = {npc = 33}},
  77.     [174] = {transforms = {transformID = 89}, coins = {npc = 33}},
  78.     [177] = {transforms = {transformID = 89}, coins = {npc = 33}},
  79.     [180] = {transforms = {transformID = 89}, coins = {npc = 33}},
  80.     [188] = {transforms = {transformID = 192}, coins = {npc = 88}},
  81.     [192] = {transforms = {transformID = 192}, coins = {npc = 88}},
  82.     [193] = {transforms = {transformID = 192}, coins = {npc = 88}},
  83.     [224] = {transforms = {transformID = 225}},
  84.     [225] = {transforms = {transformID = 225}},
  85.     [226] = {transforms = {transformID = 225}},
  86.     [369] = {transforms = {transformID = 192}, coins = {npc = 88}},
  87. }
  88.  
  89. sourceNPCTimeOffScreen = mem(0x00B2C85A, FIELD_WORD)
  90.  
  91. local itemProperties = {
  92.     [9] = {items = {isMush = true}},
  93.     [10] = {items = {isCoin = true}},
  94.     [14] = {items = {isPowerup = true, mushID = 9}},
  95.     [33] = {items = {isCoin = true}},
  96.     [34] = {items = {forcedState = 0, speedY = -6, ai = {ai1 = 0}, offsetY = -32, isPowerup = true, mushID = 9}},
  97.     [88] = {items = {isCoin = true}},
  98.     [96] = {items = {forcedState = 0, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}}, -- egg handling
  99.     [98] = {items = {forcedState = 0, frame = 1, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  100.     [99] = {items = {forcedState = 0, frame = 2, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  101.     [100] = {items = {forcedState = 0, frame = 3, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  102.     [138] = {items = {isCoin = true}},
  103.     [148] = {items = {forcedState = 0, frame = 4, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  104.     [149] = {items = {forcedState = 0, frame = 5, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  105.     [150] = {items = {forcedState = 0, frame = 6, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  106.     [182] = {items = {isPowerup = true, mushID = 184}},
  107.     [183] = {items = {isPowerup = true, mushID = 185}},
  108.     [184] = {items = {isMush = true}},
  109.     [185] = {items = {isMush = true}},
  110.     [228] = {items = {forcedState = 0, frame = 7, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  111.     [249] = {items = {isMush = true}},
  112.     [258] = {items = {isCoin = true, altItemID = 252}},
  113.     [264] = {items = {isPowerup = true, mushID = 9}},
  114.     [277] = {items = {isPowerup = true, mushID = 185}},
  115. }
  116.  
  117. local blockBlacklist = {
  118.     [622] = true, -- character switches
  119.     [623] = true,
  120.     [624] = true,
  121.     [625] = true,
  122.     [639] = true,
  123.     [641] = true,
  124.     [643] = true,
  125.     [645] = true,
  126.     [647] = true,
  127.     [649] = true,
  128.     [651] = true,
  129.     [653] = true,
  130.     [655] = true,
  131.     [659] = true,
  132.     [663] = true,
  133.     [1279] = true, -- crash switches
  134.     [1281] = true,
  135. }
  136.  
  137. local BlocksToProcess = {}
  138.  
  139. function blockBuster.onInitAPI()
  140.     registerEvent(blockBuster, "onPostBlockHit", false)
  141.     registerEvent(blockBuster, "onTickEnd", false)
  142.     registerCustomEvent(blockBuster, "onCustomCoinEvent")
  143.     registerCustomEvent(blockBuster, "onCustomItemEvent")
  144.     registerCustomEvent(blockBuster, "onBlockProcess")
  145. end
  146.  
  147. function blockBuster.blacklistBlock(blockID, bool) -- set whether a block ID is blacklisted from the system
  148.     if blockBlacklist[blockID] == nil then
  149.         table.insert(blockBlacklist, blockID)
  150.     end
  151.     blockBlacklist[blockID] = bool
  152. end
  153.  
  154. function blockBuster.getItemProperties(npcID) -- get the properties for an item
  155.     return itemProperties[npcID]
  156. end
  157.  
  158. function blockBuster.getBlockProperties(blockID) -- get the properties for a block
  159.     return blockProperties[blockID]
  160. end
  161.  
  162. function blockBuster.getCharaterProperties(characterID) -- get the properties for a character
  163.     return characterProperties[characterID]
  164. end
  165.  
  166. function blockBuster.setItemProperties(npcID, properties) -- set the properties for an item
  167.     itemProperties[npcID] = table.join(itemProperties[npcID] or {}, properties) -- so ids without default tables work
  168.     for k,_ in pairs(properties) do -- then merge any that DO have default tables
  169.         itemProperties[npcID][k] = table.join(itemProperties[npcID][k] or {}, properties[k])
  170.         for k2,_ in pairs(properties[k])  do
  171.             itemProperties[npcID][k][k2] = properties[k][k2]
  172.         end
  173.     end
  174. end
  175.  
  176. function blockBuster.setBlockProperties(blockID, properties) -- set the properties for a block
  177.     blockProperties[blockID] = table.join(blockProperties[blockID] or {}, properties)
  178.     for k,_ in pairs(properties) do
  179.         blockProperties[blockID][k] = table.join(blockProperties[blockID][k] or {}, properties[k])
  180.         for k2,_ in pairs(properties[k])  do
  181.             blockProperties[blockID][k][k2] = properties[k][k2]
  182.         end
  183.     end
  184. end
  185.  
  186. function blockBuster.setCharacterProperties(characterID, properties) -- set the properties for a character
  187.     characterProperties[characterID] = table.join(characterProperties[characterID] or {}, properties)
  188.     for k,_ in pairs(properties) do
  189.         characterProperties[characterID][k] = table.join(characterProperties[characterID][k] or {}, properties[k])
  190.         for k2,_ in pairs(properties[k])  do
  191.             characterProperties[characterID][k][k2] = properties[k][k2]
  192.         end
  193.     end
  194. end
  195.  
  196. function blockBuster.decrementCoinContents(block) -- made solely to allow users easier access. decrements coins
  197.     block.data.BBTable.oldContents = block.data.BBTable.oldContents - 1
  198. end
  199.  
  200. function blockBuster.transformBlock(block, transformID, centred) -- handles block transforming
  201.     if block.data.BBTable.oldContents <= 0 then
  202.         block:transform(transformID, centred)
  203.     end
  204. end
  205.  
  206. function blockBuster.getContentsID(block) -- gets the proper npcID from the blocks contents
  207.     return block.data.BBTable.oldContents - 1000
  208. end
  209.  
  210. function blockBuster.setTrueContentsID(block) -- sets the contents back to the normal block contents system
  211.     if not (block.data.BBTable.oldContents > 1000) and block.data.BBTable.oldContents > 0 then -- shooould pervent rewritting data already formatted to the default contents ID range
  212.         block.data.BBTable.oldContents = block.data.BBTable.oldContents + 1000
  213.     end
  214. end
  215.  
  216. -- iBlocks (or interesting blocks/blocks of interest according to comments), blocks that are doing something interesting. messing with this so bumps hurt npcs. given to me by MDA
  217. local IBLOCK_COUNT = 0x00B25784 -- iBlocks in source. holds the total amount of iBlocks
  218. local IBLOCK_ADDR = mem(0x00B25798,FIELD_DWORD) -- iBlock in source. the array of iBlocks
  219.  
  220. local function setasIBlock(block) -- sets a block as an iBlock, basic stuff
  221.     mem(IBLOCK_COUNT,FIELD_WORD, mem(IBLOCK_COUNT,FIELD_WORD) + 1)
  222.     mem(IBLOCK_ADDR + mem(IBLOCK_COUNT,FIELD_WORD)*2,FIELD_WORD, block.idx)
  223. end
  224.  
  225. function blockBuster.setAsBlockToProcess(block) -- adds a block to the list that needs processing
  226.     table.insert(BlocksToProcess, block.idx)
  227. end
  228.  
  229. local function sourceShakeUp(block) -- clone of sources' BlockShakeUp https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L823
  230.     if not block.isHidden then
  231.         block:mem(0x52, FIELD_WORD, -blockBuster.bumpAmount)
  232.         block:mem(0x54, FIELD_WORD, blockBuster.bumpAmount)
  233.         block:mem(0x56, FIELD_WORD, 0)
  234.     end
  235.     if not (block.idx == mem(IBLOCK_ADDR + mem(IBLOCK_COUNT,FIELD_WORD)*2,FIELD_WORD)) then
  236.         setasIBlock(block)
  237.     end
  238. end
  239.  
  240. local function sourceShakeDown(block) -- clone of sources' BlockShakeDown https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L851
  241.     if not block.isHidden then
  242.         block:mem(0x52, FIELD_WORD, blockBuster.bumpAmount)
  243.         block:mem(0x54, FIELD_WORD, -blockBuster.bumpAmount)
  244.         block:mem(0x56, FIELD_WORD, 0)
  245.     end
  246.     if not (block.idx == mem(IBLOCK_ADDR + mem(IBLOCK_COUNT,FIELD_WORD)*2,FIELD_WORD)) then
  247.         setasIBlock(block)
  248.     end
  249. end
  250.  
  251. function blockBuster.resolveBumps(block, upper) -- performs the shake of the proper direction, as per this https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L101
  252.     if not upper then
  253.         sourceShakeUp(block)
  254.     else
  255.         sourceShakeDown(block)
  256.     end
  257. end
  258.  
  259. function blockBuster.resolveProperty(id, pl, type, table, field) -- returns the value of the supplied to the field arguement, based on the table arguement supplied
  260.     local key
  261.     local pTable = type
  262.     if (pl ~= nil and characterProperties[pl.character] ~= nil and characterProperties[pl.character][table] ~= nil and characterProperties[pl.character][table][field] ~= nil)then
  263.         key = characterProperties[pl.character][table][field]
  264.     end
  265.     if (pTable[id] ~= nil and pTable[id][table] ~= nil and pTable[id][table][field] ~= nil) then
  266.         key = pTable[id][table][field]
  267.     end
  268.     if key == nil then
  269.         key = properties.defaults[table][field]
  270.     end
  271.     return key
  272. end
  273.  
  274. function blockBuster.defaultCoinAction(block, soundID, transformID, centred, effectID) -- the default 1.3 coins stuff remade in lua. taken from various parts of modBlock.bas
  275.     Misc.coins(1,false)
  276.     if blockBuster.playSounds then
  277.         SFX.play(soundID or properties.defaults.coins.sound)
  278.     end
  279.     if not (effectID == nil or effectID == 0) then
  280.         Effect.spawn(effectID, block.x + block.width*0.5, block.y)
  281.     end
  282.     blockBuster.decrementCoinContents(block)
  283.     blockBuster.transformBlock(block, transformID, centred)
  284. end
  285.  
  286. function blockBuster.doMultiSetup(block, pl) -- setup blocks to be RapidHit (name from source), toad style. may allow items to use this, not sure yet
  287.     local multihit = blockBuster.resolveProperty(block.id, pl, blockProperties, "coins", "multiHitAmount") -- amount of times RapidHit is applied
  288.     block.data.BBTable.oldMulti = math.floor(RNG.random() * multihit) + 1
  289.     block.data.BBTable.isMulti = true
  290.     block.data.BBTable.player = pl
  291.     block:mem(0x04, FIELD_WORD, block.data.BBTable.oldMulti)
  292. end
  293.  
  294. function blockBuster.checkCollisionUp(block) -- based on https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L194
  295.     for _,v in ipairs(Block.getIntersecting(block.x + 1, block.y - 31, (block.x + 1) + 30, (block.y - 31) + 30)) do
  296.         if v and not (v == block) and not Block.config[v.id].semisolid and not v.isHidden and not Block.config[v.id].sizable then
  297.             return true
  298.         end
  299.     end
  300. end
  301.  
  302. function blockBuster.checkCollisionDown(block) -- vaugely based on https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L79
  303.     for _,v in ipairs(Block.getIntersecting(block.x, block.y + block.height, block.x + block.width, (block.y + block.height) + 17)) do
  304.         if v and not (v == block) then
  305.             return true
  306.         end
  307.     end
  308. end
  309.  
  310. function blockBuster.spawnCoin(block, upper, pl, npcID) -- the default coin spawning stuff roughly translated to lua https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L200
  311.     local spawnLayer = blockBuster.resolveProperty(block.id, pl, blockProperties, "coins", "spawnLayer") -- layer the coins are put on upon spawning
  312.     local s = NPC.spawn(npcID, block.x + (block.width*0.5) - (NPC.config[npcID].width*0.5), block.y-NPC.config[npcID].height - 0.01, blockutils.getBlockSection(block), false, false)
  313.     if spawnLayer then
  314.         s.layerName = spawnLayer
  315.     end
  316.     s.ai1 = 1
  317.     s.speedX = RNG.random() * 3 - 1.5
  318.     s.speedY = -RNG.random() * 4 - 3
  319.     if upper then
  320.         s.speedY = -s.speedY * 0.5
  321.         s.y = block.y+block.height
  322.     end
  323.     s:mem(0x156, FIELD_WORD, 20) -- timer to make npcs immune to harm. makes it so iBlocks don't collect them instantly
  324. end
  325.  
  326.  
  327. function blockBuster.filterPowerups(npcID, pl) -- approximation of powerup handling for source https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L345
  328.     local mushID = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "mushID") -- id of the mushroom to turn into
  329.     local isPowerup = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "isPowerup") -- if the item is a powerup
  330.     local progressivePowerups = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "progressivePowerups") -- if the character or block should do progressive powerups
  331.     local mushroom = false
  332.     if pl and pl.powerup == PLAYER_SMALL and not mem(0x00B2D740, FIELD_BOOL) and progressivePowerups then mushroom = true end --0x00B2D740: battle mode bool address
  333.     if (isPowerup and mushID and mushroom) then
  334.         npcID = mushID
  335.     end
  336.     return npcID
  337. end
  338.  
  339. function blockBuster.filterCharacterItems(npcID, ai1, pl) -- approximation of CharStuff for source https://github.com/smbx/smbx-legacy-source/blob/master/modNPC.bas#L12271
  340.     local mushID = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "mushID") -- id of the mushroom to turn into
  341.     local isMush = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "isMush") -- if the item is a mushroom it's self
  342.     local isEgg = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "isEgg")  -- if the item should be an egg on spawn
  343.     local mountID = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "mountID") -- id of mount to turn into if not yoshi
  344.     local isCoin = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "isCoin") -- if the item is a coin
  345.     local coinID = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "coinID") -- the id of the coin to turn into
  346.     local altItemID = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "altItemID") -- the id of the item to turn into if being transformed
  347.  
  348.     if isMush then
  349.         if mushID then
  350.             npcID = mushID
  351.         end
  352.     end
  353.     if isEgg then
  354.         local altItemID = blockBuster.resolveProperty(ai1, pl, itemProperties, "items", "altItemID")
  355.        
  356.         if mountID then
  357.             -- ai1 = mountID this is overridden by 1.3 on npc creation/transformation anyways. it makes eggs not keep their frames either
  358.             if altItemID then
  359.                 ai1 = altItemID
  360.             end
  361.         end
  362.     end
  363.     if isCoin then
  364.         if coinID then
  365.             npcID = coinID
  366.             if altItemID then
  367.                 npcID = altItemID
  368.             end
  369.         end
  370.     end
  371.     return npcID, ai1
  372. end
  373.  
  374. function blockBuster.spawnItem(block, upper, pl, npcID) -- this looks familiar lol. loosely based around this https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L400
  375.     local blockTransformID = blockBuster.resolveProperty(block.id, pl, blockProperties, "transforms", "transformID") -- ID of block to transform. used here for positioning only
  376.     local forced = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "forcedState") -- the state/"effect" the npc is under upon spawning
  377.     local forced2 = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "forcedState2") -- npc dependant timer for the forced state
  378.     local direction = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "direction") -- npc direction on spawn
  379.     local usePlayerDirection = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "usePlayerDirection") -- whether the npc uses the players direction or behaves according to source (oppisite of the players direction)
  380.     local speedX = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "speedX") -- horizontal speed upon spawning
  381.     local speedY = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "speedY") -- vertical speed upon spawning
  382.     local offsetX = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "offsetX") -- horizontal offset of the item from the items' alignment
  383.     local offsetY = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "offsetY") -- vertical offset of the item from the items' alignment
  384.     local xAlign = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "xAlign") -- items' horizontal alignment from the block
  385.     local yAlign = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "yAlign") -- items' vertical alignment from the block
  386.     local ai = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "ai") -- items' AI table upon spawn
  387.     local data = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "data") -- items' data table upon spawn
  388.     local despawnTimer = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "despawnTimer") -- items' despawn timer upon spawn
  389.     local isEgg = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "isEgg") -- if the item should spawn in an egg
  390.     local frame = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "frame") -- frame of the item upon spawning. only used by eggs in source?
  391.     local immunity = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "immunity") -- immunity frames upon spawn. used to keep things from being instant harmed when spawned.
  392.     local upperOffsetX = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperOffsetX") -- same as offsetX, used for being hit from above
  393.     local upperOffsetY = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperOffsetY") -- same as offsetY, used for being hit from above
  394.     local upperXAlign = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperXAlign") -- same as xAlign, used for being hit from above
  395.     local upperYAlign = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperYAlign") -- same as YAlign, used for being hit from above
  396.     local upperSpeedX = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperSpeedX") -- same as speedX, used for being hit from above
  397.     local upperSpeedY = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperSpeedY") -- same as speedY, used for being hit from above
  398.     local upperAI = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperAI") -- same as ai, used for being hit from above
  399.     local upperData = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperData") -- same as data, used for being hit from above
  400.     local upperForced = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperForcedState") -- same as forcedState, used for being hit from above
  401.     local upperForced2 = blockBuster.resolveProperty(npcID, pl, itemProperties, "items", "upperForcedState2") -- same as forcedState2, used for being hit from above
  402.    
  403.     local tempWidth = Block.config[blockTransformID].width
  404.     local tempX = block.x
  405.     if tempWidth == 32 then
  406.         tempWidth = Block.config[blockTransformID].width - 0.1
  407.         tempX = block.x - 0.05
  408.     end
  409.     if upper then
  410.         xAlign = upperXAlign
  411.         yAlign = upperYAlign
  412.         offsetX = upperOffsetX
  413.         offsetY = upperOffsetY
  414.         speedX = upperSpeedX
  415.         speedY = upperSpeedY
  416.         ai = upperAI
  417.         data = upperData
  418.         forced = upperForced
  419.         forced2 = upperForcedState2
  420.     end
  421.     if isEgg then -- if it's meant to be in an egg, put it in one
  422.         ai.ai1 = npcID
  423.         npcID = 96
  424.     end
  425.     npcID = blockBuster.filterPowerups(npcID, pl) -- makes fire flowers, leafs, ect. into mushrooms when needed
  426.     npcID, ai.ai1 = blockBuster.filterCharacterItems(npcID, ai.ai1, pl) -- does character specific things with items like yoshi's to boots or coins to rupees
  427.     local s = NPC.spawn(npcID, tempX + (tempWidth*xAlign) - (NPC.config[npcID].width*xAlign) + offsetX, block.y + (Block.config[blockTransformID].height*yAlign) - (NPC.config[npcID].height*yAlign) + offsetY, blockutils.getBlockSection(block), false, false)
  428.     if spawnLayer then
  429.         s.layerName = spawnLayer
  430.     end
  431.     if frame then
  432.         s.animationFrame = frame
  433.     end
  434.     if data ~= nil then -- append data to the item's data table
  435.         for  k,_ in pairs(data) do
  436.             if not (s.data[k] == data[k]) then
  437.                 s.data[k] = data[k]
  438.             end
  439.         end
  440.     end
  441.     if ai ~= nil then -- set an item's ai# fields
  442.         for  k,_ in pairs(ai) do
  443.             if not (s[k] == ai[k]) then
  444.                 s[k] = ai[k]
  445.             end
  446.         end
  447.     end
  448.     s:mem(0x124, FIELD_BOOL, true) -- active flag
  449.     if despawnTimer then
  450.         s.despawnTimer = despawnTimer
  451.     end
  452.     if direction and usePlayerDirection ~= nil and not usePlayerDirection then -- set direction to either a defined one or the player, as per properties set. uses -player.direction if 0 https://github.com/smbx/smbx-legacy-source/blob/master/modNPC.bas#L3486
  453.         s.direction = direction
  454.     elseif usePlayerDirection ~= nil and usePlayerDirection then
  455.         s.direction = pl.direction
  456.     end
  457.     if forced then
  458.         s:mem(0x138, FIELD_WORD, forced) -- forced state/effect
  459.     end
  460.     if forced2 then
  461.         s:mem(0x13C, FIELD_DFLOAT, forced2) -- a forced state timer/effect2
  462.     end
  463.     s.speedY = speedY
  464.     s.speedX = speedX
  465.     if forced == 1 then
  466.         s.height = 0
  467.     end
  468.     if immunity then
  469.         s:mem(0x156, FIELD_WORD, immunity) -- immune timer
  470.     end
  471.     return s
  472. end
  473.  
  474. function blockBuster.onPostBlockHit(v, upper, pl)
  475.     if not blockBuster.enabled then return end
  476.     if blockBlacklist[v.id] then return end -- make it so the lib doesn't work for blacklisted blocks
  477.  
  478.     if v:mem(0x52, FIELD_WORD) ~= 0 or v:mem(0x54, FIELD_WORD) ~= 0 or v:mem(0x56, FIELD_WORD) ~= 0 then return end -- "if the block has just been hit, ignore" comment from source https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L68
  479.  
  480.     v.data.BBTable = v.data.BBTable or {}
  481.     local data = v.data.BBTable
  482.    
  483.     if not (v.contentID == 0) then
  484.         if mem(0x00B2D740, FIELD_BOOL) and v:mem(0x02, FIELD_WORD) == 0 then --because why not at this point, yeah? https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L15
  485.             v:mem(0x02, FIELD_WORD, 1)
  486.         end
  487.         v:mem(0x5A , FIELD_BOOL, false) -- allows invisible blocks to work properly with blockBuster
  488.         data.oldContents = v.contentID -- save block contents
  489.         data.oldMulti = v:mem(0x04, FIELD_WORD) -- save the multihit
  490.         v.contentID = 0 -- void contents
  491.         v:mem(0x04, FIELD_WORD, 0) -- void multihit
  492.         blockBuster.setAsBlockToProcess(v) -- set the block to be processed in onTickEnd
  493.     end
  494.  
  495.     if pl == nil then
  496.         if data.player and not (pl == data.player) then -- should make RapidHit work with character configs
  497.             pl = data.player
  498.         end
  499.         if blockBuster.npcOwnersToBlocks then -- allow transferring this system from thrown npcs
  500.             for _,n in ipairs(NPC.getIntersecting(v.x-1,v.y-1,v.x+v.width+1,v.y+v.height+1)) do
  501.                 if n:mem(0x132,FIELD_WORD) > 0 and n:mem(0x136,FIELD_BOOL) and pl == nil then
  502.                     pl = Player.get()[n:mem(0x132,FIELD_WORD)]
  503.                 end
  504.             end
  505.         end
  506.     end
  507.  
  508.     if upper and data.oldContents then
  509.         upper = not blockBuster.checkCollisionDown(v)
  510.     end
  511.    
  512.     if data.oldContents and data.oldContents > 0 and data.oldContents < 100 then -- coin handling. loosely based on this https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L183
  513.         data.process = PROCESS_COINS -- mark for coin processing
  514.         local coinStyle = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "style") -- style used by the block/player
  515.         local multiHitTimes = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "multiHitAmount") -- mutihit amount as per block/player settings
  516.         local npcSpawnID = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "npc") -- coin npc spawned per-block/player
  517.         local coinSoundID = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "sound") -- sound played upon hitting the block
  518.         local blockTransformID = blockBuster.resolveProperty(v.id, pl, blockProperties, "transforms", "transformID") -- what the block transforms into upon being depleted or voided
  519.         local centred = blockBuster.resolveProperty(v.id, pl, blockProperties, "transforms", "centred") -- bool for if the transformation is centred on the blocks' location or at the blocks' cords as per source
  520.         local effectID = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "effect") -- effect spawned for default coins actions as per block/player settings
  521.         local coinFunction = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "coinFunc") -- function ran for COIN_STYLE_OTHER characters
  522.         local coinClusterMax = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "coinClusterMax") -- max amount of coins for COIN_STYLE_OTHER characters
  523.         local coinClusterNulls = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "coinClusterNulls") -- if COIN_STYLE_OTHER characters void block contents upon hit, regardless if there's more coins
  524.         local coinTable = blockBuster.resolveProperty(v.id, pl, blockProperties, "coins", "coinTable") -- table containing coin variants. currently only used by link characters
  525.  
  526.         if not (multiHitTimes == nil) and multiHitTimes > 0 then
  527.             if v:mem(0x04, FIELD_WORD) == 0 and not data.isMulti then
  528.                 blockBuster.doMultiSetup(v, pl)
  529.             else
  530.                 data.oldMulti = data.oldMulti - 1
  531.             end
  532.         elseif not multiHitTimes and not data.isMulti then
  533.             data.oldMulti = 0 -- pervent vanilla multihitting
  534.         end
  535.  
  536.         if blockBuster.useCustomCoinHandling then -- allow making one's own coin code
  537.             return EventManager.callEvent("onCustomCoinEvent", v, upper, pl, data)
  538.         end
  539.  
  540.         if coinStyle == COIN_STYLE_MARIO then -- covers mario and peachs' coin styles
  541.             blockBuster.defaultCoinAction(v, coinSoundID, blockTransformID, centred, effectID)
  542.             blockBuster.resolveBumps(v, upper)
  543.         elseif coinStyle == COIN_STYLE_TOAD then -- covers toads' coin style
  544.             if not blockBuster.checkCollisionUp(v) then
  545.                 blockBuster.spawnCoin(v, upper, pl, npcSpawnID)
  546.                 if blockBuster.playSounds then
  547.                     SFX.play(coinSoundID)
  548.                 end
  549.                 blockBuster.decrementCoinContents(v)
  550.                 blockBuster.transformBlock(v, blockTransformID, centred)
  551.             else
  552.                 blockBuster.defaultCoinAction(v, coinSoundID, blockTransformID, centred, effectID)
  553.             end
  554.             blockBuster.resolveBumps(v, upper)
  555.         elseif coinStyle == COIN_STYLE_OTHER then -- covers luigi and links' coin styles
  556.             if not blockBuster.checkCollisionUp(v) then
  557.                 local max = 0
  558.                 if data.oldContents < coinClusterMax then
  559.                     max = data.oldContents
  560.                 else
  561.                     max = coinClusterMax --characterProperties[pl.character].coins.coinClusterMax
  562.                 end
  563.                 for i=1, max do
  564.                     local tempCoinID = npcSpawnID
  565.                     if coinFunction then
  566.                         tempCoinID = coinFunction(coinTable)
  567.                     end
  568.                     blockBuster.spawnCoin(v, upper, pl, tempCoinID)
  569.                     if not coinClusterNulls then
  570.                         blockBuster.decrementCoinContents(v)
  571.                     end
  572.                 end
  573.                 if blockBuster.playSounds then
  574.                     SFX.play(coinSoundID)
  575.                 end
  576.                 if coinClusterNulls then
  577.                     data.oldContents = 0
  578.                 end
  579.                 blockBuster.transformBlock(v, blockTransformID, centred)
  580.             else
  581.                 blockBuster.defaultCoinAction(v, nil, blockTransformID, centred, effectID)
  582.             end
  583.             blockBuster.resolveBumps(v, upper)
  584.         end
  585.     end
  586.  
  587.     if data.oldContents and data.oldContents >= 1000 then -- npc/item handling
  588.         data.process = PROCESS_ITEMS -- mark for item processing
  589.         local itemStyle = blockBuster.resolveProperty(v.id, pl, blockProperties, "items", "style") -- style used for items. currently there is only one
  590.         local blockTransformID = blockBuster.resolveProperty(v.id, pl, blockProperties, "transforms", "transformID") -- what the block transforms into upon being depleted or voided
  591.         local centred = blockBuster.resolveProperty(v.id, pl, blockProperties, "transforms", "centred") -- bool for if the transformation is centred on the blocks' location or at the blocks' cords as per source
  592.         local itemSoundID = blockBuster.resolveProperty(v.id, pl, blockProperties, "items", "sound") -- sound played upon hitting the block
  593.  
  594.         if blockBuster.useCustomItemHandling then -- allow making one's own item code
  595.             return EventManager.callEvent("onCustomItemEvent", v, upper, pl, data)
  596.         end
  597.  
  598.         if itemStyle == ITEM_STYLE_DEFAULT then
  599.             npcSpawnID = blockBuster.getContentsID(v)
  600.             blockBuster.spawnItem(v, upper, pl, npcSpawnID)
  601.             data.oldContents = 0
  602.             if blockBuster.playSounds then
  603.                 SFX.play(itemSoundID)
  604.             end
  605.             blockBuster.transformBlock(v, blockTransformID, centred)
  606.             blockBuster.resolveBumps(v, upper)
  607.         end
  608.     end
  609. end
  610.  
  611. function blockBuster.onTickEnd()
  612.     if not blockBuster.enabled and #BlocksToProcess == 0 then return end
  613.     for k,v in ipairs(BlocksToProcess) do
  614.         local block = Block(v)
  615.         local data = block.data.BBTable
  616.         EventManager.callEvent("onBlockProcess", block) -- allows custom handling to do things for clean up in necessary
  617.         if data.process == PROCESS_COINS then
  618.             block.contentID = data.oldContents -- restore old contents so coins work
  619.             data.oldContents = nil
  620.         elseif data.process == PROCESS_ITEMS then
  621.             blockBuster.setTrueContentsID(block)
  622.             block.contentID = data.oldContents -- restore old contents incase we ever add multiple items per block ever
  623.             data.oldContents = nil
  624.         end
  625.         block:mem(0x04, FIELD_WORD, data.oldMulti)
  626.         data.oldMulti = nil
  627.         data.process = nil -- reset process incase we're multihitting
  628.         if block:mem(0x04, FIELD_WORD) <= 0 then -- only get rid of other feilds if not using them for multihitting
  629.             data.player = nil
  630.             data.isMulti = nil
  631.             block:mem(0x04, FIELD_WORD, 0)
  632.         end
  633.         table.remove(BlocksToProcess, k)
  634.     end
  635. end
  636.  
  637. blockBuster.properties = properties
  638. blockBuster.properties.blockProperties = blockProperties
  639. blockBuster.properties.itemProperties = itemProperties
  640. blockBuster.properties.characterProperties = characterProperties
  641.  
  642. return blockBuster
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement