Airplane: carry up to 20 items and 3 clonks (#1663). Also refactoring of the script.

ipv6
Clonkonaut 2016-12-30 03:54:01 +01:00
parent 6fe22afe1a
commit 71d5e611a4
11 changed files with 287 additions and 229 deletions

View File

@ -22,10 +22,11 @@ func Intro_Init()
this.pilot->SetDir(DIR_Left);
this.pilot->SetObjectLayer(this.pilot);
this.pilot->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(5500, 0, 0));
this.dialogue = this.pilot->SetDialogue("Pyrit");
this.dialogue->SetInteraction(false);
this.plane->PlaneMount(this.pilot);
this.plane->FaceRight();
this.plane.PlaneDeath = this.Intro_PlaneDeath;
}

View File

@ -27,6 +27,7 @@ func Intro_Start()
this.pilot->SetObjectLayer(this.pilot);
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);

View File

@ -46,6 +46,7 @@ func Outro_4()
this.pilot->SetAlternativeSkin("MaleBrownHair");
this.pilot->SetDir(DIR_Right);
this.pilot->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(5500, 0, 0));
this.plane->PlaneMount(this.pilot);
this.plane->FaceRight();
this.plane->StartInstantFlight(90, 15);
return ScheduleNext(5);

View File

@ -29,6 +29,7 @@ func Attack_1()
pilot->SetColor(0xff101010);
pilot->SetDir(DIR_Left);
//plane->FaceLeft();
plane->PlaneMount(pilot);
plane->StartInstantFlight(260, 15);
plane->SetXDir(-15);
plane->MakeInvincible();

View File

@ -52,6 +52,7 @@ func Outro_6()
{
if (npc_pyrit->Contained() != this.plane) return ScheduleSame(5);
// After Pyrit is inside, rest enters freely
this.plane->PlaneMount(npc_pyrit);
this.plane->SetEntrance(true);
for (var clonk in this.plane->FindObjects(this.plane->Find_AtRect(-60,-30,120,60), Find_ID(Clonk), Find_Not(Find_Owner(NO_OWNER))))
clonk->SetCommand("Enter", this.plane);

View File

@ -29,6 +29,7 @@ func Intro_Init(object flagpole)
this.pilot->SetObjectLayer(this.pilot);
this.pilot->SetAlternativeSkin("MaleBrownHair");
this.plane->PlaneMount(this.pilot);
// Pyit has a red hat!
this.pilot->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(5500, 0, 0));

View File

