###########################################################
# PlayerProjectile - Railshooter Module
# Contains the class to create the basic player bullet
###########################################################

# DESCRIPTION:
# This Class creates a Projectile shot from the Player's gunDummy's 
# position.  The projectile then travels forward in a straight line
# slowly over time, colliding with any Enemies or Enemy Projectiles.  The 
# projectile will auto-destruct over time and can be changed over time 
# depending on what Power-ups you aquire.  


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

# Import Other Railshooter Modules
import specialEffects
import ClassGlobals
import Level1


########################################
# Player Projectile Class
########################################
class Projectile(DirectObject.DirectObject):
    def __init__(self, bulletNum, playerPos, playerHpr, bulletScale, currentCharge):   

	self.collider = ClassGlobals.collider
	self.bulletNum = str(bulletNum)
	self.bulletScale = bulletScale

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

	self.hasCollided = 0
	self.speed = 450.0	
	self.lifespan = 100

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

	self.startHpr = playerHpr
	
	self.tick = 0
	self.currentTick = 0

	self.bulletDamage = 1.0
	self.prevT = 0


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

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

     	# Add a dummy object for the projectile
	# This object is the one that gets moved around
	self.bullet = self.anchor.attachNewNode('bullet' + self.bulletNum)

        # Load the Projectile Model
 	self.shell = loader.loadModelCopy("Models/effects/regBlast")
	self.shell.setScale(self.bulletScale, self.bulletScale, self.bulletScale)
        self.shell.setHpr(180, 0, 0)
     	self.shell.reparentTo(self.bullet)

	self.rotateBlast = self.shell.hprInterval(0.2, 
				Point3(180, 0, 360), 
				startHpr=Point3(180, 0, 0))
	self.rotateBlast.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.bulletSphere = CollisionSphere(0, 0, 0, self.bulletScale * 5)
        self.collbullet = CollisionNode("collbullet" + self.bulletNum)
        self.collbullet.addSolid(self.bulletSphere)
        self.collision = self.bullet.attachNewNode(self.collbullet)
        # self.collision.show()

	# Set Bitmask for the Bullet
	# Targets need Bitmask 1 to Register a Hit
	self.collbullet.setFromCollideMask(BitMask32.bit(1))

	# Victims with Bitmask 0 Collide with Bullet
	self.collbullet.setIntoCollideMask(BitMask32.bit(0))

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

	# Set the Starting Anchor Point
	self.anchor.setPos(self.startPosX, self.startPosY, self.startPosZ)
	self.anchor.setHpr(self.startHpr)


	########################################
	# Accept Events
	########################################

	self.accept('entercollbullet' + self.bulletNum, self.explode)


    ########################################
    # 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.bullet.getY()
	        pY = pY + dt*self.speed

	        # Set New Projectile Location & Orientation
	        self.bullet.setY(self.anchor, pY)

	    # If the Projectile lasts over 10 seconds, destroy it
	    if self.tick > self.lifespan or ClassGlobals.gameIsOver == 1:
		# 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


    # Destroy the Projectile and Remove its Parts
    def explode(self, collisionEntry):

	# Don't explode if Collided with Player
	if self.bullet.isEmpty() != 1:

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

	    # Destroy the Projectile
	    self.destroy()


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

	self.collider.playerTraverser.removeCollider(self.collision)
 	self.collision.removeNode()
	self.shell.removeNode()
	self.bullet.removeNode()
	self.anchor.removeNode()













