KBM-Quine

blockBuster.lua

Nov 11th, 2021 (edited)
128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 26.76 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.  
  17. -- setup constants for reference throughout code
  18. COIN_STYLE_MARIO = 1
  19. COIN_STYLE_TOAD = 2
  20. COIN_STYLE_OTHER = 3
  21. COIN_STYLE_CUSTOM = 4
  22.  
  23. ITEM_STYLE_DEFAULT = 1
  24. ITEM_STYLE_CUSTOM = 2
  25.  
  26. function blockBuster.randLinkCoins(table)
  27.     if table == nil then return end
  28.     local npcID = table[1]
  29.     if RNG.random() * 20 <= 3 then
  30.         npcID = table[2]
  31.     elseif RNG.random() * 60 <= 3 then
  32.         npcID = table[3]
  33.     end
  34.     return npcID
  35. end
  36.  
  37. local properties = {
  38.     defaults = {transforms = {transformID = 2, centred = false}, coins = {style = COIN_STYLE_MARIO, npc = 10, sound = 14, effect = 11}, items = {style = ITEM_STYLE_DEFAULT, direction = 0, usePlrDir = false, forcedState = 1, forcedState2 = 0, upperForcedState = 3, upperForcedStateState2 = 0, speedX = 0, speedY = 0, upperSpeedX = 0, upperSpeedY = 0, offsetX = 0, offsetY = 0, upperOffsetX = 0, upperOffsetY = 4, ai = {}, upperAI = {}, despawnTimer = 1000}},
  39.     mario = {transforms = {}, coins = {style = COIN_STYLE_MARIO}, items = {progressivePowerups = true}},
  40.     luigi = {transforms = {}, coins = {style = COIN_STYLE_OTHER, coinClusterMax = 21, coinClusterNulls = true}, items = {progressivePowerups = true}},
  41.     peach = {transforms = {}, coins = {style = COIN_STYLE_MARIO}, items = {progressivePowerups = true, mountID = 35}},
  42.     toad = {transforms = {}, coins = {style = COIN_STYLE_TOAD, npc = 138, multiHitAmount = 3}, items = {progressivePowerups = true, mountID = 35}},
  43.     link = {transforms = {}, coins = {style = COIN_STYLE_OTHER, coinClusterMax = 6, coinClusterNulls = true, npc = {251, 252, 253}, sound = 81, coinFunc = blockBuster.randLinkCoins}, items = {mushID = 250, coinID = 251, progressivePowerups = false}},
  44. }
  45.  
  46. local characterProperties = {}
  47.  
  48. local propertyPresets = { -- take this table...
  49.     mario = {CHARACTER_MARIO, CHARACTER_WARIO, CHARACTER_UNCLEBROADSWORD},
  50.     luigi = {CHARACTER_LUIGI, CHARACTER_BOWSER, CHARACTER_ZELDA},
  51.     peach = {CHARACTER_PEACH, CHARACTER_NINJABOMBERMAN, CHARACTER_ROSALINA},
  52.     toad = {CHARACTER_TOAD, CHARACTER_MEGAMAN, CHARACTER_KLONOA, CHARACTER_ULTIMATERINKA},
  53.     link = {CHARACTER_LINK, CHARACTER_SNAKE, CHARACTER_SAMUS}
  54. }
  55.  
  56. for  k,v in pairs(propertyPresets) do -- and copy the defaults to the appropriate character
  57.     for  _,v2 in ipairs(v)  do
  58.         characterProperties[v2] = table.join(characterProperties[v2]  or  {}, properties[k])
  59.     end
  60. end
  61.  
  62. local blockProperties = {
  63.     [55] = {transforms = {transformID = 55}},
  64.     [60] = {transforms = {transformID = 192}, coins = {npc = 88}},
  65.     [88] = {transforms = {transformID = 89}, coins = {npc = 33}},
  66.     [89] = {transforms = {transformID = 89}, coins = {npc = 33}},
  67.     [90] = {transforms = {transformID = 89}, coins = {npc = 33}},
  68.     [159] = {transforms = {transformID = 159}},
  69.     [171] = {transforms = {transformID = 89}, coins = {npc = 33}},
  70.     [174] = {transforms = {transformID = 89}, coins = {npc = 33}},
  71.     [177] = {transforms = {transformID = 89}, coins = {npc = 33}},
  72.     [180] = {transforms = {transformID = 89}, coins = {npc = 33}},
  73.     [188] = {transforms = {transformID = 192}, coins = {npc = 88}},
  74.     [192] = {transforms = {transformID = 192}, coins = {npc = 88}},
  75.     [193] = {transforms = {transformID = 192}, coins = {npc = 88}},
  76.     [224] = {transforms = {transformID = 225}},
  77.     [225] = {transforms = {transformID = 225}},
  78.     [226] = {transforms = {transformID = 225}},
  79.     [369] = {transforms = {transformID = 192}, coins = {npc = 88}},
  80. }
  81.  
  82. sourceNPCTimeOffScreen = mem(0x00B2C85A, FIELD_WORD)
  83.  
  84. local itemProperties = {
  85.     [9] = {items = {isMush = true}},
  86.     [10] = {items = {isCoin = true}},
  87.     [14] = {items = {isPowerup = true, mushID = 9}},
  88.     [33] = {items = {isCoin = true}},
  89.     [34] = {items = {forcedState = 0, speedY = -6, ai = {ai1 = 0}, offsetY = -32, isPowerup = true, mushID = 9}},
  90.     [88] = {items = {isCoin = true}},
  91.     [96] = {items = {forcedState = 0, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  92.     [98] = {items = {forcedState = 0, frame = 1, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  93.     [99] = {items = {forcedState = 0, frame = 2, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  94.     [100] = {items = {forcedState = 0, frame = 3, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  95.     [138] = {items = {isCoin = true}},
  96.     [148] = {items = {forcedState = 0, frame = 4, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  97.     [149] = {items = {forcedState = 0, frame = 5, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  98.     [150] = {items = {forcedState = 0, frame = 6, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  99.     [182] = {items = {isPowerup = true, mushID = 184}},
  100.     [183] = {items = {isPowerup = true, mushID = 185}},
  101.     [184] = {items = {isMush = true}},
  102.     [185] = {items = {isMush = true}},
  103.     [228] = {items = {forcedState = 0, frame = 7, despawnTimer = sourceNPCTimeOffScreen*20, offsetY = -32, isEgg = true}},
  104.     [249] = {items = {isMush = true}},
  105.     [258] = {items = {isCoin = true, altID = 252}},
  106.     [264] = {items = {isPowerup = true, mushID = 9}},
  107.     [277] = {items = {isPowerup = true, mushID = 185}},
  108. }
  109.  
  110. local BlocksToProcess = {}
  111.  
  112. function blockBuster.onInitAPI()
  113.     registerEvent(blockBuster, "onPostBlockHit", false)
  114.     registerEvent(blockBuster, "onTickEnd", false)
  115.     registerCustomEvent(blockBuster, "onCustomCoinEvent")
  116.     registerCustomEvent(blockBuster, "onCustomItemEvent")
  117. end
  118.  
  119. -- not very user friendly to new coders, but might uncomment? don't know (old, may not work now)
  120. -- function blockBuster.getProperties(args)
  121. --     return args.type[args.table or args.ID]
  122. -- end
  123.  
  124. -- function blockBuster.setProperties(args)
  125. --     local pTable = args.type
  126.  
  127. --     pTable[args.ID] = table.join(pTable[args.ID] or {}, args.properties)
  128. --     for  k,_ in pairs(args.properties) do
  129. --         if not (pTable[args.ID][k] == args.properties[k]) then
  130. --             pTable[args.ID][k] = args.properties[k]
  131. --         end
  132. --     end
  133. -- end
  134.  
  135. function blockBuster.getItemProperties(npcID)
  136.     return itemProperties[npcID]
  137. end
  138.  
  139. function blockBuster.getBlockProperties(blockID)
  140.     return blockProperties[blockID]
  141. end
  142.  
  143. function blockBuster.getCharaterProperties(characterID)
  144.     return characterProperties[characterID]
  145. end
  146.  
  147. function blockBuster.setItemProperties(npcID, properties)
  148.     itemProperties[npcID] = table.join(itemProperties[npcID] or {}, properties) -- so ids without default tables work
  149.     for k,_ in pairs(properties) do -- then merge any that DO have default tables
  150.         itemProperties[npcID][k] = table.join(itemProperties[npcID][k] or {}, properties[k])
  151.         for k2,_ in pairs(properties[k])  do
  152.             itemProperties[npcID][k][k2] = properties[k][k2]
  153.         end
  154.     end
  155. end
  156.  
  157. function blockBuster.setBlockProperties(blockID, properties)
  158.     blockProperties[blockID] = table.join(blockProperties[blockID] or {}, properties)
  159.     for k,_ in pairs(properties) do
  160.         blockProperties[blockID][k] = table.join(blockProperties[blockID][k] or {}, properties[k])
  161.         for k2,_ in pairs(properties[k])  do
  162.             blockProperties[blockID][k][k2] = properties[k][k2]
  163.         end
  164.     end
  165. end
  166.  
  167. function blockBuster.setCharacterProperties(characterID, properties)
  168.     characterProperties[characterID] = table.join(characterProperties[characterID] or {}, properties)
  169.     for k,_ in pairs(properties) do
  170.         characterProperties[characterID][k] = table.join(characterProperties[characterID][k] or {}, properties[k])
  171.         for k2,_ in pairs(properties[k])  do
  172.             characterProperties[characterID][k][k2] = properties[k][k2]
  173.         end
  174.     end
  175. end
  176.  
  177. function blockBuster.decrementCoinContents(block)
  178.     block.data.BBTable.oldContents = block.data.BBTable.oldContents - 1
  179. end
  180.  
  181. function blockBuster.transformBlock(block, transformID, centred)
  182.     if block.data.BBTable.oldContents <= 0 then
  183.         block:transform(transformID, centred)
  184.     end
  185. end
  186.  
  187. -- 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
  188. local IBLOCK_COUNT = 0x00B25784 -- iBlocks in source. holds the total amount of iBlocks
  189. local IBLOCK_ADDR = mem(0x00B25798,FIELD_DWORD) -- iBlock in source. the array of iBlocks
  190.  
  191. local function setasIBlock(block) -- sets a block as an iBlock, basic stuff
  192.     mem(IBLOCK_COUNT,FIELD_WORD, mem(IBLOCK_COUNT,FIELD_WORD) + 1)
  193.     mem(IBLOCK_ADDR + mem(IBLOCK_COUNT,FIELD_WORD)*2,FIELD_WORD, block.idx)
  194. end
  195.  
  196. local function sourceShakeUp(block) -- clone of sources' BlockShakeUp https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L823
  197.     if not block.isHidden then
  198.         block:mem(0x52, FIELD_WORD, -blockBuster.bumpAmount)
  199.         block:mem(0x54, FIELD_WORD, blockBuster.bumpAmount)
  200.         block:mem(0x56, FIELD_WORD, 0)
  201.     end
  202.     if not (block.idx == mem(IBLOCK_ADDR + mem(IBLOCK_COUNT,FIELD_WORD)*2,FIELD_WORD)) then
  203.         setasIBlock(block)
  204.     end
  205. end
  206.  
  207. local function sourceShakeDown(block) -- ditto for BlockShakeDown https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L851
  208.     if not block.isHidden then
  209.         block:mem(0x52, FIELD_WORD, blockBuster.bumpAmount)
  210.         block:mem(0x54, FIELD_WORD, -blockBuster.bumpAmount)
  211.         block:mem(0x56, FIELD_WORD, 0)
  212.     end
  213.     if not (block.idx == mem(IBLOCK_ADDR + mem(IBLOCK_COUNT,FIELD_WORD)*2,FIELD_WORD)) then
  214.         setasIBlock(block)
  215.     end
  216. end
  217.  
  218. function blockBuster.resolveBumps(block, upper)
  219.     if not upper then
  220.         sourceShakeUp(block)
  221.     else
  222.         sourceShakeDown(block)
  223.     end
  224. end
  225.  
  226. function blockBuster.resolveProperties(id, pl, type, table, field)
  227.     local key
  228.     local pTable = type
  229.     if (pTable[id] ~= nil and pTable[id][table] ~= nil and pTable[id][table][field] ~= nil) then
  230.         key = pTable[id][table][field]
  231.     else
  232.         key = properties.defaults[table][field]
  233.     end
  234.     if (pl ~= nil and characterProperties[pl.character] ~= nil and characterProperties[pl.character][table] ~= nil and characterProperties[pl.character][table][field] ~= nil)then
  235.         key = characterProperties[pl.character][table][field]
  236.     end
  237.     return key
  238. end
  239.  
  240. function blockBuster.defaultCoinAction(block, soundID, transformID, centred, effectID)
  241.     Misc.coins(1,false)
  242.     if blockBuster.playSounds then
  243.         SFX.play(soundID or properties.defaults.coins.sound)
  244.     end
  245.     if not (effectID == nil or effectID == 0) then
  246.         Effect.spawn(effectID, block.x + block.width*0.5, block.y)
  247.     end
  248.     blockBuster.decrementCoinContents(block)
  249.     blockBuster.transformBlock(block, transformID, centred)
  250. end
  251.  
  252. function blockBuster.doMultiSetup(block, pl) -- setup blocks to be RapidHit (name from source), toad style. may allow items to use this, not sure yet
  253.     local multihit = blockBuster.resolveProperties(block.id, pl, blockProperties, "coins", "multiHitAmount")
  254.     block.data.BBTable.oldMulti = math.floor(RNG.random() * multihit) + 1
  255.     block.data.BBTable.isMulti = true
  256.     block.data.BBTable.player = pl
  257.     block:mem(0x04, FIELD_WORD, block.data.BBTable.oldMulti)
  258. end
  259.  
  260. function blockBuster.checkCollisionUp(block) -- based on https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L194
  261.     for _,v in ipairs(Block.getIntersecting(block.x + 1, block.y - 31, (block.x + 1) + 30, (block.y - 31) + 30)) do
  262.         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
  263.             return true
  264.         end
  265.     end
  266. end
  267.  
  268. function blockBuster.checkCollisionDown(block) -- vaugely based on https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L79
  269.     for _,v in ipairs(Block.getIntersecting(block.x, block.y + block.height, block.x + block.width, (block.y + block.height) + 17)) do
  270.         if v and not (v == block) then
  271.             return true
  272.         end
  273.     end
  274. end
  275.  
  276. function blockBuster.spawnCoin(block, upper, pl, npcID)
  277.     local spawnLayer = blockBuster.resolveProperties(block.id, pl, blockProperties, "coins", "spawnLayer")
  278.     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)
  279.     if spawnLayer then
  280.         s.layerName = spawnLayer
  281.     end
  282.     s.ai1 = 1
  283.     s.speedX = RNG.random() * 3 - 1.5
  284.     s.speedY = -RNG.random() * 4 - 3
  285.     if upper then
  286.         s.speedY = -s.speedY * 0.5
  287.         s.y = block.y+block.height
  288.     end
  289.     s:mem(0x156, FIELD_WORD, 20) -- timer to make npcs immune to harm. makes it so iBlocks don't collect them instantly
  290. end
  291.  
  292.  
  293. function blockBuster.filterPowerups(npcID, pl) -- https://github.com/smbx/smbx-legacy-source/blob/master/modBlocks.bas#L345
  294.     local mushID = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "mushID")
  295.     local isPowerup = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "isPowerup")
  296.     local progressivePowerups = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "progressivePowerups")
  297.     local mushroom = false
  298.     if pl and pl.powerup == PLAYER_SMALL and not mem(0x00B2D740, FIELD_BOOL) and progressivePowerups then mushroom = true end --battle mode address
  299.     if (isPowerup and mushID and mushroom) then
  300.         npcID = mushID
  301.     end
  302.     return npcID
  303. end
  304.  
  305. function blockBuster.filterCharacterItems(npcID, ai1, pl) -- https://github.com/smbx/smbx-legacy-source/blob/master/modNPC.bas#L12271
  306.     local mushID = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "mushID")
  307.     local isMush = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "isMush")
  308.     local isEgg = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "isEgg")
  309.     local mountID = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "mountID")
  310.     local isCoin = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "isCoin")
  311.     local coinID = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "coinID")
  312.     local altID = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "altID")
  313.  
  314.     if isMush then
  315.         if mushID then
  316.             npcID = mushID
  317.         end
  318.     end
  319.     if isEgg then
  320.         local eggContains = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "isEgg")
  321.         local altMountID = blockBuster.resolveProperties(ai1, pl, itemProperties, "items", "altID")
  322.        
  323.         if eggContains then
  324.             if mountID then
  325.                 if altMountID then
  326.                    
  327.                     ai1 = altMountID
  328.                 end
  329.             end
  330.         end
  331.     end
  332.     if isCoin then
  333.         if coinID then
  334.             npcID = coinID
  335.             if altID then
  336.                 npcID = altID
  337.             end
  338.         end
  339.     end
  340.     return npcID, ai1
  341. end
  342.  
  343. function blockBuster.spawnItem(block, upper, pl, npcID) -- this looks familiar lol
  344.     local forced = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "forcedState")
  345.     local forced2 = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "forcedState2")
  346.     local direction = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "direction")
  347.     local usePlrDir = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "usePlrDir")
  348.     local speedX = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "speedX")
  349.     local speedY = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "speedY")
  350.     local offsetX = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "offsetX")
  351.     local offsetY = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "offsetY")
  352.     local ai = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "ai")
  353.     local data = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "data")
  354.     local despawnTimer = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "despawnTimer")
  355.     local isEgg = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "isEgg")
  356.     local frame = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "frame")
  357.     local immunity = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "immunity")
  358.     local upperOffsetX = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "upperOffsetX")
  359.     local upperOffsetY = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "upperOffsetY")
  360.     local upperSpeedX = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "upperSpeedX")
  361.     local upperSpeedY = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "upperSpeedY")
  362.     local upperAI = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "upperAI")
  363.     local upperForced = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "upperForcedState")
  364.     local upperForced2 = blockBuster.resolveProperties(npcID, pl, itemProperties, "items", "upperForcedState2")
  365.    
  366.     local tempWidth = block.width
  367.     local tempX = block.x
  368.     if tempWidth == 32 then
  369.         tempWidth = block.width - 0.1
  370.         tempX = block.x - 0.05
  371.     end
  372.     if upper then
  373.         offsetX = upperOffsetX
  374.         offsetY = upperOffsetY
  375.         speedX = upperSpeedX
  376.         speedY = upperSpeedY
  377.         ai = upperAI
  378.         forced = upperForced
  379.         forced2 = upperForcedState2
  380.     end
  381.     if isEgg then
  382.         ai.ai1 = npcID
  383.         npcID = 96
  384.     end
  385.     npcID = blockBuster.filterPowerups(npcID, pl)
  386.     npcID, ai.ai1 = blockBuster.filterCharacterItems(npcID, ai.ai1, pl)
  387.     local s = NPC.spawn(npcID, tempX + (tempWidth*0.5) - (NPC.config[npcID].width*0.5) + offsetX, block.y + offsetY, blockutils.getBlockSection(block), false, false)
  388.     if spawnLayer then
  389.         s.layerName = spawnLayer
  390.     end
  391.     if frame then
  392.         s.animationFrame = frame
  393.     end
  394.     if data ~= nil then
  395.         for  k,_ in pairs(data) do
  396.             if not (s.data[k] == data[k]) then
  397.                 s.data[k] = data[k]
  398.             end
  399.         end
  400.     end
  401.     if ai ~= nil then
  402.         for  k,_ in pairs(ai) do
  403.             if not (s[k] == ai[k]) then
  404.                 s[k] = ai[k]
  405.             end
  406.         end
  407.     end
  408.     s:mem(0x124, FIELD_BOOL, true) -- active flag
  409.     if despawnTimer then
  410.         s.despawnTimer = despawnTimer
  411.     end
  412.     if direction and usePlrDir ~= nil and not usePlrDir then
  413.         s.direction = direction
  414.     elseif usePlrDir ~= nil and usePlrDir then
  415.         s.direction = pl.direction
  416.     end
  417.     if forced then
  418.         s:mem(0x138, FIELD_WORD, forced) -- forced state/effect
  419.     end
  420.     if forced2 then
  421.         s:mem(0x13C, FIELD_DFLOAT, forced2) -- a forced state timer/effect2
  422.     end
  423.     s.speedY = speedY
  424.     s.speedX = speedX
  425.     if forced == 1 then
  426.         s.height = 0
  427.     end
  428.     if immunity then
  429.         s:mem(0x156, FIELD_WORD, immunity) -- immune timer
  430.     end
  431.     return s
  432. end
  433.  
  434. function blockBuster.onPostBlockHit(v, upper, pl)
  435.     if not blockBuster.enabled then return end
  436.  
  437.     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
  438.  
  439.     v.data.BBTable = v.data.BBTable or {}
  440.     local data = v.data.BBTable
  441.    
  442.     if not (v.contentID == 0) then  -- void blocks contents to overwrite how things are done if the block isn't empty
  443.         v:mem(0x5A , FIELD_BOOL, false) -- allow invisible blocks to work properly with blockBuster
  444.         data.oldContents = v.contentID
  445.         data.oldMulti = v:mem(0x04, FIELD_WORD)
  446.         v.contentID = 0
  447.         v:mem(0x04, FIELD_WORD, 0)
  448.         table.insert(BlocksToProcess, v.idx)
  449.     end
  450.  
  451.     if pl == nil then
  452.         if data.player and not (pl == data.player) then -- should make RapidHit work with character configs
  453.             pl = data.player
  454.         end
  455.         if blockBuster.npcOwnersToBlocks then -- allow transferring this system from thrown npcs
  456.             for _,n in ipairs(NPC.getIntersecting(v.x-1,v.y-1,v.x+v.width+1,v.y+v.height+1)) do
  457.                 if n:mem(0x132,FIELD_WORD) > 0 and n:mem(0x136,FIELD_BOOL) and pl == nil then
  458.                     pl = Player.get()[n:mem(0x132,FIELD_WORD)]
  459.                 end
  460.             end
  461.         end
  462.     end
  463.  
  464.     if upper and data.oldContents then
  465.         upper = not blockBuster.checkCollisionDown(v)
  466.     end
  467.    
  468.     if data.oldContents and data.oldContents > 0 and data.oldContents < 100 then -- coin handling
  469.         local coinStyle = blockBuster.resolveProperties(v.id, pl, blockProperties, "coins", "style")
  470.         local multiHitTimes = blockBuster.resolveProperties(v.id, pl, blockProperties, "coins", "multiHitAmount")
  471.         local npcSpawnID = blockBuster.resolveProperties(v.id, pl, blockProperties, "coins", "npc")
  472.         local coinSoundID = blockBuster.resolveProperties(v.id, pl, blockProperties, "coins", "sound")
  473.         local blockTransformID = blockBuster.resolveProperties(v.id, pl, blockProperties, "transforms", "transformID")
  474.         local centred = blockBuster.resolveProperties(v.id, pl, blockProperties, "transforms", "centred")
  475.         local effectID = blockBuster.resolveProperties(v.id, pl, blockProperties, "coins", "effect")
  476.         local coinFunction = blockBuster.resolveProperties(v.id, pl, blockProperties, "coins", "coinFunc")
  477.  
  478.         if not (multiHitTimes == nil) and multiHitTimes > 0 then
  479.             if v:mem(0x04, FIELD_WORD) == 0 and not data.isMulti then
  480.                 blockBuster.doMultiSetup(v, pl)
  481.             else
  482.                 data.oldMulti = data.oldMulti - 1
  483.             end
  484.         elseif not multiHitTimes and not data.isMulti then
  485.             v:mem(0x04, FIELD_WORD, 0) -- pervent vanilla multihitting
  486.         end
  487.  
  488.         if coinStyle == COIN_STYLE_MARIO then
  489.             blockBuster.defaultCoinAction(v, coinSoundID, blockTransformID, centred, effectID)
  490.             blockBuster.resolveBumps(v, upper)
  491.         elseif coinStyle == COIN_STYLE_TOAD then
  492.             if not blockBuster.checkCollisionUp(v) then
  493.                 blockBuster.spawnCoin(v, upper, pl, npcSpawnID)
  494.                 if blockBuster.playSounds then
  495.                     SFX.play(coinSoundID)
  496.                 end
  497.                 blockBuster.decrementCoinContents(v)
  498.                 blockBuster.transformBlock(v, blockTransformID, centred)
  499.             else
  500.                 blockBuster.defaultCoinAction(v, coinSoundID, blockTransformID, centred, effectID)
  501.             end
  502.             blockBuster.resolveBumps(v, upper)
  503.         elseif coinStyle == COIN_STYLE_OTHER then
  504.             if not blockBuster.checkCollisionUp(v) then
  505.                 local max = 0
  506.                 if data.oldContents < characterProperties[pl.character].coins.coinClusterMax then
  507.                     max = data.oldContents
  508.                 else
  509.                     max = characterProperties[pl.character].coins.coinClusterMax
  510.                 end
  511.                 for i=1, max do
  512.                     local tempCoinID = blockBuster.resolveProperties(v.id, pl, blockProperties, "coins", "npc")
  513.                     if coinFunction then
  514.                         tempCoinID = coinFunction(tempCoinID)
  515.                     end
  516.                     blockBuster.spawnCoin(v, upper, pl, tempCoinID)
  517.                     if not characterProperties[pl.character].coins.coinClusterNulls then
  518.                         blockBuster.decrementCoinContents(v)
  519.                     end
  520.                 end
  521.                 if blockBuster.playSounds then
  522.                     SFX.play(coinSoundID)
  523.                 end
  524.                 if characterProperties[pl.character].coins.coinClusterNulls then
  525.                     data.oldContents = 0
  526.                 end
  527.                 blockBuster.transformBlock(v, blockTransformID, centred)
  528.             else
  529.                 blockBuster.defaultCoinAction(v, nil, blockTransformID, centred, effectID)
  530.             end
  531.             blockBuster.resolveBumps(v, upper)
  532.         elseif coinStyle == COIN_STYLE_CUSTOM then
  533.             local coinStyle = blockBuster.resolveProperties(v.id, pl, blockProperties, "coins", "style")
  534.             -- allow making one's own coin code
  535.             EventManager.callEvent("onCustomCoinEvent", v, upper, pl, data.oldContents)
  536.         end
  537.     end
  538.  
  539.     if data.oldContents and data.oldContents >= 1000 then -- npc handling
  540.         local itemStyle = blockBuster.resolveProperties(v.id, pl, blockProperties, "items", "style")
  541.  
  542.         if itemStyle == ITEM_STYLE_DEFAULT then
  543.             local npcSpawnID = data.oldContents - 1000
  544.             blockBuster.spawnItem(v, upper, pl, npcSpawnID)
  545.             data.oldContents = 0
  546.             if blockBuster.playSounds then
  547.                 SFX.play(7)
  548.             end
  549.             blockBuster.transformBlock(v, blockBuster.resolveProperties(v.id, pl, blockProperties, "transforms", "transformID"), blockBuster.resolveProperties(v.id, pl, blockProperties, "transforms", "centred"))
  550.             blockBuster.resolveBumps(v, upper)
  551.         elseif itemStyle == ITEM_STYLE_CUSTOM then
  552.             -- allow making one's own item code
  553.             EventManager.callEvent("onCustomItemEvent", v, upper, pl, data.oldContents)
  554.         end
  555.     end
  556. end
  557.  
  558. function blockBuster.onTickEnd()
  559.     if not blockBuster.enabled and #BlocksToProcess == 0 then return end
  560.     for k,v in ipairs(BlocksToProcess) do
  561.         local block = Block(v)
  562.         local data = block.data.BBTable
  563.         block.contentID = data.oldContents -- restore old contents so coins work
  564.         data.oldContents = nil
  565.         block:mem(0x04, FIELD_WORD, data.oldMulti)
  566.         data.oldMulti = nil
  567.         if block:mem(0x04, FIELD_WORD) <= 0 then -- only get rid of other feilds if not using them for multihitting
  568.             data.player = nil
  569.             data.isMulti = nil
  570.             block:mem(0x04, FIELD_WORD, 0)
  571.         end
  572.         table.remove(BlocksToProcess, k)
  573.     end
  574. end
  575.  
  576. blockBuster.properties = properties
  577.  
  578. return blockBuster
Add Comment
Please, Sign In to add comment