@ -50,6 +50,7 @@ func Outro_5()
{
if (npc_pyrit->Contained() != this.plane) return ScheduleSame(5);
// After Pyrit is inside, rest enters freely
this.plane->PlaneMount(npc_pyrit);
this.plane->SetEntrance(true);
for (var clonk in this.plane->FindObjects(this.plane->Find_AtRect(-60,-30,120,60), Find_ID(Clonk), Find_Not(Find_Owner(NO_OWNER))))
clonk->SetCommand("Enter", this.plane);

View File

@ -1,50 +1,119 @@
/*--
/**
Airplane
Author: Ringwaul
Acrobatic air-vehicle. Capable of firing lead shot.
--*/
@author: Ringwaul, Clonkonaut
*/
local throttle = 0;
local rdir = 0;
local thrust = 0;
local dir = 0;
local newrot;
local throttle;
local rdir;
local thrust;
local dir;
local propanim;
local prop_speed, prop_speed_target, prop_speed_timer; // current and target propeller speed [0, 100]
local pilot;
local clonkmesh;
public func IsVehicle() { return true; }
/*-- Engine Callbacks --*/
protected func Construction(object byobj)
func Construction()
{
SetR(-90);
}
protected func Initialize()
func Initialize()
{
propanim = PlayAnimation("Propellor", 15, Anim_Const(0));
AddEffect("IntPlane",this,1,1,this);
propanim = PlayAnimation("Propellor", 15, Anim_Const(0));
AddEffect("IntPlane", this, 1, 1, this);
SetAction("Land");
throttle = 0;
thrust = 0;
rdir = 0;
dir = 0;
return;
}
protected func RejectCollect(id def, object obj)
func RejectCollect(id def, object obj)
{
// Only accept munition and clonks.
if (def != LeadBullet && def != Boompack && !(obj->GetOCF() & OCF_CrewMember))
var contents_count = ObjectCount(Find_Container(this), Find_Not(Find_OCF(OCF_CrewMember)));
if (contents_count >= MaxContentsCount)
return true;
return false;
}
func Damage(int change, int cause, int by_player)
{
if (GetDamage() >= this.HitPoints)
{
if (pilot) PlaneDismount(pilot);
SetController(by_player);
PlaneDeath();
}
}
/*-- Control: Fire Bullets --*/
func ActivateEntrance(object clonk)
{
if (clonk->Contained() == this)
return clonk->Exit();
// Clonks cannot get into the plane if it is underwater
if(GBackLiquid()) return false;
var passengers = ObjectCount(Find_Container(this), Find_OCF(OCF_CrewMember));
if (passengers >= MaxPassengerCount) return false;
clonk->Enter(this);
clonk->SetAction("Walk");
clonk->PlayAnimation("Drive", CLONK_ANIM_SLOT_Movement, Anim_Const(10), Anim_Const(1000));
}
func Ejection(object obj)
{
if (pilot && obj == pilot)
PlaneDismount(obj);
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)
{
var remaining_hp = this.HitPoints - GetDamage();
if (remaining_hp < 10)
{
var speed = Distance(0, 0, xdir, ydir) / 10;
if (speed > 4 * remaining_hp)
DoDamage(speed / 6, FX_Call_DmgScript, GetController());
}
}
/*-- 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.
public func FaceRight()
{
SetR(90);
RollPlane(1, true);
}
public func FaceLeft()
{
SetR(-90);
RollPlane(0, true);
}
/*-- Usage --*/
// Bullet firing
public func ContainedUseStart(object clonk, int x, int y)
{
//return ContainedUseAltStart(clonk, x, y);
if (clonk != pilot) return false;
var ammo = FindObject(Find_Container(this), Find_Func("IsBullet"));
if (!ammo)
{
@ -55,7 +124,135 @@ public func ContainedUseStart(object clonk, int x, int y)
return true;
}
protected func FxFireBulletsStart(object target, proplist effect, int temp)
public func ContainedUseStop(object clonk, int x, int y)
{
if (clonk != pilot) return false;
if (GetEffect("FireBullets", this))
RemoveEffect("FireBullets", this);
return true;
}
public func ContainedUseCancel(object clonk, int x, int y)
{
if (clonk != pilot) return false;
if (GetEffect("FireBullets", this))
RemoveEffect("FireBullets", this);
return true;
}
// Rocket firing
public func ContainedUseAltStart(object clonk, int x, int y)
{
if (clonk != pilot) return false;
var rocket = FindObject(Find_Container(this), Find_ID(Boompack));
if (!rocket)
{
CustomMessage("$NoRockets$", this, clonk->GetOwner());
return true;
}
return true;
}
public func ContainedUseAltStop(object clonk, int x, int y)
{
if (clonk != pilot) return false;
var rocket = FindObject(Find_Container(this), Find_ID(Boompack));
if (!rocket)
{
CustomMessage("$NoRockets$", this, clonk->GetOwner());
return true;
}
FireRocket(rocket, x, y);
return true;
}
public func ContainedUseAltCancel(object clonk, int x, int y)
{
if (clonk != pilot) return false;
return true;
}
// 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
if (!pilot->GetAlive())
PlaneDismount(pilot);
else if (clonk != pilot)
return false;
}
//engine start
if(clonk && GetAction() == "Land")
{
if (!pilot) PlaneMount(clonk);
StartFlight(15);
return true;
}
return false;
}
// Stopping the plane
public func ContainedDown(object clonk)
{
//engine shutoff
if(GetAction() == "Fly" && clonk == pilot)
{
CancelFlight();
return true;
}
if (pilot)
{
if (!pilot->GetAlive())
PlaneDismount(pilot);
else if (clonk != pilot)
return false;
}
//allow reverse
if(clonk && GetAction() == "Land")
{
if (!pilot) PlaneMount(clonk);
StartFlight(-5);
return true;
}
return false;
}
// Steering
public func ContainedLeft(object clonk)
{
if (clonk != pilot) return false;
rdir = -1;
return true;
}
public func ContainedRight(object clonk)
{
if (clonk != pilot) return false;
rdir = 1;
return true;
}
public func ContainedStop(object clonk)
{
if (clonk != pilot) return false;
rdir = 0;
return true;
}
/*-- Bullet firing --*/
func FxFireBulletsStart(object target, proplist effect, int temp)
{
if (temp)
return FX_OK;
@ -66,10 +263,10 @@ protected func FxFireBulletsStart(object target, proplist effect, int temp)
if (!ammo)
return FX_Execute_Kill;
FireBullet(ammo);
return FX_OK;
return FX_OK;
}
protected func FxFireBulletsTimer(object target, proplist effect, int time)
func FxFireBulletsTimer(object target, proplist effect, int time)
{
var ammo = FindObject(Find_Container(this), Find_Func("IsBullet"));
if (!ammo)
@ -78,7 +275,7 @@ protected func FxFireBulletsTimer(object target, proplist effect, int time)
return FX_OK;
}
protected func FxFireBulletsStop(object target, proplist effect, int reason, bool temp)
func FxFireBulletsStop(object target, proplist effect, int reason, bool temp)
{
if (temp)
return FX_OK;
@ -87,7 +284,7 @@ protected func FxFireBulletsStop(object target, proplist effect, int reason, boo
return FX_OK;
}
private func FireBullet(object ammo)
func FireBullet(object ammo)
{
var shot = ammo->TakeObject();
var angle = this->GetR();
@ -101,60 +298,14 @@ private func FireBullet(object ammo)
var x = Sin(angle, 20);
var y = -Cos(angle, 20);
CreateParticle("Smoke", IX, IY, PV_Random(x - 20, x + 20), PV_Random(y - 20, y + 20), PV_Random(40, 60), Particles_Smoke(), 20);
CreateMuzzleFlash(IX, IY, angle, 20);
CreateParticle("Flash", 0, 0, GetXDir(), GetYDir(), 8, Particles_Flash());
return;
}
public func ContainedUseStop(object clonk, int x, int y)
{
//return ContainedUseAltStop(clonk, x, y);
if (GetEffect("FireBullets", this))
RemoveEffect("FireBullets", this);
return true;
}
/*-- Rocket firing --*/
public func ContainedUseCancel(object clonk, int x, int y)
{
//return ContainedUseAltCancel(clonk, x, y);
if (GetEffect("FireBullets", this))
RemoveEffect("FireBullets", this);
return true;
}
/*-- Control: Fire Rockets --*/
public func ContainedUseAltStart(object clonk, int x, int y)
{
var rocket = FindObject(Find_Container(this), Find_ID(Boompack));
if (!rocket)
{
CustomMessage("$NoRockets$", this, clonk->GetOwner());
return true;
}
return true;
}
public func ContainedUseAltStop(object clonk, int x, int y)
{
var rocket = FindObject(Find_Container(this), Find_ID(Boompack));
if (!rocket)
{
CustomMessage("$NoRockets$", this, clonk->GetOwner());
return true;
}
FireRocket(rocket, x, y);
return true;
}
public func ContainedUseAltCancel(object clonk, int x, int y)
{
return true;
}
private func FireRocket(object rocket, int x, int y)
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);
@ -164,10 +315,9 @@ private func FireRocket(object rocket, int x, int y)
effect.x = GetX() + x;
effect.y = GetY() + y;
rocket->SetDirectionDeviation(0);
return;
}
protected func FxIntControlRocketTimer(object target, proplist effect, int time)
func FxIntControlRocketTimer(object target, proplist effect, int time)
{
// Remove gravity on rocket.
target->SetYDir(target->GetYDir(100) - GetGravity(), 100);
@ -186,49 +336,7 @@ protected func FxIntControlRocketTimer(object target, proplist effect, int time)
return FX_OK;
}
/*-- Control: Movement --*/
public func ContainedUp(object clonk)
{
//engine start
if(GetAction() == "Land")
{
StartFlight(15);
return;
}
}
public func ContainedDown(object clonk)
{
//engine shutoff
if(GetAction() == "Fly")
{
CancelFlight();
return;
}
//allow reverse
if(GetAction() == "Land")
{
StartFlight(-5);
return;
}
}
public func ContainedLeft(object clonk)
{
rdir = -1;
}
public func ContainedRight(object clonk)
{
rdir = 1;
}
public func ContainedStop(object clonk)
{
rdir = 0;
}
/*-- Movement --*/
public func StartFlight(int new_throttle)
{
@ -248,7 +356,6 @@ public func StartInstantFlight(int angle, int new_throttle)
SetR(angle);
SetXDir(Sin(angle, thrust));
SetYDir(-Cos(angle, thrust));
return;
}
public func CancelFlight()
@ -259,10 +366,10 @@ public func CancelFlight()
throttle = 0;
}
private func FxIntPlaneTimer(object target, effect, int timer)
func FxIntPlaneTimer(object target, effect, int timer)
{
//Lift
var lift = Distance(0,0,GetXDir(),GetYDir()) / 2;
var lift = Distance(0, 0, GetXDir(), GetYDir()) / 2;
if(lift > 20) lift = 20;
if(throttle < 1) lift = 0;
@ -301,7 +408,7 @@ private func FxIntPlaneTimer(object target, effect, int timer)
if(throttle > thrust) ++thrust;
if(throttle < thrust) --thrust;
}
//propellor
var change = GetAnimationPosition(propanim) + thrust * 3;
if(change > GetAnimationLength("Propellor"))
@ -312,21 +419,24 @@ private func FxIntPlaneTimer(object target, effect, int timer)
SetAnimationPosition(propanim, Anim_Const(change));
//Thrust
SetXDir(Sin(GetR(),thrust) + GetXDir(100), 100);
SetYDir(-Cos(GetR(),thrust) + GetYDir(100) - lift, 100);
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 > 40)
var speed = Distance(0, 0, GetXDir(), GetYDir());
if(speed > maxspeed)
{
SetXDir(GetXDir(100)*maxspeed/speed,100);
SetYDir(GetYDir(100)*maxspeed/speed,100);
SetXDir(GetXDir(100)*maxspeed/speed, 100);
SetYDir(GetYDir(100)*maxspeed/speed, 100);
}
// No pilot? Look for all layers, since an NPC might be in a different layer.
var pilot = FindObject(Find_OCF(OCF_CrewMember), Find_Container(this), Find_AnyLayer());
// var pilot = FindObject(Find_OCF(OCF_CrewMember), Find_Container(this), Find_AnyLayer());
if(!pilot && throttle != 0) CancelFlight();
if (pilot && !pilot->GetAlive())
PlaneDismount(pilot);
//Planes cannot fly underwater!
if(GBackLiquid())
@ -336,100 +446,26 @@ private func FxIntPlaneTimer(object target, effect, int timer)
}
//Pilot, but no mesh? In case they are scripted into the plane.
if(FindContents(Clonk) && !clonkmesh)
PlaneMount(FindContents(Clonk));
// if(FindContents(Clonk) && !clonkmesh)
// PlaneMount(FindContents(Clonk));
}
local newrot;
public func RollPlane(int rolldir, bool instant)
{
if(dir != rolldir)
{
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));
newrot = PlayAnimation(Format("Roll%d",rolldir), 10, Anim_Linear(0, 0, GetAnimationLength(Format("Roll%d", rolldir)), i, ANIM_Hold));
dir = rolldir;
}
}
//Quick command for scenario designers. The plane starts facing right instead of left.
public func FaceRight()
{
SetR(90);
RollPlane(1,true);
}
public func FaceLeft()
{
SetR(-90);
RollPlane(0,true);
}
public func IsProjectileTarget(target,shooter) { return true; }
public func Damage(int change, int cause, int by_player)
{
if (GetDamage() >= this.HitPoints)
{
SetController(by_player);
this->~PlaneDeath();
}
}
// Inflict damage when hitting something with the plane and already damaged.
public func Hit(int xdir, int ydir)
{
var remaining_hp = this.HitPoints - GetDamage();
if (remaining_hp < 10)
{
var speed = Distance(0, 0, xdir, ydir) / 10;
if (speed > 4 * remaining_hp)
DoDamage(speed / 6, FX_Call_DmgScript, GetController());
}
return;
}
private func PlaneDeath()
{
while(Contents(0))
Contents(0)->Exit();
Explode(36);
}
public func ActivateEntrance(object clonk)
{
var cnt = ObjectCount(Find_Container(this), Find_OCF(OCF_CrewMember));
if(cnt > 0)
if(clonk->Contained() == this)
{
clonk->Exit();
return;
}
else
return;
//Clonk cannot get into the plane if it is underwater
if(GBackLiquid()) return;
if(cnt == 0)
{
clonk->Enter(this);
clonk->SetAction("Walk");
PlaneMount(clonk);
clonk->PlayAnimation("Drive", CLONK_ANIM_SLOT_Movement, Anim_Const(10), Anim_Const(1000));
}
}
public func Ejection(object obj)
{
PlaneDismount(obj);
if(obj->Contained()) Exit();
obj->SetSpeed(this->GetXDir(),this->GetYDir());
}
/*-- Piloting --*/
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);
@ -441,16 +477,22 @@ public func PlaneDismount(object clonk)
clonk->StopAnimation(clonk->GetRootAnimation(15));
DetachMesh(clonkmesh);
clonkmesh = nil;
pilot = nil;
CancelFlight();
return true;
}
/*-- Effects --*/
/* Propeller sound */
local prop_speed, prop_speed_target, prop_speed_timer; // current and target propeller speed [0, 100]
func PlaneDeath()
{
while(Contents(0))
Contents(0)->Exit();
Explode(36);
}
// Instantly set new propeller speed
private func SetPropellerSpeed(int new_speed)
public func SetPropellerSpeed(int new_speed)
{
if (prop_speed_timer)
{
@ -461,7 +503,7 @@ private func SetPropellerSpeed(int new_speed)
}
// Schedule fading to new propeller speed
private func SetPropellerSpeedTarget(int new_speed_target)
public func SetPropellerSpeedTarget(int new_speed_target)
{
prop_speed_target = new_speed_target;
if (!prop_speed_timer) prop_speed_timer = AddTimer(this.PropellerSpeedTimer, 10);
@ -469,7 +511,7 @@ private func SetPropellerSpeedTarget(int new_speed_target)
}
// Execute fading to new propeller speed
private func PropellerSpeedTimer()
func PropellerSpeedTimer()
{
prop_speed = BoundBy(prop_speed_target, prop_speed - 10, prop_speed + 4);
if (prop_speed == prop_speed_target)
@ -481,7 +523,7 @@ private func PropellerSpeedTimer()
}
// Set propeller speed sound. 0 = off, 100 = max speed.
private func SetPropellerSound(int speed)
func SetPropellerSound(int speed)
{
if (speed <= 0)
return Sound("Objects::Plane::PropellerLoop",0,100,nil,-1);
@ -489,11 +531,20 @@ private func SetPropellerSound(int speed)
return Sound("Objects::Plane::PropellerLoop",0,100,nil,1,0,(speed-100)*2/3);
}
/* Properties */
/*-- Production --*/
public func IsContainer() { return true; }
public func IsVehicle() { return true; }
public func IsShipyardProduct() { return true; }
func IsShipyardProduct() { return true; }
/*-- Display --*/
func Definition(def)
{
SetProperty("MeshTransformation", Trans_Mul(Trans_Rotate(90,0,0,1), Trans_Translate(-10000,-3375,0), Trans_Rotate(25,0,1,0)));
SetProperty("PictureTransformation",Trans_Mul(Trans_Rotate(-5,1,0,0),Trans_Rotate(40,0,1,0),Trans_Translate(-20000,-4000,20000)),def);
}
/*-- Properties --*/
local ActMap = {
Fly = {
@ -526,14 +577,10 @@ local ActMap = {
},
};
func Definition(def)
{
SetProperty("MeshTransformation", Trans_Mul(Trans_Rotate(90,0,0,1), Trans_Translate(-10000,-3375,0), Trans_Rotate(25,0,1,0)));
SetProperty("PictureTransformation",Trans_Mul(Trans_Rotate(-5,1,0,0),Trans_Rotate(40,0,1,0),Trans_Translate(-20000,-4000,20000)),def);
}
local Name="$Name$";
local Description="$Description$";
local BorderBound = C4D_Border_Sides | C4D_Border_Top | C4D_Border_Bottom;
local HitPoints = 50;
local MaxContentsCount = 20;
local MaxPassengerCount = 3;
local Components = {Metal = 6, Wood = 4};

View File

@ -19,6 +19,7 @@ public func Outro_Init(int for_plr)
this.pilot1->Enter(this.airplane1);
this.pilot1->SetAction("Walk");
this.pilot1->SetColor(0xff000000);
this.airplane1->PlaneMount(this.pilot1);
this.airplane1->FaceRight();
this.airplane1->StartInstantFlight(90, 15);
this.airplane1->SetXDir(12);
@ -32,6 +33,7 @@ public func Outro_Init(int for_plr)
this.pilot2->Enter(this.airplane2);
this.pilot2->SetAction("Walk");
this.pilot2->SetColor(0xff000000);
this.airplane2->PlaneMount(this.pilot2);
this.airplane2->FaceRight();
this.airplane2->StartInstantFlight(90, 15);
this.airplane2->SetXDir(12);

View File

@ -13,6 +13,7 @@ public func Intro_Init()
this.pilot->SetAction("Walk");
this.pilot->SetDir(DIR_Right);
this.pilot->SetColor(0xffcc11aa);
this.airplane->PlaneMount(this.pilot);
this.airplane->FaceRight();
this.airplane->StartInstantFlight(60, 15);
this.airplane->SetXDir(12);

View File

@ -21,6 +21,7 @@ public func Intro_Init(int difficulty)
this.pilot->SetAction("Walk");
this.pilot->SetDir(DIR_Right);
this.pilot->SetColor(0xff0000aa);
this.airplane->PlaneMount(this.pilot);
this.airplane->FaceRight();
this.airplane->StartInstantFlight(90, 15);
this.airplane->SetXDir(12);