--------------------------------------------------------------
-- Universal server script for all pet digs. 
-- 
-- created by brandi 3/2/10
-- updated abeechler ... 6/30/11 - free trial pre-con check
--------------------------------------------------------------

local digData = 
{ 	-- FORMAT: PD_Normal = 	{digLOT = LOT # of this object, 
	--						 spawnLOT = LOT # of thing to spawn(-1 = dont use), 
	--						 spawnMission = MissionID needed to spawn an object from this dig(-1 = dont use), 
	--						 bSpecificPet = bool if this uses a specific pet, 
	-- 						 bXBuild = bool if this is an X build, 
	--						 bBouncer = bool if this spawns a bouncer, 
	--						 bBuilderOnly = bool if the person who build the pet dig is the only one who can use it},
	PD_Normal = 	{digLOT = 3495, spawnLOT = -1, spawnMission = -1, bSpecificPet = false, bXBuild = false, bBouncer = false, bBuilderOnly = false},
	PD_PetCove = 	{digLOT = 7612, spawnLOT = -1, spawnMission = -1,  bSpecificPet = false, bXBuild = false, bBouncer = false, bBuilderOnly = false},
	PD_GF_Flag = 	{digLOT = 7410, spawnLOT = -1, spawnMission = -1,  bSpecificPet = false, bXBuild = true, bBouncer = false, bBuilderOnly = false},
	PD_GF_Crab = 	{digLOT = 9308, spawnLOT = 7694, spawnMission = -1,  bSpecificPet = false, bXBuild = false, bBouncer = false, bBuilderOnly = false},
	PD_AG_Mis = 	{digLOT = 9307, spawnLOT = -1, spawnMission = -1,  bSpecificPet = false, bXBuild = true, bBouncer = false, bBuilderOnly = true},
	PD_AG_Bouncer = {digLOT = 7559, spawnLOT = -1, spawnMission = -1,  bSpecificPet = false, bXBuild = false, bBouncer = true, bBuilderOnly = false},
	PD_CP_Dragon = 	{digLOT = 13098, spawnLOT = 13067, spawnMission = 1298,  bSpecificPet = false, bXBuild = false, bBouncer = false, bBuilderOnly = false},
	PD_CP_Bone = 	{digLOT = 12192, spawnLOT = -1, spawnMission = -1,  bSpecificPet = true, bXBuild = false, bBouncer = false, bBuilderOnly = false},
}
				
local specificPetLOTs = {}
local missionRequirements = {}

function setPetVariables(passedspecificPetLOTs,passedmissionRequirements)
	specificPetLOTs = passedspecificPetLOTs
	missionRequirements = passedmissionRequirements	
end

function onStartup(self)
	baseStartup(self)
end

function baseStartup(self, newMsg)	
	local objLot = self:GetLOT().objtemplate
	local digInfo = {}
	
	-- set the digType for later use
	for type, data in pairs(digData) do
		if data.digLOT == objLot then
			self:SetVar("digType", type)
			digInfo = data
			
			break
		end
	end
	
	if not digInfo.digLOT  then
		digInfo = digData.PD_Normal
	end
	
	if digInfo.bBouncer then -- if the treause node is one that digs up a pet bouncer 
		local bouncerNumber = self:GetVar("BouncerNumber") -- set in HF
		local petbouncer = LEVEL:GetSpawnerByName("PetBouncer"..bouncerNumber)
		local petbouncerswitch = LEVEL:GetSpawnerByName("PetBouncerSwitch"..bouncerNumber)

		-- on startup, deactivate and reset the spawner networks for the pet bouncer and pet switch
		petbouncer:SpawnerDeactivate()
		petbouncerswitch:SpawnerDeactivate()
		petbouncer:SpawnerReset()
		petbouncerswitch:SpawnerReset()			
	end	
end 

