forked from Mirrors/openclonk
292 lines
6.5 KiB
C
292 lines
6.5 KiB
C
/**
|
|
Club
|
|
|
|
Simple striking weapon.
|
|
*/
|
|
|
|
#include Library_MeleeWeapon
|
|
|
|
#include Library_Flammable
|
|
|
|
local animation_set;
|
|
local fAiming;
|
|
|
|
/*-- Engine Callbacks --*/
|
|
|
|
func Initialize()
|
|
{
|
|
ClubChangeHandAnims("R");
|
|
}
|
|
|
|
func Hit()
|
|
{
|
|
Sound("Hits::Materials::Wood::WoodHit?");
|
|
}
|
|
|
|
func ClubChangeHandAnims(string hand)
|
|
{
|
|
if (hand == "R")
|
|
{
|
|
//Changes which (R/L) animation is used
|
|
animation_set = {
|
|
AimMode = AIM_Weight,
|
|
AnimationAim = Format("BatAimArms.R",hand),
|
|
AnimationAim2 = Format("BatAim2Arms.R",hand),
|
|
AimTime = 35 * 3,
|
|
AnimationShoot = Format("BatStrikeArms.R",hand),
|
|
AnimationShoot2 = Format("BatStrike2Arms.R",hand),
|
|
ShootTime = 35 / 2,
|
|
ShootTime2 = (35 / 2) * 6 / 19, // At 6/19 of the shooting animation
|
|
};
|
|
}
|
|
else
|
|
{
|
|
//Changes which (R/L) animation is used
|
|
animation_set = {
|
|
AimMode = AIM_Weight,
|
|
AnimationAim = "BatAimArms.L",
|
|
AnimationAim2 = "BatAim2Arms.L",
|
|
AimTime = 35 * 3,
|
|
AnimationShoot = "BatStrikeArms.L",
|
|
AnimationShoot2 = "BatStrike2Arms.L",
|
|
ShootTime = 35 / 2,
|
|
ShootTime2 = (35 / 2)* 6 / 19, // At 6/19 of the shooting animation
|
|
};
|
|
}
|
|
}
|
|
|
|
/*-- Callbacks --*/
|
|
|
|
public func GetAnimationSet() { return animation_set; }
|
|
|
|
// Callback from the clonk, when he actually has stopped aiming
|
|
public func FinishedAiming(object clonk, int angle)
|
|
{
|
|
clonk->StartShoot(this);
|
|
|
|
// since the Clonk internal callback is only once, we cannot use it
|
|
// ..
|
|
AddEffect("DuringClubShootControl", clonk, 1, 1, this, nil, angle);
|
|
|
|
// aaaand, a cooldown
|
|
AddEffect("ClubWeaponCooldown", clonk, 1, 5, this);
|
|
|
|
Sound("Objects::Weapons::WeaponSwing?", {pitch = -50});
|
|
return true;
|
|
}
|
|
|
|
// Called in the half of the shoot animation (when ShootTime2 is over)
|
|
public func DuringShoot(object clonk, int angle)
|
|
{
|
|
// called only once. We don't want it only once..
|
|
// DoStrike(clonk, angle);
|
|
}
|
|
|
|
/*-- Usage --*/
|
|
|
|
public func HoldingEnabled() { return true; }
|
|
|
|
public func RejectUse(object clonk)
|
|
{
|
|
return !CanStrikeWithWeapon(clonk) || !clonk->HasHandAction(false, false, true);
|
|
}
|
|
|
|
public func ControlUseStart(object clonk, int x, int y)
|
|
{
|
|
if (clonk->GetHandPosByItemPos(clonk->GetItemPos(this)) == 0)
|
|
ClubChangeHandAnims("R");
|
|
else
|
|
ClubChangeHandAnims("L");
|
|
|
|
fAiming = true;
|
|
|
|
clonk->StartAim(this);
|
|
return 1;
|
|
}
|
|
|
|
public func ControlUseHolding(object clonk, ix, iy)
|
|
{
|
|
var angle = Angle(0, 0, ix, iy);
|
|
angle = Normalize(angle, -180);
|
|
|
|
clonk->SetAimPosition(angle);
|
|
|
|
return true;
|
|
}
|
|
|
|
public func ControlUseStop(object clonk, ix, iy)
|
|
{
|
|
clonk->StopAim();
|
|
return true;
|
|
}
|
|
|
|
public func ControlUseCancel(object clonk, int x, int y)
|
|
{
|
|
clonk->CancelAiming(this);
|
|
return true;
|
|
}
|
|
|
|
public func Reset(clonk)
|
|
{
|
|
fAiming = 0;
|
|
}
|
|
|
|
func FxDuringClubShootControlStart(target, effect, temp, p1)
|
|
{
|
|
if (temp) return;
|
|
effect.angle = p1;
|
|
}
|
|
|
|
func FxDuringClubShootControlStop(target, effect, reason, temp)
|
|
{
|
|
if (temp) return;
|
|
AddEffect("AfterClubShootControl", target, 1, 15, this);
|
|
}
|
|
|
|
func FxDuringClubShootControlTimer(target, effect, effect_time)
|
|
{
|
|
if (effect_time > 16) return -1;
|
|
if (!this) return -1;
|
|
this->DoStrike(target, effect.angle);
|
|
}
|
|
|
|
// you are not going to be hit by objects you fling away
|
|
func FxDuringClubShootControlQueryCatchBlow(object target, effect, object obj)
|
|
{
|
|
this->DoStrike(target, effect.angle);
|
|
var en = Format("CannotBeHitTwiceBy%d", this->ObjectNumber());
|
|
if (GetEffect(en, obj)) return true;
|
|
return false;
|
|
}
|
|
|
|
func FxAfterClubShootControlTimer()
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
func FxAfterClubShootControlQueryCatchBlow(object target, effect, object obj)
|
|
{
|
|
var en = Format("CannotBeHitTwiceBy%d", this->ObjectNumber());
|
|
if (GetEffect(en, obj)) return true;
|
|
return false;
|
|
}
|
|
|
|
func DoStrike(clonk, angle)
|
|
{
|
|
// hit all objects in the direction of the Clonk - the angle is only important for the direction of the flinging
|
|
var x = Sin(angle, 7);
|
|
var y = -Cos(angle, 7);
|
|
var found = false;
|
|
var already_hit_effect_name = Format("CannotBeHitTwiceBy%d", this->ObjectNumber());
|
|
for (var obj in FindObjects(Find_Distance(15, 0, 0), Find_Exclude(clonk), Find_NoContainer(), Find_Layer(GetObjectLayer()), Sort_Distance()))
|
|
{
|
|
// don't hit objects behind the Clonk
|
|
if (x < 0)
|
|
{
|
|
if (obj->GetX() > GetX()) continue;
|
|
}
|
|
else if (obj->GetX() < GetX()) continue;
|
|
|
|
if (GetEffect(already_hit_effect_name, obj)) continue;
|
|
|
|
if (obj->~IsProjectileTarget(this, Contained()))
|
|
{
|
|
var damage = ClubDamage();
|
|
ApplyWeaponBash(obj, 400, angle, clonk);
|
|
WeaponDamage(obj, damage, FX_Call_EngGetPunched, true);
|
|
}
|
|
else if (obj->GetCategory() & C4D_Object)
|
|
{
|
|
if (obj->Stuck()) continue;
|
|
var div = ClubVelocityPrecision();
|
|
if (obj->GetContact(-1)) div*=10;
|
|
|
|
// the better you hit, the more power you have
|
|
var precision = BoundBy(Distance(obj->GetX(), obj->GetY(), GetX() + x, GetY() + y), 1, 15);
|
|
|
|
// mass/size factor
|
|
var fac1 = 10000 / Max(5, obj->GetMass());
|
|
var fac2 = BoundBy(10-Abs(obj->GetDefCoreVal("Width", "DefCore")-obj->GetDefCoreVal("Height", "DefCore")), 1, 10);
|
|
var speed = (3000 * fac1 * fac2) / 2 / 1000 / precision;
|
|
speed = BoundBy(speed, 500, 1500);
|
|
|
|
obj->SetXDir((obj->GetXDir(100) + Sin(angle, speed)) / 2, div);
|
|
obj->SetYDir((obj->GetYDir(100) - Cos(angle, speed)) / 2, div);
|
|
obj->SetController(clonk->GetController());
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
AddEffect(already_hit_effect_name, obj, 1, 15, nil);
|
|
found = true;
|
|
break;
|
|
}
|
|
|
|
if (found)
|
|
{
|
|
RemoveEffect("DuringClubShoot", clonk);
|
|
Sound("Hits::Materials::Wood::WoodHit?", {pitch = -10});
|
|
}
|
|
}
|
|
|
|
func ClubDamage()
|
|
{
|
|
return 5 * 1000;
|
|
}
|
|
|
|
func ClubVelocityPrecision()
|
|
{
|
|
return 100;
|
|
}
|
|
|
|
/*-- Production --*/
|
|
|
|
public func IsWeapon() { return true; }
|
|
public func IsArmoryProduct() { return true; }
|
|
|
|
/*-- Display --*/
|
|
|
|
public func GetCarryMode(object clonk, bool idle, bool nohand)
|
|
{
|
|
if (idle || nohand)
|
|
return CARRY_Back;
|
|
|
|
return CARRY_Blunderbuss;
|
|
}
|
|
|
|
public func GetCarrySpecial(clonk)
|
|
{
|
|
if (fAiming)
|
|
{
|
|
if (clonk->GetHandPosByItemPos(clonk->GetItemPos(this)) == 1)
|
|
return "pos_hand1";
|
|
else
|
|
return "pos_hand2";
|
|
}
|
|
}
|
|
|
|
public func GetCarryTransform(object clonk, bool idle, bool nohand)
|
|
{
|
|
if (idle || nohand || fAiming)
|
|
return;
|
|
|
|
return Trans_Mul(Trans_Rotate(10, 0, 1), Trans_Translate(-800));
|
|
}
|
|
|
|
func Definition(def)
|
|
{
|
|
def.PictureTransformation = Trans_Mul(Trans_Translate(-4500, -2000, 2000), Trans_Rotate(45, 0, 0, 1));
|
|
}
|
|
|
|
/*-- Properties --*/
|
|
|
|
local Name = "$Name$";
|
|
local Description = "$Description$";
|
|
local Collectible = true;
|
|
local ForceFreeHands = true;
|
|
local Components = {Wood = 1, Metal = 1};
|
|
local BlastIncinerate = 30;
|
|
local MaterialIncinerate = true;
|