##########################################
# Module:	head_shot.py
# Author:	Dean Peternelj, dean.peternelj@gmail.com
# Date:	2008/25/03
# Version:	1.35 Beta

'''
Script is written by permission of "Scouty", a member of Wookie Clan (http://www.wookie-clan.co.uk/),
who wrote the original script.
Thanks also to e-Gor, a member of Project Reality team (http://www.realitymod.com/) and other guys
from "battlefield 2 editor" forums (http://www.bfeditor.org/forums/),
BF2 Technical Information Wiki (http://bf2.fun-o-matic.org/index.php/Main_Page ),
and to Alan Gauld for his python tutorial (http://www.freenetpages.co.uk/hp/alan.gauld/).

This script is made for Battlefield 2 game and it's intention is to inform player,
if he hit the head of the killed enemy character. When head-shot happens,
message is displayed.
'''
##########################################
#CHANGE LOG

#1.35 Beta - 2008/25/03
#-head-shot info for M95 weapon
#-hs message will now only appear when both victim and attacker are on foot

#1.30 Beta - 2008/25/01
#-fixed head-shot messages on some stationary weapons

#1.25 Beta - 2008/23/01
#-fixed head-shot messages

#1.2 Beta - 2008/22/1
#added option "one bullet for head-shot"
#fixed "head-shot message on artillery kill" bug

#1.1 Beta - 2008/21/01
#added option "can be revived after head-shot"
#bullet damage is set back to original
#server performance improved

#1.0 Beta - 2008/17/01
#first version of script released

##########################################

import bf2
import host

##########################################
#Defaults:
c_msgStyle= 0
c_canBeRevived= 1
c_oneBulletForHS = 0
##########################################
try:
	from head_shot_CONF import c_msgStyle,c_canBeRevived,c_oneBulletForHS
	
except: print "Can not locate c_msgStyle,c_canBeRevived,c_oneBulletForHS vars, proceeding with default values"

def init():
	#register event
	host.registerHandler('PlayerKilled', onPlayerKilled, 1)
	host.registerGameStatusHandler(onGameStatusChanged)
	print "###"
	print "Head-shot module initialised"
	print "Configuration is:"
	print "c_msgStyle %s\nc_canBeRevived %s\nc_oneBulletForHS %s" % (c_msgStyle,c_canBeRevived,c_oneBulletForHS)
	print "###"

#============================================================================
#"CAN BE REVIVED ON KILL" LOGIC
if c_canBeRevived == 1:
	if c_oneBulletForHS == 1:
		def onGameStatusChanged(status):
			templateChange(damageMod=6) 
	
	else:#classic Bf2 bullet damage
		def onGameStatusChanged(status):
			templateChange()

else: #can not be revied
	def onGameStatusChanged(status):
		templateChange(damageMod=25)
#============================================================================
def templateChange(damageMod=3):
		host.rcon_invoke("MaterialManager.createCell 38 25")
		host.rcon_invoke('MaterialManager.damageMod '+str(damageMod))
		host.rcon_invoke("MaterialManager.setEffectTemplate 0 e_bhit_s_sold_head")
		host.rcon_invoke("MaterialManager.setSoundTemplate 0 S_Impact_Flesh")
		host.rcon_invoke("""
						MaterialManager.createCell 38 77
						MaterialManager.damageMod 0.707
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_bodyarmor
						MaterialManager.setSoundTemplate 0 S_Impact_Flesh
						MaterialManager.createCell 38 24
						
						MaterialManager.createCell 38 23
						MaterialManager.damageMod 0.667
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_bodyarmor
						MaterialManager.setSoundTemplate 0 S_Impact_Kevlar_Vest
						
						MaterialManager.createCell 38 24
						MaterialManager.damageMod 1.007
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_limb
						MaterialManager.setSoundTemplate 0 S_Impact_Flesh

						MaterialManager.createCell 39 23
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_bodyarmor
						MaterialManager.setSoundTemplate 0 S_Impact_Kevlar_Vest
						
						MaterialManager.createCell 39 24
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_limb
						MaterialManager.setSoundTemplate 0 S_Impact_Flesh""")
		
						
		host.rcon_invoke("MaterialManager.createCell 39 25")
		host.rcon_invoke('MaterialManager.damageMod '+str(damageMod))
                host.rcon_invoke("MaterialManager.setEffectTemplate 0 e_bhit_s_sold_head")
		host.rcon_invoke("MaterialManager.setSoundTemplate 0 S_Impact_Flesh")
		host.rcon_invoke("""
						
						MaterialManager.createCell 39 77
						MaterialManager.damageMod 0.325
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_bodyarmor
						MaterialManager.setSoundTemplate 0 S_Impact_Flesh

						MaterialManager.createCell 41 23
						MaterialManager.damageMod 0.527
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_bodyarmor
						MaterialManager.setSoundTemplate 0 S_Impact_Kevlar_Vest
						
						MaterialManager.createCell 41 24
						MaterialManager.damageMod 1.007
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_limb
						MaterialManager.setSoundTemplate 0 S_Impact_Flesh
						
						MaterialManager.createCell 41 77
						MaterialManager.damageMod 0.707
						MaterialManager.setEffectTemplate 0 e_bhit_s_sold_bodyarmor
						MaterialManager.setSoundTemplate 0 S_Impact_Flesh """)
						
		host.rcon_invoke("MaterialManager.createCell 41 25")
		host.rcon_invoke('MaterialManager.damageMod '+str(damageMod))
		host.rcon_invoke("MaterialManager.setEffectTemplate 0 e_bhit_s_sold_head")
		host.rcon_invoke("MaterialManager.setSoundTemplate 0 S_Impact_Flesh")
						
		#print "damage mod set to %s" % damageMod

