airplane: add afterburner mode

This reqruired some movement code clean up, replaced old effects with new effects.
install-platforms
Maikel de Vries 2017-11-15 18:49:47 +01:00
parent 4278626b9f
commit 3a47802702
6 changed files with 382 additions and 189 deletions

View File

@ -109,7 +109,7 @@ func Intro_6()
this.projectile->DoExplode();
this.plane->SetMeshMaterial("CrashedAirplane");
this.plane->CancelFlight();
RemoveEffect("IntPlane", this.plane);
this.plane->RemovePlaneControl();
this.plane->SetRDir(-10);
// Calc fling direction to land near flagpole
var tx = 135 - this.plane->GetX();

View File

@ -27,11 +27,9 @@ func Intro_Start()
this.pilot->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(5500, 0, 0)); // Hat is seen in the cockpit!
this.plane->PlaneMount(this.pilot);
this.plane.FxIntPlaneTimer = this.Intro_PlaneTimer;
RemoveEffect("IntPlane", this.plane);
AddEffect("IntPlane",this.plane,1,1,this.plane);
this.plane->CreateEffect(FxFloatPlane, 1, 1);
this.plane->FaceRight();
this.plane->StartInstantFlight(90, 0);
this.plane->StartInstantFlight(90, 15);
g_intro_sky_moving = true;
@ -40,25 +38,19 @@ func Intro_Start()
return ScheduleNext(100, 1);
}
func Intro_PlaneTimer(...)
local FxFloatPlane = new Effect
{
// Plane flight overload: Just move sky and have plane do turbulent movement during initial part of intro
var rv = Call(Airplane.FxIntPlaneTimer, ...);
if (g_intro_sky_moving)
Timer = func(int time)
{
if (!Random(4)) this.rdir = BoundBy((80+Random(21)-GetR())/5,-1,1);
SetXDir(); SetYDir(GetR()*2-GetY()+Random(5),10);
if (g_intro_sky_moving)
{
var rdir = BoundBy((80 + Random(21) - Target->GetR()) / 5, -1, 1);
Target->SetR(Target->GetR() + rdir);
Target->SetXDir(0);
Target->SetYDir(Target->GetR() * 2 - Target->GetY() + Random(5), 10);
}
}
//propellor
var change = GetAnimationPosition(this.propanim) + 15 * 3;
if(change > GetAnimationLength("Propellor"))
change = (GetAnimationPosition(this.propanim) + 15 * 3) - GetAnimationLength("Propellor");
if(change < 0)
change = (GetAnimationLength("Propellor") - 15 * 3);
SetAnimationPosition(this.propanim, Anim_Const(change));
return rv;
}
};
func Intro_JoinPlayer(int plr)
{

View File

@ -2,17 +2,11 @@
Airplane
Acrobatic air-vehicle. Capable of firing lead shot.
@author: Ringwaul, Clonkonaut
@author: Ringwaul, Clonkonaut, Maikel
*/
local throttle = 0;
local rdir = 0;
local thrust = 0;
local dir = DIR_Left;
local newrot;
local propanim;
local prop_speed, prop_speed_target, prop_speed_timer; // current and target propeller speed [0, 100]
local pilot;
@ -22,23 +16,23 @@ local clonkmesh;
local main_action = "Cannon"; // default: fire bullets
// All available click actions
local action_list = ["Cannon", "Rocket", "Bomb", "Spray", "Balloon", "Drop"];
local action_list = ["Cannon", "Rocket", "Bomb", "Spray", "Balloon", "Drop", "Afterburner"];
/*-- Engine Callbacks --*/
func Construction()
public func Construction()
{
SetR(-90);
}
func Initialize()
public func Initialize()
{
propanim = PlayAnimation("Propellor", 15, Anim_Const(0));
AddEffect("IntPlane", this, 1, 1, this);
CreateEffect(FxControlPlaneFlight, 1, 1);
SetAction("Land");
}
func RejectCollect(id def, object obj)
public func RejectCollect(id def, object obj)
{
var contents_count = ObjectCount(Find_Container(this), Find_Not(Find_OCF(OCF_CrewMember)));
if (contents_count >= MaxContentsCount)
@ -46,17 +40,18 @@ func RejectCollect(id def, object obj)
return false;
}
func Damage(int change, int cause, int by_player)
public func Damage(int change, int cause, int by_player)
{
if (GetDamage() >= this.HitPoints)
{
if (pilot) PlaneDismount(pilot);
if (pilot)
PlaneDismount(pilot);
SetController(by_player);
PlaneDeath();
}
}
func ActivateEntrance(object clonk)
public func ActivateEntrance(object clonk)
{
if (clonk->Contained() == this)
return clonk->Exit();
@ -73,16 +68,17 @@ func ActivateEntrance(object clonk)
ShowMainActionTo(clonk);
}
func Ejection(object obj)
public func Ejection(object obj)
{
if (pilot && obj == pilot)
PlaneDismount(obj);
if(obj->Contained()) Exit();
if (obj->Contained())
Exit();
obj->SetSpeed(this->GetXDir(), this->GetYDir());
}
// Inflict damage when hitting something with the plane and already damaged.
func Hit(int xdir, int ydir)
public func Hit(int xdir, int ydir)
{
var remaining_hp = this.HitPoints - GetDamage();
if (remaining_hp < 10)
@ -93,12 +89,14 @@ func Hit(int xdir, int ydir)
}
}
/*-- Callbacks --*/
public func IsContainer() { return true; }
public func IsProjectileTarget(target, shooter) { return true; }
/*-- Interface --*/
//Quick command for scenario designers. The plane starts facing right instead of left.
@ -114,6 +112,7 @@ public func FaceLeft()
RollPlane(0, true);
}
/*-- Interaction --*/
// Provides an own interaction menu.
@ -124,7 +123,7 @@ public func GetInteractionMenus(object clonk)
{
var menus = _inherited(clonk, ...) ?? [];
// Do not show the menu if flying and if the clonk is not the pilot
// Do not show the menu if flying and if the clonk is not the pilot.
if (GetAction() == "Fly" && clonk != pilot)
return menus;
@ -201,6 +200,8 @@ public func OnSettingsHover(symbol, extra_data, desc_menu_target, menu_id)
text = Format("$BalloonInfo$", GetBalloonAmount());
if (main_action == "Drop")
text = Format("$DropInfo$");
if (main_action == "Afterburner")
text = Format("$AfterburnerInfo$");
if (text == "")
text = "$Description$";
}
@ -208,7 +209,7 @@ public func OnSettingsHover(symbol, extra_data, desc_menu_target, menu_id)
GuiUpdate({ Text = text }, menu_id, 1, desc_menu_target);
}
func GetActionTypeTooltip(string action)
private func GetActionTypeTooltip(string action)
{
// Show next firing mode
var position = GetIndexOf(action_list, action);
@ -222,7 +223,7 @@ func GetActionTypeTooltip(string action)
return Format("$SwitchTo$", GetActionTypeName(action_list[position]));
}
func GetActionTypeName(string action)
private func GetActionTypeName(string action)
{
if (action == "Cannon")
return "$Bullet$";
@ -236,9 +237,11 @@ func GetActionTypeName(string action)
return "$Balloon$";
if (action == "Drop")
return "$Drop$";
if (action == "Afterburner")
return "$Afterburner$";
}
func GetActionTypeInfo(string action)
private func GetActionTypeInfo(string action)
{
if (action == "Cannon")
return LeadBullet;
@ -252,12 +255,15 @@ func GetActionTypeInfo(string action)
return Balloon;
if (action == "Drop")
return Icon_LetGo;
if (action == "Afterburner")
return Icon_Flame;
}
public func ToggleMainAction(object clonk)
{
var current_action = GetIndexOf(action_list, main_action);
if (current_action == -1) return; // ??
if (current_action == -1)
return; // ??
if (current_action == GetLength(action_list)-1)
current_action = 0;
@ -275,6 +281,7 @@ public func ToggleMainAction(object clonk)
}
}
/*-- Usage --*/
// Main action
@ -322,32 +329,33 @@ public func ContainedUseAltCancel(object clonk, int x, int y)
return true;
}
// Starting the plane
// Starting the plane.
public func ContainedUp(object clonk)
{
if (pilot)
{
// For safety, check if the pilot is dead (which is never particularly good)
// During flight, pilot's health is constantly checked by the flying effect
// For safety, check if the pilot is dead (which is never particularly good).
// During flight, pilot's health is constantly checked by the flying effect.
if (!pilot->GetAlive())
PlaneDismount(pilot);
else if (clonk != pilot)
return false;
}
//engine start
if(clonk && GetAction() == "Land")
// Start engine.
if (clonk && GetAction() == "Land")
{
if (!pilot) PlaneMount(clonk);
if (!pilot)
PlaneMount(clonk);
StartFlight(15);
return true;
}
return false;
}
// Stopping the plane
// Stopping the plane.
public func ContainedDown(object clonk)
{
//engine shutoff
// Shut down engine.
if (GetAction() == "Fly" && clonk == pilot)
{
CancelFlight();
@ -360,7 +368,7 @@ public func ContainedDown(object clonk)
else if (clonk != pilot)
return false;
}
//allow reverse
// Allow reverse pilot.
if (clonk && GetAction() == "Land")
{
if (!pilot)
@ -371,12 +379,14 @@ public func ContainedDown(object clonk)
return false;
}
// Steering
// Steering.
public func ContainedLeft(object clonk)
{
if (clonk != pilot)
return false;
rdir = -1;
var ctrl_fx = GetPlaneControl();
if (ctrl_fx)
ctrl_fx->SetRotationDir(-1);
return true;
}
@ -384,7 +394,9 @@ public func ContainedRight(object clonk)
{
if (clonk != pilot)
return false;
rdir = 1;
var ctrl_fx = GetPlaneControl();
if (ctrl_fx)
ctrl_fx->SetRotationDir(1);
return true;
}
@ -392,31 +404,35 @@ public func ContainedStop(object clonk)
{
if (clonk != pilot)
return false;
rdir = 0;
var ctrl_fx = GetPlaneControl();
if (ctrl_fx)
ctrl_fx->SetRotationDir(0);
return true;
}
/*-- Control --*/
public func GetFacingDir()
{
return dir;
}
public func ControlLeft(object clonk)
{
if (Inside(GetR(), 80, 100) && dir == DIR_Right)
{
FaceLeft();
}
return false;
}
public func ControlRight(object clonk)
{
if (Inside(GetR(), -100, -80) && dir == DIR_Left)
{
FaceRight();
}
return false;
}
/*-- Bullet firing --*/
public func UseCannon(object clonk, int x, int y)
@ -459,7 +475,7 @@ public func GetBulletAmount()
return shots;
}
func FxFireBulletsStart(object target, proplist effect, int temp)
public func FxFireBulletsStart(object target, proplist effect, int temp)
{
if (temp)
return FX_OK;
@ -473,7 +489,7 @@ func FxFireBulletsStart(object target, proplist effect, int temp)
return FX_OK;
}
func FxFireBulletsTimer(object target, proplist effect, int time)
public func FxFireBulletsTimer(object target, proplist effect, int time)
{
var ammo = FindObject(Find_Container(this), Find_Func("IsBullet"));
if (!ammo)
@ -482,7 +498,7 @@ func FxFireBulletsTimer(object target, proplist effect, int time)
return FX_OK;
}
func FxFireBulletsStop(object target, proplist effect, int reason, bool temp)
public func FxFireBulletsStop(object target, proplist effect, int reason, bool temp)
{
if (temp)
return FX_OK;
@ -491,7 +507,7 @@ func FxFireBulletsStop(object target, proplist effect, int reason, bool temp)
return FX_OK;
}
func FireBullet(object ammo)
public func FireBullet(object ammo)
{
var shot = ammo->TakeObject();
var angle = this->GetR();
@ -510,6 +526,7 @@ func FireBullet(object ammo)
CreateParticle("Flash", 0, 0, GetXDir(), GetYDir(), 8, Particles_Flash());
}
/*-- Rocket firing --*/
public func UseRocket(object clonk, int x, int y)
@ -544,7 +561,7 @@ public func GetRocketAmount()
return ContentsCount(Boompack);
}
func FireRocket(object rocket, int x, int y)
public func FireRocket(object rocket, int x, int y)
{
var launch_x = Cos(GetR() - 180 * (1 - dir), 10);
var launch_y = Sin(GetR() - 180 * (1 - dir), 10);
@ -556,7 +573,7 @@ func FireRocket(object rocket, int x, int y)
rocket->SetDirectionDeviation(0);
}
func FxIntControlRocketTimer(object target, proplist effect, int time)
public func FxIntControlRocketTimer(object target, proplist effect, int time)
{
// Remove gravity on rocket.
target->SetYDir(target->GetYDir(100) - GetGravity(), 100);
@ -575,6 +592,7 @@ func FxIntControlRocketTimer(object target, proplist effect, int time)
return FX_OK;
}
/*-- Bombing --*/
public func UseBomb(object clonk, int x, int y)
@ -622,7 +640,7 @@ public func GetBombAmount()
return bombs;
}
func DropBomb(object bomb)
private func DropBomb(object bomb)
{
if (!bomb) return;
@ -633,6 +651,7 @@ func DropBomb(object bomb)
bomb->Fuse(true); // fuse and explode on hit
}
/*-- Liquid spray --*/
public func UseSpray(object clonk, int x, int y)
@ -680,7 +699,7 @@ public func GetBarrelAmount()
return count;
}
func SprayLiquid(object barrel, object clonk)
private func SprayLiquid(object barrel, object clonk)
{
if (!barrel) return;
@ -691,6 +710,7 @@ func SprayLiquid(object barrel, object clonk)
Sound("Liquids::Splash1");
}
/*-- Parachuting --*/
public func UseBalloon(object clonk, int x, int y)
@ -722,7 +742,7 @@ public func GetBalloonAmount()
return ContentsCount(Balloon);
}
func Parachute(object balloon, int x, int y, object clonk)
private func Parachute(object balloon, int x, int y, object clonk)
{
if (!balloon || !clonk) return;
@ -736,6 +756,7 @@ func Parachute(object balloon, int x, int y, object clonk)
balloon->ControlUseStart(clonk);
}
/*-- Object dropping --*/
public func UseDrop(object clonk, int x, int y)
@ -771,7 +792,7 @@ public func GetNonClonkContents()
return FindObjects(Find_Container(this), Find_Not(Find_OCF(OCF_CrewMember)));
}
func DropObject(object to_drop, int x, int y, object clonk)
private func DropObject(object to_drop, int x, int y, object clonk)
{
if (!to_drop) return;
@ -783,69 +804,201 @@ func DropObject(object to_drop, int x, int y, object clonk)
to_drop->SetController(clonk->GetOwner());
}
/*-- Afterburner --*/
public func UseAfterburner(object clonk, int x, int y)
{
if (clonk != pilot)
return false;
if (!GetOilBarrel())
{
CustomMessage("$NoOil$", this, clonk->GetOwner());
Sound("Objects::Weapons::Blunderbuss::Click?");
return true;
}
CreateEffect(FxAfterburner, 100, 2);
return true;
}
public func CancelAfterburner(object clonk, int x, int y)
{
if (clonk != pilot)
return false;
var fx = GetEffect("FxAfterburner", this);
if (fx)
fx->Remove();
return true;
}
public func GetOilBarrel()
{
var barrels = FindObjects(Find_Container(this), Find_Or(Find_ID(Barrel), Find_ID(MetalBarrel)));
for (var barrel in barrels)
if (barrel->GetLiquidAmount("Oil") > 0)
return barrel;
return;
}
public func IsUsingAfterburner()
{
return !!GetEffect("FxAfterburner", this);
}
local FxAfterburner = new Effect
{
Construction = func()
{
Target->Sound("Objects::Boompack::Fly", 0, 40, nil, 1);
},
Timer = func(int time)
{
var barrel = Target->GetOilBarrel();
if (!barrel)
return FX_Execute_Kill;
if (barrel->GetLiquidAmount("Oil") <= 0)
return FX_Execute_Kill;
barrel->RemoveLiquid("Oil", 1);
return FX_OK;
},
Destruction = func()
{
Target->Sound("Objects::Boompack::Fly", 0, 40, nil, -1);
}
};
/*-- Movement --*/
public func StartFlight(int new_throttle)
{
SetPropellerSpeedTarget(100);
SetAction("Fly");
throttle = new_throttle;
var ctrl_fx = GetPlaneControl();
if (ctrl_fx)
ctrl_fx.throttle = new_throttle;
return;
}
public func StartInstantFlight(int angle, int new_throttle)
{
if (angle < 0) angle += 360;
if (angle < 180) angle -= 10; else angle += 10;
if (angle < 0)
angle += 360;
if (angle < 180)
angle -= 10;
else
angle += 10;
SetPropellerSpeed(100);
SetAction("Fly");
throttle = new_throttle;
thrust = new_throttle;
var ctrl_fx = GetPlaneControl();
if (ctrl_fx)
{
ctrl_fx.throttle = new_throttle;
ctrl_fx.thrust = new_throttle;
}
SetR(angle);
SetXDir(Sin(angle, thrust));
SetYDir(-Cos(angle, thrust));
SetXDir(Sin(angle, new_throttle));
SetYDir(-Cos(angle, new_throttle));
return;
}
public func CancelFlight()
{
SetPropellerSpeedTarget(0);
SetAction("Land");
rdir = 0;
throttle = 0;
var ctrl_fx = GetPlaneControl();
if (ctrl_fx)
{
ctrl_fx.rdir = 0;
ctrl_fx.throttle = 0;
}
return;
}
func FxIntPlaneTimer(object target, effect, int timer)
public func GetPlaneControl()
{
//Lift
var lift = Distance(0, 0, GetXDir(), GetYDir()) / 2;
if (lift > 20)
lift = 20;
if (throttle < 1)
lift = 0;
return GetEffect("FxControlPlaneFlight", this);
}
if (GetAction() == "Fly")
public func RemovePlaneControl()
{
var ctrl_fx = GetPlaneControl();
if (ctrl_fx)
ctrl_fx->Remove();
return;
}
// Effect that controls the plane movement and related stuff.
local FxControlPlaneFlight = new Effect
{
Construction = func()
{
// clockwise
if (rdir == 1)
if(GetRDir() < 5) SetRDir(GetRDir() + 3);
// counter-clockwise
if (rdir == -1)
if(GetRDir() > -5) SetRDir(GetRDir() - 3);
if (rdir == 0) SetRDir();
// Roll plane to movement direction
if (throttle > 0)
this.thrust = 0;
this.throttle = 0;
this.lift = 0;
this.rdir = 0;
this.propanim = Target->PlayAnimation("Propellor", 15, Anim_Const(0));
},
Destruction = func()
{
Target->StopAnimation(this.propanim);
},
SetRotationDir = func(int new_dir)
{
this.rdir = new_dir;
},
Timer = func(int time)
{
// Perform flying actions.
if (Target->GetAction() == "Fly")
{
if(GetXDir() > 10 && dir != DIR_Right) RollPlane(1);
if(GetXDir() < -10 && dir != DIR_Left) RollPlane(0);
this->DoPlaneRotation();
this->DoEngineSmoke();
this->StirUpLiquids();
}
// Vfx
// Engine smoke
var colour = 255 - (GetDamage() * 3);
// Perform landing actions.
else
{
this->LandPlane();
}
// Perform plane movements.
this->ApplyThrust(time);
this->ApplyDrag();
this->PropellorAnim();
this->PerformSafetyChecks();
return FX_OK;
},
DoPlaneRotation = func()
{
// Perform plane rotation.
var max_rdir = 7;
if (Target->IsUsingAfterburner())
max_rdir = 9;
var current_rdir = Target->GetRDir();
var new_rdir = current_rdir + 3 * this.rdir;
if (this.rdir == 0)
new_rdir = 0;
new_rdir = BoundBy(new_rdir, -max_rdir, max_rdir);
Target->SetRDir(new_rdir);
// Roll plane to movement direction.
if (this.throttle > 0)
{
if (Target->GetXDir() > 10 && Target->GetFacingDir() != DIR_Right)
Target->RollPlane(1);
if (Target->GetXDir() < -10 && Target->GetFacingDir() != DIR_Left)
Target->RollPlane(0);
}
},
// Perform engine smoke.
DoEngineSmoke = func()
{
var colour = 255 - (Target->GetDamage() * 3);
var min = PV_Random(7, 20);
var max = PV_Random(40, 70);
if (GetDamage() >= this.HitPoints / 2)
var rot = Target->GetR();
if (Target->GetDamage() >= Target.HitPoints / 2)
{
min = PV_Random(20, 30);
max = PV_Random(70, 100);
@ -856,18 +1009,29 @@ func FxIntPlaneTimer(object target, effect, int timer)
R = colour, G = colour, B = colour,
Size = PV_Linear(min, max)
};
CreateParticle("Smoke", -Sin(GetR(), 10), Cos(GetR(), 10), 0, 0, PV_Random(36, 2 * 36), particles, 1);
// Stir up liquids
if (GBackLiquid(0, 40))
Target->CreateParticle("Smoke", -Sin(rot, 10), Cos(rot, 10), 0, 0, PV_Random(36, 2 * 36), particles, 1);
// Add fire if after burner is turned on.
if (Target->IsUsingAfterburner())
{
var particle_fire = Particles_Fire();
particle_fire.Size = PV_KeyFrames(0, 0, PV_Random(6, 8), 500, 4, 1000, 0);
Target->CreateParticle("Fire", -Sin(rot, 10), Cos(rot, 10), PV_Random(-1, 1), PV_Random(-1, 1), 20 + Random(10), particle_fire, 1);
}
},
// Stirs up liquids if flying above a liquid.
StirUpLiquids = func()
{
if (Target->GBackLiquid(0, 40))
{
var surface = 40;
while (surface && GBackSemiSolid(0, surface))
while (surface && Target->GBackSemiSolid(0, surface))
surface--;
if (surface > 0 && GBackLiquid(0, surface + 1))
if (surface > 0 && Target->GBackLiquid(0, surface + 1))
{
var phases = PV_Linear(0, 7);
if (dir == DIR_Left) phases = PV_Linear(8, 15);
var color = GetAverageTextureColor(GetTexture(0, surface + 1));
if (Target->GetFacingDir() == DIR_Left)
phases = PV_Linear(8, 15);
var color = GetAverageTextureColor(Target->GetTexture(0, surface + 1));
var particles =
{
Size = 16,
@ -879,84 +1043,105 @@ func FxIntPlaneTimer(object target, effect, int timer)
B = (color >> 0) & 0xff,
Attach = ATTACH_Front,
};
CreateParticle("Wave", 0, surface, (RandomX(-5, 5) - (-1 + 2 * dir) * 6) / 4, 0, 16, particles);
Target->CreateParticle("Wave", 0, surface, (RandomX(-5, 5) - (-1 + 2 * Target->GetFacingDir()) * 6) / 4, 0, 16, particles);
}
}
}
else // Action "Land"
},
// Lands the plane.
LandPlane = func()
{
// If under or on water, turn upright
if (GBackLiquid() || GBackLiquid(0, 21))
// If under or on water, turn upright.
if (Target->GBackLiquid() || Target->GBackLiquid(0, 21))
{
if (GetR() < 0)
if (Target->GetR() < 0)
{
if (!Inside(GetR(), -95, -85))
if (!Inside(Target->GetR(), -95, -85))
{
SetRDir((90 + GetR()) / Abs(90 + GetR()) * -3);
RollPlane(0);
Target->SetRDir((90 + Target->GetR()) / Abs(90 + Target->GetR()) * -3);
Target->RollPlane(0);
}
}
else if (!Inside(GetR(), 85, 95))
else if (!Inside(Target->GetR(), 85, 95))
{
SetRDir((90 - GetR()) / Abs(90 - GetR()) * 3);
RollPlane(1);
Target->SetRDir((90 - Target->GetR()) / Abs(90 - Target->GetR()) * 3);
Target->RollPlane(1);
}
// Also: slow down because the plane tends to slide across water
if (GetXDir() > 0)
SetXDir(GetXDir() - 1);
else if (GetXDir() < 0)
SetXDir(GetXDir() + 1);
// Also: slow down because the plane tends to slide across water.
if (Target->GetXDir() > 0)
Target->SetXDir(Target->GetXDir() - 1);
else if (Target->GetXDir() < 0)
Target->SetXDir(Target->GetXDir() + 1);
}
if (thrust > 0)
thrust--;
if (thrust < 0)
thrust++;
}
// Throttle-to-thrust lag
if (timer % 10 == 0)
// Decrease thrust rapidly.
if (this.thrust > 0)
this.thrust--;
if (this.thrust < 0)
this.thrust++;
},
ApplyThrust = func(int time)
{
if (throttle > thrust) ++thrust;
if (throttle < thrust) --thrust;
}
// Propellor
var change = GetAnimationPosition(propanim) + thrust * 3;
if(change > GetAnimationLength("Propellor"))
change = (GetAnimationPosition(propanim) + thrust * 3) - GetAnimationLength("Propellor");
if(change < 0)
change = (GetAnimationLength("Propellor") - thrust * 3);
SetAnimationPosition(propanim, Anim_Const(change));
// Thrust
SetXDir(Sin(GetR(), thrust) + GetXDir(100), 100);
SetYDir(-Cos(GetR(), thrust) + GetYDir(100) - lift, 100);
// Drag
var maxspeed = 40;
var speed = Distance(0, 0, GetXDir(), GetYDir());
if (speed > maxspeed)
// Determine airplane lift.
this.lift = Distance(0, 0, Target->GetXDir(), Target->GetYDir()) / 2;
if (this.lift > 20)
this.lift = 20;
if (this.throttle < 1)
this.lift = 0;
// Modify throttle if afterburner is being used.
var mod_throttle = this.throttle;
if (Target->IsUsingAfterburner())
mod_throttle = 3 * mod_throttle / 2;
// Throttle-to-thrust lag
if (time % 10 == 0)
{
if (mod_throttle > this.thrust)
++this.thrust;
if (mod_throttle < this.thrust)
--this.thrust;
}
// Set airplane velocity.
Target->SetXDir(Sin(Target->GetR(), this.thrust) + Target->GetXDir(100), 100);
Target->SetYDir(-Cos(Target->GetR(), this.thrust) + Target->GetYDir(100) - this.lift, 100);
},
// Applies drag to the airplane to ensure a maximum speed.
ApplyDrag = func()
{
SetXDir(GetXDir(100)*maxspeed/speed, 100);
SetYDir(GetYDir(100)*maxspeed/speed, 100);
}
if (!pilot && throttle != 0)
CancelFlight();
if (pilot && !pilot->GetAlive())
PlaneDismount(pilot);
// Planes cannot fly underwater!
if (GBackLiquid())
var maxspeed = 40;
if (Target->IsUsingAfterburner())
maxspeed += 18;
var speed = Distance(0, 0, Target->GetXDir(), Target->GetYDir());
if (speed > maxspeed)
{
Target->SetXDir(Target->GetXDir(100) * maxspeed / speed, 100);
Target->SetYDir(Target->GetYDir(100) * maxspeed / speed, 100);
}
},
PropellorAnim = func()
{
if (pilot)
Ejection(pilot);
if (throttle != 0)
CancelFlight();
var change = Target->GetAnimationPosition(this.propanim) + this.thrust * 3;
if (change > Target->GetAnimationLength("Propellor"))
change = (Target->GetAnimationPosition(this.propanim) + this.thrust * 3) - Target->GetAnimationLength("Propellor");
if (change < 0)
change = (Target->GetAnimationLength("Propellor") - this.thrust * 3);
Target->SetAnimationPosition(this.propanim, Anim_Const(change));
},
PerformSafetyChecks = func()
{
// Check for pilot.
if (!Target->GetPilot() && this.throttle != 0)
Target->CancelFlight();
if (Target->GetPilot() && !Target->GetPilot()->GetAlive())
Target->PlaneDismount(Target->GetPilot());
// Planes cannot fly underwater!
if (Target->GBackLiquid())
{
if (Target->GetPilot())
Target->Ejection(Target->GetPilot());
if (this.throttle != 0)
Target->CancelFlight();
}
}
return FX_OK;
}
};
public func RollPlane(int rolldir, bool instant)
{
@ -965,11 +1150,12 @@ public func RollPlane(int rolldir, bool instant)
var i = 36;
if (instant)
i = 1;
newrot = PlayAnimation(Format("Roll%d",rolldir), 10, Anim_Linear(0, 0, GetAnimationLength(Format("Roll%d", rolldir)), i, ANIM_Hold));
PlayAnimation(Format("Roll%d",rolldir), 10, Anim_Linear(0, 0, GetAnimationLength(Format("Roll%d", rolldir)), i, ANIM_Hold));
dir = rolldir;
}
}
/*-- Piloting --*/
public func PlaneMount(object clonk)
@ -977,7 +1163,7 @@ public func PlaneMount(object clonk)
pilot = clonk;
SetOwner(clonk->GetController());
clonk->PlayAnimation("Stand", 15, nil, Anim_Const(1000));
clonkmesh = AttachMesh(clonk,"pilot","skeleton_body",Trans_Mul(Trans_Rotate(180, 1, 0, 0), Trans_Translate(-3000, 1000, 0)),AM_DrawBefore);
clonkmesh = AttachMesh(clonk, "pilot", "skeleton_body", Trans_Mul(Trans_Rotate(180, 1, 0, 0), Trans_Translate(-3000, 1000, 0)), AM_DrawBefore);
return true;
}
@ -991,11 +1177,16 @@ public func PlaneDismount(object clonk)
return true;
}
public func GetPilot()
{
return pilot;
}
/*-- Effects --*/
func PlaneDeath()
private func PlaneDeath()
{
while(Contents(0))
while (Contents(0))
Contents(0)->Exit();
Explode(36);
}
@ -1015,12 +1206,13 @@ public func SetPropellerSpeed(int new_speed)
public func SetPropellerSpeedTarget(int new_speed_target)
{
prop_speed_target = new_speed_target;
if (!prop_speed_timer) prop_speed_timer = AddTimer(this.PropellerSpeedTimer, 10);
if (!prop_speed_timer)
prop_speed_timer = AddTimer(this.PropellerSpeedTimer, 10);
return true;
}
// Execute fading to new propeller speed
func PropellerSpeedTimer()
public func PropellerSpeedTimer()
{
prop_speed = BoundBy(prop_speed_target, prop_speed - 10, prop_speed + 4);
if (prop_speed == prop_speed_target)
@ -1032,19 +1224,21 @@ func PropellerSpeedTimer()
}
// Set propeller speed sound. 0 = off, 100 = max speed.
func SetPropellerSound(int speed)
private func SetPropellerSound(int speed)
{
if (speed <= 0)
return Sound("Objects::Plane::PropellerLoop",0,100,nil,-1);
return Sound("Objects::Plane::PropellerLoop", 0, 100, nil, -1);
else
return Sound("Objects::Plane::PropellerLoop",0,100,nil,1,0,(speed-100)*2/3);
return Sound("Objects::Plane::PropellerLoop", 0, 100, nil, 1, 0, (speed - 100) * 2 / 3);
}
/*-- Production --*/
public func IsVehicle() { return true; }
public func IsShipyardProduct() { return true; }
/*-- Display --*/
public func ShowMainActionTo(object clonk)
@ -1059,6 +1253,7 @@ public func Definition(proplist def)
return _inherited(def, ...);
}
/*-- Properties --*/
local ActMap = {

View File

@ -8,6 +8,7 @@ NoBarrels=Keine Flüssigkeiten|mehr!
NoBalloons=Keine Ballons!
NoSpaceInInventory=Inventar voll!|Kein Platz für den Ballon!
NoObjects=Leer!
NoOil=Kein Öl!
SelectedAction=Schussmodus:|%s ({{%i}})
AirplaneSettings=Schussmodus auswählen:
@ -20,10 +21,12 @@ Bomb=Bombenabwurf
Spray=Flüssigkeitsabwurf
Balloon=Ballon-Fallschirmsprung
Drop=Objektabwurf
Afterburner=Nachbrenner
BulletInfo=Mit der Kanone schießen. Schießt Kugeln ({{LeadBullet}}). Kugeln verfügbar: %d.
RocketInfo=Feuert Boompacks ({{Boompack}}) aus dem Flugzeug. Boompacks verfügbar: %d.
BombInfo=Werfe Bomben ({{IronBomb}} und {{Dynamite}}) ab. Bomben verfügbar: %d.
SprayInfo=Überzieht die Landschaft mit einem Flüssigkeitsregen. Flüssigkeit muss in Fässern ({{Barrel}} und {{MetalBarrel}}) gelagert werden. Fässer verfügbar: %d.
BalloonInfo=Mit einem Ballon ({{Balloon}}) vom Flugzeug abspringen. Diese Aktion kann auch von anderen Clonks, die das Flugzeug nicht steuern, ausgeführt werden. Ballons verfügbar: %d.
DropInfo=Werfe Objekte aus dem Flugzeug ab.
DropInfo=Werfe Objekte aus dem Flugzeug ab.
AfterburnerInfo=Verwende Öl um das Flugzeug zu beschleunigen.

View File

@ -8,6 +8,7 @@ NoBarrels=No more liquid!
NoBalloons=No balloons!
NoSpaceInInventory=Inventory full!|No space for the balloon!
NoObjects=Empty!
NoOil=No oil!
SelectedAction=Firing mode:|%s ({{%i}})
AirplaneSettings=Select airplane firing mode:
@ -20,10 +21,12 @@ Bomb=Bomb drop
Spray=Liquid spray
Balloon=Balloon parachute
Drop=Object drop
Afterburner=Afterburner
BulletInfo=Fire the main cannon, shooting bullets ({{LeadBullet}}). Shots available: %d.
RocketInfo=Fire boompacks ({{Boompack}}) from the airplane. Rockets available: %d.
BombInfo=Drop bombs ({{IronBomb}} and {{Dynamite}}) from the airplane. Bombs available: %d.
SprayInfo=Spray liquids stored in barrels ({{Barrel}} and {{MetalBarrel}}) from the airplane. Barrels available: %d.
BalloonInfo=Parachute from the airplane with a balloon ({{Balloon}}). This action will be available for passengers, too. Balloons available: %d.
DropInfo=Drop contents from the airplane.
DropInfo=Drop contents from the airplane.
AfterburnerInfo=Use oil to speed up the airplane.

View File

@ -112,7 +112,7 @@ public func Intro_5()
this.airplane->SetMeshMaterial("CrashedAirplane");
this.airplane->MakeBroken();
this.airplane->CancelFlight();
RemoveEffect("IntPlane", this.airplane);
this.airplane->RemovePlaneControl();
this.airplane->SetRDir(10);
this.airplane->SetSpeed(46, -56);
// Forward plane hit call to sequence.