[NPC Pack] Flurret

Share and discuss custom LunaLua code and content packs for SMBX2.
Emral
Cute Yoshi Egg
Cute Yoshi Egg
Posts: 9722
Joined: Mon Jan 20, 2014 12:58 pm
Flair: Phoenix

[NPC Pack] Flurret

Postby Emral » Sat Jul 27, 2019 7:16 pm

Flurret shootm's the Flurry. Lucienne says it best: Kind of like a Bowser Statue with bounceable projectiles.

A download link can be found here:
https://drive.google.com/file/d/1rsjmIq ... sp=sharing

Demo:
https://www.youtube.com/watch?v=3yZSJNPa7u8
0:40

Installation instructions can be found in the handbook or in my thread.

Modifications and adaptations of the code is permitted. If you use this particular code as a basis for an enhanced version of these NPCs, please give credit.

Lithobraker
Rex
Rex
Posts: 31
Joined: Sat Mar 09, 2019 1:41 am

Re: [NPC Pack] Flurret

Postby Lithobraker » Mon Jul 06, 2020 3:27 pm

Hey, I'm currently repurposing the Flurret code into a Ruff Puff, and I've got a 4-frame moving animation for it. Everything seems to work fine when it's left-facing with this code, but when it's facing right, the animation plays extremely rapidly for some reason.
I might be able to fix it if I knew how modulus operators (%) worked...

Code: Select all

v.animationFrame = v.animationFrame % 2
Changing the 2 here to 3 gets me an NPC which animates with only the first 3 frames of its moving animation- but it doesn't have a fit when facing right.
If it's set to 4 though, the fit occurs.
I feel like this should be obvious, but my understanding of modulus operators is that they give the remainder of the first number divided by the second. If this was true, shouldn't it not animate properly, since a remainder is only returned with an odd number? Clearly I'm missing something.

Sprite:
Image

NPC.lua:
Spoiler: show

Code: Select all

local npcManager = require("npcManager")

local ruffPuffNPC = {}

local npcID = NPC_ID
local deathEffectID = npcID

-- settings
local config = {
	id = npcID, 
	gfxoffsetx = 0, 
	gfxoffsety = 0, 
	width = 30, 
    height = 30,
    gfxwidth = 46,
    gfxheight = 38,
    frames = 6,
    framestyle = 1,
    playerblocktop = false,
    npcblocktop = false,
    playerblock = false,
    npcblock = false,
    nofireball = true,
    noiceball = false,
    nohurt = true,
	nogravity = true,
	noblockcollision = true,
    jumphurt = true,
	spinjumpsafe = true,
    projectile = 935,
	
	iswalker = true
}

npcManager.setNpcSettings(config)

npcManager.registerHarmTypes(npcID,
{
		--HARM_TYPE_JUMP,
		--HARM_TYPE_FROMBELOW,
		HARM_TYPE_NPC,
		--HARM_TYPE_PROJECTILE_USED,
		HARM_TYPE_LAVA,
		HARM_TYPE_HELD,
		--HARM_TYPE_TAIL,
		--HARM_TYPE_SPINJUMP,
		--HARM_TYPE_OFFSCREEN,
		HARM_TYPE_SWORD
	}, 
	{
		--[HARM_TYPE_JUMP]=10,
		[HARM_TYPE_FROMBELOW]= deathEffectID,
		[HARM_TYPE_NPC]= deathEffectID,
		--[HARM_TYPE_PROJECTILE_USED]= 10,
		[HARM_TYPE_LAVA]={id=13, xoffset=0.5, xoffsetBack = 0, yoffset=1, yoffsetBack = 1.5},
		[HARM_TYPE_HELD]= deathEffectID,
		--[HARM_TYPE_TAIL]=10,
		--[HARM_TYPE_SPINJUMP]=10,
		--[HARM_TYPE_OFFSCREEN]=10,
		[HARM_TYPE_SWORD]= deathEffectID,
		[HARM_TYPE_EXT_ICE] = 10,
	}
);

local ST_IDLE = 0
local ST_WAIT = 1
local ST_SHOOT = 2
local turnTimer = 0

function ruffPuffNPC.onInitAPI()
    npcManager.registerEvent(npcID, ruffPuffNPC, "onTickEndNPC")
end