function onCheckUseRequirements( self, msg )
	local player = msg.objIDUser
	local pet = player:GetPetID().objID
	local digInfo = digData[self:GetVar("digType")] or digData.PD_Normal
	
	-- Free trial status check
    local preConVar = self:GetVar("CheckPrecondition")
    
    if preConVar and preConVar ~= "" then
        local check = msg.objIDUser:CheckListOfPreconditionsFromLua{PreconditionsToCheck = preConVar, requestingID = self}
        
        if not check.bPass then 
            msg.bCanUse = false
            return msg
        end
    end

	-- We don't need to report most of this information unless this check is coming from the UI -- UI_PET_WAIT_MESSAGE
	if player:GetMissionState{missionID = 842}.missionState < 8 then --check mission
		msg.bCanUse = false
	elseif not pet or not pet:Exists() then
		msg.bCanUse = false
	elseif digInfo.bSpecificPet then
		local petLOT = pet:GetLOT().objtemplate
		local IsPet = false
		
		for k,v in ipairs(specificPetLOTs) do
			if v == petLOT then
				IsPet = true
				
				break
			end
		end
				
		if IsPet then
			for k,v in ipairs(missionRequirements) do
				if player:GetMissionState{missionID = v.ID}.missionState == v.state then --check mission
					msg.bCanUse = false
					
					break
				end
			end
		else
			msg.bCanUse = false
		end
	end
	
	-- if the pet isn't on the dig then wait for them.
	if msg.bCanUse and not pet:GetPetHasState{iStateType = 6}.bHasState then
		msg.bCanUse = false		
	end
	
	return msg
end

function onUse(self, msg)
	local petObj = msg.user:GetPetID().objID
	
	-- tell the pet to use the pet dig
	if petObj:Exists() then
		petObj:Use()
	end
end

function notifyChildLoaded(self, other, msg)
	local petObj = msg.childID
	
	-- make sure this is a pet
	if not petObj:GetIsPet().bIsPet then return end
	
	-- make sure this pet is valid for this dig
	if not CheckIsPetOk(self,petObj,other) then return end
	
	-- notify the pet that the player is on a dig
	petObj:NotifyPet{ ObjIDSource = other , ObjToNotifyPetAbout = self , iPetNotificationType = 12 }	
end

function onCollisionPhantom(self, msg)
	-- target is the pet or player or npc that collided with the node volume
	local target = msg.senderID

	if not target:Exists() then return end

	-- when something enters the collision of the node, see if the node has already been claimed and that it is actually alive
	if self:IsDead().bDead == true then return end

	-- check to see if target Is a player, if so notify pet to go to switch
	if target:IsCharacter().isChar == true then
		-- make sure we know if the player brings out a pet
		self:SendLuaNotificationRequest{requestTarget = target, messageName = "ChildLoaded"}
		
		-- see if player has a pet
		local petObj = target:GetPetID().objID
		
		if not petObj or not petObj:Exists() then return end
	
		-- make sure this pet is valid for this dig
		if not CheckIsPetOk(self,petObj,target) then return end

		-- notify the pet that the player is on a dig
		petObj:NotifyPet{ ObjIDSource = target , ObjToNotifyPetAbout = self , iPetNotificationType = 12 }		
	else
	   -- get if the target is a pet
		local isPet = target:GetIsPet()

		-- check to see if the target is a pet and if its is a wild pet
		if ( not isPet.bIsPet or isPet.bIsWild ) then return end
		
		-- already made sure that target is a pet, so get the pets owner
		local petOwner = target:GetParentObj().objIDParent

		-- make sure this pet is valid for this dig
		if not CheckIsPetOk(self,target,petOwner) then return end
		
		-- checks to see if this node was spawned by a X build
		if self:GetVar("builder") then	-- set on load from the X build			
			local petOwnerID = petOwner:GetID()

			-- this is the player that built the Xbuild that spawned the pet node
			local playerID = self:GetVar("builder")

			-- if the pet owner isn't the player who built the X build, their pet can't dig the pet dig, and therefore cant claim the node
			if (petOwnerID ~= playerID) then return end
		end

		-- notify pet that they can dig here
		target:NotifyPet{ ObjIDSource = target , ObjToNotifyPetAbout = self , iPetNotificationType = 6 }
		--set the pet ID as the pet who activated this node
		self:SetVar("activator", target:GetID())
	end	
end

