//****************************************************************************
// SPHERE by : Menasoft ©1997-2015
// www.sphereserver.net
// All SPHERE script files and formats are copyright Menasoft & Partners.
// This file may be freely edited for personal use, but may not be distributed
// in whole or in part, in any format without express written permission from
// Menasoft & Partners.  All donations and contributions
// become the property of Menasoft & Partners.
//****************************************************************************
// FILE LAST UPDATED: Friday, Jan 16, 2015
//
VERSION=0.56c

[EVENTS e_combat_system]
ON=@HitCheck
call f_combat_hit <src>
src.f_combat_gethit=<local.dam>,<argn2>


[function f_combat_hit]			// We get the hit state.
if (<src.IsItem>)						// This should not happen, but I cannot hit items.
	return -1
endif
if !(<src> || <src>==<uid> )			// I cannot hit the 'air' or myself.
	return -1
endif
// I cannot damage if I'm dead, stoned, freezed or sleeping, same if the target is dead, invul o stoned or has less than 1 hit point (this last should not happen ... just a safecheck).
serv.log combat_hit <name>
if ( (<flags>&statf_dead) || (<flags>&statf_stone) || (<flags>&statf_freeze) || (<flags>&statf_sleeping) || (<src.flags>&statf_dead) || (<src.flags>&statf_invul) || (<src.flags>&statf_stone ) || <src.hits> < 1  ) ) 
	return -1
endif
if (<region.safe> || <src.region.safe>)								// I cannot hit if my region is safe or the target is on a safe region...
	return -1 
endif
if (<region.nopvp> || <src.region.nopvp>)							// ... same for nopvp regions.
	if ((<memoryfindtype.memory_ipet.link.isplayer> || <isplayer>) && (<src.memoryfindtype.memory_ipet.link.isplayer> || <src.isplayer>) )
		return -1
	endif
endif
local.dist=<src.distance>											// Storing the distance between me and my target.
if (<local.dist>> 31)												// if Distance > Radar view distance.
	if (<serv.CombatFlags>&0200 || <Swing>!=SWING_SWINGING)			// 0200 = COMBAT_STAYINRANGE.
		return -1													// If Combat_StayInRange is not set and our swing state != preparing. Stop.
	endif
endif
if (!<serv.CombatFlags>&040 && <region.flags>&region_flag_ship)		// 040 = AllowHitFromShip. If not Combat_AllowHitFromShip and my region is a ship.
	if (<region.uid>!=<src.region.uid>)								// and target's region is not mine ( hence i'm hitting outside the ship)...
		sysmessage <defmsg.COMBAT_OUTSIDESHIP>						// Stop.
		return -1
	endif
endif
if (<CanSee <src>>)													// If I can see my target.
																	// And my target is being ridden (should not happen) or ! CanSeeLos (Ignoring windows if i'm shooting).
	if ( (<src.brain> && <src.flags>&statf_ridden) || !<CanSeeLosFlag <src>,<qval ( <Action>==archery || <action>==throwing )? LOS_NB_WINDOWS : 0>>)
		if ( !<serv.CombatFlags>&200 || <Swing>!=SWING_SWINGING)	// I'm going to stop (unless i'm preparing to hit and Combat_StayInRange is not set).
			argn1 SWING_READY
			return 1
		endif
		argn1 SWING_EQUIPPING
		return 1
	endif
else
	if ( !<serv.CombatFlags>&200 || <Swing>!=SWING_SWINGING)		// same here but without LOS check.
		argn1 SWING_READY
		return 1
	endif
	argn1 SWING_EQUIPPING
	return 1
endif
if ( (<brain>==brain_guard) && (<src.flags>&statf_conjured) )				// I'm a Guard, don't waste my time with stupid summons!!!
	src.remove
	argn1 SWING_EQUIPPING
	return 1
endif
if ( (<serv.CombatFlags>&02) && <isplayer>)							// 02 = COMBAT_FACECOMBAT. If I must face in combat and I'm a player (so NPCS doesn't have to face).
	local.dir=<dir <src>>
	if ( <local.dir> != <dir> && <local.dir> != (<dir>-1) && <local.dir> !=(<dir>+1) )	// Check if I'm looking to the target or dir = dir +1 || dir -1 ( Vision angle ).
		argn1 SWING_READY
		return 1
	endif
