--[[ wario.lua v1.2.1 Remade practically from scratch by arabslmon/ohmato, 2016 Original (the awful one) by Horikawa Otane And then Enjl took the shop out. (And then Saturnyoshi made it work again, and added HDOverride stuff) And then Enjl attempted to make the character more playable Things to do: ]] local colliders = require("colliders") local rng = require("rng") local pm = require("playerManager") local expandedDefines = require("expandedDefines") local wario = {} local chars = pm.getCharacters(); -- Debug variables local debugmode = false if debugmode then mem(0x00B2C5AC, FIELD_FLOAT, 3) end local fx_groundpound = pm.registerGraphic(CHARACTER_WARIO, "poundFX.png") local fx_charge = { [-1] = pm.registerGraphic(CHARACTER_WARIO, "chargeFXL.png"), [1] = pm.registerGraphic(CHARACTER_WARIO, "chargeFXR.png") } -- Graphical/audio assets local HUD = { stars = pm.registerGraphic(CHARACTER_WARIO, "HUD\\wario_stars.png"), lives = pm.registerGraphic(CHARACTER_WARIO, "HUD\\wario_lives.png"), meter = pm.registerGraphic(CHARACTER_WARIO, "HUD\\HUD_meter.png") } local function drawFX(effect, offset) local img = pm.getGraphic(CHARACTER_WARIO, effect) local h = img.height / 3 Graphics.drawImageToSceneWP( img, player.x + 0.5 * player.width + offset.x, player.y + 0.5 * player.height + offset.y, 0, h * (math.floor(lunatime.tick() * 0.25) % 3), img.width, h, -25 ) end local sfx = { footstep = {} } for i = 1,3 do sfx.footstep[i] = pm.registerSound(CHARACTER_WARIO, "wario_footstep"..tostring(i)..".ogg") end local itembox = pm.registerGraphic(CHARACTER_WARIO, "itembox.png") -- Dash-associated variables local dashtimer = 0 -- Aggregate timer for dashing local dashing = false -- Is the player currently dashing? local DASHCHARGETIME = 24 -- Dash length local DASHSPEED = 8 -- Speed while dashing local DASHACCEL = 4 -- Acceleration to top speed while dashing local lockedDirection = 0 -- Crawling-associated variables local crawling = false -- Is the player currently crawling? local ducking = false -- Is the player currently ducking? local CRAWLSPEED = 2 -- Speed while crawling local crawltimer = 0 -- Timer for crawl frames local isGroundPounding = false function wario.onInitAPI() registerEvent(wario, "onInputUpdate", "onInputUpdate", false) registerEvent(wario, "onNPCKill") registerEvent(wario, "onTick", "onTick", false) registerEvent(wario, "onDraw") registerEvent(wario, "onTickEnd", "DebugDraw") end -- Input management for store UI and dashing function wario.onInputUpdate() -- If the player is Wario if player.character == CHARACTER_WARIO then if Misc.isPaused() then return end pm.winStateCheck() -- Increase the dash timer when running on the ground if player.powerup > 1 then if not isGroundPounding then if player.keys.altRun == KEYS_PRESSED and player.forcedState == 0 and dashtimer == 0 then if player:isGroundTouching() then dashtimer = DASHCHARGETIME end lockedDirection = player.direction end if player.keys.altJump == KEYS_PRESSED then if not player:mem(0x36, FIELD_BOOL) and player.mount == 0 then if player:isGroundTouching() then player.altJumpKeyPressing = false player.jumpKeyPressing = true elseif player.rawKeys.altJump == KEYS_PRESSED then lockedDirection = player.direction isGroundPounding = true player.speedY = -4 end end end else if player.keys.altJump == KEYS_PRESSED then isGroundPounding = false end end end -- If holding something or on a mount, prevent dashing if player:mem(0x154, FIELD_WORD) ~= 0 or player:mem(0x108, FIELD_WORD) ~= 0 then dashtimer = 0 end end end -- Determines value of a coin NPC local function coinval(id) if id == 152 or id == 88 or id == 138 or id == 10 or id == 33 or id == 251 or id == 274 then return 1 elseif id == 103 then return 2 elseif id == 252 or id == 258 then return 5 elseif id == 253 then return 20 else return 0 end end -- Checks if an NPC is onscreen local function onscreen(npc) -- Get camera boundaries local left = camera.x; local right = left + camera.width; local top = camera.y; local bottom = top + camera.height; -- Check if offscreen if npc.x + npc.width < left or npc.x > right then return false elseif npc.y + npc.height < top or npc.y > bottom then return false else return true end end -- Spawn coins when killing an enemy, coin counter management, and monitor Lakitu helper crates function wario.onNPCKill(eventObj, killedNPC, killReason) -- If the player is Wario if player.character == CHARACTER_WARIO then -- If the player kills an enemy, drop some coins (ignore death of projectiles, powerups, in lava, an iceball, or egg) if killReason <= 8 and killReason ~= 6 and killReason ~= 4 and NPC.HITTABLE_MAP[killedNPC.id] then for i = 1, NPC.config[killedNPC.id].score do local coin = NPC.spawn(10, killedNPC.x + 0.5 * killedNPC.width, killedNPC.y + 0.5 * killedNPC.height, player.section, false, true) coin.speedX = rng.random(-2,2) coin.speedY = rng.random(-4) coin.ai1 = 1 killedNPC:mem(0x74, FIELD_WORD, -1) end end end end -- Initialization and cleanup of Wario character data function wario.initCharacter() -- Make Wario "heavier" Defines.player_runspeed = 4 Defines.player_walkspeed = 2 Defines.jumpheight = 18 Defines.jumpheight_bounce = 18 -- Adjust size of player-thrown fireball/iceball graphic NPC.config[13].gfxwidth = 32; NPC.config[265].gfxwidth = 32; NPC.config[13].gfxheight = 32; NPC.config[265].gfxheight = 32; NPC.config[13].height = 32; NPC.config[265].height = 32; NPC.config[13].width = 32; NPC.config[265].width = 32; end function wario.cleanupCharacter() -- Return physics to normal Defines.player_runspeed = nil Defines.player_walkspeed = nil Defines.jumpheight = nil Defines.jumpheight_bounce = nil -- Reset grabbing ability Defines.player_grabSideEnabled = nil Defines.player_grabShellEnabled = nil -- Reset dimensions for player-thrown fireball/iceball NPC.config[13].gfxwidth = 16; NPC.config[265].gfxwidth = 16; NPC.config[13].gfxheight = 16; NPC.config[265].gfxheight = 16; NPC.config[13].height = 16; NPC.config[265].height = 16; NPC.config[13].width = 16; NPC.config[265].width = 16; end -- Render dash charge meter local function renderDashMeter(xpos, ypos) Graphics.draw {x = xpos, y = ypos, type = RTYPE_IMAGE, priority = 5, image = pm.getGraphic(CHARACTER_WARIO, HUD.meter), sourceHeight = 18} if dashtimer < DASHCHARGETIME then Graphics.draw {x = xpos, y = ypos, type = RTYPE_IMAGE, priority = 5, image = pm.getGraphic(CHARACTER_WARIO, HUD.meter), sourceY = 18, sourceWidth = 10*math.floor(dashtimer/DASHCHARGETIME*8), sourceHeight = 18} else Graphics.draw {x = xpos, y = ypos, type = RTYPE_IMAGE, priority = 5, image = pm.getGraphic(CHARACTER_WARIO, HUD.meter), sourceY = 18, sourceWidth = 70, sourceHeight = 18} if math.floor(lunatime.tick()*10)%2 == 0 then Graphics.draw {x = xpos + 70, y = ypos, type = RTYPE_IMAGE, priority = 5, image =pm.getGraphic(CHARACTER_WARIO, HUD.meter), sourceX = 70, sourceY = 18, sourceWidth = 26, sourceHeight = 18} end end end -- Set up HUD local function drawHudElements(playerIdx, camObj, playerObj, priority, isSplit, playerCount) --renderDashMeter(camObj.width / 2 - 48, 72) end Graphics.registerCharacterHUD(CHARACTER_WARIO, Graphics.HUD_ITEMBOX, drawHudElements, { reserveBox2P = itembox, lives = HUD.lives, stars = HUD.stars, }) -- Per-frame logic function wario.onTick() -- If the player is Wario if player.character ~= CHARACTER_WARIO then return end -- Cap run/walk speed if dashtimer == 0 then Defines.player_runspeed = 4 Defines.player_walkspeed = 4 Defines.player_grabSideEnabled = true Defines.player_grabShellEnabled = true else Defines.player_runspeed = DASHSPEED Defines.player_walkspeed = DASHSPEED Defines.player_grabSideEnabled = false Defines.player_grabShellEnabled = false end if player:mem(0x40, FIELD_WORD) > 0 or player:mem(0x36, FIELD_WORD) > 0 then player.jumpKeyPressing = player.jumpKeyPressing or player.altJumpKeyPressing player.altJumpKeyPressing = false end -- Dash mechanic if isGroundPounding then player:mem(0x164, FIELD_WORD, 0) player.leftKeyPressing = false player.rightKeyPressing = false player.altRunKeyPressing = false player.runKeyPressing = true player.downKeyPressing = false player.speedX = 0 Defines.gravity = 13 Defines.player_grav = 0.8 if player:mem(0x40, FIELD_WORD) > 0 or player:mem(0x36, FIELD_BOOL) then isGroundPounding = false Defines.gravity = 12 Defines.player_grav = 0.4 end if player:isGroundTouching() then isGroundPounding = false Defines.earthquake = 4 player.speedY = -4 Defines.gravity = 12 Defines.player_grav = 0.4 playSFX(37) end if player.speedY > 0 then drawFX(fx_groundpound, {x = -41, y = -16}) for _,block in ipairs(Block.getIntersecting(player.x, player.y + player.height, player.x + player.width, player.y + player.height + 14)) do -- If block is visible if block.isHidden == false and block:mem(0x5a, FIELD_WORD) == 0 then -- If the block should be broken, destroy it if expandedDefines.BLOCK_MEGA_SMASH_MAP[block.id] then if block.contentID > 0 then block:hit(true, player) else block:remove(true) end elseif expandedDefines.BLOCK_MEGA_HIT_MAP[block.id] then block:hit(true, player) isGroundPounding = false Defines.earthquake = 4 player.speedY = -4 playSFX(37) Defines.gravity = 12 Defines.player_grav = 0.4 elseif (expandedDefines.BLOCK_SOLID_MAP[block.id] or (expandedDefines.BLOCK_SEMISOLID_MAP[block.id] and player.y + player.height <= block.y + 4) or expandedDefines.BLOCK_PLAYERSOLID_MAP[block.id]) and not expandedDefines.BLOCK_SLOPE_MAP[block.id] then block:hit(true, player) isGroundPounding = false Defines.earthquake = 4 player.speedY = -4 Defines.gravity = 12 Defines.player_grav = 0.4 playSFX(37) end end end end for _, npc in ipairs(NPC.getIntersecting(player.x, player.y + player.height, player.x + player.width, player.y + player.height + 10)) do if NPC.HITTABLE_MAP[npc.id] and (not NPC.config[npc.id].jumphurt) and (not npc.friendly) and npc:mem(0x12A, FIELD_WORD) > 0 and (not npc:mem(0x64, FIELD_BOOL)) and not (npc:mem(0x138, FIELD_WORD) > 0) and not (npc:mem(0x12C, FIELD_WORD) > 0) then npc:kill(8) colliders.bounceResponse(player) isGroundPounding = false end end else Defines.gravity = 12 Defines.player_grav = 0.4 end if dashtimer > 0 then player:mem(0x164, FIELD_WORD, 0) player.leftKeyPressing = false player.rightKeyPressing = false player.runKeyPressing = true player.downKeyPressing = false if (not player.altRunKeyPressing) or player:mem(0x40, FIELD_WORD) > 0 then dashtimer = 0 lockedDirection = 0 end if dashtimer == 1 then -- Increase speed player.direction = lockedDirection if lockedDirection == 1 then player.speedX = math.min(player.speedX + DASHACCEL, DASHSPEED) else player.speedX = math.max(player.speedX - DASHACCEL, -DASHSPEED) end -- Destroy blocks when dashing local left = 0; local right = 0 local top = player.y + 2 local bottom = player.y + player.height - 2 if lockedDirection < 0 then right = player.x left = right + player.speedX elseif lockedDirection > 0 then left = player.x + player.width right = left + player.speedX end for _,block in ipairs(Block.getIntersecting(left, top, right, bottom)) do -- If block is visible if block.isHidden == false and block:mem(0x5a, FIELD_WORD) == 0 then -- If the block should be broken, destroy it if expandedDefines.BLOCK_MEGA_SMASH_MAP[block.id] then if block.contentID > 0 then block:hit(false, player) else block:remove(true) end elseif expandedDefines.BLOCK_MEGA_HIT_MAP[block.id] then block:hit(true, player) dashtimer = 0 player.speedX = -2 * lockedDirection player.speedY = -5 end end end for _, npc in ipairs(NPC.getIntersecting(left, top, right, bottom)) do if NPC.HITTABLE_MAP[npc.id] and (not npc.friendly) and npc:mem(0x12A, FIELD_WORD) > 0 and (not npc:mem(0x64, FIELD_BOOL)) and not (npc:mem(0x138, FIELD_WORD) > 0) and not (npc:mem(0x12C, FIELD_WORD) > 0) then npc:harm(3) dashtimer = 0 player.speedX = -2 * lockedDirection player.speedY = -5 end end if player:mem(0x148, FIELD_WORD) ~= 0 or player:mem(0x14C, FIELD_WORD) ~= 0 then dashtimer = 0 for k,v in ipairs(Block.getIntersecting(left, top, right, bottom)) do v:hit(false, player) dashtimer = 0 player.speedX = -2 * lockedDirection player.speedY = -5 Defines.earthquake = 4 playSFX(37) end end -- Visual effects if touching ground if player:isGroundTouching() then Animation.spawn(74, player.x + rng.random(player.width/2) + 4 + player.speedX, player.y + player.height + rng.random(-4, 4) - 4) end elseif dashtimer > 0 then dashtimer = dashtimer - 1 end end if ducking then local ps = PlayerSettings.get(chars[player.character].base, player.powerup); local h = ps.hitboxHeight; local speedXMod = 0 if player.leftKeyPressing then speedXMod = -CRAWLSPEED elseif player.rightKeyPressing then speedXMod = CRAWLSPEED end local overheadBlocks = Block.getIntersecting(player.x + speedXMod, player.y + player.height - h, player.x + player.width + speedXMod, player.y) for k,v in ipairs(overheadBlocks) do if Block.SOLID_MAP[v.id] and (not v.isHidden) and v:mem(0x5A, FIELD_WORD) == 0 then player:mem(0x12e, FIELD_WORD, -1) player.downKeyPressing = true break end end end -- Crawling crawling = false ducking = false if player:mem(0x12e, FIELD_WORD) == -1 and player.downKeyPressing and player:mem(0x108, FIELD_WORD) == 0 and player:isGroundTouching() then dashtimer = 0 player.speedX = player.speedX * 0.95 if player.leftKeyPressing then player.speedX = -CRAWLSPEED crawling = true elseif player.rightKeyPressing then player.speedX = CRAWLSPEED crawling = true end ducking = true end if player:mem(0x122, FIELD_WORD) > 0 then dashtimer = 0 crawling = false ducking = false isGroundPounding = false end if player.powerup == 1 then dashtimer = 0 crawling = false ducking = false if player.mount == 0 then player.jumpKeyPressing = player.jumpKeyPressing or player.altJumpKeyPressing player.altJumpKeyPressing = false end isGroundPounding = false end end function wario.onDraw() if player.character ~= CHARACTER_WARIO then return end if isGroundPounding and player.speedY > 0 then drawFX(fx_groundpound, {x = -41, y = -16}) end if dashtimer ~= 1 then return end drawFX(fx_charge[lockedDirection], {x = -29 + 0.6 * player.width * lockedDirection, y = -40}) end -- Debug drawing, for showing hitboxes in debug mode local function DrawRect(x1, y1, x2, y2, clr) x1 = x1 - camera.x y1 = y1 - camera.y x2 = x2 - camera.x y2 = y2 - camera.y left = { x1,y1, x1+1,y1, x1+1,y2, x1,y1, x1,y2, x1+1,y2 } right = { x2-1,y1, x2,y1, x2,y2, x2-1,y1, x2-1,y2, x2,y2 } top = { x1,y1, x2,y1, x2,y1+1, x1,y1, x1,y1+1, x2,y1+1 } bottom = { x1,y2-1, x2,y2-1, x2,y2, x1,y2-1, x1,y2, x2,y2 } Graphics.glDraw {vertexCoords = left, color = clr} Graphics.glDraw {vertexCoords = right, color = clr} Graphics.glDraw {vertexCoords = top, color = clr} Graphics.glDraw {vertexCoords = bottom, color = clr} end function wario.DebugDraw() -- If the player is Wario if player.character == CHARACTER_WARIO then -- Show dashing frames when dashing and not on a mount if isGroundPounding then player.frame = 30 end if dashtimer > 0 and player:mem(0x108, FIELD_WORD) == 0 then player:mem(0x114, FIELD_WORD, 32 + math.floor(lunatime.tick()*0.2)%2) if not player:isGroundTouching() then player:mem(0x114, FIELD_WORD, 33) end if player:isGroundTouching() and (lunatime.tick())%8 == 0 then Audio.SfxPlayCh(-1, Audio.SfxOpen(pm.getSound(CHARACTER_WARIO, rng.irandomEntry(sfx.footstep))), 0) end end -- Show crawling frames if crawling then if crawltimer < 10 then player:mem(0x114, FIELD_WORD, 22) elseif crawltimer < 10*2 then player:mem(0x114, FIELD_WORD, 23) else crawltimer = 0 player:mem(0x114, FIELD_WORD, 22) end crawltimer = crawltimer + 1 else crawltimer = 0 end end if debugmode and Graphics.isOpenGLEnabled() then DrawRect(player.x, player.y, player.x + player.width, player.y + player.height, {0,1,0}) end --colliders.getHitbox(player):Draw(0xff00007f) end function wario.doGroundPound() lockedDirection = player.direction isGroundPounding = true end function wario.stopGroundPound() isGroundPounding = false end return wario