function ruffPuffNPC.onTickEndNPC(v)
    if Defines.levelFreeze then return end
    if v.isHidden or v:mem(0x12A, FIELD_WORD) <= 0 or v:mem(0x138, FIELD_WORD) > 0 then
        v.data.state = 0
        v.data.timer = 0
		turnTimer = 0
		return
    end

    local data = v.data

    local shootframe = NPC.config[v.id].frames - 2

    if data.state == nil then
        data.state = 0
        data.timer = 0
		turnTimer = 0
    end

    data.timer = data.timer + 1
	turnTimer = turnTimer + 1

    v.animationFrame = v.animationFrame % 4
	
	if data.state ~= ST_SHOOT then
		if turnTimer >= 128 then
			v.speedX = v.speedX * -1
			turnTimer = 0
		end
	
	end

    if data.state == ST_IDLE then
        if data.timer == 64 and not v.friendly then
            data.timer = 0
            data.state = ST_WAIT
        end
    elseif data.state == ST_WAIT then
        if data.timer == 16 then
            local n = NPC.spawn(NPC.config[v.id].projectile, v.x + 0.5 * v.width, v.y + 0.5 * v.height, player.section, false, true)
            n.speedX = 2 * v.direction
            data.timer = 0
            data.state = ST_SHOOT
            SFX.play("puffspit.ogg")
        end
        v.animationFrame = shootframe
    elseif data.state == ST_SHOOT then
        if data.timer == 16 then
            data.timer = 0
            data.state = ST_IDLE
        end
        v.animationFrame = shootframe + 1
    end

    if v.direction == 1 and NPC.config[v.id].framestyle == 1 then
        v.animationFrame = v.animationFrame + NPC.config[v.id].frames
    end
end

return ruffPuffNPC

Emral
Cute Yoshi Egg
Cute Yoshi Egg
Posts: 9722
Joined: Mon Jan 20, 2014 12:58 pm
Flair: Phoenix

Re: [NPC Pack] Flurret

Postby Emral » Mon Jul 06, 2020 4:09 pm

Ah, yeah. Might've taken an animation shortcut there. Modulo can get a bit wacky due to the nature of the spritesheet and how the right-facing frames are just higher numbers. Your intuition is correct. IDK what that line 71 is doing but you miiight be able to fix it by removing it and putting the following just after line 77 instead:
v.animationFrame = math.floor(data.timer / NPC.config[v.id].framespeed) % frame
That'll basically overwrite the basegame frame timer completely. Fairly confident that'll work.

Lithobraker
Rex
Rex
Posts: 31
Joined: Sat Mar 09, 2019 1:41 am

Re: [NPC Pack] Flurret

Postby Lithobraker » Mon Jul 06, 2020 4:12 pm

Enjl wrote:
Mon Jul 06, 2020 4:09 pm
Ah, yeah. Might've taken an animation shortcut there. Modulo can get a bit wacky due to the nature of the spritesheet and how the right-facing frames are just higher numbers. Your intuition is correct. IDK what that line 71 is doing but you miiight be able to fix it by removing it and putting the following just after line 77 instead:
v.animationFrame = math.floor(data.timer / NPC.config[v.id].framespeed) % frame
That'll basically overwrite the basegame frame timer completely. Fairly confident that'll work.
Um... line 71? In my file, line 71 is this:

Code: Select all

    npcManager.registerEvent(npcID, ruffPuffNPC, "onTickEndNPC")
I think that one's important. Could you just copy+paste which line you're talking about?

Emral
Cute Yoshi Egg
Cute Yoshi Egg
Posts: 9722
Joined: Mon Jan 20, 2014 12:58 pm
Flair: Phoenix

Re: [NPC Pack] Flurret

Postby Emral » Mon Jul 06, 2020 4:16 pm

Lithobraker wrote:
Mon Jul 06, 2020 4:12 pm
Enjl wrote:
Mon Jul 06, 2020 4:09 pm
Ah, yeah. Might've taken an animation shortcut there. Modulo can get a bit wacky due to the nature of the spritesheet and how the right-facing frames are just higher numbers. Your intuition is correct. IDK what that line 71 is doing but you miiight be able to fix it by removing it and putting the following just after line 77 instead:
v.animationFrame = math.floor(data.timer / NPC.config[v.id].framespeed) % frame
That'll basically overwrite the basegame frame timer completely. Fairly confident that'll work.
Um... line 71? In my file, line 71 is this:

Code: Select all

    npcManager.registerEvent(npcID, ruffPuffNPC, "onTickEndNPC")
I think that one's important. Could you just copy+paste which line you're talking about?
Oh, you must've modified some earlier lines. Got it.
Line 71:
v.animationFrame = v.animationFrame % 2

"Just after line 77" is between these two:

end
-- right here
elseif data.state == ST_WAIT then

Lithobraker
Rex
Rex
Posts: 31
Joined: Sat Mar 09, 2019 1:41 am