endif
argn2=dam_physical													// Creating argn2: dam_flags
if (<weapon>)
	if (<weapon.tag0.override.damagetype>)							// IF my weapon has special dmg flags ...
		argn2 = <weapon.tag.override.damagetype>					// I use them.
	elseif ( <weapon.type>==t_weapon_sword || <weapon.type>==t_weapon_axe || <weapon.type>==t_weapon_throwing )
		argn2 |=dam_slash											// Setting flag for these weapons
	elseif ( <weapon.type>==t_weapon_fence || <weapon.type>==t_weapon_bow || <weapon.type>==t_weapon_xbow )
		argn2 |=dam_pierce											// Same here
	endif
	
	if (<IsSkillRanged <action>>)									// If my action is a ranged one ( Archery or Throwing ).
		local.mindist=<qval <weapon.rangel> ? <weapon.rangel> : -1 >	// Storing the min possible distance.
		local.maxdist=<qval <weapon.rangeh> ? <weapon.rangeh> : -1 >	// Storing the max possible distance.
		if (<local.mindist> < 0)										// If stored distance doesn't meet a min required we use the default's standard.
			local.mindist = <serv.ArcheryMinDist>
		endif
		if (<local.maxdist> < 1 )										// Same for max distance.
			local.maxdist = <serv.ArcheryMaxDist>
		endif
		
		if ( <local.dist> > <local.maxdist )							// If my target is far than my weapon's max distance...
					
			if ( !<serv.CombatFlags>&200 || <Swing>!=SWING_SWINGING)	// and I'm not preparing to hit or not Combat_StayInRange
				argn1 SWING_READY
				return 1
			endif
			argn1 SWING_EQUIPPING
			return 1
		endif
		
		if (<flags>&statf_hasshield)									// This should never happen, just a safecheck.
			sysmessage=<defmsg.ITEMUSE_BOW_SHIELD>
			action=0
			argn1 -1
			return 1
		endif
		
		if ( <local.dist> < <local.mindist> )				
			sysmessage=<defmsg.COMBAT_ARCH_TOOCLOSE>					// I am so close to shoot a hit, stop.
			anim=9
			argn1 SWING_EQUIPPING
			return 1
		endif
		if !(<isgm>)
			reveal -1													// I reveal myself if i'm not GM.
		endif
		if !(<serv.CombatFlags>&01)										// COMBAT_NODIRCHANGE
			face <src>													// If no COMBAT_NoDirChange I face the enemy.
		endif
		local.ammotype = <qval <weapon.ammotype> ? <weapon.ammotype> : <fixedid <tdata3>>	// Setting the ammo id we are going to use, if the weapon doesn't have one specified with AmmoType we use TDATA3
		if (<def0.<local.ammotype>>)											// If arrow exist then we perform checks, if not ... weapon doesn't require ammo.
			local.cont=<qval <weapon.ammocont> ? <weapon.ammocont> : <uid> >	// AmmoCont is used here to set the container for the ammo.
			ref200=<findcont.<local.cont>.findid.<local.ammotype>>				// Store the ammo UID if any.
			if (!<ref200>)														// Check if there's ammo
				if (<isplayer>)													// If I'm a player and I don't have ammo: stop
					sysmessage=<defmsg.COMBAT_ARCH_NOAMMO>
					action=0
					return -1
				// else															// Uncommenting these 2 lines will make npcs stop using ranged skills if they don't have ammo.
					// return -1
				endif			
			endif
		endif
		if ( <argn1> == SWING_READY )
			if ( <local.dist> > <local.maxdist> )
				argn1 SWING_READY
				return 1
			endif
			if !(<IsGM>)
				reveal
			endif
			if !(<serv.CombatFlags>&01)	//COMBAT_NoDirChange
				face <src>
			endif
			local.time = <GetWeaponSwingTimer>
			argn1=<local.time>
			FullTrigger @HitTry	// I force the trigger and using call will make sure that code is stopped if there's a return  in the trigger.
			if (<local.return> == 1)
				return -1
			endif
			local.time = <argn1>
			
			argn1 = SWING_SWINGING
			tag.fight_moved=0
			if (<serv.CombatFlags>&04)	//Combat_PreHit
				tag.lasthit = <local.time> + <serv.time>
				anim 9
				timerd = 1
			else
				timerd = <local.time> / 2
				anim 9	// ,<local.time>/10
			endif
			return 1
		endif
		
		//BEGIN HIT
		local.color=<qval <weapon.ammoanimhue> ? <weapon.ammoanimhue> : <ref200.color> >	// I use color stored in weapon, if any, or the ammo one.
		local.anim=<qval <weapon.ammoanim> ? <weapon.ammoanim> : <weapon.tdata4> >			// I use the animation of weapon.AmmoAnim or the default in TDATA4.
		local.render=<qval <weapon.ammoanimrender> ? <weapon.ammoanimrender> ? 0 >			// If my weapon have some special AmmoAnimRender I use it.
		if (<local.ammotype>)																// If I had ammo to use...
			serv.newdupe <ref200>
			new.attr |= attr_invis
			new.timerf 20,remove
			new.cont=<findlayer.21>
			local.arrow=<new>
			consume 1 <ref200.baseid>														// I consume it.
		endif
		src.effect 0,<local.anim>,5,16,0,<local.color>,<local.render>						// I shoot the 'arrow'
		argn1 SWING_EQUIPPING
		return 0
	else	// Not ranged skill
		if ( <serv.CombatFlags>&04 && <Swing>==SWING_READY )
			local.diff = <tag0.lasthit> - <serv.time>
			if (<local.diff> > 0)
				local.diff = <qval <local.diff> > 50 ? 50 : <local.diff> >
				timerd = <local.diff>
				argn1 SWING_READY
				return 1
			endif
		endif
		local.mindist = <weapon.rangel>
		local.maxdist = <max <range>,<weapon.rangeh>>
		if ( <local.dist> < <local.mindist> || <local.dist> > <local.maxdist> )
			if ( !<serv.CombatFlags>&0200 || <swing>!=SWING_SWINGING )
				argn1 SWING_READY
				return 1
			endif
			argn1 SWING_EQUIPPING
			return 1
		endif
		if ( <swing> == SWING_READY )
			if ( <local.dist> > <local.maxdist> )
				argn1 SWING_READY
				return 1
			endif
			if !(<IsGM>)
				reveal
			endif
			if !(<serv.CombatFlags>&01)	//COMBAT_NoDirChange
				face <src>
			endif
			local.time = <GetWeaponSwingTimer>
			argn1=<local.time>
			FullTrigger @HitTry	// I force the trigger and using call will make sure that code is stopped if there's a return  in the trigger.
			if (<local.return>==1)
				return -1
			endif
			local.time = <argn1>
			
			swing = SWING_SWINGING
			tag.fight_moved=0
			if (<serv.CombatFlags>&04)	//Combat_PreHit
				tag.lasthit = <local.time> + <serv.time>
				anim 9
				timerd = 1
			else
				timerd = <local.time> / 2
				anim 9	// ,<local.time>/10
			endif
			return 1
		endif
		if !(<serv.CombatFlags>&01)										// COMBAT_NODIRCHANGE
			face <src>													// If no COMBAT_NoDirChange I face the enemy.
		endif
		if !(<IsGM>)
			reveal
		endif
	endif
	swing = SWING_SWINGING
	tag.fight_moved = 0
	local.time = <getswingtimer>
	timerd = <local.time> / 2
	local.weight = <min <qval <weapon> ? <weapon.weight> : 1 >, 10 >
	stam -=<local.weight>
	if ( <ActDiff> < 0 )
		local.sound_miss = <qval <weapon.tag0.override.sound_miss> ? <weapon.tag.override.sound_miss> : 0 >
		argo = <weapon>
		FullTrigger @HitMiss
		if (<local.return>==1)
			return -1
		endif
	endif
	if ( <ActDiff> < 0 )	// Calling it again in case the trigger had change it.
		if ( <IsSkillRanged <action> > )
			local.sound = <qval <local.sound> ? <local.sound> : <qval <r0,1>==1 ? 0233 : 0238 > >
			sound = <local.sound>
			if ( <local.arrow> )
				ref10=<local.arrow>
				if ( <r5> )
					ref10.attr &=~attr_invis
					ref10.p=<src.p>
				else
					ref10.remove
				endif
			endif
			argn1 SWING_EQUIPPING
			return 1
		endif
		local.sound = <qval <local.sound> ? <local.sound> : <eval { 0238 1, 0239 1, 023a 1} > >
		sound = <local.sound>
		if (<detail>)
			sysmessagef="<defmsg.COMBAT_MISSS>",<src.name>
		endif
		if (<src.detail>)
			src.sysmessagef="<defmsg.COMBAT_MISSO>",<name>
		endif
		argn1 SWING_EQUIPPING
		return 1
	endif
	if ( <src.action> == healing )
		src.action -1
		src.sysmessage=<defmsg.HEALING_INTERRUPT>
	endif
	
	local.dam=<CalcDamage 0>
	local.swing=<argn1>
	argn1=<action>
	FullTrigger @SkillSuccess
	//SkillTrigger @Success
	argn1=<local.dam>
	fulltrigger @Hit
	argn2 |=DAM_FIXED	// Damage has been properly set, no need of default checks so DAM_FIXED make Sphere skip internal checks.
	if (<local.return>==1)
		return -1
	endif
	if ( <local.arrow> && <r2> ) // Small chance for the arrow to be placed in backpack instead of the ground
		src.bounce <local.arrow>
	endif
	if ( !<src.region.nopvp> && !<IsPlayer> && ! <src.IsPlayer> )
		SkillUseQuick <action>
	endif
	if ( <local.sound> > 0 )
		sound = <local.sound>
	endif
	if ( <weapon> )
		if ( <weapon.morex> == 20 )	// Poisoned weapon
			if ( <r100> < <weapon.morez> )
				local.poison = <r<weapon.morez>>
				src.SetPoison <eval <local.poison> * 10 >,<eval <local.poison> / 5>, <uid>
				weapon.more -= <local.poison>
				weapon.resendtooltip
			endif
			weapon.damage=<eval <local.dam> / 4 >,<src>
		endif
	else
		if ( <brain> == BRAIN_MONSTER && <poisoning> > 30.0 && <r100> < <poisoning> )
			src.SetPoison <r<poisoning>>, <r<poisoning>/50>,<uid>
		endif
	endif
	src.skillgain <argn1>,<actdiff>
