--rosalina.lua
--v1.0.1
--Created by Horikawa Otane, 2015
--Contact me at https://www.youtube.com/subscription_center?add_user=msotane

local defs = require("expandedDefines")
local vectr = require("vectr")
local colliders = require("colliders")
local starman;
if(not isOverworld) then
	starman = require("NPCs/ai/starman")
end
local pm = require("playerManager")

local rosalina = {}

local canJump = true
local hasStar = false --No free stars
local inStar = false

local preRosaCoins = 0;
local rosaCoins = 0;

local lumatarget = pm.registerGraphic(CHARACTER_ROSALINA, "lumatarget.png")
local lumabase = pm.registerGraphic(CHARACTER_ROSALINA, "star_base.png")
local lumafill = pm.registerGraphic(CHARACTER_ROSALINA, "star_fill.png")
local lumacolorbase = pm.registerGraphic(CHARACTER_ROSALINA, "star_color.png");
local starbitcounter = pm.registerGraphic(CHARACTER_ROSALINA, "starbit.png");
local lumacolor = Graphics.getPixelData(pm.getGraphic(CHARACTER_ROSALINA, lumacolorbase));
for k,v in ipairs(lumacolor) do
	lumacolor[k] = v/255;
end

Graphics.registerCharacterHUD(CHARACTER_ROSALINA, Graphics.HUD_HEARTS, nil, { coins = starbitcounter } )

local coinTable = {}
coinTable[274] = 20;
coinTable[258] = 2;
coinTable[138] = 2;
coinTable[88] = 2;
coinTable[33] = 2;
coinTable[10] = 2;
coinTable[103] = 2;
coinTable[152] = 2;
coinTable[251] = 2;
coinTable[252] = 2;
coinTable[253] = 2;


local finalLuma = pm.registerGraphic(CHARACTER_ROSALINA, "luma.png")


local targettedNPC;
local hasFoundPeterPan = false

local projectileType = {}
projectileType[3] = 13
projectileType[6] = 291
projectileType[7] = 265

local firstRun = true
local listOfBombs = {}
local dropCounter = 0

function pm.onCostumeChange(playerID, newCostume)
	if(playerID == CHARACTER_ROSALINA) then
		lumacolor = Graphics.getPixelData(pm.getGraphic(CHARACTER_ROSALINA, lumacolorbase));
		for k,v in ipairs(lumacolor) do
			lumacolor[k] = v/255;
		end
	end
end


local function tableSortCat(a, b)
	if a.y > b.y then
		return true
	elseif a.y < b.y then
		return false
	else
		return a.x < b.x
	end
end

local function findMePeterPan(rDirection)
	local x1 = math.floor(player.x) - player.screen.left
	local y1 = math.floor(player.y) - player.screen.top
	local x2 = x1 + 800
	local y2 = y1 + 600
	local localNpcList = NPC.getIntersecting(x1, y1, x2, y2)
	local realNpcList = {}
	for i, j in pairs(localNpcList) do
		if (j.isValid and NPC.HITTABLE_MAP[j.id] and j.id ~= 17 and j.id ~= 18 and not j.friendly and j:mem(0x124, FIELD_BOOL) and not j:mem(0x64, FIELD_BOOL) and not j.isHidden) then
			table.insert(realNpcList, j)
		end
	end
	if #realNpcList ~= 0 then
		table.sort(realNpcList, tableSortCat)
		local targetIndex = 1;
		if(targettedNPC ~= nil and targettedNPC.isValid) then
			for i=1,#realNpcList do
				if(realNpcList[i] == targettedNPC) then
					targetIndex = i;
					break;
				end
			end
		end
		targetIndex = targetIndex + rDirection
		if targetIndex > #realNpcList then
			targetIndex = 1
		end
		if targetIndex < 1 then
			targetIndex = #realNpcList
		end
		targettedNPC = realNpcList[targetIndex]
		hasFoundPeterPan = true
	else
		hasFoundPeterPan = false
	end
end

function rosalina.onInitAPI()
	registerEvent(rosalina, "onKeyDown", "onKeyDown", false)
	registerEvent(rosalina, "onInputUpdate", "onInputUpdate", false)
	registerEvent(rosalina, "onTick", "onTick", false)
	registerEvent(rosalina, "onJump", "onJump", false)
	registerEvent(rosalina, "onJumpEnd", "onJumpEnd", false)
	registerEvent(rosalina, "onDraw", "onDraw", false)
	registerEvent(rosalina, "onNPCKill", "onNPCKill", false)
end

local function cleanUpBombs()
	for _, checkFireball in pairs(listOfBombs) do
		if not checkFireball.isValid then
			checkFireball = nil
		end
	end
end

local function getBombs()
	for _, fireball in pairs(NPC.get(projectileType[player.powerup], player.section)) do
		butts = fireball
		table.insert(listOfBombs, butts)
	end
