openclonk/planet/Objects.ocd/Vehicles.ocd/Catapult.ocd/Script.c

297 lines
7.1 KiB
C

/**
Catapult
Tosses objects farther than a clonk can, withour requiring gunpowder.
@author Ringwaul
*/
#include Library_ElevatorControl
local aim_anim;
local turn_anim;
local olddir;
local dir;
local clonkmesh;
// Shooting strength for normal launching and self launches.
static const CATAPULT_MaxPower = 100;
static const CATAPULT_MaxPower_SelfLaunch = 75;
public func IsVehicle() { return true; }
public func IsArmoryProduct() { return true; }
public func FitsInDoubleElevator() { return true; }
protected func Initialize()
{
dir = DIR_Right;
olddir = DIR_Right;
SetAction("Roll");
aim_anim = PlayAnimation("ArmPosition", 1, Anim_Const(0), Anim_Const(1000));
turn_anim = PlayAnimation("TurnRight", 5, Anim_Const(GetAnimationLength("TurnRight")), Anim_Const(1000));
}
protected func ContactLeft()
{
if (Stuck() && !Random(5))
SetRDir(RandomX(-7, +7));
}
protected func ContactRight()
{
if (Stuck() && !Random(5))
SetRDir(RandomX(-7, +7));
}
/*-- Controls --*/
// Activate turn animations
func ControlLeft(object clonk)
{
dir = DIR_Left;
if (dir != olddir)
{
olddir = dir;
// If the animation is playing for the other direction, turn back from where it already is in the animation.
var animstart = 0;
if (GetAnimationPosition(turn_anim) != GetAnimationLength("TurnRight"))
animstart = GetAnimationLength("TurnRight") - GetAnimationPosition(turn_anim);
StopAnimation(turn_anim);
turn_anim = PlayAnimation("TurnLeft", 5, Anim_Linear(animstart, 0, GetAnimationLength("TurnLeft"), Max(36 - (animstart * 204617 / 10000000), 1), ANIM_Hold), Anim_Const(1000));
}
}
func ControlRight(object clonk)
{
dir = DIR_Right;
if (dir != olddir)
{
olddir = dir;
// If the animation is playing for the other direction, turn back from where it already is in the animation.
var animstart = 0;
if (GetAnimationPosition(turn_anim) != GetAnimationLength("TurnLeft"))
animstart = GetAnimationLength("TurnLeft") - GetAnimationPosition(turn_anim);
StopAnimation(turn_anim);
turn_anim = PlayAnimation("TurnRight", 5, Anim_Linear(animstart, 0, GetAnimationLength("TurnRight"), Max(36 - (animstart * 204617 / 10000000), 1), ANIM_Hold), Anim_Const(1000));
}
}
public func HoldingEnabled() { return true; }
public func ControlUseStart(object clonk)
{
return true;
}
public func ControlUseHolding(object clonk, int x, int y)
{
var power = DefinePower(x, y);
DoArmAnimation(power);
ShowTrajectory(power);
return true;
}
public func ControlUseStop(object clonk, int x, int y)
{
DoFire(clonk, DefinePower(x,y));
}
public func ContainedUseStart(object clonk, int x, int y)
{
return true;
}
public func ContainedUseHolding(object clonk, int x, int y)
{
var power = DefinePower(x, y, CATAPULT_MaxPower_SelfLaunch);
DoArmAnimation(power);
ShowTrajectory(power);
return true;
}
public func ContainedUseStop(object clonk, int x, int y)
{
DoFire(clonk, DefinePower(x, y, CATAPULT_MaxPower_SelfLaunch));
}
/*-- Shooting --*/
public func DefinePower(int x, int y, int max_power)
{
if (max_power == nil)
max_power = CATAPULT_MaxPower;
var power = 2 * Distance(x, y) / 3 - 24;
power = BoundBy(power, 20, max_power);
return power;
}
public func DoArmAnimation(int power)
{
SetAnimationPosition(aim_anim, Anim_Const(759 - (power * 759 / 100)));
return;
}
public func ShowTrajectory(int power)
{
var exit = GetProjectileExit();
var x = GetX() + exit[0];
var y = GetY() + exit[1];
var angle = exit[2] + GetR();
var xdir = Sin(angle, power);
var ydir = -Cos(angle, power);
Trajectory->Create(this, x, y, xdir, ydir);
return;
}
protected func DoFire(object clonk, int power)
{
// Play the fire animation.
aim_anim = PlayAnimation("ArmPosition", 1, Anim_Linear(GetAnimationPosition(aim_anim), 0, GetAnimationLength("ArmPosition"), 3, ANIM_Hold), Anim_Const(1000));
// Sound.
Sound("Objects::Catapult_Launch");
// Remove trajectory display.
Trajectory->Remove(this);
// The clonk will be the projectile if he sits in the catapult.
var projectile;
if (clonk && (clonk->Contained() == this))
projectile = clonk;
// If clonk isn't sitting in there, shoot stuff placed into the catapult
if (!projectile)
projectile = Contents(0);
// Otherwise, fire what is in the clonk's hand.
if (!projectile)
projectile = clonk->GetHandItem(0);
// Don't do anything further if there is no projectile.
if (!projectile)
return;
// Find the spot of the catapult's arm depending on rotation.
var exit = GetProjectileExit();
var x = exit[0];
var y = exit[1];
var angle = exit[2] + GetR();
projectile->Exit();
// Put the ammo at the catapult's arm.
projectile->SetPosition(GetX() + x, GetY() + y);
// Special behavior for crew members.
if (projectile->GetOCF() & OCF_CrewMember)
{
CatapultDismount(projectile);
projectile->SetAction("Tumble");
// Make sure the Clonk can't shoot itself into solid material.
if (projectile->Stuck())
{
// First, try to just put the Clonk a few pixels lower - might still look okay in some situations.
for (var i = 0; i <= 4; ++i)
{
projectile->SetPosition(projectile->GetX(), projectile->GetY() + 2);
if (!projectile->Stuck())
break;
}
// Then as a safeguard, just place the Clonk at the catapult's feet and do nothing.
if (projectile->Stuck())
{
projectile->SetPosition(GetX(), GetY());
// Still stuck? Then we don't actually care if stuck here or at the end of the arm.
if (projectile->Stuck())
{
// Go back to normal shooting position.
projectile->SetPosition(GetX() + x, GetY() + y);
}
else
{
// We set the Clonk back down on the ground. This is not a normal shot.
angle = 0;
power = 20;
}
}
}
}
// Set the speed of the projectile.
projectile->SetVelocity(angle + GetR(), power);
return;
}
private func GetProjectileExit()
{
var xdir = 1;
if (dir == DIR_Left)
xdir = -1;
var x = 8 * xdir;
var y = -28;
var angle = 45 * xdir;
return [x, y, angle];
}
public func ActivateEntrance(object clonk)
{
var cnt = ObjectCount(Find_Container(this), Find_OCF(OCF_CrewMember));
if (cnt > 0)
{
if (clonk->Contained() == this)
{
CatapultDismount(clonk);
clonk->Exit();
}
return;
}
if (cnt == 0)
{
clonk->Enter(this);
SetOwner(clonk->GetController());
clonkmesh = AttachMesh(clonk,"shot","skeleton_body",Trans_Mul(Trans_Rotate(180, 1, 0, 0), Trans_Translate(-3000, 1000, 0)), AM_DrawBefore);
clonk->PlayAnimation("CatapultSit", CLONK_ANIM_SLOT_Movement, Anim_Const(0), Anim_Const(1000));
DoArmAnimation(CATAPULT_MaxPower_SelfLaunch);
}
return;
}
public func CatapultDismount(object clonk)
{
clonk->StopAnimation(clonk->GetRootAnimation(15));
DetachMesh(clonkmesh);
clonkmesh = nil;
return true;
}
/*-- Properties --*/
func Definition(proplist def)
{
def.PictureTransformation = Trans_Mul(Trans_Translate(-1000, -4000, 0), Trans_Rotate(-20, 1, 0, 0), Trans_Rotate(35, 0, 1, 0));
}
local Name = "$Name$";
local Description = "$Description$";
local Touchable = 1;
local BorderBound = C4D_Border_Sides;
local ActMap = {
Roll = {
Prototype = Action,
Name = "Roll",
Procedure = DFA_NONE,
Directions = 2,
//FlipDir = 1,
Length = 50,
Delay = 2,
X = 0,
Y = 0,
Wdt = 22,
Hgt = 16,
NextAction = "Roll",
},
};