endif

[function GetWeaponSwingTimer]
if ( <weapon> )
	local.speed=<qval <tag0.override.speed> ? <tag.override.speed> : <weapon.speed> >
	if ( <local.speed> )
		local.waittime = <eval (<serv.SpeedScaleFactor> * 10 ) / (<max <dex>+100,1> * <local.speed>)>
		return <qval <local.waittime> > 5 ?5:<dlocal.waittime>>
	endif
endif
if (<brain>==brain_guard)
	return 1
endif
// Base speed is just your DEX range=40 to 0
local.waittime = <muldiv (100-<dex>),40,100>
if ( <local.waittime> < 5 )	// no-one needs to be this fast.
	local.waittime = 5
else
	local.waittime +=5 // why this 'free' increase of wait time?
endif
// Speed also effected by strength
// This is only reached if weapon.speed = 0 and !weapon.tag.override.speed, correct?
if (<weapon>)
	local.weaponwait = (<weapon.weight>*10) / 40
	if (<weapon.twohands>)// 2 handed is slower
		local.weaponwait += <local.waittime>/2
	endif
else
	local.waittime +=2
endif
return <dlocal.waittime>

[function SetPoison]
// argn1 = Poison strenght
// argn2 = duration
// argn3 = src
if ( <flags>&statf_conjured )	// No poison for conjured creatures.
	return 0