function CheckIsPetOk(self,petObj,petOwner)	
	-- i think this checks to see if the pet is already using an ability
	local petAbility = petObj:GetPetAbilityObject{}

	local digInfo = digData[self:GetVar("digType")] or digData.PD_Normal

	-- check to see if this dig needs a specific pet
	if digInfo.bSpecificPet then			
		local petLOT = petObj:GetLOT().objtemplate
		local bPass = false
		
		-- run through the list of pets and see if this pet is one of them
		for k, lot in ipairs(specificPetLOTs) do
			if petLOT == lot then 
				bPass = true

				break
			end	
		end		
		
		if not bPass then
			return false
		end
		
		-- run through the table of missions and see if the player has completed the correct ones
		for k,v in ipairs(missionRequirements) do
			if petOwner:GetMissionState{missionID = v.ID}.missionState == v.state then --check mission
				return false
			end
		end				
	end
	
	-- this pet is OK
	return true
end

function onOffCollisionPhantom(self, msg)	
	-- target is the pet or player or npc that un-collided with the node volume
	local target = msg.senderID

	if not target:Exists() then return end
	
	-- check if owner needs to notify pet that he/she is not on dig anymore
	if (target:IsCharacter().isChar == true) then
		-- see if player has a pet
		local petObj = target:GetPetID().objID

		if( petObj and petObj:Exists() ) then
			-- if the character stepped off the dig, notify the player's pet
			-- iPetNotification type 15 is PET_NOTIFY_OWNER_OFF_DIG
			petObj:NotifyPet{ ObjIDSource = target , ObjToNotifyPetAbout = self , iPetNotificationType = 15 }
		end
		
		-- dont listen for the player to spawn a pet anymore
		self:SendLuaNotificationCancel{requestTarget= other, messageName="ChildLoaded"}
	end

	-- get if the target is a pet
	local isPet = target:GetIsPet()		
	
	-- check to see if the target is a pet and if its is a wild pet AND if the node was already claimed
	if (not isPet.bIsPet or isPet.bIsWild )  then return end
	
	-- activator is the pet that claimed the node in onCollision
	local activatorID = self:GetVar("activator")
	
	-- check to see if a pet was set as activator and if that pet is the pet that just un- collided with the node
	if ( not activatorID or ( target:GetID() ~= activatorID ) ) then return end
	
	-- Notify pet they've left the pet node and set their state back to normal
	target:NotifyPet{ ObjIDSource = target, ObjToNotifyPetAbout = self, iPetNotificationType = 7 }
end

function onNotifyObject(self, msg)
	-- If treasure node receives notification a pet is digging it up
	if  not ( msg.name == "petdughere" ) then return end

	local petObj = msg.ObjIDSender
	
	if petObj:Exists() then
		local digTime = petObj:GetAnimationTime{animationID = "dig"}.time or 2
		
		-- Ability is done being used, remove using-ability state from pet
		petObj:RemovePetState{iStateType = 9}
		
		-- create a timer for half the animation time to spawn the loot
		GAMEOBJ:GetTimer():AddTimerWithCancel( digTime/2, "dig_" .. petObj:GetID(), self ) 		
	end
end