#============================================================================
#CREATE LOWER-CASE WEAPON LIST	
try:

	from hs_weapon_list import allowedWeaponList as tempList
	print "handheldList imported successfully"
	
	weaponList=[]
	
	#LOWER-CASE HANDHELD WEAPON NAMES
	for weapon in tempList:
		weapon=weapon.lower()
		weaponList.append(weapon)
	else: print "Handheld weapons lower-cased"

except:
	print "hs_weapon_list can not be found"
#============================================================================		


#SERVER MESSAGE STYLE LOGIC
#depending on serve-message-style choice, one function is defined.I did this here to avoid branching
#in events

if c_msgStyle == 0:
	def message(attacker="unknownAttacker",victim="unknownVictim"):
		attackerName=attacker.getName()
		victimName=victim.getName()
		#
		message='"'+70*" "+str(attackerName)+" §C1001[HEADSHOT]§C1001 "+str(victimName)+'"'
		host.rcon_invoke('game.sayAll '+message)
else:
	def message(attacker="unknownAttacker",victim="unknownVictim"):
		attackerName=attacker.getName()
		victimName=victim.getName()
		#
		message='"'+str(attackerName)+" §C1001[HEADSHOT]§C1001 "+str(victimName)+'"'
		host.rcon_invoke('game.sayAll '+message)


if c_canBeRevived == 1:
	def onPlayerKilled(victim, attacker, weapon, assists, object):
		#all 3 objects are needed, othervise we can't get hs
		if attacker == None or victim == None or weapon == None:
			#print "attacker and victim and weapon are None, returning"
			return 
			
		#attacker must be "on foot",vehicle kills excluded - This filter can vary, if player gives a kill with vehicle
		#and he jumped out before projectile killed enemy
		if attacker.getVehicle() != attacker.getDefaultVehicle(): 
			#print "Attacker is in vehicle,returning"
			return
		
		#victim must be "on foot"	
		if victim.getVehicle() != victim.getDefaultVehicle(): 
			#print "victim is in vehicle,returning"
			return
			
		#if team-kill happens, head shot isnt valid
		if victim.getTeam() == attacker.getTeam():
			#print "team-kill happened,returning"
			return 

		#check if suicide happened	
		if attacker == victim:
			#print "suicide happened, returning"
			return

		weaponName=weapon.templateName
		weaponName=weaponName.lower()
		
		#check if weapon is allowed
		for weaponStr in weaponList: 
			if weaponName == weaponStr:
				#print "weapon is allowed, proceeding to head-shot"
				break
		
		else: #gets executed if weapon is not found (if "break" isnt executed)
			#print "no allowed weapon found, hs not valid,returning"
			return
	
			
		victimDamage=victim.getDefaultVehicle().getDamage()
		delta=0.1
		alwaysTrigger=1
		data=[victim, attacker,weapon,victimDamage]
		
		#timer needed because isManDown() would return false on player killed event
		bf2.Timer(headShot, delta, alwaysTrigger,data) 


	def headShot(data):
		
		victim=data[0]
		attacker=data[1]
		weapon=data[2]
		victimDmgBeforeKill=data[3]

		try:
			victimDmgAfterKill=(victim.getDefaultVehicle().getDamage())*10.0
		except AttributeError:
			#print "Can not get victimDmgAfterKill, it seems victim is in vehicle,returning"
			return
		except:
			#print "Can not get victimDmgAfterKill,returning"
			return
		
		deltaDamage = abs(victimDmgBeforeKill) + abs(victimDmgAfterKill)
		deltaDamage = round(deltaDamage,3) 
				
		if deltaDamage % 3 == 0.0: 
				message(attacker,victim)
	
else:
	def onPlayerKilled(victim, attacker, weapon, assists, object):

		#all 3 objects are needed, othervise we can't get hs
		if attacker == None or victim == None or weapon == None:
			#print "one of needed objects is none, returning"
			return 
		
		#attacker must be "on foot",vehicle kills excluded - This filter can vary, if player gives a kill with vehicle
		#and he jumped out before projectile killed enemy
		if attacker.getVehicle() != attacker.getDefaultVehicle(): 
			#print "Attacker is in vehicle,returning"
			return
		
		#victim must be "on foot"	
		if victim.getVehicle() != victim.getDefaultVehicle(): 
			print "Victim is in vehicle,returning"
			return
		
		#if team-kill happens, head shot isnt valid
		if victim.getTeam() == attacker.getTeam():
			#print "team-kill happened,returning"
			return 

		#check if suicide happened	
		if attacker == victim:
			#print "suicide happened, returning"
			return

		weaponName=weapon.templateName
		weaponName=weaponName.lower()
		
		#check if weapon is allowed
		for weaponStr in weaponList: 
			if weaponName == weaponStr:
				#print "weapon is allowed, proceeding to head-shot"
				break
		
		else: #gets executed if weapon is not found (if "break" isnt executed)
			#print "not allowed weapon found, hs not valid,returning"
			return
			
		delta=0.1
		alwaysTrigger=1
		data=[victim, attacker,weapon]
		
		#timer needed because isManDown() would return false on player killed event
		bf2.Timer(headShot, delta, alwaysTrigger,data)


	def headShot(data):
		victim=data[0]
		attacker=data[1]
		weapon=data[2]

		victimStatus=victim.isManDown()

		if victimStatus == 0:
			message(attacker,victim)