endif
if ( <flags>&statf_poisoned )	// If already poisoned, charges get updated (but not strenght)
	findid.i_rune_poison.more2 += <argv2>
	return 0
endif
sysmessage=<defmsg.JUST_BEEN_POISONED>
if ( <flags>&statf_freeze )
	flags &=~statf_freeze
endif
spelleffect s_poison,<argv1>,<argv3>
new.more2=<argv2>
return 1



[function f_combat_gethit]			// GetHit
if (<flags>&statf_invul)
	effect 3,14265,9,30
	return 1
elseif (<flags>&statf_stone)
	effect 3,14265,9,30
	return 1
elseif (<region.safe>)
	effect 3,14265,9,30
	return 1
elseif ( (<region.nopvp>) && ((<src.IsPlayer>) || (<src.memoryfindtype.memory_ipet.link.isplayer>)) )
	effect 3,14265,9,30
	return 1
elseif (<flags>&statf_dead)
	return 1
endif
	
local.dam=<argn1>
if (<serv.CombatFlags>&00008)	// Combat_Use_Resistance
	if (<argn2>&dam_physical)
		local.damcount ++
	endif
	if (<argn2>&dam_pierce)
		local.damcount ++
	endif
	if (<argn2>&dam_slash)
		local.damcount ++
	endif
	if (<argn2>&dam_poison)
		local.damcount ++
		local.temppoison ++
	endif
	if (<argn2>&dam_energy)
		local.damcount ++
		local.tempenergy ++
	endif
	if (<argn2>&dam_cold)
		local.damcount ++
		local.tempcold ++
	endif
	if (<argn2>&dam_fire)
	//if (<serv.chardef.<baseid>.can>&mt_fire_immune)	// Old check, can is also stored in dynamic characters, not only chardef.
		if ( <can>&mt_fire_immune )
			if !( <argn2>& DAM_PHYSICAL || <argn2>& DAM_PIERCE || <argn2>& DAM_SLASH || <argn2>& DAM_POISON || <argn2>& DAM_ENERGY || <argn2>& DAM_COLD )		// if the damage type is fire only 
				return 1	// no dmg
			endif
			// local.dmg /=2 	// this is the default code
			local.tmpfire = 0	// but this makes more sense.
		else
			local.damcount ++
			local.tempfire ++
		endif
	endif
	if (<local.damcount>==7)	// if all damages are present, bonus dmg.
		local.damcount ++
	endif
	
	local.temppoison *= <argn> / <local.damcount>
	local.tempfire *= <argn> / <local.damcount>
	local.tempcold *= <argn> / <local.damcount>
	local.tempenergy *= <argn> / <local.damcount>
	
	if ( (<local.temppoison>+<local.tempfire>+<local.tempcold>+<local.tempenergy>) < <local.dam> )
		local.dam -= (<local.temppoison>+<local.tempfire>+<local.tempcold>+<local.tempenergy>)
	else
		local.dam = 0
	endif
	
	local.fire +=<local.tempfire>
	local.cold +=<local.tempcold>
	local.energy +=<local.tempenergy>
	local.poison +=<local.temppoison>
endif
local.fire -= <muldiv <local.fire>,<resfire>,100>
local.cold -= <muldiv <local.cold>,<rescold>,100>
local.energy -= <muldiv <local.energy>,<resenergy>,100>
local.poison -= <muldiv <local.poison>,<respoison>,100>

if (<local.dam> < 0 && <local.fire> < 0 && <local.cold> < 0 && <local.energy>< 0 && <local.poison>< 0 )
	return 1
endif
if ( <src.Weapon> && <serv.CombatFlags>&00080 && (<argn2>&DAM_PHYSICAL || <argn2>&DAM_PIERCE || <argn2>&DAM_SLASH)) )		// COMBAT_OSIDAMAGEMOD  
	local.mod = 0
	local.modtemp = 0 
	// Begin bonus section
	if ( <src.weapon.type>==t_weapon_axe || <weapon.type>==t_weapon_sword )
		local.modtemp = <src.lumberjacking>/50
		if (<src.lumberjacking> > 100.0)
			local.modtemp +=10
		endif
	endif
	local.mod +=<local.modtemp>
	
	local.modtemp=<src.tactics>/16
	if (<src.tactics>> 100.0)
		local.modtemp +=6
	endif
	local.mod +=<local.modtemp>
	
	local.modtemp=<src.anatomy>/16
	if (<src.anatomy>> 100.0)
		local.modtemp +=5
	endif
	local.mod += <local.modtemp>
	
	local.modtemp=<src.str>/3
	if (<src.str> > 100 )
		local.modtemp += 5
	endif
	local.mod += <local.modtemp>
	
	local.dam += <local.dam> * (<local.mod>/100)	// local.dam += <local.dam> * current bonus /100
	// End bonus section