function CompleteDig(self, petObj)
	-- convoluted way of getting the pet owner based on the message sender
	local petOwner = petObj:GetParentObj().objIDParent	
	-- get the object LOT of the treasure node
	local lot = self:GetLOT().objtemplate

	local digInfo = digData[self:GetVar("digType")] or digData.PD_Normal
	
	-- if the lot is the pet cove pet dig node, go to the achievement function	
	if self:GetVar("PetDig") then	
		PetDigAchievement(self,petOwner)
	end
	
	if digInfo.spawnLOT ~= -1 then
		SpawnPet(self,petOwner)
	-- if the lot is the AG Xbuild
	elseif digInfo.bBuilderOnly then	
		-- get the ID of the player who built the X
		local player = self:GetVar("builder")
		
		-- if the player that tried to dig up the pet dig is not the player who built the X, skip the rest of the script
		if (petOwner:GetID() ~= player) then return	end	
	-- if the lot is the lot of the flag digs in GF, go to the X build function
	elseif digInfo.bXBuild then 
		Xbuild(self,petOwner)
		
		return -- skip the rest of this function		
	-- if the lot is one of the pet bouncer digs, then go to the bouncer dig function
	elseif digInfo.bBouncer then	
		BouncerDig(self,petOwner)	
	end
	
	-- check to see if the player has completed with pet dig acheivement
	local DigMissionState = petOwner:GetMissionState{ missionID = 843 }.missionState

	-- if the player has not completed with mission
	if (DigMissionState == 2) then	
		petOwner:UpdateMissionTask{taskType = "complete", value = 843, value2 = 1, target = self}
	end
	
	petOwner:TerminateInteraction{type = 'user', ObjIDTerminator = petOwner}	
	-- killing the treasure node with violent is what spits out the loot, and the loot shows up for the pet owner
	self:RequestDie{ killType = "VIOLENT" , killerID = petOwner, lootOwnerID = petOwner }
	--tells the client side script that the treasure was dug up
	self:SetNetworkVar("treasure_dug", true)	
	
	local otherPets = self:GetObjectsInPhysicsBounds().objects
	
	if table.maxn(otherPets) == 0 then return end
	
	-- loop through the list of pets in the proximity and tell them to reset their states
	for k,v in ipairs(otherPets) do
		if v:GetIsPet().bIsPet then
			v:RemovePetState{iStateType = 9}
			v:NotifyPet{ ObjIDSource = v, ObjToNotifyPetAbout = self, iPetNotificationType = 7 }
			-- if the character stepped off the dig, notify the player's pet
			-- iPetNotification type 15 is PET_NOTIFY_OWNER_OFF_DIG
			v:NotifyPet{ ObjIDSource = target , ObjToNotifyPetAbout = self , iPetNotificationType = 15 }
		end
	end	
		
	local X = self:GetVar("X") or 0
	
	-- check to see if their is a quick build X, and kills it too
	if X == 0 then return end
	
	GAMEOBJ:GetObjectByID(X):RequestDie{ killType = "VIOLENT" }
end

-- function to spawn a pet on pet dig
function SpawnPet(self,petOwner)	
	local digInfo = digData[self:GetVar("digType")] or digData.PD_Normal
	
	-- if we have a spawn mission but aren't currently on it then dont spawn the pet
	if digInfo.spawnMission ~= -1 and petOwner:GetMissionState{ missionID = digInfo.spawnMission }.missionState < 2 then return end
	
	-- get the location of the pet dig to spawn the pet there
	local mypos = self:GetPosition().pos
	local myRot = self:GetRotation()	
	-- set the config data with the tamer as the pet Owner so only the person who dug the crab can tame it, and add it to a group 
	-- with the pet tamer's ID built in to the name of the group so the pet can be found through script
	local config = { { "tamer", petOwner:GetID() } , { "groupID", "pet"..petOwner:GetID()}, {"spawnAnim", "spawn-pet"}, {"spawnTimer", 1.0}}
	
	-- spawn a pet
	RESMGR:LoadObject { objectTemplate = digInfo.spawnLOT , x = mypos.x , y = mypos.y , z = mypos.z , rw= myRot.w, rx= myRot.x, ry= myRot.y, rz = myRot.z, owner = self, configData = config }
end

-- function to update achievements for doing all the pet digs in Pet Cove
function PetDigAchievement(self,petOwner)
	-- check to see if the player has completed with pet dig acheivement
	local AchievementState = petOwner:GetMissionState{ missionID = 505 }.missionState
	
	-- if the player has not completed with mission
	if (AchievementState == 4) then return end

	local digNum = self:GetVar('PetDig') -- set in HF
	-- use the number of the pet dig to get the player flag number for that pet dig
	local flagNumber = tonumber("126"..digNum)
	
	-- check to see if the player has already dug that particular pet dig before
	if (petOwner:GetFlag{iFlagID = flagNumber}.bFlag == false ) then 	
		--set flag to true so we know the player has alread done this  
		petOwner:SetFlag{iFlagID = flagNumber, bFlag = true} 
		-- update the player's achievement for digging a new pet dig
		petOwner:UpdateMissionTask{taskType = "complete", value = 505, value2 = 1, target = self}	
	end
end

