local npcManager = require("npcManager")
local npcutils = require("npcs/npcutils")

local playerstun = require("playerstun")

local onlinePlay = require("scripts/onlinePlay")
local onlinePlayNPC = require("scripts/onlinePlay_npc")
local onlinePlayPlayers = require("scripts/onlinePlay_players")

local battlePlayer = require("scripts/battlePlayer")


local shockwave = {}
local npcID = NPC_ID

local shockwaveSettings = {
	id = npcID,
	
	gfxwidth = 32,
	gfxheight = 32,

	gfxoffsetx = 0,
	gfxoffsety = 2,
	
	width = 24,
	height = 28,
	
	frames = 2,
	framestyle = 1,
	framespeed = 6,
	
	speed = 1,
	
	npcblock = false,
	npcblocktop = false, --Misnomer, affects whether thrown NPCs bounce off the NPC.
	playerblock = false,
	playerblocktop = false, --Also handles other NPCs walking atop this NPC.

	nohurt = true,
	nogravity = true,
	noblockcollision = true,
	nofireball = true,
	noiceball = true,
	noyoshi = true,
	nowaterphysics = true,
	
	jumphurt = true,
	spinjumpsafe = false,
	harmlessgrab = false,
	harmlessthrown = false,

	notcointransformable = true,
	ignorethrownnpcs = true,
	staticdirection = true,
	luahandlesspeed = true,

	grabside = false,
	grabtop = false,

	foreground = true,


	speed = 4,
	deceleration = 0.975,

	startSinkSpeed = 2,
	sinkAcceleration = 0.001325,

	playerStunTime = 40,
}

npcManager.setNpcSettings(shockwaveSettings)
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]       = 10,
		[HARM_TYPE_NPC]             = 10,
		[HARM_TYPE_PROJECTILE_USED] = 10,
		[HARM_TYPE_LAVA]            = {id=13, xoffset=0.5, xoffsetBack = 0, yoffset=1, yoffsetBack = 1.5},
		[HARM_TYPE_HELD]            = 10,
		[HARM_TYPE_TAIL]            = 10,
		[HARM_TYPE_SPINJUMP]        = 10,
	}
)

function shockwave.onInitAPI()
	npcManager.registerEvent(npcID, shockwave, "onTickNPC")
	npcManager.registerEvent(npcID, shockwave, "onDrawNPC")
end


local stunCommand = onlinePlayNPC.createNPCCommand("battle_stoneShockwave_stun", onlinePlay.IMPORTANCE_MAJOR)

local function stunPlayer(v,playerIdx)
	local config = NPC.config[v.id]
	local data = v.data

	local p = Player(playerIdx)

	Effect.spawn(10,v.x + v.width*0.5 - 16,v.y + v.height*0.5 - 16)
	onlinePlayNPC.forceKillNPC(v,HARM_TYPE_VANISH)

	if not p.isTanookiStatue and not p.hasStarman then
		playerstun.stunPlayer(playerIdx,config.playerStunTime)
	end

	data.hasHitPlayer = true
end

function stunCommand.onReceive(v,sourcePlayerIdx)
	stunPlayer(v,sourcePlayerIdx)
end


local function initialise(v,data,config)
	v.speedX = config.speed*v.direction

	data.heightMultiplier = 1
	data.sinkSpeed = 0

	data.hasHitPlayer = false

	data.initialized = true
end


local function canHitPlayer(v,p)
	if v:mem(0x130,FIELD_WORD) > 0 then
		if v:mem(0x130,FIELD_WORD) == p.idx or battlePlayer.playersAreOnSameTeam(v:mem(0x130,FIELD_WORD),p.idx) then
			return false
		end
	end

	if (p.invincibilityTimer ~= 0 and not p.hasStarman) or p.forcedState ~= FORCEDSTATE_NONE then
		return false
	end

	return true
end


function shockwave.onTickNPC(v)
	if Defines.levelFreeze then return end
	
	local data = v.data
	
	if v.despawnTimer <= 0 then
		data.initialized = false
		return
	end

	local config = NPC.config[v.id]

	if not data.initialized then
		initialise(v,data,config)
	end
	
	-- Speed/sinking
	v.speedX = v.speedX*config.deceleration

	if math.abs(v.speedX) <= config.startSinkSpeed then
		data.sinkSpeed = data.sinkSpeed + config.sinkAcceleration
		data.heightMultiplier = math.max(0,data.heightMultiplier - data.sinkSpeed)
	end

	if data.heightMultiplier <= 0 then
		v:kill(HARM_TYPE_VANISH)
	end

	-- Adjust height
	local newHeight = config.height*data.heightMultiplier

	v.y = v.y + v.height - newHeight
	v.height = newHeight

	-- Don't hurt the player
	if v:mem(0x12E,FIELD_WORD) > 0 then
		v:mem(0x12E,FIELD_WORD,100)
	end


	if data.hasHitPlayer then
		return
	end

	-- Stun players
	for _,p in ipairs(Player.getIntersecting(v.x,v.y,v.x + v.width,v.y + v.height)) do
		if onlinePlayPlayers.ownsPlayer(p) and canHitPlayer(v,p) then
			if onlinePlay.currentMode ~= onlinePlay.MODE_OFFLINE then
				stunCommand:send(v,0)
			end

			stunPlayer(v,p.idx)

			break
		end
	end

	-- Harm NPC's
	local npcs = Colliders.getColliding{a = v,b = NPC.HITTABLE,btype = Colliders.NPC}

	for _,n in ipairs(npcs) do
		n:harm(HARM_TYPE_NPC)
	end
end


function shockwave.onDrawNPC(v)
	if v.despawnTimer <= 0 then
		return
	end

	local texture = Graphics.sprites.npc[v.id].img

	if texture == nil then
		return
	end


	local config = NPC.config[v.id]
	local data = v.data

	if not data.initialized then
		initialise(v,data,config)
	end


	local priority = -45
	if config.foreground then
		priority = -15
	end

	local width = config.gfxwidth
	local height = config.gfxheight*data.heightMultiplier

	local x = v.x + (v.width - width)*0.5 + config.gfxoffsetx
	local y = v.y + v.height - height + config.gfxoffsety

	--customCamera.drawQuadToScene(args,texture,priority,x,y,width,height,0,v.animationFrame*config.gfxheight)
	Graphics.drawImageToSceneWP(texture,x,y,0,v.animationFrame*config.gfxheight,width,height,priority)
	
	-- Debug
	--Colliders.getHitbox(v):draw()

	npcutils.hideNPC(v)
end


return shockwave