endif 

local.dam =  <local.dam> + <local.fire> + <local.energy> + <local.cold> + <local.poison>

argn1=<local.dam>
FullTrigger @GetHit
if (<local.return> == 1)
	return 1
endif
if ( (<argn2>&dam_energy || <argn2>&dam_physical || <argn2>&dam_fire || <argn2>&dam_pierce || <argn2>&dam_slash || <argn2>&dam_magic ) && !(<argn2>&dam_nounparalyze))
	if (<flags>&statf_freeze)
		findid.i_rune_paralyze.remove
	endif
endif
if ( <argn2>&dam_physical || <argn2>&dam_pierce || <argn2>&dam_slash) )
	if (<flags>&statf_hidden)
		flags &= ~statf_hidden
	endif
	if ( (<flags>&statf_reactive) && !(<argn2>&dam_god) )
		if !( (<src> == <uid>) || (<src.brain>==brain_guard) || (<distance> > 2) )	// We shouldn't reflect dmg to ourselves or guards or targets with distance > 2
			local.effect=<f_value_getlinear <magery>,100.0,<serv.spell.s_reactive_armor.effect>>	// We asume max magery skill = 100.0
		endif
		local.effect=<medium <0,<local.effect>,(<local.dam>-1)>
		
		// make sure the reflected damage is between 0 and local.Dam-1 or else
		// 2 reactive armour users could get caught in an infinite loop of
		// reflecting damage
		if (<local.effect> > 0)
			local.dam -=<local.effect>
			src.damage <local.effect>,<uid>,<argn2>
			TRYSRC <src> effect 3,14154,9,6
		endif
	endif
	//armor calculations
	if !(<argn2>&dam_god)
		if !(<argn2>&dam_general)
			local.armor=<r<max (<armor>+<modar>),0>>
			local.dmg=<OnTakeDmg <local.dam>,<src>,<argn2>>		// fixme iDmg = OnTakeDamageHitPoint( iDmg, pSrc, uType );
			if (<serv.MagicFlags>&04)	// MAGICF_IGNOREAR 
				local.armor = 0
			else
				local.armor /=2
			endif
		local.dmg -= <local.armor>
		elseif !(<serv.MagicFlags>&04 || <argn2>&dam_magic)
			local.dmg -=<r<<armor>+<serv.chardef.<baseid>.armor>>>
		endif
	endif
endif
//FixMe
// from here i'll add DAM_FIXED so the sphere itself handles the rest of code, which not all can be scriptable right now (the parts with FIXME)

// FIXME src.AttackedBy <uid>

// local.id=<attacker.id <src>>
// if !( <local.id>)
	// attacker.add <src>
	// local.id=<attacker.id <src>>
// endif
// attacker.<dlocal.id>.dam += <local.dam>
// attacker.<dlocal.id>.elapsed = 0
// attacker.<dlocal.id>.threat += <local.dam>

// if (<local.dam> > 10 )
	// local.blood=<r4650,4655>
// elseif (<r<local.dam>> > 5)
	// local.blood=5701
// endif
// if ( (<local.blood> && (<argn2>&dam_pierce || <argn2>&dam_slash) && !(<flags>&statf_conjured) )
	// serv.newitem=<local.blood>
	// new.attr=attr_decay|attr_move_never
	// new.timer=7
// endif
// hits -= <local.dam>
// anim = 20
//fixme add/remove/update memorys
//fixme @Death/@DeathCorpse + @Kill triggers
// return 1
argn2 |=dam_fixed


[function OnTakeDmg]
// This function is called when every check is already done, the damage is calculated and the dam is going to come.
// The body part which is going to be hit is checked in this function.
// Deflect some damage with shield or weapon ?
if !( <argv2>&DAM_GENERAL )
	return <argv0>
endif
local.dam=<argv0>
if ( ( <flags>&STATF_HASSHIELD ) && ( ( <argv2>&DAM_PHYSICAL ) || ( <argv2>&DAM_PIERCE ) || ( <argv2>&DAM_SLASH ) ) && !( ( <argv2>&DAM_GOD ) || ( <argv2>&DAM_ENERGY ) ) )
	ref1=<findlayer.2>
	if ( <ref1.type>==t_shield && <SkillUseQuick Parrying,<r<qval <src>!=<uid>? <src.tactics>/10:100>>> )
		local.def=<r<ref1.Armor_GetDefense>/2>
		local.hitscur=<ref1.hits>
		ref1.damage=<min <local.dam>,<local.def>>,<argv1>,<argv2>
		if ( <hits> < <local.hitscur> )
			sysmessage = <defmsg.COMBAT_PARRY>
		endif
		local.dam -= <local.def>
	endif
endif
if ( <can>&MT_NONHUM )
	return <dlocal.dam>
