###########################################################
# Powerup - Railshooter Module
# Contains the class to create Powerups
###########################################################

# DESCRIPTION:
# This Class creates a Powerup Objects that float towards the player.  
# The Powerup is spawned at the position of the target passed into the
# Constructor.  The effect of the Power-up is determined in the 
# PlayerCraft Class.


from direct.showbase.ShowBaseGlobal import *
from direct.showbase import DirectObject
from direct.task import Task
from pandac.PandaModules import *
import math

# Import Other Railshooter Modules
import specialEffects
import ClassGlobals
import SoundFX
import Level1


########################################
# Player Powerup Class
########################################
class Powerup(DirectObject.DirectObject):
    def __init__(self, powerupType, powerupNum, target):

	self.collider = ClassGlobals.collider
	self.powerupType = powerupType
	self.powerupNum = str(powerupNum)

	########################################
	# Initialize Variables
	########################################
	self.gameSpeed = ClassGlobals.gameSpeed

	self.hasCollided = 0
	self.speed = 10.0
	self.acceleration = 0.5
	self.maxSpeed = 50
	self.lifespan = 1000

	self.tick = 0
	self.currentTick = 0
	self.prevT = 0

	self.startPosX = target.getX(Level1.railDummy)
	self.startPosY = target.getY(Level1.railDummy)
	self.startPosZ = target.getZ(Level1.railDummy)


	########################################
	# Load the Projectile Model
	########################################

	# Dummy object for the bullet to keep track of its starting 
	# Pos and Orientation
	self.pUp = render.attachNewNode('pUp' + self.powerupNum)
	self.pUp.reparentTo(Level1.railDummy)

        # Load the Projectile Model
 	self.shell = loader.loadModelCopy("Models/powerup/Powerup")
	self.shell.setScale(1.5, 1.5, 1.5)
     	self.shell.reparentTo(self.pUp)

	self.rotatePowerup = self.shell.hprInterval(2, 
				Point3(360, 0, 0), 
				startHpr=Point3(0, 0, 0))
	self.rotatePowerup.loop()

	# Create a Blank Light Attribute
	# Results in Object being unaffected by light and
	# glowing as a result
	lightAttributes = LightAttrib.makeAllOff()
	self.shell.node().setAttrib(lightAttributes)

        # Create Player's Collision Sphere
        self.powerupSphere = CollisionSphere(0, 0, 0, 3)
        self.collpowerup = CollisionNode("collpowerup" + self.powerupNum)
        self.collpowerup.addSolid(self.powerupSphere)
        self.collision = self.pUp.attachNewNode(self.collpowerup)
        # self.collision.show()

	# Set Bitmask for the Powerup
	# Targets need Bitmask 1 to Register a Hit
	self.collpowerup.setFromCollideMask(BitMask32.bit(0))

	# Victims with Bitmask 0 Collide with Powerup
	self.collpowerup.setIntoCollideMask(BitMask32.bit(1))

	# Turn on collisions
	self.collider.laserTraverser.addCollider(self.collision, self.collider.collisionEvent)

	# Set the Starting Point for Powerup
	self.pUp.setPos(Level1.railDummy, self.startPosX, self.startPosY, self.startPosZ)

	# Create Effect Trail
	self.effectTrail = specialEffects.ChainSpriteShockwave('powerup', 10, 0, 0.8, 12, self.shell, 1, 1)


	# Add Task to Move Powerup
	taskMgr.add(self.moveProjectile, 'movePowerup')
	
	
	########################################
	# Accept Events
	########################################

	self.accept('entercollpowerup' + self.powerupNum, self.checkCollide)


    ########################################
    # Define Tasks
    ########################################

    # Create a task to Move the Projectile
    def moveProjectile(self, task):

	# If Projectile has not Collided yet
	if self.hasCollided == 0:

	    # Calculate the Current Tick (Game Time)
	    # This makes the game controls independent of Framerate
	    self.currentTick = math.floor(task.time / self.gameSpeed)

	    # If it is a Tick, then Update the World
	    if self.currentTick > self.tick:
	        self.tick = self.currentTick
	    
            	# Get Change in Time
 	    	dt = task.time - self.prevT
            	self.prevT = task.time

  	        # Get Projectile's Coordinates
                pY = self.pUp.getY()
	        pY = pY - dt*self.speed

		# Add Acceleration to Speed
		if self.speed < self.maxSpeed:
		    self.speed += self.acceleration

	        # Set New Projectile Location & Orientation
	        self.pUp.setY(Level1.railDummy, pY)

	    # If the Projectile lasts over 10 seconds, destroy it
	    if self.tick > self.lifespan:
		# End the Task
		self.destroy()
		return Task.done

	    else:
		# Make the task continue
		return Task.cont

	# Else, Projectile is Dead, so End Task
	else:
	    return Task.done


    # Checks for Collision Death
    def checkCollide(self, collisionEntry):

	# Get the CollisionEntry's Name
	incoming = collisionEntry.getFromNode()
	incoming = incoming.getName()

	# Make Sure Powerup Collides only with Player
	if incoming[0:10] == 'collplayer' and (self.pUp.isEmpty() != 1):

	    # Play Sound Effect
	    SoundFX.powup.start()
    
	    # Remove Powerup
	    self.destroy()


    # Destroy the Projectile and Remove its Parts
    def destroy(self):

	# The Powerup has Collided (Mark for Destruction)
	self.hasCollided = 1

	self.collider.laserTraverser.removeCollider(self.collision)
 	self.collision.removeNode()
	self.shell.removeNode()
	self.pUp.removeNode()