end

function rosalina.onKeyDown(keycode)
	if (player.character == CHARACTER_ROSALINA) then
		if (keycode == KEY_JUMP) or (keycode == KEY_SPINJUMP) then
			if (canJump) then
				player.speedY = -8
				playSFX(1)
				canJump = false
			end
		end
		if (keycode == KEY_SEL) then
			if (player.powerup == 3 or player.powerup == 7) then
				findMePeterPan(1)
			end
			if (player.powerup == 6) then
				gotBombs = NPC.get(projectileType[player.powerup], player.section)
				if #gotBombs >= 1 then
					local bomb = gotBombs[1]
					bomb.data.drop = true
				end
				--for _, fireball in pairs(NPC.get(projectileType[player.powerup], player.section)) do
					--butts = fireball
					--butts.data.drop = true
				--end
			end
		end
		if (keycode == KEY_RUN) then
			if (not inStar) and (hasStar) then
				hasStar = false
				mem(0x00B2C5A8, FIELD_WORD, 0);
				starman.startTheStar()
			end
		end
		if hasFoundPeterPan then
			if player.keys.dropItem == KEYS_DOWN then
				if (keycode == KEY_RIGHT) then
					findMePeterPan(1)
				end
				if (keycode == KEY_LEFT) then
					findMePeterPan(-1)
				end
			end
		end
	end
end

local function handleJumps()
	if (player:mem(0x146, FIELD_WORD) == 0) and (player:mem(0x48, FIELD_WORD) == 0) then
		if player:mem(0x40, FIELD_WORD) ~= 3 then
			if not hasJumped then
				canJump = true
				hasJumped = true
			end
		else
			canJump = false
			hasJumped = false
		end
		if  player.keys.jump == KEYS_DOWN or player.keys.altJump == KEYS_DOWN then
			if player.speedY > 0.2 then
				player.speedY = 0.2
			end
			--Sparkle
			player:mem(0x02, FIELD_WORD, -1)
			--Hover timer
			player:mem(0x1C, FIELD_WORD, -1)
		end
	else
		canJump = false
		hasJumped = false
		--No Sparkle
		player:mem(0x02, FIELD_WORD, 0)
	end
end