endif
// Where was the hit ?
local.HitRoll = <r100>	// determine area of body hit
local.HitArea = 0		// 0 = HEAD

local.HitPref = <qval <src.tag0.HitPreference> ?<src.tag.HitPreference>:0>
local.HitPrefChance = <qval <src.tag0.HitPreference_Chance>?<src.tag.HitPreference_Chance>:<src.tactics>>
local.HitPrefPenalty = <qval <src.tag0.HitPreference_Penalty>?<src.tag0.HitPreference_Penalty>:30>	// Percent
local.HitPrefBonus	= <qval <src.tag0.HitPreference_Bonus>?<src.tag0.HitPreference_Bonus>:30>	// Percent

if ( ( <serv.CombatFlags>&02000 ) && ( <local.HitPref>!=0 ) && ( ( <argv2>&DAM_PHYSICAL ) || ( <argv2>&DAM_PIERCE ) || ( <argv2>&DAM_SLASH ) ) && !( ( <argv2>&DAM_GOD ) || ( <argv2>&DAM_ENERGY ) ) )
	if (<r1100> < <local.HitPrefChance> )
		while ( <local.HitPref> > 7 )	// Here the default body parts are used, if you are planing to extend it ... place a check for bodies, ie: if body == dragon, must be higher than 7 and lower than 14?
			local.HitPref -= 7			// We lower it until we get a useable value.
		end
		local.HitArea=<local.HitPref>-1
		local.dam += (<local.dam>*<local.HitPrefBonus>)/100
	else
		local.dam += (<local.dam>*<local.HitPrefPenalty>)/100
		src.sysmessage=<defmsg.COMBAT_TARGET_MISSED>
		while ( <local.hitarea> <= 7 && <local.hitroll> > 0 )
			local.HitRoll -= <Armor_GetCoverageZone <local.hitarea>>
			local.hitarea ++
		end
	endif
else
	while ( <local.hitarea> <= 7 && <local.hitroll> > 0 )
		local.HitRoll -= <Armor_GetCoverageZone <local.hitarea>>
		local.hitarea ++
	end
endif
if ( ( ( <argv2>&DAM_PHYSICAL ) || ( <argv2>&DAM_PIERCE ) || ( <argv2>&DAM_SLASH ) ) && !( ( <argv2>&DAM_GOD ) || ( <argv2>&DAM_ENERGY ) ) )
	if ( <detail> || <src.detail> )
		local.rMsg=<r3>
		doswitch <local.hitarea>
			local.tMsg=combat_hit_head
			local.tMsg=combat_hit_neck
			local.tMsg=combat_hit_back
			local.tMsg=combat_hit_chest
			local.tMsg=combat_hit_arms
			local.tMsg=combat_hit_hands
			local.tMsg=combat_hit_legs
			local.tMsg=combat_hit_feet
		enddo
		if ( <argv0> > 10 && ( <local.hitarea>==ARMOR_HEAD || <local.hitarea>==ARMOR_CHEST ) )
			local.rMsg +=3
		endif
		local.selfmsg=<local.tMsg><dlocal.rMsg>o
		local.targmsg=<local.tMsg><dlocal.rMsg>s
		if (<detail>)
			sysmessagef=<defmsg.<local.selfmsg>>,<src.name>
		endif
		if (<src.detail>)
			src.sysmessagef=<defmsg.<local.targmsg>>,<name>
		endif
	endif
endif
if ( ( <serv.MagicFlags>&04 ) && ( <argv2>&DAM_MAGIC ) ) //MAGICF_IGNOREAR. No need to check the following if we don't need it.
	return <dlocal.dam>
endif
local.maxcoverage=0
for 0 24
	ref1=<findlayer.<local._for>>
	if (<ref1>)
		if (<ref1.morex>)
			if (<ref1.morex> == s_SteelSkin || <ref1.morex> == s_StoneSkin || <ref1.morex> == s_Arch_Prot || <ref1.morex> == s_Protection )
				local.maxcoverage <max <local.maxcoverage>,<f_value_getlinear <morez>,<serv.skillclass.skillclass_undeclared.magery>,<serv.spell.<ref1.morex>.effect>> >
			endif
		endif
		for zone 0 7
			if (<ref1.armor_IsCoverageZone <local.zone>>)
				if ( <serv.CombatFlags>&01000 )	// COMBAT_STACKARMOR
					local.maxcoverage +=<ref1.armor_getdefense>
				else
					local.maxcoverage = <max <local.maxcoverage>,<ref1.armor_getdefense> >
				endif
				ref1.damage=<local.dam>,<argv1>,<argv2>
			endif
		endfor
	endif
endfor
local.dam -=<r<local.maxcoverage>>

return <dlocal.dam>
[DEFNAME body_parts]		
// These are the current hit parts.
ARMOR_HEAD 			= 0
ARMOR_NECK 			= 1
ARMOR_BACK			= 2
ARMOR_CHEST			= 3	// or thorax
ARMOR_ARMS			= 4
ARMOR_HANDS			= 5
ARMOR_LEGS			= 6
ARMOR_FEET			= 7

// Following ones are not being used, but can give some ideas for extending the actual hit system.