Re: [NPC Pack] Flurret

Postby Lithobraker » Mon Jul 06, 2020 4:20 pm

Enjl wrote:
Mon Jul 06, 2020 4:16 pm
Lithobraker wrote:
Mon Jul 06, 2020 4:12 pm
Enjl wrote:
Mon Jul 06, 2020 4:09 pm
Ah, yeah. Might've taken an animation shortcut there. Modulo can get a bit wacky due to the nature of the spritesheet and how the right-facing frames are just higher numbers. Your intuition is correct. IDK what that line 71 is doing but you miiight be able to fix it by removing it and putting the following just after line 77 instead:
v.animationFrame = math.floor(data.timer / NPC.config[v.id].framespeed) % frame
That'll basically overwrite the basegame frame timer completely. Fairly confident that'll work.
Um... line 71? In my file, line 71 is this:

Code: Select all

    npcManager.registerEvent(npcID, ruffPuffNPC, "onTickEndNPC")
I think that one's important. Could you just copy+paste which line you're talking about?
Oh, you must've modified some earlier lines. Got it.
Line 71:
v.animationFrame = v.animationFrame % 2

"Just after line 77" is between these two:

end
-- right here
elseif data.state == ST_WAIT then
Well, I had to change your line a bit, because "% frame" is calling a global that doesn't exist. You meant "% NPC.config[v.id].frames", right?

Code: Select all

v.animationFrame = math.floor(data.timer / NPC.config[v.id].framespeed) % NPC.config[v.id].frames
With the changes you suggested made, though, while the idle animations seem to work mostly fine, the NPC plays the shooting animation repeatedly. I can't tell if it's doing this because it's cycling through all its frames, or if it actually thinks it's shooting a bit before it does.
I'm inclined to believe the former.

Emral
Cute Yoshi Egg
Cute Yoshi Egg
Posts: 9722
Joined: Mon Jan 20, 2014 12:58 pm
Flair: Phoenix

Re: [NPC Pack] Flurret

Postby Emral » Mon Jul 06, 2020 4:23 pm

Lithobraker wrote:
Mon Jul 06, 2020 4:20 pm
Well, I had to change your line a bit, because "% frame" is calling a global that doesn't exist. You meant "% NPC.config[v.id].frames", right?

Code: Select all

v.animationFrame = math.floor(data.timer / NPC.config[v.id].framespeed) % NPC.config[v.id].frames
With the changes you suggested made, though, while the idle animations seem to work mostly fine, the NPC plays the shooting animation repeatedly. I can't tell if it's doing this because it's cycling through all its frames, or if it actually thinks it's shooting a bit before it does.
I'm inclined to believe the former.
Wait... huh? We were both looking at the flurret ai file, right?
It is the former, hold on.. Here's what my file I just downloaded looked like:
https://hastebin.com/oleduqugog.rb
Notice the definition of "frame" in line 62. It's the number of the first shooting frame, so I was taking modulo by that to take the animation loop of the frames before it.

Lithobraker
Rex
Rex
Posts: 31
Joined: Sat Mar 09, 2019 1:41 am

Re: [NPC Pack] Flurret

Postby Lithobraker » Mon Jul 06, 2020 4:27 pm

Enjl wrote:
Mon Jul 06, 2020 4:23 pm
Lithobraker wrote:
Mon Jul 06, 2020 4:20 pm
Well, I had to change your line a bit, because "% frame" is calling a global that doesn't exist. You meant "% NPC.config[v.id].frames", right?

Code: Select all

v.animationFrame = math.floor(data.timer / NPC.config[v.id].framespeed) % NPC.config[v.id].frames
With the changes you suggested made, though, while the idle animations seem to work mostly fine, the NPC plays the shooting animation repeatedly. I can't tell if it's doing this because it's cycling through all its frames, or if it actually thinks it's shooting a bit before it does.
I'm inclined to believe the former.
Wait... huh? We were both looking at the flurret ai file, right?
It is the former, hold on.. Here's what my file I just downloaded looked like:
https://hastebin.com/oleduqugog.rb
Notice the definition of "frame" in line 62. It's the number of the first shooting frame, so I was taking modulo by that to take the animation loop of the frames before it.
Ah, right. I renamed that to "shootframe" since that's what it appears to mean, so I would be able to read the file better. That fixed it! Thanks for the help.
You've been a huge help in general so far! I hope you don't mind all these questions I've been having.


Return to “LunaLua”

Who is online

Users browsing this forum: No registered users and 4 guests

SMWCentralTalkhausMario Fan Games GalaxyKafukaMarioWikiSMBXEquipoEstelari