local function drawStarPower()
		local coins = mem(0x00B2C5A8, FIELD_WORD)
		if(hasStar) then
			coins = 100;
		end
		local x,y = 576,24;
		local p = (coins/100);
		local c = math.ceil(#lumacolor*0.25);
		c = math.min(4*math.floor(p*c + 0.5) + 1, #lumacolor-3);
		p = 1-p;
		Graphics.drawImageWP(pm.getGraphic(CHARACTER_ROSALINA,lumabase), x, y, 5);
		Graphics.glDraw {
		vertexCoords={x+6,y+6+(32*p),x+32+6,y+6+(32*p),x+32+6,y+32+6,x+6,y+32+6},
		primitive=Graphics.GL_TRIANGLE_FAN,
		textureCoords={0,p,1,p,1,1,0,1},
		texture=pm.getGraphic(CHARACTER_ROSALINA,lumafill),
		color={lumacolor[c+2],lumacolor[c+1],lumacolor[c],lumacolor[c+3]},
		priority=5
						}
	if hasStar then
		Graphics.drawImageWP(pm.getGraphic(CHARACTER_ROSALINA,finalLuma), x+4, y+4, 5);
	else
		--for i, v in pairs(coinTable) do
		--	if coins >= v.coinLowerValue and coins < v.coinUpperValue then
		--		Graphics.drawImage(v.coinFile, 580, 25);
		--		break
		--	end
		--end
	end
end

function rosalina.onDraw()
	if(player.character == CHARACTER_ROSALINA) then
		if (player.powerup == 3 or player.powerup == 7) then
			if hasFoundPeterPan and targettedNPC.isValid then
				Graphics.drawImageToSceneWP(pm.getGraphic(CHARACTER_ROSALINA,lumatarget), targettedNPC.x + .5 * targettedNPC.width - 24, targettedNPC.y - 37, -25)
			end
		end
		if hasStar then
			mem(0x00B2C5A8, FIELD_WORD,0);
		end
		drawStarPower()
	end
end

local function handleProjectiles()
	if(player:mem(0x13E,FIELD_WORD) == 0) then
		if (player.powerup == 3 or player.powerup == 7) then
			if hasFoundPeterPan and targettedNPC.isValid then
				for _, fireball in pairs(NPC.get(projectileType[player.powerup], player.section)) do
					fireball.speedX = 0
					fireball.speedY = -.21
					local direction = vectr.v2(targettedNPC.x + targettedNPC.width*0.5 - fireball.x, targettedNPC.y + targettedNPC.height*0.5 - fireball.y):normalise() * 3
					fireball.x = fireball.x + direction.x
					fireball.y = fireball.y + direction.y
				end
			end
		elseif player.powerup == 6 then
			cleanUpBombs()
			for _, fireball in pairs(listOfBombs) do
				if fireball.data.drop == nil and fireball.isValid then
					fireball.speedX = 0
					fireball.speedY = -.21
				end
			end
		end
		if dropCounter == 20 and projectileType[player.powerup] ~= nil then
			for _, fireball in pairs(NPC.get(projectileType[player.powerup], player.section)) do
				butts = fireball
				butts.data.drop = true
				if(player.holdingNPC == fireball) then
					player:mem(0x154,FIELD_WORD,0);
				end
			end
		end
		--Check if there are stil targets on screen.
		if hasFoundPeterPan then
			findMePeterPan(0)
		end
	end
end

function rosalina.onNPCKill(event, npc, reason)
	if(player.character == CHARACTER_ROSALINA) then
		if(reason == 9 and (colliders.collide(player,npc) or colliders.speedCollide(player,npc))) then
			if(coinTable[npc.id] ~= nil) then
				local newCoinCount = mem(0x00B2C5A8, FIELD_WORD) + coinTable[npc.id] - 1;
				if newCoinCount >= 100 then
					mem(0x00B2C5A8, FIELD_WORD, 0)
					hasStar = true
				else
					mem(0x00B2C5A8, FIELD_WORD, newCoinCount)
				end
			--[[elseif (npc.id == 258 or npc.id == 138 or npc.id == 88 or npc.id == 33 or npc.id == 10 or npc.id == 103 or npc.id == 152 or npc.id == 251 or npc.id == 252 or npc.id == 253) then
				if not hasStar and mem(0x00B2C5A8, FIELD_WORD) >= 99 and not inStar then
						hasStar = true
						mem(0x00B2C5A8, FIELD_WORD, 0)
					end]]
			end
		end
	end
end

local pressedRun = false;

function rosalina.onInputUpdate()
	if player.character == CHARACTER_ROSALINA then
		pm.winStateCheck()
		if(not Misc.isPaused()) then
			if(player.runKeyPressing or player.altRunKeyPressing) then
				if(not pressedRun) then
					if(player.powerup == PLAYER_HAMMER and player.holdingNPC == nil and player.altRunKeyPressing) then
						local n = NPC.spawn(projectileType[PLAYER_HAMMER], player.x+player.width*0.5, player.y, player.section);
						n.x = n.x-n.width*0.5;
						table.insert(listOfBombs,n);
						player:mem(0x154, FIELD_WORD, NPC.count());
						n:mem(0x12C,FIELD_WORD,1);
						Audio.playSFX(23)
					end
					pressedRun = true;
				end
			else
				pressedRun = false;
			end

			if player.dropItemKeyPressing then
				dropCounter = dropCounter + 1
			else
				dropCounter = 0
			end
		else
			pressedRun = true;
		end
	end
end

local function setPlayerSettings()
	--Princess hover is available
	player:mem(0x18, FIELD_WORD, -1)
	--Star sparkling effect on player
	player:mem(0x02, FIELD_WORD, -1)
	--Holding jump button
	player:mem(0x1A, FIELD_WORD, 0)
end

function rosalina.onTick()
	if (player.character == CHARACTER_ROSALINA) then
		if Level.winState() == 0 then
			if(player.powerup == PLAYER_HAMMER) then
				player:mem(0x160,FIELD_WORD,2);
			end
			cleanUpBombs()
			handleProjectiles()
			setPlayerSettings()
			handleProjectiles()
			handleJumps()
		end
	end
end

function rosalina.onJump()
	if (player.character == CHARACTER_ROSALINA) then
		canJump = true
	end
end

function rosalina.onJumpEnd()
	if (player.character == CHARACTER_ROSALINA) then
		canJump = false
	end
end

function rosalina.initCharacter()
	-- CLEANUP NOTE: This is not safe if a level makes it's own use of jumpheight
	Defines.jumpheight = 7
	Defines.jumpheight_bounce = 8

	preRosaCoins = mem(0x00B2C5A8, FIELD_WORD);
	mem(0x00B2C5A8, FIELD_WORD, rosaCoins);
end

function rosalina.cleanupCharacter()

	-- CLEANUP NOTE: This is not safe if a level makes it's own use of jumpheight
	Defines.jumpheight = nil
	Defines.jumpheight_bounce = nil

	Graphics.sprites.hardcoded["33-2"].img = nil;

	rosaCoins = mem(0x00B2C5A8, FIELD_WORD);
	mem(0x00B2C5A8, FIELD_WORD, preRosaCoins);

	-- CLEANUP NOTE: This is not quite safe for various reasons...
	--mem(0x00B2C8C0, FIELD_WORD, 0)
end

function rosalina.resetjump()
  canJump = true
end

return rosalina