// BODYPART_LEGS2		=8	// Alternate set of legs (spider)
// BODYPART_TAIL		=9	// Dragon, Snake, Alligator, etc. (tail attack?)
// BODYPART_WINGS		=10	// Dragon, Mongbat, Gargoyle
// BODYPART_CLAWS		=11	// can't wear any gloves here!
// BODYPART_HOOVES		=12	// No shoes
// BODYPART_HORNS		=13	// Bull, Daemon

// BODYPART_STALKS		=14	// Gazer or Corpser
// BODYPART_BRANCHES	=15	// Reaper.
// BODYPART_TRUNK		=16	// Reaper.
// BODYPART_PSEUDOPOD	=17	// Slime
// BODYPART_ABDOMEN	=18	// Spider or insect. asusme throax and chest are the same.
	

[function Armor_GetCoverageZone]
if ( <argn>==ARMOR_BACK )
	return <max <Armor_GetCoverageLayer LAYER_SHIRT,<argn>>,<Armor_GetCoverageLayer LAYER_CHEST,<argn>>,<Armor_GetCoverageLayer LAYER_TUNIC,<argn>>,<Armor_GetCoverageLayer LAYER_CAPE,<argn>>,<Armor_GetCoverageLayer LAYER_ROBE,<argn>>>
elseif ( <args> == ARMOR_FEET )
	return <max <Armor_GetCoverageLayer LAYER_SHOES,<argn>>,<Armor_GetCoverageLayer LAYER_LEGS,<argn>>>
elseif ( <args> == ARMOR_LEGS )
	return <max <Armor_GetCoverageLayer LAYER_PANTS,<argn>>,<Armor_GetCoverageLayer LAYER_SKIRT,<argn>>,<Armor_GetCoverageLayer LAYER_HALF_APRON,<argn>>,<Armor_GetCoverageLayer LAYER_ROBE,<argn>>,<Armor_GetCoverageLayer LAYER_LEGS,<argn>>>
elseif ( <args> == ARMOR_CHEST )
	return <max <Armor_GetCoverageLayer LAYER_SHIRT,<argn>>,<Armor_GetCoverageLayer LAYER_CHEST,<argn>>,<Armor_GetCoverageLayer LAYER_TUNIC,<argn>>,<Armor_GetCoverageLayer LAYER_ROBE,<argn>>>
elseif ( <args> == ARMOR_NECK )
	return <Armor_GetCoverageLayer LAYER_COLLAR,<argn>>
elseif ( <args> == ARMOR_ARMS )
	return <max <Armor_GetCoverageLayer LAYER_ARMS,<argn>>,<Armor_GetCoverageLayer LAYER_ROBE,<argn>>,<Armor_GetCoverageLayer LAYER_CAPE,<argn>>>
elseif ( <args> == ARMOR_HANDS )
	return <Armor_GetCoverageLayer LAYER_GLOVES,<argn>>
elseif ( <args> == ARMOR_HEAD )
	return <Armor_GetCoverageLayer LAYER_HELM,<argn>>
endif
return 0

[function Armor_IsCoverageZone]
if ( <args> == ARMOR_BACK )
	return <eval ( (<layer>==LAYER_SHIRT) || (<layer>==LAYER_CHEST) || (<layer>==LAYER_TUNIC) || (<layer>==LAYER_CAPE) || (<layer>==LAYER_ROBE))>
elseif ( <args> == ARMOR_FEET )
	return <eval (<layer>==LAYER_SHOES || <layer>==LAYER_LEGS )>
elseif ( <args> == ARMOR_LEGS )
	return <eval (<layer>==LAYER_PANTS || <layer>==LAYER_SKIRT || <layer>==LAYER_HALF_APRON || <layer>==LAYER_ROBE || <layer>==LAYER_LEGS)>
elseif ( <args> == ARMOR_CHEST )
	return <eval (<layer>==LAYER_SHIRT || <layer>==LAYER_CHEST || <layer>==LAYER_TUNIC || <layer>==LAYER_ROBE )>
elseif ( <args> == ARMOR_NECK )
	return <eval (<layer>==LAYER_COLLAR )>
elseif ( <args> == ARMOR_ARMS )
	return <eval (<layer>==LAYER_ARMS || <layer>==LAYER_ROBE || <layer>==LAYER_CAPE )>
elseif ( <args> == ARMOR_HANDS )
	return <eval (<layer>==LAYER_GLOVES )>
elseif ( <args> == ARMOR_HEAD )
	return <eval (<layer>==LAYER_HELM )>
endif
return 0

[function Armor_GetCoverageLayer]
// Uncommenting the first line will make the system calc the percentaje of armor for armor + modar*GetcoveragePercent (body area),100 (Old Style) instead of ResPhysical when hitting body parts.
return <eval <findlayer.<argv0>.armor> +<findlayer.<argv0>.modar>>

// Here we have the % of armor coverage for each body zone
[function Armor_GetCoveragePercent]
if ( <argn>==ARMOR_BACK )
	return <ddef.coverage_layer_back>
elseif ( <argn>==ARMOR_HEAD )
	return <ddef.coverage_layer_head>
elseif ( <argn>==ARMOR_NECK )
	return <ddef.coverage_layer_collar>
