forked from Mirrors/openclonk
318 lines
6.4 KiB
C
318 lines
6.4 KiB
C
/*--
|
|
Melee weapons
|
|
Author: Zapper
|
|
|
|
Generic weapon template
|
|
--*/
|
|
|
|
|
|
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 FxDelayTranslateVelocityTimer(pTarget, effect, iEffectTime)
|
|
{
|
|
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);
|
|
}
|
|
|
|
func FxIntWeaponChargeStop(pTarget, effect, iReason, iTemp)
|
|
{
|
|
if (iTemp) return;
|
|
if (!pTarget) return;
|
|
if (this)
|
|
{
|
|
this->StopWeaponAnimation(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;
|
|
}
|
|
|
|
func FxIntWeaponChargeHitByWeapon(pTarget, effect)
|
|
{
|
|
return this->~HitByWeapon(...);
|
|
}
|
|
|
|
func FxIntIsBeingStruckStart(pTarget, effect, iTemp, iDamage, angle, object from)
|
|
{
|
|
if (iTemp) return;
|
|
effect.delay = 3;
|
|
effect.damage = iDamage;
|
|
effect.angle = angle;
|
|
effect.from = from;
|
|
effect.from_player = NO_OWNER;
|
|
if (from)
|
|
effect.from_player = from->GetOwner();
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
pTarget->SetXDir(Sin(effect.angle, effect.damage), 100);
|
|
pTarget->SetYDir(-Abs(Cos(effect.angle, effect.damage)), 100);
|
|
|
|
// in case the object is flung down a cliff
|
|
if (effect.from_player != NO_OWNER)
|
|
pTarget->SetKiller(effect.from_player);
|
|
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()
|
|
{
|
|
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 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 ApplyShieldFactor(pFrom, pTo, damage)
|
|
{
|
|
// totally prevent the strike?
|
|
if (pTo->~QueryCatchBlow(pFrom)) return 100;
|
|
|
|
var state = 0;
|
|
var shield = -1;
|
|
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++))
|
|
{
|
|
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, nil, 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, object from)
|
|
{
|
|
from = from ?? this;
|
|
AddEffect("IntIsBeingStruck", pTo, 2, 1, nil, GetID(), strength, angle, from);
|
|
}
|
|
|
|
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)
|
|
{
|
|
angle += 360;
|
|
a += 360;
|
|
angle = BoundBy(angle, a - iLimited, a + iLimited);
|
|
}
|
|
|
|
pTarget->SetXDir(Sin(angle, speed), 100);
|
|
pTarget->SetYDir(-Cos(angle, speed), 100);
|
|
}
|