-- function for the flag pet digs in GF
function Xbuild(self,petOwner)
	local playerID = self:GetVar("builder") or 0
	
	if playerID == 0 then return end
	
	local player = GAMEOBJ:GetObjectByID(playerID)

	-- check to make sure the pet owner is still the player who built the X, just another check
	if (petOwner:GetID() ~= player:GetID()) then return end
		
	-- set variable for player flag num
	local PlayerFlagNum = 0
	local groupID = self:GetVar("groupID") -- set in HF
	
	--set the flag number to check/set on the player based on which flag in GF it is. 
	--player flag number set in the database
	if (groupID == "Flag1") then	
		PlayerFlagNum = 61		
	elseif (groupID == "Flag2") then	
		PlayerFlagNum = 62		
	elseif (groupID == "Flag3") then	
		PlayerFlagNum = 63		
	end
	
	--check to see if they player has dug the flag up before
	if not petOwner:GetFlag{iFlagID = PlayerFlagNum}.bFlag then
		-- Ability is done being used, remove using-ability state from pet
		player:GetPetID().objID:RemovePetState{iStateType = 9}
		
		--get the flag based on the group, to change the collision group and visiblity on those scripts
		--assume only one object in group
		local flag = self:GetObjectsInGroup{ group = groupID, ignoreSpawners = true }.objects[1]
		
		--notifies script on the flag L_GF_DUG_FLAG_CLIENT
		flag:NotifyClientObject{ name = "changePhysics" , paramObj = player , rerouteID = player }		
		--set the player flag for this collectible flag so next time the player digs it, he'll get generic pet loot instead
		petOwner:SetFlag{iFlagID = PlayerFlagNum, bFlag = true}  		
		-- it's ok to use Deleteobject because we know this node was spawned through script, and this is a server script
		GAMEOBJ:DeleteObject(self)	
	-- if the player has already gotten this flag, then have the pet dig drop normal pet dig loot
	else	
		--remove the dig state from the pet
		petOwner:GetPetID().objID:RemovePetState{iStateType = 9}		
		-- killing the treasure node with violent is what spits out the loot, and the loot shows up for the pet owner
		self:RequestDie{ killType = "VIOLENT", killerID = petOwner }		
		-- delete this chest immediately so it will not have to wait for the 
		-- RequestDie->Die->Client message chain to complete before disappearing
		-- loot will be generated correctly in the RequestDie call above because 
		-- all the server-side loot generation occurs when Die is handled in the 
		-- call to RequestDie which will complete before we send DeleteObject
		-- it's ok to use Deleteobject because we know this node was spawned through script, and this is a server script
		GAMEOBJ:DeleteObject(self)
	end
	
	local X = self:GetVar("X") or 0
	
	-- check to see if their is a quick build X, and kills it too
	if X == 0 then return end
	
	GAMEOBJ:GetObjectByID(X):RequestDie{ killType = "VIOLENT" }
end

-- function for the pet dig that digs up a pet bouncer and switch
function BouncerDig(self,petOwner)
	local bouncerNumber = self:GetVar("BouncerNumber") -- set in HF
	
	-- check so script doesnt crash because there's no config data set
	if not bouncerNumber then return end
	
	-- spawner networks for the bouncer and switch must be set up like this to work
	local bouncerSpawner = LEVEL:GetSpawnerByName("PetBouncer"..bouncerNumber)
	local switchSpawner = LEVEL:GetSpawnerByName("PetBouncerSwitch"..bouncerNumber)
	
	-- check that there is a spawner network with that name before activating it
	if bouncerSpawner then	
		-- activating the spawner network spawns the bouncer
		--bouncerSpawner:SpawnerReset()
		bouncerSpawner:SpawnerActivate()		
	end
	
	-- check that there is a spawner network with that name before activating it
	if switchSpawner then
		-- activating the spawner network spawns the switch
		--switchSpawner:SpawnerReset()
		switchSpawner:SpawnerActivate()
	end	
end

function onTimerDone(self, msg)
	-- split out the timer
	local tTimer = split(msg.name, "_")
	
	-- if this is the dig timer then check the pet and have the do CompleteDig
	if tTimer[1] == "dig" then
		local petID = tTimer[2] or 0
		
		if petID == 0 then return end
		
		local petObj = GAMEOBJ:GetObjectByID(petID)
		
		if petObj:Exists() then
			CompleteDig(self, petObj)
		end
	end
end

function split(str, pat)
    local t = {}
    
    -- creates a table of strings based on the passed in pattern   
    string.gsub(str .. pat, "(.-)" .. pat, function(result) table.insert(t, result) end)

    return t
end 