elseif ( <argn>==ARMOR_CHEST )
	return <ddef.coverage_layer_chest>
elseif ( <argn>==ARMOR_ARMS )
	return <ddef.coverage_layer_arms>
elseif ( <argn>==ARMOR_HANDS )
	return <ddef.coverage_layer_gloves>
elseif ( <argn>==ARMOR_LEGS )
	return <ddef.coverage_layer_legs>
elseif ( <argn>==ARMOR_FEET )
	return <ddef.coverage_layer_feet>
endif

[DEFNAME armor_coverages]
coverage_layer_head=10
coverage_layer_neck=5
coverage_layer_back=10
coverage_layer_chest=30
coverage_layer_arms=10
coverage_layer_hands=10
coverage_layer_legs=20
coverage_layer_feet=5

[function Armor_GetDefense]
if !( <IsArmor> )
	return 0
endif
local.val = <armor> + <modar>
local.repair = <GetRepairPercent>
local.val = <muldiv <local.val>,<local.repair>,100>
if ( <attr>&ATTR_MAGIC )
	local.repair = <f_value_getlinear <morey>,<serv.skillclass.skillclass_undeclared.magery>,<serv.spell.s_enchant.effect>
	local.val += <local.repair>
	if ( <local.val> < 0 )
		local.val = 0
	endif
endif
return <dlocal.val>

[function medium]
return <qval <argv0>><argv1> ? <argv0> : <qval <argv2>< <argv1> ? <argv2> : <argv1>>>

	
[function f_value_getlinear]
// arg0 = actual value
// arg1 = max posible value
// arg2-5 = values to calculate
// example: <f_Value_GetLinear <magery>,<serv.skillclass.<skillclass>.magery>,<serv.spell.s_reactive_armor.effect>> will return the current value for your magery skill at this spell.
local.SegSize=0
local.LoIdx=0

local.skill=<argv0>
args=<streat <args>>
local.max=<argv0>
args=<streat <args>>
local.Qty = <argv>
doswitch <local.Qty>
	return 0	// no values defined !
	return <eval (<args>*<local.skill>)/<local.max>>
	local.SegSize=1000
	begin
	if ( <local.skill> >= 500 )
		local.LoIdx = 1
		local.skill -= 500
	endif
	local.SegSize = 500
	end
enddo
if (<local.qty>>3)
	local.LoIdx = <MULDIV <local.skill>, <local.Qty>, 1000 >
	local.Qty --
	if ( <local.LoIdx> >= <local.Qty> )
		local.LoIdx = <local.Qty> - 1
	endif
	iSegSize = 1000 / <local.Qty>
	local.skill -= ( <local.LoIdx> * <local.SegSize> )
endif
local.LoVal = <argv<dlocal.LoIdx>>
local.HiVal = <argv<eval <local.LoIdx>+1>>
if (<local.HiVal> < <local.LoVal>)
	local.HiVal = <local.LoVal>
endif
local.Chance = <local.LoVal> + <MULDIV <eval <local.HiVal> - <local.LoVal>>, <local.skill>, <local.SegSize> >

if ( <local.Chance> <= 0 )
	return 0 // less than no chance ?
endif

return <dlocal.Chance>


[function CalcDamage]
// argn1 = 0 = normal damage.
// argn1 = 1  = random damage.
if ( <brain> == BRAIN_GUARD && <serv.GuardsInstantKill> )
	return <src.maxhits> + 10000
endif
local.ret=1
if ( <serv.CombatFlags>&080 )	// Combat_OsiDamageMod
	if ( <IsSkillRanged <action> > )
		local.ret += <qval <argn1> == 1 ? <r<dex>> : <dex> > / 10
	else
		local.ret += <qval <argn1> == 1 ? <r<str>> : <str> > / 10
	endif
endif
if ( <weapon> )
	local.ret += <weapon.WeaponCalcDamage <argn1>>
else
	local.ret += <dam.lo>
	local.ret += <qval <argn1> == 1 ? <r<dam.hi>> : <dam.hi> >
endif
if ( <local.ret> < 0 )
	local.ret = 0
endif
return <dlocal.ret>


[function WeaponCalcDamage]
local.ret=<dam.lo> + <modar>
local.ret += <qval <argn1> == 1 ? <r<dam.hi>> : <dam.hi> >
local.ret = <muldiv <local.ret>,<GetRepairPercent>,100>
if ( <attr>&attr_magic && !<type>==t_wand )
	local.ret += <f_Value_GetLinear <more2>,<serv.skillclass.0.magery>,<serv.spell.s_enchant.effect>>
endif
if ( <local.ret> < 0 )
	local.ret = 0
endif
return <dlocal.ret>


[function GetRepairPercent]
if ( !<MaxHits> || ( <MaxHits> < <Hits> ) )
	return 100
endif
return <muldiv <hits>,100,<MaxHits> >


[function fixedid]
local.flags=<tdata3>
local.flags &=~0ffffffff9c000000
return <local.flags>


[function IsSkillRanged]
if !(<def0.<args>>)
	return 0
endif
return <qval <args>==archery ? 1 : <qval <args>==throwing ? 1 : 0>>





[EOF]