forked from Mirrors/openclonk
411 lines
9.8 KiB
C
411 lines
9.8 KiB
C
/*--
|
|
Melee weapons
|
|
Author: Zapper
|
|
|
|
Generic weapon template
|
|
--*/
|
|
|
|
|
|
/*local fDrawn;
|
|
local fAttack;
|
|
local iAnimStrike;*/
|
|
|
|
//local iWeaponChargeType;
|
|
//local hWeaponMesh;
|
|
local hWeaponAnimStrike;
|
|
|
|
func Construction()
|
|
{
|
|
hWeaponAnimStrike = nil;
|
|
return _inherited(...);
|
|
}
|
|
|
|
func CheckStrike()
|
|
{
|
|
return _inherited(...);
|
|
}
|
|
|
|
public func CanStrikeWithWeapon(clonk)
|
|
{
|
|
if(!(clonk->~IsClonk())) return false;
|
|
|
|
if(GetEffect("*WeaponCooldown*", clonk))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(GetEffect("*WeaponCharge", clonk))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
func FxDelayTranslateVelocityStart(pTarget, effect, temp, p1)
|
|
{
|
|
if(temp) return;
|
|
//effect.var0 = p1; // old flinging behavior
|
|
}
|
|
|
|
func FxDelayTranslateVelocityTimer(pTarget, effect, iEffectTime)
|
|
{
|
|
//if(iEffectNumber.var0)
|
|
// if(iEffectTime > iEffectNumber.var0) return -1;
|
|
if(pTarget->GetContact(-1) & CNAT_Bottom) return -1;
|
|
return 1;
|
|
}
|
|
|
|
func FxDelayTranslateVelocityStop(pTarget, effect, reason, temp)
|
|
{
|
|
if(temp) return;
|
|
if(!(pTarget->GetContact(-1) & CNAT_Bottom))
|
|
if(Sqrt(pTarget->GetXDir()**2 + pTarget->GetYDir()**2) > 10)
|
|
pTarget->SetSpeed(pTarget->GetXDir()/3, pTarget->GetYDir()/3);
|
|
}
|
|
|
|
func FxIntWeaponChargeStart(pTarget, effect, iTemp, length)
|
|
{
|
|
if(iTemp) return;
|
|
|
|
// saved velocity
|
|
effect.velocity = 0;
|
|
// save length
|
|
effect.length = length;
|
|
}
|
|
|
|
func FxIntWeaponChargeTimer(pTarget, effect, iEffectTime)
|
|
{
|
|
if(this->Contained() != pTarget) return -1;
|
|
if(!pTarget->~IsWalking() && !pTarget->~IsJumping()) return -1;
|
|
var strikeTime=effect.length;
|
|
if(strikeTime != -1 && iEffectTime > strikeTime)
|
|
{
|
|
this->~WeaponStrikeExpired();
|
|
return -1;
|
|
}
|
|
this->CheckStrike(iEffectTime);
|
|
|
|
/* var x, y;
|
|
var time = Min(iEffectTime, strikeTime);
|
|
var step=(((time*100) / GetStrikeTime()) * 180) / 100;
|
|
x=-Cos(step, 10);
|
|
y=-Sin(step, 6)-3;
|
|
if(GetChargeType() == L_WN_down) y*=-1;
|
|
if(pTarget->GetDir() == DIR_Left) x *= -1;
|
|
CreateParticle("Blast", x, y, 0, 0, 20);
|
|
|
|
var strength = 0;
|
|
if(iEffectTime <= GetStrikeTime())
|
|
strength = (((iEffectTime*100)/GetStrikeTime()) * this->WeaponSharpness()) / 100;
|
|
var bash = EffectCall(pTarget, iEffectNumber, "GetBash");
|
|
var bashAngle = Angle(0, 0, pTarget->GetXDir(), pTarget->GetYDir());
|
|
var found = false;
|
|
for(var obj in FindObjects(Find_AtPoint(x, y), Find_OCF(OCF_Alive), Find_Exclude(pTarget)))
|
|
{
|
|
var b = bash;
|
|
var b2;
|
|
var effect;
|
|
if(effect = GetEffect("IntWeaponCharge", obj))
|
|
if(pTarget->GetDir() != obj->GetDir()) // facing each other
|
|
b2 = EffectCall(0, effect, "GetBash");
|
|
|
|
var xVel=Abs(pTarget->GetXDir());
|
|
if(BoundBy(pTarget->GetXDir(), -1, 1) != BoundBy(obj->GetXDir(), -1, 1))
|
|
xVel+=Abs(obj->GetXDir());
|
|
else xVel-=Abs(obj->GetXDir());
|
|
|
|
var yVel=Abs(pTarget->GetYDir());
|
|
if(BoundBy(pTarget->GetYDir(), -1, 1) != BoundBy(obj->GetYDir(), -1, 1))
|
|
yVel+=Abs(obj->GetYDir());
|
|
else yVel-=Abs(obj->GetYDir());
|
|
b = (b*Sqrt((xVel**2)+(yVel**2)));
|
|
|
|
var dmg = ((2*strength) + b) / 3;
|
|
if(b > strength) dmg = ((2*b) + strength) / 3;
|
|
var angle = 0;
|
|
if(bash != 0) angle = bashAngle;
|
|
dmg = Max(0, dmg - b2);
|
|
|
|
if(dmg)
|
|
AddEffect("IntIsBeingStruck", obj, 1, 1, 0, GetID(), dmg, angle);
|
|
Log("b: %d strength: %d b2: %d dmg: %d xVel: %d yVel: %d", b, strength, b2, dmg);
|
|
found = true;
|
|
}
|
|
|
|
if(found)
|
|
{
|
|
var velocity = Sqrt((pTarget->GetXDir())**2 + (pTarget->GetYDir())**2);
|
|
velocity = Min(1, velocity-1);
|
|
pTarget->SetSpeed(Sin(bashAngle, velocity), -Cos(bashAngle, velocity));
|
|
}
|
|
|
|
if(iEffectTime == GetStrikeTime()+1)
|
|
{
|
|
effect.Interval = 3;
|
|
effect.Time = 0;
|
|
}*/
|
|
}
|
|
|
|
func FxIntWeaponChargeStop(pTarget, effect, iReason, iTemp)
|
|
{
|
|
if(iTemp) return;
|
|
if(!pTarget) return;
|
|
if(this)
|
|
{
|
|
this->StopWeaponAnimation(pTarget);
|
|
//this->DetachWeaponMesh(pTarget);
|
|
this->~OnWeaponHitCheckStop(pTarget);
|
|
}
|
|
|
|
}
|
|
|
|
func FxIntWeaponChargeAddWeaponSlow(pTarget, effect, iStrength)
|
|
{
|
|
effect.slow += iStrength;
|
|
}
|
|
|
|
func FxIntWeaponChargeGetWeaponSlow(pTarget, effect)
|
|
{
|
|
return effect.slow;
|
|
}
|
|
|
|
func FxIntWeaponChargeGetBash(pTarget, effect)
|
|
{
|
|
return 0;
|
|
//return (this->WeaponBash() * Sqrt((pTarget->GetXDir())**2+(pTarget->GetYDir())**2)) / 1000;
|
|
}
|
|
|
|
func FxIntWeaponChargeHitByWeapon(pTarget, effect)
|
|
{
|
|
return this->~HitByWeapon(...);
|
|
}
|
|
|
|
func FxIntIsBeingStruckStart(pTarget, effect, iTemp, iDamage, angle)
|
|
{
|
|
if(iTemp) return;
|
|
effect.delay = 3;
|
|
effect.damage = iDamage;
|
|
effect.angle = angle;
|
|
}
|
|
|
|
func FxIntIsBeingStruckTimer(pTarget, effect, iEffectTime)
|
|
{
|
|
if(effect.delay -- == 0)
|
|
{
|
|
// FALCON PUNCH
|
|
if(pTarget->GetContact(-1) & CNAT_Bottom)
|
|
{
|
|
if(!pTarget->Stuck())
|
|
{
|
|
pTarget->SetPosition(pTarget->GetX(), pTarget->GetY()-1);
|
|
if(pTarget->Stuck()) pTarget->SetPosition(pTarget->GetX(), pTarget->GetY()+1);
|
|
}
|
|
if(effect.damage > 60)
|
|
pTarget->Fling();
|
|
}
|
|
//if(iEffectNumber.var1 > 20) iEffectNumber.var1 = 20;
|
|
pTarget->SetXDir(Sin(effect.angle, effect.damage ), 100);
|
|
pTarget->SetYDir(-Abs(Cos(effect.angle, effect.damage )), 100);
|
|
return -1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
func FxIntIsBeingStruckEffect(string szNewEffectName, object pTarget)
|
|
{
|
|
if(szNewEffectName == "IntIsBeingStruck") return -2;
|
|
return 0;
|
|
}
|
|
|
|
func FxIntIsBeingStruckAdd (object pTarget, effect, string szNewEffectName, int iNewEffectTimer, int damage, int angle)
|
|
{
|
|
// reset delay
|
|
effect.delay = 3;
|
|
|
|
// add damage!
|
|
if(damage > effect.damage)
|
|
effect.damage = damage;
|
|
else
|
|
effect.var1 = (effect.damage*2 + damage) / 2;
|
|
|
|
// check angle
|
|
if(!effect.angle)
|
|
effect.angle = angle;
|
|
else if(angle)
|
|
// should actually set the new angle to the average between the old and the new one. but I don't feel like doing such calculations now
|
|
// let's see if anyone notices it
|
|
effect.angle = angle;
|
|
}
|
|
|
|
func GetStrikeAnimation()
|
|
{
|
|
/*if(iWeaponChargeType == L_WN_straight) return "StrikeArms";
|
|
if(iWeaponChargeType == L_WN_up) return "Strike2Arms";
|
|
if(iWeaponChargeType == L_WN_down) return "Strike3Arms";
|
|
DebugLog("WARNING: L_WN::GetStrikeAnimation() called at the wrong time!");*/
|
|
return "StrikeArms";
|
|
}
|
|
|
|
|
|
func StopWeaponAnimation(pTarget)
|
|
{
|
|
if(hWeaponAnimStrike == nil) return;
|
|
pTarget->StopAnimation(hWeaponAnimStrike);
|
|
hWeaponAnimStrike = nil;
|
|
}
|
|
|
|
func PlayWeaponAnimation(pTarget)
|
|
{
|
|
if(hWeaponAnimStrike != nil) StopWeaponAnimation(pTarget);
|
|
hWeaponAnimStrike = pTarget->PlayAnimation(...);
|
|
}
|
|
|
|
/*func StartWeaponAnimation(pTarget)
|
|
{
|
|
if(hWeaponAnimStrike) StopWeaponAnimation(pTarget);
|
|
hWeaponAnimStrike = pTarget->PlayAnimation(GetStrikeAnimation(), 10, Anim_Linear(0, 0, pTarget->GetAnimationLength(GetStrikeAnimation()), GetStrikeTime(), ANIM_Remove), Anim_Const(1000));
|
|
}*/
|
|
|
|
func GetRelativeVelocity(pObject1, pObject2)
|
|
{
|
|
var b=0;
|
|
var xVel=Abs(pObject1->GetXDir());
|
|
if(BoundBy(pObject1->GetXDir(), -1, 1) != BoundBy(pObject2->GetXDir(), -1, 1))
|
|
xVel+=Abs(pObject2->GetXDir());
|
|
else xVel-=Abs(pObject2->GetXDir());
|
|
|
|
var yVel=Abs(pObject1->GetYDir());
|
|
if(BoundBy(pObject1->GetYDir(), -1, 1) != BoundBy(pObject2->GetYDir(), -1, 1))
|
|
yVel+=Abs(pObject2->GetYDir());
|
|
else yVel-=Abs(pObject2->GetYDir());
|
|
b = Sqrt((xVel**2)+(yVel**2));
|
|
return b;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
func AttachWeaponMesh(pTarget)
|
|
{
|
|
if(hWeaponMesh)
|
|
{
|
|
DetachWeaponMesh(pTarget);
|
|
}
|
|
hWeaponMesh = pTarget->AttachMesh(GetID(), "pos_hand1", "Main", 130);
|
|
}
|
|
|
|
func DetachWeaponMesh(pTarget)
|
|
{
|
|
if(!hWeaponMesh) return;
|
|
pTarget->DetachMesh(hWeaponMesh);
|
|
hWeaponMesh = 0;
|
|
}
|
|
*/
|
|
|
|
|
|
func GetJumpLength(pClonk)
|
|
{
|
|
if(!pClonk->~IsJumping()) return 0;
|
|
var x = pClonk->GetX(), y = pClonk->GetY(), xDir = pClonk->GetXDir(), yDir = pClonk->GetYDir();
|
|
//crash! var l=SimFlight(x, y, xDir, yDir, 0, 0, 100, 0); //SimFlight behavior changed (10/1/10)
|
|
var l=0;
|
|
if(!l) return 50;
|
|
else
|
|
{
|
|
// not a very good approximation. I really think SimFlight should return the number of iterations
|
|
return Sqrt((x - pClonk->GetX()) ** 2 + (y - pClonk->GetY()) ** 2);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
func ApplyShieldFactor(pFrom, pTo, damage)
|
|
{
|
|
// totally prevent the strike?
|
|
if(pTo->~QueryCatchBlow(pFrom)) return 100;
|
|
|
|
var state=0;
|
|
var shield=-1;
|
|
//for(var i = GetEffectCount(0, pTo); i--;)
|
|
for(;state <= 1;state++)
|
|
{
|
|
var effect_name="*Shield*";
|
|
if(state == 1) effect_name="IntWeaponCharge";
|
|
var iEffect;
|
|
var i=0;
|
|
while(iEffect=GetEffect(effect_name, pTo, i++))
|
|
{
|
|
//iEffect = GetEffect("*Shield*", pTo, i);
|
|
//if(!iEffect) iEffect = GetEffect("IntWeaponCharge", pTo, i);
|
|
var s=EffectCall(pTo, iEffect, "HitByWeapon", pFrom, damage);
|
|
if(s && shield == -1) shield=s;
|
|
else if(s)
|
|
{
|
|
shield=(100-(((100-s)*(100-shield))/100));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
if(shield == -1) return 0;
|
|
return shield;
|
|
}
|
|
|
|
func StartWeaponHitCheckEffect(pClonk, iLength, iInterval)
|
|
{
|
|
AddEffect("IntWeaponCharge", pClonk, 10, iInterval, this, 0, iLength);
|
|
}
|
|
|
|
func StopWeaponHitCheckEffect(pClonk)
|
|
{
|
|
if(GetEffect("IntWeaponCharge", pClonk))
|
|
RemoveEffect("IntWeaponCharge", pClonk);
|
|
}
|
|
|
|
func DoWeaponSlow(pClonk, iStrength)
|
|
{
|
|
var e=GetEffect("IntWeaponCharge", pClonk);
|
|
var s=Sqrt( (pClonk->GetXDir(1000)) ** 2 + (pClonk->GetYDir(1000)) ** 2);
|
|
var angle=Angle(0,0,pClonk->GetXDir(), pClonk->GetYDir());
|
|
|
|
s-=iStrength;
|
|
if(s < 0) s=0;
|
|
pClonk->SetXDir(Sin(angle, s), 1000);
|
|
pClonk->SetYDir(-Cos(angle, s), 1000);
|
|
|
|
if(e)
|
|
EffectCall(nil, e, "AddWeaponSlow", iStrength);
|
|
return true;
|
|
}
|
|
|
|
func GetWeaponSlow(pClonk)
|
|
{
|
|
var e=GetEffect("IntWeaponCharge", pClonk);
|
|
if(!e) return 0;
|
|
return EffectCall(nil, e, "GetWeaponSlow");
|
|
}
|
|
|
|
func ApplyWeaponBash(pTo, int strength, angle)
|
|
{
|
|
AddEffect("IntIsBeingStruck", pTo, 2, 1, nil, GetID(), strength, angle);
|
|
}
|
|
|
|
func TranslateVelocity(object pTarget, int angle, int iLimited, int iExtraVelocity)
|
|
{
|
|
var speed=Sqrt((pTarget->GetXDir(100) ** 2) + (pTarget->GetYDir(100) ** 2)) + iExtraVelocity;
|
|
var a=Angle(0, 0, pTarget->GetXDir(), pTarget->GetYDir());
|
|
|
|
if(iLimited)
|
|
{
|
|
//if(Abs(angle-a) > Abs(angle-(a+360)))
|
|
// a=(a+360);
|
|
angle+=360;
|
|
a+=360;
|
|
angle=BoundBy(angle, a-iLimited, a+iLimited);
|
|
}
|
|
|
|
pTarget->SetXDir(Sin(angle, speed), 100);
|
|
pTarget->SetYDir(-Cos(angle, speed), 100);
|
|
}
|